@guiexpert/table 1.1.97 → 1.1.99

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 (110) hide show
  1. package/README.md +12 -0
  2. package/css/main.css +381 -27
  3. package/css/table-classes.css +33 -9
  4. package/css/table-clipboard.css +41 -0
  5. package/css/table-color-vars.css +56 -0
  6. package/css/table-fill-batch.css +9 -2
  7. package/css/table-master-detail.css +20 -0
  8. package/css/table-sheet-editing.css +149 -0
  9. package/css/table-spreadsheet.css +50 -0
  10. package/css/table-tree.css +23 -16
  11. package/index.cjs +54 -67
  12. package/index.d.ts +52 -0
  13. package/index.js +18968 -11475
  14. package/lib/table/action/action-id.type.d.ts +1 -1
  15. package/lib/table/action/shortcut.service.d.ts +9 -0
  16. package/lib/table/aria/aria-texts.d.ts +26 -0
  17. package/lib/table/aria/aria-texts.if.d.ts +196 -0
  18. package/lib/table/batch-edit/batch-edit-service.d.ts +22 -0
  19. package/lib/table/batch-edit/cell-change.if.d.ts +6 -2
  20. package/lib/table/batch-edit/pending-cell-changes.d.ts +7 -0
  21. package/lib/table/batch-edit/write-row-value.d.ts +14 -0
  22. package/lib/table/calc/column-values.d.ts +2 -0
  23. package/lib/table/clipboard/clipboard-html.d.ts +41 -0
  24. package/lib/table/clipboard/clipboard-keymap.d.ts +18 -0
  25. package/lib/table/clipboard/clipboard-options.d.ts +30 -0
  26. package/lib/table/clipboard/clipboard-options.if.d.ts +67 -0
  27. package/lib/table/clipboard/clipboard-service.d.ts +122 -0
  28. package/lib/table/clipboard/input-pipes.d.ts +59 -0
  29. package/lib/table/clipboard/paste-plan.d.ts +96 -0
  30. package/lib/table/clipboard/tsv.d.ts +31 -0
  31. package/lib/table/crud/crud-object-edit.d.ts +2 -0
  32. package/lib/table/crud/crud-object-view.d.ts +2 -0
  33. package/lib/table/crud/crud-table-model-factory.d.ts +2 -0
  34. package/lib/table/data/common/event/ge-edit-event.d.ts +46 -0
  35. package/lib/table/data/common/event/ge-row-drag-event.d.ts +2 -2
  36. package/lib/table/data/common/event/ge-undo-event.d.ts +29 -0
  37. package/lib/table/data/options/table-options.d.ts +34 -0
  38. package/lib/table/data/options/table-options.if.d.ts +116 -1
  39. package/lib/table/data/tablemodel/areamodel/abstract-area-model.d.ts +11 -2
  40. package/lib/table/data/tablemodel/areamodel/area-model-array-of-arrays.d.ts +14 -0
  41. package/lib/table/data/tablemodel/areamodel/area-model-object-array.d.ts +14 -0
  42. package/lib/table/data/tablemodel/areamodel/area-model.if.d.ts +11 -0
  43. package/lib/table/data/tablemodel/column/column-def.d.ts +13 -0
  44. package/lib/table/data/tablemodel/column/column-def.if.d.ts +36 -1
  45. package/lib/table/data/tablemodel/column/default-editable.d.ts +18 -0
  46. package/lib/table/ele-scope.d.ts +37 -0
  47. package/lib/table/event-adapter.d.ts +6 -0
  48. package/lib/table/event-listener-hub.d.ts +10 -0
  49. package/lib/table/event-listener.if.d.ts +16 -0
  50. package/lib/table/factory/pivot-factory.d.ts +1 -1
  51. package/lib/table/factory/row-group-factory.d.ts +1 -1
  52. package/lib/table/factory/table-factory.d.ts +14 -0
  53. package/lib/table/formula/formula-ast.if.d.ts +32 -2
  54. package/lib/table/formula/formula-error.d.ts +4 -2
  55. package/lib/table/formula/parser.d.ts +5 -2
  56. package/lib/table/formula/tokenizer.d.ts +5 -2
  57. package/lib/table/input-handler.d.ts +8 -0
  58. package/lib/table/master-detail/master-detail-service.d.ts +9 -0
  59. package/lib/table/render-scope.d.ts +40 -0
  60. package/lib/table/row-drag/row-drag-service.d.ts +3 -2
  61. package/lib/table/rtl/rtl-util.d.ts +126 -0
  62. package/lib/table/rtl/table-direction.type.d.ts +23 -0
  63. package/lib/table/selection/selection-service.d.ts +48 -0
  64. package/lib/table/service/convenience-dom.service.d.ts +49 -1
  65. package/lib/table/service/excel-export-options.if.d.ts +23 -0
  66. package/lib/table/service/excel-service.d.ts +12 -2
  67. package/lib/table/service/excel-service.if.d.ts +38 -1
  68. package/lib/table/sheet/cell-address.d.ts +100 -0
  69. package/lib/table/sheet/cell-formula-options.d.ts +27 -0
  70. package/lib/table/sheet/cell-formula-options.if.d.ts +27 -0
  71. package/lib/table/sheet/excel-formula.d.ts +20 -0
  72. package/lib/table/sheet/format-formula.d.ts +19 -0
  73. package/lib/table/sheet/sheet-cells.if.d.ts +17 -0
  74. package/lib/table/sheet/sheet-compiler.d.ts +47 -0
  75. package/lib/table/sheet/sheet-engine.d.ts +207 -0
  76. package/lib/table/sheet/sheet-function-info.d.ts +25 -0
  77. package/lib/table/sheet/sheet-functions.d.ts +27 -0
  78. package/lib/table/sheet/sheet-values.d.ts +154 -0
  79. package/lib/table/sheet/shift-formula.d.ts +71 -0
  80. package/lib/table/sheet/table-sheet.d.ts +214 -0
  81. package/lib/table/sheet-editing/cell-editor-service.d.ts +105 -0
  82. package/lib/table/sheet-editing/cell-editor.if.d.ts +110 -0
  83. package/lib/table/sheet-editing/editing-keymap.d.ts +17 -0
  84. package/lib/table/sheet-editing/editing-options.d.ts +34 -0
  85. package/lib/table/sheet-editing/editing-options.if.d.ts +49 -0
  86. package/lib/table/sheet-editing/editors/date-cell-editor.d.ts +23 -0
  87. package/lib/table/sheet-editing/editors/number-cell-editor.d.ts +18 -0
  88. package/lib/table/sheet-editing/editors/select-cell-editor.d.ts +36 -0
  89. package/lib/table/sheet-editing/editors/text-cell-editor.d.ts +35 -0
  90. package/lib/table/sheet-editing/formula-assist.d.ts +103 -0
  91. package/lib/table/sheet-editing/formula-text.d.ts +61 -0
  92. package/lib/table/sheet-editing/sheet-navigation.d.ts +26 -0
  93. package/lib/table/spreadsheet/area-model-sheet.d.ts +170 -0
  94. package/lib/table/spreadsheet/formula-bar.d.ts +53 -0
  95. package/lib/table/spreadsheet/spreadsheet-factory.d.ts +111 -0
  96. package/lib/table/spreadsheet/spreadsheet-options.if.d.ts +28 -0
  97. package/lib/table/spreadsheet/spreadsheet-preset.d.ts +37 -0
  98. package/lib/table/spreadsheet/structure-edit.d.ts +35 -0
  99. package/lib/table/table-api.d.ts +533 -4
  100. package/lib/table/table-scope.d.ts +299 -1
  101. package/lib/table/undo/cell-changes-undoable.d.ts +34 -0
  102. package/lib/table/undo/model-rows.d.ts +17 -0
  103. package/lib/table/undo/pending-changes-undoable.d.ts +35 -0
  104. package/lib/table/undo/undo-keymap.d.ts +17 -0
  105. package/lib/table/undo/undo-options.d.ts +26 -0
  106. package/lib/table/undo/undo-options.if.d.ts +30 -0
  107. package/lib/table/undo/undo-service.d.ts +103 -0
  108. package/lib/table/undo/undo-stack.d.ts +62 -0
  109. package/lib/table/undo/undoable.if.d.ts +36 -0
  110. package/package.json +1 -1
