@3kles/kles-material-table-v2 21.4.1 → 21.5.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';
23
+ import * as i24 from '@angular/cdk/drag-drop';
22
24
  import { DragDropModule } from '@angular/cdk/drag-drop';
23
- import * as i23 from '@angular/material/progress-spinner';
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) {
@@ -92,7 +94,7 @@ const FOOTER = new InjectionToken('FOOTER');
92
94
  const EXTRA_ROWS = new InjectionToken('EXTRA_ROWS');
93
95
  const ROW_DRAG_DROP = new InjectionToken('ROW_DRAG_DROP');
94
96
  const DRAG_DROP_CONFIG = new InjectionToken('DRAG_DROP_CONFIG');
95
- // export const KLES_TABLE_SERVICE = new InjectionToken<KlesTableService>('KLES_TABLE_SERVICE');
97
+ const KLES_DRAG_DROP_ROW_CONTEXT = new InjectionToken('KLES_DRAG_DROP_ROW_CONTEXT');
96
98
  const PAGINATOR_CONFIG = new InjectionToken('PAGINATOR_CONFIG');
97
99
  const SORT_CONFIG = new InjectionToken('SORT_CONFIG');
98
100
  const HEADER_SERVICE = new InjectionToken('HEADER_SERVICE');
@@ -155,147 +157,487 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
155
157
  type: Injectable
156
158
  }] });
157
159
 
160
+ class ColumnsService {
161
+ constructor(_columns, eventsService) {
162
+ this._columns = _columns;
163
+ this.eventsService = eventsService;
164
+ this.stickyStartBoundary = computed(() => {
165
+ return this.getVisibleColumns()
166
+ .filter((column) => column.sticky === true)
167
+ .at(-1)?.columnDef;
168
+ }, ...(ngDevMode ? [{ debugName: "stickyStartBoundary" }] : /* istanbul ignore next */ []));
169
+ this.stickyEndBoundary = computed(() => {
170
+ return this.getVisibleColumns()
171
+ .filter((column) => column.stickyEnd === true)
172
+ .at(0)?.columnDef;
173
+ }, ...(ngDevMode ? [{ debugName: "stickyEndBoundary" }] : /* istanbul ignore next */ []));
174
+ }
175
+ register() {
176
+ this.setDisplayedColumns();
177
+ }
178
+ get columns() {
179
+ return this._columns.asReadonly();
180
+ }
181
+ getVisible() {
182
+ return this.getVisibleColumns().map((column) => column.columnDef);
183
+ }
184
+ setVisible(columnDef, visible) {
185
+ this.updateColumn(columnDef, { visible });
186
+ this.eventsService.emit('columnVisibilityChange', {
187
+ columnDef,
188
+ columns: this.getVisible(),
189
+ visible,
190
+ });
191
+ }
192
+ toggleVisible(columnDef) {
193
+ const visible = this._columns().find((col) => col.columnDef === columnDef)?.visible;
194
+ this.setVisible(columnDef, visible === undefined ? false : !visible);
195
+ }
196
+ changeWidth(columnDef, options) {
197
+ this.updateColumn(columnDef, {
198
+ ...(options.width && { width: options.width }),
199
+ ...(options.maxWidth && { maxWidth: options.maxWidth }),
200
+ ...(options.minWidth && { minWidth: options.minWidth }),
201
+ });
202
+ }
203
+ setResizable(columnDef, resizable) {
204
+ this.updateColumn(columnDef, { resizable });
205
+ }
206
+ toggleResizable(columnDef) {
207
+ const resizable = this._columns().find((col) => col.columnDef === columnDef)?.resizable;
208
+ this.setResizable(columnDef, resizable === undefined ? true : !resizable);
209
+ }
210
+ setSticky(columnDef, options) {
211
+ this.updateColumn(columnDef, {
212
+ ...(options.sticky !== undefined && { sticky: options.sticky }),
213
+ ...(options.stickyEnd !== undefined && { stickyEnd: options.stickyEnd }),
214
+ });
215
+ }
216
+ setColumnPosition(columnDef, position) {
217
+ const columns = this._columns();
218
+ const previousIndex = columns.findIndex((column) => column.columnDef === columnDef);
219
+ if (previousIndex < 0 || columns.length < 2 || !Number.isFinite(position))
220
+ return;
221
+ const currentIndex = Math.min(columns.length - 1, Math.max(0, Math.trunc(position)));
222
+ if (previousIndex === currentIndex)
223
+ return;
224
+ const reorderedColumns = [...columns];
225
+ const [column] = reorderedColumns.splice(previousIndex, 1);
226
+ reorderedColumns.splice(currentIndex, 0, column);
227
+ this._columns.set(reorderedColumns);
228
+ this.eventsService.emit('columnOrderChange', {
229
+ previousIndex,
230
+ currentIndex,
231
+ columns: this.getVisible(),
232
+ });
233
+ }
234
+ updateColumn(columnDef, config) {
235
+ this._columns.update((columns) => columns.map((col) => col.columnDef === columnDef
236
+ ? {
237
+ ...col,
238
+ ...config,
239
+ cell: config.cell ? { ...col.cell, ...config.cell } : col.cell,
240
+ headerCell: config.headerCell ? { ...col.headerCell, ...config.headerCell } : col.headerCell,
241
+ footerCell: config.footerCell ? { ...col.footerCell, ...config.footerCell } : col.footerCell,
242
+ }
243
+ : col));
244
+ }
245
+ setDisplayedColumns() {
246
+ this.displayedColumns = computed(() => {
247
+ return this.getVisibleColumns().map((column) => column.columnDef);
248
+ }, ...(ngDevMode ? [{ debugName: "displayedColumns" }] : /* istanbul ignore next */ []));
249
+ }
250
+ getVisibleColumns() {
251
+ return this._columns().filter((column) => {
252
+ if (column.visibleWhen !== undefined) {
253
+ return column.visibleWhen();
254
+ }
255
+ return column.visible !== false;
256
+ });
257
+ }
258
+ 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 }); }
259
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: ColumnsService }); }
260
+ }
261
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: ColumnsService, decorators: [{
262
+ type: Injectable
263
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
264
+ type: Inject,
265
+ args: [COLUMNS]
266
+ }] }, { type: EventsService }] });
267
+
158
268
  class ResizableColumnDirective {
159
269
  get appResizableColumnAttr() {
160
270
  return this.column().columnDef;
161
271
  }
162
- constructor(el, renderer, zone, eventsService) {
272
+ constructor(el, renderer, zone, eventsService, columnsService) {
163
273
  this.el = el;
164
274
  this.renderer = renderer;
165
275
  this.zone = zone;
166
276
  this.eventsService = eventsService;
277
+ this.columnsService = columnsService;
167
278
  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 */ []));
279
+ this.defaultMinWidth = 60;
280
+ this.defaultMaxWidth = 1200;
281
+ this.keyboardStep = 4;
174
282
  this.startX = 0;
175
283
  this.startWidth = 0;
176
284
  this.currentWidth = 0;
285
+ this.resizing = false;
286
+ this.activeCells = [];
287
+ this.resizeCells = [];
288
+ this.resizeMinWidth = this.defaultMinWidth;
289
+ this.resizeMaxWidth = this.defaultMaxWidth;
290
+ this.contentMinWidth = this.defaultMinWidth;
291
+ this.handleCleanups = [];
292
+ this.documentCleanups = [];
177
293
  }
178
294
  ngOnInit() {
179
- if (this.column().resizable) {
295
+ if (this.column().resizable)
180
296
  this.apply();
181
- }
182
297
  }
183
298
  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
- }
299
+ const change = changes.column;
300
+ if (change && !change.isFirstChange() && change.previousValue.resizable !== change.currentValue.resizable) {
301
+ change.currentValue.resizable ? this.apply() : this.remove();
193
302
  }
194
303
  }
195
- onDown(e) {
196
- e.preventDefault();
197
- this.startResize(e.clientX);
304
+ ngOnDestroy() {
305
+ this.stopResize(false);
306
+ this.remove();
198
307
  }
199
- onTouchDown(e) {
200
- if (!e.touches?.length)
308
+ startResize(event) {
309
+ if (event.button !== 0 || this.resizing)
201
310
  return;
202
- e.preventDefault();
203
- this.startResize(e.touches[0].clientX);
204
- }
205
- startResize(clientX) {
311
+ event.preventDefault();
312
+ event.stopPropagation();
313
+ this.cancelContentMeasurement();
206
314
  const th = this.el.nativeElement;
207
- this.startX = clientX;
315
+ this.startX = event.clientX;
208
316
  this.startWidth = th.getBoundingClientRect().width;
209
317
  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
- });
318
+ this.cacheResizeTargets();
319
+ this.resizing = true;
320
+ this.setActiveState(true);
321
+ this.updateWidthLabel(this.currentWidth);
322
+ this.emitResizeStart(this.startWidth);
217
323
  this.zone.runOutsideAngular(() => {
218
324
  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
- });
325
+ 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()));
326
+ });
327
+ }
328
+ onPointerMove(event) {
329
+ if (!this.resizing)
330
+ return;
331
+ event.preventDefault();
332
+ this.pendingWidth = this.startWidth + event.clientX - this.startX;
333
+ this.scheduleResizeFrame();
334
+ }
335
+ stopResize(emit = true) {
336
+ this.clearDocumentListeners();
337
+ if (!this.resizing)
338
+ return;
339
+ this.flushResizeFrame();
340
+ this.resizing = false;
341
+ this.applyWidth(this.currentWidth, this.resizeCells);
342
+ this.setActiveState(false);
343
+ this.clearResizeCache();
344
+ this.scheduleContentMeasurement();
345
+ if (this.currentWidth <= 0)
346
+ return;
347
+ this.columnsService.changeWidth(this.column().columnDef, { width: `${this.currentWidth}px` });
348
+ if (emit) {
349
+ this.zone.run(() => this.eventsService.emit('columnResizeEnd', {
350
+ columnDef: this.column().columnDef,
351
+ width: this.currentWidth,
352
+ previousWidth: this.startWidth,
353
+ }));
255
354
  }
256
355
  }
