@guiexpert/table 1.1.94 → 1.1.96

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.
Files changed (72) hide show
  1. package/README.md +12 -0
  2. package/css/main.css +192 -0
  3. package/css/table-calc.css +7 -0
  4. package/css/table-color-vars.css +46 -0
  5. package/css/table-fill-batch.css +58 -0
  6. package/css/table-row-drag.css +81 -0
  7. package/index.cjs +39 -37
  8. package/index.d.ts +28 -0
  9. package/index.js +5501 -1934
  10. package/lib/table/action/action-id.type.d.ts +1 -1
  11. package/lib/table/aria/aria-texts.d.ts +11 -0
  12. package/lib/table/aria/aria-texts.if.d.ts +87 -0
  13. package/lib/table/batch-edit/batch-edit-options.d.ts +21 -0
  14. package/lib/table/batch-edit/batch-edit-options.if.d.ts +20 -0
  15. package/lib/table/batch-edit/batch-edit-service.d.ts +104 -0
  16. package/lib/table/batch-edit/cell-change.if.d.ts +39 -0
  17. package/lib/table/batch-edit/cell-value-change.if.d.ts +18 -0
  18. package/lib/table/batch-edit/pending-cell-changes.d.ts +104 -0
  19. package/lib/table/calc/column-values.d.ts +55 -0
  20. package/lib/table/calc/show-values-as-internals.d.ts +4 -0
  21. package/lib/table/calc/show-values-as.d.ts +87 -0
  22. package/lib/table/calc/show-values-as.type.d.ts +55 -0
  23. package/lib/table/calc/value-getter-context.if.d.ts +35 -0
  24. package/lib/table/calc/value-getter.type.d.ts +36 -0
  25. package/lib/table/data/common/event/ge-batch-edit-event.d.ts +46 -0
  26. package/lib/table/data/common/event/ge-model-change-event.d.ts +27 -1
  27. package/lib/table/data/common/event/ge-row-drag-event.d.ts +89 -0
  28. package/lib/table/data/options/table-options.d.ts +6 -0
  29. package/lib/table/data/options/table-options.if.d.ts +44 -0
  30. package/lib/table/data/tablemodel/areamodel/abstract-area-model.d.ts +66 -0
  31. package/lib/table/data/tablemodel/areamodel/area-model-aggregate-footer.d.ts +5 -0
  32. package/lib/table/data/tablemodel/areamodel/area-model-array-of-arrays.d.ts +24 -0
  33. package/lib/table/data/tablemodel/areamodel/area-model-object-array.d.ts +70 -0
  34. package/lib/table/data/tablemodel/areamodel/area-model-pivot.d.ts +31 -0
  35. package/lib/table/data/tablemodel/areamodel/area-model-row-groups.d.ts +23 -1
  36. package/lib/table/data/tablemodel/areamodel/area-model-tree.d.ts +83 -0
  37. package/lib/table/data/tablemodel/areamodel/area-model.if.d.ts +55 -0
  38. package/lib/table/data/tablemodel/column/column-def.d.ts +31 -1
  39. package/lib/table/data/tablemodel/column/column-def.if.d.ts +86 -0
  40. package/lib/table/event-adapter.d.ts +7 -0
  41. package/lib/table/event-listener.if.d.ts +32 -0
  42. package/lib/table/factory/table-factory.d.ts +11 -0
  43. package/lib/table/fill/compute-fill-changes.d.ts +67 -0
  44. package/lib/table/fill/fill-direction.type.d.ts +7 -0
  45. package/lib/table/fill/fill-handle-options.d.ts +29 -0
  46. package/lib/table/fill/fill-handle-options.if.d.ts +35 -0
  47. package/lib/table/fill/fill-handle-service.d.ts +55 -0
  48. package/lib/table/fill/fill-series.d.ts +60 -0
  49. package/lib/table/fill/fill-value-context.if.d.ts +36 -0
  50. package/lib/table/formula/compile-formula.d.ts +86 -0
  51. package/lib/table/formula/evaluator.d.ts +19 -0
  52. package/lib/table/formula/formula-ast.if.d.ts +42 -0
  53. package/lib/table/formula/formula-error.d.ts +59 -0
  54. package/lib/table/formula/formula-options.if.d.ts +41 -0
  55. package/lib/table/formula/formula-values.d.ts +13 -0
  56. package/lib/table/formula/functions.d.ts +18 -0
  57. package/lib/table/formula/parser.d.ts +10 -0
  58. package/lib/table/formula/tokenizer.d.ts +22 -0
  59. package/lib/table/pivot/pivot-value.type.d.ts +13 -0
  60. package/lib/table/render-scope.d.ts +81 -0
  61. package/lib/table/renderer/edit/input-cell-renderer.d.ts +1 -1
  62. package/lib/table/renderer/edit/select-cell-renderer.d.ts +1 -1
  63. package/lib/table/row-drag/move-rows.d.ts +157 -0
  64. package/lib/table/row-drag/row-drag-options.d.ts +28 -0
  65. package/lib/table/row-drag/row-drag-options.if.d.ts +36 -0
  66. package/lib/table/row-drag/row-drag-service.d.ts +130 -0
  67. package/lib/table/row-drag/row-drop-target.if.d.ts +29 -0
  68. package/lib/table/service/excel-service.d.ts +6 -0
  69. package/lib/table/service/excel-service.if.d.ts +35 -0
  70. package/lib/table/table-api.d.ts +277 -2
  71. package/lib/table/table-scope.d.ts +121 -0
  72. package/package.json +1 -1
