@guiexpert/table 1.1.94 → 1.1.97

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 (85) hide show
  1. package/README.md +16 -0
  2. package/css/main.css +299 -0
  3. package/css/table-calc.css +7 -0
  4. package/css/table-color-vars.css +58 -0
  5. package/css/table-fill-batch.css +58 -0
  6. package/css/table-master-detail.css +95 -0
  7. package/css/table-row-drag.css +81 -0
  8. package/index.cjs +37 -35
  9. package/index.d.ts +34 -0
  10. package/index.js +9749 -5000
  11. package/lib/table/action/action-id.type.d.ts +1 -1
  12. package/lib/table/aria/aria-ids.d.ts +7 -0
  13. package/lib/table/aria/aria-texts.d.ts +13 -0
  14. package/lib/table/aria/aria-texts.if.d.ts +101 -0
  15. package/lib/table/batch-edit/batch-edit-options.d.ts +21 -0
  16. package/lib/table/batch-edit/batch-edit-options.if.d.ts +20 -0
  17. package/lib/table/batch-edit/batch-edit-service.d.ts +104 -0
  18. package/lib/table/batch-edit/cell-change.if.d.ts +39 -0
  19. package/lib/table/batch-edit/cell-value-change.if.d.ts +18 -0
  20. package/lib/table/batch-edit/pending-cell-changes.d.ts +104 -0
  21. package/lib/table/calc/column-values.d.ts +55 -0
  22. package/lib/table/calc/show-values-as-internals.d.ts +4 -0
  23. package/lib/table/calc/show-values-as.d.ts +87 -0
  24. package/lib/table/calc/show-values-as.type.d.ts +55 -0
  25. package/lib/table/calc/value-getter-context.if.d.ts +35 -0
  26. package/lib/table/calc/value-getter.type.d.ts +36 -0
  27. package/lib/table/data/common/event/ge-batch-edit-event.d.ts +46 -0
  28. package/lib/table/data/common/event/ge-detail-event.d.ts +40 -0
  29. package/lib/table/data/common/event/ge-model-change-event.d.ts +27 -1
  30. package/lib/table/data/common/event/ge-row-drag-event.d.ts +89 -0
  31. package/lib/table/data/options/auto-restore-options.d.ts +2 -0
  32. package/lib/table/data/options/auto-restore-options.if.d.ts +6 -0
  33. package/lib/table/data/options/table-options.d.ts +8 -0
  34. package/lib/table/data/options/table-options.if.d.ts +62 -0
  35. package/lib/table/data/tablemodel/areamodel/abstract-area-model.d.ts +66 -0
  36. package/lib/table/data/tablemodel/areamodel/area-model-aggregate-footer.d.ts +5 -0
  37. package/lib/table/data/tablemodel/areamodel/area-model-array-of-arrays.d.ts +24 -0
  38. package/lib/table/data/tablemodel/areamodel/area-model-object-array.d.ts +70 -0
  39. package/lib/table/data/tablemodel/areamodel/area-model-pivot.d.ts +31 -0
  40. package/lib/table/data/tablemodel/areamodel/area-model-row-groups.d.ts +23 -1
  41. package/lib/table/data/tablemodel/areamodel/area-model-tree.d.ts +83 -0
  42. package/lib/table/data/tablemodel/areamodel/area-model.if.d.ts +55 -0
  43. package/lib/table/data/tablemodel/column/column-def.d.ts +31 -1
  44. package/lib/table/data/tablemodel/column/column-def.if.d.ts +86 -0
  45. package/lib/table/ele-scope.d.ts +14 -0
  46. package/lib/table/event-adapter.d.ts +10 -0
  47. package/lib/table/event-listener.if.d.ts +39 -0
  48. package/lib/table/factory/table-factory.d.ts +11 -0
  49. package/lib/table/fill/compute-fill-changes.d.ts +67 -0
  50. package/lib/table/fill/fill-direction.type.d.ts +7 -0
  51. package/lib/table/fill/fill-handle-options.d.ts +29 -0
  52. package/lib/table/fill/fill-handle-options.if.d.ts +35 -0
  53. package/lib/table/fill/fill-handle-service.d.ts +55 -0
  54. package/lib/table/fill/fill-series.d.ts +60 -0
  55. package/lib/table/fill/fill-value-context.if.d.ts +36 -0
  56. package/lib/table/formula/compile-formula.d.ts +86 -0
  57. package/lib/table/formula/evaluator.d.ts +19 -0
  58. package/lib/table/formula/formula-ast.if.d.ts +42 -0
  59. package/lib/table/formula/formula-error.d.ts +59 -0
  60. package/lib/table/formula/formula-options.if.d.ts +41 -0
  61. package/lib/table/formula/formula-values.d.ts +13 -0
  62. package/lib/table/formula/functions.d.ts +18 -0
  63. package/lib/table/formula/parser.d.ts +10 -0
  64. package/lib/table/formula/tokenizer.d.ts +22 -0
  65. package/lib/table/master-detail/detail-renderer.if.d.ts +99 -0
  66. package/lib/table/master-detail/master-detail-options.d.ts +30 -0
  67. package/lib/table/master-detail/master-detail-options.if.d.ts +60 -0
  68. package/lib/table/master-detail/master-detail-service.d.ts +223 -0
  69. package/lib/table/pivot/pivot-value.type.d.ts +13 -0
  70. package/lib/table/render-scope.d.ts +154 -0
  71. package/lib/table/renderer/edit/input-cell-renderer.d.ts +1 -1
  72. package/lib/table/renderer/edit/select-cell-renderer.d.ts +1 -1
  73. package/lib/table/row-drag/move-rows.d.ts +157 -0
  74. package/lib/table/row-drag/row-drag-options.d.ts +28 -0
  75. package/lib/table/row-drag/row-drag-options.if.d.ts +36 -0
  76. package/lib/table/row-drag/row-drag-service.d.ts +130 -0
  77. package/lib/table/row-drag/row-drop-target.if.d.ts +29 -0
  78. package/lib/table/row-layout/row-layout.d.ts +120 -0
  79. package/lib/table/service/excel-service.d.ts +6 -0
  80. package/lib/table/service/excel-service.if.d.ts +35 -0
  81. package/lib/table/state/table-state.if.d.ts +4 -1
  82. package/lib/table/state/table-state.service.d.ts +4 -0
  83. package/lib/table/table-api.d.ts +378 -2
  84. package/lib/table/table-scope.d.ts +185 -0
  85. package/package.json +1 -1