257
- applyWidth(px) {
258
- const root = this.el.nativeElement.closest('table, mat-table, cdk-table');
259
- if (!root)
356
+ onKeyDown(event) {
357
+ if (!['ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(event.key))
358
+ return;
359
+ event.preventDefault();
360
+ event.stopPropagation();
361
+ const previousWidth = this.el.nativeElement.getBoundingClientRect().width;
362
+ const step = event.shiftKey ? this.keyboardStep * 4 : this.keyboardStep;
363
+ let next = previousWidth;
364
+ if (event.key === 'ArrowLeft')
365
+ next -= step;
366
+ if (event.key === 'ArrowRight')
367
+ next += step;
368
+ if (event.key === 'Home')
369
+ next = this.getMinWidth();
370
+ if (event.key === 'End')
371
+ next = this.getMaxWidth();
372
+ this.commitAccessibleResize(previousWidth, this.clampWidth(next));
373
+ }
374
+ autoFit(event) {
375
+ event.preventDefault();
376
+ event.stopPropagation();
377
+ const previousWidth = this.el.nativeElement.getBoundingClientRect().width;
378
+ this.commitAccessibleResize(previousWidth, this.measureContentWidth());
379
+ }
380
+ commitAccessibleResize(previousWidth, nextWidth) {
381
+ if (Math.round(previousWidth) === Math.round(nextWidth))
260
382
  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
383
+ this.startWidth = previousWidth;
384
+ this.currentWidth = previousWidth;
385
+ this.emitResizeStart(previousWidth);
386
+ this.resizeTo(nextWidth, true, false);
387
+ this.columnsService.changeWidth(this.column().columnDef, { width: `${nextWidth}px` });
388
+ this.eventsService.emit('columnResizeEnd', {
389
+ columnDef: this.column().columnDef,
390
+ width: nextWidth,
391
+ previousWidth,
392
+ });
393
+ }
394
+ resizeTo(width, emit, previewOnly = this.resizing) {
395
+ const next = this.resizing
396
+ ? Math.min(this.resizeMaxWidth, Math.max(this.resizeMinWidth, width))
397
+ : this.clampWidth(width);
398
+ if (Math.round(next) === Math.round(this.currentWidth))
399
+ return;
400
+ const previousWidth = this.currentWidth;
401
+ this.currentWidth = next;
402
+ previewOnly ? this.applyPreviewWidth(next) : this.applyWidth(next);
403
+ this.updateWidthLabel(next);
404
+ if (emit) {
405
+ this.zone.run(() => this.eventsService.emit('columnResize', {
406
+ columnDef: this.column().columnDef,
407
+ width: next,
408
+ previousWidth,
409
+ }));
410
+ }
411
+ }
412
+ emitResizeStart(width) {
413
+ this.zone.run(() => this.eventsService.emit('columnResizeStart', {
414
+ columnDef: this.column().columnDef,
415
+ width,
416
+ previousWidth: width,
417
+ }));
418
+ }
419
+ applyWidth(px, cells = this.getColumnCells()) {
420
+ if (this.resizeCol)
421
+ this.resizeCol.style.width = `${px}px`;
422
+ for (const cell of cells) {
265
423
  cell.style.width = `${px}px`;
266
424
  cell.style.minWidth = `${px}px`;
267
425
  cell.style.maxWidth = `${px}px`;
268
- // mode flex
269
426
  cell.style.flex = `0 0 ${px}px`;
270
427
  }
428
+ this.handle?.setAttribute('aria-valuenow', `${Math.round(px)}`);
271
429
  }
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));
430
+ applyPreviewWidth(px) {
431
+ this.resizeRoot?.style.setProperty('--kles-column-resize-width', `${px}px`);
432
+ if (this.resizeCol) {
433
+ this.resizeCol.style.width = `${px}px`;
434
+ }
435
+ else {
436
+ // Fallback for consumers rendering without the table colgroup.
437
+ for (const cell of this.resizeCells)
438
+ cell.style.width = `${px}px`;
439
+ }
440
+ this.handle?.setAttribute('aria-valuenow', `${Math.round(px)}`);
279
441
  }
280
- remove() {
281
- if (this.child) {
282
- this.renderer.removeChild(this.el.nativeElement, this.child);
283
- this.child = undefined;
442
+ scheduleResizeFrame() {
443
+ if (this.animationFrameId !== undefined)
444
+ return;
445
+ const view = this.el.nativeElement.ownerDocument.defaultView;
446
+ if (!view) {
447
+ this.flushPendingWidth();
448
+ return;
284
449
  }
450
+ this.animationFrameId = view.requestAnimationFrame(() => {
451
+ this.animationFrameId = undefined;
452
+ this.flushPendingWidth();
453
+ });
285
454
  }
286
- ngOnDestroy() {
287
- this.stopResize();
455
+ flushResizeFrame() {
456
+ const view = this.el.nativeElement.ownerDocument.defaultView;
457
+ if (this.animationFrameId !== undefined && view)
458
+ view.cancelAnimationFrame(this.animationFrameId);
459
+ this.animationFrameId = undefined;
460
+ this.flushPendingWidth();
461
+ }
462
+ flushPendingWidth() {
463
+ if (this.pendingWidth === undefined)
464
+ return;
465
+ const width = this.pendingWidth;
466
+ this.pendingWidth = undefined;
467
+ this.resizeTo(width, true, true);
288
468
  }
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 }); }
469
+ cacheResizeTargets() {
470
+ const root = this.el.nativeElement.closest('table, mat-table, cdk-table');
471
+ this.resizeRoot = root ? root : undefined;
472
+ this.resizeCells = this.getColumnCells();
473
+ this.resizeCol = root
474
+ ? Array.from(root.querySelectorAll('col[data-column-def]')).find((col) => col.dataset['columnDef'] === this.column().columnDef)
475
+ : undefined;
476
+ this.resizeMinWidth = Math.max(this.getMinWidth(), this.contentMinWidth);
477
+ this.resizeMaxWidth = Math.max(this.resizeMinWidth, this.getMaxWidth());
478
+ this.handle?.setAttribute('aria-valuemin', `${Math.round(this.resizeMinWidth)}`);
479
+ }
480
+ clearResizeCache() {
481
+ this.resizeRoot?.style.removeProperty('--kles-column-resize-width');
482
+ this.pendingWidth = undefined;
483
+ this.resizeCells = [];
484
+ this.resizeCol = undefined;
485
+ this.resizeRoot = undefined;
486
+ this.resizeMinWidth = this.defaultMinWidth;
487
+ this.resizeMaxWidth = this.defaultMaxWidth;
488
+ }
489
+ scheduleContentMeasurement() {
490
+ if (this.resizing || this.contentMeasurementFrameId !== undefined)
491
+ return;
492
+ const view = this.el.nativeElement.ownerDocument.defaultView;
493
+ if (!view)
494
+ return;
495
+ this.contentMeasurementFrameId = view.requestAnimationFrame(() => {
496
+ this.contentMeasurementFrameId = undefined;
497
+ if (this.resizing || !this.handle)
498
+ return;
499
+ this.contentMinWidth = this.measureContentWidth();
500
+ this.handle.setAttribute('aria-valuemin', `${Math.round(Math.max(this.getMinWidth(), this.contentMinWidth))}`);
501
+ });
502
+ }
503
+ cancelContentMeasurement() {
504
+ const view = this.el.nativeElement.ownerDocument.defaultView;
505
+ if (this.contentMeasurementFrameId !== undefined && view)
506
+ view.cancelAnimationFrame(this.contentMeasurementFrameId);
507
+ this.contentMeasurementFrameId = undefined;
508
+ }
509
+ measureContentWidth(cells = this.getColumnCells()) {
510
+ const doc = this.el.nativeElement.ownerDocument;
511
+ const measurementRoot = this.renderer.createElement('div');
512
+ const clones = [];
513
+ Object.assign(measurementRoot.style, {
514
+ position: 'fixed',
515
+ left: '-10000px',
516
+ top: '0',
517
+ display: 'flex',
518
+ flexDirection: 'column',
519
+ alignItems: 'flex-start',
520
+ visibility: 'hidden',
521
+ pointerEvents: 'none',
522
+ });
523
+ let measured = this.getMinWidth();
524
+ for (const cell of cells) {
525
+ const clone = cell.cloneNode(true);
526
+ clone.querySelector('.resize-handle')?.remove();
527
+ Object.assign(clone.style, {
528
+ position: 'static',
529
+ width: 'max-content',
530
+ minWidth: '0',
531
+ maxWidth: 'none',
532
+ whiteSpace: 'nowrap',
533
+ flex: 'none',
534
+ });
535
+ clones.push(clone);
536
+ measurementRoot.appendChild(clone);
537
+ }
538
+ doc.body.appendChild(measurementRoot);
539
+ for (const clone of clones) {
540
+ measured = Math.max(measured, clone.getBoundingClientRect().width);
541
+ }
542
+ measurementRoot.remove();
543
+ return this.clampWidth(Math.ceil(measured));
544
+ }
545
+ setActiveState(active) {
546
+ const th = this.el.nativeElement;
547
+ const method = active ? 'addClass' : 'removeClass';
548
+ this.renderer[method](th, 'column-resizing');
549
+ this.renderer[method](th.ownerDocument.body, 'kles-column-resizing');
550
+ if (active) {
551
+ this.renderer.setStyle(th.ownerDocument.body, 'cursor', 'col-resize');
552
+ this.renderer.setStyle(th.ownerDocument.body, 'user-select', 'none');
553
+ }
554
+ else {
555
+ this.renderer.removeStyle(th.ownerDocument.body, 'cursor');
556
+ this.renderer.removeStyle(th.ownerDocument.body, 'user-select');
557
+ }
558
+ this.activeCells = active ? this.resizeCells : this.activeCells;
559
+ for (const cell of this.activeCells)
560
+ this.renderer[method](cell, 'column-resizing-cell');
561
+ if (!active)
562
+ this.activeCells = [];
563
+ }
564
+ updateWidthLabel(width) {
565
+ if (this.widthLabel)
566
+ this.widthLabel.textContent = `${Math.round(width)} px`;
567
+ }
568
+ getColumnCells() {
569
+ const root = this.el.nativeElement.closest('table, mat-table, cdk-table');
570
+ if (!root)
571
+ return [];
572
+ const columnDef = this.column().columnDef.replace(/[^a-z0-9_-]/gi, '-');
573
+ return Array.from(root.querySelectorAll(`.mat-column-${columnDef}, .cdk-column-${columnDef}`));
574
+ }
575
+ clampWidth(width) {
576
+ return Math.min(this.getMaxWidth(), Math.max(this.getMinWidth(), width));
577
+ }
578
+ getMinWidth() {
579
+ return this.resolveCssWidth(this.column().minWidth, this.defaultMinWidth);
580
+ }
581
+ getMaxWidth() {
582
+ return Math.max(this.getMinWidth(), this.resolveCssWidth(this.column().maxWidth, this.defaultMaxWidth));
583
+ }
584
+ resolveCssWidth(value, fallback) {
585
+ if (!value)
586
+ return fallback;
587
+ const numeric = Number.parseFloat(value);
588
+ if (value.trim().endsWith('px') && Number.isFinite(numeric))
589
+ return numeric;
590
+ const probe = this.renderer.createElement('span');
591
+ Object.assign(probe.style, { position: 'absolute', visibility: 'hidden', pointerEvents: 'none', width: value });
592
+ this.renderer.appendChild(this.el.nativeElement, probe);
593
+ const width = probe.getBoundingClientRect().width;
594
+ this.renderer.removeChild(this.el.nativeElement, probe);
595
+ return width > 0 ? width : fallback;
596
+ }
597
+ apply() {
598
+ this.remove();
599
+ const th = this.el.nativeElement;
600
+ this.handle = this.renderer.createElement('span');
601
+ this.widthLabel = this.renderer.createElement('span');
602
+ this.renderer.addClass(th, 'resizable-column');
603
+ this.renderer.addClass(this.handle, 'resize-handle');
604
+ this.renderer.addClass(this.widthLabel, 'resize-width-label');
605
+ this.renderer.appendChild(this.handle, this.widthLabel);
606
+ this.renderer.appendChild(th, this.handle);
607
+ this.renderer.setAttribute(this.handle, 'role', 'separator');
608
+ this.renderer.setAttribute(this.handle, 'aria-orientation', 'vertical');
609
+ this.renderer.setAttribute(this.handle, 'aria-label', `Redimensionner la colonne ${this.column().columnDef}`);
610
+ this.renderer.setAttribute(this.handle, 'aria-valuemin', `${Math.round(this.getMinWidth())}`);
611
+ this.renderer.setAttribute(this.handle, 'aria-valuemax', `${Math.round(this.getMaxWidth())}`);
612
+ this.renderer.setAttribute(this.handle, 'aria-valuenow', `${Math.round(th.getBoundingClientRect().width)}`);
613
+ this.renderer.setAttribute(this.handle, 'tabindex', '0');
614
+ 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()));
615
+ this.scheduleContentMeasurement();
616
+ }
617
+ remove() {
618
+ if (this.resizing)
619
+ this.stopResize(false);
620
+ this.flushResizeFrame();
621
+ this.cancelContentMeasurement();
622
+ this.clearResizeCache();
623
+ this.clearDocumentListeners();
624
+ this.handleCleanups.splice(0).forEach((cleanup) => cleanup());
625
+ if (this.handle)
626
+ this.renderer.removeChild(this.el.nativeElement, this.handle);
627
+ this.renderer.removeClass(this.el.nativeElement, 'resizable-column');
628
+ this.handle = undefined;
629
+ this.widthLabel = undefined;
630
+ }
631
+ clearDocumentListeners() {
632
+ this.documentCleanups.splice(0).forEach((cleanup) => cleanup());
633
+ }
634
+ 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
635
  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
636
  }
292
637
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: ResizableColumnDirective, decorators: [{
293
638
  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: [{
639
+ args: [{ selector: 'th[appResizableColumn]', standalone: true }]
640
+ }], 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
641
  type: HostBinding,
300
642
  args: ['attr.appResizableColumn']
301
643
  }] } });
@@ -424,136 +766,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
424
766
  args: [LOADER_CONFIG]
425
767
  }] }] });
426
768
 
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
769
  class RowFormFactory {
558
770
  createControl(field, value) {
559
771
  let control;
@@ -656,7 +868,9 @@ class KlesForm {
656
868
  });
657
869
  this.uiStore = new WeakMap();
658
870
  this.rowsStructureChangedSubject = new Subject();
871
+ this.rowsReplacedSubject = new Subject();
659
872
  this.rowsStructureChanged$ = this.rowsStructureChangedSubject.asObservable();
873
+ this.rowsReplaced$ = this.rowsReplacedSubject.asObservable();
660
874
  }
661
875
  getRows() {
662
876
  return this.form.get('rows');
@@ -688,6 +902,7 @@ class KlesForm {
688
902
  this.getRows().push(r.formGroup, { emitEvent: false });
689
903
  this.getUiRows().push(r.groupUi);
690
904
  });
905
+ this.rowsReplacedSubject.next();
691
906
  this.notifyRowsStructureChanged();
692
907
  }
