@3kles/kles-material-table-v2 21.4.2 → 21.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,8 @@
1
- import * as i16 from '@angular/common';
1
+ import * as i17 from '@angular/common';
2
2
  import { CommonModule } from '@angular/common';
3
3
  import * as i0 from '@angular/core';
4
- import { Pipe, InjectionToken, Injectable, input, computed, HostBinding, Directive, inject, Inject, signal, DestroyRef, Component, ChangeDetectorRef, ChangeDetectionStrategy, Optional, EventEmitter, ViewChild, effect, Injector, Output, NgModule } from '@angular/core';
5
- import * as i17 from '@angular/forms';
4
+ import { Pipe, InjectionToken, Injectable, computed, Inject, input, HostBinding, Directive, inject, signal, DestroyRef, Component, ChangeDetectorRef, ChangeDetectionStrategy, Optional, EventEmitter, Injector, ViewChild, effect, Output, NgModule } from '@angular/core';
5
+ import * as i18 from '@angular/forms';
6
6
  import { FormControl, FormGroup, FormArray, ReactiveFormsModule } from '@angular/forms';
7
7
  import * as i2 from '@angular/material/button';
8
8
  import { MatButtonModule } from '@angular/material/button';
@@ -10,27 +10,29 @@ import { MatFormFieldModule } from '@angular/material/form-field';
10
10
  import * as i1 from '@angular/material/icon';
11
11
  import { MatIconModule } from '@angular/material/icon';
12
12
  import { MatInputModule } from '@angular/material/input';
13
- import * as i19 from '@angular/material/table';
13
+ import * as i20 from '@angular/material/table';
14
14
  import { MatTableDataSource, MatTableModule, MatTable } from '@angular/material/table';
15
- import * as i20 from '@angular/cdk/table';
15
+ import * as i21 from '@angular/cdk/table';
16
16
  import { CdkTableModule } from '@angular/cdk/table';
17
- import * as i21 from '@3kles/kles-material-dynamicforms';
17
+ import * as i22 from '@angular/cdk/scrolling';
18
+ import { ScrollingModule } from '@angular/cdk/scrolling';
19
+ import * as i23 from '@3kles/kles-material-dynamicforms';
18
20
  import { componentMapper, klesFieldControlFactory, klesFieldUiFactory, GroupUiState, ArrayUiState, KlesMaterialDynamicformsModule } from '@3kles/kles-material-dynamicforms';
19
21
  import * as i4 from '@angular/material/sort';
20
22
  import { MatSortModule, MatSort } from '@angular/material/sort';
21
- import * as i22 from '@angular/cdk/drag-drop';
22
- import { DragDropModule } from '@angular/cdk/drag-drop';
23
- import * as i23 from '@angular/material/progress-spinner';
23
+ import * as i24 from '@angular/cdk/drag-drop';
24
+ import { CdkDragHandle, DragDropModule } from '@angular/cdk/drag-drop';
25
+ import * as i25 from '@angular/material/progress-spinner';
24
26
  import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
25
- import { Subject, BehaviorSubject, combineLatest, startWith, of, auditTime, switchMap, concat, catchError, map, filter, take, merge, debounceTime, distinctUntilChanged, scan, concatMap, withLatestFrom, shareReplay } from 'rxjs';
26
- import { toObservable, takeUntilDestroyed } from '@angular/core/rxjs-interop';
27
+ import { Subject, BehaviorSubject, combineLatest, startWith, of, auditTime, switchMap, concat, catchError, map, filter, take, defer, defaultIfEmpty, merge, debounceTime, distinctUntilChanged, scan, concatMap, withLatestFrom, shareReplay } from 'rxjs';
28
+ import { takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop';
27
29
  import * as _ from 'lodash';
28
30
  import ___default from 'lodash';
29
31
  import * as i3 from '@angular/material/tooltip';
30
32
  import { MatTooltipModule } from '@angular/material/tooltip';
33
+ import { __decorate, __param } from 'tslib';
31
34
  import * as i2$1 from '@angular/material/paginator';
32
35
  import { MatPaginatorModule, MatPaginator, MatPaginatorIntl } from '@angular/material/paginator';
33
- import { ScrollingModule } from '@angular/cdk/scrolling';
34
36
 
35
37
  class HeaderFieldPipe {
36
38
  transform(col) {
@@ -90,9 +92,10 @@ const LOADER_CONFIG = new InjectionToken('LOADER_CONFIG');
90
92
  const COLUMNS = new InjectionToken('COLUMNS');
91
93
  const FOOTER = new InjectionToken('FOOTER');
92
94
  const EXTRA_ROWS = new InjectionToken('EXTRA_ROWS');
95
+ const MULTI_UNFOLD = new InjectionToken('MULTI_UNFOLD');
93
96
  const ROW_DRAG_DROP = new InjectionToken('ROW_DRAG_DROP');
94
97
  const DRAG_DROP_CONFIG = new InjectionToken('DRAG_DROP_CONFIG');
95
- // export const KLES_TABLE_SERVICE = new InjectionToken<KlesTableService>('KLES_TABLE_SERVICE');
98
+ const KLES_DRAG_DROP_ROW_CONTEXT = new InjectionToken('KLES_DRAG_DROP_ROW_CONTEXT');
96
99
  const PAGINATOR_CONFIG = new InjectionToken('PAGINATOR_CONFIG');
97
100
  const SORT_CONFIG = new InjectionToken('SORT_CONFIG');
98
101
  const HEADER_SERVICE = new InjectionToken('HEADER_SERVICE');
@@ -155,147 +158,487 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
155
158
  type: Injectable
156
159
  }] });
157
160
 
161
+ class ColumnsService {
162
+ constructor(_columns, eventsService) {
163
+ this._columns = _columns;
164
+ this.eventsService = eventsService;
165
+ this.stickyStartBoundary = computed(() => {
166
+ return this.getVisibleColumns()
167
+ .filter((column) => column.sticky === true)
168
+ .at(-1)?.columnDef;
169
+ }, ...(ngDevMode ? [{ debugName: "stickyStartBoundary" }] : /* istanbul ignore next */ []));
170
+ this.stickyEndBoundary = computed(() => {
171
+ return this.getVisibleColumns()
172
+ .filter((column) => column.stickyEnd === true)
173
+ .at(0)?.columnDef;
174
+ }, ...(ngDevMode ? [{ debugName: "stickyEndBoundary" }] : /* istanbul ignore next */ []));
175
+ }
176
+ register() {
177
+ this.setDisplayedColumns();
178
+ }
179
+ get columns() {
180
+ return this._columns.asReadonly();
181
+ }
182
+ getVisible() {
183
+ return this.getVisibleColumns().map((column) => column.columnDef);
184
+ }
185
+ setVisible(columnDef, visible) {
186
+ this.updateColumn(columnDef, { visible });
187
+ this.eventsService.emit('columnVisibilityChange', {
188
+ columnDef,
189
+ columns: this.getVisible(),
190
+ visible,
191
+ });
192
+ }
193
+ toggleVisible(columnDef) {
194
+ const visible = this._columns().find((col) => col.columnDef === columnDef)?.visible;
195
+ this.setVisible(columnDef, visible === undefined ? false : !visible);
196
+ }
197
+ changeWidth(columnDef, options) {
198
+ this.updateColumn(columnDef, {
199
+ ...(options.width && { width: options.width }),
200
+ ...(options.maxWidth && { maxWidth: options.maxWidth }),
201
+ ...(options.minWidth && { minWidth: options.minWidth }),
202
+ });
203
+ }
204
+ setResizable(columnDef, resizable) {
205
+ this.updateColumn(columnDef, { resizable });
206
+ }
207
+ toggleResizable(columnDef) {
208
+ const resizable = this._columns().find((col) => col.columnDef === columnDef)?.resizable;
209
+ this.setResizable(columnDef, resizable === undefined ? true : !resizable);
210
+ }
211
+ setSticky(columnDef, options) {
212
+ this.updateColumn(columnDef, {
213
+ ...(options.sticky !== undefined && { sticky: options.sticky }),
214
+ ...(options.stickyEnd !== undefined && { stickyEnd: options.stickyEnd }),
215
+ });
216
+ }
217
+ setColumnPosition(columnDef, position) {
218
+ const columns = this._columns();
219
+ const previousIndex = columns.findIndex((column) => column.columnDef === columnDef);
220
+ if (previousIndex < 0 || columns.length < 2 || !Number.isFinite(position))
221
+ return;
222
+ const currentIndex = Math.min(columns.length - 1, Math.max(0, Math.trunc(position)));
223
+ if (previousIndex === currentIndex)
224
+ return;
225
+ const reorderedColumns = [...columns];
226
+ const [column] = reorderedColumns.splice(previousIndex, 1);
227
+ reorderedColumns.splice(currentIndex, 0, column);
228
+ this._columns.set(reorderedColumns);
229
+ this.eventsService.emit('columnOrderChange', {
230
+ previousIndex,
231
+ currentIndex,
232
+ columns: this.getVisible(),
233
+ });
234
+ }
235
+ updateColumn(columnDef, config) {
236
+ this._columns.update((columns) => columns.map((col) => col.columnDef === columnDef
237
+ ? {
238
+ ...col,
239
+ ...config,
240
+ cell: config.cell ? { ...col.cell, ...config.cell } : col.cell,
241
+ headerCell: config.headerCell ? { ...col.headerCell, ...config.headerCell } : col.headerCell,
242
+ footerCell: config.footerCell ? { ...col.footerCell, ...config.footerCell } : col.footerCell,
243
+ }
244
+ : col));
245
+ }
246
+ setDisplayedColumns() {
247
+ this.displayedColumns = computed(() => {
248
+ return this.getVisibleColumns().map((column) => column.columnDef);
249
+ }, ...(ngDevMode ? [{ debugName: "displayedColumns" }] : /* istanbul ignore next */ []));
250
+ }
251
+ getVisibleColumns() {
252
+ return this._columns().filter((column) => {
253
+ if (column.visibleWhen !== undefined) {
254
+ return column.visibleWhen();
255
+ }
256
+ return column.visible !== false;
257
+ });
258
+ }
259
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: ColumnsService, deps: [{ token: COLUMNS }, { token: EventsService }], target: i0.ɵɵFactoryTarget.Injectable }); }
260
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: ColumnsService }); }
261
+ }
262
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: ColumnsService, decorators: [{
263
+ type: Injectable
264
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
265
+ type: Inject,
266
+ args: [COLUMNS]
267
+ }] }, { type: EventsService }] });
268
+
158
269
  class ResizableColumnDirective {
159
270
  get appResizableColumnAttr() {
160
271
  return this.column().columnDef;
161
272
  }
162
- constructor(el, renderer, zone, eventsService) {
273
+ constructor(el, renderer, zone, eventsService, columnsService) {
163
274
  this.el = el;
164
275
  this.renderer = renderer;
165
276
  this.zone = zone;
166
277
  this.eventsService = eventsService;
278
+ this.columnsService = columnsService;
167
279
  this.column = input.required({ ...(ngDevMode ? { debugName: "column" } : /* istanbul ignore next */ {}), alias: 'appResizableColumn' });
168
- this.minWidth = computed(() => {
169
- return 60; //TODO trouver une solution pour ne plus avoir une valeur en dur
170
- }, ...(ngDevMode ? [{ debugName: "minWidth" }] : /* istanbul ignore next */ []));
171
- this.maxWidth = computed(() => {
172
- return 800; //TODO trouver une solution pour ne plus avoir une valeur en dur
173
- }, ...(ngDevMode ? [{ debugName: "maxWidth" }] : /* istanbul ignore next */ []));
280
+ this.defaultMinWidth = 60;
281
+ this.defaultMaxWidth = 1200;
282
+ this.keyboardStep = 4;
174
283
  this.startX = 0;
175
284
  this.startWidth = 0;
176
285
  this.currentWidth = 0;
286
+ this.resizing = false;
287
+ this.activeCells = [];
288
+ this.resizeCells = [];
289
+ this.resizeMinWidth = this.defaultMinWidth;
290
+ this.resizeMaxWidth = this.defaultMaxWidth;
291
+ this.contentMinWidth = this.defaultMinWidth;
292
+ this.handleCleanups = [];
293
+ this.documentCleanups = [];
177
294
  }
178
295
  ngOnInit() {
179
- if (this.column().resizable) {
296
+ if (this.column().resizable)
180
297
  this.apply();
181
- }
182
298
  }
183
299
  ngOnChanges(changes) {
184
- if (!changes.column.isFirstChange()) {
185
- if (changes.column.previousValue.resizable !== changes.column.currentValue.resizable) {
186
- if (changes.column.currentValue.resizable) {
187
- this.apply();
188
- }
189
- else {
190
- this.remove();
191
- }
192
- }
300
+ const change = changes.column;
301
+ if (change && !change.isFirstChange() && change.previousValue.resizable !== change.currentValue.resizable) {
302
+ change.currentValue.resizable ? this.apply() : this.remove();
193
303
  }
194
304
  }
195
- onDown(e) {
196
- e.preventDefault();
197
- this.startResize(e.clientX);
305
+ ngOnDestroy() {
306
+ this.stopResize(false);
307
+ this.remove();
198
308
  }
199
- onTouchDown(e) {
200
- if (!e.touches?.length)
309
+ startResize(event) {
310
+ if (event.button !== 0 || this.resizing)
201
311
  return;
202
- e.preventDefault();
203
- this.startResize(e.touches[0].clientX);
204
- }
205
- startResize(clientX) {
312
+ event.preventDefault();
313
+ event.stopPropagation();
314
+ this.cancelContentMeasurement();
206
315
  const th = this.el.nativeElement;
207
- this.startX = clientX;
316
+ this.startX = event.clientX;
208
317
  this.startWidth = th.getBoundingClientRect().width;
209
318
  this.currentWidth = this.startWidth;
210
- this.zone.run(() => {
211
- this.eventsService.emit('columnResizeStart', {
212
- columnDef: this.column().columnDef,
213
- width: this.startWidth,
214
- previousWidth: this.startWidth,
215
- });
216
- });
319
+ this.cacheResizeTargets();
320
+ this.resizing = true;
321
+ this.setActiveState(true);
322
+ this.updateWidthLabel(this.currentWidth);
323
+ this.emitResizeStart(this.startWidth);
217
324
  this.zone.runOutsideAngular(() => {
218
325
  const doc = th.ownerDocument;
219
- const onMove = (ev) => {
220
- const x = ev instanceof MouseEvent ? ev.clientX : (ev.touches?.[0]?.clientX ?? this.startX);
221
- const delta = x - this.startX;
222
- const next = Math.min(this.maxWidth(), Math.max(this.minWidth(), this.startWidth + delta));
223
- if (next === this.currentWidth) {
224
- return;
225
- }
226
- const previousWidth = this.currentWidth;
227
- this.currentWidth = next;
228
- this.applyWidth(next);
229
- this.eventsService.emit('columnResize', {
230
- columnDef: this.column().columnDef,
231
- width: next,
232
- previousWidth,
233
- });
234
- };
235
- const onUp = () => this.stopResize();
236
- this.cleanupMove = this.renderer.listen(doc, 'mousemove', onMove);
237
- this.renderer.listen(doc, 'touchmove', onMove);
238
- this.cleanupUp = this.renderer.listen(doc, 'mouseup', onUp);
239
- this.renderer.listen(doc, 'touchend', onUp);
240
- });
241
- }
242
- stopResize() {
243
- this.cleanupMove?.();
244
- this.cleanupUp?.();
245
- this.cleanupMove = undefined;
246
- this.cleanupUp = undefined;
247
- if (this.currentWidth > 0) {
248
- this.zone.run(() => {
249
- this.eventsService.emit('columnResizeEnd', {
250
- columnDef: this.column().columnDef,
251
- width: this.currentWidth,
252
- previousWidth: this.startWidth,
253
- });
254
- });
326
+ this.documentCleanups.push(this.renderer.listen(doc, 'pointermove', (moveEvent) => this.onPointerMove(moveEvent)), this.renderer.listen(doc, 'pointerup', () => this.stopResize()), this.renderer.listen(doc, 'pointercancel', () => this.stopResize()));
327
+ });
328
+ }
329
+ onPointerMove(event) {
330
+ if (!this.resizing)
331
+ return;
332
+ event.preventDefault();
333
+ this.pendingWidth = this.startWidth + event.clientX - this.startX;
334
+ this.scheduleResizeFrame();
335
+ }
336
+ stopResize(emit = true) {
337
+ this.clearDocumentListeners();
338
+ if (!this.resizing)
339
+ return;
340
+ this.flushResizeFrame();
341
+ this.resizing = false;
342
+ this.applyWidth(this.currentWidth, this.resizeCells);
343
+ this.setActiveState(false);
344
+ this.clearResizeCache();
345
+ this.scheduleContentMeasurement();
346
+ if (this.currentWidth <= 0)
347
+ return;
348
+ this.columnsService.changeWidth(this.column().columnDef, { width: `${this.currentWidth}px` });
349
+ if (emit) {
350
+ this.zone.run(() => this.eventsService.emit('columnResizeEnd', {
351
+ columnDef: this.column().columnDef,
352
+ width: this.currentWidth,
353
+ previousWidth: this.startWidth,
354
+ }));
255
355
  }
256
356
  }
257
- applyWidth(px) {
258
- const root = this.el.nativeElement.closest('table, mat-table, cdk-table');
259
- if (!root)
357
+ onKeyDown(event) {
358
+ if (!['ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(event.key))
260
359
  return;
261
- const selectors = [`.mat-column-${this.column().columnDef}`, `.cdk-column-${this.column().columnDef}`];
262
- const cells = root.querySelectorAll(selectors.join(','));
263
- for (const cell of Array.from(cells)) {
264
- // table natif
360
+ event.preventDefault();
361
+ event.stopPropagation();
362
+ const previousWidth = this.el.nativeElement.getBoundingClientRect().width;
363
+ const step = event.shiftKey ? this.keyboardStep * 4 : this.keyboardStep;
364
+ let next = previousWidth;
365
+ if (event.key === 'ArrowLeft')
366
+ next -= step;
367
+ if (event.key === 'ArrowRight')
368
+ next += step;
369
+ if (event.key === 'Home')
370
+ next = this.getMinWidth();
371
+ if (event.key === 'End')
372
+ next = this.getMaxWidth();
373
+ this.commitAccessibleResize(previousWidth, this.clampWidth(next));
374
+ }
375
+ autoFit(event) {
376
+ event.preventDefault();
377
+ event.stopPropagation();
378
+ const previousWidth = this.el.nativeElement.getBoundingClientRect().width;
379
+ this.commitAccessibleResize(previousWidth, this.measureContentWidth());
380
+ }
381
+ commitAccessibleResize(previousWidth, nextWidth) {
382
+ if (Math.round(previousWidth) === Math.round(nextWidth))
383
+ return;
384
+ this.startWidth = previousWidth;
385
+ this.currentWidth = previousWidth;
386
+ this.emitResizeStart(previousWidth);
387
+ this.resizeTo(nextWidth, true, false);
388
+ this.columnsService.changeWidth(this.column().columnDef, { width: `${nextWidth}px` });
389
+ this.eventsService.emit('columnResizeEnd', {
390
+ columnDef: this.column().columnDef,
391
+ width: nextWidth,
392
+ previousWidth,
393
+ });
394
+ }
395
+ resizeTo(width, emit, previewOnly = this.resizing) {
396
+ const next = this.resizing
397
+ ? Math.min(this.resizeMaxWidth, Math.max(this.resizeMinWidth, width))
398
+ : this.clampWidth(width);
399
+ if (Math.round(next) === Math.round(this.currentWidth))
400
+ return;
401
+ const previousWidth = this.currentWidth;
402
+ this.currentWidth = next;
403
+ previewOnly ? this.applyPreviewWidth(next) : this.applyWidth(next);
404
+ this.updateWidthLabel(next);
405
+ if (emit) {
406
+ this.zone.run(() => this.eventsService.emit('columnResize', {
407
+ columnDef: this.column().columnDef,
408
+ width: next,
409
+ previousWidth,
410
+ }));
411
+ }
412
+ }
413
+ emitResizeStart(width) {
414
+ this.zone.run(() => this.eventsService.emit('columnResizeStart', {
415
+ columnDef: this.column().columnDef,
416
+ width,
417
+ previousWidth: width,
418
+ }));
419
+ }
420
+ applyWidth(px, cells = this.getColumnCells()) {
421
+ if (this.resizeCol)
422
+ this.resizeCol.style.width = `${px}px`;
423
+ for (const cell of cells) {
265
424
  cell.style.width = `${px}px`;
266
425
  cell.style.minWidth = `${px}px`;
267
426
  cell.style.maxWidth = `${px}px`;
268
- // mode flex
269
427
  cell.style.flex = `0 0 ${px}px`;
270
428
  }
429
+ this.handle?.setAttribute('aria-valuenow', `${Math.round(px)}`);
271
430
  }
272
- apply() {
273
- this.remove();
274
- this.child = this.renderer.createElement('span');
275
- this.renderer.addClass(this.child, 'resize-handle');
276
- this.renderer.appendChild(this.el.nativeElement, this.child);
277
- this.renderer.listen(this.child, 'mousedown', (e) => this.onDown(e));
278
- this.renderer.listen(this.child, 'touchstart', (e) => this.onTouchDown(e));
431
+ applyPreviewWidth(px) {
432
+ this.resizeRoot?.style.setProperty('--kles-column-resize-width', `${px}px`);
433
+ if (this.resizeCol) {
434
+ this.resizeCol.style.width = `${px}px`;
435
+ }
436
+ else {
437
+ // Fallback for consumers rendering without the table colgroup.
438
+ for (const cell of this.resizeCells)
439
+ cell.style.width = `${px}px`;
440
+ }
441
+ this.handle?.setAttribute('aria-valuenow', `${Math.round(px)}`);
279
442
  }
280
- remove() {
281
- if (this.child) {
282
- this.renderer.removeChild(this.el.nativeElement, this.child);
283
- this.child = undefined;
443
+ scheduleResizeFrame() {
444
+ if (this.animationFrameId !== undefined)
445
+ return;
446
+ const view = this.el.nativeElement.ownerDocument.defaultView;
447
+ if (!view) {
448
+ this.flushPendingWidth();
449
+ return;
284
450
  }
451
+ this.animationFrameId = view.requestAnimationFrame(() => {
452
+ this.animationFrameId = undefined;
453
+ this.flushPendingWidth();
454
+ });
285
455
  }
286
- ngOnDestroy() {
287
- this.stopResize();
456
+ flushResizeFrame() {
457
+ const view = this.el.nativeElement.ownerDocument.defaultView;
458
+ if (this.animationFrameId !== undefined && view)
459
+ view.cancelAnimationFrame(this.animationFrameId);
460
+ this.animationFrameId = undefined;
461
+ this.flushPendingWidth();
288
462
  }
289
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: ResizableColumnDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.NgZone }, { token: EventsService }], target: i0.ɵɵFactoryTarget.Directive }); }
463
+ flushPendingWidth() {
464
+ if (this.pendingWidth === undefined)
465
+ return;
466
+ const width = this.pendingWidth;
467
+ this.pendingWidth = undefined;
468
+ this.resizeTo(width, true, true);
469
+ }
470
+ cacheResizeTargets() {
471
+ const root = this.el.nativeElement.closest('table, mat-table, cdk-table');
472
+ this.resizeRoot = root ? root : undefined;
473
+ this.resizeCells = this.getColumnCells();
474
+ this.resizeCol = root
475
+ ? Array.from(root.querySelectorAll('col[data-column-def]')).find((col) => col.dataset['columnDef'] === this.column().columnDef)
476
+ : undefined;
477
+ this.resizeMinWidth = Math.max(this.getMinWidth(), this.contentMinWidth);
478
+ this.resizeMaxWidth = Math.max(this.resizeMinWidth, this.getMaxWidth());
479
+ this.handle?.setAttribute('aria-valuemin', `${Math.round(this.resizeMinWidth)}`);
480
+ }
481
+ clearResizeCache() {
482
+ this.resizeRoot?.style.removeProperty('--kles-column-resize-width');
483
+ this.pendingWidth = undefined;
484
+ this.resizeCells = [];
485
+ this.resizeCol = undefined;
486
+ this.resizeRoot = undefined;
487
+ this.resizeMinWidth = this.defaultMinWidth;
488
+ this.resizeMaxWidth = this.defaultMaxWidth;
489
+ }
490
+ scheduleContentMeasurement() {
491
+ if (this.resizing || this.contentMeasurementFrameId !== undefined)
492
+ return;
493
+ const view = this.el.nativeElement.ownerDocument.defaultView;
494
+ if (!view)
495
+ return;
496
+ this.contentMeasurementFrameId = view.requestAnimationFrame(() => {
497
+ this.contentMeasurementFrameId = undefined;
498
+ if (this.resizing || !this.handle)
499
+ return;
500
+ this.contentMinWidth = this.measureContentWidth();
501
+ this.handle.setAttribute('aria-valuemin', `${Math.round(Math.max(this.getMinWidth(), this.contentMinWidth))}`);
502
+ });
503
+ }
504
+ cancelContentMeasurement() {
505
+ const view = this.el.nativeElement.ownerDocument.defaultView;
506
+ if (this.contentMeasurementFrameId !== undefined && view)
507
+ view.cancelAnimationFrame(this.contentMeasurementFrameId);
508
+ this.contentMeasurementFrameId = undefined;
509
+ }
510
+ measureContentWidth(cells = this.getColumnCells()) {
511
+ const doc = this.el.nativeElement.ownerDocument;
512
+ const measurementRoot = this.renderer.createElement('div');
513
+ const clones = [];
514
+ Object.assign(measurementRoot.style, {
515
+ position: 'fixed',
516
+ left: '-10000px',
517
+ top: '0',
518
+ display: 'flex',
519
+ flexDirection: 'column',
520
+ alignItems: 'flex-start',
521
+ visibility: 'hidden',
522
+ pointerEvents: 'none',
523
+ });
524
+ let measured = this.getMinWidth();
525
+ for (const cell of cells) {
526
+ const clone = cell.cloneNode(true);
527
+ clone.querySelector('.resize-handle')?.remove();
528
+ Object.assign(clone.style, {
529
+ position: 'static',
530
+ width: 'max-content',
531
+ minWidth: '0',
532
+ maxWidth: 'none',
533
+ whiteSpace: 'nowrap',
534
+ flex: 'none',
535
+ });
536
+ clones.push(clone);
537
+ measurementRoot.appendChild(clone);
538
+ }
539
+ doc.body.appendChild(measurementRoot);
540
+ for (const clone of clones) {
541
+ measured = Math.max(measured, clone.getBoundingClientRect().width);
542
+ }
543
+ measurementRoot.remove();
544
+ return this.clampWidth(Math.ceil(measured));
545
+ }
546
+ setActiveState(active) {
547
+ const th = this.el.nativeElement;
548
+ const method = active ? 'addClass' : 'removeClass';
549
+ this.renderer[method](th, 'column-resizing');
550
+ this.renderer[method](th.ownerDocument.body, 'kles-column-resizing');
551
+ if (active) {
552
+ this.renderer.setStyle(th.ownerDocument.body, 'cursor', 'col-resize');
553
+ this.renderer.setStyle(th.ownerDocument.body, 'user-select', 'none');
554
+ }
555
+ else {
556
+ this.renderer.removeStyle(th.ownerDocument.body, 'cursor');
557
+ this.renderer.removeStyle(th.ownerDocument.body, 'user-select');
558
+ }
559
+ this.activeCells = active ? this.resizeCells : this.activeCells;
560
+ for (const cell of this.activeCells)
561
+ this.renderer[method](cell, 'column-resizing-cell');
562
+ if (!active)
563
+ this.activeCells = [];
564
+ }
565
+ updateWidthLabel(width) {
566
+ if (this.widthLabel)
567
+ this.widthLabel.textContent = `${Math.round(width)} px`;
568
+ }
569
+ getColumnCells() {
570
+ const root = this.el.nativeElement.closest('table, mat-table, cdk-table');
571
+ if (!root)
572
+ return [];
573
+ const columnDef = this.column().columnDef.replace(/[^a-z0-9_-]/gi, '-');
574
+ return Array.from(root.querySelectorAll(`.mat-column-${columnDef}, .cdk-column-${columnDef}`));
575
+ }
576
+ clampWidth(width) {
577
+ return Math.min(this.getMaxWidth(), Math.max(this.getMinWidth(), width));
578
+ }
579
+ getMinWidth() {
580
+ return this.resolveCssWidth(this.column().minWidth, this.defaultMinWidth);
581
+ }
582
+ getMaxWidth() {
583
+ return Math.max(this.getMinWidth(), this.resolveCssWidth(this.column().maxWidth, this.defaultMaxWidth));
584
+ }
585
+ resolveCssWidth(value, fallback) {
586
+ if (!value)
587
+ return fallback;
588
+ const numeric = Number.parseFloat(value);
589
+ if (value.trim().endsWith('px') && Number.isFinite(numeric))
590
+ return numeric;
591
+ const probe = this.renderer.createElement('span');
592
+ Object.assign(probe.style, { position: 'absolute', visibility: 'hidden', pointerEvents: 'none', width: value });
593
+ this.renderer.appendChild(this.el.nativeElement, probe);
594
+ const width = probe.getBoundingClientRect().width;
595
+ this.renderer.removeChild(this.el.nativeElement, probe);
596
+ return width > 0 ? width : fallback;
597
+ }
598
+ apply() {
599
+ this.remove();
600
+ const th = this.el.nativeElement;
601
+ this.handle = this.renderer.createElement('span');
602
+ this.widthLabel = this.renderer.createElement('span');
603
+ this.renderer.addClass(th, 'resizable-column');
604
+ this.renderer.addClass(this.handle, 'resize-handle');
605
+ this.renderer.addClass(this.widthLabel, 'resize-width-label');
606
+ this.renderer.appendChild(this.handle, this.widthLabel);
607
+ this.renderer.appendChild(th, this.handle);
608
+ this.renderer.setAttribute(this.handle, 'role', 'separator');
609
+ this.renderer.setAttribute(this.handle, 'aria-orientation', 'vertical');
610
+ this.renderer.setAttribute(this.handle, 'aria-label', `Redimensionner la colonne ${this.column().columnDef}`);
611
+ this.renderer.setAttribute(this.handle, 'aria-valuemin', `${Math.round(this.getMinWidth())}`);
612
+ this.renderer.setAttribute(this.handle, 'aria-valuemax', `${Math.round(this.getMaxWidth())}`);
613
+ this.renderer.setAttribute(this.handle, 'aria-valuenow', `${Math.round(th.getBoundingClientRect().width)}`);
614
+ this.renderer.setAttribute(this.handle, 'tabindex', '0');
615
+ this.handleCleanups.push(this.renderer.listen(this.handle, 'pointerdown', (event) => this.startResize(event)), this.renderer.listen(this.handle, 'pointerenter', () => this.scheduleContentMeasurement()), this.renderer.listen(this.handle, 'dblclick', (event) => this.autoFit(event)), this.renderer.listen(this.handle, 'keydown', (event) => this.onKeyDown(event)), this.renderer.listen(this.handle, 'click', (event) => event.stopPropagation()));
616
+ this.scheduleContentMeasurement();
617
+ }
618
+ remove() {
619
+ if (this.resizing)
620
+ this.stopResize(false);
621
+ this.flushResizeFrame();
622
+ this.cancelContentMeasurement();
623
+ this.clearResizeCache();
624
+ this.clearDocumentListeners();
625
+ this.handleCleanups.splice(0).forEach((cleanup) => cleanup());
626
+ if (this.handle)
627
+ this.renderer.removeChild(this.el.nativeElement, this.handle);
628
+ this.renderer.removeClass(this.el.nativeElement, 'resizable-column');
629
+ this.handle = undefined;
630
+ this.widthLabel = undefined;
631
+ }
632
+ clearDocumentListeners() {
633
+ this.documentCleanups.splice(0).forEach((cleanup) => cleanup());
634
+ }
635
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: ResizableColumnDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.NgZone }, { token: EventsService }, { token: ColumnsService }], target: i0.ɵɵFactoryTarget.Directive }); }
290
636
  static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.19", type: ResizableColumnDirective, isStandalone: true, selector: "th[appResizableColumn]", inputs: { column: { classPropertyName: "column", publicName: "appResizableColumn", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "attr.appResizableColumn": "this.appResizableColumnAttr" } }, usesOnChanges: true, ngImport: i0 }); }
291
637
  }
292
638
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: ResizableColumnDirective, decorators: [{
293
639
  type: Directive,
294
- args: [{
295
- selector: 'th[appResizableColumn]',
296
- standalone: true,
297
- }]
298
- }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i0.NgZone }, { type: EventsService }], propDecorators: { column: [{ type: i0.Input, args: [{ isSignal: true, alias: "appResizableColumn", required: true }] }], appResizableColumnAttr: [{
640
+ args: [{ selector: 'th[appResizableColumn]', standalone: true }]
641
+ }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i0.NgZone }, { type: EventsService }, { type: ColumnsService }], propDecorators: { column: [{ type: i0.Input, args: [{ isSignal: true, alias: "appResizableColumn", required: true }] }], appResizableColumnAttr: [{
299
642
  type: HostBinding,
300
643
  args: ['attr.appResizableColumn']
301
644
  }] } });