@@ -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;
@@ -6,6 +6,10 @@ import { FilterFunction } from '../../common/filter-function.js';
6
6
  import { SorterService } from '../../../service/sorter.service.js';
7
7
  import { SortItem } from '../../common/sort-item.js';
8
8
  import { TreeRowIf } from '../../common/tree-row-if.js';
9
+ import { CellRendererIf } from '../../../renderer/cell-render.if.js';
10
+ import { DerivedValuesChangeIf } from './derived-values-change.if.js';
11
+ import { ShowValuesAsIf } from '../../../calc/show-values-as.type.js';
12
+ import { RowDropTargetIf } from '../../../row-drag/row-drop-target.if.js';
9
13
 
10
14
  /**
11
15
  * Represents a tree-based table model.
@@ -57,6 +61,8 @@ export declare class AreaModelTree<S> extends AbstractAreaModel<TreeRow<S>> {
57
61
  private lastPredictFn?;
58
62
  /** `row.keep` was set for the current filter (it depends on the filter and the data, not on expand/collapse). */
59
63
  private keepMarked;
64
+ /** „Show values as“: shown value per row and property (cleared on filter, sorting and invalidation). */
65
+ private showValuesCache;
60
66
  constructor(areaIdent: AreaIdent, rows: TreeRowIf<S>[], defaultRowHeight: number, columnDefs?: ColumnDefIf[]);
61
67
  changeColumnOrder(sourceColumnIndex: number, targetColumnIndex: number): void;
62
68
  /**
@@ -136,7 +142,84 @@ export declare class AreaModelTree<S> extends AbstractAreaModel<TreeRow<S>> {
136
142
  * @since 1.1.92
137
143
  */
138
144
  getUnfilteredRowCount(): number;
145
+ /**
146
+ * Row drag: true if the rows can be moved to the target – no filter hides a displayed row, and the target is none of
147
+ * the dragged rows and no descendant of them (no cycle). `"before"` / `"after"` = sibling of the target row,
148
+ * `"inside"` = last child.
149
+ *
150
+ * @param {number[]} rowIndices - display indices of the dragged rows
151
+ * @param {RowDropTargetIf} target - the drop target
152
+ * @returns {boolean} true if {@link moveRows} would move them
153
+ *
154
+ * @example
155
+ * const treeModel = tableModel.getBodyModel() as AreaModelTree<OrderNode>;
156
+ * treeModel.canMoveRows([0], { rowIndex: 1, position: "inside" }); // false if row 1 is a child of row 0
157
+ *
158
+ * @since 1.1.95
159
+ */
160
+ canMoveRows(rowIndices: number[], target: RowDropTargetIf): boolean;
161
+ /**
162
+ * Row drag: moves tree rows (with their children) in front of / behind the target row (siblings) or into it
163
+ * (`"inside"`: last children, the target is expanded) – in place in {@link rows} and the `children` arrays;
164
+ * `parent` and `deep` follow. See {@link canMoveRows}.
165
+ *
166
+ * @param {number[]} rowIndices - display indices of the dragged rows
167
+ * @param {RowDropTargetIf} target - the drop target (display index before the move)
168
+ * @returns {boolean} true if moved
169
+ *
170
+ * @example
171
+ * const treeModel = tableModel.getBodyModel() as AreaModelTree<OrderNode>;
172
+ * treeModel.moveRows([3], { rowIndex: 0, position: "inside" });
173
+ * tableApi.repaintHard(); // or simply tableApi.moveRows([3], { rowIndex: 0, position: "inside" })
174
+ *
175
+ * @since 1.1.95
176
+ */
177
+ moveRows(rowIndices: number[], target: RowDropTargetIf): boolean;
178
+ /** The topmost tree rows of the display indices (children travel with their parent). */
179
+ private getDragRows;
139
180
  getValueAt(rowIndex: number, columnIndex: number): any;