693
908
  insertRowAndNotify(row, index, options, notify) {
@@ -710,11 +925,166 @@ class KlesForm {
710
925
  return this.insertRowAndNotify(row, index, options, true);
711
926
  }
712
927
  insertRows(rows, index) {
713
- rows.forEach((r) => {
714
- this.insertRowAndNotify(r, index);
928
+ rows.forEach((r, offset) => {
929
+ this.insertRowAndNotify(r, index === undefined ? undefined : index + offset, { emitEvent: false }, false);
715
930
  });
931
+ this.getRows().updateValueAndValidity({ emitEvent: true });
716
932
  this.notifyRowsStructureChanged();
717
933
  }
934
+ moveRow(row, targetRow) {
935
+ const rows = this.getRows();
936
+ const previousIndex = rows.controls.indexOf(row);
937
+ const targetIndex = rows.controls.indexOf(targetRow);
938
+ if (previousIndex < 0 || targetIndex < 0 || previousIndex === targetIndex) {
939
+ return undefined;
940
+ }
941
+ const rowUi = this.uiStore.get(row) ?? this.getUiRows().at(previousIndex);
942
+ rows.removeAt(previousIndex, { emitEvent: false });
943
+ this.getUiRows().removeAt(previousIndex);
944
+ // En descendant, la suppression décale la cible d'une position : utiliser
945
+ // son index initial insère donc naturellement la ligne après celle-ci.
946
+ rows.insert(targetIndex, row, { emitEvent: false });
947
+ this.getUiRows().insert(targetIndex, rowUi);
948
+ rows.updateValueAndValidity({ emitEvent: true });
949
+ this.notifyRowsStructureChanged();
950
+ return {
951
+ previousIndex,
952
+ currentIndex: rows.controls.indexOf(row),
953
+ };
954
+ }
955
+ canMoveSubtree(row, targetRow) {
956
+ if (row === targetRow)
957
+ return true;
958
+ const rowValue = row.getRawValue();
959
+ const targetValue = targetRow.getRawValue();
960
+ if (rowValue._parentId !== targetValue._parentId || (rowValue._depth ?? 0) !== (targetValue._depth ?? 0))
961
+ return false;
962
+ return !this.getSubtreeRows(row).includes(targetRow);
963
+ }
964
+ moveSubtree(row, targetRow) {
965
+ const rows = this.getRows();
966
+ const previousIndex = rows.controls.indexOf(row);
967
+ const targetIndex = rows.controls.indexOf(targetRow);
968
+ if (previousIndex < 0 || targetIndex < 0 || previousIndex === targetIndex || !this.canMoveSubtree(row, targetRow))
969
+ return undefined;
970
+ const movedRows = this.getSubtreeRows(row);
971
+ const movedSet = new Set(movedRows);
972
+ const movedUis = movedRows.map((movedRow) => this.uiStore.get(movedRow) ?? this.getUiRows().at(rows.controls.indexOf(movedRow)));
973
+ const parentId = row.getRawValue()._parentId;
974
+ const previousSiblingIndex = this.getSiblingIndex(row);
975
+ let targetSubtreeEnd = targetIndex + this.getSubtreeRows(targetRow).length;
976
+ let insertionIndex = previousIndex < targetIndex ? targetSubtreeEnd : targetIndex;
977
+ for (let index = rows.length - 1; index >= 0; index--) {
978
+ if (!movedSet.has(rows.at(index)))
979
+ continue;
980
+ rows.removeAt(index, { emitEvent: false });
981
+ this.getUiRows().removeAt(index);
982
+ if (index < insertionIndex)
983
+ insertionIndex--;
984
+ }
985
+ movedRows.forEach((movedRow, offset) => {
986
+ rows.insert(insertionIndex + offset, movedRow, { emitEvent: false });
987
+ this.getUiRows().insert(insertionIndex + offset, movedUis[offset]);
988
+ });
989
+ rows.updateValueAndValidity({ emitEvent: true });
990
+ this.notifyRowsStructureChanged();
991
+ return {
992
+ previousIndex,
993
+ currentIndex: rows.controls.indexOf(row),
994
+ previousSiblingIndex,
995
+ currentSiblingIndex: this.getSiblingIndex(row, parentId),
996
+ movedRows,
997
+ };
998
+ }
999
+ getSubtreeRows(row) {
1000
+ const rows = this.getRows().controls;
1001
+ const index = rows.indexOf(row);
1002
+ if (index < 0)
1003
+ return [];
1004
+ const depth = row.getRawValue()._depth ?? 0;
1005
+ const subtree = [row];
1006
+ for (let current = index + 1; current < rows.length; current++) {
1007
+ if ((rows[current].getRawValue()._depth ?? 0) <= depth)
1008
+ break;
1009
+ subtree.push(rows[current]);
1010
+ }
1011
+ return subtree;
1012
+ }
1013
+ getSiblingIndex(row, parentId = row.getRawValue()._parentId) {
1014
+ return this.getRows()
1015
+ .controls.filter((candidate) => candidate.getRawValue()._parentId === parentId)
1016
+ .indexOf(row);
1017
+ }
1018
+ transferRowTo(target, row, targetRow) {
1019
+ if (target === this) {
1020
+ return targetRow ? this.moveRow(row, targetRow) : undefined;
1021
+ }
1022
+ const previousIndex = this.getRows().controls.indexOf(row);
1023
+ if (previousIndex < 0) {
1024
+ return undefined;
1025
+ }
1026
+ const rowUi = this.uiStore.get(row) ?? this.getUiRows().at(previousIndex);
1027
+ const rowContext = this.rowContextStore.get(row)?.();
1028
+ const targetIndex = targetRow ? target.getRows().controls.indexOf(targetRow) : target.getRows().length;
1029
+ const currentIndex = targetIndex < 0 ? target.getRows().length : targetIndex;
1030
+ this.getRows().removeAt(previousIndex, { emitEvent: false });
1031
+ this.getUiRows().removeAt(previousIndex);
1032
+ this.rowContextStore.delete(row);
1033
+ target.getRows().insert(currentIndex, row, { emitEvent: false });
1034
+ target.getUiRows().insert(currentIndex, rowUi);
1035
+ target.uiStore.set(row, rowUi);
1036
+ if (rowContext) {
1037
+ target.rowContextStore.set(row, rowContext);
1038
+ }
1039
+ this.getRows().updateValueAndValidity({ emitEvent: true });
1040
+ target.getRows().updateValueAndValidity({ emitEvent: true });
1041
+ this.notifyRowsStructureChanged();
1042
+ target.notifyRowsStructureChanged();
1043
+ return { previousIndex, currentIndex };
1044
+ }
1045
+ transferSubtreeTo(target, row, targetRow) {
1046
+ if (target === this)
1047
+ return targetRow ? this.moveSubtree(row, targetRow) : undefined;
1048
+ const previousIndex = this.getRows().controls.indexOf(row);
1049
+ if (previousIndex < 0 || (row.getRawValue()._depth ?? 0) !== 0)
1050
+ return undefined;
1051
+ if (targetRow && ((targetRow.getRawValue()._depth ?? 0) !== 0 || targetRow.getRawValue()._parentId != null))
1052
+ return undefined;
1053
+ const movedRows = this.getSubtreeRows(row);
1054
+ const previousSiblingIndex = this.getSiblingIndex(row);
1055
+ const movedData = movedRows.map((movedRow) => ({
1056
+ row: movedRow,
1057
+ ui: this.uiStore.get(movedRow) ?? this.getUiRows().at(this.getRows().controls.indexOf(movedRow)),
1058
+ context: this.rowContextStore.get(movedRow)?.(),
1059
+ }));
1060
+ for (let index = this.getRows().length - 1; index >= 0; index--) {
1061
+ if (!movedRows.includes(this.getRows().at(index)))
1062
+ continue;
1063
+ const movedRow = this.getRows().at(index);
1064
+ this.getRows().removeAt(index, { emitEvent: false });
1065
+ this.getUiRows().removeAt(index);
1066
+ this.rowContextStore.delete(movedRow);
1067
+ }
1068
+ const insertionIndex = targetRow ? target.getRows().controls.indexOf(targetRow) : target.getRows().length;
1069
+ movedData.forEach(({ row: movedRow, ui, context }, offset) => {
1070
+ target.getRows().insert(insertionIndex + offset, movedRow, { emitEvent: false });
1071
+ target.getUiRows().insert(insertionIndex + offset, ui);
1072
+ target.uiStore.set(movedRow, ui);
1073
+ if (context)
1074
+ target.rowContextStore.set(movedRow, context);
1075
+ });
1076
+ this.getRows().updateValueAndValidity({ emitEvent: true });
1077
+ target.getRows().updateValueAndValidity({ emitEvent: true });
1078
+ this.notifyRowsStructureChanged();
1079
+ target.notifyRowsStructureChanged();
1080
+ return {
1081
+ previousIndex,
1082
+ currentIndex: target.getRows().controls.indexOf(row),
1083
+ previousSiblingIndex,
1084
+ currentSiblingIndex: target.getSiblingIndex(row, null),
1085
+ movedRows,
1086
+ };
1087
+ }
718
1088
  updateRow(_id, value, options) {
719
1089
  const row = this.getRows().controls.find((c) => c.getRawValue()._id === _id);
720
1090
  if (row) {
@@ -732,14 +1102,25 @@ class KlesForm {
732
1102
  }
733
1103
  }
734
1104
  deleteRowById(id, option) {
735
- const index = this.getRows().controls.findIndex((c) => c.getRawValue()._id === id);
736
- if (index !== -1) {
1105
+ this.deleteRowsByIds([id], option);
1106
+ }
1107
+ deleteRowsByIds(ids, option) {
1108
+ const idSet = new Set(ids);
1109
+ const indexes = this.getRows()
1110
+ .controls.map((row, index) => ({ row, index }))
1111
+ .filter(({ row }) => idSet.has(row.getRawValue()._id))
1112
+ .map(({ index }) => index)
1113
+ .sort((a, b) => b - a);
1114
+ if (indexes.length === 0)
1115
+ return;
1116
+ for (const index of indexes) {
737
1117
  const row = this.getRows().at(index);
738
- this.getRows().removeAt(index, option);
1118
+ this.getRows().removeAt(index, { emitEvent: false });
739
1119
  this.rowContextStore.delete(row);
740
1120
  this.getUiRows().removeAt(index);
741
- this.notifyRowsStructureChanged();
742
1121
  }
1122
+ this.getRows().updateValueAndValidity(option);
1123
+ this.notifyRowsStructureChanged();
743
1124
  }
744
1125
  setHeaderControl(name, header, options) {
745
1126
  this.getHeader().setControl(name, header, options);
@@ -800,64 +1181,161 @@ class TreeService {
800
1181
  constructor() {
801
1182
  this.loaderConfig = inject(LOADER_CONFIG);
802
1183
  this.loaderChildrensService = inject(LoaderChildrensService);
803
- this.loadingService = inject(LoadingService);
804
1184
  this.fm = inject(KlesForm);
805
1185
  this.columnsService = inject(ColumnsService);
806
1186
  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);
1187
+ this.eventsService = inject(EventsService);
1188
+ this.destroyRef = inject(DestroyRef);
1189
+ this.expandedSubject = new BehaviorSubject(new Set());
1190
+ this.expandedIds$ = this.expandedSubject.asObservable();
1191
+ this.expandedIds = signal(new Set(), ...(ngDevMode ? [{ debugName: "expandedIds" }] : /* istanbul ignore next */ []));
1192
+ this.loadingIds = signal(new Set(), ...(ngDevMode ? [{ debugName: "loadingIds" }] : /* istanbul ignore next */ []));
1193
+ this.fm.rowsReplaced$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => this.reset());
813
1194
  }
814
1195
  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
- }
1196
+ if (this.isLoading(id))
1197
+ return;
1198
+ this.isExpanded(id) ? this.collapse(id, group, depth) : this.expand(id, group, depth);
1199
+ }
1200
+ expand(id, group, depth) {
1201
+ if (this.isExpanded(id) || this.isLoading(id))
1202
+ return;
1203
+ const parent = group ?? this.findRow(id);
1204
+ if (!parent)
1205
+ return;
1206
+ const level = depth ?? parent.getRawValue()._depth ?? 0;
1207
+ if (!this.hasChildren(parent, level))
1208
+ return;
1209
+ const payload = this.rowPayload(parent, level);
1210
+ this.setLoading(id, true);
1211
+ this.eventsService.emit('nodeLoadChildren', payload);
1212
+ this.loaderChildrensService
1213
+ .load(parent, level)
1214
+ .pipe(filter((response) => !response.loading), take(1), takeUntilDestroyed(this.destroyRef))
1215
+ .subscribe((response) => {
1216
+ this.setLoading(id, false);
1217
+ if (response.error) {
1218
+ this.eventsService.emit('loadError', {
1219
+ error: response.error,
1220
+ message: response.error instanceof Error ? response.error.message : undefined,
1221
+ });
1222
+ return;
1223
+ }
1224
+ const parentIndex = this.fm.getRows().controls.indexOf(parent);
1225
+ if (parentIndex < 0)
1226
+ return;
1227
+ const children = this.rowFactory.createRows(this.columnsService.columns().map((column) => ({ ...column.cell?.field, name: column.columnDef })), response.items, { depth: level + 1, parentId: id });
1228
+ this.fm.insertRows(children, parentIndex + 1);
1229
+ this.setExpanded(id, true);
1230
+ const childRows = children.map((child) => child.formGroup);
1231
+ this.eventsService.emit('nodeChildrenLoaded', {
1232
+ ...payload,
1233
+ children: childRows,
1234
+ childValues: childRows.map((child) => child.getRawValue()),
840
1235
  });
1236
+ this.eventsService.emit('nodeExpand', payload);
1237
+ });
1238
+ }
1239
+ collapse(id, group, depth) {
1240
+ if (!this.isExpanded(id))
1241
+ return;
1242
+ const parent = group ?? this.findRow(id);
1243
+ if (!parent) {
1244
+ this.setExpanded(id, false);
1245
+ return;
1246
+ }
1247
+ const descendants = this.getDescendants(id);
1248
+ const descendantIds = descendants.map((row) => row.getRawValue()._id);
1249
+ const expanded = new Set(this.expandedSubject.value);
1250
+ expanded.delete(id);
1251
+ descendantIds.forEach((descendantId) => expanded.delete(descendantId));
1252
+ this.publishExpanded(expanded);
1253
+ this.fm.deleteRowsByIds(descendantIds, { emitEvent: false });
1254
+ this.eventsService.emit('nodeCollapse', this.rowPayload(parent, depth ?? parent.getRawValue()._depth ?? 0));
1255
+ }
1256
+ collapseAll() {
1257
+ const childIds = this.fm
1258
+ .getRows()
1259
+ .controls.filter((row) => (row.getRawValue()._depth ?? 0) > 0)
1260
+ .map((row) => row.getRawValue()._id);
1261
+ this.publishExpanded(new Set());
1262
+ this.fm.deleteRowsByIds(childIds, { emitEvent: false });
1263
+ }
1264
+ reset() {
1265
+ this.publishExpanded(new Set());
1266
+ this.loadingIds.set(new Set());
1267
+ }
1268
+ isExpanded(id) {
1269
+ return this.expandedSubject.value.has(id);
1270
+ }
1271
+ isLoading(id) {
1272
+ return this.loadingIds().has(id);
1273
+ }
1274
+ getChildren(id) {
1275
+ return this.fm.getRows().controls.filter((row) => row.getRawValue()._parentId === id);
1276
+ }
1277
+ getDescendants(id) {
1278
+ const rows = this.fm.getRows().controls;
1279
+ const parentIndex = rows.findIndex((row) => row.getRawValue()._id === id);
1280
+ if (parentIndex < 0)
1281
+ return [];
1282
+ const parentDepth = rows[parentIndex].getRawValue()._depth ?? 0;
1283
+ const descendants = [];
1284
+ for (let index = parentIndex + 1; index < rows.length; index++) {
1285
+ const row = rows[index];
1286
+ if ((row.getRawValue()._depth ?? 0) <= parentDepth)
1287
+ break;
1288
+ descendants.push(row);
841
1289
  }
1290
+ return descendants;
842
1291
  }
843
1292
  hasChildren(group, depth) {
844
- return this.loaderConfig.lines.hasChildren?.(group, depth) ?? true;
1293
+ const configured = this.loaderConfig.lines.hasChildren;
1294
+ return configured ? configured(group, depth) : typeof this.loaderConfig.lines.childrens === 'function';
1295
+ }
1296
+ findRow(id) {
1297
+ return this.fm.getRows().controls.find((row) => row.getRawValue()._id === id);
1298
+ }
1299
+ setExpanded(id, expanded) {
1300
+ const ids = new Set(this.expandedSubject.value);
1301
+ expanded ? ids.add(id) : ids.delete(id);
1302
+ this.publishExpanded(ids);
1303
+ }
1304
+ publishExpanded(ids) {
1305
+ this.expandedSubject.next(ids);
1306
+ this.expandedIds.set(ids);
1307
+ }
1308
+ setLoading(id, loading) {
1309
+ const ids = new Set(this.loadingIds());
1310
+ loading ? ids.add(id) : ids.delete(id);
1311
+ this.loadingIds.set(ids);
1312
+ }
1313
+ rowPayload(row, level) {
1314
+ return {
1315
+ row,
1316
+ rowIndex: this.fm.getRows().controls.indexOf(row),
1317
+ value: row.value,
1318
+ rawValue: row.getRawValue(),
1319
+ level,
1320
+ };
845
1321
  }
846
1322
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: TreeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
847
1323
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: TreeService }); }
848
1324
  }