@@ -361,7 +704,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
361
704
  }] });
362
705
 
363
706
  class ExpandedRowStore {
364
- constructor() {
707
+ constructor(multiUnfold = false) {
708
+ this.multiUnfold = multiUnfold;
365
709
  this._expandedIds$ = new BehaviorSubject(new Set());
366
710
  this.expandedIds$ = this._expandedIds$.asObservable();
367
711
  }
@@ -375,7 +719,7 @@ class ExpandedRowStore {
375
719
  return this._expandedIds$.value;
376
720
  }
377
721
  expand(id) {
378
- const next = new Set(this._expandedIds$.value);
722
+ const next = this.multiUnfold ? new Set(this._expandedIds$.value) : new Set();
379
723
  next.add(id);
380
724
  this._expandedIds$.next(next);
381
725
  }
@@ -385,16 +729,22 @@ class ExpandedRowStore {
385
729
  this._expandedIds$.next(next);
386
730
  }
387
731
  toggle(id) {
388
- const next = new Set(this._expandedIds$.value);
389
- next.has(id) ? next.delete(id) : next.add(id);
390
- this._expandedIds$.next(next);
732
+ if (this.isExpanded(id)) {
733
+ this.collapse(id);
734
+ }
735
+ else {
736
+ this.expand(id);
737
+ }
391
738
  }
392
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: ExpandedRowStore, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
739
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: ExpandedRowStore, deps: [{ token: MULTI_UNFOLD }], target: i0.ɵɵFactoryTarget.Injectable }); }
393
740
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: ExpandedRowStore }); }
394
741
  }
395
742
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: ExpandedRowStore, decorators: [{
396
743
  type: Injectable
397
- }] });
744
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
745
+ type: Inject,
746
+ args: [MULTI_UNFOLD]
747
+ }] }] });
398
748
 
399
749
  class LoaderChildrensService {
400
750
  constructor(loaderConfig) {
@@ -424,136 +774,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
424
774
  args: [LOADER_CONFIG]
425
775
  }] }] });
426
776
 
427
- class LoadingService {
428
- constructor() {
429
- this._loading = signal(false, ...(ngDevMode ? [{ debugName: "_loading" }] : /* istanbul ignore next */ []));
430
- }
431
- get loading() {
432
- return this._loading.asReadonly();
433
- }
434
- start() {
435
- this._loading.set(true);
436
- }
437
- stop() {
438
- this._loading.set(false);
439
- }
440
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: LoadingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
441
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: LoadingService }); }
442
- }
443
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: LoadingService, decorators: [{
444
- type: Injectable
445
- }] });
446
-
447
- class ColumnsService {
448
- constructor(_columns, eventsService) {
449
- this._columns = _columns;
450
- this.eventsService = eventsService;
451
- this.stickyStartBoundary = computed(() => {
452
- return this.getVisibleColumns()
453
- .filter((column) => column.sticky === true)
454
- .at(-1)?.columnDef;
455
- }, ...(ngDevMode ? [{ debugName: "stickyStartBoundary" }] : /* istanbul ignore next */ []));
456
- this.stickyEndBoundary = computed(() => {
457
- return this.getVisibleColumns()
458
- .filter((column) => column.stickyEnd === true)
459
- .at(0)?.columnDef;
460
- }, ...(ngDevMode ? [{ debugName: "stickyEndBoundary" }] : /* istanbul ignore next */ []));
461
- }
462
- register() {
463
- this.setDisplayedColumns();
464
- }
465
- get columns() {
466
- return this._columns.asReadonly();
467
- }
468
- getVisible() {
469
- return this.getVisibleColumns().map((column) => column.columnDef);
470
- }
471
- setVisible(columnDef, visible) {
472
- this.updateColumn(columnDef, { visible });
473
- this.eventsService.emit('columnVisibilityChange', {
474
- columnDef,
475
- columns: this.getVisible(),
476
- visible,
477
- });
478
- }
479
- toggleVisible(columnDef) {
480
- const visible = this._columns().find((col) => col.columnDef === columnDef)?.visible;
481
- this.setVisible(columnDef, visible === undefined ? false : !visible);
482
- }
483
- changeWidth(columnDef, options) {
484
- this.updateColumn(columnDef, {
485
- ...(options.width && { width: options.width }),
486
- ...(options.maxWidth && { maxWidth: options.maxWidth }),
487
- ...(options.minWidth && { minWidth: options.minWidth }),
488
- });
489
- }
490
- setResizable(columnDef, resizable) {
491
- this.updateColumn(columnDef, { resizable });
492
- }
493
- toggleResizable(columnDef) {
494
- const resizable = this._columns().find((col) => col.columnDef === columnDef)?.resizable;
495
- this.setResizable(columnDef, resizable === undefined ? true : !resizable);
496
- }
497
- setSticky(columnDef, options) {
498
- this.updateColumn(columnDef, {
499
- ...(options.sticky && { sticky: options.sticky }),
500
- ...(options.stickyEnd && { stickyEnd: options.stickyEnd }),
501
- });
502
- }
503
- setColumnPosition(columnDef, position) {
504
- const previousIndex = this._columns().findIndex((c) => c.columnDef === columnDef);
505
- this._columns.update((columns) => {
506
- if (previousIndex >= 0 && position >= 0 && previousIndex != position) {
507
- const currentElement = columns.at(position);
508
- const [val] = columns.splice(previousIndex, 1);
509
- const newCurrentElementPosition = columns.findIndex((c) => c.columnDef === currentElement?.columnDef);
510
- columns.splice(newCurrentElementPosition, 0, val);
511
- return [...columns];
512
- }
513
- else {
514
- return columns;
515
- }
516
- });
517
- this.eventsService.emit('columnOrderChange', {
518
- previousIndex: previousIndex,
519
- columns: this.getVisible(),
520
- currentIndex: position,
521
- });
522
- }
523
- updateColumn(columnDef, config) {
524
- this._columns.update((columns) => columns.map((col) => col.columnDef === columnDef
525
- ? {
526
- ...col,
527
- ...config,
528
- cell: config.cell ? { ...col.cell, ...config.cell } : col.cell,
529
- headerCell: config.headerCell ? { ...col.headerCell, ...config.headerCell } : col.headerCell,
530
- footerCell: config.footerCell ? { ...col.footerCell, ...config.footerCell } : col.footerCell,
531
- }
532
- : col));
533
- }
534
- setDisplayedColumns() {
535
- this.displayedColumns = computed(() => {
536
- return this.getVisibleColumns().map((column) => column.columnDef);
537
- }, ...(ngDevMode ? [{ debugName: "displayedColumns" }] : /* istanbul ignore next */ []));
538
- }
539
- getVisibleColumns() {
540
- return this._columns().filter((column) => {
541
- if (column.visibleWhen !== undefined) {
542
- return column.visibleWhen();
543
- }
544
- return column.visible !== false;
545
- });
546
- }
547
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: ColumnsService, deps: [{ token: COLUMNS }, { token: EventsService }], target: i0.ɵɵFactoryTarget.Injectable }); }
548
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: ColumnsService }); }
549
- }
550
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: ColumnsService, decorators: [{
551
- type: Injectable
552
- }], ctorParameters: () => [{ type: undefined, decorators: [{
553
- type: Inject,
554
- args: [COLUMNS]
555
- }] }, { type: EventsService }] });
556
-
557
777
  class RowFormFactory {
558
778
  createControl(field, value) {
559
779
  let control;
@@ -656,7 +876,9 @@ class KlesForm {
656
876
  });
657
877
  this.uiStore = new WeakMap();
658
878
  this.rowsStructureChangedSubject = new Subject();
879
+ this.rowsReplacedSubject = new Subject();
659
880
  this.rowsStructureChanged$ = this.rowsStructureChangedSubject.asObservable();
881
+ this.rowsReplaced$ = this.rowsReplacedSubject.asObservable();
660
882
  }
661
883
  getRows() {
662
884
  return this.form.get('rows');
@@ -688,6 +910,7 @@ class KlesForm {
688
910
  this.getRows().push(r.formGroup, { emitEvent: false });
689
911
  this.getUiRows().push(r.groupUi);
690
912
  });
913
+ this.rowsReplacedSubject.next();
691
914
  this.notifyRowsStructureChanged();
692
915
  }
693
916
  insertRowAndNotify(row, index, options, notify) {
@@ -710,11 +933,166 @@ class KlesForm {
710
933
  return this.insertRowAndNotify(row, index, options, true);
711
934
  }
712
935
  insertRows(rows, index) {
713
- rows.forEach((r) => {
714
- this.insertRowAndNotify(r, index);
936
+ rows.forEach((r, offset) => {
937
+ this.insertRowAndNotify(r, index === undefined ? undefined : index + offset, { emitEvent: false }, false);
715
938
  });
939
+ this.getRows().updateValueAndValidity({ emitEvent: true });
716
940
  this.notifyRowsStructureChanged();
717
941
  }
942
+ moveRow(row, targetRow) {
943
+ const rows = this.getRows();
944
+ const previousIndex = rows.controls.indexOf(row);
945
+ const targetIndex = rows.controls.indexOf(targetRow);
946
+ if (previousIndex < 0 || targetIndex < 0 || previousIndex === targetIndex) {
947
+ return undefined;
948
+ }
949
+ const rowUi = this.uiStore.get(row) ?? this.getUiRows().at(previousIndex);
950
+ rows.removeAt(previousIndex, { emitEvent: false });
951
+ this.getUiRows().removeAt(previousIndex);
952
+ // En descendant, la suppression décale la cible d'une position : utiliser
953
+ // son index initial insère donc naturellement la ligne après celle-ci.
954
+ rows.insert(targetIndex, row, { emitEvent: false });
955
+ this.getUiRows().insert(targetIndex, rowUi);
956
+ rows.updateValueAndValidity({ emitEvent: true });
957
+ this.notifyRowsStructureChanged();
958
+ return {
959
+ previousIndex,
960
+ currentIndex: rows.controls.indexOf(row),
961
+ };
962
+ }
963
+ canMoveSubtree(row, targetRow) {
964
+ if (row === targetRow)
965
+ return true;
966
+ const rowValue = row.getRawValue();
967
+ const targetValue = targetRow.getRawValue();
968
+ if (rowValue._parentId !== targetValue._parentId || (rowValue._depth ?? 0) !== (targetValue._depth ?? 0))
969
+ return false;
970
+ return !this.getSubtreeRows(row).includes(targetRow);
971
+ }
972
+ moveSubtree(row, targetRow) {
973
+ const rows = this.getRows();
974
+ const previousIndex = rows.controls.indexOf(row);
975
+ const targetIndex = rows.controls.indexOf(targetRow);
976
+ if (previousIndex < 0 || targetIndex < 0 || previousIndex === targetIndex || !this.canMoveSubtree(row, targetRow))
977
+ return undefined;
978
+ const movedRows = this.getSubtreeRows(row);
979
+ const movedSet = new Set(movedRows);
980
+ const movedUis = movedRows.map((movedRow) => this.uiStore.get(movedRow) ?? this.getUiRows().at(rows.controls.indexOf(movedRow)));
981
+ const parentId = row.getRawValue()._parentId;
982
+ const previousSiblingIndex = this.getSiblingIndex(row);
983
+ let targetSubtreeEnd = targetIndex + this.getSubtreeRows(targetRow).length;
984
+ let insertionIndex = previousIndex < targetIndex ? targetSubtreeEnd : targetIndex;
985
+ for (let index = rows.length - 1; index >= 0; index--) {
986
+ if (!movedSet.has(rows.at(index)))
987
+ continue;
988
+ rows.removeAt(index, { emitEvent: false });
989
+ this.getUiRows().removeAt(index);
990
+ if (index < insertionIndex)
991
+ insertionIndex--;
992
+ }
993
+ movedRows.forEach((movedRow, offset) => {
994
+ rows.insert(insertionIndex + offset, movedRow, { emitEvent: false });
995
+ this.getUiRows().insert(insertionIndex + offset, movedUis[offset]);
996
+ });
997
+ rows.updateValueAndValidity({ emitEvent: true });
998
+ this.notifyRowsStructureChanged();
999
+ return {
1000
+ previousIndex,
1001
+ currentIndex: rows.controls.indexOf(row),
1002
+ previousSiblingIndex,
1003
+ currentSiblingIndex: this.getSiblingIndex(row, parentId),
1004
+ movedRows,
1005
+ };
1006
+ }
1007
+ getSubtreeRows(row) {
1008
+ const rows = this.getRows().controls;
1009
+ const index = rows.indexOf(row);
1010
+ if (index < 0)
1011
+ return [];
1012
+ const depth = row.getRawValue()._depth ?? 0;
1013
+ const subtree = [row];
1014
+ for (let current = index + 1; current < rows.length; current++) {
1015
+ if ((rows[current].getRawValue()._depth ?? 0) <= depth)
1016
+ break;
1017
+ subtree.push(rows[current]);
1018
+ }
1019
+ return subtree;
1020
+ }
1021
+ getSiblingIndex(row, parentId = row.getRawValue()._parentId) {
1022
+ return this.getRows()
1023
+ .controls.filter((candidate) => candidate.getRawValue()._parentId === parentId)
1024
+ .indexOf(row);
1025
+ }
1026
+ transferRowTo(target, row, targetRow) {
1027
+ if (target === this) {
1028
+ return targetRow ? this.moveRow(row, targetRow) : undefined;
1029
+ }
1030
+ const previousIndex = this.getRows().controls.indexOf(row);
1031
+ if (previousIndex < 0) {
1032
+ return undefined;
1033
+ }
1034
+ const rowUi = this.uiStore.get(row) ?? this.getUiRows().at(previousIndex);
1035
+ const rowContext = this.rowContextStore.get(row)?.();
1036
+ const targetIndex = targetRow ? target.getRows().controls.indexOf(targetRow) : target.getRows().length;
1037
+ const currentIndex = targetIndex < 0 ? target.getRows().length : targetIndex;
1038
+ this.getRows().removeAt(previousIndex, { emitEvent: false });
1039
+ this.getUiRows().removeAt(previousIndex);
1040
+ this.rowContextStore.delete(row);
1041
+ target.getRows().insert(currentIndex, row, { emitEvent: false });
1042
+ target.getUiRows().insert(currentIndex, rowUi);
1043
+ target.uiStore.set(row, rowUi);
1044
+ if (rowContext) {
1045
+ target.rowContextStore.set(row, rowContext);
1046
+ }
1047
+ this.getRows().updateValueAndValidity({ emitEvent: true });
1048
+ target.getRows().updateValueAndValidity({ emitEvent: true });
1049
+ this.notifyRowsStructureChanged();
1050
+ target.notifyRowsStructureChanged();
1051
+ return { previousIndex, currentIndex };
1052
+ }
1053
+ transferSubtreeTo(target, row, targetRow) {
1054
+ if (target === this)
1055
+ return targetRow ? this.moveSubtree(row, targetRow) : undefined;
1056
+ const previousIndex = this.getRows().controls.indexOf(row);
1057
+ if (previousIndex < 0 || (row.getRawValue()._depth ?? 0) !== 0)
1058
+ return undefined;
1059
+ if (targetRow && ((targetRow.getRawValue()._depth ?? 0) !== 0 || targetRow.getRawValue()._parentId != null))
1060
+ return undefined;
1061
+ const movedRows = this.getSubtreeRows(row);
1062
+ const previousSiblingIndex = this.getSiblingIndex(row);
1063
+ const movedData = movedRows.map((movedRow) => ({
1064
+ row: movedRow,
1065
+ ui: this.uiStore.get(movedRow) ?? this.getUiRows().at(this.getRows().controls.indexOf(movedRow)),
1066
+ context: this.rowContextStore.get(movedRow)?.(),
1067
+ }));
1068
+ for (let index = this.getRows().length - 1; index >= 0; index--) {
1069
+ if (!movedRows.includes(this.getRows().at(index)))
1070
+ continue;
1071
+ const movedRow = this.getRows().at(index);
1072
+ this.getRows().removeAt(index, { emitEvent: false });
1073
+ this.getUiRows().removeAt(index);
1074
+ this.rowContextStore.delete(movedRow);
1075
+ }
1076
+ const insertionIndex = targetRow ? target.getRows().controls.indexOf(targetRow) : target.getRows().length;
1077
+ movedData.forEach(({ row: movedRow, ui, context }, offset) => {
1078
+ target.getRows().insert(insertionIndex + offset, movedRow, { emitEvent: false });
1079
+ target.getUiRows().insert(insertionIndex + offset, ui);
1080
+ target.uiStore.set(movedRow, ui);
1081
+ if (context)
1082
+ target.rowContextStore.set(movedRow, context);
1083
+ });
1084
+ this.getRows().updateValueAndValidity({ emitEvent: true });
1085
+ target.getRows().updateValueAndValidity({ emitEvent: true });
1086
+ this.notifyRowsStructureChanged();
1087
+ target.notifyRowsStructureChanged();
1088
+ return {
1089
+ previousIndex,
1090
+ currentIndex: target.getRows().controls.indexOf(row),
1091
+ previousSiblingIndex,
1092
+ currentSiblingIndex: target.getSiblingIndex(row, null),
1093
+ movedRows,
1094
+ };
1095
+ }
718
1096
  updateRow(_id, value, options) {
719
1097
  const row = this.getRows().controls.find((c) => c.getRawValue()._id === _id);
720
1098
  if (row) {
@@ -732,14 +1110,25 @@ class KlesForm {
732
1110
  }
733
1111
  }
734
1112
  deleteRowById(id, option) {
735
- const index = this.getRows().controls.findIndex((c) => c.getRawValue()._id === id);
736
- if (index !== -1) {
1113
+ this.deleteRowsByIds([id], option);
1114
+ }
1115
+ deleteRowsByIds(ids, option) {
1116
+ const idSet = new Set(ids);
1117
+ const indexes = this.getRows()
1118
+ .controls.map((row, index) => ({ row, index }))
1119
+ .filter(({ row }) => idSet.has(row.getRawValue()._id))
1120
+ .map(({ index }) => index)
1121
+ .sort((a, b) => b - a);
1122
+ if (indexes.length === 0)
1123
+ return;
1124
+ for (const index of indexes) {
737
1125
  const row = this.getRows().at(index);
738
- this.getRows().removeAt(index, option);
1126
+ this.getRows().removeAt(index, { emitEvent: false });
739
1127
  this.rowContextStore.delete(row);
740
1128
  this.getUiRows().removeAt(index);
741
- this.notifyRowsStructureChanged();
742
1129
  }
1130
+ this.getRows().updateValueAndValidity(option);
1131
+ this.notifyRowsStructureChanged();
743
1132
  }
744
1133
  setHeaderControl(name, header, options) {
745
1134
  this.getHeader().setControl(name, header, options);
@@ -800,64 +1189,162 @@ class TreeService {
800
1189
  constructor() {
801
1190
  this.loaderConfig = inject(LOADER_CONFIG);
802
1191
  this.loaderChildrensService = inject(LoaderChildrensService);
803
- this.loadingService = inject(LoadingService);
804
1192
  this.fm = inject(KlesForm);
805
1193
  this.columnsService = inject(ColumnsService);
806
1194
  this.rowFactory = inject(RowFormFactory);
807
- this.loading = new Set();
808
- this._expandedIds$ = new BehaviorSubject(new Set());
809
- this.expandedIds$ = this._expandedIds$.asObservable();
810
- }
811
- findParentIndex(id) {
812
- return this.fm.getRows().controls.findIndex((c) => c.getRawValue()._id === id);
1195
+ this.eventsService = inject(EventsService);
1196
+ this.destroyRef = inject(DestroyRef);
1197
+ this.expandedSubject = new BehaviorSubject(new Set());
1198
+ this.expandedIds$ = this.expandedSubject.asObservable();
1199
+ this.expandedIds = signal(new Set(), ...(ngDevMode ? [{ debugName: "expandedIds" }] : /* istanbul ignore next */ []));
1200
+ this.loadingIds = signal(new Set(), ...(ngDevMode ? [{ debugName: "loadingIds" }] : /* istanbul ignore next */ []));
1201
+ this.fm.rowsReplaced$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => this.reset());
813
1202
  }
814
1203
  toggle(id, group, depth) {
815
- const expanded = new Set(this._expandedIds$.value);
816
- if (expanded.has(id)) {
817
- this.fm
818
- .getRows()
819
- .controls.filter((control) => control.getRawValue()._parentId === id)
820
- .map((control) => control.getRawValue()._id)
821
- .forEach((_id) => this.fm.deleteRowById(_id));
822
- expanded.delete(id);
823
- this._expandedIds$.next(expanded);
824
- }
825
- else {
826
- const index = this.findParentIndex(id);
827
- this.loaderChildrensService.load(group, depth).subscribe((response) => {
828
- if (response.loading) {
829
- this.loading.add(id);
830
- // this.loadingService.start();
831
- }
832
- else {
833
- this.loading.delete(id);
834
- // this.loadingService.stop();
835
- // console.log( (group.getRawValue()._depth ?? 0) + 1)
836
- this.fm.insertRows(this.rowFactory.createRows(this.columnsService.columns().map((col) => ({ ...col.cell?.field, name: col.columnDef })), response.items, { depth: (group.getRawValue()._depth ?? 0) + 1, parentId: id }), index + 1);
837
- expanded.add(id);
838
- this._expandedIds$.next(expanded);
839
- }
1204
+ if (this.isLoading(id))
1205
+ return;
1206
+ this.isExpanded(id) ? this.collapse(id, group, depth) : this.expand(id, group, depth);
1207
+ }
1208
+ expand(id, group, depth) {
1209
+ if (this.isExpanded(id) || this.isLoading(id))
1210
+ return;
1211
+ const parent = group ?? this.findRow(id);
1212
+ if (!parent)
1213
+ return;
1214
+ const level = depth ?? parent.getRawValue()._depth ?? 0;
1215
+ if (!this.hasChildren(parent, level))
1216
+ return;
1217
+ const payload = this.rowPayload(parent, level);
1218
+ this.setLoading(id, true);
1219
+ this.eventsService.emit('nodeLoadChildren', payload);
1220
+ this.loaderChildrensService
1221
+ .load(parent, level)
1222
+ .pipe(filter((response) => !response.loading), take(1), takeUntilDestroyed(this.destroyRef))
1223
+ .subscribe((response) => {
1224
+ this.setLoading(id, false);
1225
+ if (response.error) {
1226
+ this.eventsService.emit('loadError', {
1227
+ error: response.error,
1228
+ message: response.error instanceof Error ? response.error.message : undefined,
1229
+ });
1230
+ return;
1231
+ }
1232
+ const parentIndex = this.fm.getRows().controls.indexOf(parent);
1233
+ if (parentIndex < 0)
1234
+ return;
1235
+ const children = this.rowFactory.createRows(this.columnsService.columns().map((column) => ({ ...column.cell?.field, name: column.columnDef })), response.items, { depth: level + 1, parentId: id });
1236
+ this.fm.insertRows(children, parentIndex + 1);
1237
+ this.setExpanded(id, true);
1238
+ const childRows = children.map((child) => child.formGroup);
1239
+ this.eventsService.emit('nodeChildrenLoaded', {
1240
+ ...payload,
1241
+ children: childRows,
1242
+ childValues: childRows.map((child) => child.getRawValue()),
840
1243
  });
1244
+ this.eventsService.emit('nodeExpand', payload);
1245
+ });
1246
+ }
1247
+ collapse(id, group, depth) {
1248
+ if (!this.isExpanded(id))
1249
+ return;
1250
+ const parent = group ?? this.findRow(id);
1251
+ if (!parent) {
1252
+ this.setExpanded(id, false);
1253
+ return;
841
1254
  }
1255
+ const descendants = this.getDescendants(id);
1256
+ const descendantIds = descendants.map((row) => row.getRawValue()._id);
1257
+ const expanded = new Set(this.expandedSubject.value);
1258
+ expanded.delete(id);
1259
+ descendantIds.forEach((descendantId) => expanded.delete(descendantId));
1260
+ this.publishExpanded(expanded);
1261
+ this.fm.deleteRowsByIds(descendantIds, { emitEvent: false });
1262
+ this.eventsService.emit('nodeCollapse', this.rowPayload(parent, depth ?? parent.getRawValue()._depth ?? 0));
1263
+ }
1264
+ collapseAll() {
1265
+ const childIds = this.fm
1266
+ .getRows()
1267
+ .controls.filter((row) => (row.getRawValue()._depth ?? 0) > 0)
1268
+ .map((row) => row.getRawValue()._id);
1269
+ this.publishExpanded(new Set());
1270
+ this.fm.deleteRowsByIds(childIds, { emitEvent: false });
1271
+ }
1272
+ reset() {
1273
+ this.publishExpanded(new Set());
1274
+ this.loadingIds.set(new Set());
1275
+ }
1276
+ isExpanded(id) {
1277
+ return this.expandedSubject.value.has(id);
1278
+ }
1279
+ isLoading(id) {
1280
+ return this.loadingIds().has(id);
1281
+ }
1282
+ getChildren(id) {
1283
+ return this.fm.getRows().controls.filter((row) => row.getRawValue()._parentId === id);
1284
+ }
1285
+ getDescendants(id) {
1286
+ const rows = this.fm.getRows().controls;
1287
+ const parentIndex = rows.findIndex((row) => row.getRawValue()._id === id);
1288
+ if (parentIndex < 0)
1289
+ return [];
1290
+ const parentDepth = rows[parentIndex].getRawValue()._depth ?? 0;
1291
+ const descendants = [];
1292
+ for (let index = parentIndex + 1; index < rows.length; index++) {
1293
+ const row = rows[index];
1294
+ if ((row.getRawValue()._depth ?? 0) <= parentDepth)
1295
+ break;
1296
+ descendants.push(row);
1297
+ }
1298
+ return descendants;
842
1299
  }
843
1300
  hasChildren(group, depth) {
844
- return this.loaderConfig.lines.hasChildren?.(group, depth) ?? true;
1301
+ const configured = this.loaderConfig.lines.hasChildren;
1302
+ return configured ? configured(group, depth) : typeof this.loaderConfig.lines.childrens === 'function';
1303
+ }
1304
+ findRow(id) {
1305
+ return this.fm.getRows().controls.find((row) => row.getRawValue()._id === id);
1306
+ }
1307
+ setExpanded(id, expanded) {
1308
+ const ids = new Set(this.expandedSubject.value);
1309
+ expanded ? ids.add(id) : ids.delete(id);
1310
+ this.publishExpanded(ids);
1311
+ }
1312
+ publishExpanded(ids) {
1313
+ this.expandedSubject.next(ids);
1314
+ this.expandedIds.set(ids);
1315
+ }
1316
+ setLoading(id, loading) {
1317
+ const ids = new Set(this.loadingIds());
1318
+ loading ? ids.add(id) : ids.delete(id);
1319
+ this.loadingIds.set(ids);
1320
+ }
1321
+ rowPayload(row, level) {
1322
+ return {
1323
+ row,
1324
+ rowIndex: this.fm.getRows().controls.indexOf(row),
1325
+ value: row.value,
1326
+ rawValue: row.getRawValue(),
1327
+ level,
1328
+ };
845
1329
  }
846
1330
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: TreeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
847
1331
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: TreeService }); }
848
1332
  }
849
1333
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: TreeService, decorators: [{
850
1334
  type: Injectable
851
- }] });
1335
+ }], ctorParameters: () => [] });
852
1336
 