181
+ /**
182
+ * The value of a tree row for a property – before „Show values as“: the computed value of a calculated column,
183
+ * otherwise the property (path) of `row.data`. Subclasses (row groups) return their aggregates for group rows.
184
+ *
185
+ * @param {TreeRowIf<S>} row - the tree row
186
+ * @param {string} prop - the property of the column
187
+ * @returns {any} the raw value
188
+ * @since 1.1.95
189
+ */
190
+ protected getRawValueOfRow(row: TreeRowIf<S>, prop: string): any;
191
+ /**
192
+ * The text of a cell: for a „Show values as“ column the formatted value (`"66.7%"`), for a formula error its code;
193
+ * otherwise like before (`'' + value`).
194
+ *
195
+ * @param {number} rowIndex - the row
196
+ * @param {number} columnIndex - the column
197
+ * @returns {string} the text
198
+ */
199
+ getTextValueAt(rowIndex: number, columnIndex: number): string;
200
+ /** A „Show values as“ column without an own body renderer shows the formatted text. */
201
+ getCellRenderer(rowIndex: number, columnIndex: number): CellRendererIf | undefined;
202
+ /** The message of a formula error as tooltip. */
203
+ getTooltipAt(rowIndex: number, columnIndex: number): any;
204
+ /**
205
+ * Drops derived values: cached aggregates of formulas and „Show values as“ (called by the table on filter,
206
+ * sorting, editing, `updateCells` and `api.repaint()`).
207
+ *
208
+ * @param {DerivedValuesChangeIf} [_change] - the changed rows (not used here)
209
+ * @since 1.1.95
210
+ */
211
+ invalidateDerivedValues(_change?: DerivedValuesChangeIf): void;
212
+ /**
213
+ * „Show values as“ of one tree row: percentages of the column total relate to the (filtered) leaf rows,
214
+ * `percentOfParentTotal`, `runningTotal`, `differenceFromPrevious` and `rank` to the displayed siblings.
215
+ */
216
+ protected applyShowValuesAs(row: TreeRowIf<S>, property: string, value: unknown, options: ShowValuesAsIf): unknown;
217
+ protected readPropertyPath(t: any, property: string): unknown;
218
+ protected getAggregationSourceForValues(): {
219
+ signal: unknown;
220
+ length: number;
221
+ rows: () => ArrayLike<unknown>;
222
+ };
140
223
  getRowHeight(_rowIndex: number): number;
141
224
  /**
142
225
  * All rows share `defaultRowHeight` – unless a subclass overrides `getRowHeight()`, then row heights may
@@ -1,3 +1,4 @@
1
+ import { RowDropTargetIf } from '../../../row-drag/row-drop-target.if.js';
1
2
  import { DerivedValuesChangeIf } from './derived-values-change.if.js';
2
3
  import { CellRendererIf } from '../../../renderer/cell-render.if.js';
3
4
  import { CheckedType } from '../../common/checked-type.js';
@@ -281,6 +282,40 @@ export interface AreaModelIf {
281
282
  * @since 1.1.92
282
283
  */
283
284
  getUnfilteredRowCount?(): number;
285
+ /**
286
+ * Optional (row drag, managed mode): true if the rows can be moved to the target – e.g. false for a node dropped
287
+ * into its own child, or while a filter hides rows. Without {@link moveRows} the table cannot move rows itself.
288
+ *
289
+ * @param {number[]} rowIndices - display indices of the dragged rows (ascending)
290
+ * @param {RowDropTargetIf} target - the drop target (display index before the move)
291
+ * @returns {boolean} true if {@link moveRows} would move them
292
+ *
293
+ * @example
294
+ * class TasksBodyModel extends AreaModel {
295
+ * tasks: string[] = ["Write", "Test", "Ship"];
296
+ * override getRowCount(): number { return this.tasks.length; }
297
+ * override getValueAt(rowIndex: number): any { return this.tasks[rowIndex]; }
298
+ * canMoveRows(rowIndices: number[], target: RowDropTargetIf): boolean { return target.position !== "inside"; }
299
+ * moveRows(rowIndices: number[], target: RowDropTargetIf): boolean {
300
+ * return moveArrayItems(this.tasks, rowIndices, getInsertBeforeIndex(target)) > -1;
301
+ * }
302
+ * }
303
+ *
304
+ * @since 1.1.95
305
+ */
306
+ canMoveRows?(rowIndices: number[], target: RowDropTargetIf): boolean;
307
+ /**
308
+ * Optional (row drag, managed mode): moves the rows to the target in the model – the table calls it on a drop and
309
+ * for `tableApi.moveRows()`, then repaints. Implemented by `AreaModelObjectArray`, `AreaModelArrayOfArrays` and
310
+ * `AreaModelTree` (in place in their row arrays). See {@link canMoveRows} for an example.
311
+ *
312
+ * @param {number[]} rowIndices - display indices of the dragged rows (ascending)
313
+ * @param {RowDropTargetIf} target - the drop target (display index before the move)
314
+ * @returns {boolean} true if the rows were moved
315
+ *
316
+ * @since 1.1.95
317
+ */
318
+ moveRows?(rowIndices: number[], target: RowDropTargetIf): boolean;
284
319
  /**
285
320
  * Optional: drops cached, derived values (e.g. the totals of an {@link AreaModelAggregateFooter}). The table calls
286
321
  * it for all three areas when data may have changed: filter, sorting, editing, `updateCells()` and the public
@@ -319,6 +354,26 @@ export interface AreaModelIf {
319
354
  * @since 1.1.94
320
355
  */