849
1325
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: TreeService, decorators: [{
850
1326
  type: Injectable
851
- }] });
1327
+ }], ctorParameters: () => [] });
852
1328
 
853
1329
  class KlesCellComponent {
854
1330
  constructor() {
855
1331
  this.destroyRef = inject(DestroyRef);
856
1332
  this.expandedRowStore = inject(ExpandedRowStore);
857
1333
  this.treeService = inject(TreeService);
1334
+ this.eventsService = inject(EventsService);
858
1335
  this.ui = input.required(...(ngDevMode ? [{ debugName: "ui" }] : /* istanbul ignore next */ []));
859
1336
  this.group = input.required(...(ngDevMode ? [{ debugName: "group" }] : /* istanbul ignore next */ []));
860
1337
  this.column = input.required(...(ngDevMode ? [{ debugName: "column" }] : /* istanbul ignore next */ []));
1338
+ this.rowIndex = input.required(...(ngDevMode ? [{ debugName: "rowIndex" }] : /* istanbul ignore next */ []));
861
1339
  this.expandedRow = computed(() => {
862
1340
  return (this.column().canExpand ?? false) && (this.ui().get(this.column().columnDef)?.value().expandedRow ?? false);
863
1341
  }, ...(ngDevMode ? [{ debugName: "expandedRow" }] : /* istanbul ignore next */ []));
@@ -867,6 +1345,8 @@ class KlesCellComponent {
867
1345
  this.hasChildren = computed(() => {
868
1346
  return this.treeService.hasChildren(this.group(), this.group().getRawValue()._depth);
869
1347
  }, ...(ngDevMode ? [{ debugName: "hasChildren" }] : /* istanbul ignore next */ []));
1348
+ this.depth = computed(() => Math.max(0, this.group().getRawValue()._depth ?? 0), ...(ngDevMode ? [{ debugName: "depth" }] : /* istanbul ignore next */ []));
1349
+ this.loadingNode = computed(() => this.treeService.isLoading(this.group().getRawValue()._id), ...(ngDevMode ? [{ debugName: "loadingNode" }] : /* istanbul ignore next */ []));
870
1350
  this.column$ = toObservable(this.column);
871
1351
  }
872
1352
  ngOnInit() {
@@ -876,10 +1356,21 @@ class KlesCellComponent {
876
1356
  event.stopPropagation();
877
1357
  }
878
1358
  expandRow() {
879
- this.expandedRowStore.toggle(this.group().getRawValue()._id);
1359
+ const row = this.group();
1360
+ const expanded = this.expandedRowStore.isExpanded(row.getRawValue()._id);
1361
+ this.expandedRowStore.toggle(row.getRawValue()._id);
1362
+ const payload = {
1363
+ row,
1364
+ rowIndex: this.rowIndex(),
1365
+ value: row.value,
1366
+ rawValue: row.getRawValue(),
1367
+ level: row.getRawValue()._depth,
1368
+ };
1369
+ this.eventsService.emit(expanded ? 'rowCollapse' : 'rowExpand', payload);
1370
+ this.eventsService.emit('rowToggleExpand', payload);
880
1371
  }
881
1372
  expandNode() {
882
- this.treeService.toggle(this.group().getRawValue()._id, this.group(), 0); //TODO depth
1373
+ this.treeService.toggle(this.group().getRawValue()._id, this.group(), this.group().getRawValue()._depth ?? 0);
883
1374
  }
884
1375
  listen() {
885
1376
  this.column$
@@ -902,12 +1393,12 @@ class KlesCellComponent {
902
1393
  });
903
1394
  }
904
1395
  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"] }] }); }
1396
+ 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 } }, 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 (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}\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"] }] }); }
906
1397
  }
907
1398
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: KlesCellComponent, decorators: [{
908
1399
  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 }] }] } });
1400
+ 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 (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}\n"] }]
1401
+ }], 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 }] }] } });
911
1402
 
912
1403
  class KlesHeaderComponent {
913
1404
  constructor() {
@@ -1111,6 +1602,15 @@ class KlesTableConnectorService {
1111
1602
  get events() {
1112
1603
  return this.table.events;
1113
1604
  }
1605
+ get emptyState() {
1606
+ return this.table.emptyState;
1607
+ }
1608
+ get render() {
1609
+ return this.table.render;
1610
+ }
1611
+ get tree() {
1612
+ return this.table.tree;
1613
+ }
1114
1614
  refresh() {
1115
1615
  this.table?.refresh();
1116
1616
  }
@@ -1121,6 +1621,35 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
1121
1621
  type: Injectable
1122
1622
  }], ctorParameters: () => [] });
1123
1623
 
1624
+ class LoadingService {
1625
+ constructor(eventsService) {
1626
+ this.eventsService = eventsService;
1627
+ this._loading = signal(false, ...(ngDevMode ? [{ debugName: "_loading" }] : /* istanbul ignore next */ []));
1628
+ }
1629
+ get loading() {
1630
+ return this._loading.asReadonly();
1631
+ }
1632
+ start() {
1633
+ if (this._loading()) {
1634
+ return;
1635
+ }
1636
+ this._loading.set(true);
1637
+ this.eventsService.emit('loadingChange', { loading: true });
1638
+ }
1639
+ stop() {
1640
+ if (!this._loading()) {
1641
+ return;
1642
+ }
1643
+ this._loading.set(false);
1644
+ this.eventsService.emit('loadingChange', { loading: false });
1645
+ }
1646
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: LoadingService, deps: [{ token: EventsService }], target: i0.ɵɵFactoryTarget.Injectable }); }
1647
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: LoadingService }); }
1648
+ }
1649
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: LoadingService, decorators: [{
1650
+ type: Injectable
1651
+ }], ctorParameters: () => [{ type: EventsService }] });
1652
+
1124
1653
  class PaginatorStore {
1125
1654
  constructor(config) {
1126
1655
  this.config = config;
@@ -1301,19 +1830,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
1301
1830
  }] });
1302
1831
 
1303
1832
  class FooterService {
1304
- constructor(_footer) {
1833
+ constructor(_footer, eventsService) {
1305
1834
  this._footer = _footer;
1835
+ this.eventsService = eventsService;
1306
1836
  }
1307
1837
  get footer() {
1308
1838
  return this._footer.asReadonly();
1309
1839
  }
1310
1840
  show() {
1841
+ if (this._footer()) {
1842
+ return;
1843
+ }
1311
1844
  this._footer.set(true);
1845
+ this.eventsService.emit('footerVisibilityChange', { visible: true });
1312
1846
  }
1313
1847
  hide() {
1848
+ if (!this._footer()) {
1849
+ return;
1850
+ }
1314
1851
  this._footer.set(false);
1852
+ this.eventsService.emit('footerVisibilityChange', { visible: false });
1315
1853
  }
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 }); }
1854
+ 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
1855
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FooterService }); }
1318
1856
  }
1319
1857
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FooterService, decorators: [{
@@ -1321,7 +1859,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
1321
1859
  }], ctorParameters: () => [{ type: undefined, decorators: [{
1322
1860
  type: Inject,
1323
1861
  args: [FOOTER]
1324
- }] }] });
1862
+ }] }, { type: EventsService }] });
1325
1863
 
1326
1864
  class ExtraRowService {
1327
1865
  constructor(_extraRowsConfig, expandedRowStore) {
@@ -1565,7 +2103,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
1565
2103
  type: Injectable
1566
2104
  }], ctorParameters: () => [{ type: EventsService }] });
1567
2105
 
1568
- //TODO Abstract Datasource service
1569
2106
  class DatasourceService {
1570
2107
  constructor(fm, columnsService, cellValueChangeService, validationService) {
1571
2108
  this.fm = fm;
@@ -1833,7 +2370,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
1833
2370
  }], ctorParameters: () => [{ type: EventsService }] });
1834
2371
 
1835
2372
  class EmptyStateService {
1836
- constructor(config) {
2373
+ constructor(config, eventsService) {
2374
+ this.eventsService = eventsService;
1837
2375
  this._enabled = signal(true, ...(ngDevMode ? [{ debugName: "_enabled" }] : /* istanbul ignore next */ []));
1838
2376
  this.enabled = this._enabled.asReadonly();
1839
2377
  if (typeof config === 'boolean') {
@@ -1845,15 +2383,23 @@ class EmptyStateService {
1845
2383
  this.component = config?.component ?? KlesTableEmptyStateComponent;
1846
2384
  }
1847
2385
  enable() {
2386
+ if (this._enabled()) {
2387
+ return;
2388
+ }
1848
2389
  this._enabled.set(true);
2390
+ this.eventsService.emit('emptyStateChange', { enabled: true });
1849
2391
  }
1850
2392
  disable() {
2393
+ if (!this._enabled()) {
2394
+ return;
2395
+ }
1851
2396
  this._enabled.set(false);
2397
+ this.eventsService.emit('emptyStateChange', { enabled: false });
1852
2398
  }
1853
2399
  toggle() {
1854
- this._enabled.update((enabled) => !enabled);
2400
+ this._enabled() ? this.disable() : this.enable();
1855
2401
  }
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 }); }
2402
+ 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
2403
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: EmptyStateService }); }
1858
2404
  }
1859
2405
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: EmptyStateService, decorators: [{
@@ -1861,90 +2407,175 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
1861
2407
  }], ctorParameters: () => [{ type: undefined, decorators: [{
1862
2408
  type: Inject,
1863
2409
  args: [EMPTY_STATE_CONFIG]
1864
- }] }] });
2410
+ }] }, { type: EventsService }] });
1865
2411
 
