@guiexpert/table 1.1.93 → 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 (123) hide show
  1. package/README.md +25 -0
  2. package/css/main.css +334 -0
  3. package/css/table-calc.css +7 -0
  4. package/css/table-classes.css +34 -0
  5. package/css/table-color-vars.css +78 -0
  6. package/css/table-fill-batch.css +58 -0
  7. package/css/table-pivot.css +42 -0
  8. package/css/table-row-drag.css +81 -0
  9. package/css/table-row-group.css +25 -0
  10. package/css/table-tree.css +9 -0
  11. package/index.cjs +57 -47
  12. package/index.d.ts +67 -0
  13. package/index.js +11290 -4985
  14. package/lib/table/action/action-id.type.d.ts +1 -1
  15. package/lib/table/aggregation/aggregate-internals.d.ts +30 -0
  16. package/lib/table/aggregation/aggregate-spec.if.d.ts +51 -0
  17. package/lib/table/aggregation/aggregate.d.ts +58 -0
  18. package/lib/table/aggregation/aggregator-name.type.d.ts +39 -0
  19. package/lib/table/aggregation/aggregator.if.d.ts +51 -0
  20. package/lib/table/aggregation/aggregators.d.ts +37 -0
  21. package/lib/table/aggregation/create-value-getter.d.ts +18 -0
  22. package/lib/table/aggregation/selection-aggregates.if.d.ts +35 -0
  23. package/lib/table/aggregation/value-accessor.type.d.ts +13 -0
  24. package/lib/table/aria/aria-texts.d.ts +11 -0
  25. package/lib/table/aria/aria-texts.if.d.ts +87 -0
  26. package/lib/table/batch-edit/batch-edit-options.d.ts +21 -0
  27. package/lib/table/batch-edit/batch-edit-options.if.d.ts +20 -0
  28. package/lib/table/batch-edit/batch-edit-service.d.ts +104 -0
  29. package/lib/table/batch-edit/cell-change.if.d.ts +39 -0
  30. package/lib/table/batch-edit/cell-value-change.if.d.ts +18 -0
  31. package/lib/table/batch-edit/pending-cell-changes.d.ts +104 -0
  32. package/lib/table/calc/column-values.d.ts +55 -0
  33. package/lib/table/calc/show-values-as-internals.d.ts +4 -0
  34. package/lib/table/calc/show-values-as.d.ts +87 -0
  35. package/lib/table/calc/show-values-as.type.d.ts +55 -0
  36. package/lib/table/calc/value-getter-context.if.d.ts +35 -0
  37. package/lib/table/calc/value-getter.type.d.ts +36 -0
  38. package/lib/table/data/common/event/ge-batch-edit-event.d.ts +46 -0
  39. package/lib/table/data/common/event/ge-model-change-event.d.ts +27 -1
  40. package/lib/table/data/common/event/ge-row-drag-event.d.ts +89 -0
  41. package/lib/table/data/common/row-number-column-def.d.ts +107 -0
  42. package/lib/table/data/common/row-number-columns.d.ts +17 -0
  43. package/lib/table/data/common/row-number-options.d.ts +19 -0
  44. package/lib/table/data/common/row-number-options.if.d.ts +44 -0
  45. package/lib/table/data/options/table-options.d.ts +6 -0
  46. package/lib/table/data/options/table-options.if.d.ts +44 -0
  47. package/lib/table/data/tablemodel/areamodel/abstract-area-model.d.ts +66 -0
  48. package/lib/table/data/tablemodel/areamodel/aggregate-footer-options.if.d.ts +73 -0
  49. package/lib/table/data/tablemodel/areamodel/area-model-aggregate-footer.d.ts +150 -0
  50. package/lib/table/data/tablemodel/areamodel/area-model-array-of-arrays.d.ts +24 -0
  51. package/lib/table/data/tablemodel/areamodel/area-model-cell-groups.d.ts +18 -1
  52. package/lib/table/data/tablemodel/areamodel/area-model-object-array.d.ts +70 -0
  53. package/lib/table/data/tablemodel/areamodel/area-model-pivot-footer.d.ts +47 -0
  54. package/lib/table/data/tablemodel/areamodel/area-model-pivot.d.ts +281 -0
  55. package/lib/table/data/tablemodel/areamodel/area-model-row-groups.d.ts +336 -0
  56. package/lib/table/data/tablemodel/areamodel/area-model-tree.d.ts +97 -0
  57. package/lib/table/data/tablemodel/areamodel/area-model.if.d.ts +94 -0
  58. package/lib/table/data/tablemodel/areamodel/derived-values-change.if.d.ts +30 -0
  59. package/lib/table/data/tablemodel/column/column-def.d.ts +31 -1
  60. package/lib/table/data/tablemodel/column/column-def.if.d.ts +86 -0
  61. package/lib/table/event-adapter.d.ts +7 -0
  62. package/lib/table/event-listener.if.d.ts +32 -0
  63. package/lib/table/factory/pivot-factory.d.ts +63 -0
  64. package/lib/table/factory/pivot-table-model-para.if.d.ts +44 -0
  65. package/lib/table/factory/row-group-factory.d.ts +70 -0
  66. package/lib/table/factory/row-group-table-model-para.if.d.ts +66 -0
  67. package/lib/table/factory/table-factory.d.ts +56 -1
  68. package/lib/table/fill/compute-fill-changes.d.ts +67 -0
  69. package/lib/table/fill/fill-direction.type.d.ts +7 -0
  70. package/lib/table/fill/fill-handle-options.d.ts +29 -0
  71. package/lib/table/fill/fill-handle-options.if.d.ts +35 -0
  72. package/lib/table/fill/fill-handle-service.d.ts +55 -0
  73. package/lib/table/fill/fill-series.d.ts +60 -0
  74. package/lib/table/fill/fill-value-context.if.d.ts +36 -0
  75. package/lib/table/formula/compile-formula.d.ts +86 -0
  76. package/lib/table/formula/evaluator.d.ts +19 -0
  77. package/lib/table/formula/formula-ast.if.d.ts +42 -0
  78. package/lib/table/formula/formula-error.d.ts +59 -0
  79. package/lib/table/formula/formula-options.if.d.ts +41 -0
  80. package/lib/table/formula/formula-values.d.ts +13 -0
  81. package/lib/table/formula/functions.d.ts +18 -0
  82. package/lib/table/formula/parser.d.ts +10 -0
  83. package/lib/table/formula/tokenizer.d.ts +22 -0
  84. package/lib/table/instanceof-workaround.d.ts +143 -6
  85. package/lib/table/pivot/area-model-pivot-header.d.ts +9 -0
  86. package/lib/table/pivot/pivot-column-def.d.ts +28 -0
  87. package/lib/table/pivot/pivot-column-info.if.d.ts +25 -0
  88. package/lib/table/pivot/pivot-config.if.d.ts +58 -0
  89. package/lib/table/pivot/pivot-internals.d.ts +13 -0
  90. package/lib/table/pivot/pivot-layout.d.ts +40 -0
  91. package/lib/table/pivot/pivot-result.d.ts +157 -0
  92. package/lib/table/pivot/pivot-table-model.d.ts +86 -0
  93. package/lib/table/pivot/pivot-value.type.d.ts +80 -0
  94. package/lib/table/render-scope.d.ts +142 -4
  95. package/lib/table/renderer/aggregate-cell-renderer.d.ts +27 -0
  96. package/lib/table/renderer/edit/input-cell-renderer.d.ts +1 -1
  97. package/lib/table/renderer/edit/select-cell-renderer.d.ts +1 -1
  98. package/lib/table/renderer/row-number-cell-renderer.d.ts +27 -0
  99. package/lib/table/row-drag/move-rows.d.ts +157 -0
  100. package/lib/table/row-drag/row-drag-options.d.ts +28 -0
  101. package/lib/table/row-drag/row-drag-options.if.d.ts +36 -0
  102. package/lib/table/row-drag/row-drag-service.d.ts +130 -0
  103. package/lib/table/row-drag/row-drop-target.if.d.ts +29 -0
  104. package/lib/table/rowgroup/group-rows-internals.d.ts +14 -0
  105. package/lib/table/rowgroup/group-rows-options.if.d.ts +13 -0
  106. package/lib/table/rowgroup/group-rows.d.ts +48 -0
  107. package/lib/table/rowgroup/row-group-column-def.d.ts +26 -0
  108. package/lib/table/rowgroup/row-group-column-options.if.d.ts +27 -0
  109. package/lib/table/rowgroup/row-group-detail-row.d.ts +8 -0
  110. package/lib/table/rowgroup/row-group-field.type.d.ts +56 -0
  111. package/lib/table/rowgroup/row-group-internals.d.ts +31 -0
  112. package/lib/table/rowgroup/row-group-layout.d.ts +13 -0
  113. package/lib/table/rowgroup/row-group-model-options.if.d.ts +39 -0
  114. package/lib/table/rowgroup/row-group.d.ts +51 -0
  115. package/lib/table/rowgroup/row-group.if.d.ts +48 -0
  116. package/lib/table/selection/selection-aggregator.d.ts +37 -0
  117. package/lib/table/selection/selection-service.d.ts +7 -0
  118. package/lib/table/service/convenience-dom.service.d.ts +5 -0
  119. package/lib/table/service/excel-service.d.ts +6 -0
  120. package/lib/table/service/excel-service.if.d.ts +35 -0
  121. package/lib/table/table-api.d.ts +389 -3
  122. package/lib/table/table-scope.d.ts +140 -0
  123. package/package.json +3 -2