321
356
  isRowHeaderCell?(rowIndex: number, columnIndex: number): boolean;
357
+ /**
358
+ * Optional: true if the column with this property is calculated (`ColumnDefIf.valueGetter` / `formula`).
359
+ * Implemented by the object-array, tree, row-group and pivot models.
360
+ *
361
+ * @example
362
+ * tableModel.getBodyModel().isCalculatedProperty?.("total"); // true
363
+ *
364
+ * @since 1.1.95
365
+ */
366
+ isCalculatedProperty?(property: string): boolean;
367
+ /**
368
+ * Optional: the value of a column for a row object – computed for a calculated column, otherwise the property
369
+ * path ({@link TableApi.getRowValue}). Implemented by the object-array, tree, row-group and pivot models.
370
+ *
371
+ * @example
372
+ * tableModel.getBodyModel().getRowValue?.({ price: 25, quantity: 10 }, "total"); // 250
373
+ *
374
+ * @since 1.1.95
375
+ */
376
+ getRowValue?(row: any, property: string): unknown;
322
377
  /**
323
378
  * Returns the value of the cell at the specified row and column indices.
324
379
  * This is one of the most important methods in the area model, as it provides
@@ -1,5 +1,5 @@
1
1
  import { SizeIf } from '../../common/size.if.js';
2
- import { ColumnDefIf, ValueRowSortComparator } from './column-def.if.js';
2
+ import { CellValidator, ColumnDefIf, RowDragColumnOption, ValueRowSortComparator } from './column-def.if.js';
3
3
  import { CellRendererIf } from '../../../renderer/cell-render.if.js';
4
4
  import { AreaObjectMapType } from '../../common/area-map.type.js';
5
5
  import { AreaObjectMap } from '../../common/area-map.js';
@@ -7,6 +7,9 @@ import { BooleanFunction } from '../../common/boolean-function.js';
7
7
  import { SortState } from '../../common/sort-state.type.js';
8
8
  import { GetEditRenderer } from '../../../renderer/edit/edit-cell-renderer.type.js';
9
9
  import { editInputPipe } from '../../../renderer/edit/edit-input-pipe.if.js';
10
+ import { ValueGetter, ValueSetter } from '../../../calc/value-getter.type.js';
11
+ import { ShowValuesAsConfig } from '../../../calc/show-values-as.type.js';
12
+ import { FormulaOptionsIf } from '../../../formula/formula-options.if.js';
10
13
 
11
14
  /**
12
15
  * The column definition – see {@link ColumnDefIf} for all fields.
@@ -52,6 +55,17 @@ export declare class ColumnDef implements ColumnDefIf {
52
55
  editInputPipe?: editInputPipe | undefined;
53
56
  isVisible: BooleanFunction;
54
57
  visible: boolean;
58
+ /** A calculated column, see {@link ColumnDefIf.valueGetter}. */
59
+ valueGetter?: ValueGetter;
60
+ /** Writes an edited calculated value back, see {@link ColumnDefIf.valueSetter}. */
61
+ valueSetter?: ValueSetter;
62
+ /** „Show values as“, see {@link ColumnDefIf.showValuesAs}. */
63
+ showValuesAs?: ShowValuesAsConfig;
64
+ /** The formula of a formula column, see {@link ColumnDefIf.formula}. */
65
+ formula?: string;
66
+ rowDrag?: RowDragColumnOption;
67
+ /** Checks edited values, see {@link ColumnDefIf.validate} (since 1.1.96). */
68
+ validate?: CellValidator;
55
69
  constructor(property: string, headerLabel: string, width?: SizeIf, classes?: AreaObjectMapType<string[]>, rendererMap?: AreaObjectMapType<CellRendererIf>, minWidth?: SizeIf, maxWidth?: SizeIf, sortable?: BooleanFunction | undefined, sortComparator?: ValueRowSortComparator | undefined, sortState?: SortState | undefined, sortStatesOrder?: SortState[] | undefined, sortIconVisible?: BooleanFunction | undefined, editable?: BooleanFunction | undefined, getEditRenderer?: GetEditRenderer | undefined, editInputPipe?: editInputPipe | undefined, isVisible?: BooleanFunction);