@@ -0,0 +1,36 @@
1
+ import { ValueGetterContextIf } from './value-getter-context.if.js';
2
+
3
+ /**
4
+ * Computes the value of a calculated column from the row (`ColumnDefIf.valueGetter`). The row is the data object
5
+ * (in a tree the `TreeRow.data`). The data is not changed – sorting, filter (`tableApi.getRowValue`), copy, Excel and
6
+ * totals use the computed value.
7
+ *
8
+ * Keep it fast and free of side effects: it runs for every visible cell on each render (values are not cached) and
9
+ * once per row for sorting and totals.
10
+ *
11
+ * @example
12
+ * const total: ValueGetter<Item> = row => row.price * row.quantity;
13
+ * ColumnDef.create({ property: "total", headerLabel: "Total", valueGetter: total });
14
+ *
15
+ * @typeParam T - the row type
16
+ * @since 1.1.95
17
+ * @category Calculated columns & formulas
18
+ */
19
+ export type ValueGetter<T = any> = (row: T, context: ValueGetterContextIf) => unknown;
20
+ /**
21
+ * Writes an edited value of a calculated column back into the row (`ColumnDefIf.valueSetter`). Without a setter a
22
+ * calculated column cannot be edited. Return `false` to reject the value.
23
+ *
24
+ * @example
25
+ * // "total" is price × quantity – editing the total changes the price
26
+ * const setTotal: ValueSetter<Item> = (row, value) => {
27
+ * const total = Number(value);
28
+ * if (!Number.isFinite(total) || !row.quantity) return false;
29
+ * row.price = total / row.quantity;
30
+ * };
31
+ *
32
+ * @typeParam T - the row type
33
+ * @since 1.1.95
34
+ * @category Calculated columns & formulas
35
+ */
36
+ export type ValueSetter<T = any> = (row: T, value: unknown) => boolean | void;
@@ -0,0 +1,46 @@
1
+ import { CellChangeIf } from '../../../batch-edit/cell-change.if.js';
2
+
3
+ /**
4
+ * What happened in a batch edit: `"start"` ({@link TableApi.startBatchEdit}), `"change"` (values were marked or a
5
+ * value was set back), `"commit"` (written), `"cancel"` (discarded).
6
+ *
7
+ * @category Fill handle & batch edit
8
+ * @since 1.1.96
9
+ */
10
+ export type GeBatchEditEventType = "start" | "change" | "commit" | "cancel";
11
+ /**
12
+ * Reported by {@link EventListenerIf.onBatchEditChanged}: the pending changes of a batch edit changed – e.g. to enable
13
+ * a "Save" button.
14
+ *
15
+ * @example
16
+ * const listener = new EventAdapter();
17
+ * listener.onBatchEditChanged = (evt: GeBatchEditEvent) => {
18
+ * saveButton.disabled = evt.pendingCount === 0 || evt.invalidCount > 0;
19
+ * discardButton.disabled = evt.pendingCount === 0;
20
+ * };
21
+ *
22
+ * @category Fill handle & batch edit
23
+ * @since 1.1.96
24
+ */
25
+ export declare class GeBatchEditEvent {
26
+ /** What happened. */
27
+ readonly type: GeBatchEditEventType;
28
+ /** The cells of this step (`"commit"`: the written cells, `"cancel"`: the discarded ones). */
29
+ readonly changes: CellChangeIf[];
30
+ /** The number of pending cells after this step. */
31
+ readonly pendingCount: number;
32
+ /** The number of pending cells with an invalid value. */
33
+ readonly invalidCount: number;
34
+ private readonly pendingProvider;
35
+ constructor(
36
+ /** What happened. */
37
+ type: GeBatchEditEventType,
38
+ /** The cells of this step (`"commit"`: the written cells, `"cancel"`: the discarded ones). */
39
+ changes: CellChangeIf[],
40
+ /** The number of pending cells after this step. */
41
+ pendingCount: number,
42
+ /** The number of pending cells with an invalid value. */
43
+ invalidCount: number, pendingProvider?: () => CellChangeIf[]);
44
+ /** All pending changes after this step (computed when read – it scans the shown rows once). */
45
+ get pendingChanges(): CellChangeIf[];
46
+ }
@@ -1,9 +1,13 @@
1
1
  import { GeCellIndices } from './ge-cell-indices.js';
2
+ import { CellChangeIf, CellChangeSource } from '../../../batch-edit/cell-change.if.js';
2
3
 