1866
2412
  class DragDropBase {
1867
- constructor(config) {
2413
+ static { this.nextDropListId = 0; }
2414
+ constructor(config, eventsService, klesForm, injector, tableId) {
1868
2415
  this.config = config;
2416
+ this.eventsService = eventsService;
2417
+ this.klesForm = klesForm;
2418
+ this.injector = injector;
2419
+ this.dropListId = tableId ? this.toDropListId(tableId) : `kles-rows-drop-list-${DragDropBase.nextDropListId++}`;
1869
2420
  }
1870
2421
  get enable() {
1871
2422
  return this.config?.enable || false;
1872
2423
  }
1873
2424
  get autoScrollStep() {
1874
- return this.config?.options?.autoScrollStep ?? true;
2425
+ return this.config?.options?.autoScrollStep ?? 8;
1875
2426
  }
1876
2427
  get connectedTo() {
1877
- return this.config?.options?.connectedTo;
2428
+ return this.config?.options?.connectedTo?.map((id) => this.toDropListId(id));
1878
2429
  }
1879
2430
  get sortPredicate() {
1880
2431
  return (index, item) => {
1881
- return true;
2432
+ const row = item.data;
2433
+ const targetRow = item.dropContainer.getSortedItems()[index]?.data;
2434
+ if (!targetRow || row === targetRow)
2435
+ return true;
2436
+ const targetForm = item.dropContainer.data;
2437
+ if (targetForm !== this.klesForm) {
2438
+ return (row.getRawValue()._depth ?? 0) === 0 && (targetRow.getRawValue()._depth ?? 0) === 0;
2439
+ }
2440
+ return this.klesForm.canMoveSubtree(row, targetRow);
1882
2441
  };
1883
2442
  }
1884
2443
  get previewComponent() {
1885
2444
  return this.config?.options?.dragPreview?.component;
1886
2445
  }
1887
2446
  get previewMatchSize() {
1888
- return this.config?.options?.dragPreview?.matchSize || true;
2447
+ return this.config?.options?.dragPreview?.matchSize ?? true;
2448
+ }
2449
+ get placeholderComponent() {
2450
+ return this.config?.options?.dragPlaceholder?.component;
2451
+ }
2452
+ isDragDisabled(row) {
2453
+ return this.config?.options?.dragDisabled?.(row) ?? false;
2454
+ }
2455
+ componentInjector(row, rowIndex) {
2456
+ return Injector.create({
2457
+ parent: this.injector,
2458
+ providers: [
2459
+ {
2460
+ provide: KLES_DRAG_DROP_ROW_CONTEXT,
2461
+ useValue: this.rowPayload(row, rowIndex),
2462
+ },
2463
+ ],
2464
+ });
2465
+ }
2466
+ rowDragStarted(row, rowIndex) {
2467
+ this.eventsService.emit('rowDragStart', this.rowPayload(row, rowIndex));
2468
+ }
2469
+ rowDragMoved(row, rowIndex) {
2470
+ this.eventsService.emit('rowDragMove', this.rowPayload(row, rowIndex));
2471
+ }
2472
+ rowDragEnded(row, rowIndex) {
2473
+ this.eventsService.emit('rowDragEnd', this.rowPayload(row, rowIndex));
2474
+ }
2475
+ rowPayload(row, rowIndex) {
2476
+ return {
2477
+ row,
2478
+ rowIndex,
2479
+ value: row.value,
2480
+ rawValue: row.getRawValue(),
2481
+ };
2482
+ }
2483
+ reorder(event) {
2484
+ const row = event.item.data;
2485
+ const visibleRows = event.container.getSortedItems().map((item) => item.data);
2486
+ const targetRow = visibleRows[event.currentIndex];
2487
+ if (!targetRow) {
2488
+ return;
2489
+ }
2490
+ const moved = this.klesForm.moveSubtree(row, targetRow);
2491
+ if (moved) {
2492
+ this.handleDrop({
2493
+ ...this.rowPayload(row, moved.currentIndex),
2494
+ previousIndex: moved.previousIndex,
2495
+ currentIndex: moved.currentIndex,
2496
+ parentId: row.getRawValue()._parentId,
2497
+ depth: row.getRawValue()._depth ?? 0,
2498
+ previousSiblingIndex: moved.previousSiblingIndex,
2499
+ currentSiblingIndex: moved.currentSiblingIndex,
2500
+ movedRows: moved.movedRows,
2501
+ movedRawValues: moved.movedRows.map((movedRow) => movedRow.getRawValue()),
2502
+ });
2503
+ }
2504
+ }
2505
+ transfer(event) {
2506
+ const row = event.item.data;
2507
+ const targetRows = event.container.getSortedItems().map((item) => item.data);
2508
+ const targetRow = targetRows[event.currentIndex];
2509
+ const moved = event.previousContainer.data.transferSubtreeTo(event.container.data, row, targetRow);
2510
+ if (moved) {
2511
+ this.handleDrop({
2512
+ ...this.rowPayload(row, moved.currentIndex),
2513
+ previousIndex: moved.previousIndex,
2514
+ currentIndex: moved.currentIndex,
2515
+ previousContainerId: event.previousContainer.id,
2516
+ currentContainerId: event.container.id,
2517
+ parentId: row.getRawValue()._parentId,
2518
+ depth: row.getRawValue()._depth ?? 0,
2519
+ previousSiblingIndex: moved.previousSiblingIndex,
2520
+ currentSiblingIndex: moved.currentSiblingIndex,
2521
+ movedRows: moved.movedRows,
2522
+ movedRawValues: moved.movedRows.map((movedRow) => movedRow.getRawValue()),
2523
+ });
2524
+ }
2525
+ }
2526
+ handleDrop(change) {
2527
+ this.eventsService.emit('rowDrop', change);
2528
+ const drop = this.config?.options?.drop;
2529
+ if (!drop) {
2530
+ return;
2531
+ }
2532
+ defer(() => drop(change))
2533
+ .pipe(defaultIfEmpty(undefined), take(1))
2534
+ .subscribe({
2535
+ next: () => this.eventsService.emit('rowDropSuccess', change),
2536
+ error: (error) => this.eventsService.emit('rowDropError', { change, error }),
2537
+ });
2538
+ }
2539
+ toDropListId(id) {
2540
+ return id.endsWith('-rows-drop-list') ? id : `${id}-rows-drop-list`;
1889
2541
  }
1890
2542
  }
1891
- class DragDropService extends DragDropBase {
1892
- constructor(config, paginatorStore) {
1893
- super(config);
1894
- this.config = config;
1895
- this.paginatorStore = paginatorStore;
2543
+ let DragDropService = class DragDropService extends DragDropBase {
2544
+ constructor(config, eventsService, klesForm, injector, tableId) {
2545
+ super(config, eventsService, klesForm, injector, tableId);
1896
2546
  }
1897
2547
  listDropped(event) {
1898
2548
  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
- }
2549
+ this.reorder(event);
1908
2550
  }
1909
2551
  else {
1910
- //TODO
2552
+ this.transfer(event);
1911
2553
  }
1912
2554
  }
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;
2555
+ };
2556
+ DragDropService = __decorate([
2557
+ __param(0, Optional()),
2558
+ __param(0, Inject(DRAG_DROP_CONFIG))
2559
+ ], DragDropService);
2560
+ let DragDropLazyService = class DragDropLazyService extends DragDropBase {
2561
+ constructor(config, eventsService, klesForm, injector, tableId) {
2562
+ super(config, eventsService, klesForm, injector, tableId);
1930
2563
  }
1931
2564
  listDropped(event) {
1932
- // TODO appeler un observable + refresh tableau
2565
+ if (event.previousContainer === event.container) {
2566
+ this.reorder(event);
2567
+ return;
2568
+ }
2569
+ this.transfer(event);
1933
2570
  }
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
- }] }] });
2571
+ };
2572
+ DragDropLazyService = __decorate([
2573
+ __param(0, Optional()),
2574
+ __param(0, Inject(DRAG_DROP_CONFIG))
2575
+ ], DragDropLazyService);
1945
2576
 
1946
2577
  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) {
2578
+ 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
2579
  this.host = host;
1949
2580
  this.connectorService = connectorService;
1950
2581
  this.loader = loader;
@@ -1967,9 +2598,10 @@ class TableComponent {
1967
2598
  this.rowService = rowService;
1968
2599
  this.cellService = cellService;
1969
2600
  this.emptyStateService = emptyStateService;
1970
- this.headerHeightPx = 56;
1971
- this.scrollHeightPx = 0;
1972
- this.footerHeightPx = 0;
2601
+ this.treeService = treeService;
2602
+ this.headerHeightPx = signal(56, ...(ngDevMode ? [{ debugName: "headerHeightPx" }] : /* istanbul ignore next */ []));
2603
+ this.scrollHeightPx = signal(0, ...(ngDevMode ? [{ debugName: "scrollHeightPx" }] : /* istanbul ignore next */ []));
2604
+ this.footerHeightPx = signal(0, ...(ngDevMode ? [{ debugName: "footerHeightPx" }] : /* istanbul ignore next */ []));
1973
2605
  this.destroyRef = inject(DestroyRef);
1974
2606
  this.emptyStateComponent = KlesTableEmptyStateComponent;
1975
2607
  this.columns = this.columnsService.columns;
@@ -1993,6 +2625,33 @@ class TableComponent {
1993
2625
  listen: () => this.eventsService.events$,
1994
2626
  };
1995
2627
  }
2628
+ get emptyState() {
2629
+ return {
2630
+ enabled: this.emptyStateService.enabled,
2631
+ enable: () => this.emptyStateService.enable(),
2632
+ disable: () => this.emptyStateService.disable(),
2633
+ toggle: () => this.emptyStateService.toggle(),
2634
+ };
2635
+ }
2636
+ get render() {
2637
+ return {
2638
+ rows: () => this.renderService.forceRenderRows(),
2639
+ };
2640
+ }
2641
+ get tree() {
2642
+ return {
2643
+ expandedIds: this.treeService.expandedIds,
2644
+ loadingIds: this.treeService.loadingIds,
2645
+ isExpanded: (id) => this.treeService.isExpanded(id),
2646
+ isLoading: (id) => this.treeService.isLoading(id),
2647
+ getChildren: (id) => this.treeService.getChildren(id),
2648
+ getDescendants: (id) => this.treeService.getDescendants(id),
2649
+ expand: (id) => this.treeService.expand(id),
2650
+ collapse: (id) => this.treeService.collapse(id),
2651
+ toggle: (id) => this.treeService.toggle(id),
2652
+ collapseAll: () => this.treeService.collapseAll(),
2653
+ };
2654
+ }
1996
2655
  get form() {
1997
2656
  return {
1998
2657
  header: {
@@ -2011,25 +2670,43 @@ class TableComponent {
2011
2670
  list: () => this.tableService.klesForm.getRows(),
2012
2671
  get: (_id) => this.tableService.klesForm.getRows().controls.find((row) => row.value._id === _id),
2013
2672
  create: (value, index, options) => {
2014
- return this.tableService.klesForm.insertRow(this.rowFactory.createRow(this.columnsService
2673
+ const row = this.tableService.klesForm.insertRow(this.rowFactory.createRow(this.columnsService
2015
2674
  .columns()
2016
2675
  .map((col) => ({ ...col.cell?.field, name: col.columnDef }))
2017
2676
  .concat(this.extraRowService.extraColumns().map((col) => ({ ...col, name: col.columnDef }))), value), index, options).formGroup;
2677
+ this.eventsService.emit('rowCreate', this.rowEventPayload(row));
2678
+ return row;
2018
2679
  },
2019
2680
  patch: (_id, value, options) => {
2020
- return this.tableService.klesForm.updateRow(_id, value, options);
2681
+ const row = this.tableService.klesForm.updateRow(_id, value, options);
2682
+ if (row) {
2683
+ this.eventsService.emit('rowPatch', this.rowEventPayload(row));
2684
+ }
2685
+ return row;
2021
2686
  },
2022
2687
  remove: (_id, options) => {
2688
+ const row = this.tableService.klesForm.getRows().controls.find((current) => current.getRawValue()._id === _id);
2689
+ const payload = row ? this.rowEventPayload(row) : undefined;
2023
2690
  this.tableService.klesForm.deleteRowById(_id, options);
2691
+ if (payload) {
2692
+ this.eventsService.emit('rowDelete', payload);
2693
+ }
2024
2694
  },
2025
2695
  reset: (_id, value, options) => {
2026
2696
  this.tableService.klesForm.resetRow(_id, value, options);
2697
+ const row = this.tableService.klesForm.getRows().controls.find((current) => current.getRawValue()._id === _id);
2698
+ if (row) {
2699
+ this.eventsService.emit('rowUpdate', this.rowEventPayload(row));
2700
+ }
2027
2701
  },
2028
2702
  },
2029
2703
  };
2030
2704
  }
2031
2705
  get scrollbar() {
2032
2706
  return {
2707
+ setVisible: (visible) => this.scrollbarService.setScrollbarVisible(visible),
2708
+ show: () => this.scrollbarService.showScrollbar(),
2709
+ hide: () => this.scrollbarService.hideScrollbar(),
2033
2710
  getTop: () => this.scrollbarService.getTop(),
2034
2711
  to: (top, left, sb) => this.scrollbarService.to(top, left, sb),
2035
2712
  toTop: (sb) => this.scrollbarService.toTop(sb),
@@ -2040,6 +2717,7 @@ class TableComponent {
2040
2717
  }
2041
2718
  get column() {
2042
2719
  return {
2720
+ getVisible: () => this.columnsService.getVisible(),
2043
2721
  setVisible: (columnDef, visible) => this.columnsService.setVisible(columnDef, visible),
2044
2722
  toggleVisible: (columnDef) => this.columnsService.toggleVisible(columnDef),
2045
2723
  changeWidth: (columnDef, options) => this.columnsService.changeWidth(columnDef, options),
@@ -2052,6 +2730,7 @@ class TableComponent {
2052
2730
  }
2053
2731
  get pagination() {
2054
2732
  return {
2733
+ disabled: this.paginatorService.disabled(),
2055
2734
  setPageIndex: (index) => this.paginatorService.setPageIndex(index),
2056
2735
  setPageSize: (size) => this.paginatorService.setPageSize(size),
2057
2736
  firstPage: () => this.paginatorService.firstPage(),
@@ -2068,10 +2747,6 @@ class TableComponent {
2068
2747
  enable: () => this.selectionService.enable(),
2069
2748
  count: this.selectionService.count(),
2070
2749
  selectionModel: this.selectionService.selectionModel,
2071
- // changed: () => {},
2072
- // isEmpty: () => {},
2073
- // isMultipleSelection: () => {},
2074
- // selected: () => {},
2075
2750
  };
2076
2751
  }
2077
2752
  get sort() {
@@ -2083,12 +2758,14 @@ class TableComponent {
2083
2758
  }
2084
2759
  get loading() {
2085
2760
  return {
2761
+ active: this.loadingService.loading,
2086
2762
  start: () => this.loadingService.start(),
2087
2763
  stop: () => this.loadingService.stop(),
2088
2764
  };
2089
2765
  }
2090
2766
  get footer() {
2091
2767
  return {
2768
+ visible: this.footerService.footer,
2092
2769
  hide: () => this.footerService.hide(),
2093
2770
  show: () => this.footerService.show(),
2094
2771
  };
@@ -2097,8 +2774,17 @@ class TableComponent {
2097
2774
  return this.tableService.ui;
2098
2775
  }
2099
2776
  refresh() {
2777
+ this.treeService.collapseAll();
2100
2778
  this.loader.refresh();
2101
2779
  }
2780
+ rowEventPayload(row) {
2781
+ return {
2782
+ row,
2783
+ rowIndex: this.tableService.klesForm.getRows().controls.indexOf(row),
2784
+ value: row.value,
2785
+ rawValue: row.getRawValue(),
2786
+ };
2787
+ }
2102
2788
  ngOnInit() {
2103
2789
  this.sortService.register(this.matSort);
2104
2790
  const el = this.formElemRef.nativeElement;
@@ -2120,9 +2806,6 @@ class TableComponent {
2120
2806
  this._cleanup?.();
2121
2807
  this.scrollbarService.unregister();
2122
2808
  }
2123
- submit() {
2124
- // TODO
2125
- }
2126
2809
  getColumnSeparator(column, section) {
2127
2810
  const separatorConfig = column.separator;
2128
2811
  if (separatorConfig === false || separatorConfig === undefined) {
@@ -2155,13 +2838,6 @@ class TableComponent {
2155
2838
  }
2156
2839
  return this.getColumnSeparator(column, section);
2157
2840
  }
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
2841
  getStickyEndSeparator(column, section) {
2166
2842
  if (column.stickyEnd !== true) {
2167
2843
  return null;
@@ -2187,9 +2863,9 @@ class TableComponent {
2187
2863
  const header = this.host.nativeElement.querySelector('.mat-mdc-header-row');
2188
2864
  const footer = this.host.nativeElement.querySelector('.mat-mdc-footer-row');
2189
2865
  const compute = () => {
2190
- this.scrollHeightPx = Math.max(0, (formNativeElem?.offsetHeight ?? 0) - (formNativeElem?.clientHeight ?? 0));
2191
- this.headerHeightPx = Math.ceil(header?.getBoundingClientRect().height ?? 0);
2192
- this.footerHeightPx = Math.max(0, footer?.getBoundingClientRect().height ?? 0);
2866
+ this.scrollHeightPx.set(Math.max(0, (formNativeElem?.offsetHeight ?? 0) - (formNativeElem?.clientHeight ?? 0)));
2867
+ this.headerHeightPx.set(Math.ceil(header?.getBoundingClientRect().height ?? 0));
2868
+ this.footerHeightPx.set(Math.max(0, footer?.getBoundingClientRect().height ?? 0));
2193
2869
  };
2194
2870
  const scheduleCompute = () => {
2195
2871
  if (this.rafId) {
@@ -2224,8 +2900,8 @@ class TableComponent {
2224
2900
  };
2225
2901
  }
2226
2902
  }
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" }] }); }
2903
+ 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 }); }
2904
+ 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 [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\" [rowIndex]=\"dataIndex ?? index\">\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"] }, { 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" }] }); }
2229
2905
  }
2230
2906
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: TableComponent, decorators: [{
2231
2907
  type: Component,
@@ -2239,6 +2915,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
2239
2915
  MatIconModule,
2240
2916
  MatButtonModule,
2241
2917
  CdkTableModule,
2918
+ ScrollingModule,
2242
2919
  KlesMaterialDynamicformsModule,
2243
2920
  HeaderFieldPipe,
2244
2921
  CellFieldPipe,
@@ -2254,8 +2931,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
2254
2931
  KlesCellComponent,
2255
2932
  KlesHeaderComponent,
2256
2933
  HeaderPipe,
2257
- 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"] }]
2934
+ RowContextPipe,
2935
+ ], 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 [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\" [rowIndex]=\"dataIndex ?? index\">\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
2936
  }], ctorParameters: () => [{ type: i0.ElementRef }, { type: KlesTableConnectorService }, { type: undefined, decorators: [{
2260
2937
  type: Inject,
2261
2938
  args: [LOADER_SERVICE]
@@ -2276,7 +2953,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
2276
2953
  args: [SORT_SERVICE]
2277
2954
  }] }, { type: FilterService, decorators: [{
2278
2955
  type: Optional
2279
- }] }, { type: ExpandedRowStore }, { type: RowFormFactory }, { type: EventsService }, { type: RowService }, { type: CellService }, { type: EmptyStateService }], propDecorators: { table: [{
2956
+ }] }, { type: ExpandedRowStore }, { type: RowFormFactory }, { type: EventsService }, { type: RowService }, { type: CellService }, { type: EmptyStateService }, { type: TreeService }], propDecorators: { table: [{
2280
2957
  type: ViewChild,
2281
2958
  args: [MatTable]
2282
2959
  }], matSort: [{
@@ -2535,15 +3212,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
2535
3212
  }] });
2536
3213
 
2537
3214
  class InfiniteScrollTableComponent {
2538
- constructor() { }
2539
- ngOnInit() { }
2540
3215
  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 }] }); }
3216
+ 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
3217
  }
2543
3218
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: InfiniteScrollTableComponent, decorators: [{
2544
3219
  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: () => [] });
3220
+ args: [{ selector: 'kles-infinite-scroll-table', standalone: true, imports: [], template: "" }]
3221
+ }] });
2547
3222
 
2548
3223
  class SelectionLoaderService {
2549
3224
  constructor(selectionConfig) {
@@ -2553,7 +3228,7 @@ class SelectionLoaderService {
2553
3228
  return this.selectionConfig?.key || '#select';
2554
3229
  }
2555
3230
  select(row, selected, filters) {
2556
- return (this.selectionConfig?.params?.() || of({})).pipe(auditTime(0), take(1), switchMap((params) => {
3231
+ return defer(() => this.selectionConfig?.params?.() || of({})).pipe(auditTime(0), take(1), switchMap((params) => {
2557
3232
  const selection$ = this.selectionConfig?.select
2558
3233
  ? this.selectionConfig.select(params, row, selected, filters)
2559
3234
  : of({
@@ -2573,10 +3248,14 @@ class SelectionLoaderService {
2573
3248
  loading: true,
2574
3249
  success: false,
2575
3250
  }), result$);
2576
- }));
3251
+ }), catchError((error) => of({
3252
+ error,
3253
+ loading: false,
3254
+ success: false,
3255
+ })));
2577
3256
  }
2578
3257
  selectAll(selected, filters) {
2579
- return (this.selectionConfig?.params?.() || of({})).pipe(auditTime(0), take(1), switchMap((params) => {
3258
+ return defer(() => this.selectionConfig?.params?.() || of({})).pipe(auditTime(0), take(1), switchMap((params) => {
2580
3259
  const selection$ = this.selectionConfig?.selectAll
2581
3260
  ? this.selectionConfig.selectAll(params, selected, filters)
2582
3261
  : of({
@@ -2597,7 +3276,11 @@ class SelectionLoaderService {
2597
3276
  loading: true,
2598
3277
  success: false,
2599
3278
  }), result$);
2600
- }));
3279
+ }), catchError((error) => of({
3280
+ error,
3281
+ loading: false,
3282
+ success: false,
3283
+ })));
2601
3284
  }
2602
3285
  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
3286
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: SelectionLoaderService }); }
@@ -2795,9 +3478,10 @@ class KlesSelectionModel {
2795
3478
  this._stateChanged = new Subject();
2796
3479
  this._state = KlesSelectionModelState.ENABLED;
2797
3480
  this._count = signal(0, ...(ngDevMode ? [{ debugName: "_count" }] : /* istanbul ignore next */ []));
2798
- initialValues?.forEach((v) => {
2799
- this._selection.add(v);
2800
- });
3481
+ const values = initialValues ?? [];
3482
+ this.assertSelectionCardinality(values);
3483
+ values.forEach((value) => this._selection.add(value));
3484
+ this._count.set(this._selection.size);
2801
3485
  }