56
70
  static bodyRenderer(bodyRenderer: CellRendererIf): AreaObjectMap<CellRendererIf>;
57
71
  /**
@@ -109,5 +123,21 @@ export declare class ColumnDef implements ColumnDefIf {
109
123
  getEditRenderer?: GetEditRenderer;
110
124
  /** Converts the editor text before it is stored, e.g. `editInputPipeForNumber`. */
111
125
  editInputPipe?: editInputPipe;
126
+ /** A calculated column: `(row, context) => value` (since 1.1.95). */
127
+ valueGetter?: ValueGetter;
128
+ /** Makes a calculated column editable (since 1.1.95). */
129
+ valueSetter?: ValueSetter;
130
+ /** „Show values as“: `"percentOfColumnTotal"`, `"rank"` … (since 1.1.95). */
131
+ showValuesAs?: ShowValuesAsConfig;
132
+ /**
133
+ * A formula column, e.g. `"[price] * [quantity] * 1.19"` – compiled once into the `valueGetter` (since 1.1.95,
134
+ * see {@link compileFormula}). Takes precedence over `valueGetter`.
135
+ */
136
+ formula?: string;
137
+ /** Own functions of the formula (since 1.1.95). */
138
+ formulaOptions?: FormulaOptionsIf;
139
+ rowDrag?: RowDragColumnOption;
140
+ /** Checks edited values: a message for an invalid value (since 1.1.96). */
141
+ validate?: CellValidator;
112
142
  }): ColumnDefIf;
113
143
  }
@@ -5,6 +5,8 @@ import { BooleanFunction } from '../../common/boolean-function.js';
5
5
  import { SortState } from '../../common/sort-state.type.js';
6
6
  import { GetEditRenderer } from '../../../renderer/edit/edit-cell-renderer.type.js';
7
7
  import { editInputPipe } from '../../../renderer/edit/edit-input-pipe.if.js';
8
+ import { ValueGetter, ValueSetter } from '../../../calc/value-getter.type.js';
9
+ import { ShowValuesAsConfig } from '../../../calc/show-values-as.type.js';
8
10
 
9
11
  /**
10
12
  * Represents a function that compares two values for sorting purposes.
@@ -116,4 +118,88 @@ export interface ColumnDefIf {
116
118
  getEditRenderer?: GetEditRenderer;
117
119
  /** Converts the text of the editor before it is written into the model, e.g. {@link editInputPipeForNumber}. */
118
120
  editInputPipe?: editInputPipe;
121
+ /**
122
+ * A calculated column: computes the value from the row instead of reading `property` (the data stays unchanged).
123
+ * Sorting, filter ({@link TableApi.getRowValue}), copy, Excel, totals (`footerAggregates`) and row groups use the
124
+ * computed value. `property` stays the id of the column (state, `footerAggregates`, other formulas).
125
+ * Without a {@link ColumnDefIf.valueSetter} the column cannot be edited.
126
+ *
127
+ * Supported by the models of `TableFactory.createTableModel({ rows })`, trees, row groups (not by array-of-arrays
128
+ * models; an own `AreaModel` calls it itself).
129
+ *
130
+ * @example
131
+ * ColumnDef.create({ property: "total", headerLabel: "Total", sortable: TrueFn,
132
+ * valueGetter: (o: Item) => o.price * o.quantity })
133
+ *
134
+ * @see Training: [Columns with ColumnDef](https://gui.expert/training/column-definitions/)
135
+ * @since 1.1.95
136
+ */
137
+ valueGetter?: ValueGetter;
138
+ /**
139
+ * Makes a calculated column editable: writes the edited value back into the row (return `false` to reject).
140
+ *
141
+ * @example
142
+ * valueSetter: (o: Item, v: unknown) => { o.price = Number(v) / o.quantity; }
143
+ *
144
+ * @since 1.1.95
145
+ */
146
+ valueSetter?: ValueSetter;
147
+ /**
148
+ * Shows the numbers of the column differently without changing the data: share of the column total, running
149
+ * total, rank … (see {@link ShowValuesAs}). Change it at runtime with {@link TableApi.setShowValuesAs}.
150
+ *
151
+ * @example
152
+ * ColumnDef.create({ property: "total", headerLabel: "Share", showValuesAs: "percentOfColumnTotal" })
153
+ *
154
+ * @since 1.1.95
155
+ */
156
+ showValuesAs?: ShowValuesAsConfig;
157
+ /**
158
+ * The formula of a formula column (`ColumnDef.create({ formula })` compiles it into the `valueGetter`), e.g.
159
+ * `"[price] * [quantity] * 1.19"`. Informational – change it with {@link TableApi.setColumnFormula}.
160
+ *
161
+ * @since 1.1.95
162
+ */
163
+ formula?: string;
164
+ /**
165
+ * Row drag: the body cells of this column get a drag handle (`true`, or a function that decides per row – e.g. no
166
+ * handle for locked rows). Dragging the handle moves the row (see {@link TableOptionsIf.rowDragOptions}); the keyboard
167
+ * alternative is Ctrl+Alt+↑/↓. `TableFactory.createTableModel({ rows, rowDrag: true })` sets it on the first data
168
+ * column.
169
+ *
170
+ * @example
171
+ * ColumnDef.create({ property: "title", headerLabel: "Task", rowDrag: (task: { locked: boolean }) => !task.locked })
172
+ *
173
+ * @since 1.1.95
174
+ */
175
+ rowDrag?: RowDragColumnOption;
176
+ /**
177
+ * Checks an edited, filled or pasted value (after `editInputPipe`): return a message for an invalid value,
178
+ * `undefined` for a valid one. Batch edit: invalid values are marked (`ge-table-cell-invalid`, the message as
179
+ * tooltip) and block {@link TableApi.commitBatchEdit}; otherwise an invalid value is not written.
180
+ *
181
+ * @example
182
+ * ColumnDef.create({
183
+ * property: "price", headerLabel: "Price", editable: TrueFn, editInputPipe: editInputPipeForNumber,
184
+ * validate: (value: unknown) => typeof value === "number" && value >= 0 ? undefined : "A price is a number ≥ 0",
185
+ * })
186
+ *
187
+ * @since 1.1.96
188
+ */
189
+ validate?: CellValidator;
119
190
  }