3
4
  /**
4
5
  * Reported by {@link EventListenerIf.onModelChanged} after cells were edited: the row and column indices
5
6
  * of the changed cells. The new values are already written into the area model.
6
7
  *
8
+ * Since 1.1.96 the event comes **once per change** – an edit, a fill (fill handle, Ctrl/⌘+D), a commit of a batch
9
+ * edit or {@link TableApi.applyCellChanges} – with all cells, and {@link changes} tells old and new values.
10
+ *
7
11
  * @example
8
12
  * override onModelChanged(evt: GeModelChangeEvent): void {
9
13
  * for (const { rowIndex } of evt.cells) {
@@ -19,6 +23,28 @@ import { GeCellIndices } from './ge-cell-indices.js';
19
23
  */
20
24
  export declare class GeModelChangeEvent {
21
25
  cells: GeCellIndices[];
22
- constructor(cells: GeCellIndices[]);
26
+ /**
27
+ * The changed cells with row object, property, old and new value (since 1.1.96; `undefined` for events created by
28
+ * own code with the old constructor).
29
+ */
30
+ changes?: CellChangeIf<any>[] | undefined;
31
+ /** What changed the cells: `"edit"`, `"fill"`, `"commit"` or `"api"` (since 1.1.96). */
32
+ source?: CellChangeSource | undefined;
33
+ constructor(cells: GeCellIndices[],
34
+ /**
35
+ * The changed cells with row object, property, old and new value (since 1.1.96; `undefined` for events created by
36
+ * own code with the old constructor).
37
+ */
38
+ changes?: CellChangeIf<any>[] | undefined,
39
+ /** What changed the cells: `"edit"`, `"fill"`, `"commit"` or `"api"` (since 1.1.96). */
40
+ source?: CellChangeSource | undefined);
41
+ /**
42
+ * An event for a change set (since 1.1.96): `cells` from the row and column indices of the changes.
43
+ *
44
+ * @param {CellChangeIf[]} changes - the changed cells
45
+ * @param {CellChangeSource} source - what changed them
46
+ * @returns {GeModelChangeEvent} the event
47
+ */
48
+ static createForChanges(changes: CellChangeIf[], source: CellChangeSource): GeModelChangeEvent;
23
49
  static createSingle(rowIndex: number, columnIndex: number): GeModelChangeEvent;
24
50
  }
@@ -0,0 +1,89 @@
1
+ import { RowDropTargetIf } from '../../../row-drag/row-drop-target.if.js';
2
+
3
+ /**
4
+ * Phase of a row drag: `"start"` (the pointer moved past the threshold, or a move key), `"move"` (the drop target
5
+ * changed), `"end"` (dropped) or `"cancel"` (Escape, `pointercancel`, `tableApi.cancelRowDrag()`, destroy).
6
+ *
7
+ * @category Row drag
8
+ * @since 1.1.95
9
+ */
10
+ export type GeRowDragEventType = "start" | "move" | "end" | "cancel";
11
+ /**
12
+ * What started the drag: the pointer (mouse, touch, pen) on a drag handle, or the keyboard
13
+ * (`MOVE_ROW_UP` / `MOVE_ROW_DOWN`, Ctrl+Alt+↑/↓).
14
+ *
15
+ * @category Row drag
16
+ * @since 1.1.95
17
+ */
18
+ export type GeRowDragSource = "pointer" | "keyboard";
19
+ /**
20
+ * A row drag ({@link EventListenerIf.onRowDragStart}, {@link EventListenerIf.onRowDragMove},
21
+ * {@link EventListenerIf.onRowDragEnd}).
22
+ *
23
+ * Call {@link preventDefault} to veto: in `"start"` no drag happens, in `"move"` the target is invalid (no drop
24
+ * marker, no drop). In managed mode `"end"` comes after the move (`moved`, `toIndex` = the real position).
25
+ *
26
+ * @example
27
+ * const listener = new EventAdapter();
28
+ * listener.onRowDragEnd = (evt: GeRowDragEvent<Order>) => {
29
+ * if (evt.moved) {
30
+ * const ids = evt.rows.map(order => order.id);
31
+ * void fetch("/api/orders/move", { method: "POST", body: JSON.stringify({ ids, toIndex: evt.toIndex }) });
32
+ * }
33
+ * };
34
+ *
35
+ * @category Row drag
36
+ * @since 1.1.95
37
+ */
38
+ export declare class GeRowDragEvent<T = any> {
39
+ /** Phase of the drag. */
40
+ readonly type: GeRowDragEventType;
41
+ /** Pointer or keyboard. */
42
+ readonly source: GeRowDragSource;
43
+ /** The dragged row objects (tree: the `TreeRow`s) in display order. */
44
+ readonly rows: T[];
45
+ /** Display indices of the dragged rows when the drag started (ascending). */
46
+ readonly rowIndices: number[];
47
+ /** The current drop target – `undefined` if there is none (invalid, vetoed, outside the table). */
48
+ readonly target: RowDropTargetIf | undefined;
49
+ /**
50
+ * Flat tables: display index of the first dragged row after the drop (`0` = first row), `-1` without target.
51
+ * Trees: `-1` before the move; in a managed `"end"` the index the row really got.
52
+ */
53
+ toIndex: number;
54
+ /** true if the pointer is outside the table – e.g. over an own drop zone of the page. */
55
+ readonly outside: boolean;
56
+ /** true if the table moves the rows itself ({@link RowDragOptionsIf.managed}). */
57
+ readonly managed: boolean;
58
+ /** The browser event behind this event (pointer or keyboard). */
59
+ readonly originalEvent?: PointerEvent | KeyboardEvent | undefined;
60
+ /** true if the moved rows changed in the table (managed mode, `"end"`, not prevented). */
61
+ moved: boolean;
62
+ private prevented;
63
+ constructor(
64
+ /** Phase of the drag. */
65
+ type: GeRowDragEventType,
66
+ /** Pointer or keyboard. */
67
+ source: GeRowDragSource,
68
+ /** The dragged row objects (tree: the `TreeRow`s) in display order. */
69
+ rows: T[],
70
+ /** Display indices of the dragged rows when the drag started (ascending). */
71
+ rowIndices: number[],
72
+ /** The current drop target – `undefined` if there is none (invalid, vetoed, outside the table). */
73
+ target: RowDropTargetIf | undefined,
74
+ /**
75
+ * Flat tables: display index of the first dragged row after the drop (`0` = first row), `-1` without target.
76
+ * Trees: `-1` before the move; in a managed `"end"` the index the row really got.
77
+ */
78
+ toIndex: number,
79
+ /** true if the pointer is outside the table – e.g. over an own drop zone of the page. */
80
+ outside: boolean,
81
+ /** true if the table moves the rows itself ({@link RowDragOptionsIf.managed}). */
82
+ managed: boolean,
83
+ /** The browser event behind this event (pointer or keyboard). */
84
+ originalEvent?: PointerEvent | KeyboardEvent | undefined);
85
+ /** true after {@link preventDefault}. */
86
+ get defaultPrevented(): boolean;
87
+ /** Veto: no drag (`"start"`), invalid target (`"move"`); no effect in `"end"` and `"cancel"`. */
88
+ preventDefault(): void;
89
+ }
@@ -12,6 +12,9 @@ import { ShortcutActionIdMapping } from '../../action/shortcut-actionid-mapping.
12
12
  import { HeaderGroupOptions } from './header-group-options.js';
