@guiexpert/table 1.1.98 → 1.1.100

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 (99) hide show
  1. package/README.md +9 -0
  2. package/css/main.css +296 -0
  3. package/css/table-clipboard.css +41 -0
  4. package/css/table-color-vars.css +56 -0
  5. package/css/table-sheet-editing.css +149 -0
  6. package/css/table-spreadsheet.css +50 -0
  7. package/index.cjs +46 -59
  8. package/index.d.ts +46 -0
  9. package/index.js +18934 -11624
  10. package/lib/table/action/action-id.type.d.ts +1 -1
  11. package/lib/table/action/shortcut.service.d.ts +9 -0
  12. package/lib/table/aria/aria-texts.d.ts +26 -0
  13. package/lib/table/aria/aria-texts.if.d.ts +196 -0
  14. package/lib/table/batch-edit/batch-edit-service.d.ts +22 -0
  15. package/lib/table/batch-edit/cell-change.if.d.ts +6 -2
  16. package/lib/table/batch-edit/pending-cell-changes.d.ts +7 -0
  17. package/lib/table/batch-edit/write-row-value.d.ts +14 -0
  18. package/lib/table/calc/column-values.d.ts +2 -0
  19. package/lib/table/clipboard/clipboard-html.d.ts +41 -0
  20. package/lib/table/clipboard/clipboard-keymap.d.ts +18 -0
  21. package/lib/table/clipboard/clipboard-options.d.ts +30 -0
  22. package/lib/table/clipboard/clipboard-options.if.d.ts +67 -0
  23. package/lib/table/clipboard/clipboard-service.d.ts +122 -0
  24. package/lib/table/clipboard/input-pipes.d.ts +59 -0
  25. package/lib/table/clipboard/paste-plan.d.ts +96 -0
  26. package/lib/table/clipboard/tsv.d.ts +31 -0
  27. package/lib/table/data/common/event/ge-edit-event.d.ts +46 -0
  28. package/lib/table/data/common/event/ge-row-drag-event.d.ts +2 -2
  29. package/lib/table/data/common/event/ge-undo-event.d.ts +29 -0
  30. package/lib/table/data/options/table-options.d.ts +28 -0
  31. package/lib/table/data/options/table-options.if.d.ts +99 -1
  32. package/lib/table/data/tablemodel/areamodel/abstract-area-model.d.ts +11 -2
  33. package/lib/table/data/tablemodel/areamodel/area-model-array-of-arrays.d.ts +14 -0
  34. package/lib/table/data/tablemodel/areamodel/area-model-object-array.d.ts +14 -0
  35. package/lib/table/data/tablemodel/areamodel/area-model.if.d.ts +11 -0
  36. package/lib/table/data/tablemodel/column/column-def.d.ts +13 -0
  37. package/lib/table/data/tablemodel/column/column-def.if.d.ts +36 -1
  38. package/lib/table/data/tablemodel/column/default-editable.d.ts +18 -0
  39. package/lib/table/event-adapter.d.ts +6 -0
  40. package/lib/table/event-listener-hub.d.ts +10 -0
  41. package/lib/table/event-listener.if.d.ts +16 -0
  42. package/lib/table/factory/pivot-factory.d.ts +1 -1
  43. package/lib/table/factory/row-group-factory.d.ts +1 -1
  44. package/lib/table/factory/table-factory.d.ts +14 -0
  45. package/lib/table/formula/formula-ast.if.d.ts +32 -2
  46. package/lib/table/formula/formula-error.d.ts +4 -2
  47. package/lib/table/formula/parser.d.ts +5 -2
  48. package/lib/table/formula/tokenizer.d.ts +5 -2
  49. package/lib/table/input-handler.d.ts +8 -0
  50. package/lib/table/master-detail/master-detail-service.d.ts +9 -0
  51. package/lib/table/render-scope.d.ts +40 -0
  52. package/lib/table/row-drag/row-drag-service.d.ts +3 -2
  53. package/lib/table/selection/selection-service.d.ts +48 -0
  54. package/lib/table/service/excel-export-options.if.d.ts +6 -0
  55. package/lib/table/service/excel-service.d.ts +4 -0
  56. package/lib/table/service/excel-service.if.d.ts +35 -0
  57. package/lib/table/sheet/cell-address.d.ts +100 -0
  58. package/lib/table/sheet/cell-formula-options.d.ts +27 -0
  59. package/lib/table/sheet/cell-formula-options.if.d.ts +27 -0
  60. package/lib/table/sheet/excel-formula.d.ts +20 -0
  61. package/lib/table/sheet/format-formula.d.ts +19 -0
  62. package/lib/table/sheet/sheet-cells.if.d.ts +17 -0
  63. package/lib/table/sheet/sheet-compiler.d.ts +47 -0
  64. package/lib/table/sheet/sheet-engine.d.ts +207 -0
  65. package/lib/table/sheet/sheet-function-info.d.ts +25 -0
  66. package/lib/table/sheet/sheet-functions.d.ts +27 -0
  67. package/lib/table/sheet/sheet-values.d.ts +154 -0
  68. package/lib/table/sheet/shift-formula.d.ts +71 -0
  69. package/lib/table/sheet/table-sheet.d.ts +214 -0
  70. package/lib/table/sheet-editing/cell-editor-service.d.ts +105 -0
  71. package/lib/table/sheet-editing/cell-editor.if.d.ts +110 -0
  72. package/lib/table/sheet-editing/editing-keymap.d.ts +17 -0
  73. package/lib/table/sheet-editing/editing-options.d.ts +34 -0
  74. package/lib/table/sheet-editing/editing-options.if.d.ts +49 -0
  75. package/lib/table/sheet-editing/editors/date-cell-editor.d.ts +23 -0
  76. package/lib/table/sheet-editing/editors/number-cell-editor.d.ts +18 -0
  77. package/lib/table/sheet-editing/editors/select-cell-editor.d.ts +36 -0
  78. package/lib/table/sheet-editing/editors/text-cell-editor.d.ts +35 -0
  79. package/lib/table/sheet-editing/formula-assist.d.ts +103 -0
  80. package/lib/table/sheet-editing/formula-text.d.ts +61 -0
  81. package/lib/table/sheet-editing/sheet-navigation.d.ts +26 -0
  82. package/lib/table/spreadsheet/area-model-sheet.d.ts +170 -0
  83. package/lib/table/spreadsheet/formula-bar.d.ts +53 -0
  84. package/lib/table/spreadsheet/spreadsheet-factory.d.ts +111 -0
  85. package/lib/table/spreadsheet/spreadsheet-options.if.d.ts +28 -0
  86. package/lib/table/spreadsheet/spreadsheet-preset.d.ts +37 -0
  87. package/lib/table/spreadsheet/structure-edit.d.ts +35 -0
  88. package/lib/table/table-api.d.ts +511 -2
  89. package/lib/table/table-scope.d.ts +294 -1
  90. package/lib/table/undo/cell-changes-undoable.d.ts +34 -0
  91. package/lib/table/undo/model-rows.d.ts +17 -0
  92. package/lib/table/undo/pending-changes-undoable.d.ts +35 -0
  93. package/lib/table/undo/undo-keymap.d.ts +17 -0
  94. package/lib/table/undo/undo-options.d.ts +26 -0
  95. package/lib/table/undo/undo-options.if.d.ts +30 -0
  96. package/lib/table/undo/undo-service.d.ts +103 -0
  97. package/lib/table/undo/undo-stack.d.ts +62 -0
  98. package/lib/table/undo/undoable.if.d.ts +36 -0
  99. package/package.json +1 -1