@@ -7,6 +7,7 @@ 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 { ColumnEditorOption } from '../../../sheet-editing/cell-editor.if.js';
10
11
  import { ValueGetter, ValueSetter } from '../../../calc/value-getter.type.js';
11
12
  import { ShowValuesAsConfig } from '../../../calc/show-values-as.type.js';
12
13
  import { FormulaOptionsIf } from '../../../formula/formula-options.if.js';
@@ -66,6 +67,12 @@ export declare class ColumnDef implements ColumnDefIf {
66
67
  rowDrag?: RowDragColumnOption;
67
68
  /** Checks edited values, see {@link ColumnDefIf.validate} (since 1.1.96). */
68
69
  validate?: CellValidator;
70
+ /** The editor of Excel-style editing, see {@link ColumnDefIf.editor} (since 1.1.99). */
71
+ editor?: ColumnEditorOption;
72
+ /** The value of a cleared cell, see {@link ColumnDefIf.emptyValue} (since 1.1.99). */
73
+ emptyValue?: unknown;
74
+ /** `false`: no cell formulas in this column, see {@link ColumnDefIf.cellFormulas} (since 1.1.99). */
75
+ cellFormulas?: boolean;
69
76
  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);
70
77
  static bodyRenderer(bodyRenderer: CellRendererIf): AreaObjectMap<CellRendererIf>;