2802
3486
  get selected() {
2803
3487
  return {
@@ -2818,20 +3502,32 @@ class KlesSelectionModel {
2818
3502
  get stateChanged() {
2819
3503
  return this._stateChanged.asObservable();
2820
3504
  }
3505
+ get selectionMode() {
3506
+ return this.multiple;
3507
+ }
2821
3508
  select(value, options) {
2822
3509
  const added = [];
2823
3510
  const removed = [];
2824
3511
  if (this._state === KlesSelectionModelState.ENABLED) {
2825
3512
  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);
3513
+ this.assertSelectionCardinality(value);
3514
+ if (!this.multiple && value.length === 1) {
3515
+ const singleValue = value[0];
3516
+ if (!this.isSelected(singleValue)) {
3517
+ removed.push(...Array.from(this._selection));
3518
+ this._selection.clear();
3519
+ this._selection.add(singleValue);
3520
+ added.push(singleValue);
2833
3521
  }
2834
- });
3522
+ }
3523
+ else {
3524
+ value.forEach((v) => {
3525
+ if (!this.isSelected(v)) {
3526
+ this._selection.add(v);
3527
+ added.push(v);
3528
+ }
3529
+ });
3530
+ }
2835
3531
  }
2836
3532
  else {
2837
3533
  if (!this.isSelected(value)) {
@@ -2845,7 +3541,7 @@ class KlesSelectionModel {
2845
3541
  }
2846
3542
  }
2847
3543
  this._count.set(this._selection.size);
2848
- if (options?.emitEvent ?? true) {
3544
+ if ((options?.emitEvent ?? true) && (added.length > 0 || removed.length > 0)) {
2849
3545
  this._changed.next({ added, removed, count: this._selection.size, state: this._state });
2850
3546
  }
2851
3547
  }
@@ -2869,7 +3565,7 @@ class KlesSelectionModel {
2869
3565
  }
2870
3566
  }
2871
3567
  this._count.set(this._selection.size);
2872
- if (options?.emitEvent ?? true) {
3568
+ if ((options?.emitEvent ?? true) && (added.length > 0 || removed.length > 0)) {
2873
3569
  this._changed.next({ added, removed, count: this._selection.size, state: this._state });
2874
3570
  }
2875
3571
  }
@@ -2896,20 +3592,40 @@ class KlesSelectionModel {
2896
3592
  this._stateChanged.next(this._state);
2897
3593
  }
2898
3594
  isSelected(value) {
2899
- return this._selection.has(this.getValue(value));
3595
+ return this._selection.has(value);
2900
3596
  }
2901
3597
  isMultipleSelection() {
2902
3598
  return this.multiple || false;
2903
3599
  }
2904
- getValue(value) {
2905
- // si jamais je rajoute une méthode de comparaison avec _selection
2906
- return value;
3600
+ reset(values, options) {
3601
+ this.assertSelectionCardinality(values);
3602
+ const previous = Array.from(this._selection);
3603
+ this._selection.clear();
3604
+ values.forEach((value) => this._selection.add(value));
3605
+ this._count.set(this._selection.size);
3606
+ if (options?.emitEvent ?? true) {
3607
+ this._changed.next({
3608
+ added: values.filter((value) => !previous.includes(value)),
3609
+ removed: previous.filter((value) => !this._selection.has(value)),
3610
+ count: this._selection.size,
3611
+ state: this._state,
3612
+ });
3613
+ }
3614
+ }
3615
+ assertSelectionCardinality(values) {
3616
+ if (!this.multiple && values.length > 1) {
3617
+ throw getMultipleValuesInSingleSelectionError();
3618
+ }
2907
3619
  }
2908
3620
  }
2909
3621
 
2910
3622
  class AbstractSelectionService {
2911
- constructor(selectionConfig) {
3623
+ constructor(selectionConfig, fm, eventsService) {
2912
3624
  this.selectionConfig = selectionConfig;
3625
+ this.fm = fm;
3626
+ this.eventsService = eventsService;
3627
+ this._loadingRows = signal(new Set(), ...(ngDevMode ? [{ debugName: "_loadingRows" }] : /* istanbul ignore next */ []));
3628
+ this.loadingRows = this._loadingRows.asReadonly();
2913
3629
  }
2914
3630
  get key() {
2915
3631
  return this.selectionConfig?.key || '#select';
@@ -2917,7 +3633,66 @@ class AbstractSelectionService {
2917
3633
  get selectionMode() {
2918
3634
  return this.selectionConfig?.selectionMode || false;
2919
3635
  }
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 }); }
3636
+ isLoading(row) {
3637
+ return this._loadingRows().has(row);
3638
+ }
3639
+ emitSelectionEvents(changed, selectedCount = changed.count) {
3640
+ const payload = this.selectionPayload(changed.added, changed.removed, selectedCount);
3641
+ this.eventsService.emit('selectionChange', payload);
3642
+ changed.added?.forEach((row) => this.eventsService.emit('rowSelect', this.rowPayload(row)));
3643
+ changed.removed?.forEach((row) => this.eventsService.emit('rowUnselect', this.rowPayload(row)));
3644
+ }
3645
+ emitBulkSelectionEvent(selected, selectedCount) {
3646
+ this.eventsService.emit(selected ? 'selectAll' : 'unselectAll', this.selectionPayload(undefined, undefined, selectedCount));
3647
+ }
3648
+ startRowSelection(row) {
3649
+ this._loadingRows.update((rows) => new Set([...rows, row]));
3650
+ row.controls[this.key]?.disable({ emitEvent: false });
3651
+ }
3652
+ stabilizeRowSelection(row, selected) {
3653
+ row.controls[this.key]?.patchValue(selected, { emitEvent: false });
3654
+ this._loadingRows.update((rows) => {
3655
+ const next = new Set(rows);
3656
+ next.delete(row);
3657
+ return next;
3658
+ });
3659
+ if (this.selectionModel.state === KlesSelectionModelState.DISABLED || this.selectionConfig?.isDisabled?.(row)) {
3660
+ row.controls[this.key]?.disable({ emitEvent: false });
3661
+ }
3662
+ else {
3663
+ row.controls[this.key]?.enable({ emitEvent: false });
3664
+ }
3665
+ }
3666
+ emitSelectionError(error, requestedSelected, previousSelected, row) {
3667
+ const payload = {
3668
+ error,
3669
+ requestedSelected,
3670
+ previousSelected,
3671
+ ...(row ? this.rowPayload(row) : {}),
3672
+ };
3673
+ this.eventsService.emit('selectionError', payload);
3674
+ }
3675
+ selectionPayload(addedRows, removedRows, selectedCount = 0) {
3676
+ const selectedRows = this.selectionModel.selected.items ?? [];
3677
+ return {
3678
+ selectedRows,
3679
+ selectedValues: selectedRows.map((row) => row.value),
3680
+ selectedRawValues: selectedRows.map((row) => row.getRawValue()),
3681
+ selectedCount,
3682
+ addedRows,
3683
+ removedRows,
3684
+ allSelected: selectedCount > 0 && selectedCount === this.linesTotal(),
3685
+ };
3686
+ }
3687
+ rowPayload(row) {
3688
+ return {
3689
+ row,
3690
+ rowIndex: this.fm.getRows().controls.indexOf(row),
3691
+ value: row.value,
3692
+ rawValue: row.getRawValue(),
3693
+ };
3694
+ }
3695
+ 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
3696
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: AbstractSelectionService }); }
2922
3697
  }