@@ -5,6 +5,7 @@ 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 { ColumnEditorOption } from '../../../sheet-editing/cell-editor.if.js';
8
9
  import { ValueGetter, ValueSetter } from '../../../calc/value-getter.type.js';
9
10
  import { ShowValuesAsConfig } from '../../../calc/show-values-as.type.js';
10
11
 
@@ -131,7 +132,7 @@ export interface ColumnDefIf {
131
132
  * ColumnDef.create({ property: "total", headerLabel: "Total", sortable: TrueFn,
132
133
  * valueGetter: (o: Item) => o.price * o.quantity })
133
134
  *
134
- * @see Training: [Columns with ColumnDef](https://gui.expert/training/column-definitions/)
135
+ * @see [Live demo: formulas & calculated columns](https://gui.expert/showcase/formulas/run/) · Training: [Calculated columns, “Show values as” and formulas](https://gui.expert/training/formulas/)
135
136
  * @since 1.1.95
136
137
  */
137
138
  valueGetter?: ValueGetter;
@@ -151,6 +152,7 @@ export interface ColumnDefIf {
151
152
  * @example
152
153
  * ColumnDef.create({ property: "total", headerLabel: "Share", showValuesAs: "percentOfColumnTotal" })
153
154
  *
155
+ * @see Training: [Show values as](https://gui.expert/training/formulas/#show-values-as)
154
156
  * @since 1.1.95
155
157
  */
156
158
  showValuesAs?: ShowValuesAsConfig;
@@ -158,6 +160,7 @@ export interface ColumnDefIf {
158
160
  * The formula of a formula column (`ColumnDef.create({ formula })` compiles it into the `valueGetter`), e.g.
159
161
  * `"[price] * [quantity] * 1.19"`. Informational – change it with {@link TableApi.setColumnFormula}.
160
162
  *
163
+ * @see [Live demo: formulas](https://gui.expert/showcase/formulas/run/) · Training: [Formulas your users can type](https://gui.expert/training/formulas/#formulas)
161
164
  * @since 1.1.95
162
165
  */
163
166
  formula?: string;
@@ -187,6 +190,38 @@ export interface ColumnDefIf {
187
190
  * @since 1.1.96
188
191
  */
189
192
  validate?: CellValidator;
193
+ /**
194
+ * The editor of this column in Excel-style editing ({@link TableOptionsIf.editing}): `"text"`, `"number"`,
195
+ * `"date"` or a factory for an own {@link CellEditorIf}. Without it the table chooses by the value (numbers →
196
+ * number editor, dates → date editor, otherwise text). A column with an own {@link getEditRenderer} keeps that
197
+ * editor (inside the cell, as before).
198
+ *
199
+ * @example
200
+ * ColumnDef.create({ property: "status", editable: TrueFn, editor: () => SelectCellEditor.create(["open", "paid"]) })
201
+ *
202
+ * @since 1.1.99
203
+ */
204
+ editor?: ColumnEditorOption;
205
+ /**
206
+ * The value a cleared cell gets (Delete/Backspace in Excel-style editing), e.g. `null` or `0`. Default:
207
+ * {@link EditingOptionsIf.emptyValue} (`""`).
208
+ *
209
+ * @example
210
+ * ColumnDef.create({ property: "quantity", editable: TrueFn, emptyValue: 0 })
211
+ *
212
+ * @since 1.1.99
213
+ */
214
+ emptyValue?: unknown;
215
+ /**
216
+ * `false`: this column never holds cell formulas ({@link TableOptionsIf.cellFormulas}) – `"=…"` stays text (free
217
+ * text, notes). Default: every data column of a table with `cellFormulas`.
218
+ *
219
+ * @example
220
+ * ColumnDef.create({ property: "note", editable: TrueFn, cellFormulas: false })
221
+ *
222
+ * @since 1.1.99
223
+ */
224
+ cellFormulas?: boolean;
190
225
  }
191
226
  /**
192
227
  * {@link ColumnDefIf.validate}: a message for an invalid value, `undefined` (or `null`, `""`) for a valid one.
@@ -0,0 +1,18 @@
1
+ import { ColumnDefIf } from './column-def.if.js';
2
+
3
+ /**
4
+ * `editable` of a column that `ColumnDef.create()` got without `editable`: read only (Excel-style editing with
5
+ * `defaultEditable` may edit it). An own `editable` set later – also `FalseFn` – replaces it.
6
+ *
7
+ * @returns {boolean} false
8
+ * @internal
9
+ */
10
+ export declare const DEFAULTED_EDITABLE: () => boolean;
11
+ /**
12
+ * True if the column has no own `editable` (`undefined`, or the default of `ColumnDef.create`).
13
+ *
14
+ * @param {ColumnDefIf} def - the column
15
+ * @returns {boolean} true without own `editable`
16
+ * @internal
17
+ */
18
+ export declare function hasDefaultEditable(def: ColumnDefIf): boolean;
@@ -1,3 +1,5 @@
1
+ import { GeEditEvent } from './data/common/event/ge-edit-event.js';
2
+ import { GeUndoEvent } from './data/common/event/ge-undo-event.js';
1
3
  import { GeDetailEvent } from './data/common/event/ge-detail-event.js';
2
4
  import { GeModelChangeEvent } from './data/common/event/ge-model-change-event.js';
3
5
  import { GeMouseEvent } from './data/common/event/ge-mouse-event.js';
@@ -43,4 +45,8 @@ export declare class EventAdapter implements EventListenerIf {
43
45
  onBatchEditChanged(_evt: GeBatchEditEvent): void;
44
46
  /** @since 1.1.97 */
45
47
  onDetailExpandedChanged(_evt: GeDetailEvent): void;
48
+ /** @since 1.1.99 */
49
+ onEditingChanged(_evt: GeEditEvent): void;
50
+ /** @since 1.1.99 */
51
+ onUndoStackChanged(_evt: GeUndoEvent): void;
46
52
  }
@@ -0,0 +1,10 @@
1
+ import { EventListenerIf } from './event-listener.if.js';
2
+
3
+ /**
4
+ * The event listener of a table: the listener given to the constructor plus the listeners of
5
+ * {@link TableApi.subscribe}. Without subscribers every call goes to the main listener exactly as before
6
+ * (`listener.onX` is the main listener's member, also `undefined`).
7
+ *
8
+ * Not exported: an internal of {@link TableScope}.
9
+ */
10
+ export declare function createEventListenerHub(main: EventListenerIf, subscribers: Set<Partial<EventListenerIf>>): EventListenerIf;
@@ -1,3 +1,5 @@
1
+ import { GeEditEvent } from './data/common/event/ge-edit-event.js';
2
+ import { GeUndoEvent } from './data/common/event/ge-undo-event.js';
1
3
  import { GeDetailEvent } from './data/common/event/ge-detail-event.js';
2
4
  import { GeMouseEvent } from './data/common/event/ge-mouse-event.js';
3
5
  import { GeModelChangeEvent } from './data/common/event/ge-model-change-event.js';
@@ -102,4 +104,18 @@ export interface EventListenerIf extends EventFocusChangedListenerIf, EventSelec
102
104
  * @since 1.1.97
103
105
  */
104
106
  onDetailExpandedChanged?(evt: GeDetailEvent): void;
107
+ /**
108
+ * The cell editor opened, its text changed (Excel-style editing), it committed or it was cancelled. Optional.
109
+ *
110
+ * @param {GeEditEvent} evt - type, cell, mode, editor text
111
+ * @since 1.1.99
112
+ */
113
+ onEditingChanged?(evt: GeEditEvent): void;
114
+ /**
115
+ * The undo history changed (undo and redo, {@link TableOptionsIf.undo}) – to enable and label own buttons. Optional.
116
+ *
117
+ * @param {GeUndoEvent} evt - can undo/redo, labels, size
118
+ * @since 1.1.99
119
+ */
120
+ onUndoStackChanged?(evt: GeUndoEvent): void;
105
121
  }
@@ -38,7 +38,7 @@ import { PivotTableModel } from '../pivot/pivot-table-model.js';
38
38
  * });
39
39
  * select.addEventListener("change", () => tableApi.setPivotConfig({ columnFields: [select.value] }));
40
40
  *
41
- * @see Training: [Pivot tables](https://gui.expert/training/pivot-tables/)
41
+ * @see [Live demo: pivot tables](https://gui.expert/showcase/pivot/run/) · Training: [Pivot tables](https://gui.expert/training/pivot-tables/)
42
42
  *
43
43
  * @since 1.1.94
44
44
  * @category Pivot
@@ -31,7 +31,7 @@ import { RowGroupTableModelParaIf } from './row-group-table-model-para.if.js';
31
31
  * });
32
32
  * select.addEventListener("change", () => tableApi.setRowGroupBy(select.value.split(",")));
33
33
  *
34
- * @see Training: [Row grouping](https://gui.expert/training/row-grouping/)
34
+ * @see [Live demo: row grouping](https://gui.expert/showcase/rowgrouping/run/) · Training: [Row grouping](https://gui.expert/training/row-grouping/)
35
35
  *
36
36
  * @since 1.1.94
37
37
  * @category Row grouping
@@ -54,6 +54,7 @@ export interface CreateTableModelPara {
54
54
  * footerAggregates: { quantity: "sum", total: "sum" } // footer: "100,000 rows" | … | 549,812 | 27,481,033.5
55
55
  * });
56
56
  *
57
+ * @see [Live demo: totals & aggregation](https://gui.expert/showcase/aggregation/run/) · Training: [Totals in one option](https://gui.expert/training/footer-totals/#built-in)
57
58
  * @since 1.1.94
58
59
  */
59
60
  footerAggregates: AggregateFooterConfig;
@@ -75,6 +76,7 @@ export interface CreateTableModelPara {
75
76
  * @example
76
77
  * const tableModel = TableFactory.createTableModel({ rows: orders, columnDefs, rowNumbersVisible: true });
77
78
  *
79
+ * @see [Live demo: row numbers](https://gui.expert/showcase/rownumbers/run/) · Training: [Row numbers](https://gui.expert/training/fixed-columns/#row-numbers)
78
80
  * @since 1.1.93
79
81
  */
80
82
  rowNumbersVisible: boolean | Partial<RowNumberOptionsIf>;
@@ -86,9 +88,21 @@ export interface CreateTableModelPara {
86
88
  * @example
87
89
  * const tableModel = TableFactory.createTableModel({ rows: orders, rowDrag: true });
88
90
  *
91
+ * @see [Live demo: row drag](https://gui.expert/showcase/rowdrag/run/) · Training: [Dragging rows into order](https://gui.expert/training/events-and-context-menu/#row-drag)
89
92
  * @since 1.1.95
90
93
  */
91
94
  rowDrag: boolean;
95
+ /**
96
+ * Column letters `A, B, …` as an extra header row above the header labels (like a spreadsheet; for cell formulas,
97
+ * {@link TableOptionsIf.cellFormulas}). A click on a letter selects the column (selection type `"range"`).
98
+ * Row number and checkbox columns get no letter. Only with the default header (labels or `headerData`).
99
+ *
100
+ * @example
101
+ * const tableModel = TableFactory.createTableModel({ rows, columnDefs, rowNumbersVisible: { mode: "original" }, columnLetters: true });
102
+ *
103
+ * @since 1.1.99
104
+ */
105
+ columnLetters: boolean;
92
106
  /** Row heights of header, body and footer in px. Default: `tableOptions.defaultRowHeights`, otherwise 34 / 34 / 34. */
93
107
  defaultRowHeights: DefaultRowHeightsIf;
94
108
  /** The columns: property, header label, width, classes, renderers, sorting, editing. See {@link ColumnDef}. */
@@ -2,6 +2,10 @@
2
2
  * A node of a compiled formula (abstract syntax tree). Read-only; the evaluator walks it – no code is generated
3
3
  * (no `eval`, no `new Function`).
4
4
  *
5
+ * Cell formulas (since 1.1.99, spreadsheet mode) add cell references (`ref`), ranges (`range`), error literals
6
+ * (`error`, e.g. `#REF!` after deleting rows) and the percent operator (`unary` with `"%"`); the formulas of
7
+ * calculated columns never contain them.
8
+ *
5
9
  * @example
6
10
  * const ast = compileFormula("[price] * 2").ast;
7
11
  * // { kind: "binary", op: "*", left: { kind: "field", name: "price" }, right: { kind: "literal", value: 2 } }
@@ -11,13 +15,13 @@
11
15
  */
12
16
  export type FormulaNode = {
13
17
  readonly kind: "literal";
14
- readonly value: number | string | boolean;
18
+ readonly value: number | string | boolean | null;
15
19
  } | {
16
20
  readonly kind: "field";
17
21
  readonly name: string;
18
22
  } | {
19
23
  readonly kind: "unary";
20
- readonly op: "-" | "+";
24
+ readonly op: "-" | "+" | "%";
21
25
  readonly operand: FormulaNode;
22
26
  } | {
23
27
  readonly kind: "binary";
@@ -28,7 +32,33 @@ export type FormulaNode = {
28
32
  readonly kind: "call";
29
33
  readonly name: string;
30
34
  readonly args: readonly FormulaNode[];
35
+ } | FormulaRefNode | {
36
+ readonly kind: "range";
37
+ readonly from: FormulaRefNode;
38
+ readonly to: FormulaRefNode;
39
+ } | {
40
+ readonly kind: "error";
41
+ readonly code: string;
42
+ readonly message?: string;
43
+ readonly text?: string;
31
44
  };
45
+ /**
46
+ * A cell reference of a cell formula: row and column 0-based (`B3` = row 2, column 1), `$` = absolute. In a range a
47
+ * whole column (`A:A`) has `row: -1`, a whole row (`3:3`) has `col: -1`.
48
+ *
49
+ * @example
50
+ * const ref: FormulaRefNode = { kind: "ref", row: 2, col: 1, absRow: true, absCol: false }; // B$3
51
+ *
52
+ * @since 1.1.99
53
+ * @category Spreadsheet
54
+ */
55
+ export interface FormulaRefNode {
56
+ readonly kind: "ref";
57
+ readonly row: number;
58
+ readonly col: number;
59
+ readonly absRow: boolean;
60
+ readonly absCol: boolean;
61
+ }
32
62
  /**
33
63
  * The binary operators of a formula: arithmetic (`+ - * / ^`), text concatenation (`&`) and comparisons
34
64
  * (`=`/`==`, `<>`/`!=`, `<`, `<=`, `>`, `>=`; normalized to `=` and `<>`).
@@ -8,12 +8,14 @@
8
8
  * | `#VALUE!` | wrong type, e.g. `"abc" * 2` |
9
9
  * | `#DIV/0!` | division by zero |
10
10
  * | `#NUM!` | the result is not a finite number (`SQRT(-1)`, overflow) |
11
- * | `#CIRC!` | circular reference between calculated columns |
11
+ * | `#CIRC!` | circular reference between calculated columns (cell formulas: between cells) |
12
+ * | `#REF!` | cell formulas: a reference to a deleted or non-existing cell (since 1.1.99) |
13
+ * | `#N/A` | cell formulas: a lookup found nothing, `NA()` (since 1.1.99) |
12
14
  *
13
15
  * @since 1.1.95
14
16
  * @category Calculated columns & formulas
15
17
  */
16
- export type FormulaErrorCode = "#ERROR!" | "#NAME?" | "#VALUE!" | "#DIV/0!" | "#NUM!" | "#CIRC!";
18
+ export type FormulaErrorCode = "#ERROR!" | "#NAME?" | "#VALUE!" | "#DIV/0!" | "#NUM!" | "#CIRC!" | "#REF!" | "#N/A";
17
19
  /**
18
20
  * An error value of a formula. Formulas never throw: a cell shows the {@link FormulaErrorCode} (`toString()`), the
19
21
  * table adds the CSS class `ge-table-cell-error` and shows the message as tooltip. Errors propagate through
@@ -6,5 +6,8 @@ export declare const MAX_FORMULA_LENGTH = 10000;
6
6
  export declare const MAX_FORMULA_DEPTH = 64;
7
7
  /** The maximum number of binary operators (a long chain is a deep tree, too). */
8
8
  export declare const MAX_FORMULA_OPERATORS = 1000;
9
- /** Parses a formula into an AST. Throws a {@link FormulaSyntaxError}. */
10
- export declare function parseFormula(source: string): FormulaNode;
9
+ /**
10
+ * Parses a formula into an AST. Throws a {@link FormulaSyntaxError}. `references`: a cell formula with Excel's syntax
11
+ * (cell references, ranges, `%`, `;`, Excel's precedence of the negation) – since 1.1.99.
12
+ */
13
+ export declare function parseFormula(source: string, references?: boolean): FormulaNode;
@@ -1,7 +1,7 @@
1
1
  import { FormulaError } from './formula-error.js';
2
2
 
3
3
  /** The kinds of tokens of a formula. */
4
- export type FormulaTokenKind = "number" | "string" | "field" | "ident" | "op" | "(" | ")" | "," | "eof";
4
+ export type FormulaTokenKind = "number" | "string" | "field" | "ident" | "op" | "(" | ")" | "," | "error" | "eof";
5
5
  /** One token: kind, text (number/string already decoded) and position in the source. */
6
6
  export interface FormulaToken {
7
7
  readonly kind: FormulaTokenKind;
@@ -18,5 +18,8 @@ export declare class FormulaSyntaxError extends Error {
18
18
  /**
19
19
  * Splits a formula into tokens. Whitespace is ignored. Throws a {@link FormulaSyntaxError} for an unknown character,
20
20
  * an unterminated string or field reference.
21
+ *
22
+ * `references` (cell formulas, since 1.1.99): Excel's rules – texts only in `"…"` with `""` as quotation mark, `$` in
23
+ * identifiers (`$B$3`), `:` and `%`, `;` as argument separator, error literals like `#REF!`.
21
24
  */
22
- export declare function tokenize(source: string): FormulaToken[];
25
+ export declare function tokenize(source: string, references?: boolean): FormulaToken[];
@@ -11,6 +11,14 @@ import { TableScope } from './table-scope.js';
11
11
  export declare class InputHandler {
12
12
  protected tableScope: TableScope;
13
13
  constructor(tableScope: TableScope);
14
+ /**
15
+ * A restored in-cell editor (its text was put back after a repaint, see {@link RenderScope.setEditorDraft}) fires
16
+ * no "change" for that text – it is committed when the focus leaves it (not when a repaint removes it).
17
+ */
18
+ private onHostElementFocusOut;
19
+ private commitInCellEditor;
20
+ /** Text typed into the in-cell editor: remembered, so that a repaint (scrolling, live data) keeps it (since 1.1.99). */
21
+ private onHostElementInput;
14
22
  /** Escape in the cell editor cancels the editing: the old value stays, nothing is committed. */
15
23
  private onHostElementKeyDown;
16
24
  /**
@@ -215,6 +215,15 @@ export declare class MasterDetailService {
215
215
  /** The mouse wheel over a detail row: scrolls the outer table if nothing in the detail row takes the movement. */
216
216
  private onWheel;
217
217
  private canScrollInside;
218
+ /**
219
+ * True if Tab on the master row `rowIndex` goes into its open detail row (a focusable element in it) – Excel-style
220
+ * editing then leaves Tab to this service.
221
+ *
222
+ * @param {number} rowIndex - display row index of the focused cell
223
+ * @returns {boolean} true with a tab target
224
+ * @since 1.1.99
225
+ */
226
+ hasTabTarget(rowIndex: number): boolean;
218
227
  /** Tab on a master row with an open detail row: the focus moves to the first focusable element in it. */
219
228
  private onHostKeyDown;
220
229
  /** The host got the focus back from a detail row (Shift+Tab): its master row gets the focus. */
@@ -1,6 +1,7 @@
1
1
  import { RowDragService } from './row-drag/row-drag-service.js';
2
2
  import { BatchEditService } from './batch-edit/batch-edit-service.js';
3
3
  import { FillHandleService } from './fill/fill-handle-service.js';
4
+ import { CellEditorService } from './sheet-editing/cell-editor-service.js';
4
5
  import { TableOverlayChange } from './overlay/table-overlay.js';
5
6
  import { EleScope } from './ele-scope.js';
6
7
  import { TableModelIf } from './data/tablemodel/table-model.if.js';
@@ -28,6 +29,7 @@ import { AriaGridInfo } from './aria/aria-grid-info.js';
28
29
  import { AriaTextsIf } from './aria/aria-texts.if.js';
29
30
  import { RowLayout } from './row-layout/row-layout.js';
30
31
  import { MasterDetailService } from './master-detail/master-detail-service.js';
32
+ import { TableSheet } from './sheet/table-sheet.js';
31
33
 
32
34
  /** @category Internals */
33
35
  export declare class RenderScope extends EleScope {
@@ -105,12 +107,28 @@ export declare class RenderScope extends EleScope {
105
107
  * @since 1.1.96
106
108
  */
107
109
  fillHandleService?: FillHandleService;
110
+ /**
111
+ * Excel-style editing of this table (the editor above the cell) – created by {@link TableScope} with
112
+ * `tableOptions.editing`.
113
+ * @since 1.1.99
114
+ */
115
+ cellEditorService?: CellEditorService;
116
+ /**
117
+ * The text of the open in-cell editor (`getEditRenderer`): the cell is rebuilt on every repaint, the text and
118
+ * the caret are put back (before 1.1.99 the typed text was lost when the table scrolled or repainted).
119
+ */
120
+ private editorDraft?;
108
121
  /**
109
122
  * Master/detail of this table (detail rows below master rows) – created by {@link TableScope} with
110
123
  * `tableOptions.masterDetail`.
111
124
  * @since 1.1.97
112
125
  */
113
126
  masterDetailService?: MasterDetailService;
127
+ /**
128
+ * Cell formulas of this table – created by {@link TableScope} with `tableOptions.cellFormulas` (flat bodies).
129
+ * @since 1.1.99
130
+ */
131
+ tableSheet?: TableSheet;
114
132
  /** Positions of the body rows (prefix sums of the heights + detail rows), see {@link getBodyRowLayout}. */
115
133
  private readonly bodyRowLayout;
116
134
  private bodyRowLayoutDirty;
@@ -221,6 +239,23 @@ export declare class RenderScope extends EleScope {
221
239
  */
222
240
  getScrollerToContentRatioY(): number;
223
241
  isEditing(): boolean;
242
+ /**
243
+ * The cell of the open editor inside a cell (`getEditRenderer`, the way before Excel-style editing).
244
+ *
245
+ * @returns {[number, number] | undefined} display row and model column, `undefined` without such an editor
246
+ * @since 1.1.99
247
+ */
248
+ getInCellEditorCell(): [number, number] | undefined;
249
+ /**
250
+ * Remembers the text of the open in-cell editor (called on every input, see {@link InputHandler}) so that a
251
+ * repaint keeps it.
252
+ *
253
+ * @param {number} rowIndex - display row index of the edited cell
254
+ * @param {number} columnIndex - model column index
255
+ * @param {HTMLInputElement | HTMLTextAreaElement} input - the editor element
256
+ * @since 1.1.99
257
+ */
258
+ setEditorDraft(rowIndex: number, columnIndex: number, input: HTMLInputElement | HTMLTextAreaElement): void;
224
259
  /**
225
260
  * Resets the editor renderer by clearing its values and state.
226
261
  *
@@ -327,6 +362,11 @@ export declare class RenderScope extends EleScope {
327
362
  * @returns {void}
328
363
  */
329
364
  updateCells(events: TableCellUpdateEventIf[], repaintAll?: boolean): void;
365
+ /**
366
+ * Writes a value without the column's `editInputPipe` (values copied inside the table are already converted – a pipe
367
+ * that expects text could break them). All area models apply the pipe in `setValue`, so it is left out for the call.
368
+ */
369
+ protected setRawValue(rowIndex: number, columnIndex: number, value: unknown): boolean;
330
370
  /**
331
371
  * After `updateCells()` without a repaint: draws the rendered cells of calculated and „Show values as“ columns of
332
372
  * the body again (they depend on the changed cells, e.g. `total = price * quantity` or a share of the total).
@@ -42,9 +42,10 @@ export declare class RowDragService {
42
42
  isDragSourceRow(rowIndex: number): boolean;
43
43
  /**
44
44
  * Why a managed drag is not possible right now: `"sorted"` (a column has the sort state asc/desc), `"filtered"`
45
- * (a filter hides rows) – `undefined` if it is possible or the drag is unmanaged.
45
+ * (a filter hides rows), `"cellFormulas"` (moved rows would change the references of cell formulas, since 1.1.99)
46
+ * – `undefined` if it is possible or the drag is unmanaged.
46
47
  */
47
- getBlockReason(): "sorted" | "filtered" | undefined;
48
+ getBlockReason(): "sorted" | "filtered" | "cellFormulas" | undefined;
48
49
  /**
49
50
  * The drag handle of a body cell: none (no `rowDrag`, a group or pivot row, a managed drag the model cannot do),
50
51
  * enabled or disabled (managed + sorted/filtered).
@@ -20,6 +20,10 @@ export declare class SelectionService implements OnActionTriggeredIf {
20
20
  protected anchorRanges: CellRange[];
21
21
  /** The selection before a Ctrl/⌘-drag – each drag frame replaces only the dragged rectangle. */
22
22
  protected dragSnapshot?: SelectionSnapshot;
23
+ /** The cell a Shift+click or Shift+arrow range starts at (the last click, or the active cell). @since 1.1.99 */
24
+ protected anchor?: [number, number];
25
+ /** The moving corner of the range of Shift+arrows (Excel); `undefined` = the anchor. @since 1.1.99 */
26
+ protected extent?: [number, number];
23
27
  constructor(tableScope: TableScope);
24
28
  /**
25
29
  * Called on mouse down: a new gesture starts.
@@ -51,8 +55,52 @@ export declare class SelectionService implements OnActionTriggeredIf {
51
55
  */
52
56
  onMouseClicked(evt: GeMouseEvent, _previousEvt: GeMouseEvent | undefined): boolean;
53
57
  onActionTriggered(actionId: ActionId): boolean;
58
+ /**
59
+ * The cell a Shift+click or Shift+arrow range starts at: the last clicked cell or the active cell set by the
60
+ * keyboard ({@link collapseTo}).
61
+ *
62
+ * @returns {[number, number] | undefined} row and column, `undefined` before the first click/keyboard move
63
+ * @since 1.1.99
64
+ */
65
+ getAnchor(): [number, number] | undefined;
66
+ /**
67
+ * The moving corner of the range Shift+arrows grow (the anchor if there is none).
68
+ *
69
+ * @returns {[number, number] | undefined} row and column
70
+ * @since 1.1.99
71
+ */
72
+ getExtent(): [number, number] | undefined;
73
+ /**
74
+ * Excel-style editing: the active cell moved (arrow keys, Tab, Enter) – the selection becomes this one cell and it
75
+ * is the new anchor. Selection types other than `"range"`/`"cell"` only get the anchor.
76
+ *
77
+ * @param {number} rowIndex - display row index
78
+ * @param {number} columnIndex - model column index
79
+ * @since 1.1.99
80
+ */
81
+ collapseTo(rowIndex: number, columnIndex: number): void;
82
+ /**
83
+ * Excel-style editing (Shift+arrows): the last range is spanned from the anchor to `(rowIndex, columnIndex)`;
84
+ * other ranges (Ctrl/⌘-clicks) stay. Only for the selection type `"range"`.
85
+ *
86
+ * @param {number} rowIndex - the new moving corner (display row index)
87
+ * @param {number} columnIndex - model column index
88
+ * @returns {CellRange | undefined} the new range, `undefined` without a range selection
89
+ * @since 1.1.99
90
+ */
91
+ extendTo(rowIndex: number, columnIndex: number): CellRange | undefined;
92
+ private static rangeBetween;
54
93
  /** True if the column is a row number column ({@link RowNumberColumnDef}). */
55
94
  private isRowNumberColumn;
95
+ /** True for a cell of a header row with column letters (spreadsheet) – not over row numbers. */
96
+ private isColumnLetterCell;
97
+ /**
98
+ * A click on a column letter (selection type "range"): the whole column – Shift: the columns from the last letter
99
+ * (or the active cell), Ctrl/⌘: added. The active cell goes into the column.
100
+ */
101
+ private clickColumnLetter;
102
+ /** The column of the last click on a letter (Shift+click spans from it). */
103
+ private letterAnchor?;
56
104
  /** A click on the header cell of the row numbers: everything (selection types "row" and "range"). */
57
105
  private selectAllByRowNumberHeader;
58
106
  /** Selection type "range", click on a row number: the whole row – new, toggled (Ctrl/⌘) or removed (Ctrl/⌘+Alt). */
@@ -14,4 +14,10 @@ export interface ExcelExportOptionsIf {
14
14
  * {@link TableApi.downloadExcel} sets it for a right-to-left table ({@link TableOptionsIf.direction}).
15
15
  */
16
16
  rightToLeft?: boolean;
17
+ /**
18
+ * {@link TableApi.downloadExcel}: cell formulas ({@link TableOptionsIf.cellFormulas}) become Excel formulas with their
19
+ * calculated values (otherwise: values). Only if the export is the sheet itself – no filter hides rows, no sorting,
20
+ * every data column visible; otherwise values and a warning. Since 1.1.99.
21
+ */
22
+ cellFormulas?: boolean;
17
23
  }
@@ -27,6 +27,8 @@ import { ExcelServiceIf } from './excel-service.if.js';
27
27
  export declare class ExcelService implements ExcelServiceIf {
28
28
  /** Understands cells `{ value, numberFormat }` ({@link ExcelFormattedValueIf}), since 1.1.95. */
29
29
  readonly supportsNumberFormats = true;
30
+ /** Understands cells `{ formula, value }` ({@link ExcelFormulaCellIf}), since 1.1.99. */
31
+ readonly supportsFormulas = true;
30
32
  /**
31
33
  * Downloads a matrix data as an Excel file.
32
34
  *
@@ -52,6 +54,8 @@ export declare class ExcelService implements ExcelServiceIf {
52
54
  createExcelBlob(matrix: Array<Array<any>>, author?: string, options?: ExcelExportOptionsIf): Promise<Blob>;
53
55
  private generateMap;
54
56
  private getX1WorksheetsSheet1Xml;
57
+ /** A formula cell: `<f>` plus the cached value with its type (`str`, `b`, `e`; numbers and dates without). */
58
+ private formulaCellXml;
55
59
  /** Number format → cell style index (1-based; 0 = default), filled by withNumberFormats() before the sheet is written. */
56
60
  private numberFormatStyles;
57
61
  /** Adds one cell style per number format used in the matrix (`<numFmts>` + `<cellXfs>`); unchanged without formats. */
@@ -15,7 +15,42 @@ export interface ExcelServiceIf {
15
15
  * otherwise a service gets plain numbers (since 1.1.95).
16
16
  */
17
17
  readonly supportsNumberFormats?: boolean;
18
+ /**
19
+ * True if the service understands cells of the form {@link ExcelFormulaCellIf} (`{ formula, value }`). Only then
20
+ * {@link TableApi.downloadExcel} with `{ cellFormulas: true }` exports cell formulas as formulas (since 1.1.99).
21
+ */
22
+ readonly supportsFormulas?: boolean;
23
+ }
24
+ /**
25
+ * A cell of an Excel matrix with a formula (`<f>`) and its calculated value (`<v>`, shown until Excel recalculates).
26
+ * Understood by {@link ExcelService}; {@link TableApi.downloadExcel} writes them for cell formulas with
27
+ * `{ cellFormulas: true }`.
28
+ *
29
+ * @example
30
+ * await new ExcelService().downloadExcel([[2, 3, { formula: "A1*B1", value: 6 }]], "sheet.xlsx");
31
+ *
32
+ * @since 1.1.99
33
+ * @category Export & clipboard
34
+ */
35
+ export interface ExcelFormulaCellIf {
36
+ /** The formula without `=`, with Excel's function names (`"SUM(D2:D4)"`, `"_xlfn.XLOOKUP(…)"`). */
37
+ formula: string;
38
+ /** The calculated value: a number, text, boolean, `Date` or an error value. */
39
+ value: unknown;
18
40
  }
41
+ /**
42
+ * True for a cell of the form {@link ExcelFormulaCellIf}.
43
+ *
44
+ * @param {unknown} cell - a cell of an Excel matrix
45
+ * @returns {boolean} whether it is a formula cell
46
+ *
47
+ * @example
48
+ * isExcelFormulaCell({ formula: "A1*2", value: 4 }); // true
49
+ *
50
+ * @since 1.1.99
51
+ * @category Export & clipboard
52
+ */
53
+ export declare function isExcelFormulaCell(cell: unknown): cell is ExcelFormulaCellIf;
19
54
  /**
20
55
  * A cell of an Excel matrix with a number format, e.g. a share shown as percentage. Understood by
21
56
  * {@link ExcelService} (`supportsNumberFormats`).