71
78
  /**
@@ -139,5 +146,11 @@ export declare class ColumnDef implements ColumnDefIf {
139
146
  rowDrag?: RowDragColumnOption;
140
147
  /** Checks edited values: a message for an invalid value (since 1.1.96). */
141
148
  validate?: CellValidator;
149
+ /** The editor of Excel-style editing: `"text"`, `"number"`, `"date"` or a factory (since 1.1.99). */
150
+ editor?: ColumnEditorOption;
151
+ /** The value of a cleared cell (Delete) – default `EditingOptionsIf.emptyValue` (since 1.1.99). */
152
+ emptyValue?: unknown;
153
+ /** `false`: `"=…"` stays text in this column of a table with cell formulas (since 1.1.99). */
154
+ cellFormulas?: boolean;
142
155
  }): ColumnDefIf;
143
156
  }
@@ -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;
@@ -7,6 +7,7 @@ import { AriaIds } from './aria/aria-ids.js';
7
7
  import { AreaIdent } from './data/tablemodel/area-ident.type.js';
8
8
  import { SideIdent } from './data/side-ident.type.js';
9
9
  import { TableOverlay } from './overlay/table-overlay.js';
10
+ import { ResolvedTableDirection } from './rtl/table-direction.type.js';
10
11
 
11
12
  /**
12
13
  * Represents a store for HTML elements.
@@ -53,7 +54,43 @@ export declare class EleScope {
53
54
  readonly ariaIds: AriaIds;
54
55
  /** The overlay layer over the body ("Loading…", "No rows to show"). @since 1.1.92 */
55
56
  readonly tableOverlay: TableOverlay;
57
+ /**
58
+ * The resolved writing direction of the table ({@link TableOptionsIf.direction}; `"auto"` is decided when the table
59
+ * is built). @since 1.1.98
60
+ */
61
+ readonly direction: ResolvedTableDirection;
56
62
  constructor(hostElement: HTMLDivElement, tableModel: TableModelIf, dom: ConvenienceDomService, tableOptions: TableOptionsIf);