853
1337
  class KlesCellComponent {
854
1338
  constructor() {
855
1339
  this.destroyRef = inject(DestroyRef);
856
1340
  this.expandedRowStore = inject(ExpandedRowStore);
857
1341
  this.treeService = inject(TreeService);
1342
+ this.eventsService = inject(EventsService);
858
1343
  this.ui = input.required(...(ngDevMode ? [{ debugName: "ui" }] : /* istanbul ignore next */ []));
859
1344
  this.group = input.required(...(ngDevMode ? [{ debugName: "group" }] : /* istanbul ignore next */ []));
860
1345
  this.column = input.required(...(ngDevMode ? [{ debugName: "column" }] : /* istanbul ignore next */ []));
1346
+ this.rowIndex = input.required(...(ngDevMode ? [{ debugName: "rowIndex" }] : /* istanbul ignore next */ []));
1347
+ this.dragHandle = input(false, ...(ngDevMode ? [{ debugName: "dragHandle" }] : /* istanbul ignore next */ []));
861
1348
  this.expandedRow = computed(() => {
862
1349
  return (this.column().canExpand ?? false) && (this.ui().get(this.column().columnDef)?.value().expandedRow ?? false);
863
1350
  }, ...(ngDevMode ? [{ debugName: "expandedRow" }] : /* istanbul ignore next */ []));
@@ -867,6 +1354,8 @@ class KlesCellComponent {
867
1354
  this.hasChildren = computed(() => {
868
1355
  return this.treeService.hasChildren(this.group(), this.group().getRawValue()._depth);
869
1356
  }, ...(ngDevMode ? [{ debugName: "hasChildren" }] : /* istanbul ignore next */ []));
1357
+ this.depth = computed(() => Math.max(0, this.group().getRawValue()._depth ?? 0), ...(ngDevMode ? [{ debugName: "depth" }] : /* istanbul ignore next */ []));
1358
+ this.loadingNode = computed(() => this.treeService.isLoading(this.group().getRawValue()._id), ...(ngDevMode ? [{ debugName: "loadingNode" }] : /* istanbul ignore next */ []));
870
1359
  this.column$ = toObservable(this.column);
871
1360
  }
872
1361
  ngOnInit() {
@@ -876,16 +1365,27 @@ class KlesCellComponent {
876
1365
  event.stopPropagation();
877
1366
  }
878
1367
  expandRow() {
879
- this.expandedRowStore.toggle(this.group().getRawValue()._id);
1368
+ const row = this.group();
1369
+ const expanded = this.expandedRowStore.isExpanded(row.getRawValue()._id);
1370
+ this.expandedRowStore.toggle(row.getRawValue()._id);
1371
+ const payload = {
1372
+ row,
1373
+ rowIndex: this.rowIndex(),
1374
+ value: row.value,
1375
+ rawValue: row.getRawValue(),
1376
+ level: row.getRawValue()._depth,
1377
+ };
1378
+ this.eventsService.emit(expanded ? 'rowCollapse' : 'rowExpand', payload);
1379
+ this.eventsService.emit('rowToggleExpand', payload);
880
1380
  }
881
1381
  expandNode() {
882
- this.treeService.toggle(this.group().getRawValue()._id, this.group(), 0); //TODO depth
1382
+ this.treeService.toggle(this.group().getRawValue()._id, this.group(), this.group().getRawValue()._depth ?? 0);
883
1383
  }
884
1384
  listen() {
885
1385
  this.column$
886
1386
  .pipe(filter((column) => column.canExpand ?? false), switchMap(() => {
887
1387
  return this.expandedRowStore.expandedIds$.pipe(takeUntilDestroyed(this.destroyRef), map((ids) => {
888
- return ids.has(this.group().value._id);
1388
+ return ids.has(this.group().getRawValue()._id);
889
1389
  }));
890
1390
  }))
891
1391
  .subscribe((expandedRow) => {
@@ -902,21 +1402,22 @@ class KlesCellComponent {
902
1402
  });
903
1403
  }
904
1404
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: KlesCellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
905
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: KlesCellComponent, isStandalone: true, selector: "kles-cell", inputs: { ui: { classPropertyName: "ui", publicName: "ui", isSignal: true, isRequired: true, transformFunction: null }, group: { classPropertyName: "group", publicName: "group", isSignal: true, isRequired: true, transformFunction: null }, column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "@if (column().canExpand) {\n <button matIconButton class=\"expand-button\" (click)=\"expandRow(); stopPropagation($event)\">\n @if (this.expandedRow()) {\n <mat-icon>keyboard_arrow_down</mat-icon>\n } @else {\n <mat-icon>chevron_right</mat-icon>\n }\n </button>\n}\n@if (hasChildren() && column().canExpandNode) {\n <button matIconButton class=\"expand-button\" (click)=\"expandNode(); stopPropagation($event)\">\n @if (this.expandedNode()) {\n <mat-icon>keyboard_arrow_down</mat-icon>\n } @else {\n <mat-icon>chevron_right</mat-icon>\n }\n </button>\n}\n<div class=\"cell-field\"><ng-content></ng-content></div>\n", styles: [":host{display:flex;flex-direction:row;justify-content:inherit;gap:5px;align-items:center}.cell-field{flex-grow:1;justify-content:inherit;flex-direction:column;display:flex;text-align:center}.expand-button.mat-mdc-icon-button{--mdc-icon-button-state-layer-size: 28px;--mdc-icon-button-icon-size: 22px;width:28px;height:28px;padding:0;display:grid;place-items:center}.expand-button.mat-mdc-icon-button .mat-icon{width:22px;height:22px;font-size:22px;line-height:22px;margin:0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }] }); }
1405
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: KlesCellComponent, isStandalone: true, selector: "kles-cell", inputs: { ui: { classPropertyName: "ui", publicName: "ui", isSignal: true, isRequired: true, transformFunction: null }, group: { classPropertyName: "group", publicName: "group", isSignal: true, isRequired: true, transformFunction: null }, column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: true, transformFunction: null }, rowIndex: { classPropertyName: "rowIndex", publicName: "rowIndex", isSignal: true, isRequired: true, transformFunction: null }, dragHandle: { classPropertyName: "dragHandle", publicName: "dragHandle", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (dragHandle()) {\n <button\n type=\"button\"\n matIconButton\n cdkDragHandle\n class=\"drag-handle\"\n aria-label=\"D\u00E9placer la ligne\"\n (click)=\"stopPropagation($event)\"\n (dblclick)=\"stopPropagation($event)\"\n >\n <mat-icon>drag_indicator</mat-icon>\n </button>\n}\n@if (column().canExpand) {\n <button matIconButton class=\"expand-button\" (click)=\"expandRow(); stopPropagation($event)\">\n @if (this.expandedRow()) {\n <mat-icon>keyboard_arrow_down</mat-icon>\n } @else {\n <mat-icon>chevron_right</mat-icon>\n }\n </button>\n}\n@if (column().canExpandNode) {\n <span class=\"tree-indent\" [style.width.px]=\"depth() * 24\" aria-hidden=\"true\"></span>\n @if (hasChildren()) {\n <button\n matIconButton\n class=\"expand-button\"\n [disabled]=\"loadingNode()\"\n [attr.aria-expanded]=\"expandedNode()\"\n [attr.aria-label]=\"expandedNode() ? 'R\u00E9duire la ligne' : 'D\u00E9velopper la ligne'\"\n (click)=\"expandNode(); stopPropagation($event)\"\n >\n @if (loadingNode()) {\n <mat-icon class=\"tree-loading-icon\">more_horiz</mat-icon>\n } @else if (expandedNode()) {\n <mat-icon>keyboard_arrow_down</mat-icon>\n } @else {\n <mat-icon>chevron_right</mat-icon>\n }\n </button>\n } @else {\n <span class=\"expand-button-spacer\" aria-hidden=\"true\"></span>\n }\n}\n<div class=\"cell-field\"><ng-content></ng-content></div>\n", styles: [":host{display:flex;flex-direction:row;justify-content:inherit;gap:5px;align-items:center}.cell-field{min-width:0;flex-grow:1;justify-content:inherit;flex-direction:column;display:flex;text-align:center}.tree-indent{flex:0 0 auto}.expand-button-spacer{flex:0 0 28px;width:28px;height:28px}.tree-loading-icon{animation:tree-loading-pulse .8s ease-in-out infinite alternate}@keyframes tree-loading-pulse{0%{opacity:.35}to{opacity:1}}.expand-button.mat-mdc-icon-button{--mdc-icon-button-state-layer-size: 28px;--mdc-icon-button-icon-size: 22px;width:28px;height:28px;padding:0;display:grid;place-items:center}.expand-button.mat-mdc-icon-button .mat-icon{width:22px;height:22px;font-size:22px;line-height:22px;margin:0}.drag-handle.mat-mdc-icon-button{--mdc-icon-button-state-layer-size: 32px;--mdc-icon-button-icon-size: 24px;flex:0 0 32px;width:32px;height:32px;padding:0;cursor:grab;touch-action:none;display:grid;place-items:center}.drag-handle.mat-mdc-icon-button .mat-icon{width:24px;height:24px;font-size:24px;line-height:24px;margin:0}.drag-handle.mat-mdc-icon-button:active{cursor:grabbing}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "directive", type: CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }] }); }
906
1406
  }
907
1407
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: KlesCellComponent, decorators: [{
908
1408
  type: Component,
909
- args: [{ selector: 'kles-cell', standalone: true, imports: [CommonModule, MatIconModule, MatButtonModule], template: "@if (column().canExpand) {\n <button matIconButton class=\"expand-button\" (click)=\"expandRow(); stopPropagation($event)\">\n @if (this.expandedRow()) {\n <mat-icon>keyboard_arrow_down</mat-icon>\n } @else {\n <mat-icon>chevron_right</mat-icon>\n }\n </button>\n}\n@if (hasChildren() && column().canExpandNode) {\n <button matIconButton class=\"expand-button\" (click)=\"expandNode(); stopPropagation($event)\">\n @if (this.expandedNode()) {\n <mat-icon>keyboard_arrow_down</mat-icon>\n } @else {\n <mat-icon>chevron_right</mat-icon>\n }\n </button>\n}\n<div class=\"cell-field\"><ng-content></ng-content></div>\n", styles: [":host{display:flex;flex-direction:row;justify-content:inherit;gap:5px;align-items:center}.cell-field{flex-grow:1;justify-content:inherit;flex-direction:column;display:flex;text-align:center}.expand-button.mat-mdc-icon-button{--mdc-icon-button-state-layer-size: 28px;--mdc-icon-button-icon-size: 22px;width:28px;height:28px;padding:0;display:grid;place-items:center}.expand-button.mat-mdc-icon-button .mat-icon{width:22px;height:22px;font-size:22px;line-height:22px;margin:0}\n"] }]
910
- }], propDecorators: { ui: [{ type: i0.Input, args: [{ isSignal: true, alias: "ui", required: true }] }], group: [{ type: i0.Input, args: [{ isSignal: true, alias: "group", required: true }] }], column: [{ type: i0.Input, args: [{ isSignal: true, alias: "column", required: true }] }] } });
1409
+ args: [{ selector: 'kles-cell', standalone: true, imports: [CommonModule, MatIconModule, MatButtonModule, CdkDragHandle], template: "@if (dragHandle()) {\n <button\n type=\"button\"\n matIconButton\n cdkDragHandle\n class=\"drag-handle\"\n aria-label=\"D\u00E9placer la ligne\"\n (click)=\"stopPropagation($event)\"\n (dblclick)=\"stopPropagation($event)\"\n >\n <mat-icon>drag_indicator</mat-icon>\n </button>\n}\n@if (column().canExpand) {\n <button matIconButton class=\"expand-button\" (click)=\"expandRow(); stopPropagation($event)\">\n @if (this.expandedRow()) {\n <mat-icon>keyboard_arrow_down</mat-icon>\n } @else {\n <mat-icon>chevron_right</mat-icon>\n }\n </button>\n}\n@if (column().canExpandNode) {\n <span class=\"tree-indent\" [style.width.px]=\"depth() * 24\" aria-hidden=\"true\"></span>\n @if (hasChildren()) {\n <button\n matIconButton\n class=\"expand-button\"\n [disabled]=\"loadingNode()\"\n [attr.aria-expanded]=\"expandedNode()\"\n [attr.aria-label]=\"expandedNode() ? 'R\u00E9duire la ligne' : 'D\u00E9velopper la ligne'\"\n (click)=\"expandNode(); stopPropagation($event)\"\n >\n @if (loadingNode()) {\n <mat-icon class=\"tree-loading-icon\">more_horiz</mat-icon>\n } @else if (expandedNode()) {\n <mat-icon>keyboard_arrow_down</mat-icon>\n } @else {\n <mat-icon>chevron_right</mat-icon>\n }\n </button>\n } @else {\n <span class=\"expand-button-spacer\" aria-hidden=\"true\"></span>\n }\n}\n<div class=\"cell-field\"><ng-content></ng-content></div>\n", styles: [":host{display:flex;flex-direction:row;justify-content:inherit;gap:5px;align-items:center}.cell-field{min-width:0;flex-grow:1;justify-content:inherit;flex-direction:column;display:flex;text-align:center}.tree-indent{flex:0 0 auto}.expand-button-spacer{flex:0 0 28px;width:28px;height:28px}.tree-loading-icon{animation:tree-loading-pulse .8s ease-in-out infinite alternate}@keyframes tree-loading-pulse{0%{opacity:.35}to{opacity:1}}.expand-button.mat-mdc-icon-button{--mdc-icon-button-state-layer-size: 28px;--mdc-icon-button-icon-size: 22px;width:28px;height:28px;padding:0;display:grid;place-items:center}.expand-button.mat-mdc-icon-button .mat-icon{width:22px;height:22px;font-size:22px;line-height:22px;margin:0}.drag-handle.mat-mdc-icon-button{--mdc-icon-button-state-layer-size: 32px;--mdc-icon-button-icon-size: 24px;flex:0 0 32px;width:32px;height:32px;padding:0;cursor:grab;touch-action:none;display:grid;place-items:center}.drag-handle.mat-mdc-icon-button .mat-icon{width:24px;height:24px;font-size:24px;line-height:24px;margin:0}.drag-handle.mat-mdc-icon-button:active{cursor:grabbing}\n"] }]
1410
+ }], propDecorators: { ui: [{ type: i0.Input, args: [{ isSignal: true, alias: "ui", required: true }] }], group: [{ type: i0.Input, args: [{ isSignal: true, alias: "group", required: true }] }], column: [{ type: i0.Input, args: [{ isSignal: true, alias: "column", required: true }] }], rowIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowIndex", required: true }] }], dragHandle: [{ type: i0.Input, args: [{ isSignal: true, alias: "dragHandle", required: false }] }] } });
911
1411
 
912
1412
  class KlesHeaderComponent {
913
1413
  constructor() {
914
1414
  this.header = input.required(...(ngDevMode ? [{ debugName: "header" }] : /* istanbul ignore next */ []));
915
1415
  this.group = input.required(...(ngDevMode ? [{ debugName: "group" }] : /* istanbul ignore next */ []));
1416
+ this.dragHandleSpacer = input(false, ...(ngDevMode ? [{ debugName: "dragHandleSpacer" }] : /* istanbul ignore next */ []));
916
1417
  }
917
1418
  ngOnInit() { }
918
1419
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: KlesHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
919
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: KlesHeaderComponent, isStandalone: true, selector: "kles-header", inputs: { header: { classPropertyName: "header", publicName: "header", isSignal: true, isRequired: true, transformFunction: null }, group: { classPropertyName: "group", publicName: "group", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `
1420
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: KlesHeaderComponent, isStandalone: true, selector: "kles-header", inputs: { header: { classPropertyName: "header", publicName: "header", isSignal: true, isRequired: true, transformFunction: null }, group: { classPropertyName: "group", publicName: "group", isSignal: true, isRequired: true, transformFunction: null }, dragHandleSpacer: { classPropertyName: "dragHandleSpacer", publicName: "dragHandleSpacer", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
920
1421
  <div
921
1422
  class="header"
922
1423
  mat-sort-header
@@ -928,7 +1429,10 @@ class KlesHeaderComponent {
928
1429
  {{ header().label }}
929
1430
  </div>
930
1431
 
931
- <div class="filterHeader">
1432
+ <div class="filterHeader" [class.has-drag-handle-spacer]="dragHandleSpacer()">
1433
+ @if (dragHandleSpacer()) {
1434
+ <span class="drag-handle-spacer" aria-hidden="true"></span>
1435
+ }
932
1436
  <div class="field">
933
1437
  <ng-content></ng-content>
934
1438
  </div>
@@ -947,7 +1451,7 @@ class KlesHeaderComponent {
947
1451
  </div>
948
1452
  }
949
1453
  </div>
950
- `, isInline: true, styles: [":host{padding-bottom:10px;display:flex;flex-direction:column;justify-content:inherit}.header{flex-grow:1;align-items:center;display:flex;justify-content:inherit}.filterHeader{display:flex;flex-grow:1;align-items:center;gap:2px}.field{flex-grow:1;text-align:center}.icon-button button[mat-icon-button].icon-button-small{width:24px;height:24px;line-height:24px;padding:0}.icon-button button[mat-icon-button].icon-button-small .mat-icon{font-size:18px;width:18px;height:18px;line-height:18px}.icon-button button[mat-icon-button].icon-button-small .mat-mdc-button-ripple{font-size:inherit;width:inherit;height:inherit;line-height:inherit}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i3.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatSortModule }, { kind: "component", type: i4.MatSortHeader, selector: "[mat-sort-header]", inputs: ["mat-sort-header", "arrowPosition", "start", "disabled", "sortActionDescription", "disableClear"], exportAs: ["matSortHeader"] }] }); }
1454
+ `, isInline: true, styles: [":host{padding-bottom:10px;display:flex;flex-direction:column;justify-content:inherit}.header{flex-grow:1;align-items:center;display:flex;justify-content:inherit}.filterHeader{display:flex;flex-grow:1;align-items:center;gap:2px}.filterHeader.has-drag-handle-spacer{gap:5px}.drag-handle-spacer{flex:0 0 32px;width:32px;height:32px}.field{flex-grow:1;text-align:center}.icon-button button[mat-icon-button].icon-button-small{width:24px;height:24px;line-height:24px;padding:0}.icon-button button[mat-icon-button].icon-button-small .mat-icon{font-size:18px;width:18px;height:18px;line-height:18px}.icon-button button[mat-icon-button].icon-button-small .mat-mdc-button-ripple{font-size:inherit;width:inherit;height:inherit;line-height:inherit}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i3.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatSortModule }, { kind: "component", type: i4.MatSortHeader, selector: "[mat-sort-header]", inputs: ["mat-sort-header", "arrowPosition", "start", "disabled", "sortActionDescription", "disableClear"], exportAs: ["matSortHeader"] }] }); }
951
1455
  }
952
1456
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: KlesHeaderComponent, decorators: [{
953
1457
  type: Component,
@@ -963,7 +1467,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
963
1467
  {{ header().label }}
964
1468
  </div>
965
1469
 
966
- <div class="filterHeader">
1470
+ <div class="filterHeader" [class.has-drag-handle-spacer]="dragHandleSpacer()">
1471
+ @if (dragHandleSpacer()) {
1472
+ <span class="drag-handle-spacer" aria-hidden="true"></span>
1473
+ }
967
1474
  <div class="field">
968
1475
  <ng-content></ng-content>
969
1476
  </div>
@@ -982,8 +1489,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
982
1489
  </div>
983
1490
  }
984
1491
  </div>
985
- `, standalone: true, imports: [CommonModule, ReactiveFormsModule, MatIconModule, MatButtonModule, MatTooltipModule, MatSortModule], styles: [":host{padding-bottom:10px;display:flex;flex-direction:column;justify-content:inherit}.header{flex-grow:1;align-items:center;display:flex;justify-content:inherit}.filterHeader{display:flex;flex-grow:1;align-items:center;gap:2px}.field{flex-grow:1;text-align:center}.icon-button button[mat-icon-button].icon-button-small{width:24px;height:24px;line-height:24px;padding:0}.icon-button button[mat-icon-button].icon-button-small .mat-icon{font-size:18px;width:18px;height:18px;line-height:18px}.icon-button button[mat-icon-button].icon-button-small .mat-mdc-button-ripple{font-size:inherit;width:inherit;height:inherit;line-height:inherit}\n"] }]
986
- }], propDecorators: { header: [{ type: i0.Input, args: [{ isSignal: true, alias: "header", required: true }] }], group: [{ type: i0.Input, args: [{ isSignal: true, alias: "group", required: true }] }] } });
1492
+ `, standalone: true, imports: [CommonModule, ReactiveFormsModule, MatIconModule, MatButtonModule, MatTooltipModule, MatSortModule], styles: [":host{padding-bottom:10px;display:flex;flex-direction:column;justify-content:inherit}.header{flex-grow:1;align-items:center;display:flex;justify-content:inherit}.filterHeader{display:flex;flex-grow:1;align-items:center;gap:2px}.filterHeader.has-drag-handle-spacer{gap:5px}.drag-handle-spacer{flex:0 0 32px;width:32px;height:32px}.field{flex-grow:1;text-align:center}.icon-button button[mat-icon-button].icon-button-small{width:24px;height:24px;line-height:24px;padding:0}.icon-button button[mat-icon-button].icon-button-small .mat-icon{font-size:18px;width:18px;height:18px;line-height:18px}.icon-button button[mat-icon-button].icon-button-small .mat-mdc-button-ripple{font-size:inherit;width:inherit;height:inherit;line-height:inherit}\n"] }]
1493
+ }], propDecorators: { header: [{ type: i0.Input, args: [{ isSignal: true, alias: "header", required: true }] }], group: [{ type: i0.Input, args: [{ isSignal: true, alias: "group", required: true }] }], dragHandleSpacer: [{ type: i0.Input, args: [{ isSignal: true, alias: "dragHandleSpacer", required: false }] }] } });
987
1494
 
988
1495
  class HeaderPipe {
989
1496
  transform(col) {
@@ -1111,6 +1618,15 @@ class KlesTableConnectorService {
1111
1618
  get events() {
1112
1619
  return this.table.events;
1113
1620
  }
1621
+ get emptyState() {
1622
+ return this.table.emptyState;
1623
+ }
1624
+ get render() {
1625
+ return this.table.render;
1626
+ }
1627
+ get tree() {
1628
+ return this.table.tree;
1629
+ }
1114
1630
  refresh() {
1115
1631
  this.table?.refresh();
1116
1632
  }
@@ -1121,6 +1637,35 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
1121
1637
  type: Injectable
1122
1638
  }], ctorParameters: () => [] });
1123
1639
 
1640
+ class LoadingService {
1641
+ constructor(eventsService) {
1642
+ this.eventsService = eventsService;
1643
+ this._loading = signal(false, ...(ngDevMode ? [{ debugName: "_loading" }] : /* istanbul ignore next */ []));
1644
+ }
1645
+ get loading() {
1646
+ return this._loading.asReadonly();
1647
+ }
1648
+ start() {
1649
+ if (this._loading()) {
1650
+ return;
1651
+ }
1652
+ this._loading.set(true);
1653
+ this.eventsService.emit('loadingChange', { loading: true });
1654
+ }
1655
+ stop() {
1656
+ if (!this._loading()) {
1657
+ return;
1658
+ }
1659
+ this._loading.set(false);
1660
+ this.eventsService.emit('loadingChange', { loading: false });
1661
+ }
1662
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: LoadingService, deps: [{ token: EventsService }], target: i0.ɵɵFactoryTarget.Injectable }); }
1663
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: LoadingService }); }
1664
+ }
1665
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: LoadingService, decorators: [{
1666
+ type: Injectable
1667
+ }], ctorParameters: () => [{ type: EventsService }] });
1668
+
1124
1669
  class PaginatorStore {
1125
1670
  constructor(config) {
1126
1671
  this.config = config;
@@ -1301,19 +1846,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
1301
1846
  }] });
1302
1847
 
1303
1848
  class FooterService {
1304
- constructor(_footer) {
1849
+ constructor(_footer, eventsService) {
1305
1850
  this._footer = _footer;
1851
+ this.eventsService = eventsService;
1306
1852
  }
1307
1853
  get footer() {
1308
1854
  return this._footer.asReadonly();
1309
1855
  }
1310
1856
  show() {
1857
+ if (this._footer()) {
1858
+ return;
1859
+ }
1311
1860
  this._footer.set(true);
1861
+ this.eventsService.emit('footerVisibilityChange', { visible: true });
1312
1862
  }
1313
1863
  hide() {
1864
+ if (!this._footer()) {
1865
+ return;
1866
+ }
1314
1867
  this._footer.set(false);
1868
+ this.eventsService.emit('footerVisibilityChange', { visible: false });
1315
1869
  }
1316
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FooterService, deps: [{ token: FOOTER }], target: i0.ɵɵFactoryTarget.Injectable }); }
1870
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FooterService, deps: [{ token: FOOTER }, { token: EventsService }], target: i0.ɵɵFactoryTarget.Injectable }); }
1317
1871
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FooterService }); }
1318
1872
  }
1319
1873
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FooterService, decorators: [{
@@ -1321,7 +1875,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
1321
1875
  }], ctorParameters: () => [{ type: undefined, decorators: [{
1322
1876
  type: Inject,
1323
1877
  args: [FOOTER]
1324
- }] }] });
1878
+ }] }, { type: EventsService }] });
1325
1879
 
1326
1880
  class ExtraRowService {
1327
1881
  constructor(_extraRowsConfig, expandedRowStore) {
@@ -1334,15 +1888,16 @@ class ExtraRowService {
1334
1888
  displayedColumns: config.cells.map((cel) => cel.columnDef),
1335
1889
  })), ...(ngDevMode ? [{ debugName: "rows" }] : /* istanbul ignore next */ []));
1336
1890
  }
1337
- extraColumns() {
1891
+ extraFields() {
1338
1892
  return this._extraRowsConfig()
1339
1893
  .flatMap((config) => config.cells)
1340
- .filter(Boolean);
1894
+ .filter(Boolean)
1895
+ .map((cell) => ({ ...cell.field, name: cell.columnDef }));
1341
1896
  }
1342
1897
  createWhen(config) {
1343
1898
  if (config.mode === 'expand') {
1344
1899
  return (_, row) => {
1345
- return this.expandedRowStore.isExpanded(row.value._id);
1900
+ return this.expandedRowStore.isExpanded(row.getRawValue()._id);
1346
1901
  };
1347
1902
  }
1348
1903
  else {
@@ -1565,7 +2120,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
1565
2120
  type: Injectable
1566
2121
  }], ctorParameters: () => [{ type: EventsService }] });
1567
2122
 
1568
- //TODO Abstract Datasource service
1569
2123
  class DatasourceService {
1570
2124
  constructor(fm, columnsService, cellValueChangeService, validationService) {
1571
2125
  this.fm = fm;
@@ -1833,7 +2387,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
1833
2387
  }], ctorParameters: () => [{ type: EventsService }] });
1834
2388
 
1835
2389
  class EmptyStateService {
1836
- constructor(config) {
2390
+ constructor(config, eventsService) {
2391
+ this.eventsService = eventsService;
1837
2392
  this._enabled = signal(true, ...(ngDevMode ? [{ debugName: "_enabled" }] : /* istanbul ignore next */ []));
1838
2393
  this.enabled = this._enabled.asReadonly();
1839
2394
  if (typeof config === 'boolean') {
@@ -1845,15 +2400,23 @@ class EmptyStateService {
1845
2400
  this.component = config?.component ?? KlesTableEmptyStateComponent;
1846
2401
  }
1847
2402
  enable() {
2403
+ if (this._enabled()) {
2404
+ return;
2405
+ }
1848
2406
  this._enabled.set(true);
2407
+ this.eventsService.emit('emptyStateChange', { enabled: true });
1849
2408
  }
1850
2409
  disable() {
2410
+ if (!this._enabled()) {
2411
+ return;
2412
+ }
1851
2413
  this._enabled.set(false);
2414
+ this.eventsService.emit('emptyStateChange', { enabled: false });
1852
2415
  }
1853
2416
  toggle() {
1854
- this._enabled.update((enabled) => !enabled);
2417
+ this._enabled() ? this.disable() : this.enable();
1855
2418
  }
1856
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: EmptyStateService, deps: [{ token: EMPTY_STATE_CONFIG }], target: i0.ɵɵFactoryTarget.Injectable }); }
2419
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: EmptyStateService, deps: [{ token: EMPTY_STATE_CONFIG }, { token: EventsService }], target: i0.ɵɵFactoryTarget.Injectable }); }
1857
2420
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: EmptyStateService }); }
1858
2421
  }
1859
2422
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: EmptyStateService, decorators: [{
@@ -1861,90 +2424,178 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
1861
2424
  }], ctorParameters: () => [{ type: undefined, decorators: [{
1862
2425
  type: Inject,
1863
2426
  args: [EMPTY_STATE_CONFIG]
1864
- }] }] });
2427
+ }] }, { type: EventsService }] });
1865
2428
 
1866
2429
  class DragDropBase {
1867
- constructor(config) {
2430
+ static { this.nextDropListId = 0; }
2431
+ constructor(config, eventsService, klesForm, injector, tableId) {
1868
2432
  this.config = config;
2433
+ this.eventsService = eventsService;
2434
+ this.klesForm = klesForm;
2435
+ this.injector = injector;
2436
+ this.dropListId = tableId ? this.toDropListId(tableId) : `kles-rows-drop-list-${DragDropBase.nextDropListId++}`;
1869
2437
  }
1870
2438
  get enable() {
1871
2439
  return this.config?.enable || false;
1872
2440
  }
2441
+ get handleOnly() {
2442
+ return this.enable && (this.config?.options?.handleOnly ?? false);
2443
+ }
1873
2444
  get autoScrollStep() {
1874
- return this.config?.options?.autoScrollStep ?? true;
2445
+ return this.config?.options?.autoScrollStep ?? 8;
1875
2446
  }
1876
2447
  get connectedTo() {
1877
- return this.config?.options?.connectedTo;
2448
+ return this.config?.options?.connectedTo?.map((id) => this.toDropListId(id));
1878
2449
  }
1879
2450
  get sortPredicate() {
1880
2451
  return (index, item) => {
1881
- return true;
2452
+ const row = item.data;
2453
+ const targetRow = item.dropContainer.getSortedItems()[index]?.data;
2454
+ if (!targetRow || row === targetRow)
2455
+ return true;
2456
+ const targetForm = item.dropContainer.data;
2457
+ if (targetForm !== this.klesForm) {
2458
+ return (row.getRawValue()._depth ?? 0) === 0 && (targetRow.getRawValue()._depth ?? 0) === 0;
2459
+ }
2460
+ return this.klesForm.canMoveSubtree(row, targetRow);
1882
2461
  };
1883
2462
  }
1884
2463
  get previewComponent() {
1885
2464
  return this.config?.options?.dragPreview?.component;
1886
2465
  }
1887
2466
  get previewMatchSize() {
1888
- return this.config?.options?.dragPreview?.matchSize || true;
2467
+ return this.config?.options?.dragPreview?.matchSize ?? true;
2468
+ }
2469
+ get placeholderComponent() {
2470
+ return this.config?.options?.dragPlaceholder?.component;
2471
+ }
2472
+ isDragDisabled(row) {
2473
+ return this.config?.options?.dragDisabled?.(row) ?? false;
2474
+ }
2475
+ componentInjector(row, rowIndex) {
2476
+ return Injector.create({
2477
+ parent: this.injector,
2478
+ providers: [
2479
+ {
2480
+ provide: KLES_DRAG_DROP_ROW_CONTEXT,
2481
+ useValue: this.rowPayload(row, rowIndex),
2482
+ },
2483
+ ],
2484
+ });
2485
+ }
2486
+ rowDragStarted(row, rowIndex) {
2487
+ this.eventsService.emit('rowDragStart', this.rowPayload(row, rowIndex));
2488
+ }
2489
+ rowDragMoved(row, rowIndex) {
2490
+ this.eventsService.emit('rowDragMove', this.rowPayload(row, rowIndex));
2491
+ }
2492
+ rowDragEnded(row, rowIndex) {
2493
+ this.eventsService.emit('rowDragEnd', this.rowPayload(row, rowIndex));
2494
+ }
2495
+ rowPayload(row, rowIndex) {
2496
+ return {
2497
+ row,
2498
+ rowIndex,
2499
+ value: row.value,
2500
+ rawValue: row.getRawValue(),
2501
+ };
2502
+ }
2503
+ reorder(event) {
2504
+ const row = event.item.data;
2505
+ const visibleRows = event.container.getSortedItems().map((item) => item.data);
2506
+ const targetRow = visibleRows[event.currentIndex];
2507
+ if (!targetRow) {
2508
+ return;
2509
+ }
2510
+ const moved = this.klesForm.moveSubtree(row, targetRow);
2511
+ if (moved) {
2512
+ this.handleDrop({
2513
+ ...this.rowPayload(row, moved.currentIndex),
2514
+ previousIndex: moved.previousIndex,
2515
+ currentIndex: moved.currentIndex,
2516
+ parentId: row.getRawValue()._parentId,
2517
+ depth: row.getRawValue()._depth ?? 0,
2518
+ previousSiblingIndex: moved.previousSiblingIndex,
2519
+ currentSiblingIndex: moved.currentSiblingIndex,
2520
+ movedRows: moved.movedRows,
2521
+ movedRawValues: moved.movedRows.map((movedRow) => movedRow.getRawValue()),
2522
+ });
2523
+ }
2524
+ }
2525
+ transfer(event) {
2526
+ const row = event.item.data;
2527
+ const targetRows = event.container.getSortedItems().map((item) => item.data);
2528
+ const targetRow = targetRows[event.currentIndex];
2529
+ const moved = event.previousContainer.data.transferSubtreeTo(event.container.data, row, targetRow);
2530
+ if (moved) {
2531
+ this.handleDrop({
2532
+ ...this.rowPayload(row, moved.currentIndex),
2533
+ previousIndex: moved.previousIndex,
2534
+ currentIndex: moved.currentIndex,
2535
+ previousContainerId: event.previousContainer.id,
2536
+ currentContainerId: event.container.id,
2537
+ parentId: row.getRawValue()._parentId,
2538
+ depth: row.getRawValue()._depth ?? 0,
2539
+ previousSiblingIndex: moved.previousSiblingIndex,
2540
+ currentSiblingIndex: moved.currentSiblingIndex,
2541
+ movedRows: moved.movedRows,
2542
+ movedRawValues: moved.movedRows.map((movedRow) => movedRow.getRawValue()),
2543
+ });
2544
+ }
2545
+ }
2546
+ handleDrop(change) {
2547
+ this.eventsService.emit('rowDrop', change);
2548
+ const drop = this.config?.options?.drop;
2549
+ if (!drop) {
2550
+ return;
2551
+ }
2552
+ defer(() => drop(change))
2553
+ .pipe(defaultIfEmpty(undefined), take(1))
2554
+ .subscribe({
2555
+ next: () => this.eventsService.emit('rowDropSuccess', change),
2556
+ error: (error) => this.eventsService.emit('rowDropError', { change, error }),
2557
+ });
2558
+ }
2559
+ toDropListId(id) {
2560
+ return id.endsWith('-rows-drop-list') ? id : `${id}-rows-drop-list`;
1889
2561
  }
1890
2562
  }
1891
- class DragDropService extends DragDropBase {
1892
- constructor(config, paginatorStore) {
1893
- super(config);
1894
- this.config = config;
1895
- this.paginatorStore = paginatorStore;
2563
+ let DragDropService = class DragDropService extends DragDropBase {
2564
+ constructor(config, eventsService, klesForm, injector, tableId) {
2565
+ super(config, eventsService, klesForm, injector, tableId);
1896
2566
  }
1897
2567
  listDropped(event) {
1898
2568
  if (event.previousContainer === event.container) {
1899
- const faRows = event.container.data;
1900
- const currentIndex = event.currentIndex + (this.paginatorStore?.snapshot().page ?? 0) * (this.paginatorStore?.snapshot().perPage ?? 0);
1901
- const previousIndex = event.previousIndex + (this.paginatorStore?.snapshot().page ?? 0) * (this.paginatorStore?.snapshot().perPage ?? 0);
1902
- if (previousIndex >= 0) {
1903
- const ctrl = faRows.at(previousIndex);
1904
- faRows.removeAt(previousIndex, { emitEvent: false });
1905
- faRows.insert(currentIndex, ctrl, { emitEvent: false });
1906
- faRows.updateValueAndValidity({ emitEvent: true });
1907
- }
2569
+ this.reorder(event);
1908
2570
  }
1909
2571
  else {
1910
- //TODO
2572
+ this.transfer(event);
1911
2573
  }
1912
2574
  }
1913
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: DragDropService, deps: [{ token: DRAG_DROP_CONFIG, optional: true }, { token: PaginatorStore, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
1914
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: DragDropService }); }
1915
- }
1916
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: DragDropService, decorators: [{
1917
- type: Injectable
1918
- }], ctorParameters: () => [{ type: undefined, decorators: [{
1919
- type: Optional
1920
- }, {
1921
- type: Inject,
1922
- args: [DRAG_DROP_CONFIG]
1923
- }] }, { type: PaginatorStore, decorators: [{
1924
- type: Optional
1925
- }] }] });
1926
- class DragDropLazyService extends DragDropBase {
1927
- constructor(config) {
1928
- super(config);
1929
- this.config = config;
2575
+ };
2576
+ DragDropService = __decorate([
2577
+ __param(0, Optional()),
2578
+ __param(0, Inject(DRAG_DROP_CONFIG))
2579
+ ], DragDropService);
2580
+ let DragDropLazyService = class DragDropLazyService extends DragDropBase {
2581
+ constructor(config, eventsService, klesForm, injector, tableId) {
2582
+ super(config, eventsService, klesForm, injector, tableId);
1930
2583
  }
1931
2584
  listDropped(event) {
1932
- // TODO appeler un observable + refresh tableau
2585
+ if (event.previousContainer === event.container) {
2586
+ this.reorder(event);
2587
+ return;
2588
+ }
2589
+ this.transfer(event);
1933
2590
  }
1934
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: DragDropLazyService, deps: [{ token: DRAG_DROP_CONFIG, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
1935
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: DragDropLazyService }); }
1936
- }
1937
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: DragDropLazyService, decorators: [{
1938
- type: Injectable
1939
- }], ctorParameters: () => [{ type: undefined, decorators: [{
1940
- type: Optional
1941
- }, {
1942
- type: Inject,
1943
- args: [DRAG_DROP_CONFIG]
1944
- }] }] });
2591
+ };
2592
+ DragDropLazyService = __decorate([
2593
+ __param(0, Optional()),
2594
+ __param(0, Inject(DRAG_DROP_CONFIG))
2595
+ ], DragDropLazyService);
1945
2596
 
1946
2597
  class TableComponent {
1947
- constructor(host, connectorService, loader, datasourceService, tableService, dragDropRowService, selectionService, columnsService, loadingService, paginatorService, scrollbarService, footerService, extraRowService, renderService, sortService, filterService, expandedRowStore, rowFactory, eventsService, rowService, cellService, emptyStateService) {
2598
+ constructor(host, connectorService, loader, datasourceService, tableService, dragDropRowService, selectionService, columnsService, loadingService, paginatorService, scrollbarService, footerService, extraRowService, renderService, sortService, filterService, expandedRowStore, rowFactory, eventsService, rowService, cellService, emptyStateService, treeService) {
1948
2599
  this.host = host;
1949
2600
  this.connectorService = connectorService;
1950
2601
  this.loader = loader;
@@ -1967,6 +2618,7 @@ class TableComponent {
1967
2618
  this.rowService = rowService;
1968
2619
  this.cellService = cellService;
1969
2620
  this.emptyStateService = emptyStateService;
2621
+ this.treeService = treeService;
1970
2622
  this.headerHeightPx = signal(56, ...(ngDevMode ? [{ debugName: "headerHeightPx" }] : /* istanbul ignore next */ []));
1971
2623
  this.scrollHeightPx = signal(0, ...(ngDevMode ? [{ debugName: "scrollHeightPx" }] : /* istanbul ignore next */ []));
1972
2624
  this.footerHeightPx = signal(0, ...(ngDevMode ? [{ debugName: "footerHeightPx" }] : /* istanbul ignore next */ []));
@@ -1993,6 +2645,33 @@ class TableComponent {
1993
2645
  listen: () => this.eventsService.events$,
1994
2646
  };
1995
2647
  }
2648
+ get emptyState() {
2649
+ return {
2650
+ enabled: this.emptyStateService.enabled,
2651
+ enable: () => this.emptyStateService.enable(),
2652
+ disable: () => this.emptyStateService.disable(),
2653
+ toggle: () => this.emptyStateService.toggle(),
2654
+ };
2655
+ }
2656
+ get render() {
2657
+ return {
2658
+ rows: () => this.renderService.forceRenderRows(),
2659
+ };
2660
+ }
2661
+ get tree() {
2662
+ return {
2663
+ expandedIds: this.treeService.expandedIds,
2664
+ loadingIds: this.treeService.loadingIds,
2665
+ isExpanded: (id) => this.treeService.isExpanded(id),
2666
+ isLoading: (id) => this.treeService.isLoading(id),
2667
+ getChildren: (id) => this.treeService.getChildren(id),
2668
+ getDescendants: (id) => this.treeService.getDescendants(id),
2669
+ expand: (id) => this.treeService.expand(id),
2670
+ collapse: (id) => this.treeService.collapse(id),
2671
+ toggle: (id) => this.treeService.toggle(id),
2672
+ collapseAll: () => this.treeService.collapseAll(),
2673
+ };
2674
+ }
1996
2675
  get form() {
1997
2676
  return {
1998
2677
  header: {
@@ -2011,25 +2690,43 @@ class TableComponent {
2011
2690
  list: () => this.tableService.klesForm.getRows(),
2012
2691
  get: (_id) => this.tableService.klesForm.getRows().controls.find((row) => row.value._id === _id),
2013
2692
  create: (value, index, options) => {
2014
- return this.tableService.klesForm.insertRow(this.rowFactory.createRow(this.columnsService
2693
+ const row = this.tableService.klesForm.insertRow(this.rowFactory.createRow(this.columnsService
2015
2694
  .columns()
2016
2695
  .map((col) => ({ ...col.cell?.field, name: col.columnDef }))
2017
- .concat(this.extraRowService.extraColumns().map((col) => ({ ...col, name: col.columnDef }))), value), index, options).formGroup;
2696
+ .concat(this.extraRowService.extraFields()), value), index, options).formGroup;
2697
+ this.eventsService.emit('rowCreate', this.rowEventPayload(row));
2698
+ return row;
2018
2699
  },
2019
2700
  patch: (_id, value, options) => {
2020
- return this.tableService.klesForm.updateRow(_id, value, options);
2701
+ const row = this.tableService.klesForm.updateRow(_id, value, options);
2702
+ if (row) {
2703
+ this.eventsService.emit('rowPatch', this.rowEventPayload(row));
2704
+ }
2705
+ return row;
2021
2706
  },
2022
2707
  remove: (_id, options) => {
2708
+ const row = this.tableService.klesForm.getRows().controls.find((current) => current.getRawValue()._id === _id);
2709
+ const payload = row ? this.rowEventPayload(row) : undefined;
2023
2710
  this.tableService.klesForm.deleteRowById(_id, options);
2711
+ if (payload) {
2712
+ this.eventsService.emit('rowDelete', payload);
2713
+ }
2024
2714
  },
2025
2715
  reset: (_id, value, options) => {
2026
2716
  this.tableService.klesForm.resetRow(_id, value, options);
2717
+ const row = this.tableService.klesForm.getRows().controls.find((current) => current.getRawValue()._id === _id);
2718
+ if (row) {
2719
+ this.eventsService.emit('rowUpdate', this.rowEventPayload(row));
2720
+ }
2027
2721
  },
2028
2722
  },
2029
2723
  };
2030
2724
  }
2031
2725
  get scrollbar() {
2032
2726
  return {
2727
+ setVisible: (visible) => this.scrollbarService.setScrollbarVisible(visible),
2728
+ show: () => this.scrollbarService.showScrollbar(),
2729
+ hide: () => this.scrollbarService.hideScrollbar(),
2033
2730
  getTop: () => this.scrollbarService.getTop(),
2034
2731
  to: (top, left, sb) => this.scrollbarService.to(top, left, sb),
2035
2732
  toTop: (sb) => this.scrollbarService.toTop(sb),
@@ -2040,6 +2737,7 @@ class TableComponent {
2040
2737
  }
2041
2738
  get column() {
2042
2739
  return {
2740
+ getVisible: () => this.columnsService.getVisible(),
2043
2741
  setVisible: (columnDef, visible) => this.columnsService.setVisible(columnDef, visible),
2044
2742
  toggleVisible: (columnDef) => this.columnsService.toggleVisible(columnDef),
2045
2743
  changeWidth: (columnDef, options) => this.columnsService.changeWidth(columnDef, options),
@@ -2052,6 +2750,7 @@ class TableComponent {
2052
2750
  }
2053
2751
  get pagination() {
2054
2752
  return {
2753
+ disabled: this.paginatorService.disabled(),
2055
2754
  setPageIndex: (index) => this.paginatorService.setPageIndex(index),
2056
2755
  setPageSize: (size) => this.paginatorService.setPageSize(size),
2057
2756
  firstPage: () => this.paginatorService.firstPage(),
@@ -2068,10 +2767,6 @@ class TableComponent {
2068
2767
  enable: () => this.selectionService.enable(),
2069
2768
  count: this.selectionService.count(),
2070
2769
  selectionModel: this.selectionService.selectionModel,
2071
- // changed: () => {},
2072
- // isEmpty: () => {},
2073
- // isMultipleSelection: () => {},
2074
- // selected: () => {},
2075
2770
  };
2076
2771
  }
2077
2772
  get sort() {
@@ -2083,12 +2778,14 @@ class TableComponent {
2083
2778
  }
2084
2779
  get loading() {
2085
2780
  return {
2781
+ active: this.loadingService.loading,
2086
2782
  start: () => this.loadingService.start(),
2087
2783
  stop: () => this.loadingService.stop(),
2088
2784
  };
2089
2785
  }
2090
2786
  get footer() {
2091
2787
  return {
2788
+ visible: this.footerService.footer,
2092
2789
  hide: () => this.footerService.hide(),
2093
2790
  show: () => this.footerService.show(),
2094
2791
  };
@@ -2097,8 +2794,17 @@ class TableComponent {
2097
2794
  return this.tableService.ui;
2098
2795
  }
2099
2796
  refresh() {
2797
+ this.treeService.collapseAll();
2100
2798
  this.loader.refresh();
2101
2799
  }
2800
+ rowEventPayload(row) {
2801
+ return {
2802
+ row,
2803
+ rowIndex: this.tableService.klesForm.getRows().controls.indexOf(row),
2804
+ value: row.value,
2805
+ rawValue: row.getRawValue(),
2806
+ };
2807
+ }
2102
2808
  ngOnInit() {
2103
2809
  this.sortService.register(this.matSort);
2104
2810
  const el = this.formElemRef.nativeElement;
@@ -2120,9 +2826,6 @@ class TableComponent {
2120
2826
  this._cleanup?.();
2121
2827
  this.scrollbarService.unregister();
2122
2828
  }
2123
- submit() {
2124
- // TODO
2125
- }
2126
2829
  getColumnSeparator(column, section) {
2127
2830
  const separatorConfig = column.separator;
2128
2831
  if (separatorConfig === false || separatorConfig === undefined) {
@@ -2155,13 +2858,6 @@ class TableComponent {
2155
2858
  }
2156
2859
  return this.getColumnSeparator(column, section);
2157
2860
  }
2158
- // getStickyEndSeparator(column: KlesColumnConfig, section: TableSection): string | null {
2159
- // const isBoundary = this.columnsService.stickyEndBoundary() === column.columnDef;
2160
- // if (!isBoundary) {
2161
- // return null;
2162
- // }
2163
- // return this.getSeparatorStyle(column, section);
2164
- // }
2165
2861
  getStickyEndSeparator(column, section) {
2166
2862
  if (column.stickyEnd !== true) {
2167
2863
  return null;
@@ -2224,8 +2920,8 @@ class TableComponent {
2224
2920
  };
2225
2921
  }
2226
2922
  }
2227
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: TableComponent, deps: [{ token: i0.ElementRef }, { token: KlesTableConnectorService }, { token: LOADER_SERVICE }, { token: DATASOURCE_SERVICE }, { token: TABLE_SERVICE }, { token: ROW_DRAG_DROP }, { token: SELECTION_SERVICE }, { token: ColumnsService }, { token: LoadingService }, { token: PaginatorService }, { token: ScrollbarService }, { token: FooterService }, { token: ExtraRowService }, { token: RenderService }, { token: SORT_SERVICE }, { token: FilterService, optional: true }, { token: ExpandedRowStore }, { token: RowFormFactory }, { token: EventsService }, { token: RowService }, { token: CellService }, { token: EmptyStateService }], target: i0.ɵɵFactoryTarget.Component }); }
2228
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: TableComponent, isStandalone: true, selector: "kles-table", host: { properties: { "class.loading": "this.isLoadingClass", "class.empty": "this.isEmptyClass" } }, viewQueries: [{ propertyName: "table", first: true, predicate: MatTable, descendants: true }, { propertyName: "matSort", first: true, predicate: MatSort, descendants: true, static: true }, { propertyName: "formElemRef", first: true, predicate: ["form"], descendants: true, static: true }], ngImport: i0, template: "<form #form [formGroup]=\"tableService.form\" (ngSubmit)=\"submit()\">\n <!-- [fixedLayout]=\"true\" -->\n <table\n mat-table\n [dataSource]=\"dataSource\"\n matSort\n [trackBy]=\"multiTemplateDataRows() ? null : tableService.trackBy\"\n formArrayName=\"rows\"\n cdkDropList\n [cdkDropListData]=\"tableService.form.controls.rows\"\n (cdkDropListDropped)=\"dragDropRowService.listDropped($event)\"\n [cdkDropListDisabled]=\"!dragDropRowService.enable\"\n [cdkDropListAutoScrollStep]=\"dragDropRowService.autoScrollStep\"\n [cdkDropListSortPredicate]=\"dragDropRowService.sortPredicate\"\n [cdkDropListConnectedTo]=\"dragDropRowService.connectedTo\"\n [multiTemplateDataRows]=\"multiTemplateDataRows()\"\n >\n <colgroup>\n @for (column of columns(); track column.columnDef) {\n <col [style.width]=\"column.width ?? null\" [style.minWidth]=\"column.minWidth ?? null\" [style.maxWidth]=\"column.maxWidth ?? null\" />\n }\n </colgroup>\n\n @for (column of columns(); track column.columnDef) {\n <ng-container [cdkColumnDef]=\"column.columnDef\" [sticky]=\"column.sticky ?? false\" [stickyEnd]=\"column.stickyEnd ?? false\">\n <th\n mat-header-cell\n *matHeaderCellDef\n [appResizableColumn]=\"column\"\n [style.border-inline-end]=\"getColumnSeparator(column, 'header') ?? getStickyStartSeparator(column, 'header')\"\n [style.border-inline-start]=\"getStickyEndSeparator(column, 'header')\"\n [ngStyle]=\"\n column.headerCell?.style?.ngStyle\n | resolveNgStyle\n : tableService.form.get(['header', column.columnDef])?.value\n : tableService.form.get(['header', column.columnDef])?.status\n : tableService.form.controls.header.value\n : tableService.form.controls.header.status\n \"\n >\n <div class=\"cell\">\n <kles-header [header]=\"column | header\" [group]=\"tableService.form.controls.header\">\n <ng-container\n klesDynamicField\n [field]=\"column | headerField\"\n [group]=\"tableService.form.controls.header\"\n [ui]=\"tableService.ui.states.header\"\n ></ng-container>\n </kles-header>\n </div>\n </th>\n\n <td\n mat-cell\n *cdkCellDef=\"let row; let index = index; let dataIndex = dataIndex\"\n [style.border-inline-end]=\"getColumnSeparator(column, 'body') ?? getStickyStartSeparator(column, 'body')\"\n [style.border-inline-start]=\"getStickyEndSeparator(column, 'body')\"\n [ngStyle]=\"\n column.cell?.style?.ngStyle\n | resolveNgStyle: row.controls[column.columnDef].value : row.controls[column.columnDef].status : row.value : row.status\n \"\n (click)=\"cellService.onClick($event, row, dataIndex ?? index, column.columnDef)\"\n (dblclick)=\"cellService.onDoubleClick($event, row, dataIndex ?? index, column.columnDef)\"\n (contextmenu)=\"cellService.onContextMenu($event, row, dataIndex ?? index, column.columnDef)\"\n >\n <div class=\"cell\" [style.--align]=\"column.align\">\n <kles-cell [group]=\"row\" [ui]=\"row | uiField\" [column]=\"column\">\n <ng-container klesDynamicField [field]=\"column | cellField\" [group]=\"row\" [ui]=\"row | uiField\" [context]=\"row | rowContext\"></ng-container>\n </kles-cell>\n </div>\n </td>\n\n <td\n mat-footer-cell\n *matFooterCellDef\n [style.border-inline-end]=\"getColumnSeparator(column, 'footer') ?? getStickyStartSeparator(column, 'footer')\"\n [style.border-inline-start]=\"getStickyEndSeparator(column, 'footer')\"\n [ngStyle]=\"\n column.footerCell?.style?.ngStyle\n | resolveNgStyle\n : tableService.form.get(['footer', column.columnDef])?.value\n : tableService.form.get(['footer', column.columnDef])?.status\n : tableService.form.controls.footer.value\n : tableService.form.controls.footer.status\n \"\n >\n @if (column.footerCell) {\n <ng-container\n klesDynamicField\n [field]=\"column | footerField\"\n [group]=\"tableService.form.controls.footer\"\n [ui]=\"tableService.ui.states.footer\"\n >\n </ng-container>\n }\n </td>\n </ng-container>\n }\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns(); sticky: true\"></tr>\n\n <tr\n mat-row\n *matRowDef=\"let row; let index = index; let dataIndex = dataIndex; columns: displayedColumns()\"\n cdkDrag\n [cdkDragData]=\"row\"\n (click)=\"rowService.onClick($event, row, dataIndex ?? index)\"\n (dblclick)=\"rowService.onDoubleClick($event, row, dataIndex ?? index)\"\n (contextmenu)=\"rowService.onContextMenu($event, row, dataIndex ?? index)\"\n (mouseenter)=\"rowService.onMouseEnter($event, row, dataIndex ?? index)\"\n (mouseleave)=\"rowService.onMouseLeave($event, row, dataIndex ?? index)\"\n ></tr>\n\n @if (multiTemplateDataRows()) {\n @for (extraRow of extraRows(); track extraRow) {\n @for (extraColumn of extraRow.cells; track extraColumn.columnDef) {\n <ng-container [cdkColumnDef]=\"extraColumn.columnDef\">\n <td\n mat-cell\n *cdkCellDef=\"let row\"\n [attr.colspan]=\"extraColumn.colspan | spanPipe: displayedColumns().length\"\n [attr.rowspan]=\"extraColumn.rowspan\"\n [ngStyle]=\"\n extraColumn?.style?.ngStyle\n | resolveNgStyle\n : row.controls[extraColumn.columnDef].value\n : row.controls[extraColumn.columnDef].status\n : row.value\n : row.status\n \"\n >\n <ng-container klesDynamicField [field]=\"extraColumn | extraCellField\" [group]=\"row\" [ui]=\"row | uiField\" [context]=\"row | rowContext\"></ng-container>\n </td>\n </ng-container>\n }\n <tr\n mat-row\n *matRowDef=\"let row; let index = index; let dataIndex = dataIndex; columns: extraRow.displayedColumns; when: extraRow.when\"\n (click)=\"rowService.onClick($event, row, dataIndex ?? index)\"\n (dblclick)=\"rowService.onDoubleClick($event, row, dataIndex ?? index)\"\n (contextmenu)=\"rowService.onContextMenu($event, row, dataIndex ?? index)\"\n (mouseenter)=\"rowService.onMouseEnter($event, row, dataIndex ?? index)\"\n (mouseleave)=\"rowService.onMouseLeave($event, row, dataIndex ?? index)\"\n ></tr>\n }\n }\n\n <tr mat-footer-row *matFooterRowDef=\"displayedColumns(); sticky: true\" [style.display]=\"showFooter() ? '' : 'none'\"></tr>\n </table>\n</form>\n\n@if (loadingService.loading()) {\n <div class=\"table-overlay\" [style.--header-h.px]=\"headerHeightPx()\" [style.--scroll-h.px]=\"scrollHeightPx()\" [style.--footer-h.px]=\"footerHeightPx()\">\n <mat-spinner></mat-spinner>\n </div>\n}\n\n@if (emptyStateService.enabled() && !loadingService.loading() && isEmpty()) {\n <div\n class=\"table-empty-state-overlay\"\n [style.--header-h.px]=\"headerHeightPx()\"\n [style.--scroll-h.px]=\"scrollHeightPx()\"\n [style.--footer-h.px]=\"footerHeightPx()\"\n >\n <div class=\"table-empty-state-content\">\n <ng-container *ngComponentOutlet=\"emptyStateService.component\"></ng-container>\n </div>\n </div>\n}\n", styles: [":host{--kles-table-divider-color: color-mix(in srgb, var(--mat-sys-outline-variant) 65%, transparent);--kles-table-divider-strong-color: var(--mat-sys-outline-variant);--kles-table-header-background: var(--mat-sys-surface-container);--kles-table-header-color: var(--mat-sys-on-surface);--kles-table-header-divider-color: var(--mat-sys-outline-variant);--kles-table-row-hover-background: color-mix(in srgb, var(--mat-sys-primary) 7%, var(--mat-sys-surface));overflow:auto;display:flex;flex-direction:column;position:relative;height:100%;--mat-form-field-filled-container-color: transparent;--mat-form-field-hover-state-layer-opacity: 0;--mat-form-field-focus-state-layer-opacity: 0;--mat-form-field-state-layer-color: transparent}:host(.loading),:host(.empty){min-height:280px}form{display:flex;flex-direction:column;flex-grow:1;position:relative;overflow:auto}table{width:100%;flex-grow:1}th,td{text-wrap:pretty;white-space:normal;padding-top:2px;padding-bottom:2px;box-sizing:border-box}td{word-break:normal}th .cell,td .cell{display:flex;flex-direction:column;justify-content:var(--align, center)}th[appResizableColumn]{position:relative}th[appResizableColumn] .resize-handle{position:absolute;top:0;right:-4px;width:8px;height:100%;cursor:col-resize;-webkit-user-select:none;user-select:none}.table-overlay{position:absolute;inset-inline:0;top:var(--header-h, 56px);bottom:calc(var(--scroll-h, 0px) + var(--footer-h, 0px));display:grid;place-items:center;background:color-mix(in srgb,var(--mat-sys-surface-container-highest) 75%,transparent);box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--mat-sys-outline-variant) 30%,transparent);z-index:500}:host .mat-mdc-row{transition:background-color .12s ease}:host .mat-mdc-row:hover{background:var(--kles-table-row-hover-background)}:host .mat-mdc-table .mat-mdc-cell,:host .mat-mdc-table .mat-mdc-header-cell{border-bottom-color:var(--mat-sys-outline-variant)}:host .mat-mdc-table .mat-mdc-cell:last-child,:host .mat-mdc-table .mat-mdc-header-cell:last-child{border-right:none}:host tr.mat-mdc-footer-row td.mat-mdc-footer-cell{border-top:1px solid var(--kles-table-divider-strong-color)}:host tr.mat-mdc-row:last-of-type td.mat-mdc-cell{border-bottom:1px solid var(--kles-table-divider-color)}:host tr.mat-mdc-footer-row{font-weight:500}:host .mat-mdc-header-row,:host .mat-mdc-header-cell{background-color:var(--kles-table-header-background);color:var(--kles-table-header-color)}:host .mat-mdc-header-cell{border-bottom-color:var(--kles-table-header-divider-color)}.table-empty-state-overlay{position:absolute;inset-inline:0;top:var(--header-h, 56px);bottom:calc(var(--scroll-h, 0px) + var(--footer-h, 0px));z-index:400;overflow:hidden;background:var(--mat-sys-surface);display:grid;place-items:center}.table-empty-state-content{width:100%;height:100%}.scrollbar-hidden{scrollbar-width:none;-ms-overflow-style:none;overflow-y:hidden}.scrollbar-hidden::-webkit-scrollbar{display:none;overflow-y:hidden}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i16.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }, { kind: "directive", type: i16.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i17.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i17.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i17.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i17.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "ngmodule", type: MatSortModule }, { kind: "directive", type: i4.MatSort, selector: "[matSort]", inputs: ["matSortActive", "matSortStart", "matSortDirection", "matSortDisableClear", "matSortDisabled"], outputs: ["matSortChange"], exportAs: ["matSort"] }, { kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i19.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i19.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i19.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i19.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i19.MatFooterCellDef, selector: "[matFooterCellDef]" }, { kind: "directive", type: i19.MatFooterRowDef, selector: "[matFooterRowDef]", inputs: ["matFooterRowDef", "matFooterRowDefSticky"] }, { kind: "directive", type: i19.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i19.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "directive", type: i19.MatFooterCell, selector: "mat-footer-cell, td[mat-footer-cell]" }, { kind: "component", type: i19.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i19.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "component", type: i19.MatFooterRow, selector: "mat-footer-row, tr[mat-footer-row]", exportAs: ["matFooterRow"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: MatInputModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "ngmodule", type: MatButtonModule }, { kind: "ngmodule", type: CdkTableModule }, { kind: "directive", type: i20.CdkCellDef, selector: "[cdkCellDef]" }, { kind: "directive", type: i20.CdkColumnDef, selector: "[cdkColumnDef]", inputs: ["cdkColumnDef", "sticky", "stickyEnd"] }, { kind: "ngmodule", type: KlesMaterialDynamicformsModule }, { kind: "directive", type: i21.KlesDynamicFieldDirective, selector: "[klesDynamicField]", inputs: ["field", "group", "ui", "siblingFields", "context"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i22.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i22.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i23.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "directive", type: ResizableColumnDirective, selector: "th[appResizableColumn]", inputs: ["appResizableColumn"] }, { kind: "component", type: KlesCellComponent, selector: "kles-cell", inputs: ["ui", "group", "column"] }, { kind: "component", type: KlesHeaderComponent, selector: "kles-header", inputs: ["header", "group"] }, { kind: "pipe", type: HeaderFieldPipe, name: "headerField" }, { kind: "pipe", type: CellFieldPipe, name: "cellField" }, { kind: "pipe", type: UiFieldPipe, name: "uiField" }, { kind: "pipe", type: FooterFieldPipe, name: "footerField" }, { kind: "pipe", type: SpanPipe, name: "spanPipe" }, { kind: "pipe", type: ExtraCellFieldPipe, name: "extraCellField" }, { kind: "pipe", type: ResolveNgStylePipe, name: "resolveNgStyle" }, { kind: "pipe", type: HeaderPipe, name: "header" }, { kind: "pipe", type: RowContextPipe, name: "rowContext" }] }); }
2923
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: TableComponent, deps: [{ token: i0.ElementRef }, { token: KlesTableConnectorService }, { token: LOADER_SERVICE }, { token: DATASOURCE_SERVICE }, { token: TABLE_SERVICE }, { token: ROW_DRAG_DROP }, { token: SELECTION_SERVICE }, { token: ColumnsService }, { token: LoadingService }, { token: PaginatorService }, { token: ScrollbarService }, { token: FooterService }, { token: ExtraRowService }, { token: RenderService }, { token: SORT_SERVICE }, { token: FilterService, optional: true }, { token: ExpandedRowStore }, { token: RowFormFactory }, { token: EventsService }, { token: RowService }, { token: CellService }, { token: EmptyStateService }, { token: TreeService }], target: i0.ɵɵFactoryTarget.Component }); }
2924
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: TableComponent, isStandalone: true, selector: "kles-table", host: { properties: { "class.loading": "this.isLoadingClass", "class.empty": "this.isEmptyClass" } }, viewQueries: [{ propertyName: "table", first: true, predicate: MatTable, descendants: true }, { propertyName: "matSort", first: true, predicate: MatSort, descendants: true, static: true }, { propertyName: "formElemRef", first: true, predicate: ["form"], descendants: true, static: true }], ngImport: i0, template: "<form #form cdkScrollable [formGroup]=\"tableService.form\">\n <table\n mat-table\n [dataSource]=\"dataSource\"\n matSort\n [trackBy]=\"multiTemplateDataRows() ? null : tableService.trackBy\"\n formArrayName=\"rows\"\n cdkDropList\n [id]=\"dragDropRowService.dropListId\"\n [cdkDropListData]=\"tableService.klesForm\"\n (cdkDropListDropped)=\"dragDropRowService.listDropped($event)\"\n [cdkDropListDisabled]=\"!dragDropRowService.enable\"\n [cdkDropListAutoScrollStep]=\"dragDropRowService.autoScrollStep\"\n [cdkDropListSortPredicate]=\"dragDropRowService.sortPredicate\"\n [cdkDropListConnectedTo]=\"dragDropRowService.connectedTo\"\n [multiTemplateDataRows]=\"multiTemplateDataRows()\"\n >\n <colgroup>\n @for (column of columns(); track column.columnDef) {\n <col\n [attr.data-column-def]=\"column.columnDef\"\n [style.width]=\"column.width ?? null\"\n [style.minWidth]=\"column.minWidth ?? null\"\n [style.maxWidth]=\"column.maxWidth ?? null\"\n />\n }\n </colgroup>\n\n @for (column of columns(); track column.columnDef) {\n <ng-container [cdkColumnDef]=\"column.columnDef\" [sticky]=\"column.sticky ?? false\" [stickyEnd]=\"column.stickyEnd ?? false\">\n <th\n mat-header-cell\n *matHeaderCellDef\n [appResizableColumn]=\"column\"\n [style.border-inline-end]=\"getColumnSeparator(column, 'header') ?? getStickyStartSeparator(column, 'header')\"\n [style.border-inline-start]=\"getStickyEndSeparator(column, 'header')\"\n [ngStyle]=\"\n column.headerCell?.style?.ngStyle\n | resolveNgStyle\n : tableService.form.get(['header', column.columnDef])?.value\n : tableService.form.get(['header', column.columnDef])?.status\n : tableService.form.controls.header.value\n : tableService.form.controls.header.status\n \"\n >\n <div class=\"cell\">\n <kles-header\n [header]=\"column | header\"\n [group]=\"tableService.form.controls.header\"\n [dragHandleSpacer]=\"dragDropRowService.handleOnly && column.columnDef === displayedColumns()?.[0]\"\n >\n <ng-container\n klesDynamicField\n [field]=\"column | headerField\"\n [group]=\"tableService.form.controls.header\"\n [ui]=\"tableService.ui.states.header\"\n ></ng-container>\n </kles-header>\n </div>\n </th>\n\n <td\n mat-cell\n *cdkCellDef=\"let row; let index = index; let dataIndex = dataIndex\"\n [style.border-inline-end]=\"getColumnSeparator(column, 'body') ?? getStickyStartSeparator(column, 'body')\"\n [style.border-inline-start]=\"getStickyEndSeparator(column, 'body')\"\n [ngStyle]=\"\n column.cell?.style?.ngStyle\n | resolveNgStyle: row.controls[column.columnDef].value : row.controls[column.columnDef].status : row.value : row.status\n \"\n (click)=\"cellService.onClick($event, row, dataIndex ?? index, column.columnDef)\"\n (dblclick)=\"cellService.onDoubleClick($event, row, dataIndex ?? index, column.columnDef)\"\n (contextmenu)=\"cellService.onContextMenu($event, row, dataIndex ?? index, column.columnDef)\"\n >\n <div class=\"cell\" [style.--align]=\"column.align\">\n <kles-cell\n [group]=\"row\"\n [ui]=\"row | uiField\"\n [column]=\"column\"\n [rowIndex]=\"dataIndex ?? index\"\n [dragHandle]=\"dragDropRowService.handleOnly && column.columnDef === displayedColumns()?.[0]\"\n >\n @if (column.columnDef === selectionService.key && selectionService.isLoading(row)) {\n <mat-spinner class=\"selection-row-spinner\" [diameter]=\"20\"></mat-spinner>\n } @else {\n <ng-container klesDynamicField [field]=\"column | cellField\" [group]=\"row\" [ui]=\"row | uiField\" [context]=\"row | rowContext\"></ng-container>\n }\n </kles-cell>\n </div>\n </td>\n\n <td\n mat-footer-cell\n *matFooterCellDef\n [style.border-inline-end]=\"getColumnSeparator(column, 'footer') ?? getStickyStartSeparator(column, 'footer')\"\n [style.border-inline-start]=\"getStickyEndSeparator(column, 'footer')\"\n [ngStyle]=\"\n column.footerCell?.style?.ngStyle\n | resolveNgStyle\n : tableService.form.get(['footer', column.columnDef])?.value\n : tableService.form.get(['footer', column.columnDef])?.status\n : tableService.form.controls.footer.value\n : tableService.form.controls.footer.status\n \"\n >\n @if (column.footerCell) {\n <ng-container\n klesDynamicField\n [field]=\"column | footerField\"\n [group]=\"tableService.form.controls.footer\"\n [ui]=\"tableService.ui.states.footer\"\n >\n </ng-container>\n }\n </td>\n </ng-container>\n }\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns(); sticky: true\"></tr>\n\n <tr\n mat-row\n *matRowDef=\"let row; let index = index; let dataIndex = dataIndex; columns: displayedColumns()\"\n cdkDrag\n [cdkDragData]=\"row\"\n [cdkDragDisabled]=\"dragDropRowService.isDragDisabled(row)\"\n (cdkDragStarted)=\"dragDropRowService.rowDragStarted(row, dataIndex ?? index)\"\n (cdkDragMoved)=\"dragDropRowService.rowDragMoved(row, dataIndex ?? index)\"\n (cdkDragEnded)=\"dragDropRowService.rowDragEnded(row, dataIndex ?? index)\"\n (click)=\"rowService.onClick($event, row, dataIndex ?? index)\"\n (dblclick)=\"rowService.onDoubleClick($event, row, dataIndex ?? index)\"\n (contextmenu)=\"rowService.onContextMenu($event, row, dataIndex ?? index)\"\n (mouseenter)=\"rowService.onMouseEnter($event, row, dataIndex ?? index)\"\n (mouseleave)=\"rowService.onMouseLeave($event, row, dataIndex ?? index)\"\n >\n @if (dragDropRowService.previewComponent; as previewComponent) {\n <ng-template cdkDragPreview [matchSize]=\"dragDropRowService.previewMatchSize\">\n <div class=\"kles-row-drag-preview\">\n <ng-container\n *ngComponentOutlet=\"previewComponent; injector: dragDropRowService.componentInjector(row, dataIndex ?? index)\"\n ></ng-container>\n </div>\n </ng-template>\n }\n\n @if (dragDropRowService.placeholderComponent; as placeholderComponent) {\n <ng-template cdkDragPlaceholder>\n <tr class=\"kles-row-drag-placeholder\">\n <td [attr.colspan]=\"displayedColumns()?.length ?? 1\">\n <ng-container\n *ngComponentOutlet=\"placeholderComponent; injector: dragDropRowService.componentInjector(row, dataIndex ?? index)\"\n ></ng-container>\n </td>\n </tr>\n </ng-template>\n }\n </tr>\n\n @if (multiTemplateDataRows()) {\n @for (extraRow of extraRows(); track extraRow) {\n @for (extraColumn of extraRow.cells; track extraColumn.columnDef) {\n <ng-container [cdkColumnDef]=\"extraColumn.columnDef\">\n <td\n mat-cell\n *cdkCellDef=\"let row\"\n [attr.colspan]=\"extraColumn.colspan | spanPipe: displayedColumns().length\"\n [attr.rowspan]=\"extraColumn.rowspan\"\n [ngStyle]=\"\n extraColumn?.style?.ngStyle\n | resolveNgStyle\n : row.controls[extraColumn.columnDef].value\n : row.controls[extraColumn.columnDef].status\n : row.value\n : row.status\n \"\n >\n <ng-container klesDynamicField [field]=\"extraColumn | extraCellField\" [group]=\"row\" [ui]=\"row | uiField\" [context]=\"row | rowContext\"></ng-container>\n </td>\n </ng-container>\n }\n <tr\n mat-row\n *matRowDef=\"let row; let index = index; let dataIndex = dataIndex; columns: extraRow.displayedColumns; when: extraRow.when\"\n (click)=\"rowService.onClick($event, row, dataIndex ?? index)\"\n (dblclick)=\"rowService.onDoubleClick($event, row, dataIndex ?? index)\"\n (contextmenu)=\"rowService.onContextMenu($event, row, dataIndex ?? index)\"\n (mouseenter)=\"rowService.onMouseEnter($event, row, dataIndex ?? index)\"\n (mouseleave)=\"rowService.onMouseLeave($event, row, dataIndex ?? index)\"\n ></tr>\n }\n }\n\n <tr mat-footer-row *matFooterRowDef=\"displayedColumns(); sticky: true\" [style.display]=\"showFooter() ? '' : 'none'\"></tr>\n </table>\n</form>\n\n@if (loadingService.loading()) {\n <div class=\"table-overlay\" [style.--header-h.px]=\"headerHeightPx()\" [style.--scroll-h.px]=\"scrollHeightPx()\" [style.--footer-h.px]=\"footerHeightPx()\">\n <mat-spinner></mat-spinner>\n </div>\n}\n\n@if (emptyStateService.enabled() && !loadingService.loading() && isEmpty()) {\n <div\n class=\"table-empty-state-overlay\"\n [style.--header-h.px]=\"headerHeightPx()\"\n [style.--scroll-h.px]=\"scrollHeightPx()\"\n [style.--footer-h.px]=\"footerHeightPx()\"\n >\n <div class=\"table-empty-state-content\">\n <ng-container *ngComponentOutlet=\"emptyStateService.component\"></ng-container>\n </div>\n </div>\n}\n", styles: [":host{--kles-table-divider-color: color-mix(in srgb, var(--mat-sys-outline-variant) 65%, transparent);--kles-table-divider-strong-color: var(--mat-sys-outline-variant);--kles-table-header-background: var(--mat-sys-surface-container);--kles-table-header-color: var(--mat-sys-on-surface);--kles-table-header-divider-color: var(--mat-sys-outline-variant);--kles-table-row-hover-background: color-mix(in srgb, var(--mat-sys-primary) 7%, var(--mat-sys-surface));overflow:auto;display:flex;flex-direction:column;position:relative;height:100%;--mat-form-field-filled-container-color: transparent;--mat-form-field-hover-state-layer-opacity: 0;--mat-form-field-focus-state-layer-opacity: 0;--mat-form-field-state-layer-color: transparent}:host(.loading),:host(.empty){min-height:280px}form{display:flex;flex-direction:column;flex-grow:1;position:relative;overflow:auto}table{width:100%;flex-grow:1}th,td{text-wrap:pretty;white-space:normal;padding-top:2px;padding-bottom:2px;box-sizing:border-box}td{word-break:normal}th .cell,td .cell{display:flex;flex-direction:column;justify-content:var(--align, center)}th[appResizableColumn].resizable-column{position:relative}th[appResizableColumn]>.resize-handle{position:absolute;top:0;inset-inline-end:-7px;z-index:20;width:14px;height:100%;cursor:col-resize;-webkit-user-select:none;user-select:none;touch-action:none;outline:none}th[appResizableColumn]>.resize-handle:before{content:\"\";position:absolute;top:15%;bottom:15%;inset-inline-start:6px;width:2px;border-radius:2px;background:var(--mat-sys-outline);opacity:0;transition:opacity .12s ease,background-color .12s ease,transform .12s ease}th[appResizableColumn].resizable-column:hover>.resize-handle:before,th[appResizableColumn]>.resize-handle:focus-visible:before{opacity:.65}th[appResizableColumn].column-resizing>.resize-handle:before{top:0;bottom:0;background:var(--mat-sys-primary);opacity:1;transform:scaleX(1.25)}th[appResizableColumn].column-resizing>.resize-handle:after{content:\"\";position:absolute;top:100%;inset-inline-start:6px;width:2px;height:100vh;background:color-mix(in srgb,var(--mat-sys-primary) 70%,transparent);pointer-events:none}th[appResizableColumn]>.resize-handle>.resize-width-label{position:absolute;top:calc(100% + 8px);inset-inline-start:50%;z-index:30;display:none;padding:3px 7px;color:var(--mat-sys-on-primary);font-size:11px;font-weight:600;line-height:16px;white-space:nowrap;background:var(--mat-sys-primary);border-radius:var(--mat-sys-corner-extra-small);box-shadow:var(--mat-sys-level2);transform:translate(-50%);pointer-events:none}th[appResizableColumn].column-resizing>.resize-handle>.resize-width-label{display:block}:host .column-resizing-cell{width:var(--kles-column-resize-width)!important;min-width:var(--kles-column-resize-width)!important;max-width:var(--kles-column-resize-width)!important;flex:0 0 var(--kles-column-resize-width)!important;background-image:linear-gradient(color-mix(in srgb,var(--mat-sys-primary) 5%,transparent),color-mix(in srgb,var(--mat-sys-primary) 5%,transparent))}.table-overlay{position:absolute;inset-inline:0;top:var(--header-h, 56px);bottom:calc(var(--scroll-h, 0px) + var(--footer-h, 0px));display:grid;place-items:center;background:color-mix(in srgb,var(--mat-sys-surface-container-highest) 75%,transparent);box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--mat-sys-outline-variant) 30%,transparent);z-index:500}:host .mat-mdc-row{transition:background-color .12s ease}:host .mat-mdc-row:hover{background:var(--kles-table-row-hover-background)}:host tr.mat-mdc-row.cdk-drag-placeholder{opacity:1;background:color-mix(in srgb,var(--mat-sys-primary) 12%,var(--mat-sys-surface))}:host tr.mat-mdc-row.cdk-drag-placeholder td{border-block:2px dashed var(--mat-sys-primary)}:host tr.mat-mdc-row.cdk-drag-placeholder td>*{visibility:hidden}:host tr.mat-mdc-row.cdk-drag-placeholder td:first-child{border-inline-start:2px dashed var(--mat-sys-primary)}:host tr.mat-mdc-row.cdk-drag-placeholder td:last-child{border-inline-end:2px dashed var(--mat-sys-primary)}:host .cdk-drop-list-dragging tr.mat-mdc-row:not(.cdk-drag-placeholder),:host tr.mat-mdc-row.cdk-drag-animating{transition:transform .18s cubic-bezier(0,0,.2,1)}.kles-row-drag-preview{overflow:hidden;border-radius:var(--mat-sys-corner-small);background:var(--mat-sys-surface-container);box-shadow:var(--mat-sys-level3)}.selection-row-spinner{margin-inline:auto}:host tr.kles-row-drag-placeholder td{padding:0;border:2px dashed var(--mat-sys-primary);background:color-mix(in srgb,var(--mat-sys-primary) 12%,var(--mat-sys-surface))}:host .mat-mdc-table .mat-mdc-cell,:host .mat-mdc-table .mat-mdc-header-cell{border-bottom-color:var(--mat-sys-outline-variant)}:host .mat-mdc-table .mat-mdc-cell:last-child,:host .mat-mdc-table .mat-mdc-header-cell:last-child{border-right:none}:host tr.mat-mdc-footer-row td.mat-mdc-footer-cell{border-top:1px solid var(--kles-table-divider-strong-color)}:host tr.mat-mdc-row:last-of-type td.mat-mdc-cell{border-bottom:1px solid var(--kles-table-divider-color)}:host tr.mat-mdc-footer-row{font-weight:500}:host .mat-mdc-header-row,:host .mat-mdc-header-cell{background-color:var(--kles-table-header-background);color:var(--kles-table-header-color)}:host .mat-mdc-header-cell{border-bottom-color:var(--kles-table-header-divider-color)}.table-empty-state-overlay{position:absolute;inset-inline:0;top:var(--header-h, 56px);bottom:calc(var(--scroll-h, 0px) + var(--footer-h, 0px));z-index:400;overflow:hidden;background:var(--mat-sys-surface);display:grid;place-items:center}.table-empty-state-content{width:100%;height:100%}.scrollbar-hidden{scrollbar-width:none;-ms-overflow-style:none;overflow-y:hidden}.scrollbar-hidden::-webkit-scrollbar{display:none;overflow-y:hidden}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i17.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }, { kind: "directive", type: i17.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i18.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i18.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i18.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i18.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "ngmodule", type: MatSortModule }, { kind: "directive", type: i4.MatSort, selector: "[matSort]", inputs: ["matSortActive", "matSortStart", "matSortDirection", "matSortDisableClear", "matSortDisabled"], outputs: ["matSortChange"], exportAs: ["matSort"] }, { kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i20.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i20.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i20.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i20.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i20.MatFooterCellDef, selector: "[matFooterCellDef]" }, { kind: "directive", type: i20.MatFooterRowDef, selector: "[matFooterRowDef]", inputs: ["matFooterRowDef", "matFooterRowDefSticky"] }, { kind: "directive", type: i20.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i20.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "directive", type: i20.MatFooterCell, selector: "mat-footer-cell, td[mat-footer-cell]" }, { kind: "component", type: i20.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i20.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "component", type: i20.MatFooterRow, selector: "mat-footer-row, tr[mat-footer-row]", exportAs: ["matFooterRow"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: MatInputModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "ngmodule", type: MatButtonModule }, { kind: "ngmodule", type: CdkTableModule }, { kind: "directive", type: i21.CdkCellDef, selector: "[cdkCellDef]" }, { kind: "directive", type: i21.CdkColumnDef, selector: "[cdkColumnDef]", inputs: ["cdkColumnDef", "sticky", "stickyEnd"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i22.CdkScrollable, selector: "[cdk-scrollable], [cdkScrollable]" }, { kind: "ngmodule", type: KlesMaterialDynamicformsModule }, { kind: "directive", type: i23.KlesDynamicFieldDirective, selector: "[klesDynamicField]", inputs: ["field", "group", "ui", "siblingFields", "context"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i24.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i24.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i24.CdkDragPreview, selector: "ng-template[cdkDragPreview]", inputs: ["data", "matchSize"] }, { kind: "directive", type: i24.CdkDragPlaceholder, selector: "ng-template[cdkDragPlaceholder]", inputs: ["data"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i25.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "directive", type: ResizableColumnDirective, selector: "th[appResizableColumn]", inputs: ["appResizableColumn"] }, { kind: "component", type: KlesCellComponent, selector: "kles-cell", inputs: ["ui", "group", "column", "rowIndex", "dragHandle"] }, { kind: "component", type: KlesHeaderComponent, selector: "kles-header", inputs: ["header", "group", "dragHandleSpacer"] }, { kind: "pipe", type: HeaderFieldPipe, name: "headerField" }, { kind: "pipe", type: CellFieldPipe, name: "cellField" }, { kind: "pipe", type: UiFieldPipe, name: "uiField" }, { kind: "pipe", type: FooterFieldPipe, name: "footerField" }, { kind: "pipe", type: SpanPipe, name: "spanPipe" }, { kind: "pipe", type: ExtraCellFieldPipe, name: "extraCellField" }, { kind: "pipe", type: ResolveNgStylePipe, name: "resolveNgStyle" }, { kind: "pipe", type: HeaderPipe, name: "header" }, { kind: "pipe", type: RowContextPipe, name: "rowContext" }] }); }
2229
2925
  }
2230
2926
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: TableComponent, decorators: [{
2231
2927
  type: Component,
@@ -2239,6 +2935,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
2239
2935
  MatIconModule,
2240
2936
  MatButtonModule,
2241
2937
  CdkTableModule,
2938
+ ScrollingModule,
2242
2939
  KlesMaterialDynamicformsModule,
2243
2940
  HeaderFieldPipe,
2244
2941
  CellFieldPipe,
@@ -2255,7 +2952,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
2255
2952
  KlesHeaderComponent,
2256
2953
  HeaderPipe,
2257
2954
  RowContextPipe,
2258
- ], template: "<form #form [formGroup]=\"tableService.form\" (ngSubmit)=\"submit()\">\n <!-- [fixedLayout]=\"true\" -->\n <table\n mat-table\n [dataSource]=\"dataSource\"\n matSort\n [trackBy]=\"multiTemplateDataRows() ? null : tableService.trackBy\"\n formArrayName=\"rows\"\n cdkDropList\n [cdkDropListData]=\"tableService.form.controls.rows\"\n (cdkDropListDropped)=\"dragDropRowService.listDropped($event)\"\n [cdkDropListDisabled]=\"!dragDropRowService.enable\"\n [cdkDropListAutoScrollStep]=\"dragDropRowService.autoScrollStep\"\n [cdkDropListSortPredicate]=\"dragDropRowService.sortPredicate\"\n [cdkDropListConnectedTo]=\"dragDropRowService.connectedTo\"\n [multiTemplateDataRows]=\"multiTemplateDataRows()\"\n >\n <colgroup>\n @for (column of columns(); track column.columnDef) {\n <col [style.width]=\"column.width ?? null\" [style.minWidth]=\"column.minWidth ?? null\" [style.maxWidth]=\"column.maxWidth ?? null\" />\n }\n </colgroup>\n\n @for (column of columns(); track column.columnDef) {\n <ng-container [cdkColumnDef]=\"column.columnDef\" [sticky]=\"column.sticky ?? false\" [stickyEnd]=\"column.stickyEnd ?? false\">\n <th\n mat-header-cell\n *matHeaderCellDef\n [appResizableColumn]=\"column\"\n [style.border-inline-end]=\"getColumnSeparator(column, 'header') ?? getStickyStartSeparator(column, 'header')\"\n [style.border-inline-start]=\"getStickyEndSeparator(column, 'header')\"\n [ngStyle]=\"\n column.headerCell?.style?.ngStyle\n | resolveNgStyle\n : tableService.form.get(['header', column.columnDef])?.value\n : tableService.form.get(['header', column.columnDef])?.status\n : tableService.form.controls.header.value\n : tableService.form.controls.header.status\n \"\n >\n <div class=\"cell\">\n <kles-header [header]=\"column | header\" [group]=\"tableService.form.controls.header\">\n <ng-container\n klesDynamicField\n [field]=\"column | headerField\"\n [group]=\"tableService.form.controls.header\"\n [ui]=\"tableService.ui.states.header\"\n ></ng-container>\n </kles-header>\n </div>\n </th>\n\n <td\n mat-cell\n *cdkCellDef=\"let row; let index = index; let dataIndex = dataIndex\"\n [style.border-inline-end]=\"getColumnSeparator(column, 'body') ?? getStickyStartSeparator(column, 'body')\"\n [style.border-inline-start]=\"getStickyEndSeparator(column, 'body')\"\n [ngStyle]=\"\n column.cell?.style?.ngStyle\n | resolveNgStyle: row.controls[column.columnDef].value : row.controls[column.columnDef].status : row.value : row.status\n \"\n (click)=\"cellService.onClick($event, row, dataIndex ?? index, column.columnDef)\"\n (dblclick)=\"cellService.onDoubleClick($event, row, dataIndex ?? index, column.columnDef)\"\n (contextmenu)=\"cellService.onContextMenu($event, row, dataIndex ?? index, column.columnDef)\"\n >\n <div class=\"cell\" [style.--align]=\"column.align\">\n <kles-cell [group]=\"row\" [ui]=\"row | uiField\" [column]=\"column\">\n <ng-container klesDynamicField [field]=\"column | cellField\" [group]=\"row\" [ui]=\"row | uiField\" [context]=\"row | rowContext\"></ng-container>\n </kles-cell>\n </div>\n </td>\n\n <td\n mat-footer-cell\n *matFooterCellDef\n [style.border-inline-end]=\"getColumnSeparator(column, 'footer') ?? getStickyStartSeparator(column, 'footer')\"\n [style.border-inline-start]=\"getStickyEndSeparator(column, 'footer')\"\n [ngStyle]=\"\n column.footerCell?.style?.ngStyle\n | resolveNgStyle\n : tableService.form.get(['footer', column.columnDef])?.value\n : tableService.form.get(['footer', column.columnDef])?.status\n : tableService.form.controls.footer.value\n : tableService.form.controls.footer.status\n \"\n >\n @if (column.footerCell) {\n <ng-container\n klesDynamicField\n [field]=\"column | footerField\"\n [group]=\"tableService.form.controls.footer\"\n [ui]=\"tableService.ui.states.footer\"\n >\n </ng-container>\n }\n </td>\n </ng-container>\n }\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns(); sticky: true\"></tr>\n\n <tr\n mat-row\n *matRowDef=\"let row; let index = index; let dataIndex = dataIndex; columns: displayedColumns()\"\n cdkDrag\n [cdkDragData]=\"row\"\n (click)=\"rowService.onClick($event, row, dataIndex ?? index)\"\n (dblclick)=\"rowService.onDoubleClick($event, row, dataIndex ?? index)\"\n (contextmenu)=\"rowService.onContextMenu($event, row, dataIndex ?? index)\"\n (mouseenter)=\"rowService.onMouseEnter($event, row, dataIndex ?? index)\"\n (mouseleave)=\"rowService.onMouseLeave($event, row, dataIndex ?? index)\"\n ></tr>\n\n @if (multiTemplateDataRows()) {\n @for (extraRow of extraRows(); track extraRow) {\n @for (extraColumn of extraRow.cells; track extraColumn.columnDef) {\n <ng-container [cdkColumnDef]=\"extraColumn.columnDef\">\n <td\n mat-cell\n *cdkCellDef=\"let row\"\n [attr.colspan]=\"extraColumn.colspan | spanPipe: displayedColumns().length\"\n [attr.rowspan]=\"extraColumn.rowspan\"\n [ngStyle]=\"\n extraColumn?.style?.ngStyle\n | resolveNgStyle\n : row.controls[extraColumn.columnDef].value\n : row.controls[extraColumn.columnDef].status\n : row.value\n : row.status\n \"\n >\n <ng-container klesDynamicField [field]=\"extraColumn | extraCellField\" [group]=\"row\" [ui]=\"row | uiField\" [context]=\"row | rowContext\"></ng-container>\n </td>\n </ng-container>\n }\n <tr\n mat-row\n *matRowDef=\"let row; let index = index; let dataIndex = dataIndex; columns: extraRow.displayedColumns; when: extraRow.when\"\n (click)=\"rowService.onClick($event, row, dataIndex ?? index)\"\n (dblclick)=\"rowService.onDoubleClick($event, row, dataIndex ?? index)\"\n (contextmenu)=\"rowService.onContextMenu($event, row, dataIndex ?? index)\"\n (mouseenter)=\"rowService.onMouseEnter($event, row, dataIndex ?? index)\"\n (mouseleave)=\"rowService.onMouseLeave($event, row, dataIndex ?? index)\"\n ></tr>\n }\n }\n\n <tr mat-footer-row *matFooterRowDef=\"displayedColumns(); sticky: true\" [style.display]=\"showFooter() ? '' : 'none'\"></tr>\n </table>\n</form>\n\n@if (loadingService.loading()) {\n <div class=\"table-overlay\" [style.--header-h.px]=\"headerHeightPx()\" [style.--scroll-h.px]=\"scrollHeightPx()\" [style.--footer-h.px]=\"footerHeightPx()\">\n <mat-spinner></mat-spinner>\n </div>\n}\n\n@if (emptyStateService.enabled() && !loadingService.loading() && isEmpty()) {\n <div\n class=\"table-empty-state-overlay\"\n [style.--header-h.px]=\"headerHeightPx()\"\n [style.--scroll-h.px]=\"scrollHeightPx()\"\n [style.--footer-h.px]=\"footerHeightPx()\"\n >\n <div class=\"table-empty-state-content\">\n <ng-container *ngComponentOutlet=\"emptyStateService.component\"></ng-container>\n </div>\n </div>\n}\n", styles: [":host{--kles-table-divider-color: color-mix(in srgb, var(--mat-sys-outline-variant) 65%, transparent);--kles-table-divider-strong-color: var(--mat-sys-outline-variant);--kles-table-header-background: var(--mat-sys-surface-container);--kles-table-header-color: var(--mat-sys-on-surface);--kles-table-header-divider-color: var(--mat-sys-outline-variant);--kles-table-row-hover-background: color-mix(in srgb, var(--mat-sys-primary) 7%, var(--mat-sys-surface));overflow:auto;display:flex;flex-direction:column;position:relative;height:100%;--mat-form-field-filled-container-color: transparent;--mat-form-field-hover-state-layer-opacity: 0;--mat-form-field-focus-state-layer-opacity: 0;--mat-form-field-state-layer-color: transparent}:host(.loading),:host(.empty){min-height:280px}form{display:flex;flex-direction:column;flex-grow:1;position:relative;overflow:auto}table{width:100%;flex-grow:1}th,td{text-wrap:pretty;white-space:normal;padding-top:2px;padding-bottom:2px;box-sizing:border-box}td{word-break:normal}th .cell,td .cell{display:flex;flex-direction:column;justify-content:var(--align, center)}th[appResizableColumn]{position:relative}th[appResizableColumn] .resize-handle{position:absolute;top:0;right:-4px;width:8px;height:100%;cursor:col-resize;-webkit-user-select:none;user-select:none}.table-overlay{position:absolute;inset-inline:0;top:var(--header-h, 56px);bottom:calc(var(--scroll-h, 0px) + var(--footer-h, 0px));display:grid;place-items:center;background:color-mix(in srgb,var(--mat-sys-surface-container-highest) 75%,transparent);box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--mat-sys-outline-variant) 30%,transparent);z-index:500}:host .mat-mdc-row{transition:background-color .12s ease}:host .mat-mdc-row:hover{background:var(--kles-table-row-hover-background)}:host .mat-mdc-table .mat-mdc-cell,:host .mat-mdc-table .mat-mdc-header-cell{border-bottom-color:var(--mat-sys-outline-variant)}:host .mat-mdc-table .mat-mdc-cell:last-child,:host .mat-mdc-table .mat-mdc-header-cell:last-child{border-right:none}:host tr.mat-mdc-footer-row td.mat-mdc-footer-cell{border-top:1px solid var(--kles-table-divider-strong-color)}:host tr.mat-mdc-row:last-of-type td.mat-mdc-cell{border-bottom:1px solid var(--kles-table-divider-color)}:host tr.mat-mdc-footer-row{font-weight:500}:host .mat-mdc-header-row,:host .mat-mdc-header-cell{background-color:var(--kles-table-header-background);color:var(--kles-table-header-color)}:host .mat-mdc-header-cell{border-bottom-color:var(--kles-table-header-divider-color)}.table-empty-state-overlay{position:absolute;inset-inline:0;top:var(--header-h, 56px);bottom:calc(var(--scroll-h, 0px) + var(--footer-h, 0px));z-index:400;overflow:hidden;background:var(--mat-sys-surface);display:grid;place-items:center}.table-empty-state-content{width:100%;height:100%}.scrollbar-hidden{scrollbar-width:none;-ms-overflow-style:none;overflow-y:hidden}.scrollbar-hidden::-webkit-scrollbar{display:none;overflow-y:hidden}\n"] }]
2955
+ ], template: "<form #form cdkScrollable [formGroup]=\"tableService.form\">\n <table\n mat-table\n [dataSource]=\"dataSource\"\n matSort\n [trackBy]=\"multiTemplateDataRows() ? null : tableService.trackBy\"\n formArrayName=\"rows\"\n cdkDropList\n [id]=\"dragDropRowService.dropListId\"\n [cdkDropListData]=\"tableService.klesForm\"\n (cdkDropListDropped)=\"dragDropRowService.listDropped($event)\"\n [cdkDropListDisabled]=\"!dragDropRowService.enable\"\n [cdkDropListAutoScrollStep]=\"dragDropRowService.autoScrollStep\"\n [cdkDropListSortPredicate]=\"dragDropRowService.sortPredicate\"\n [cdkDropListConnectedTo]=\"dragDropRowService.connectedTo\"\n [multiTemplateDataRows]=\"multiTemplateDataRows()\"\n >\n <colgroup>\n @for (column of columns(); track column.columnDef) {\n <col\n [attr.data-column-def]=\"column.columnDef\"\n [style.width]=\"column.width ?? null\"\n [style.minWidth]=\"column.minWidth ?? null\"\n [style.maxWidth]=\"column.maxWidth ?? null\"\n />\n }\n </colgroup>\n\n @for (column of columns(); track column.columnDef) {\n <ng-container [cdkColumnDef]=\"column.columnDef\" [sticky]=\"column.sticky ?? false\" [stickyEnd]=\"column.stickyEnd ?? false\">\n <th\n mat-header-cell\n *matHeaderCellDef\n [appResizableColumn]=\"column\"\n [style.border-inline-end]=\"getColumnSeparator(column, 'header') ?? getStickyStartSeparator(column, 'header')\"\n [style.border-inline-start]=\"getStickyEndSeparator(column, 'header')\"\n [ngStyle]=\"\n column.headerCell?.style?.ngStyle\n | resolveNgStyle\n : tableService.form.get(['header', column.columnDef])?.value\n : tableService.form.get(['header', column.columnDef])?.status\n : tableService.form.controls.header.value\n : tableService.form.controls.header.status\n \"\n >\n <div class=\"cell\">\n <kles-header\n [header]=\"column | header\"\n [group]=\"tableService.form.controls.header\"\n [dragHandleSpacer]=\"dragDropRowService.handleOnly && column.columnDef === displayedColumns()?.[0]\"\n >\n <ng-container\n klesDynamicField\n [field]=\"column | headerField\"\n [group]=\"tableService.form.controls.header\"\n [ui]=\"tableService.ui.states.header\"\n ></ng-container>\n </kles-header>\n </div>\n </th>\n\n <td\n mat-cell\n *cdkCellDef=\"let row; let index = index; let dataIndex = dataIndex\"\n [style.border-inline-end]=\"getColumnSeparator(column, 'body') ?? getStickyStartSeparator(column, 'body')\"\n [style.border-inline-start]=\"getStickyEndSeparator(column, 'body')\"\n [ngStyle]=\"\n column.cell?.style?.ngStyle\n | resolveNgStyle: row.controls[column.columnDef].value : row.controls[column.columnDef].status : row.value : row.status\n \"\n (click)=\"cellService.onClick($event, row, dataIndex ?? index, column.columnDef)\"\n (dblclick)=\"cellService.onDoubleClick($event, row, dataIndex ?? index, column.columnDef)\"\n (contextmenu)=\"cellService.onContextMenu($event, row, dataIndex ?? index, column.columnDef)\"\n >\n <div class=\"cell\" [style.--align]=\"column.align\">\n <kles-cell\n [group]=\"row\"\n [ui]=\"row | uiField\"\n [column]=\"column\"\n [rowIndex]=\"dataIndex ?? index\"\n [dragHandle]=\"dragDropRowService.handleOnly && column.columnDef === displayedColumns()?.[0]\"\n >\n @if (column.columnDef === selectionService.key && selectionService.isLoading(row)) {\n <mat-spinner class=\"selection-row-spinner\" [diameter]=\"20\"></mat-spinner>\n } @else {\n <ng-container klesDynamicField [field]=\"column | cellField\" [group]=\"row\" [ui]=\"row | uiField\" [context]=\"row | rowContext\"></ng-container>\n }\n </kles-cell>\n </div>\n </td>\n\n <td\n mat-footer-cell\n *matFooterCellDef\n [style.border-inline-end]=\"getColumnSeparator(column, 'footer') ?? getStickyStartSeparator(column, 'footer')\"\n [style.border-inline-start]=\"getStickyEndSeparator(column, 'footer')\"\n [ngStyle]=\"\n column.footerCell?.style?.ngStyle\n | resolveNgStyle\n : tableService.form.get(['footer', column.columnDef])?.value\n : tableService.form.get(['footer', column.columnDef])?.status\n : tableService.form.controls.footer.value\n : tableService.form.controls.footer.status\n \"\n >\n @if (column.footerCell) {\n <ng-container\n klesDynamicField\n [field]=\"column | footerField\"\n [group]=\"tableService.form.controls.footer\"\n [ui]=\"tableService.ui.states.footer\"\n >\n </ng-container>\n }\n </td>\n </ng-container>\n }\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns(); sticky: true\"></tr>\n\n <tr\n mat-row\n *matRowDef=\"let row; let index = index; let dataIndex = dataIndex; columns: displayedColumns()\"\n cdkDrag\n [cdkDragData]=\"row\"\n [cdkDragDisabled]=\"dragDropRowService.isDragDisabled(row)\"\n (cdkDragStarted)=\"dragDropRowService.rowDragStarted(row, dataIndex ?? index)\"\n (cdkDragMoved)=\"dragDropRowService.rowDragMoved(row, dataIndex ?? index)\"\n (cdkDragEnded)=\"dragDropRowService.rowDragEnded(row, dataIndex ?? index)\"\n (click)=\"rowService.onClick($event, row, dataIndex ?? index)\"\n (dblclick)=\"rowService.onDoubleClick($event, row, dataIndex ?? index)\"\n (contextmenu)=\"rowService.onContextMenu($event, row, dataIndex ?? index)\"\n (mouseenter)=\"rowService.onMouseEnter($event, row, dataIndex ?? index)\"\n (mouseleave)=\"rowService.onMouseLeave($event, row, dataIndex ?? index)\"\n >\n @if (dragDropRowService.previewComponent; as previewComponent) {\n <ng-template cdkDragPreview [matchSize]=\"dragDropRowService.previewMatchSize\">\n <div class=\"kles-row-drag-preview\">\n <ng-container\n *ngComponentOutlet=\"previewComponent; injector: dragDropRowService.componentInjector(row, dataIndex ?? index)\"\n ></ng-container>\n </div>\n </ng-template>\n }\n\n @if (dragDropRowService.placeholderComponent; as placeholderComponent) {\n <ng-template cdkDragPlaceholder>\n <tr class=\"kles-row-drag-placeholder\">\n <td [attr.colspan]=\"displayedColumns()?.length ?? 1\">\n <ng-container\n *ngComponentOutlet=\"placeholderComponent; injector: dragDropRowService.componentInjector(row, dataIndex ?? index)\"\n ></ng-container>\n </td>\n </tr>\n </ng-template>\n }\n </tr>\n\n @if (multiTemplateDataRows()) {\n @for (extraRow of extraRows(); track extraRow) {\n @for (extraColumn of extraRow.cells; track extraColumn.columnDef) {\n <ng-container [cdkColumnDef]=\"extraColumn.columnDef\">\n <td\n mat-cell\n *cdkCellDef=\"let row\"\n [attr.colspan]=\"extraColumn.colspan | spanPipe: displayedColumns().length\"\n [attr.rowspan]=\"extraColumn.rowspan\"\n [ngStyle]=\"\n extraColumn?.style?.ngStyle\n | resolveNgStyle\n : row.controls[extraColumn.columnDef].value\n : row.controls[extraColumn.columnDef].status\n : row.value\n : row.status\n \"\n >\n <ng-container klesDynamicField [field]=\"extraColumn | extraCellField\" [group]=\"row\" [ui]=\"row | uiField\" [context]=\"row | rowContext\"></ng-container>\n </td>\n </ng-container>\n }\n <tr\n mat-row\n *matRowDef=\"let row; let index = index; let dataIndex = dataIndex; columns: extraRow.displayedColumns; when: extraRow.when\"\n (click)=\"rowService.onClick($event, row, dataIndex ?? index)\"\n (dblclick)=\"rowService.onDoubleClick($event, row, dataIndex ?? index)\"\n (contextmenu)=\"rowService.onContextMenu($event, row, dataIndex ?? index)\"\n (mouseenter)=\"rowService.onMouseEnter($event, row, dataIndex ?? index)\"\n (mouseleave)=\"rowService.onMouseLeave($event, row, dataIndex ?? index)\"\n ></tr>\n }\n }\n\n <tr mat-footer-row *matFooterRowDef=\"displayedColumns(); sticky: true\" [style.display]=\"showFooter() ? '' : 'none'\"></tr>\n </table>\n</form>\n\n@if (loadingService.loading()) {\n <div class=\"table-overlay\" [style.--header-h.px]=\"headerHeightPx()\" [style.--scroll-h.px]=\"scrollHeightPx()\" [style.--footer-h.px]=\"footerHeightPx()\">\n <mat-spinner></mat-spinner>\n </div>\n}\n\n@if (emptyStateService.enabled() && !loadingService.loading() && isEmpty()) {\n <div\n class=\"table-empty-state-overlay\"\n [style.--header-h.px]=\"headerHeightPx()\"\n [style.--scroll-h.px]=\"scrollHeightPx()\"\n [style.--footer-h.px]=\"footerHeightPx()\"\n >\n <div class=\"table-empty-state-content\">\n <ng-container *ngComponentOutlet=\"emptyStateService.component\"></ng-container>\n </div>\n </div>\n}\n", styles: [":host{--kles-table-divider-color: color-mix(in srgb, var(--mat-sys-outline-variant) 65%, transparent);--kles-table-divider-strong-color: var(--mat-sys-outline-variant);--kles-table-header-background: var(--mat-sys-surface-container);--kles-table-header-color: var(--mat-sys-on-surface);--kles-table-header-divider-color: var(--mat-sys-outline-variant);--kles-table-row-hover-background: color-mix(in srgb, var(--mat-sys-primary) 7%, var(--mat-sys-surface));overflow:auto;display:flex;flex-direction:column;position:relative;height:100%;--mat-form-field-filled-container-color: transparent;--mat-form-field-hover-state-layer-opacity: 0;--mat-form-field-focus-state-layer-opacity: 0;--mat-form-field-state-layer-color: transparent}:host(.loading),:host(.empty){min-height:280px}form{display:flex;flex-direction:column;flex-grow:1;position:relative;overflow:auto}table{width:100%;flex-grow:1}th,td{text-wrap:pretty;white-space:normal;padding-top:2px;padding-bottom:2px;box-sizing:border-box}td{word-break:normal}th .cell,td .cell{display:flex;flex-direction:column;justify-content:var(--align, center)}th[appResizableColumn].resizable-column{position:relative}th[appResizableColumn]>.resize-handle{position:absolute;top:0;inset-inline-end:-7px;z-index:20;width:14px;height:100%;cursor:col-resize;-webkit-user-select:none;user-select:none;touch-action:none;outline:none}th[appResizableColumn]>.resize-handle:before{content:\"\";position:absolute;top:15%;bottom:15%;inset-inline-start:6px;width:2px;border-radius:2px;background:var(--mat-sys-outline);opacity:0;transition:opacity .12s ease,background-color .12s ease,transform .12s ease}th[appResizableColumn].resizable-column:hover>.resize-handle:before,th[appResizableColumn]>.resize-handle:focus-visible:before{opacity:.65}th[appResizableColumn].column-resizing>.resize-handle:before{top:0;bottom:0;background:var(--mat-sys-primary);opacity:1;transform:scaleX(1.25)}th[appResizableColumn].column-resizing>.resize-handle:after{content:\"\";position:absolute;top:100%;inset-inline-start:6px;width:2px;height:100vh;background:color-mix(in srgb,var(--mat-sys-primary) 70%,transparent);pointer-events:none}th[appResizableColumn]>.resize-handle>.resize-width-label{position:absolute;top:calc(100% + 8px);inset-inline-start:50%;z-index:30;display:none;padding:3px 7px;color:var(--mat-sys-on-primary);font-size:11px;font-weight:600;line-height:16px;white-space:nowrap;background:var(--mat-sys-primary);border-radius:var(--mat-sys-corner-extra-small);box-shadow:var(--mat-sys-level2);transform:translate(-50%);pointer-events:none}th[appResizableColumn].column-resizing>.resize-handle>.resize-width-label{display:block}:host .column-resizing-cell{width:var(--kles-column-resize-width)!important;min-width:var(--kles-column-resize-width)!important;max-width:var(--kles-column-resize-width)!important;flex:0 0 var(--kles-column-resize-width)!important;background-image:linear-gradient(color-mix(in srgb,var(--mat-sys-primary) 5%,transparent),color-mix(in srgb,var(--mat-sys-primary) 5%,transparent))}.table-overlay{position:absolute;inset-inline:0;top:var(--header-h, 56px);bottom:calc(var(--scroll-h, 0px) + var(--footer-h, 0px));display:grid;place-items:center;background:color-mix(in srgb,var(--mat-sys-surface-container-highest) 75%,transparent);box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--mat-sys-outline-variant) 30%,transparent);z-index:500}:host .mat-mdc-row{transition:background-color .12s ease}:host .mat-mdc-row:hover{background:var(--kles-table-row-hover-background)}:host tr.mat-mdc-row.cdk-drag-placeholder{opacity:1;background:color-mix(in srgb,var(--mat-sys-primary) 12%,var(--mat-sys-surface))}:host tr.mat-mdc-row.cdk-drag-placeholder td{border-block:2px dashed var(--mat-sys-primary)}:host tr.mat-mdc-row.cdk-drag-placeholder td>*{visibility:hidden}:host tr.mat-mdc-row.cdk-drag-placeholder td:first-child{border-inline-start:2px dashed var(--mat-sys-primary)}:host tr.mat-mdc-row.cdk-drag-placeholder td:last-child{border-inline-end:2px dashed var(--mat-sys-primary)}:host .cdk-drop-list-dragging tr.mat-mdc-row:not(.cdk-drag-placeholder),:host tr.mat-mdc-row.cdk-drag-animating{transition:transform .18s cubic-bezier(0,0,.2,1)}.kles-row-drag-preview{overflow:hidden;border-radius:var(--mat-sys-corner-small);background:var(--mat-sys-surface-container);box-shadow:var(--mat-sys-level3)}.selection-row-spinner{margin-inline:auto}:host tr.kles-row-drag-placeholder td{padding:0;border:2px dashed var(--mat-sys-primary);background:color-mix(in srgb,var(--mat-sys-primary) 12%,var(--mat-sys-surface))}:host .mat-mdc-table .mat-mdc-cell,:host .mat-mdc-table .mat-mdc-header-cell{border-bottom-color:var(--mat-sys-outline-variant)}:host .mat-mdc-table .mat-mdc-cell:last-child,:host .mat-mdc-table .mat-mdc-header-cell:last-child{border-right:none}:host tr.mat-mdc-footer-row td.mat-mdc-footer-cell{border-top:1px solid var(--kles-table-divider-strong-color)}:host tr.mat-mdc-row:last-of-type td.mat-mdc-cell{border-bottom:1px solid var(--kles-table-divider-color)}:host tr.mat-mdc-footer-row{font-weight:500}:host .mat-mdc-header-row,:host .mat-mdc-header-cell{background-color:var(--kles-table-header-background);color:var(--kles-table-header-color)}:host .mat-mdc-header-cell{border-bottom-color:var(--kles-table-header-divider-color)}.table-empty-state-overlay{position:absolute;inset-inline:0;top:var(--header-h, 56px);bottom:calc(var(--scroll-h, 0px) + var(--footer-h, 0px));z-index:400;overflow:hidden;background:var(--mat-sys-surface);display:grid;place-items:center}.table-empty-state-content{width:100%;height:100%}.scrollbar-hidden{scrollbar-width:none;-ms-overflow-style:none;overflow-y:hidden}.scrollbar-hidden::-webkit-scrollbar{display:none;overflow-y:hidden}\n"] }]
2259
2956
  }], ctorParameters: () => [{ type: i0.ElementRef }, { type: KlesTableConnectorService }, { type: undefined, decorators: [{
2260
2957
  type: Inject,
2261
2958
  args: [LOADER_SERVICE]
@@ -2276,7 +2973,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
2276
2973
  args: [SORT_SERVICE]
2277
2974
  }] }, { type: FilterService, decorators: [{
2278
2975
  type: Optional
2279
- }] }, { type: ExpandedRowStore }, { type: RowFormFactory }, { type: EventsService }, { type: RowService }, { type: CellService }, { type: EmptyStateService }], propDecorators: { table: [{
2976
+ }] }, { type: ExpandedRowStore }, { type: RowFormFactory }, { type: EventsService }, { type: RowService }, { type: CellService }, { type: EmptyStateService }, { type: TreeService }], propDecorators: { table: [{
2280
2977
  type: ViewChild,
2281
2978
  args: [MatTable]
2282
2979
  }], matSort: [{
@@ -2535,15 +3232,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
2535
3232
  }] });
2536
3233
 
2537
3234
  class InfiniteScrollTableComponent {
2538
- constructor() { }
2539
- ngOnInit() { }
2540
3235
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: InfiniteScrollTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2541
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.19", type: InfiniteScrollTableComponent, isStandalone: true, selector: "kles-infinite-scroll-table", ngImport: i0, template: "<!-- <cdk-virtual-scroll-viewport itemSize=\"48\">\n <kles-table></kles-table>\n</cdk-virtual-scroll-viewport> -->\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ScrollingModule }] }); }
3236
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.19", type: InfiniteScrollTableComponent, isStandalone: true, selector: "kles-infinite-scroll-table", ngImport: i0, template: "" }); }
2542
3237
  }
2543
3238
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: InfiniteScrollTableComponent, decorators: [{
2544
3239
  type: Component,
2545
- args: [{ selector: 'kles-infinite-scroll-table', standalone: true, imports: [CommonModule, ScrollingModule], template: "<!-- <cdk-virtual-scroll-viewport itemSize=\"48\">\n <kles-table></kles-table>\n</cdk-virtual-scroll-viewport> -->\n" }]
2546
- }], ctorParameters: () => [] });
3240
+ args: [{ selector: 'kles-infinite-scroll-table', standalone: true, imports: [], template: "" }]
3241
+ }] });
2547
3242
 
2548
3243
  class SelectionLoaderService {
2549
3244
  constructor(selectionConfig) {
@@ -2553,7 +3248,7 @@ class SelectionLoaderService {
2553
3248
  return this.selectionConfig?.key || '#select';
2554
3249
  }
2555
3250
  select(row, selected, filters) {
2556
- return (this.selectionConfig?.params?.() || of({})).pipe(auditTime(0), take(1), switchMap((params) => {
3251
+ return defer(() => this.selectionConfig?.params?.() || of({})).pipe(auditTime(0), take(1), switchMap((params) => {
2557
3252
  const selection$ = this.selectionConfig?.select
2558
3253
  ? this.selectionConfig.select(params, row, selected, filters)
2559
3254
  : of({
@@ -2573,10 +3268,14 @@ class SelectionLoaderService {
2573
3268
  loading: true,
2574
3269
  success: false,
2575
3270
  }), result$);
2576
- }));
3271
+ }), catchError((error) => of({
3272
+ error,
3273
+ loading: false,
3274
+ success: false,
3275
+ })));
2577
3276
  }
2578
3277
  selectAll(selected, filters) {
2579
- return (this.selectionConfig?.params?.() || of({})).pipe(auditTime(0), take(1), switchMap((params) => {
3278
+ return defer(() => this.selectionConfig?.params?.() || of({})).pipe(auditTime(0), take(1), switchMap((params) => {
2580
3279
  const selection$ = this.selectionConfig?.selectAll
2581
3280
  ? this.selectionConfig.selectAll(params, selected, filters)
2582
3281
  : of({
@@ -2597,7 +3296,11 @@ class SelectionLoaderService {
2597
3296
  loading: true,
2598
3297
  success: false,
2599
3298
  }), result$);
2600
- }));
3299
+ }), catchError((error) => of({
3300
+ error,
3301
+ loading: false,
3302
+ success: false,
3303
+ })));
2601
3304
  }
2602
3305
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: SelectionLoaderService, deps: [{ token: SELECTION_CONFIG, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
2603
3306
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: SelectionLoaderService }); }
@@ -2795,9 +3498,10 @@ class KlesSelectionModel {
2795
3498
  this._stateChanged = new Subject();
2796
3499
  this._state = KlesSelectionModelState.ENABLED;
2797
3500
  this._count = signal(0, ...(ngDevMode ? [{ debugName: "_count" }] : /* istanbul ignore next */ []));
2798
- initialValues?.forEach((v) => {
2799
- this._selection.add(v);
2800
- });
3501
+ const values = initialValues ?? [];
3502
+ this.assertSelectionCardinality(values);
3503
+ values.forEach((value) => this._selection.add(value));
3504
+ this._count.set(this._selection.size);
2801
3505
  }
2802
3506
  get selected() {
2803
3507
  return {
@@ -2818,20 +3522,32 @@ class KlesSelectionModel {
2818
3522
  get stateChanged() {
2819
3523
  return this._stateChanged.asObservable();
2820
3524
  }
3525
+ get selectionMode() {
3526
+ return this.multiple;
3527
+ }
2821
3528
  select(value, options) {
2822
3529
  const added = [];
2823
3530
  const removed = [];
2824
3531
  if (this._state === KlesSelectionModelState.ENABLED) {
2825
3532
  if (Array.isArray(value)) {
2826
- if (value.length > 1 && !this.multiple) {
2827
- throw getMultipleValuesInSingleSelectionError();
2828
- }
2829
- value.forEach((v) => {
2830
- if (!this.isSelected(v)) {
2831
- this._selection.add(v);
2832
- added.push(v);
3533
+ this.assertSelectionCardinality(value);
3534
+ if (!this.multiple && value.length === 1) {
3535
+ const singleValue = value[0];
3536
+ if (!this.isSelected(singleValue)) {
3537
+ removed.push(...Array.from(this._selection));
3538
+ this._selection.clear();
3539
+ this._selection.add(singleValue);
3540
+ added.push(singleValue);
2833
3541
  }
2834
- });
3542
+ }
3543
+ else {
3544
+ value.forEach((v) => {
3545
+ if (!this.isSelected(v)) {
3546
+ this._selection.add(v);
3547
+ added.push(v);
3548
+ }
3549
+ });
3550
+ }
2835
3551
  }
2836
3552
  else {
2837
3553
  if (!this.isSelected(value)) {
@@ -2845,7 +3561,7 @@ class KlesSelectionModel {
2845
3561
  }
2846
3562
  }
2847
3563
  this._count.set(this._selection.size);
2848
- if (options?.emitEvent ?? true) {
3564
+ if ((options?.emitEvent ?? true) && (added.length > 0 || removed.length > 0)) {
2849
3565
  this._changed.next({ added, removed, count: this._selection.size, state: this._state });
2850
3566
  }
2851
3567
  }
@@ -2869,7 +3585,7 @@ class KlesSelectionModel {
2869
3585
  }
2870
3586
  }
2871
3587
  this._count.set(this._selection.size);
2872
- if (options?.emitEvent ?? true) {
3588
+ if ((options?.emitEvent ?? true) && (added.length > 0 || removed.length > 0)) {
2873
3589
  this._changed.next({ added, removed, count: this._selection.size, state: this._state });
2874
3590
  }
2875
3591
  }
@@ -2896,20 +3612,40 @@ class KlesSelectionModel {
2896
3612
  this._stateChanged.next(this._state);
2897
3613
  }
2898
3614
  isSelected(value) {
2899
- return this._selection.has(this.getValue(value));
3615
+ return this._selection.has(value);
2900
3616
  }
2901
3617
  isMultipleSelection() {
2902
3618
  return this.multiple || false;
2903
3619
  }
2904
- getValue(value) {
2905
- // si jamais je rajoute une méthode de comparaison avec _selection
2906
- return value;
3620
+ reset(values, options) {
3621
+ this.assertSelectionCardinality(values);
3622
+ const previous = Array.from(this._selection);
3623
+ this._selection.clear();
3624
+ values.forEach((value) => this._selection.add(value));
3625
+ this._count.set(this._selection.size);
3626
+ if (options?.emitEvent ?? true) {
3627
+ this._changed.next({
3628
+ added: values.filter((value) => !previous.includes(value)),
3629
+ removed: previous.filter((value) => !this._selection.has(value)),
3630
+ count: this._selection.size,
3631
+ state: this._state,
3632
+ });
3633
+ }
3634
+ }
3635
+ assertSelectionCardinality(values) {
3636
+ if (!this.multiple && values.length > 1) {
3637
+ throw getMultipleValuesInSingleSelectionError();
3638
+ }
2907
3639
  }
2908
3640
  }
2909
3641
 
2910
3642
  class AbstractSelectionService {
2911
- constructor(selectionConfig) {
3643
+ constructor(selectionConfig, fm, eventsService) {
2912
3644
  this.selectionConfig = selectionConfig;
3645
+ this.fm = fm;
3646
+ this.eventsService = eventsService;
3647
+ this._loadingRows = signal(new Set(), ...(ngDevMode ? [{ debugName: "_loadingRows" }] : /* istanbul ignore next */ []));
3648
+ this.loadingRows = this._loadingRows.asReadonly();
2913
3649
  }
2914
3650
  get key() {
2915
3651
  return this.selectionConfig?.key || '#select';
@@ -2917,7 +3653,66 @@ class AbstractSelectionService {
2917
3653
  get selectionMode() {
2918
3654
  return this.selectionConfig?.selectionMode || false;
2919
3655
  }
2920
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: AbstractSelectionService, deps: [{ token: SELECTION_CONFIG, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
3656
+ isLoading(row) {
3657
+ return this._loadingRows().has(row);
3658
+ }
3659
+ emitSelectionEvents(changed, selectedCount = changed.count) {
3660
+ const payload = this.selectionPayload(changed.added, changed.removed, selectedCount);
3661
+ this.eventsService.emit('selectionChange', payload);
3662
+ changed.added?.forEach((row) => this.eventsService.emit('rowSelect', this.rowPayload(row)));
3663
+ changed.removed?.forEach((row) => this.eventsService.emit('rowUnselect', this.rowPayload(row)));
3664
+ }
3665
+ emitBulkSelectionEvent(selected, selectedCount) {
3666
+ this.eventsService.emit(selected ? 'selectAll' : 'unselectAll', this.selectionPayload(undefined, undefined, selectedCount));
3667
+ }
3668
+ startRowSelection(row) {
3669
+ this._loadingRows.update((rows) => new Set([...rows, row]));
3670
+ row.controls[this.key]?.disable({ emitEvent: false });
3671
+ }
3672
+ stabilizeRowSelection(row, selected) {
3673
+ row.controls[this.key]?.patchValue(selected, { emitEvent: false });
3674
+ this._loadingRows.update((rows) => {
3675
+ const next = new Set(rows);
3676
+ next.delete(row);
3677
+ return next;
3678
+ });
3679
+ if (this.selectionModel.state === KlesSelectionModelState.DISABLED || this.selectionConfig?.isDisabled?.(row)) {
3680
+ row.controls[this.key]?.disable({ emitEvent: false });
3681
+ }
3682
+ else {
3683
+ row.controls[this.key]?.enable({ emitEvent: false });
3684
+ }
3685
+ }
3686
+ emitSelectionError(error, requestedSelected, previousSelected, row) {
3687
+ const payload = {
3688
+ error,
3689
+ requestedSelected,
3690
+ previousSelected,
3691
+ ...(row ? this.rowPayload(row) : {}),
3692
+ };
3693
+ this.eventsService.emit('selectionError', payload);
3694
+ }
3695
+ selectionPayload(addedRows, removedRows, selectedCount = 0) {
3696
+ const selectedRows = this.selectionModel.selected.items ?? [];
3697
+ return {
3698
+ selectedRows,
3699
+ selectedValues: selectedRows.map((row) => row.value),
3700
+ selectedRawValues: selectedRows.map((row) => row.getRawValue()),
3701
+ selectedCount,
3702
+ addedRows,
3703
+ removedRows,
3704
+ allSelected: selectedCount > 0 && selectedCount === this.linesTotal(),
3705
+ };
3706
+ }
3707
+ rowPayload(row) {
3708
+ return {
3709
+ row,
3710
+ rowIndex: this.fm.getRows().controls.indexOf(row),
3711
+ value: row.value,
3712
+ rawValue: row.getRawValue(),
3713
+ };
3714
+ }
3715
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: AbstractSelectionService, deps: [{ token: SELECTION_CONFIG, optional: true }, { token: KlesForm }, { token: EventsService }], target: i0.ɵɵFactoryTarget.Injectable }); }
2921
3716
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: AbstractSelectionService }); }
2922
3717
  }
2923
3718
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: AbstractSelectionService, decorators: [{
@@ -2927,11 +3722,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
2927
3722
  }, {
2928
3723
  type: Inject,
2929
3724
  args: [SELECTION_CONFIG]
2930
- }] }] });
3725
+ }] }, { type: KlesForm }, { type: EventsService }] });
2931
3726
  class SelectionService extends AbstractSelectionService {
2932
- constructor(selectionConfig, fm, selectionLoaderService, scrollbarService, loadingService, datasourceService, linesService) {
2933
- super(selectionConfig);
2934
- this.fm = fm;
3727
+ constructor(selectionConfig, fm, selectionLoaderService, scrollbarService, loadingService, datasourceService, linesService, eventsService) {
3728
+ super(selectionConfig, fm, eventsService);
2935
3729
  this.selectionLoaderService = selectionLoaderService;
2936
3730
  this.scrollbarService = scrollbarService;
2937
3731
  this.loadingService = loadingService;
@@ -2956,21 +3750,25 @@ class SelectionService extends AbstractSelectionService {
2956
3750
  enable() {
2957
3751
  this.selectionModel.enable();
2958
3752
  }
3753
+ linesTotal() {
3754
+ return this.linesService.total();
3755
+ }
2959
3756
  setSelection() {
2960
3757
  this.linesService
2961
3758
  .loaded()
2962
3759
  .pipe(takeUntilDestroyed(this.destroyRef))
2963
3760
  .subscribe(() => {
3761
+ // Build the initial model silently, then update the header once.
2964
3762
  this.fm.getRows().controls.forEach((group) => {
2965
3763
  if (group.controls[this.selectionLoaderService.key]?.value === true) {
2966
- this.selectionModel.select(group, { emitEvent: false }); // event false to avoid multiple send event
3764
+ this.selectionModel.select(group, { emitEvent: false });
2967
3765
  }
2968
3766
  else if (this.selectionConfig?.isSelected != undefined && this.selectionConfig.isSelected(group)) {
2969
- this.selectionModel.select(group, { emitEvent: false }); // event false to avoid multiple send event
3767
+ this.selectionModel.select(group, { emitEvent: false });
2970
3768
  group.controls[this.selectionLoaderService.key]?.patchValue(true, { emitEvent: false });
2971
3769
  }
2972
3770
  else {
2973
- this.selectionModel.deselect(group, { emitEvent: false }); // event false to avoid multiple send event
3771
+ this.selectionModel.deselect(group, { emitEvent: false });
2974
3772
  }
2975
3773
  if (this.selectionConfig?.isDisabled && this.selectionConfig.isDisabled(group)) {
2976
3774
  group.controls[this.selectionLoaderService.key]?.disable({ emitEvent: false });
@@ -2983,31 +3781,46 @@ class SelectionService extends AbstractSelectionService {
2983
3781
  this.fm
2984
3782
  .getHeader()
2985
3783
  .controls[this.key]?.valueChanges.pipe(takeUntilDestroyed(this.destroyRef), switchMap((value) => {
2986
- return this.selectionLoaderService.selectAll(!!value, this.fm.getHeader().getRawValue());
3784
+ const requestedSelected = !!value;
3785
+ const previousSelected = this.areAllFilteredRowsSelected();
3786
+ return this.selectionLoaderService
3787
+ .selectAll(requestedSelected, this.fm.getHeader().getRawValue())
3788
+ .pipe(map((response) => ({ response, requestedSelected, previousSelected })));
2987
3789
  }))
2988
- .subscribe((response) => {
3790
+ .subscribe(({ response, requestedSelected, previousSelected }) => {
2989
3791
  if (response.loading) {
2990
3792
  this.scrollbarService.toTop('instant');
2991
3793
  this.loadingService.start();
2992
3794
  return;
2993
3795
  }
2994
- else {
2995
- this.loadingService.stop();
2996
- if (response.selected) {
2997
- if (this.selectionModel.isMultipleSelection()) {
2998
- this.selectionModel.select(this.datasourceService.datasource.filteredData?.filter((g) => g.controls[this.selectionLoaderService.key]?.enabled) ??
2999
- []);
3000
- }
3001
- else {
3002
- this.selectionModel.select(this.datasourceService.datasource.filteredData?.filter((g) => g.controls[this.selectionLoaderService.key]?.enabled)[0] ?? []);
3003
- }
3796
+ this.loadingService.stop();
3797
+ if (!response.success || response.selected === undefined) {
3798
+ this.updateHeader();
3799
+ this.emitSelectionError(response.error ?? new Error('The bulk selection response is invalid.'), requestedSelected, previousSelected);
3800
+ return;
3801
+ }
3802
+ if (response.selected) {
3803
+ if (this.selectionModel.isMultipleSelection()) {
3804
+ this.selectionModel.select(this.datasourceService.datasource.filteredData?.filter((g) => g.controls[this.selectionLoaderService.key]?.enabled) ??
3805
+ []);
3004
3806
  }
3005
3807
  else {
3006
- this.selectionModel.deselect(this.datasourceService.datasource.filteredData?.filter((g) => g.controls[this.selectionLoaderService.key]?.enabled));
3808
+ const row = this.datasourceService.datasource.filteredData?.filter((g) => g.controls[this.selectionLoaderService.key]?.enabled)[0];
3809
+ if (row) {
3810
+ this.selectionModel.select(row);
3811
+ }
3007
3812
  }
3008
3813
  }
3814
+ else {
3815
+ this.selectionModel.deselect(this.datasourceService.datasource.filteredData?.filter((g) => g.controls[this.selectionLoaderService.key]?.enabled));
3816
+ }
3817
+ this.emitBulkSelectionEvent(response.selected, this.selectionModel.selected.count);
3009
3818
  });
3010
3819
  }
3820
+ areAllFilteredRowsSelected() {
3821
+ const rows = this.datasourceService.datasource.filteredData.filter((group) => group.controls[this.selectionLoaderService.key]?.enabled);
3822
+ return rows.length > 0 && rows.every((group) => this.selectionModel.isSelected(group));
3823
+ }
3011
3824
  listenRowSelection() {
3012
3825
  this.datasourceService.datasource
3013
3826
  .connect()
@@ -3020,25 +3833,32 @@ class SelectionService extends AbstractSelectionService {
3020
3833
  })
3021
3834
  .filter(Boolean));
3022
3835
  }), concatMap(({ row, selected }) => {
3836
+ const previousSelected = this.selectionModel.isSelected(row);
3023
3837
  return this.selectionLoaderService.select(row, selected).pipe(map((response) => {
3024
3838
  return {
3025
3839
  row,
3840
+ selected,
3841
+ previousSelected,
3026
3842
  response,
3027
3843
  };
3028
3844
  }));
3029
3845
  }))
3030
- .subscribe(({ row, response }) => {
3846
+ .subscribe(({ row, selected, previousSelected, response }) => {
3031
3847
  if (response.loading) {
3032
- //mettre la ligne avec un spinner
3848
+ this.startRowSelection(row);
3849
+ return;
3850
+ }
3851
+ if (!response.success || response.selected === undefined) {
3852
+ this.stabilizeRowSelection(row, previousSelected);
3853
+ this.emitSelectionError(response.error ?? new Error('The row selection response is invalid.'), selected, previousSelected, row);
3854
+ return;
3855
+ }
3856
+ this.stabilizeRowSelection(row, response.selected);
3857
+ if (response.selected) {
3858
+ this.selectionModel.select(row);
3033
3859
  }
3034
3860
  else {
3035
- if (response.selected) {
3036
- this.selectionModel.select(row);
3037
- }
3038
- else {
3039
- this.selectionModel.deselect(row);
3040
- }
3041
- //enlever la ligne en spinner
3861
+ this.selectionModel.deselect(row);
3042
3862
  }
3043
3863
  });
3044
3864
  }
@@ -3052,12 +3872,15 @@ class SelectionService extends AbstractSelectionService {
3052
3872
  });
3053
3873
  this.fm.getRows().updateValueAndValidity({ emitEvent: false });
3054
3874
  this.updateHeader();
3875
+ this.emitSelectionEvents(changed);
3055
3876
  });
3056
3877
  this.selectionModel.stateChanged.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((state) => {
3057
3878
  if (state === KlesSelectionModelState.ENABLED) {
3058
3879
  this.fm.getHeader().controls[this.key].enable({ emitEvent: false });
3059
3880
  this.fm.getRows().controls.forEach((group) => {
3060
- group.controls[this.key].enable({ emitEvent: false });
3881
+ if (!this.isLoading(group) && !this.selectionConfig?.isDisabled?.(group)) {
3882
+ group.controls[this.key].enable({ emitEvent: false });
3883
+ }
3061
3884
  });
3062
3885
  }
3063
3886
  else {
@@ -3094,7 +3917,7 @@ class SelectionService extends AbstractSelectionService {
3094
3917
  this.fm.getHeader().controls[this.selectionLoaderService.key]?.patchValue(false, { emitEvent: false });
3095
3918
  }
3096
3919
  }
3097
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: SelectionService, deps: [{ token: SELECTION_CONFIG, optional: true }, { token: KlesForm }, { token: SelectionLoaderService }, { token: ScrollbarService }, { token: LoadingService }, { token: DATASOURCE_SERVICE }, { token: LINES_SERVICE }], target: i0.ɵɵFactoryTarget.Injectable }); }
3920
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: SelectionService, deps: [{ token: SELECTION_CONFIG, optional: true }, { token: KlesForm }, { token: SelectionLoaderService }, { token: ScrollbarService }, { token: LoadingService }, { token: DATASOURCE_SERVICE }, { token: LINES_SERVICE }, { token: EventsService }], target: i0.ɵɵFactoryTarget.Injectable }); }
3098
3921
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: SelectionService }); }
3099
3922
  }
3100
3923
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: SelectionService, decorators: [{
@@ -3110,11 +3933,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
3110
3933
  }] }, { type: undefined, decorators: [{
3111
3934
  type: Inject,
3112
3935
  args: [LINES_SERVICE]
3113
- }] }] });
3936
+ }] }, { type: EventsService }] });
3114
3937
  class SelectionLazyService extends AbstractSelectionService {
3115
- constructor(selectionConfig, fm, selectionLoaderService, scrollbarService, loadingService, datasourceService, linesService, filterStore) {
3116
- super(selectionConfig);
3117
- this.fm = fm;
3938
+ constructor(selectionConfig, fm, selectionLoaderService, scrollbarService, loadingService, datasourceService, linesService, filterStore, eventsService) {
3939
+ super(selectionConfig, fm, eventsService);
3118
3940
  this.selectionLoaderService = selectionLoaderService;
3119
3941
  this.scrollbarService = scrollbarService;
3120
3942
  this.loadingService = loadingService;
@@ -3123,8 +3945,10 @@ class SelectionLazyService extends AbstractSelectionService {
3123
3945
  this.filterStore = filterStore;
3124
3946
  this.destroyRef = inject(DestroyRef);
3125
3947
  this._count = signal(0, ...(ngDevMode ? [{ debugName: "_count" }] : /* istanbul ignore next */ []));
3948
+ this.selectionModel = new KlesSelectionModel(selectionConfig?.selectionMode);
3126
3949
  }
3127
3950
  register() {
3951
+ this.listenSelection();
3128
3952
  this.setSelection();
3129
3953
  this.listenHeaderSelection();
3130
3954
  this.listenRowSelection();
@@ -3133,37 +3957,56 @@ class SelectionLazyService extends AbstractSelectionService {
3133
3957
  return this._count.asReadonly();
3134
3958
  }
3135
3959
  disable() {
3136
- this.fm.getHeader().controls[this.key].disable({ emitEvent: false });
3960
+ this.selectionModel.disable();
3137
3961
  }
3138
3962
  enable() {
3139
- this.fm.getHeader().controls[this.key].enable({ emitEvent: false });
3963
+ this.selectionModel.enable();
3964
+ }
3965
+ linesTotal() {
3966
+ return this.linesService.total();
3140
3967
  }
3141
3968
  listenHeaderSelection() {
3142
3969
  this.fm
3143
3970
  .getHeader()
3144
3971
  .controls[this.key]?.valueChanges.pipe(takeUntilDestroyed(this.destroyRef), switchMap((value) => {
3145
- return this.selectionLoaderService.selectAll(!!value, this.fm.getHeader().getRawValue());
3972
+ const requestedSelected = !!value;
3973
+ const previousSelected = this._count() > 0 && this._count() === this.linesService.total();
3974
+ return this.selectionLoaderService
3975
+ .selectAll(requestedSelected, this.fm.getHeader().getRawValue())
3976
+ .pipe(map((response) => ({ response, requestedSelected, previousSelected })));
3146
3977
  }))
3147
- .subscribe((response) => {
3978
+ .subscribe(({ response, requestedSelected, previousSelected }) => {
3148
3979
  if (response.loading) {
3149
3980
  this.scrollbarService.toTop('instant');
3150
3981
  this.loadingService.start();
3151
3982
  return;
3152
3983
  }
3984
+ this.loadingService.stop();
3985
+ if (!response.success || response.selected === undefined) {
3986
+ this.updateHeader();
3987
+ this.emitSelectionError(response.error ?? new Error('The bulk selection response is invalid.'), requestedSelected, previousSelected);
3988
+ return;
3989
+ }
3990
+ this._count.set(response.count ?? 0);
3991
+ const rows = this.fm.getRows().controls.filter((group) => group.controls[this.selectionLoaderService.key]?.enabled);
3992
+ if (response.selected) {
3993
+ if (this.selectionModel.isMultipleSelection()) {
3994
+ this.selectionModel.select(rows);
3995
+ }
3996
+ else {
3997
+ const row = rows[0];
3998
+ if (row) {
3999
+ this.selectionModel.select(row);
4000
+ }
4001
+ }
4002
+ }
3153
4003
  else {
3154
- this.loadingService.stop();
3155
- this._count.set(response.count ?? 0);
3156
- this.fm
3157
- .getRows()
3158
- .controls.filter((group) => group.controls[this.key]?.enabled)
3159
- .forEach((group) => {
3160
- group.controls[this.selectionLoaderService.key].patchValue(response.selected, { emitEvent: false });
3161
- });
3162
- this.fm.getRows().updateValueAndValidity({ emitEvent: false });
3163
- // if (response.footer) {
3164
- // this.fm.getFooter().patchValue(response.footer, { emitEvent: false });
3165
- // }
4004
+ this.selectionModel.deselect(rows);
3166
4005
  }
4006
+ this.fm.getRows().updateValueAndValidity({
4007
+ emitEvent: false,
4008
+ });
4009
+ this.emitBulkSelectionEvent(response.selected, this._count());
3167
4010
  });
3168
4011
  }
3169
4012
  listenRowSelection() {
@@ -3181,28 +4024,68 @@ class SelectionLazyService extends AbstractSelectionService {
3181
4024
  })
3182
4025
  .filter(Boolean));
3183
4026
  }), withLatestFrom(this.filterStore?.filters$ ?? of({})), concatMap(([{ row, selected }, filters]) => {
4027
+ const previousSelected = this.selectionModel.isSelected(row);
3184
4028
  return this.selectionLoaderService.select(row, selected, filters).pipe(map((response) => {
3185
4029
  return {
3186
4030
  row,
4031
+ selected,
4032
+ previousSelected,
3187
4033
  response,
3188
4034
  };
3189
4035
  }));
3190
4036
  }))
3191
- .subscribe(({ row, response }) => {
4037
+ .subscribe(({ row, selected, previousSelected, response }) => {
3192
4038
  if (response.loading) {
3193
- //mettre la ligne avec un spinner
4039
+ this.startRowSelection(row);
4040
+ return;
4041
+ }
4042
+ if (!response.success || response.selected === undefined) {
4043
+ this.stabilizeRowSelection(row, previousSelected);
4044
+ this.emitSelectionError(response.error ?? new Error('The row selection response is invalid.'), selected, previousSelected, row);
4045
+ return;
4046
+ }
4047
+ this._count.set(response.count ?? 0);
4048
+ this.stabilizeRowSelection(row, response.selected);
4049
+ if (response.selected) {
4050
+ this.selectionModel.select(row);
3194
4051
  }
3195
4052
  else {
3196
- this.fm
3197
- .getUiHeader()
3198
- .get(this.selectionLoaderService.key)
3199
- ?.patchValue({
3200
- indeterminate: response.count != undefined ? response.count > 0 && this.linesService.total() > response.count : false,
4053
+ this.selectionModel.deselect(row);
4054
+ }
4055
+ this.updateHeader(this._count());
4056
+ });
4057
+ }
4058
+ listenSelection() {
4059
+ this.selectionModel.changed.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((changed) => {
4060
+ changed.removed?.forEach((group) => {
4061
+ group.controls[this.selectionLoaderService.key]?.patchValue(false, { emitEvent: false });
4062
+ });
4063
+ changed.added?.forEach((group) => {
4064
+ group.controls[this.selectionLoaderService.key]?.patchValue(true, { emitEvent: false });
4065
+ });
4066
+ this.fm.getRows().updateValueAndValidity({
4067
+ emitEvent: false,
4068
+ });
4069
+ this.emitSelectionEvents(changed, this._count());
4070
+ });
4071
+ this.selectionModel.stateChanged.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((state) => {
4072
+ if (state === KlesSelectionModelState.ENABLED) {
4073
+ this.fm.getHeader().controls[this.key]?.enable({ emitEvent: false });
4074
+ this.fm.getRows().controls.forEach((group) => {
4075
+ if (!this.isLoading(group) && !this.selectionConfig?.isDisabled?.(group)) {
4076
+ group.controls[this.key]?.enable({
4077
+ emitEvent: false,
4078
+ });
4079
+ }
3201
4080
  });
3202
- // if (footer) {
3203
- // this.fm.getFooter().patchValue(footer, { emitEvent: false });
3204
- // }
4081
+ return;
3205
4082
  }
4083
+ this.fm.getHeader().controls[this.key]?.disable({ emitEvent: false });
4084
+ this.fm.getRows().controls.forEach((group) => {
4085
+ group.controls[this.key]?.disable({
4086
+ emitEvent: false,
4087
+ });
4088
+ });
3206
4089
  });
3207
4090
  }
3208
4091
  setSelection() {
@@ -3210,18 +4093,39 @@ class SelectionLazyService extends AbstractSelectionService {
3210
4093
  .loaded()
3211
4094
  .pipe(takeUntilDestroyed(this.destroyRef))
3212
4095
  .subscribe(() => {
3213
- this.fm.getRows().controls.forEach((group) => {
3214
- if (this.selectionConfig?.isSelected != undefined && this.selectionConfig.isSelected(group)) {
3215
- group.controls[this.selectionLoaderService.key]?.patchValue(true, { emitEvent: false });
4096
+ const selectedRows = this.fm.getRows().controls.filter((group) => {
4097
+ const selected = group.controls[this.selectionLoaderService.key]?.value === true || this.selectionConfig?.isSelected?.(group) === true;
4098
+ if (selected) {
4099
+ group.controls[this.selectionLoaderService.key]?.patchValue(true, {
4100
+ emitEvent: false,
4101
+ });
3216
4102
  }
3217
- if (this.selectionConfig?.isDisabled && this.selectionConfig.isDisabled(group)) {
3218
- group.controls[this.selectionLoaderService.key]?.disable({ emitEvent: false });
4103
+ if (this.selectionConfig?.isDisabled?.(group)) {
4104
+ group.controls[this.selectionLoaderService.key]?.disable({
4105
+ emitEvent: false,
4106
+ });
3219
4107
  }
4108
+ return selected;
3220
4109
  });
3221
- // this.updateHeader();
4110
+ this.selectionModel.reset(selectedRows, {
4111
+ emitEvent: false,
4112
+ });
4113
+ this.updateHeader(this._count());
4114
+ });
4115
+ }
4116
+ updateHeader(count = this._count()) {
4117
+ const total = this.linesService.total();
4118
+ this.fm
4119
+ .getUiHeader()
4120
+ .get(this.selectionLoaderService.key)
4121
+ ?.patchValue({
4122
+ indeterminate: count > 0 && count < total,
4123
+ });
4124
+ this.fm.getHeader().controls[this.selectionLoaderService.key]?.patchValue(count > 0 && count === total, {
4125
+ emitEvent: false,
3222
4126
  });
3223
4127
  }
3224
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: SelectionLazyService, deps: [{ token: SELECTION_CONFIG, optional: true }, { token: KlesForm }, { token: SelectionLoaderService }, { token: ScrollbarService }, { token: LoadingService }, { token: DATASOURCE_SERVICE }, { token: LINES_SERVICE }, { token: FilterStore, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
4128
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: SelectionLazyService, deps: [{ token: SELECTION_CONFIG, optional: true }, { token: KlesForm }, { token: SelectionLoaderService }, { token: ScrollbarService }, { token: LoadingService }, { token: DATASOURCE_SERVICE }, { token: LINES_SERVICE }, { token: FilterStore, optional: true }, { token: EventsService }], target: i0.ɵɵFactoryTarget.Injectable }); }
3225
4129
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: SelectionLazyService }); }
3226
4130
  }
3227
4131
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: SelectionLazyService, decorators: [{
@@ -3239,7 +4143,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
3239
4143
  args: [LINES_SERVICE]
3240
4144
  }] }, { type: FilterStore, decorators: [{
3241
4145
  type: Optional
3242
- }] }] });
4146
+ }] }, { type: EventsService }] });
3243
4147
 
3244
4148
  class LoaderService {
3245
4149
  constructor(loaderConfig, eventsService) {
@@ -3367,7 +4271,7 @@ class LinesService {
3367
4271
  this.fm.setRows(this.rowFactory.createRows(this.columnsService
3368
4272
  .columns()
3369
4273
  .map((col) => ({ ...col.cell?.field, name: col.columnDef }))
3370
- .concat(this.extraRowService.extraColumns().map((col) => ({ ...col, name: col.columnDef }))), response.items ?? []));
4274
+ .concat(this.extraRowService.extraFields()), response.items ?? []));
3371
4275
  this._total = response.items?.length ?? 0;
3372
4276
  this._loaded.next();
3373
4277
  this.eventsService.emit('loadSuccess', {
@@ -3438,7 +4342,7 @@ class LinesLazyService {
3438
4342
  this.fm.setRows(this.rowFactory.createRows(this.columnsService
3439
4343
  .columns()
3440
4344
  .map((col) => ({ ...col.cell?.field, name: col.columnDef }))
3441
- .concat(this.extraRowService.extraColumns().map((col) => ({ ...col, name: col.columnDef }))), response.items));
4345
+ .concat(this.extraRowService.extraFields()), response.items));
3442
4346
  this.paginatorService.setlength(response.total ?? 0);
3443
4347
  this._total = response.total ?? 0;
3444
4348
  this._loaded.next();
@@ -3636,7 +4540,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
3636
4540
  args: [LINES_SERVICE]
3637
4541
  }] }, { type: ScrollbarService }] });
3638
4542
 
3639
- // import { ScrollbarLazyOrchestratorService, ScrollbarOrchestratorService } from '../services/features/scrollbar/scrollbar-orchestrator.service';
3640
4543
  class DynamicTableLoaderDirective {
3641
4544
  constructor(viewContainerRef) {
3642
4545
  this.viewContainerRef = viewContainerRef;
@@ -3659,7 +4562,6 @@ class DynamicTableLoaderDirective {
3659
4562
  }
3660
4563
  });
3661
4564
  }
3662
- ngOnInit() { }
3663
4565
  ngOnDestroy() {
3664
4566
  this.clearComponent();
3665
4567
  }
@@ -3704,6 +4606,10 @@ class DynamicTableLoaderDirective {
3704
4606
  provide: EXTRA_ROWS,
3705
4607
  useValue: signal(this.tableConfig().extraRows ?? []),
3706
4608
  },
4609
+ {
4610
+ provide: MULTI_UNFOLD,
4611
+ useValue: this.tableConfig().multiUnfold ?? false,
4612
+ },
3707
4613
  {
3708
4614
  provide: FOOTER,
3709
4615
  useValue: signal(this.tableConfig().footer ?? false),
@@ -3799,7 +4705,7 @@ class DynamicTableLoaderDirective {
3799
4705
  ValidationService,
3800
4706
  SelectionLoaderService,
3801
4707
  PaginatorService,
3802
- LoaderChildrensService, //TODO
4708
+ LoaderChildrensService,
3803
4709
  {
3804
4710
  provide: TABLE_SERVICE,
3805
4711
  useClass: TableService,
@@ -3824,7 +4730,7 @@ class DynamicTableLoaderDirective {
3824
4730
  },
3825
4731
  {
3826
4732
  provide: ROW_DRAG_DROP,
3827
- useFactory: () => new DragDropLazyService(this.tableConfig().dragDropRows),
4733
+ useFactory: () => new DragDropLazyService(this.tableConfig().dragDropRows, inject(EventsService), inject(KlesForm), inject(Injector), this.tableConfig().id),
3828
4734
  },
3829
4735
  {
3830
4736
  provide: SORT_SERVICE,
@@ -3851,8 +4757,7 @@ class DynamicTableLoaderDirective {
3851
4757
  FilterService,
3852
4758
  {
3853
4759
  provide: ROW_DRAG_DROP,
3854
- useFactory: (paginatorstore) => new DragDropService(this.tableConfig().dragDropRows, paginatorstore),
3855
- deps: [...(this.tableConfig().paginator ? [PaginatorStore] : [])],
4760
+ useFactory: () => new DragDropService(this.tableConfig().dragDropRows, inject(EventsService), inject(KlesForm), inject(Injector), this.tableConfig().id),
3856
4761
  },
3857
4762
  {
3858
4763
  provide: SORT_SERVICE,
@@ -3883,12 +4788,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
3883
4788
  }], ctorParameters: () => [{ type: i0.ViewContainerRef }], propDecorators: { tableConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "tableConfig", required: true }] }] } });
3884
4789
 
3885
4790
  class KlesTableComponent {
3886
- // @Output() selectionChange = new EventEmitter<KlesTableSelectionChangePayload<TValue>>();
3887
- // @Output() pageChange = new EventEmitter<KlesTablePageChangePayload>();
3888
- // @Output() sortChange = new EventEmitter<KlesTableSortPayload>();
3889
- // @Output() filterChange = new EventEmitter<KlesTableFilterChangePayload>();
3890
- // @Output() lazyQueryChange = new EventEmitter<KlesTableLazyQueryChangePayload>();
3891
- // @Output() loadError = new EventEmitter<KlesTableLoadErrorPayload>();
3892
4791
  constructor(connectorService) {
3893
4792
  this.connectorService = connectorService;
3894
4793
  this.tableConfig = input.required(...(ngDevMode ? [{ debugName: "tableConfig" }] : /* istanbul ignore next */ []));
@@ -3897,8 +4796,25 @@ class KlesTableComponent {
3897
4796
  this.rowClick = new EventEmitter();
3898
4797
  this.rowDoubleClick = new EventEmitter();
3899
4798
  this.rowContextMenu = new EventEmitter();
4799
+ this.rowMouseEnter = new EventEmitter();
4800
+ this.rowMouseLeave = new EventEmitter();
4801
+ this.rowDrop = new EventEmitter();
4802
+ this.rowDropSuccess = new EventEmitter();
4803
+ this.rowDropError = new EventEmitter();
3900
4804
  this.cellClick = new EventEmitter();
4805
+ this.cellDoubleClick = new EventEmitter();
4806
+ this.cellContextMenu = new EventEmitter();
3901
4807
  this.cellValueChange = new EventEmitter();
4808
+ this.selectionChange = new EventEmitter();
4809
+ this.selectionError = new EventEmitter();
4810
+ this.pageChange = new EventEmitter();
4811
+ this.sortChange = new EventEmitter();
4812
+ this.filterChange = new EventEmitter();
4813
+ this.loadError = new EventEmitter();
4814
+ this.nodeExpand = new EventEmitter();
4815
+ this.nodeCollapse = new EventEmitter();
4816
+ this.nodeLoadChildren = new EventEmitter();
4817
+ this.nodeChildrenLoaded = new EventEmitter();
3902
4818
  this.elevationShadow = computed(() => {
3903
4819
  const level = this.tableConfig().elevation ?? 2;
3904
4820
  return level === 0 ? 'none' : `var(--mat-sys-level${level})`;
@@ -3906,9 +4822,9 @@ class KlesTableComponent {
3906
4822
  }
3907
4823
  ngOnInit() {
3908
4824
  this.connectorService.connected$
3909
- .pipe(takeUntilDestroyed(this.destroyRef), filter((connected) => connected), switchMap(() => {
3910
- return this.connectorService.events.listen();
3911
- }))
4825
+ .pipe(filter((connected) => connected), switchMap(() => {
4826
+ return this.events.listen();
4827
+ }), takeUntilDestroyed(this.destroyRef))
3912
4828
  .subscribe((event) => {
3913
4829
  this.dispatchEvent(event);
3914
4830
  });
@@ -3943,6 +4859,18 @@ class KlesTableComponent {
3943
4859
  get footer() {
3944
4860
  return this.connectorService.footer;
3945
4861
  }
4862
+ get emptyState() {
4863
+ return this.connectorService.emptyState;
4864
+ }
4865
+ get render() {
4866
+ return this.connectorService.render;
4867
+ }
4868
+ get events() {
4869
+ return this.connectorService.events;
4870
+ }
4871
+ get tree() {
4872
+ return this.connectorService.tree;
4873
+ }
3946
4874
  get ui() {
3947
4875
  return this.connectorService.ui;
3948
4876
  }
@@ -3958,34 +4886,67 @@ class KlesTableComponent {
3958
4886
  case 'rowContextMenu':
3959
4887
  this.rowContextMenu.emit(event.payload);
3960
4888
  break;
4889
+ case 'rowMouseEnter':
4890
+ this.rowMouseEnter.emit(event.payload);
4891
+ break;
4892
+ case 'rowMouseLeave':
4893
+ this.rowMouseLeave.emit(event.payload);
4894
+ break;
4895
+ case 'rowDrop':
4896
+ this.rowDrop.emit(event.payload);
4897
+ break;
4898
+ case 'rowDropSuccess':
4899
+ this.rowDropSuccess.emit(event.payload);
4900
+ break;
4901
+ case 'rowDropError':
4902
+ this.rowDropError.emit(event.payload);
4903
+ break;
3961
4904
  case 'cellClick':
3962
4905
  this.cellClick.emit(event.payload);
3963
4906
  break;
4907
+ case 'cellDoubleClick':
4908
+ this.cellDoubleClick.emit(event.payload);
4909
+ break;
4910
+ case 'cellContextMenu':
4911
+ this.cellContextMenu.emit(event.payload);
4912
+ break;
3964
4913
  case 'cellValueChange':
3965
4914
  this.cellValueChange.emit(event.payload);
3966
4915
  break;
3967
- // case 'selectionChange':
3968
- // this.selectionChange.emit(event.payload);
3969
- // break;
3970
- // case 'pageChange':
3971
- // this.pageChange.emit(event.payload);
3972
- // break;
3973
- // case 'sortChange':
3974
- // this.sortChange.emit(event.payload);
3975
- // break;
3976
- // case 'filterChange':
3977
- // this.filterChange.emit(event.payload);
3978
- // break;
3979
- // case 'lazyQueryChange':
3980
- // this.lazyQueryChange.emit(event.payload);
3981
- // break;
3982
- // case 'loadError':
3983
- // this.loadError.emit(event.payload);
3984
- // break;
4916
+ case 'selectionChange':
4917
+ this.selectionChange.emit(event.payload);
4918
+ break;
4919
+ case 'selectionError':
4920
+ this.selectionError.emit(event.payload);
4921
+ break;
4922
+ case 'pageChange':
4923
+ this.pageChange.emit(event.payload);
4924
+ break;
4925
+ case 'sortChange':
4926
+ this.sortChange.emit(event.payload);
4927
+ break;
4928
+ case 'filterChange':
4929
+ this.filterChange.emit(event.payload);
4930
+ break;
4931
+ case 'loadError':
4932
+ this.loadError.emit(event.payload);
4933
+ break;
4934
+ case 'nodeExpand':
4935
+ this.nodeExpand.emit(event.payload);
4936
+ break;
4937
+ case 'nodeCollapse':
4938
+ this.nodeCollapse.emit(event.payload);
4939
+ break;
4940
+ case 'nodeLoadChildren':
4941
+ this.nodeLoadChildren.emit(event.payload);
4942
+ break;
4943
+ case 'nodeChildrenLoaded':
4944
+ this.nodeChildrenLoaded.emit(event.payload);
4945
+ break;
3985
4946
  }
3986
4947
  }
3987
4948
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: KlesTableComponent, deps: [{ token: KlesTableConnectorService }], target: i0.ɵɵFactoryTarget.Component }); }
3988
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.19", type: KlesTableComponent, isStandalone: true, selector: "kles-dynamic-table", inputs: { tableConfig: { classPropertyName: "tableConfig", publicName: "tableConfig", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { tableEvent: "tableEvent", rowClick: "rowClick", rowDoubleClick: "rowDoubleClick", rowContextMenu: "rowContextMenu", cellClick: "cellClick", cellValueChange: "cellValueChange" }, host: { properties: { "attr.id": "this.hostId" } }, providers: [KlesTableConnectorService], ngImport: i0, template: "<div class=\"table-frame\" [style.box-shadow]=\"elevationShadow()\">\n <ng-template appDynamicTableLoader [tableConfig]=\"tableConfig()\"></ng-template>\n</div>\n", styles: [":host{display:flex;flex-direction:column;max-height:100%;overflow:auto;padding:4px;box-sizing:border-box}.table-frame{display:flex;flex-direction:column;flex:1 1 auto;min-height:0;background:var(--mat-sys-surface);border-radius:var(--mat-sys-corner-small);overflow:hidden}\n"], dependencies: [{ kind: "directive", type: DynamicTableLoaderDirective, selector: "[appDynamicTableLoader]", inputs: ["tableConfig"] }] }); }
4949
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.19", type: KlesTableComponent, isStandalone: true, selector: "kles-dynamic-table", inputs: { tableConfig: { classPropertyName: "tableConfig", publicName: "tableConfig", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { tableEvent: "tableEvent", rowClick: "rowClick", rowDoubleClick: "rowDoubleClick", rowContextMenu: "rowContextMenu", rowMouseEnter: "rowMouseEnter", rowMouseLeave: "rowMouseLeave", rowDrop: "rowDrop", rowDropSuccess: "rowDropSuccess", rowDropError: "rowDropError", cellClick: "cellClick", cellDoubleClick: "cellDoubleClick", cellContextMenu: "cellContextMenu", cellValueChange: "cellValueChange", selectionChange: "selectionChange", selectionError: "selectionError", pageChange: "pageChange", sortChange: "sortChange", filterChange: "filterChange", loadError: "loadError", nodeExpand: "nodeExpand", nodeCollapse: "nodeCollapse", nodeLoadChildren: "nodeLoadChildren", nodeChildrenLoaded: "nodeChildrenLoaded" }, host: { properties: { "attr.id": "this.hostId" } }, providers: [KlesTableConnectorService], ngImport: i0, template: "<div class=\"table-frame\" [style.box-shadow]=\"elevationShadow()\">\n <ng-template appDynamicTableLoader [tableConfig]=\"tableConfig()\"></ng-template>\n</div>\n", styles: [":host{display:flex;flex-direction:column;max-height:100%;overflow:auto;padding:4px;box-sizing:border-box}.table-frame{display:flex;flex-direction:column;flex:1 1 auto;min-height:0;background:var(--mat-sys-surface);border-radius:var(--mat-sys-corner-small);overflow:hidden}\n"], dependencies: [{ kind: "directive", type: DynamicTableLoaderDirective, selector: "[appDynamicTableLoader]", inputs: ["tableConfig"] }] }); }
3989
4950
  }
3990
4951
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: KlesTableComponent, decorators: [{
3991
4952
  type: Component,
@@ -3998,10 +4959,44 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
3998
4959
  type: Output
3999
4960
  }], rowContextMenu: [{
4000
4961
  type: Output
4962
+ }], rowMouseEnter: [{
4963
+ type: Output
4964
+ }], rowMouseLeave: [{
4965
+ type: Output
4966
+ }], rowDrop: [{
4967
+ type: Output
4968
+ }], rowDropSuccess: [{
4969
+ type: Output
4970
+ }], rowDropError: [{
4971
+ type: Output
4001
4972
  }], cellClick: [{
4002
4973
  type: Output
4974
+ }], cellDoubleClick: [{
4975
+ type: Output
4976
+ }], cellContextMenu: [{
4977
+ type: Output
4003
4978
  }], cellValueChange: [{
4004
4979
  type: Output
4980
+ }], selectionChange: [{
4981
+ type: Output
4982
+ }], selectionError: [{
4983
+ type: Output
4984
+ }], pageChange: [{
4985
+ type: Output
4986
+ }], sortChange: [{
4987
+ type: Output
4988
+ }], filterChange: [{
4989
+ type: Output
4990
+ }], loadError: [{
4991
+ type: Output
4992
+ }], nodeExpand: [{
4993
+ type: Output
4994
+ }], nodeCollapse: [{
4995
+ type: Output
4996
+ }], nodeLoadChildren: [{
4997
+ type: Output
4998
+ }], nodeChildrenLoaded: [{
4999
+ type: Output
4005
5000
  }], hostId: [{
4006
5001
  type: HostBinding,
4007
5002
  args: ['attr.id']
@@ -4045,5 +5040,5 @@ var AlignCell;
4045
5040
  * Generated bundle index. Do not edit.
4046
5041
  */
4047
5042
 
4048
- export { AlignCell, COLUMNS, DATASOURCE_SERVICE, DRAG_DROP_CONFIG, EMPTY_STATE_CONFIG, EXTRA_ROWS, FOOTER, HEADER_SERVICE, KlesMaterialTableModule, KlesTableComponent, KlesTableEmptyStateComponent, KlesTableIntl, LINES_SERVICE, LOADER_CONFIG, LOADER_SERVICE, PAGINATOR_CONFIG, ROW_DRAG_DROP, SCROLLBAR_ORCHESTRATOR_SERVICE, SELECTION_CONFIG, SELECTION_SERVICE, SORT_CONFIG, SORT_SERVICE, Span, TABLE_SERVICE, TableComponent, linesLazyLoader, linesLoader, selectionConfig };
5043
+ export { AlignCell, COLUMNS, DATASOURCE_SERVICE, DRAG_DROP_CONFIG, EMPTY_STATE_CONFIG, EXTRA_ROWS, FOOTER, HEADER_SERVICE, KLES_DRAG_DROP_ROW_CONTEXT, KlesMaterialTableModule, KlesTableComponent, KlesTableEmptyStateComponent, KlesTableIntl, LINES_SERVICE, LOADER_CONFIG, LOADER_SERVICE, MULTI_UNFOLD, PAGINATOR_CONFIG, ROW_DRAG_DROP, SCROLLBAR_ORCHESTRATOR_SERVICE, SELECTION_CONFIG, SELECTION_SERVICE, SORT_CONFIG, SORT_SERVICE, Span, TABLE_SERVICE, TableComponent, linesLazyLoader, linesLoader, selectionConfig };
4049
5044
  //# sourceMappingURL=3kles-kles-material-table-v2.mjs.map