13
13
  import { AriaTextsIf } from '../../aria/aria-texts.if.js';
14
14
  import { OverlayOptionsIf } from './overlay-options.if.js';
15
+ import { RowDragOptionsIf } from '../../row-drag/row-drag-options.if.js';
16
+ import { FillHandleOptionsIf } from '../../fill/fill-handle-options.if.js';
17
+ import { BatchEditOptionsIf } from '../../batch-edit/batch-edit-options.if.js';
15
18
 
16
19
  /**
17
20
  * All default options of a table – see {@link TableOptionsIf} for the meaning of each field.
@@ -80,4 +83,7 @@ export declare class TableOptions implements TableOptionsIf {
80
83
  ariaTexts?: Partial<AriaTextsIf>;
81
84
  /** Texts and behaviour of the "Loading…" / "No rows" overlays; missing fields use {@link OverlayOptions}. @since 1.1.92 */
82
85
  overlayOptions?: Partial<OverlayOptionsIf>;
86
+ rowDragOptions?: Partial<RowDragOptionsIf>;
87
+ fillHandle?: boolean | Partial<FillHandleOptionsIf>;
88
+ batchEdit?: boolean | Partial<BatchEditOptionsIf>;
83
89
  }
@@ -1,3 +1,6 @@
1
+ import { RowDragOptionsIf } from '../../row-drag/row-drag-options.if.js';
2
+ import { FillHandleOptionsIf } from '../../fill/fill-handle-options.if.js';
3
+ import { BatchEditOptionsIf } from '../../batch-edit/batch-edit-options.if.js';
1
4
  import { DefaultRowHeightsIf } from './default-row-heights.if.js';
2
5
  import { TreeOptionsIf } from './tree-options.if.js';
3
6
  import { FilterFunction } from '../common/filter-function.js';