2923
3698
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: AbstractSelectionService, decorators: [{
@@ -2927,11 +3702,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
2927
3702
  }, {
2928
3703
  type: Inject,
2929
3704
  args: [SELECTION_CONFIG]
2930
- }] }] });
3705
+ }] }, { type: KlesForm }, { type: EventsService }] });
2931
3706
  class SelectionService extends AbstractSelectionService {
2932
- constructor(selectionConfig, fm, selectionLoaderService, scrollbarService, loadingService, datasourceService, linesService) {
2933
- super(selectionConfig);
2934
- this.fm = fm;
3707
+ constructor(selectionConfig, fm, selectionLoaderService, scrollbarService, loadingService, datasourceService, linesService, eventsService) {
3708
+ super(selectionConfig, fm, eventsService);
2935
3709
  this.selectionLoaderService = selectionLoaderService;
2936
3710
  this.scrollbarService = scrollbarService;
2937
3711
  this.loadingService = loadingService;
@@ -2956,21 +3730,25 @@ class SelectionService extends AbstractSelectionService {
2956
3730
  enable() {
2957
3731
  this.selectionModel.enable();
2958
3732
  }
3733
+ linesTotal() {
3734
+ return this.linesService.total();
3735
+ }
2959
3736
  setSelection() {
2960
3737
  this.linesService
2961
3738
  .loaded()
2962
3739
  .pipe(takeUntilDestroyed(this.destroyRef))
2963
3740
  .subscribe(() => {
3741
+ // Build the initial model silently, then update the header once.
2964
3742
  this.fm.getRows().controls.forEach((group) => {
2965
3743
  if (group.controls[this.selectionLoaderService.key]?.value === true) {
2966
- this.selectionModel.select(group, { emitEvent: false }); // event false to avoid multiple send event
3744
+ this.selectionModel.select(group, { emitEvent: false });
2967
3745
  }
2968
3746
  else if (this.selectionConfig?.isSelected != undefined && this.selectionConfig.isSelected(group)) {
2969
- this.selectionModel.select(group, { emitEvent: false }); // event false to avoid multiple send event
3747
+ this.selectionModel.select(group, { emitEvent: false });
2970
3748
  group.controls[this.selectionLoaderService.key]?.patchValue(true, { emitEvent: false });
2971
3749
  }
2972
3750
  else {
2973
- this.selectionModel.deselect(group, { emitEvent: false }); // event false to avoid multiple send event
3751
+ this.selectionModel.deselect(group, { emitEvent: false });
2974
3752
  }
2975
3753
  if (this.selectionConfig?.isDisabled && this.selectionConfig.isDisabled(group)) {
2976
3754
  group.controls[this.selectionLoaderService.key]?.disable({ emitEvent: false });
@@ -2983,31 +3761,46 @@ class SelectionService extends AbstractSelectionService {
2983
3761
  this.fm
2984
3762
  .getHeader()
2985
3763
  .controls[this.key]?.valueChanges.pipe(takeUntilDestroyed(this.destroyRef), switchMap((value) => {
2986
- return this.selectionLoaderService.selectAll(!!value, this.fm.getHeader().getRawValue());
3764
+ const requestedSelected = !!value;
3765
+ const previousSelected = this.areAllFilteredRowsSelected();
3766
+ return this.selectionLoaderService
3767
+ .selectAll(requestedSelected, this.fm.getHeader().getRawValue())
3768
+ .pipe(map((response) => ({ response, requestedSelected, previousSelected })));
2987
3769
  }))
2988
- .subscribe((response) => {
3770
+ .subscribe(({ response, requestedSelected, previousSelected }) => {
2989
3771
  if (response.loading) {
2990
3772
  this.scrollbarService.toTop('instant');
2991
3773
  this.loadingService.start();
2992
3774
  return;
2993
3775
  }
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
- }
3776
+ this.loadingService.stop();
3777
+ if (!response.success || response.selected === undefined) {
3778
+ this.updateHeader();
3779
+ this.emitSelectionError(response.error ?? new Error('The bulk selection response is invalid.'), requestedSelected, previousSelected);
3780
+ return;
3781
+ }
3782
+ if (response.selected) {
3783
+ if (this.selectionModel.isMultipleSelection()) {
3784
+ this.selectionModel.select(this.datasourceService.datasource.filteredData?.filter((g) => g.controls[this.selectionLoaderService.key]?.enabled) ??
3785
+ []);
3004
3786
  }
3005
3787
  else {
3006
- this.selectionModel.deselect(this.datasourceService.datasource.filteredData?.filter((g) => g.controls[this.selectionLoaderService.key]?.enabled));
3788
+ const row = this.datasourceService.datasource.filteredData?.filter((g) => g.controls[this.selectionLoaderService.key]?.enabled)[0];
3789
+ if (row) {
3790
+ this.selectionModel.select(row);
3791
+ }
3007
3792
  }
3008
3793
  }
3794
+ else {
3795
+ this.selectionModel.deselect(this.datasourceService.datasource.filteredData?.filter((g) => g.controls[this.selectionLoaderService.key]?.enabled));
3796
+ }
3797
+ this.emitBulkSelectionEvent(response.selected, this.selectionModel.selected.count);
3009
3798
  });
3010
3799
  }
3800
+ areAllFilteredRowsSelected() {
3801
+ const rows = this.datasourceService.datasource.filteredData.filter((group) => group.controls[this.selectionLoaderService.key]?.enabled);
3802
+ return rows.length > 0 && rows.every((group) => this.selectionModel.isSelected(group));
3803
+ }
3011
3804
  listenRowSelection() {
3012
3805
  this.datasourceService.datasource
3013
3806
  .connect()
@@ -3020,25 +3813,32 @@ class SelectionService extends AbstractSelectionService {
3020
3813
  })
3021
3814
  .filter(Boolean));
3022
3815
  }), concatMap(({ row, selected }) => {
3816
+ const previousSelected = this.selectionModel.isSelected(row);
3023
3817
  return this.selectionLoaderService.select(row, selected).pipe(map((response) => {
3024
3818
  return {
3025
3819
  row,
3820
+ selected,
3821
+ previousSelected,
3026
3822
  response,
3027
3823
  };
3028
3824
  }));
3029
3825
  }))
3030
- .subscribe(({ row, response }) => {
3826
+ .subscribe(({ row, selected, previousSelected, response }) => {
3031
3827
  if (response.loading) {
3032
- //mettre la ligne avec un spinner
3828
+ this.startRowSelection(row);
3829
+ return;
3830
+ }
3831
+ if (!response.success || response.selected === undefined) {
3832
+ this.stabilizeRowSelection(row, previousSelected);
3833
+ this.emitSelectionError(response.error ?? new Error('The row selection response is invalid.'), selected, previousSelected, row);
3834
+ return;
3835
+ }
3836
+ this.stabilizeRowSelection(row, response.selected);
3837
+ if (response.selected) {
3838
+ this.selectionModel.select(row);
3033
3839
  }
3034
3840
  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
3841
+ this.selectionModel.deselect(row);
3042
3842
  }
3043
3843
  });
3044
3844
  }
@@ -3052,12 +3852,15 @@ class SelectionService extends AbstractSelectionService {
3052
3852
  });
3053
3853
  this.fm.getRows().updateValueAndValidity({ emitEvent: false });
3054
3854
  this.updateHeader();
3855
+ this.emitSelectionEvents(changed);
3055
3856
  });
3056
3857
  this.selectionModel.stateChanged.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((state) => {
3057
3858
  if (state === KlesSelectionModelState.ENABLED) {
3058
3859
  this.fm.getHeader().controls[this.key].enable({ emitEvent: false });
3059
3860
  this.fm.getRows().controls.forEach((group) => {
3060
- group.controls[this.key].enable({ emitEvent: false });
3861
+ if (!this.isLoading(group) && !this.selectionConfig?.isDisabled?.(group)) {
3862
+ group.controls[this.key].enable({ emitEvent: false });
3863
+ }
3061
3864
  });
3062
3865
  }
3063
3866
  else {
@@ -3094,7 +3897,7 @@ class SelectionService extends AbstractSelectionService {
3094
3897
  this.fm.getHeader().controls[this.selectionLoaderService.key]?.patchValue(false, { emitEvent: false });
3095
3898
  }
3096
3899
  }
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 }); }
3900
+ 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
3901
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: SelectionService }); }
3099
3902
  }
3100
3903
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: SelectionService, decorators: [{
@@ -3110,11 +3913,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
3110
3913
  }] }, { type: undefined, decorators: [{
3111
3914
  type: Inject,
3112
3915
  args: [LINES_SERVICE]
3113
- }] }] });
3916
+ }] }, { type: EventsService }] });
3114
3917
  class SelectionLazyService extends AbstractSelectionService {
3115
- constructor(selectionConfig, fm, selectionLoaderService, scrollbarService, loadingService, datasourceService, linesService, filterStore) {
3116
- super(selectionConfig);
3117
- this.fm = fm;
3918
+ constructor(selectionConfig, fm, selectionLoaderService, scrollbarService, loadingService, datasourceService, linesService, filterStore, eventsService) {
3919
+ super(selectionConfig, fm, eventsService);
3118
3920
  this.selectionLoaderService = selectionLoaderService;
3119
3921
  this.scrollbarService = scrollbarService;
3120
3922
  this.loadingService = loadingService;
@@ -3123,8 +3925,10 @@ class SelectionLazyService extends AbstractSelectionService {
3123
3925
  this.filterStore = filterStore;
3124
3926
  this.destroyRef = inject(DestroyRef);
3125
3927
  this._count = signal(0, ...(ngDevMode ? [{ debugName: "_count" }] : /* istanbul ignore next */ []));
3928
+ this.selectionModel = new KlesSelectionModel(selectionConfig?.selectionMode);
3126
3929
  }
3127
3930
  register() {
3931
+ this.listenSelection();
3128
3932
  this.setSelection();
3129
3933
  this.listenHeaderSelection();
3130
3934
  this.listenRowSelection();
@@ -3133,37 +3937,56 @@ class SelectionLazyService extends AbstractSelectionService {
3133
3937
  return this._count.asReadonly();
3134
3938
  }
3135
3939
  disable() {
3136
- this.fm.getHeader().controls[this.key].disable({ emitEvent: false });
3940
+ this.selectionModel.disable();
3137
3941
  }
3138
3942
  enable() {
3139
- this.fm.getHeader().controls[this.key].enable({ emitEvent: false });
3943
+ this.selectionModel.enable();
3944
+ }
3945
+ linesTotal() {
3946
+ return this.linesService.total();
3140
3947
  }
3141
3948
  listenHeaderSelection() {
3142
3949
  this.fm
3143
3950
  .getHeader()
3144
3951
  .controls[this.key]?.valueChanges.pipe(takeUntilDestroyed(this.destroyRef), switchMap((value) => {
3145
- return this.selectionLoaderService.selectAll(!!value, this.fm.getHeader().getRawValue());
3952
+ const requestedSelected = !!value;
3953
+ const previousSelected = this._count() > 0 && this._count() === this.linesService.total();
3954
+ return this.selectionLoaderService
3955
+ .selectAll(requestedSelected, this.fm.getHeader().getRawValue())
3956
+ .pipe(map((response) => ({ response, requestedSelected, previousSelected })));
3146
3957
  }))
3147
- .subscribe((response) => {
3958
+ .subscribe(({ response, requestedSelected, previousSelected }) => {
3148
3959
  if (response.loading) {
3149
3960
  this.scrollbarService.toTop('instant');
3150
3961
  this.loadingService.start();
3151
3962
  return;
3152
3963
  }
3964
+ this.loadingService.stop();
3965
+ if (!response.success || response.selected === undefined) {
3966
+ this.updateHeader();
3967
+ this.emitSelectionError(response.error ?? new Error('The bulk selection response is invalid.'), requestedSelected, previousSelected);
3968
+ return;
3969
+ }
3970
+ this._count.set(response.count ?? 0);
3971
+ const rows = this.fm.getRows().controls.filter((group) => group.controls[this.selectionLoaderService.key]?.enabled);
3972
+ if (response.selected) {
3973
+ if (this.selectionModel.isMultipleSelection()) {
3974
+ this.selectionModel.select(rows);
3975
+ }
3976
+ else {
3977
+ const row = rows[0];
3978
+ if (row) {
3979
+ this.selectionModel.select(row);
3980
+ }
3981
+ }
3982
+ }
3153
3983
  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
- // }
3984
+ this.selectionModel.deselect(rows);
3166
3985
  }
3986
+ this.fm.getRows().updateValueAndValidity({
3987
+ emitEvent: false,
3988
+ });
3989
+ this.emitBulkSelectionEvent(response.selected, this._count());
3167
3990
  });
3168
3991
  }
3169
3992
  listenRowSelection() {
@@ -3181,28 +4004,68 @@ class SelectionLazyService extends AbstractSelectionService {
3181
4004
  })
3182
4005
  .filter(Boolean));
3183
4006
  }), withLatestFrom(this.filterStore?.filters$ ?? of({})), concatMap(([{ row, selected }, filters]) => {
4007
+ const previousSelected = this.selectionModel.isSelected(row);
3184
4008
  return this.selectionLoaderService.select(row, selected, filters).pipe(map((response) => {
3185
4009
  return {
3186
4010
  row,
4011
+ selected,
4012
+ previousSelected,
3187
4013
  response,
3188
4014
  };
3189
4015
  }));
3190
4016
  }))
3191
- .subscribe(({ row, response }) => {
4017
+ .subscribe(({ row, selected, previousSelected, response }) => {
3192
4018
  if (response.loading) {
3193
- //mettre la ligne avec un spinner
4019
+ this.startRowSelection(row);
4020
+ return;
4021
+ }
4022
+ if (!response.success || response.selected === undefined) {
4023
+ this.stabilizeRowSelection(row, previousSelected);
4024
+ this.emitSelectionError(response.error ?? new Error('The row selection response is invalid.'), selected, previousSelected, row);
4025
+ return;
4026
+ }
4027
+ this._count.set(response.count ?? 0);
4028
+ this.stabilizeRowSelection(row, response.selected);
4029
+ if (response.selected) {
4030
+ this.selectionModel.select(row);
3194
4031
  }
3195
4032
  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,
4033
+ this.selectionModel.deselect(row);
4034
+ }
4035
+ this.updateHeader(this._count());
4036
+ });
4037
+ }
4038
+ listenSelection() {
4039
+ this.selectionModel.changed.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((changed) => {
4040
+ changed.removed?.forEach((group) => {
4041
+ group.controls[this.selectionLoaderService.key]?.patchValue(false, { emitEvent: false });
4042
+ });
4043
+ changed.added?.forEach((group) => {
4044
+ group.controls[this.selectionLoaderService.key]?.patchValue(true, { emitEvent: false });
4045
+ });
4046
+ this.fm.getRows().updateValueAndValidity({
4047
+ emitEvent: false,
4048
+ });
4049
+ this.emitSelectionEvents(changed, this._count());
4050
+ });
4051
+ this.selectionModel.stateChanged.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((state) => {
4052
+ if (state === KlesSelectionModelState.ENABLED) {
4053
+ this.fm.getHeader().controls[this.key]?.enable({ emitEvent: false });
4054
+ this.fm.getRows().controls.forEach((group) => {
4055
+ if (!this.isLoading(group) && !this.selectionConfig?.isDisabled?.(group)) {
4056
+ group.controls[this.key]?.enable({
4057
+ emitEvent: false,
4058
+ });
4059
+ }
3201
4060
  });
3202
- // if (footer) {
3203
- // this.fm.getFooter().patchValue(footer, { emitEvent: false });
3204
- // }
4061
+ return;
3205
4062
  }
4063
+ this.fm.getHeader().controls[this.key]?.disable({ emitEvent: false });
4064
+ this.fm.getRows().controls.forEach((group) => {
4065
+ group.controls[this.key]?.disable({
4066
+ emitEvent: false,
4067
+ });
4068
+ });
3206
4069
  });
3207
4070
  }
3208
4071
  setSelection() {
@@ -3210,18 +4073,39 @@ class SelectionLazyService extends AbstractSelectionService {
3210
4073
  .loaded()
3211
4074
  .pipe(takeUntilDestroyed(this.destroyRef))
3212
4075
  .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 });
4076
+ const selectedRows = this.fm.getRows().controls.filter((group) => {
4077
+ const selected = group.controls[this.selectionLoaderService.key]?.value === true || this.selectionConfig?.isSelected?.(group) === true;
4078
+ if (selected) {
4079
+ group.controls[this.selectionLoaderService.key]?.patchValue(true, {
4080
+ emitEvent: false,
4081
+ });
3216
4082
  }
3217
- if (this.selectionConfig?.isDisabled && this.selectionConfig.isDisabled(group)) {
3218
- group.controls[this.selectionLoaderService.key]?.disable({ emitEvent: false });
4083
+ if (this.selectionConfig?.isDisabled?.(group)) {
4084
+ group.controls[this.selectionLoaderService.key]?.disable({
4085
+ emitEvent: false,
4086
+ });
3219
4087
  }
4088
+ return selected;
3220
4089
  });
3221
- // this.updateHeader();
4090
+ this.selectionModel.reset(selectedRows, {
4091
+ emitEvent: false,
4092
+ });
4093
+ this.updateHeader(this._count());
4094
+ });
4095
+ }
4096
+ updateHeader(count = this._count()) {
4097
+ const total = this.linesService.total();
4098
+ this.fm
4099
+ .getUiHeader()
4100
+ .get(this.selectionLoaderService.key)
4101
+ ?.patchValue({
4102
+ indeterminate: count > 0 && count < total,
4103
+ });
4104
+ this.fm.getHeader().controls[this.selectionLoaderService.key]?.patchValue(count > 0 && count === total, {
4105
+ emitEvent: false,
3222
4106
  });
3223
4107
  }
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 }); }
4108
+ 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
4109
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: SelectionLazyService }); }
3226
4110
  }