191
+ /**
192
+ * {@link ColumnDefIf.validate}: a message for an invalid value, `undefined` (or `null`, `""`) for a valid one.
193
+ *
194
+ * @category Fill handle & batch edit
195
+ * @since 1.1.96
196
+ */
197
+ export type CellValidator<T = any> = (value: unknown, row: T) => string | undefined | null | void;
198
+ /**
199
+ * {@link ColumnDefIf.rowDrag}: `true` = every row has a drag handle in this column, a function decides per row
200
+ * (`row` = the row object, a `TreeRow` in a tree; `rowIndex` = display index).
201
+ *
202
+ * @category Row drag
203
+ * @since 1.1.95
204
+ */
205
+ export type RowDragColumnOption = boolean | ((row: any, rowIndex: number) => boolean);
@@ -98,6 +98,12 @@ export declare class EleScope {
98
98
  * @return {void}
99
99
  */
100
100
  adjustContainersAndRows(): void;
101
+ /**
102
+ * Position and size of the detail layer (master/detail) in the host – overwritten in {@link RenderScope}.
103
+ *
104
+ * @since 1.1.97
105
+ */
106
+ protected adjustDetailLayerBounds(_left: number, _top: number, _width: number, _height: number): void;
101
107
  /**
102
108
  * Adjusts the position or appearance of elements after scrolling.
103
109
  * This method must be overwritten in child classes.
@@ -105,6 +111,14 @@ export declare class EleScope {
105
111
  * @return {void}
106
112
  */
107
113
  adjustAfterScrolling(): void;
114
+ /**
115
+ * The height of all body rows in px – the model's content height plus, in {@link RenderScope}, the heights of open
116
+ * detail rows (master/detail).
117
+ *
118
+ * @returns {number} px
119
+ * @since 1.1.97
120
+ */
121
+ protected getBodyContentHeight(): number;
108
122
  /**
109
123
  * Resets the size of the wrapper div based on the content dimensions.
110
124
  *
@@ -1,3 +1,4 @@
1
+ import { GeDetailEvent } from './data/common/event/ge-detail-event.js';
1
2
  import { GeModelChangeEvent } from './data/common/event/ge-model-change-event.js';
2
3
  import { GeMouseEvent } from './data/common/event/ge-mouse-event.js';
3
4
  import { GeScrollEvent } from './data/common/event/ge-scroll-event.js';
@@ -5,6 +6,8 @@ import { EventListenerIf } from './event-listener.if.js';
5
6
  import { SelectionModelIf } from './selection/selection-model.if.js';
6
7
  import { FocusModelIf } from './focus/focus-model.if.js';
7
8
  import { GeStateChangeEvent } from './data/common/event/ge-state-change-event.js';
9
+ import { GeBatchEditEvent } from './data/common/event/ge-batch-edit-event.js';
10
+ import { GeRowDragEvent } from './data/common/event/ge-row-drag-event.js';
8
11
 
9
12
  /**
10
13
  * Empty implementation of {@link EventListenerIf} – extend it and override only the events you need.
@@ -33,4 +36,11 @@ export declare class EventAdapter implements EventListenerIf {
33
36
  onFocusChanged(_model: FocusModelIf): void;
34
37
  /** @since 1.1.92 */
35
38
  onStateChanged(_evt: GeStateChangeEvent): void;
39
+ onRowDragStart(_evt: GeRowDragEvent): void;
40
+ onRowDragMove(_evt: GeRowDragEvent): void;
41
+ onRowDragEnd(_evt: GeRowDragEvent): void;
42
+ /** @since 1.1.96 */
43
+ onBatchEditChanged(_evt: GeBatchEditEvent): void;
44
+ /** @since 1.1.97 */
45
+ onDetailExpandedChanged(_evt: GeDetailEvent): void;
36
46
  }