@@ -317,6 +320,47 @@ export interface TableOptionsIf {
317
320
  * @since 1.1.92
318
321
  */
319
322
  overlayOptions?: Partial<OverlayOptionsIf>;
323
+ /**
324
+ * Row drag: managed or events only, multi-row drag, tree drop, auto-scroll (see {@link RowDragOptionsIf}). The drag
325
+ * handles come from {@link ColumnDefIf.rowDrag}. Fields you leave out keep their default ({@link RowDragOptions}).
326
+ *
327
+ * @example
328
+ * const tableOptions: TableOptionsIf = {
329
+ * ...new TableOptions(),
330
+ * rowDragOptions: { managed: false }, // only events – e.g. the server decides
331
+ * };
332
+ *
333
+ * @since 1.1.95
334
+ */
335
+ rowDragOptions?: Partial<RowDragOptionsIf>;
336
+ /**
337
+ * The fill handle: a small square at the bottom right corner of the selected range. Dragging it fills the
338
+ * neighbouring cells (copy, or a series: 1, 2, 3 …, dates, `Item 1` → `Item 2`); ⌥/Alt switches between series and
339
+ * copy. Keyboard: Ctrl/⌘+D fills down, Ctrl/⌘+R fills right. Needs a selection model of the type `"range"`;
340
+ * only editable cells are filled. `true` = defaults ({@link FillHandleOptions}).
341
+ *
342
+ * @example
343
+ * const selectionModel = new SelectionModel("range", "multi"); // one model – not a new one per call
344
+ * const tableOptions: TableOptionsIf = {
345
+ * ...new TableOptions(),
346
+ * getSelectionModel: () => selectionModel,
347
+ * fillHandle: true,
348
+ * };
349
+ *
350
+ * @since 1.1.96
351
+ */
352
+ fillHandle?: boolean | Partial<FillHandleOptionsIf>;
353
+ /**
354
+ * Batch edit always on: edited and filled values are collected (marked `ge-table-cell-pending`) and written with
355
+ * {@link TableApi.commitBatchEdit} or discarded with {@link TableApi.cancelBatchEdit}. Without it, start a batch
356
+ * edit with {@link TableApi.startBatchEdit} (it ends with commit or cancel).
357
+ *
358
+ * @example
359
+ * const tableOptions: TableOptionsIf = { ...new TableOptions(), batchEdit: true };
360
+ *
361
+ * @since 1.1.96
362
+ */
363
+ batchEdit?: boolean | Partial<BatchEditOptionsIf>;
320
364
  /**
321
365
  * The state the table starts with: column layout, sorting, tree, checked and selected rows … – e.g. loaded from
322
366
  * your server ({@link TableApi.getState}, {@link EventListenerIf.onStateChanged}). A state stored by
@@ -7,6 +7,7 @@ import { CheckboxModelIf } from '../../../checkbox/checkbox-model.if.js';
7
7
  import { FilterFunction } from '../../common/filter-function.js';
8
8
  import { SortItem } from '../../common/sort-item.js';
9
9
  import { HasDefaultRowHeightIf } from './has-default-row-height-if.js';
10
+ import { ColumnValues } from '../../../calc/column-values.js';
10
11
 
11
12
  /** @category Area models */
12
13
  export declare abstract class AbstractAreaModel<T> implements AreaModelIf, HasDefaultRowHeightIf {
@@ -14,6 +15,8 @@ export declare abstract class AbstractAreaModel<T> implements AreaModelIf, HasDe
14
15
  protected columnDefs: ColumnDefIf[];
15
16
  defaultRowHeight: number;
16
17
  rowSelectionModel: CheckboxModelIf<any> | undefined;
18
+ private columnValuesInstance?;
19
+ private calcTextRenderer?;
17
20
  protected cellRenderers: (CellRendererIf | undefined)[];
18
21
  protected yPositions: number[];
19
22
  constructor(areaIdent: AreaIdent, columnDefs?: ColumnDefIf[], defaultRowHeight?: number);
@@ -48,4 +51,67 @@ export declare abstract class AbstractAreaModel<T> implements AreaModelIf, HasDe
48
51
  protected setPropertyValue(o: any, props: string[], value: any): boolean;
49
52
  protected arrayMove(arr: any[], fromIndex: number, toIndex: number): any[];
50
53
  private calcYPositions;
54
+ /**
55
+ * True if a column of this model with this property is calculated (`valueGetter` or `formula`).
56
+ *
57
+ * @param {string} property - the property of the column
58
+ * @returns {boolean} whether its values are computed
59
+ *
60
+ * @example
61
+ * tableModel.getBodyModel().isCalculatedProperty?.("total"); // true
62
+ *
63
+ * @since 1.1.95
64
+ */
65
+ isCalculatedProperty(property: string): boolean;
66
+ /**
67
+ * The value of a column for a row object – the computed value of a calculated column, otherwise the property
68
+ * (path). A `TreeRow` is unwrapped. The table API offers it as {@link TableApi.getRowValue}.
69
+ *
70
+ * @param {any} row - a row object (or `TreeRow`)
71
+ * @param {string} property - the property of the column
72
+ * @returns {unknown} the value
73
+ *
74
+ * @example
75
+ * const body = tableModel.getBodyModel() as AreaModelObjectArray<Item>;
76
+ * body.getRowValue({ price: 25, quantity: 10 }, "total"); // 250
77
+ *
78
+ * @since 1.1.95
79
+ */
80
+ getRowValue(row: any, property: string): unknown;
81
+ /**
82
+ * True if the model has calculated or „Show values as“ columns – their cells depend on other cells
83
+ * (the table redraws them after `updateCells`).
84
+ *
85
+ * @returns {boolean} whether derived columns exist
86
+ * @since 1.1.95
87
+ */
88
+ hasDerivedColumns(): boolean;
89
+ /**
90
+ * True if the cells of a column depend on other cells (calculated or „Show values as“).
91
+ *
92
+ * @param {string} property - the property of the column
93
+ * @returns {boolean} whether the column is derived
94
+ * @since 1.1.95
95
+ */
96
+ isDerivedProperty(property: string): boolean;
97
+ /** The resolver of calculated values of this model (created on first use). @internal */
98
+ protected getColumnValues(): ColumnValues;
99
+ /** Drops the cached aggregates and the getter lookup of calculated columns. */
100
+ protected invalidateColumnValues(): void;
101
+ /** The value of a property path – overridden by the models with their own path semantics. */
102
+ protected readPropertyPath(row: any, property: string): unknown;
103
+ /** The rows of column aggregates in formulas (`SUM([total])`): the filtered row objects. */
104
+ protected getAggregationSourceForValues(): {
105
+ signal: unknown;
106
+ length: number;
107
+ rows: () => ArrayLike<unknown>;
108
+ };
109
+ /** Writes an edited value of a calculated column through its `valueSetter`; without one: rejected. */
110
+ protected setCalculatedValue(row: any, columnDef: ColumnDefIf, value: any): boolean;
111
+ /** The text of a cell of a calculated / „Show values as“ column; `undefined` for a normal column. */
112
+ protected getCalculatedText(property: string | undefined, value: unknown): string | undefined;
113
+ /** The renderer of a „Show values as“ column without an own renderer: the text of `getTextValueAt`. */
114
+ protected getCalculatedRenderer(property: string | undefined): CellRendererIf | undefined;
115
+ /** The CSS class and tooltip of an error value of a formula. */
116
+ protected addCalculatedClasses(classes: string[], property: string | undefined, value: () => unknown): string[];
51
117
  }
@@ -140,6 +140,11 @@ export declare class AreaModelAggregateFooter<T = any> extends AreaModel impleme
140
140
  * @internal
141
141
  */
142
142
  protected createIndexGetter(body: AreaModelIf, spec: ResolvedAggregateSpec<T>): ((rowIndex: number) => unknown) | undefined;
143
+ /**
144
+ * A spec whose value is the property of a calculated column of the body (`footerAggregates: { total: "sum" }` with
145
+ * `total` = `price * quantity`) sums the computed values, not the (missing) property of the row (since 1.1.95).
146
+ */
147
+ private withCalculatedValues;
143
148
  private compute;
144
149
  }