3227
4111
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: SelectionLazyService, decorators: [{
@@ -3239,7 +4123,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
3239
4123
  args: [LINES_SERVICE]
3240
4124
  }] }, { type: FilterStore, decorators: [{
3241
4125
  type: Optional
3242
- }] }] });
4126
+ }] }, { type: EventsService }] });
3243
4127
 
3244
4128
  class LoaderService {
3245
4129
  constructor(loaderConfig, eventsService) {
@@ -3636,7 +4520,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
3636
4520
  args: [LINES_SERVICE]
3637
4521
  }] }, { type: ScrollbarService }] });
3638
4522
 
3639
- // import { ScrollbarLazyOrchestratorService, ScrollbarOrchestratorService } from '../services/features/scrollbar/scrollbar-orchestrator.service';
3640
4523
  class DynamicTableLoaderDirective {
3641
4524
  constructor(viewContainerRef) {
3642
4525
  this.viewContainerRef = viewContainerRef;
@@ -3659,7 +4542,6 @@ class DynamicTableLoaderDirective {
3659
4542
  }
3660
4543
  });
3661
4544
  }
3662
- ngOnInit() { }
3663
4545
  ngOnDestroy() {
3664
4546
  this.clearComponent();
3665
4547
  }
@@ -3799,7 +4681,7 @@ class DynamicTableLoaderDirective {
3799
4681
  ValidationService,
3800
4682
  SelectionLoaderService,
3801
4683
  PaginatorService,
3802
- LoaderChildrensService, //TODO
4684
+ LoaderChildrensService,
3803
4685
  {
3804
4686
  provide: TABLE_SERVICE,
3805
4687
  useClass: TableService,
@@ -3824,7 +4706,7 @@ class DynamicTableLoaderDirective {
3824
4706
  },
3825
4707
  {
3826
4708
  provide: ROW_DRAG_DROP,
3827
- useFactory: () => new DragDropLazyService(this.tableConfig().dragDropRows),
4709
+ useFactory: () => new DragDropLazyService(this.tableConfig().dragDropRows, inject(EventsService), inject(KlesForm), inject(Injector), this.tableConfig().id),
3828
4710
  },
3829
4711
  {
3830
4712
  provide: SORT_SERVICE,
@@ -3851,8 +4733,7 @@ class DynamicTableLoaderDirective {
3851
4733
  FilterService,
3852
4734
  {
3853
4735
  provide: ROW_DRAG_DROP,
3854
- useFactory: (paginatorstore) => new DragDropService(this.tableConfig().dragDropRows, paginatorstore),
3855
- deps: [...(this.tableConfig().paginator ? [PaginatorStore] : [])],
4736
+ useFactory: () => new DragDropService(this.tableConfig().dragDropRows, inject(EventsService), inject(KlesForm), inject(Injector), this.tableConfig().id),
3856
4737
  },
3857
4738
  {
3858
4739
  provide: SORT_SERVICE,
@@ -3883,12 +4764,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
3883
4764
  }], ctorParameters: () => [{ type: i0.ViewContainerRef }], propDecorators: { tableConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "tableConfig", required: true }] }] } });
3884
4765
 
3885
4766
  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
4767
  constructor(connectorService) {
3893
4768
  this.connectorService = connectorService;
3894
4769
  this.tableConfig = input.required(...(ngDevMode ? [{ debugName: "tableConfig" }] : /* istanbul ignore next */ []));
@@ -3897,8 +4772,25 @@ class KlesTableComponent {
3897
4772
  this.rowClick = new EventEmitter();
3898
4773
  this.rowDoubleClick = new EventEmitter();
3899
4774
  this.rowContextMenu = new EventEmitter();
4775
+ this.rowMouseEnter = new EventEmitter();
4776
+ this.rowMouseLeave = new EventEmitter();
4777
+ this.rowDrop = new EventEmitter();
4778
+ this.rowDropSuccess = new EventEmitter();
4779
+ this.rowDropError = new EventEmitter();
3900
4780
  this.cellClick = new EventEmitter();
4781
+ this.cellDoubleClick = new EventEmitter();
4782
+ this.cellContextMenu = new EventEmitter();
3901
4783
  this.cellValueChange = new EventEmitter();
4784
+ this.selectionChange = new EventEmitter();
4785
+ this.selectionError = new EventEmitter();
4786
+ this.pageChange = new EventEmitter();
4787
+ this.sortChange = new EventEmitter();
4788
+ this.filterChange = new EventEmitter();
4789
+ this.loadError = new EventEmitter();
4790
+ this.nodeExpand = new EventEmitter();
4791
+ this.nodeCollapse = new EventEmitter();
4792
+ this.nodeLoadChildren = new EventEmitter();
4793
+ this.nodeChildrenLoaded = new EventEmitter();
3902
4794
  this.elevationShadow = computed(() => {
3903
4795
  const level = this.tableConfig().elevation ?? 2;
3904
4796
  return level === 0 ? 'none' : `var(--mat-sys-level${level})`;
@@ -3906,9 +4798,9 @@ class KlesTableComponent {
3906
4798
  }
3907
4799
  ngOnInit() {
3908
4800
  this.connectorService.connected$
3909
- .pipe(takeUntilDestroyed(this.destroyRef), filter((connected) => connected), switchMap(() => {
3910
- return this.connectorService.events.listen();
3911
- }))
4801
+ .pipe(filter((connected) => connected), switchMap(() => {
4802
+ return this.events.listen();
4803
+ }), takeUntilDestroyed(this.destroyRef))
3912
4804
  .subscribe((event) => {
3913
4805
  this.dispatchEvent(event);
3914
4806
  });
@@ -3943,6 +4835,18 @@ class KlesTableComponent {
3943
4835
  get footer() {
3944
4836
  return this.connectorService.footer;
3945
4837
  }
4838
+ get emptyState() {
4839
+ return this.connectorService.emptyState;
4840
+ }
4841
+ get render() {
4842
+ return this.connectorService.render;
4843
+ }
4844
+ get events() {
4845
+ return this.connectorService.events;
4846
+ }
4847
+ get tree() {
4848
+ return this.connectorService.tree;
4849
+ }
3946
4850
  get ui() {
3947
4851
  return this.connectorService.ui;
3948
4852
  }
@@ -3958,34 +4862,67 @@ class KlesTableComponent {
3958
4862
  case 'rowContextMenu':
3959
4863
  this.rowContextMenu.emit(event.payload);
3960
4864
  break;
4865
+ case 'rowMouseEnter':
4866
+ this.rowMouseEnter.emit(event.payload);
4867
+ break;
4868
+ case 'rowMouseLeave':
4869
+ this.rowMouseLeave.emit(event.payload);
4870
+ break;
4871
+ case 'rowDrop':
4872
+ this.rowDrop.emit(event.payload);
4873
+ break;
4874
+ case 'rowDropSuccess':
4875
+ this.rowDropSuccess.emit(event.payload);
4876
+ break;
4877
+ case 'rowDropError':
4878
+ this.rowDropError.emit(event.payload);
4879
+ break;
3961
4880
  case 'cellClick':
3962
4881
  this.cellClick.emit(event.payload);
3963
4882
  break;
4883
+ case 'cellDoubleClick':
4884
+ this.cellDoubleClick.emit(event.payload);
4885
+ break;
4886
+ case 'cellContextMenu':
4887
+ this.cellContextMenu.emit(event.payload);
4888
+ break;
3964
4889
  case 'cellValueChange':
3965
4890
  this.cellValueChange.emit(event.payload);
3966
4891
  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;
4892
+ case 'selectionChange':
4893
+ this.selectionChange.emit(event.payload);
4894
+ break;
4895
+ case 'selectionError':
4896
+ this.selectionError.emit(event.payload);
4897
+ break;
4898
+ case 'pageChange':
4899
+ this.pageChange.emit(event.payload);
4900
+ break;
4901
+ case 'sortChange':
4902
+ this.sortChange.emit(event.payload);
4903
+ break;
4904
+ case 'filterChange':
4905
+ this.filterChange.emit(event.payload);
4906
+ break;
4907
+ case 'loadError':
4908
+ this.loadError.emit(event.payload);
4909
+ break;
4910
+ case 'nodeExpand':
4911
+ this.nodeExpand.emit(event.payload);
4912
+ break;
4913
+ case 'nodeCollapse':
4914
+ this.nodeCollapse.emit(event.payload);
4915
+ break;
4916
+ case 'nodeLoadChildren':
4917
+ this.nodeLoadChildren.emit(event.payload);
4918
+ break;
4919
+ case 'nodeChildrenLoaded':
4920
+ this.nodeChildrenLoaded.emit(event.payload);
4921
+ break;
3985
4922
  }
3986
4923
  }
3987
4924
  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"] }] }); }
4925
+ 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
4926
  }
3990
4927
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: KlesTableComponent, decorators: [{
3991
4928
  type: Component,
@@ -3998,10 +4935,44 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
3998
4935
  type: Output
3999
4936
  }], rowContextMenu: [{
4000
4937
  type: Output
4938
+ }], rowMouseEnter: [{
4939
+ type: Output
4940
+ }], rowMouseLeave: [{
4941
+ type: Output
4942
+ }], rowDrop: [{
4943
+ type: Output
4944
+ }], rowDropSuccess: [{
4945
+ type: Output
4946
+ }], rowDropError: [{
4947
+ type: Output
4001
4948
  }], cellClick: [{
4002
4949
  type: Output
4950
+ }], cellDoubleClick: [{
4951
+ type: Output
4952
+ }], cellContextMenu: [{
4953
+ type: Output
4003
4954
  }], cellValueChange: [{
4004
4955
  type: Output
4956
+ }], selectionChange: [{
4957
+ type: Output
4958
+ }], selectionError: [{
4959
+ type: Output
4960
+ }], pageChange: [{
4961
+ type: Output
4962
+ }], sortChange: [{
4963
+ type: Output
4964
+ }], filterChange: [{
4965
+ type: Output
4966
+ }], loadError: [{
4967
+ type: Output
4968
+ }], nodeExpand: [{
4969
+ type: Output
4970
+ }], nodeCollapse: [{
4971
+ type: Output
4972
+ }], nodeLoadChildren: [{
4973
+ type: Output
4974
+ }], nodeChildrenLoaded: [{
4975
+ type: Output
4005
4976
  }], hostId: [{
4006
4977
  type: HostBinding,
4007
4978
  args: ['attr.id']
@@ -4045,5 +5016,5 @@ var AlignCell;
4045
5016
  * Generated bundle index. Do not edit.
4046
5017
  */
4047
5018
 
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 };
5019
+ 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, PAGINATOR_CONFIG, ROW_DRAG_DROP, SCROLLBAR_ORCHESTRATOR_SERVICE, SELECTION_CONFIG, SELECTION_SERVICE, SORT_CONFIG, SORT_SERVICE, Span, TABLE_SERVICE, TableComponent, linesLazyLoader, linesLoader, selectionConfig };
4049
5020
  //# sourceMappingURL=3kles-kles-material-table-v2.mjs.map