63
+ /**
64
+ * Whether the table runs from right to left ({@link TableOptionsIf.direction}).
65
+ *
66
+ * @returns {boolean} true for `"rtl"` (also a resolved `"auto"`)
67
+ * @since 1.1.98
68
+ */
69
+ isRtl(): boolean;
70
+ /**
71
+ * The horizontal scroll position of the body as distance from the **start** (≥ 0) – `scrollLeft`, in
72
+ * right-to-left `-scrollLeft`.
73
+ *
74
+ * @returns {number} px
75
+ * @since 1.1.98
76
+ */
77
+ getViewportScrollLeft(): number;
78
+ /**
79
+ * Sets the horizontal scroll position of the body as distance from the **start** (see {@link getViewportScrollLeft}).
80
+ *
81
+ * @param {number} x - px from the start
82
+ * @since 1.1.98
83
+ */
84
+ setViewportScrollLeft(x: number): void;
85
+ /**
86
+ * A client x coordinate (e.g. `PointerEvent.clientX`) as x in the host from the start of its padding box – the
87
+ * coordinates in which the table positions everything (right-to-left: from the right edge).
88
+ *
89
+ * @param {number} clientX - x in client (viewport) coordinates
90
+ * @returns {number} px from the start
91
+ * @since 1.1.98
92
+ */
93
+ clientXToHostX(clientX: number): number;
57
94
  /**
58
95
  * Shows the overlay that fits the current state (requested by the API, or "no rows" for an empty body).
59
96
  * Overwritten in {@link RenderScope}.
@@ -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).
@@ -0,0 +1,126 @@
1
+ import { ResolvedTableDirection, TableDirection } from './table-direction.type.js';
2
+
3
+ /**
4
+ * Decides the direction of a table: `"rtl"` and `"ltr"` as given, `"auto"` from the computed `direction` of the host
5
+ * (inherited from `<html dir="rtl">` or any parent) – for a host that is not in the document yet from the nearest
6
+ * `dir` attribute of the host or a parent. Missing (`undefined`) = `"ltr"`.
7
+ *
8
+ * Must be called before the table sets the `dir` attribute of the host.
9
+ *
10
+ * @param {TableDirection | undefined} direction - the option ({@link TableOptionsIf.direction})
11
+ * @param {HTMLElement} [host] - the host element of the table (needed for `"auto"`)
12
+ * @returns {ResolvedTableDirection} `"ltr"` or `"rtl"`
13
+ *
14
+ * @example
15
+ * resolveTableDirection("auto", document.getElementById("table")!); // "rtl" on a page with <html dir="rtl">
16
+ *
17
+ * @since 1.1.98
18
+ * @category Utilities
19
+ */
20
+ export declare function resolveTableDirection(direction: TableDirection | undefined, host?: HTMLElement): ResolvedTableDirection;
21
+ /**
22
+ * The horizontal scroll position of an element as distance from the **start** (≥ 0): in left-to-right `scrollLeft`,
23
+ * in right-to-left `-scrollLeft` (browsers report 0 at the right start and negative values when scrolled to the left,
24
+ * CSSOM View).
25
+ *
26
+ * @param {{ scrollLeft: number }} element - a scroll container
27
+ * @param {boolean} rtl - the container is right-to-left
28
+ * @returns {number} px from the start
29
+ *
30
+ * @example
31
+ * const fromStart = getLogicalScrollLeft(tableApi.getTableScope().scrollViewport, tableApi.getDirection() === "rtl");
32
+ *
33
+ * @since 1.1.98
34
+ * @category Utilities
35
+ */
36
+ export declare function getLogicalScrollLeft(element: {
37
+ scrollLeft: number;
38
+ }, rtl: boolean): number;
39
+ /**
40
+ * Sets the horizontal scroll position of an element as distance from the **start** (see {@link getLogicalScrollLeft}).
41
+ *
42
+ * @param {{ scrollLeft: number }} element - a scroll container
43
+ * @param {number} x - px from the start
44
+ * @param {boolean} rtl - the container is right-to-left
45
+ *
46
+ * @example
47
+ * setLogicalScrollLeft(tableApi.getTableScope().scrollViewport, 0, true); // back to the (right) start
48
+ *
49
+ * @since 1.1.98
50
+ * @category Utilities
51
+ */
52
+ export declare function setLogicalScrollLeft(element: {
53
+ scrollLeft: number;
54
+ }, x: number, rtl: boolean): void;
55
+ /**
56
+ * The horizontal scroll position for `element.scrollTo(…)` – physical, i.e. negative in right-to-left.
57
+ *
58
+ * @param {number} x - px from the start
59
+ * @param {boolean} rtl - right-to-left
60
+ * @returns {number} the value for `scrollLeft` / `scrollTo()`
61
+ *
62
+ * @example
63
+ * tableApi.getTableScope().scrollViewport.scrollTo(toPhysicalScrollLeft(200, true), 0); // 200 px from the right start
64
+ *
65
+ * @since 1.1.98
66
+ * @category Utilities
67
+ */
68
+ export declare function toPhysicalScrollLeft(x: number, rtl: boolean): number;
69
+ /**
70
+ * Whether a scroll container can still scroll horizontally by `dx` (physical: `dx > 0` = to the right) – for
71
+ * left-to-right and right-to-left containers alike.
72
+ *
73
+ * @param {{ scrollLeft: number, scrollWidth: number, clientWidth: number }} element - a scroll container
74
+ * @param {number} dx - physical delta (e.g. `WheelEvent.deltaX`)
75
+ * @param {boolean} rtl - the container is right-to-left
76
+ * @returns {boolean} true if a scroll by `dx` would move the content
77
+ *
78
+ * @example
79
+ * host.addEventListener("wheel", e => {
80
+ * const takesIt = canScrollHorizontally(host, e.deltaX, getComputedStyle(host).direction === "rtl");
81
+ * console.info(takesIt ? "the element scrolls itself" : "pass it on");
82
+ * });
83
+ *
84
+ * @since 1.1.98
85
+ * @category Utilities
86
+ */
87
+ export declare function canScrollHorizontally(element: {
88
+ scrollLeft: number;
89
+ scrollWidth: number;
90
+ clientWidth: number;
91
+ }, dx: number, rtl: boolean): boolean;
92
+ /**
93
+ * A client x coordinate (e.g. `PointerEvent.clientX`) as position in a box measured from the box's **start**:
94
+ * left-to-right from its left edge, right-to-left from its right edge.
95
+ *
96
+ * @param {number} clientX - x in client (viewport) coordinates
97
+ * @param {number} boxLeft - the left edge of the box in client coordinates
98
+ * @param {number} boxWidth - the width of the box
99
+ * @param {boolean} rtl - right-to-left
100
+ * @returns {number} px from the start of the box
101
+ *
102
+ * @example
103
+ * host.addEventListener("pointerdown", e => {
104
+ * const r = host.getBoundingClientRect();
105
+ * console.info(toLogicalX(e.clientX, r.left + host.clientLeft, host.clientWidth, true)); // px from the right edge
106
+ * });
107
+ *
108
+ * @since 1.1.98
109
+ * @category Utilities
110
+ */
111
+ export declare function toLogicalX(clientX: number, boxLeft: number, boxWidth: number, rtl: boolean): number;
112
+ /**
113
+ * Swaps the arrow keys "left" and "right" in a harmonized shortcut (e.g. `"cmd left"` → `"cmd right"`) – the
114
+ * keyboard handling of a right-to-left table, so that → moves backwards in reading direction.
115
+ *
116
+ * @param {string} shortcut - a harmonized shortcut (`harmonizeShortcut`)
117
+ * @returns {string} the shortcut with swapped arrow keys
118
+ *
119
+ * @example
120
+ * mirrorArrowKeys("left"); // "right"
121
+ * mirrorArrowKeys("cmd right"); // "cmd left"
122
+ *
123
+ * @since 1.1.98
124
+ * @category Keyboard
125
+ */
126
+ export declare function mirrorArrowKeys(shortcut: string): string;