145
150
  export {};
@@ -2,6 +2,7 @@ import { AbstractAreaModel } from './abstract-area-model.js';
2
2
  import { AreaIdent } from '../area-ident.type.js';
3
3
  import { ColumnDefIf } from '../column/column-def.if.js';
4
4
  import { FilterFunction } from '../../common/filter-function.js';
5
+ import { RowDropTargetIf } from '../../../row-drag/row-drop-target.if.js';
5
6
 
6
7
  /**
7
8
  * Represents a model for an area containing a two-dimensional array of data.
@@ -25,6 +26,29 @@ export declare class AreaModelArrayOfArrays<T> extends AbstractAreaModel<T[][]>
25
26
  * @since 1.1.92
26
27
  */
27
28
  getUnfilteredRowCount(): number;
29
+ /**
30
+ * Row drag: true if the rows can be moved (no filter hides a row, target `"before"` / `"after"` a row).
31
+ *
32
+ * @param {number[]} rowIndices - display indices of the dragged rows
33
+ * @param {RowDropTargetIf} target - the drop target
34
+ * @returns {boolean} true if {@link moveRows} would move them
35
+ * @since 1.1.95
36
+ */
37
+ canMoveRows(rowIndices: number[], target: RowDropTargetIf): boolean;
38
+ /**
39
+ * Row drag: moves the rows – in place in the displayed rows and in {@link arr}.
40
+ *
41
+ * @param {number[]} rowIndices - display indices of the dragged rows
42
+ * @param {RowDropTargetIf} target - the drop target (display index before the move)
43
+ * @returns {boolean} true if moved
44
+ *
45
+ * @example
46
+ * const model = new AreaModelArrayOfArrays("body", [["a"], ["b"], ["c"]], 30);
47
+ * model.moveRows([0], { rowIndex: 2, position: "after" }); // b, c, a
48
+ *
49
+ * @since 1.1.95
50
+ */
51
+ moveRows(rowIndices: number[], target: RowDropTargetIf): boolean;
28
52
  getValueAt(rowIndex: number, columnIndex: number): any;
29
53
  setValue(rowIndex: number, columnIndex: number, value: any): boolean;
30
54
  getRowByIndex(rowIndex: number): any;
@@ -5,6 +5,10 @@ import { FilterFunction } from '../../common/filter-function.js';
5
5
  import { SorterService } from '../../../service/sorter.service.js';
6
6
  import { SortItem } from '../../common/sort-item.js';
7
7
  import { ObjectArrayHolderIf } from './object-array-holder.if.js';
8
+ import { CellRendererIf } from '../../../renderer/cell-render.if.js';
9
+ import { DerivedValuesChangeIf } from './derived-values-change.if.js';
10
+ import { ShowValuesAsIf } from '../../../calc/show-values-as.type.js';
11
+ import { RowDropTargetIf } from '../../../row-drag/row-drop-target.if.js';
8
12
 
9
13
  /**
10
14
  * @class AreaModelObjectArray
@@ -171,6 +175,8 @@ export declare class AreaModelObjectArray<T> extends AbstractAreaModel<T> implem
171
175
  * @internal
172
176
  */
173
177
  protected sorterService: SorterService;