@@ -0,0 +1,104 @@
1
+ /**
2
+ * One pending (not yet written) cell value of a batch edit – an entry of {@link PendingCellChanges}.
3
+ *
4
+ * @category Internals
5
+ * @since 1.1.96
6
+ */
7
+ export interface PendingCellIf {
8
+ /** The key of the row: the row object (tree: the data of the `TreeRow`), or the row index for models without objects. */
9
+ rowKey: unknown;
10
+ /** The property of the column (`"#3"` for a column without property). */
11
+ property: string;
12
+ /** The value before the first change. */
13
+ oldValue: unknown;
14
+ /** The value shown (after the column's `editInputPipe`). */
15
+ newValue: unknown;
16
+ /** The value as entered (written with `setValue` on commit – the pipe runs there once). */
17
+ rawValue: unknown;
18
+ /** The message of {@link ColumnDefIf.validate}, if the value is invalid. */
19
+ error?: string;
20
+ }
21
+ /**
22
+ * What {@link PendingCellChanges.set} did: a new entry, a changed entry, an entry removed because the value is the
23
+ * old one again (B8), or nothing (the value equals the old one and there was no entry).
24
+ *
25
+ * @category Internals
26
+ * @since 1.1.96
27
+ */
28
+ export type PendingChangeResult = "added" | "changed" | "removed" | "unchanged";
29
+ /**
30
+ * True if two cell values are the same for a batch edit: `Object.is`, dates by time, a number and the text of the same
31
+ * number (an editor without `editInputPipe` returns texts), and `null` / `undefined` / `""` as "empty".
32
+ *
33
+ * @param {unknown} a - one value
34
+ * @param {unknown} b - another value
35
+ * @returns {boolean} whether the cell would not change
36
+ *
37
+ * @example
38
+ * isSameCellValue(5, "5"); // true
39
+ * isSameCellValue(new Date(2026, 0, 1), new Date(2026, 0, 1)); // true
40
+ * isSameCellValue(undefined, ""); // true
41
+ *
42
+ * @category Fill handle & batch edit
43
+ * @since 1.1.96
44
+ */
45
+ export declare function isSameCellValue(a: unknown, b: unknown): boolean;
46
+ /**
47
+ * The pending values of a batch edit: per row (the row **object**, not its index – sorting and filtering don't
48
+ * change the assignment) and property one entry with old and new value. DOM-free; the table keeps one in its
49
+ * batch edit service.
50
+ *
51
+ * @example
52
+ * const pending = new PendingCellChanges();
53
+ * const row = { price: 10 };
54
+ * pending.set(row, "price", 10, 12, "12"); // "added"
55
+ * pending.set(row, "price", 12, 10, "10"); // "removed" – the old value again
56
+ *
57
+ * @category Internals
58
+ * @since 1.1.96
59
+ */
60
+ export declare class PendingCellChanges {
61
+ private readonly rows;
62
+ private count;
63
+ /**
64
+ * Sets the pending value of a cell. The old value of an existing entry stays (the value before the first change);
65
+ * a value equal to it removes the entry (B8).
66
+ *
67
+ * @param {unknown} rowKey - the row object (or the row index for models without objects)
68
+ * @param {string} property - the property of the column
69
+ * @param {unknown} oldValue - the current value in the model (used for a new entry)
70
+ * @param {unknown} newValue - the new value (after the pipe)
71
+ * @param {unknown} rawValue - the value as entered
72
+ * @param {string} [error] - validation message
73
+ * @returns {PendingChangeResult} what happened
74
+ */
75
+ set(rowKey: unknown, property: string, oldValue: unknown, newValue: unknown, rawValue: unknown, error?: string): PendingChangeResult;
76
+ /**
77
+ * The pending entry of a cell.
78
+ *
79
+ * @param {unknown} rowKey - the row object (or index)
80
+ * @param {string} property - the property of the column
81
+ * @returns {PendingCellIf | undefined} the entry, `undefined` if the cell is unchanged
82
+ */
83
+ get(rowKey: unknown, property: string): PendingCellIf | undefined;
84
+ /**
85
+ * Removes the entry of a cell.
86
+ *
87
+ * @param {unknown} rowKey - the row object (or index)
88
+ * @param {string} property - the property of the column
89
+ * @returns {boolean} true if there was an entry
90
+ */
91
+ remove(rowKey: unknown, property: string): boolean;
92
+ /** @returns {boolean} true if the row has pending values */
93
+ hasRow(rowKey: unknown): boolean;
94
+ /** @returns {number} the number of pending cells */
95
+ size(): number;
96
+ /** @returns {boolean} true if nothing is pending */
97
+ isEmpty(): boolean;
98
+ /** @returns {number} the number of pending cells with a validation message */
99
+ invalidCount(): number;
100
+ /** @returns {PendingCellIf[]} all entries, in the order they were first changed */
101
+ entries(): PendingCellIf[];
102
+ /** Forgets all entries. */
103
+ clear(): void;
104
+ }
@@ -0,0 +1,55 @@
1
+ import { ColumnDefIf } from '../data/tablemodel/column/column-def.if.js';
2
+ import { ValueGetter } from './value-getter.type.js';
3
+ import { ValueGetterContextIf } from './value-getter-context.if.js';
4
+ import { AggregatorRef } from '../aggregation/aggregator-name.type.js';
5
+ import { ShowValuesAsIf } from './show-values-as.type.js';
6
+
7
+ /** What an area model provides to its {@link ColumnValues}. */
8
+ export interface ColumnValuesOwner {
9
+ /** The column definitions (read lazily – they may be replaced, e.g. by a pivot). */
10
+ getColumnDefsForValues(): ColumnDefIf[];
11
+ /** The value of a property path (the model's own semantics – unchanged behaviour for normal columns). */
12
+ readPath(row: any, property: string): unknown;
13
+ /** The rows of column aggregates (filtered, data objects) and a cheap signal that changes with them. */
14
+ getAggregationSource(): {
15
+ signal: unknown;
16
+ length: number;
17
+ rows: () => ArrayLike<unknown>;
18
+ };
19
+ }
20
+ /**
21
+ * Resolves `valueGetter`s by property, detects cycles (`#CIRC!`), caches column aggregates.
22
+ * Without calculated columns `get()` is one empty-map lookup plus the model's own path read.
23
+ */
24
+ export declare class ColumnValues {
25
+ private readonly owner;
26
+ private getters?;
27
+ private showValuesAs?;
28
+ private properties?;
29
+ private defsLength;
30
+ /** property → rows whose value is being computed (a getter may read the same column of another row) */
31
+ private readonly computing;
32
+ private readonly contexts;
33
+ private aggregates;
34
+ private aggSignal;
35
+ private aggLength;
36
+ constructor(owner: ColumnValuesOwner);
37
+ /** Drops the getter lookup and the cached aggregates (`invalidateDerivedValues`). */
38
+ invalidate(): void;
39
+ /** The getter of a calculated column. */
40
+ getter(property: string | undefined): ValueGetter | undefined;
41
+ hasGetters(): boolean;
42
+ isCalculated(property: string): boolean;
43
+ hasColumn(property: string): boolean;
44
+ /** The „Show values as“ options of a column. */
45
+ getShowValuesAs(property: string | undefined): ShowValuesAsIf | undefined;
46
+ hasShowValuesAs(): boolean;
47
+ /** The value of a column for a row: its getter (cycle-safe, exceptions → `#VALUE!`) or the path. */
48
+ get(row: any, property: string): unknown;
49
+ /** An aggregate of a column over the filtered rows – cached. */
50
+ aggregate(property: string, aggregator: AggregatorRef): unknown;
51
+ /** The context passed to a getter. */
52
+ context(property: string): ValueGetterContextIf;
53
+ private call;
54
+ private lookup;
55
+ }
@@ -0,0 +1,4 @@
1
+ import { ShowValuesAsConfig } from './show-values-as.type.js';
2
+
3
+ /** The Excel number format of a shown value (percentages: `0.0%`), `undefined` for the default. */
4
+ export declare function excelFormatOfShowValuesAs(config: ShowValuesAsConfig | undefined): string | undefined;
@@ -0,0 +1,87 @@
1
+ import { ShowValuesAs, ShowValuesAsConfig, ShowValuesAsIf } from './show-values-as.type.js';
2
+
3
+ /**
4
+ * The full options of a „Show values as“ configuration – `undefined` for none or an unknown mode.
5
+ *
6
+ * @param {ShowValuesAsConfig | undefined} config - a mode or mode with options
7
+ * @returns {ShowValuesAsIf | undefined} the options
8
+ *
9
+ * @example
10
+ * resolveShowValuesAs("rank"); // { mode: "rank" }
11
+ *
12
+ * @since 1.1.95
13
+ * @category Calculated columns & formulas
14
+ */
15
+ export declare function resolveShowValuesAs(config: ShowValuesAsConfig | undefined | null): ShowValuesAsIf | undefined;
16
+ /**
17
+ * All modes of {@link ShowValuesAs}, e.g. for an own select box.
18
+ *
19
+ * @example
20
+ * select.append(...SHOW_VALUES_AS_MODES.map(mode => new Option(mode, mode)));
21
+ *
22
+ * @since 1.1.95
23
+ * @category Calculated columns & formulas
24
+ */
25
+ export declare const SHOW_VALUES_AS_MODES: readonly ShowValuesAs[];
26
+ /**
27
+ * True for the modes that show a share (a fraction, shown as percentage).
28
+ *
29
+ * @param {ShowValuesAs} mode - the mode
30
+ * @returns {boolean} whether the shown value is a fraction
31
+ *
32
+ * @example
33
+ * isPercentShowValuesAs("percentOfColumnTotal"); // true
34
+ * isPercentShowValuesAs("rank"); // false
35
+ *
36
+ * @since 1.1.95
37
+ * @category Calculated columns & formulas
38
+ */
39
+ export declare function isPercentShowValuesAs(mode: ShowValuesAs | undefined): boolean;
40
+ /**
41
+ * The text of a shown value: percentages with one decimal (`"66.7%"`), ranks without decimals, differences and
42
+ * running totals like totals (`"1,234.5"`). Not a number → `""`.
43
+ *
44
+ * @param {unknown} value - the shown value (a fraction for percentages)
45
+ * @param {ShowValuesAsConfig} config - the configuration of the column
46
+ * @returns {string} the text
47
+ *
48
+ * @example
49
+ * formatShowValuesAs(0.667, "percentOfColumnTotal"); // "66.7%"
50
+ * formatShowValuesAs(0.667, { mode: "percentOfColumnTotal", fractionDigits: 2 }); // "66.70%"
51
+ *
52
+ * @since 1.1.95
53
+ * @category Calculated columns & formulas
54
+ */
55
+ export declare function formatShowValuesAs(value: unknown, config: ShowValuesAsConfig): string;
56
+ /**
57
+ * The sum of the numbers of a list (Neumaier, like {@link Aggregators}.sum); other values are skipped.
58
+ *
59
+ * @param {ArrayLike<unknown>} values - the values
60
+ * @returns {number} the sum, 0 for none
61
+ *
62
+ * @example
63
+ * sumOfNumbers([1, "2", 3, undefined]); // 4
64
+ *
65
+ * @since 1.1.95
66
+ * @category Calculated columns & formulas
67
+ */
68
+ export declare function sumOfNumbers(values: ArrayLike<unknown>): number;
69
+ /**
70
+ * „Show values as“ over a list of values in display order – DOM-free, for own area models. Percentages are
71
+ * fractions (`0.667`); the reference is the list itself (`percentOfRowTotal` is not applicable to a list: the values are
72
+ * returned unchanged). Values that are no numbers → `undefined`.
73
+ *
74
+ * @param {ArrayLike<unknown>} values - the raw values in display order
75
+ * @param {ShowValuesAs} mode - the mode
76
+ * @returns {(number | undefined)[]} the shown values
77
+ *
78
+ * @example
79
+ * calculateShowValuesAs([2598, 1047, 250], "percentOfColumnTotal"); // [0.667…, 0.268…, 0.064…]
80
+ * calculateShowValuesAs([10, 20, 20, 5], "rank"); // [3, 1, 1, 4]
81
+ * calculateShowValuesAs([10, 20, 5], "runningTotal"); // [10, 30, 35]
82
+ * calculateShowValuesAs([10, 20, 5], "differenceFromPrevious"); // [undefined, 10, -15]
83
+ *
84
+ * @since 1.1.95
85
+ * @category Calculated columns & formulas
86
+ */
87
+ export declare function calculateShowValuesAs(values: ArrayLike<unknown>, mode: ShowValuesAs): (number | undefined)[];
@@ -0,0 +1,55 @@
1
+ /**
2
+ * How a column shows its numbers – without changing the data („Show values as“):
3
+ *
4
+ * | Mode | Shows | Flat table | Tree / row groups | Pivot |
5
+ * |---|---|---|---|---|
6
+ * | `"percentOfColumnTotal"` | value / sum of the column | ✓ | sum of the (filtered) leaf rows | cell / column total |
7
+ * | `"percentOfGrandTotal"` | value / grand total | = column total | = column total | cell / grand total |
8
+ * | `"percentOfParentTotal"` | value / total of the parent | = column total | value / sum of its siblings (each group = 100 %) | cell / parent row |
9
+ * | `"percentOfRowTotal"` | value / row total | – | – | cell / row total |
10
+ * | `"differenceFromPrevious"` | value − value of the row above | ✓ (first row empty) | among siblings | – |
11
+ * | `"runningTotal"` | sum up to this row (display order) | ✓ | among siblings | – |
12
+ * | `"rank"` | 1 = largest value, ties share a rank (1, 2, 2, 4) | ✓ | among siblings | – |
13
+ *
14
+ * The reference are the **filtered** rows (like the total row). Not applicable (–): the raw value is shown.
15
+ * Values that are no numbers and a total of 0 give an empty cell.
16
+ *
17
+ * @example
18
+ * ColumnDef.create({ property: "share", headerLabel: "Share", valueGetter: o => o.total,
19
+ * showValuesAs: "percentOfColumnTotal" });
20
+ *
21
+ * @since 1.1.95
22
+ * @category Calculated columns & formulas
23
+ */
24
+ export type ShowValuesAs = "percentOfColumnTotal" | "percentOfGrandTotal" | "percentOfParentTotal" | "percentOfRowTotal" | "differenceFromPrevious" | "runningTotal" | "rank";
25
+ /**
26
+ * „Show values as“ with options: mode, decimals, own text.
27
+ *
28
+ * @example
29
+ * ColumnDef.create({
30
+ * property: "total", headerLabel: "Share",
31
+ * showValuesAs: { mode: "percentOfColumnTotal", fractionDigits: 2 } // "66.70%"
32
+ * });
33
+ *
34
+ * @since 1.1.95
35
+ * @category Calculated columns & formulas
36
+ */
37
+ export interface ShowValuesAsIf {
38
+ /** The mode. */
39
+ mode: ShowValuesAs;
40
+ /** Decimals of the text. Default: 1 for percentages, at most 2 otherwise, 0 for `rank`. */
41
+ fractionDigits?: number;
42
+ /** An own text of the shown value (a fraction for percentages, e.g. `0.667`). Text only – never HTML. */
43
+ format?: (value: number) => string;
44
+ }
45
+ /**
46
+ * The configuration of a column: a mode or a mode with options.
47
+ *
48
+ * @example
49
+ * const share: ShowValuesAsConfig = "percentOfColumnTotal";
50
+ * const precise: ShowValuesAsConfig = { mode: "percentOfColumnTotal", fractionDigits: 2 };
51
+ *
52
+ * @since 1.1.95
53
+ * @category Calculated columns & formulas
54
+ */
55
+ export type ShowValuesAsConfig = ShowValuesAs | ShowValuesAsIf;
@@ -0,0 +1,35 @@
1
+ import { AggregatorRef } from '../aggregation/aggregator-name.type.js';
2
+
3
+ /**
4
+ * The second parameter of a {@link ValueGetter}: access to other columns of the same table – also calculated ones –
5
+ * and to column aggregates over the (filtered) rows. Formulas ({@link compileFormula}) use it for `[total]` and
6
+ * `SUM([total])`.
7
+ *
8
+ * @example
9
+ * ColumnDef.create({
10
+ * property: "share", headerLabel: "Share",
11
+ * valueGetter: (row: Item, ctx: ValueGetterContextIf) =>
12
+ * Number(ctx.getValue(row, "total")) / Number(ctx.aggregate("total", "sum"))
13
+ * });
14
+ *
15
+ * @since 1.1.95
16
+ * @category Calculated columns & formulas
17
+ */
18
+ export interface ValueGetterContextIf {
19
+ /** The property of the column that is computed. */
20
+ readonly property: string;
21
+ /**
22
+ * The value of another column of the row: its `valueGetter` (with protection against circular references –
23
+ * a cycle returns a `#CIRC!` {@link FormulaError}) or the property path.
24
+ */
25
+ getValue(row: any, property: string): unknown;
26
+ /** True if a column of the table shows this property. */
27
+ hasColumn(property: string): boolean;
28
+ /** True if that column is calculated (`valueGetter` or `formula`). */
29
+ isCalculated(property: string): boolean;
30
+ /**
31
+ * An aggregate of a column over the filtered rows of the body (cached until the data, filter or sorting changes),
32
+ * e.g. `aggregate("total", "sum")`. Values that are no numbers are skipped (see {@link Aggregators}).
33
+ */
34
+ aggregate(property: string, aggregator: AggregatorRef): unknown;
35
+ }
@@ -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
+ }
@@ -0,0 +1,107 @@
1
+ import { SizeIf } from './size.if.js';
2
+ import { ColumnDefIf } from '../tablemodel/column/column-def.if.js';
3
+ import { CellRendererIf } from '../../renderer/cell-render.if.js';
4
+ import { AreaObjectMapType } from './area-map.type.js';
5
+ import { AreaModelIf } from '../tablemodel/areamodel/area-model.if.js';
6
+ import { BooleanFunction } from './boolean-function.js';
7
+ import { RowNumberOptionsIf } from './row-number-options.if.js';
8
+
9
+ /**
10
+ * A built-in column with running row numbers (1, 2, 3 …) like the row headers of a spreadsheet.
11
+ *
12
+ * The easy way is the factory flag: `TableFactory.createTableModel({ rows, rowNumbersVisible: true })` puts this column
13
+ * in front of the others and fixes it on the left. Put it into `columnDefs` yourself if you build the models yourself
14
+ * – as the **first** column, counted in `fixedLeftColumnCount`.
15
+ *
16
+ * What the table does with it:
17
+ * - the width follows the largest number (`"9"` → `"2000000"`) – after `setRows`, filtering, expanding tree rows;
18
+ * - not sortable, not editable, no resize handle, can't be dragged, no column can be dragged in front of it;
19
+ * - body cells have `role="rowheader"` – screen readers announce the number with the row;
20
+ * - a click on a number selects the row (selection type `"row"` and `"range"`), Shift extends, Ctrl/⌘ toggles;
21
+ * a click on the header cell selects all;
22
+ * - copy ({@link TableApi.copyToClipboard}) and Excel export ({@link TableApi.downloadExcel}) leave it out, unless
23
+ * `exported: true`;
24
+ * - with a {@link CheckboxColumnDef} directly behind it, the checkbox, the tree arrow and
25
+ * `showCheckboxWihoutExtraColumn` move one column to the right.
26
+ *
27
+ * Note: it is a real column – the indices of all other columns are one higher (like with a `CheckboxColumnDef`).
28
+ * Use properties where you can (`tableApi.setColumnVisible("total", false)`, {@link TableApi.getColumnIndex}).
29
+ *
30
+ * @example
31
+ * const withNumbers: ColumnDefIf[] = [new RowNumberColumnDef(), new CheckboxColumnDef(), ...columnDefs];
32
+ * const model = TableFactory.createTableModel({ rows: orders, columnDefs: withNumbers, fixedLeftColumnCount: 2 });
33
+ *
34
+ * @see Training: [Fixed columns](https://gui.expert/training/fixed-columns/)
35
+ *
36
+ * @since 1.1.93
37
+ * @category Row numbers
38
+ */
39
+ export declare class RowNumberColumnDef implements ColumnDefIf {
40
+ /** Marker for {@link isRowNumberColumnDef} (works across copies of the core). */
41
+ readonly type = "RowNumberColumnDef";
42
+ property: string;
43
+ headerLabel: string;
44
+ /** Starts with `minWidthInPx`; the table widens it to fit the largest number. */
45
+ width: SizeIf;
46
+ minWidth: SizeIf;
47
+ maxWidth: SizeIf;
48
+ rendererMap: AreaObjectMapType<CellRendererIf>;
49
+ classes: AreaObjectMapType<string[]>;
50
+ isVisible: BooleanFunction;
51
+ /** The options (defaults from {@link RowNumberOptions}). */
52
+ readonly options: RowNumberOptionsIf;
53
+ /**
54
+ * "original": position of each row in getAllRows() – built when needed, for one array with one length. Checked on
55
+ * every lookup (`rows[position] === row`): rows sorted or replaced in place rebuild it.
56
+ */
57
+ private originalIndex?;
58
+ constructor(options?: Partial<RowNumberOptionsIf>);
59
+ /**
60
+ * The number of a body row (1-based): its position in the view (`"display"`) or in `getAllRows()` (`"original"`).
61
+ *
62
+ * @param {number} rowIndex - row index in the body (the current view)
63
+ * @param {AreaModelIf} bodyModel - the body model
64
+ * @returns {number} the row number
65
+ *
66
+ * @example
67
+ * const columnDef = new RowNumberColumnDef();
68
+ * const rowNumber = columnDef.getRowNumber(0, tableModel.getBodyModel()); // 1
69
+ */
70
+ getRowNumber(rowIndex: number, bodyModel: AreaModelIf): number;
71
+ /**
72
+ * The text of a row number: `options.format(getRowNumber(…))`.
73
+ *
74
+ * @param {number} rowIndex - row index in the body
75
+ * @param {AreaModelIf} bodyModel - the body model
76
+ * @returns {string} the text shown in the cell (and exported with `exported: true`)
77
+ *
78
+ * @example
79
+ * const columnDef = new RowNumberColumnDef({ format: n => n.toLocaleString("en-US") });
80
+ * const text = columnDef.getRowNumberText(1999, tableModel.getBodyModel()); // "2,000"
81
+ */
82
+ getRowNumberText(rowIndex: number, bodyModel: AreaModelIf): string;
83
+ /**
84
+ * The text of the largest number the column can show now – the table measures it for the column width.
85
+ * `"display"`: the row count; `"original"`: the count of all rows (unfiltered). At least the text of 1.
86
+ *
87
+ * @param {AreaModelIf} bodyModel - the body model
88
+ * @returns {string} e.g. `"2000000"`
89
+ *
90
+ * @example
91
+ * const widest = new RowNumberColumnDef().getWidestText(tableModel.getBodyModel()); // "1000" for 1000 rows
92
+ */
93
+ getWidestText(bodyModel: AreaModelIf): string;
94
+ /**
95
+ * True if the numbers are shown without an own `format` (plain digits) – the Excel export then writes numbers.
96
+ *
97
+ * @returns {boolean} false with an own `options.format`
98
+ *
99
+ * @example
100
+ * const plain = new RowNumberColumnDef().hasDefaultFormat(); // true
101
+ */
102
+ hasDefaultFormat(): boolean;
103
+ private hasAllRows;
104
+ /** Position of a row in getAllRows() (0-based), undefined if the model has no getAllRows() or the row is not in it. */
105
+ private getOriginalPosition;
106
+ private buildOriginalIndex;
107
+ }