@@ -1,7 +1,10 @@
1
+ import { GeDetailEvent } from './data/common/event/ge-detail-event.js';
1
2
  import { GeMouseEvent } from './data/common/event/ge-mouse-event.js';
2
3
  import { GeModelChangeEvent } from './data/common/event/ge-model-change-event.js';
3
4
  import { GeScrollEvent } from './data/common/event/ge-scroll-event.js';
4
5
  import { GeStateChangeEvent } from './data/common/event/ge-state-change-event.js';
6
+ import { GeRowDragEvent } from './data/common/event/ge-row-drag-event.js';
7
+ import { GeBatchEditEvent } from './data/common/event/ge-batch-edit-event.js';
5
8
  import { SelectionModelIf } from './selection/selection-model.if.js';
6
9
  import { FocusModelIf } from './focus/focus-model.if.js';
7
10
  import { EventFocusChangedListenerIf } from './focus/event-focus-changed-listener.if.js';
@@ -63,4 +66,40 @@ export interface EventListenerIf extends EventFocusChangedListenerIf, EventSelec
63
66
  * @since 1.1.92
64
67
  */
65
68
  onStateChanged?(evt: GeStateChangeEvent): void;
69
+ /**
70
+ * Optional: a row drag started (drag handle moved past the threshold, or Ctrl+Alt+↑/↓). `evt.preventDefault()`
71
+ * cancels it. See {@link GeRowDragEvent}.
72
+ *
73
+ * @since 1.1.95
74
+ */
75
+ onRowDragStart?(evt: GeRowDragEvent): void;
76
+ /**
77
+ * Optional: the drop target of a row drag changed (not on every pixel). `evt.preventDefault()` marks the target as
78
+ * invalid (no drop marker, no drop).
79
+ *
80
+ * @since 1.1.95
81
+ */
82
+ onRowDragMove?(evt: GeRowDragEvent): void;
83
+ /**
84
+ * Optional: a row drag ended – `evt.type` is `"end"` (dropped; `evt.moved` = the table moved the rows) or `"cancel"`.
85
+ * Managed: called after the move (`evt.toIndex` = the real position). Save the new order here; to veto a drop, call
86
+ * `evt.preventDefault()` in {@link onRowDragMove}.
87
+ *
88
+ * @since 1.1.95
89
+ */
90
+ onRowDragEnd?(evt: GeRowDragEvent): void;
91
+ /**
92
+ * The pending changes of a batch edit changed: values were marked, set back, written or discarded
93
+ * ({@link TableApi.startBatchEdit}, {@link TableOptionsIf.batchEdit}). Optional.
94
+ *
95
+ * @param {GeBatchEditEvent} evt - type, cells of this step, number of pending and invalid cells
96
+ * @since 1.1.96
97
+ */
98
+ onBatchEditChanged?(evt: GeBatchEditEvent): void;
99
+ /**
100
+ * A detail row was expanded or collapsed (master/detail, {@link TableOptionsIf.masterDetail}).
101
+ *
102
+ * @since 1.1.97
103
+ */
104
+ onDetailExpandedChanged?(evt: GeDetailEvent): void;
66
105
  }