178
+ /** Cached „Show values as“ values per property (cleared on filter, sorting and invalidation). */
179
+ private showValuesCache;
174
180
  /**
175
181
  * Creates an instance of AreaModelObjectArray.
176
182
  *
@@ -280,6 +286,36 @@ export declare class AreaModelObjectArray<T> extends AbstractAreaModel<T> implem
280
286
  * @since 1.1.92
281
287
  */
282
288
  getUnfilteredRowCount(): number;
289
+ /**
290
+ * Row drag: true if the rows can be moved – no filter hides a row and the target is a row of this model
291
+ * (`"before"` / `"after"`).
292
+ *
293
+ * @param {number[]} rowIndices - display indices of the dragged rows
294
+ * @param {RowDropTargetIf} target - the drop target
295
+ * @returns {boolean} true if {@link moveRows} would move them
296
+ *
297
+ * @example
298
+ * bodyAreaModel.canMoveRows([2], { rowIndex: 6, position: "after" }); // true without a filter
299
+ *
300
+ * @since 1.1.95
301
+ */
302
+ canMoveRows(rowIndices: number[], target: RowDropTargetIf): boolean;
303
+ /**
304
+ * Row drag: moves the rows in the display order and writes that order back to {@link getAllRows} – **in place**
305
+ * (like `Array.prototype.sort`: with `TableFactory.createTableModel({ rows })` your array has the new order).
306
+ * Works only without a hiding filter ({@link canMoveRows}). The table repaints after a drop; from code use
307
+ * `tableApi.moveRows()`.
308
+ *
309
+ * @param {number[]} rowIndices - display indices of the dragged rows
310
+ * @param {RowDropTargetIf} target - the drop target (display index before the move)
311
+ * @returns {boolean} true if moved
312
+ *
313
+ * @example
314
+ * bodyAreaModel.moveRows([2], { rowIndex: 6, position: "after" }); // row 3 becomes row 7
315
+ *
316
+ * @since 1.1.95
317
+ */
318
+ moveRows(rowIndices: number[], target: RowDropTargetIf): boolean;
283
319
  /**
284
320
  * Gets the value at the specified row and column indices.
285
321
  * This method handles tree rows and nested properties.
@@ -302,6 +338,35 @@ export declare class AreaModelObjectArray<T> extends AbstractAreaModel<T> implem
302
338
  * }
303
339
  */
304
340
  getValueAt(rowIndex: number, columnIndex: number): any;
341
+ /**
342
+ * The text of a cell: for a „Show values as“ column the formatted value (`"66.7%"`), for a formula error its code;
343
+ * otherwise like before (`'' + value`).
344
+ *
345
+ * @param {number} rowIndex - the row
346
+ * @param {number} columnIndex - the column
347
+ * @returns {string} the text
348
+ */
349
+ getTextValueAt(rowIndex: number, columnIndex: number): string;
350
+ /** A „Show values as“ column without an own body renderer shows the formatted text. */
351
+ getCellRenderer(rowIndex: number, columnIndex: number): CellRendererIf | undefined;
352
+ /** The message of a formula error as tooltip. */
353
+ getTooltipAt(rowIndex: number, columnIndex: number): any;
354
+ /**
355
+ * Drops derived values: cached aggregates of formulas and „Show values as“ (called by the table on filter,
356
+ * sorting, editing, `updateCells` and `api.repaint()`).
357
+ *
358
+ * @param {DerivedValuesChangeIf} [_change] - the changed rows (not used)
359
+ * @since 1.1.95
360
+ */
361
+ invalidateDerivedValues(_change?: DerivedValuesChangeIf): void;
362
+ /** „Show values as“ of one cell; the reference are the filtered rows in display order. */
363
+ protected applyShowValuesAs(rowIndex: number, property: string, value: unknown, options: ShowValuesAsIf): unknown;
364
+ protected readPropertyPath(t: any, property: string): unknown;
365
+ protected getAggregationSourceForValues(): {
366
+ signal: unknown;
367
+ length: number;
368
+ rows: () => ArrayLike<unknown>;
369
+ };
305
370
  /**
306
371
  * Retrieves the filtered and sorted rows from the dataset.
307
372
  * These rows are used for rendering the table.
@@ -565,6 +630,11 @@ export declare class AreaModelObjectArray<T> extends AbstractAreaModel<T> implem
565
630
  * const sortedRows = [...this.getFilteredRows()].sort(comparator);
566
631
  */
567
632
  protected genericFlatTableSortComparator(property: string, f: number): (a: T, b: T) => number;
633
+ /**
634
+ * The value of a row for a sort pass: a calculated column is computed once per row (memo for this pass, not
635
+ * 2·n·log n times); formula errors sort last (as `undefined`).
636
+ */
637
+ protected createSortValueReader(property: string): (row: T) => unknown;
568
638
  /**
569
639
  * Recursively gets a value from an object using an array of property names.
570
640
  * This is a helper method used by `getValueByT` to access nested properties.
@@ -1,4 +1,5 @@
1
1
  import { AreaModelTree } from './area-model-tree.js';
2
+ import { RowDropTargetIf } from '../../../row-drag/row-drop-target.if.js';
2
3
  import { ColumnDefIf } from '../column/column-def.if.js';
3
4
  import { CellRendererIf } from '../../../renderer/cell-render.if.js';
4
5
  import { FilterFunction } from '../../common/filter-function.js';
@@ -179,6 +180,36 @@ export declare class AreaModelPivot<T = any> extends AreaModelTree<any> {
179
180
  */
180
181
  getCellSourceRows(rowIndex: number, columnIndex: number): T[];
181
182
  getValueAt(rowIndex: number, columnIndex: number): any;
183
+ /**
184
+ * The value of a pivot cell as shown: the aggregate, or with „Show values as“ ({@link PivotValueIf.showValuesAs})
185
+ * its share of the row total, column total, grand total or parent row.
186
+ *
187
+ * @param {RowGroupIf<T> | undefined} group - the row group; `undefined` = all rows (the total row)
188
+ * @param {PivotColumnInfoIf} info - the column ({@link getColumnInfo})
189
+ * @returns {unknown} the shown value, `undefined` for an empty cell
190
+ *
191
+ * @example
192
+ * const body = (tableModel as PivotTableModel).getPivotBody();
193
+ * body.getShownValue(body.getRowGroup(0), body.getColumnInfo(2)!); // 0.4 – 40 % of the row
194
+ *
195
+ * @since 1.1.95
196
+ */
197
+ getShownValue(group: RowGroupIf<T> | undefined, info: PivotColumnInfoIf): unknown;
198
+ /**
199
+ * Row drag: `false` – the table does not move rows of a pivot table itself (pivot rows are aggregates). With
200
+ * `rowDragOptions.managed: false` the app gets the events and decides.
201
+ *
202
+ * @returns {boolean} always false
203
+ * @since 1.1.95
204
+ */
205
+ canMoveRows(_rowIndices: number[], _target: RowDropTargetIf): boolean;
206
+ /**
207
+ * Row drag: does nothing (see {@link canMoveRows}).
208
+ *
209
+ * @returns {boolean} always false
210
+ * @since 1.1.95
211
+ */
212
+ moveRows(_rowIndices: number[], _target: RowDropTargetIf): boolean;
182
213
  getTextValueAt(rowIndex: number, columnIndex: number): string;
183
214
  /** Value columns: the {@link AggregateCellRenderer} (text node); the group column: none (label as text). */
184
215
  getCellRenderer(_rowIndex: number, columnIndex: number): CellRendererIf | undefined;
@@ -1,4 +1,6 @@
1
1
  import { AreaModelTree } from './area-model-tree.js';
2
+ import { RowDropTargetIf } from '../../../row-drag/row-drop-target.if.js';
3
+ import { TreeRowIf } from '../../common/tree-row-if.js';
2
4
  import { ColumnDefIf } from '../column/column-def.if.js';
3
5
  import { CellRendererIf } from '../../../renderer/cell-render.if.js';
4
6
  import { FilterFunction } from '../../common/filter-function.js';
@@ -230,7 +232,23 @@ export declare class AreaModelRowGroups<T = any> extends AreaModelTree<any> {
230
232
  * });
231
233
  */
232
234
  batch(fn: () => void): boolean;
233
- getValueAt(rowIndex: number, columnIndex: number): any;
235
+ /** Group rows: the label resp. the aggregate of the column; detail rows: the value of the row (calculated or path). */
236
+ protected getRawValueOfRow(row: TreeRowIf<any>, property: string): any;
237
+ /**
238
+ * Row drag: `false` – the table does not move rows of a grouped table itself (group rows are built from the data, a change of group means changing data). With
239
+ * `rowDragOptions.managed: false` the app gets the events and decides.
240
+ *
241
+ * @returns {boolean} always false
242
+ * @since 1.1.95
243
+ */
244
+ canMoveRows(_rowIndices: number[], _target: RowDropTargetIf): boolean;
245
+ /**
246
+ * Row drag: does nothing (see {@link canMoveRows}).
247
+ *
248
+ * @returns {boolean} always false
249
+ * @since 1.1.95
250
+ */
251
+ moveRows(_rowIndices: number[], _target: RowDropTargetIf): boolean;
234
252
  getTextValueAt(rowIndex: number, columnIndex: number): string;
235
253
  /** Group rows: the {@link AggregateCellRenderer} for aggregates, no renderer otherwise; detail rows: the column's. */
236
254
  getCellRenderer(rowIndex: number, columnIndex: number): CellRendererIf | undefined;
@@ -295,6 +313,10 @@ export declare class AreaModelRowGroups<T = any> extends AreaModelTree<any> {
295
313
  */
296
314
  invalidateDerivedValues(change?: DerivedValuesChangeIf): void;
297
315
  /** After sorting the tree rows: the groups (`getGroups()`, `children`) in display order. */
316
+ /** An aggregate over a calculated column (key or value = its property) uses the computed value. */
317
+ private withCalculatedValue;
318
+ /** A grouping level on a calculated column groups by the computed value. */
319
+ private withCalculatedKeys;
298
320
  private syncGroupOrder;
299
321
  /** The label of a group row in the group column. */
300
322
  protected getGroupLabel(group: RowGroup<T>): string;