@@ -78,6 +78,17 @@ export interface CreateTableModelPara {
78
78
  * @since 1.1.93
79
79
  */
80
80
  rowNumbersVisible: boolean | Partial<RowNumberOptionsIf>;
81
+ /**
82
+ * Row drag: `true` puts a drag handle into the first data column (behind row numbers and checkboxes) –
83
+ * sets {@link ColumnDefIf.rowDrag} on that column definition. Options: {@link TableOptionsIf.rowDragOptions}.
84
+ * Default false.
85
+ *
86
+ * @example
87
+ * const tableModel = TableFactory.createTableModel({ rows: orders, rowDrag: true });
88
+ *
89
+ * @since 1.1.95
90
+ */
91
+ rowDrag: boolean;
81
92
  /** Row heights of header, body and footer in px. Default: `tableOptions.defaultRowHeights`, otherwise 34 / 34 / 34. */
82
93
  defaultRowHeights: DefaultRowHeightsIf;
83
94
  /** The columns: property, header label, width, classes, renderers, sorting, editing. See {@link ColumnDef}. */
@@ -0,0 +1,67 @@
1
+ import { CellRange } from '../data/common/cell-range.js';
2
+ import { CellValueChangeIf } from '../batch-edit/cell-value-change.if.js';
3
+ import { FillDirection } from './fill-direction.type.js';
4
+ import { FillValueContextIf } from './fill-value-context.if.js';
5
+ import { FillMode } from './fill-series.js';
6
+
7
+ /**
8
+ * Input of {@link computeFillChanges}.
9
+ *
10
+ * @category Fill handle & batch edit
11
+ * @since 1.1.96
12
+ */
13
+ export interface FillRequestIf {
14
+ /** The selected source range (body display indices, `r1 <= r2`, `c1 <= c2`). */
15
+ source: CellRange;
16
+ /** Where the range is extended to. */
17
+ direction: FillDirection;
18
+ /** The number of rows (down/up) or columns (right/left) to fill. */
19
+ count: number;
20
+ /** Series or copy, see {@link FillMode}. */
21
+ mode?: FillMode;
22
+ /** The shown value of a cell (batch edit: the pending value). */
23
+ getValue: (rowIndex: number, columnIndex: number) => unknown;
24
+ /** `false` skips a target cell (not editable, hidden column …); the series keeps counting. */
25
+ isFillable?: (rowIndex: number, columnIndex: number) => boolean;
26
+ /** Own fill function, see {@link FillHandleOptionsIf.fillValue}. */
27
+ fillValue?: (ctx: FillValueContextIf) => unknown;
28
+ /** Row object and property of a cell – for `fillValue`. */
29
+ getCellInfo?: (rowIndex: number, columnIndex: number) => {
30
+ row: unknown;
31
+ property: string;
32
+ };
33
+ }
34
+ /**
35
+ * The cells a fill covers: the source range extended by `count` rows or columns in `direction`.
36
+ *
37
+ * @param {CellRange} source - the selected range
38
+ * @param {FillDirection} direction - the direction of the fill
39
+ * @param {number} count - rows or columns added
40
+ * @returns {CellRange} source and filled cells together
41
+ *
42
+ * @example
43
+ * getFillRange(new CellRange(2, 1, 3, 1), "down", 3); // rows 2…6 of column 1
44
+ *
45
+ * @category Fill handle & batch edit
46
+ * @since 1.1.96
47
+ */
48
+ export declare function getFillRange(source: CellRange, direction: FillDirection, count: number): CellRange;
49
+ /**
50
+ * The values a fill writes: per line of the source range (each column when filling down/up, each row when filling
51
+ * right/left) the continuation of its values ({@link computeFillValues}) – DOM-free, the table applies the result with
52
+ * {@link TableApi.applyCellChanges}.
53
+ *
54
+ * @param {FillRequestIf} request - source range, direction, count, value access
55
+ * @returns {CellValueChangeIf[]} one change per fillable target cell (column = model index)
56
+ *
57
+ * @example
58
+ * const values = [[1], [2]]; // a 2 × 1 source range
59
+ * computeFillChanges({
60
+ * source: new CellRange(0, 0, 1, 0), direction: "down", count: 2,
61
+ * getValue: (r, c) => values[r]?.[c],
62
+ * }); // [{ rowIndex: 2, column: 0, value: 3 }, { rowIndex: 3, column: 0, value: 4 }]
63
+ *
64
+ * @category Fill handle & batch edit
65
+ * @since 1.1.96
66
+ */
67
+ export declare function computeFillChanges(request: FillRequestIf): CellValueChangeIf[];
@@ -0,0 +1,7 @@
1
+ /**
2
+ * The direction of a fill: the fill handle was dragged down, up, right or left of the selected range.
3
+ *
4
+ * @category Fill handle & batch edit
5
+ * @since 1.1.96
6
+ */
7
+ export type FillDirection = "down" | "up" | "right" | "left";
@@ -0,0 +1,29 @@
1
+ import { FillHandleOptionsIf } from './fill-handle-options.if.js';
2
+ import { FillValueContextIf } from './fill-value-context.if.js';
3
+
4
+ /**
5
+ * The defaults of {@link FillHandleOptionsIf}.
6
+ *
7
+ * @example
8
+ * const options = FillHandleOptions.create(true);
9
+ * options?.direction; // "both"
10
+ *
11
+ * @category Fill handle & batch edit
12
+ * @since 1.1.96
13
+ */
14
+ export declare class FillHandleOptions implements FillHandleOptionsIf {
15
+ direction: "vertical" | "horizontal" | "both";
16
+ fillValue?: (ctx: FillValueContextIf) => unknown;
17
+ maxCells: number;
18
+ dragThresholdInPx: number;
19
+ autoScrollZoneInPx: number;
20
+ autoScrollMaxSpeedInPx: number;
21
+ /**
22
+ * The options of {@link TableOptionsIf.fillHandle}: `undefined`/`false` = no fill handle, `true` = the defaults, an
23
+ * object = the defaults overridden by its values (`undefined` keeps the default).
24
+ *
25
+ * @param {boolean | Partial<FillHandleOptionsIf>} [option] - `tableOptions.fillHandle`
26
+ * @returns {FillHandleOptionsIf | undefined} complete options, `undefined` if the fill handle is off
27
+ */
28
+ static create(option?: boolean | Partial<FillHandleOptionsIf>): FillHandleOptionsIf | undefined;
29
+ }