@pixerate/editor 0.24.0 → 0.26.0

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 (162) hide show
  1. package/README.md +101 -1
  2. package/THIRD_PARTY_NOTICES.md +40 -0
  3. package/dist/agent/index.cjs +175 -11
  4. package/dist/agent/index.cjs.map +1 -1
  5. package/dist/agent/index.d.cts +18 -4
  6. package/dist/agent/index.d.ts +18 -4
  7. package/dist/agent/index.js +168 -4
  8. package/dist/agent/index.js.map +1 -1
  9. package/dist/{arrangeShortcuts-B8O3f8-P.d.cts → arrange-BICutYPk.d.cts} +243 -29
  10. package/dist/{arrangeShortcuts-sLlD2rSX.d.ts → arrange-BICutYPk.d.ts} +243 -29
  11. package/dist/builtins-CdPcLwwF.d.cts +176 -0
  12. package/dist/builtins-Chj6zv_O.d.ts +176 -0
  13. package/dist/canvas/index.cjs +8588 -1857
  14. package/dist/canvas/index.cjs.map +1 -1
  15. package/dist/canvas/index.d.cts +1847 -9
  16. package/dist/canvas/index.d.ts +1847 -9
  17. package/dist/canvas/index.js +8577 -1846
  18. package/dist/canvas/index.js.map +1 -1
  19. package/dist/chunk-3CC7OPUQ.cjs +831 -0
  20. package/dist/chunk-3CC7OPUQ.cjs.map +1 -0
  21. package/dist/chunk-4BVP64JJ.cjs +1406 -0
  22. package/dist/chunk-4BVP64JJ.cjs.map +1 -0
  23. package/dist/chunk-BVP3TSLH.cjs +69 -0
  24. package/dist/chunk-BVP3TSLH.cjs.map +1 -0
  25. package/dist/{chunk-OLZJXL4R.cjs → chunk-CS6NZWWA.cjs} +59 -25
  26. package/dist/chunk-CS6NZWWA.cjs.map +1 -0
  27. package/dist/{chunk-MCSJFWAO.cjs → chunk-EWCOFSCQ.cjs} +685 -100
  28. package/dist/chunk-EWCOFSCQ.cjs.map +1 -0
  29. package/dist/chunk-HDYMLS3X.cjs +409 -0
  30. package/dist/chunk-HDYMLS3X.cjs.map +1 -0
  31. package/dist/chunk-HRMEDT2L.js +1406 -0
  32. package/dist/chunk-HRMEDT2L.js.map +1 -0
  33. package/dist/{chunk-D27YFC46.cjs → chunk-IFHKKVXH.cjs} +382 -63
  34. package/dist/chunk-IFHKKVXH.cjs.map +1 -0
  35. package/dist/{chunk-PGNZKFQS.js → chunk-JOIREKL7.js} +137 -58
  36. package/dist/chunk-JOIREKL7.js.map +1 -0
  37. package/dist/chunk-KRGXUQ2Y.js +1696 -0
  38. package/dist/chunk-KRGXUQ2Y.js.map +1 -0
  39. package/dist/{chunk-3LV6RRPH.js → chunk-MHEPLBFB.js} +2 -2
  40. package/dist/chunk-MR2764X2.js +831 -0
  41. package/dist/chunk-MR2764X2.js.map +1 -0
  42. package/dist/{chunk-XNORY7M6.cjs → chunk-NFVBT3UZ.cjs} +166 -87
  43. package/dist/chunk-NFVBT3UZ.cjs.map +1 -0
  44. package/dist/chunk-NQF32I6Z.cjs +6478 -0
  45. package/dist/chunk-NQF32I6Z.cjs.map +1 -0
  46. package/dist/chunk-O5RYH2PG.js +69 -0
  47. package/dist/chunk-O5RYH2PG.js.map +1 -0
  48. package/dist/{chunk-ITBSKI26.js → chunk-Q2OHWD2A.js} +1064 -360
  49. package/dist/chunk-Q2OHWD2A.js.map +1 -0
  50. package/dist/{chunk-FODNLX5N.js → chunk-QJSOZFCZ.js} +38 -4
  51. package/dist/chunk-QJSOZFCZ.js.map +1 -0
  52. package/dist/{chunk-SML64VJG.cjs → chunk-RRREAOVM.cjs} +4 -4
  53. package/dist/{chunk-SML64VJG.cjs.map → chunk-RRREAOVM.cjs.map} +1 -1
  54. package/dist/{chunk-5S3Z4PPF.js → chunk-SWE3NPOU.js} +347 -28
  55. package/dist/chunk-SWE3NPOU.js.map +1 -0
  56. package/dist/chunk-TXXNBDQX.cjs +1696 -0
  57. package/dist/chunk-TXXNBDQX.cjs.map +1 -0
  58. package/dist/chunk-UBCFIABU.js +409 -0
  59. package/dist/chunk-UBCFIABU.js.map +1 -0
  60. package/dist/chunk-X7HXL2SB.js +6478 -0
  61. package/dist/chunk-X7HXL2SB.js.map +1 -0
  62. package/dist/{chunk-SBCZ6RN5.cjs → chunk-YOMYSFJU.cjs} +1163 -459
  63. package/dist/chunk-YOMYSFJU.cjs.map +1 -0
  64. package/dist/{chunk-3CN2WD3X.js → chunk-ZRNHGAQT.js} +661 -76
  65. package/dist/chunk-ZRNHGAQT.js.map +1 -0
  66. package/dist/commands/index.cjs +425 -4
  67. package/dist/commands/index.cjs.map +1 -1
  68. package/dist/commands/index.d.cts +39 -77
  69. package/dist/commands/index.d.ts +39 -77
  70. package/dist/commands/index.js +424 -3
  71. package/dist/commands/index.js.map +1 -1
  72. package/dist/compare/index.cjs +3 -3
  73. package/dist/compare/index.d.cts +1 -1
  74. package/dist/compare/index.d.ts +1 -1
  75. package/dist/compare/index.js +2 -2
  76. package/dist/controller-CxXGOEmy.d.cts +2038 -0
  77. package/dist/controller-CxXGOEmy.d.ts +2038 -0
  78. package/dist/{documents-BQjzJNe2.d.ts → documents-CHT1U5Vs.d.ts} +10 -0
  79. package/dist/{documents-KRTPhvst.d.cts → documents-Gp7wb0Me.d.cts} +10 -0
  80. package/dist/export/index.cjs +36 -0
  81. package/dist/export/index.cjs.map +1 -0
  82. package/dist/export/index.d.cts +243 -0
  83. package/dist/export/index.d.ts +243 -0
  84. package/dist/export/index.js +36 -0
  85. package/dist/export/index.js.map +1 -0
  86. package/dist/extensions/index.cjs +101 -6
  87. package/dist/extensions/index.cjs.map +1 -1
  88. package/dist/extensions/index.d.cts +18 -5
  89. package/dist/extensions/index.d.ts +18 -5
  90. package/dist/extensions/index.js +101 -6
  91. package/dist/generation/index.cjs +1013 -69
  92. package/dist/generation/index.cjs.map +1 -1
  93. package/dist/generation/index.d.cts +474 -13
  94. package/dist/generation/index.d.ts +474 -13
  95. package/dist/generation/index.js +976 -32
  96. package/dist/generation/index.js.map +1 -1
  97. package/dist/image-editor/index.cjs +3385 -1275
  98. package/dist/image-editor/index.cjs.map +1 -1
  99. package/dist/image-editor/index.d.cts +693 -128
  100. package/dist/image-editor/index.d.ts +693 -128
  101. package/dist/image-editor/index.js +3325 -1215
  102. package/dist/image-editor/index.js.map +1 -1
  103. package/dist/{index-fJrlkJCd.d.ts → index-B273Zllk.d.ts} +500 -7
  104. package/dist/{index-BhJBSm2d.d.cts → index-jcJwmBYt.d.cts} +500 -7
  105. package/dist/index.cjs +1603 -45
  106. package/dist/index.cjs.map +1 -1
  107. package/dist/index.d.cts +154 -27
  108. package/dist/index.d.ts +154 -27
  109. package/dist/index.js +1584 -26
  110. package/dist/index.js.map +1 -1
  111. package/dist/mention-text-CDnCFd3c.d.cts +53 -0
  112. package/dist/mention-text-CDnCFd3c.d.ts +53 -0
  113. package/dist/model-C1zApQM8.d.cts +219 -0
  114. package/dist/model-C1zApQM8.d.ts +219 -0
  115. package/dist/persistence/index.d.cts +3 -120
  116. package/dist/persistence/index.d.ts +3 -120
  117. package/dist/registry-CED5C0lA.d.cts +204 -0
  118. package/dist/registry-CED5C0lA.d.ts +204 -0
  119. package/dist/{registry-GJI4gToU.d.cts → registry-CEgwXED1.d.cts} +12 -1
  120. package/dist/{registry-GJI4gToU.d.ts → registry-CEgwXED1.d.ts} +12 -1
  121. package/dist/{registry-D32LpIc4.d.cts → registry-D0GADKc7.d.cts} +1 -1
  122. package/dist/{registry-evKTP4ls.d.ts → registry-DhVUZioj.d.ts} +1 -1
  123. package/dist/serializers/index.cjs +12 -4
  124. package/dist/serializers/index.cjs.map +1 -1
  125. package/dist/serializers/index.d.cts +41 -13
  126. package/dist/serializers/index.d.ts +41 -13
  127. package/dist/serializers/index.js +12 -4
  128. package/dist/spreadsheet/index.cjs +157 -3
  129. package/dist/spreadsheet/index.cjs.map +1 -1
  130. package/dist/spreadsheet/index.d.cts +534 -11
  131. package/dist/spreadsheet/index.d.ts +534 -11
  132. package/dist/spreadsheet/index.js +157 -3
  133. package/dist/storage-BpFfspHm.d.cts +120 -0
  134. package/dist/storage-BpFfspHm.d.ts +120 -0
  135. package/dist/tokens/index.cjs +115 -0
  136. package/dist/tokens/index.cjs.map +1 -0
  137. package/dist/tokens/index.d.cts +212 -0
  138. package/dist/tokens/index.d.ts +212 -0
  139. package/dist/tokens/index.js +115 -0
  140. package/dist/tokens/index.js.map +1 -0
  141. package/dist/{track-changes-BK5sVf4_.d.cts → track-changes-D_VAPELi.d.cts} +95 -11
  142. package/dist/{track-changes-CDjCrwKe.d.ts → track-changes-Db_fGEvx.d.ts} +95 -11
  143. package/package.json +15 -1
  144. package/dist/chunk-3CN2WD3X.js.map +0 -1
  145. package/dist/chunk-5S3Z4PPF.js.map +0 -1
  146. package/dist/chunk-D27YFC46.cjs.map +0 -1
  147. package/dist/chunk-FODNLX5N.js.map +0 -1
  148. package/dist/chunk-ITBSKI26.js.map +0 -1
  149. package/dist/chunk-MA2F5KHF.cjs +0 -3223
  150. package/dist/chunk-MA2F5KHF.cjs.map +0 -1
  151. package/dist/chunk-MCSJFWAO.cjs.map +0 -1
  152. package/dist/chunk-OLZJXL4R.cjs.map +0 -1
  153. package/dist/chunk-PGNZKFQS.js.map +0 -1
  154. package/dist/chunk-SBCZ6RN5.cjs.map +0 -1
  155. package/dist/chunk-U5KWZU4X.js +0 -3223
  156. package/dist/chunk-U5KWZU4X.js.map +0 -1
  157. package/dist/chunk-XNORY7M6.cjs.map +0 -1
  158. package/dist/controller-BhLLAoi8.d.cts +0 -1000
  159. package/dist/controller-BhLLAoi8.d.ts +0 -1000
  160. package/dist/types-DX4Mh4SL.d.cts +0 -217
  161. package/dist/types-DX4Mh4SL.d.ts +0 -217
  162. /package/dist/{chunk-3LV6RRPH.js.map → chunk-MHEPLBFB.js.map} +0 -0
@@ -0,0 +1,2038 @@
1
+ /**
2
+ * Conditional formatting rule model.
3
+ *
4
+ * Portions ported from gridcraft/crates/model/src/features.rs (MIT OR
5
+ * Apache-2.0, © ArtCraft Team and contributors). See THIRD_PARTY_NOTICES.md.
6
+ */
7
+
8
+ /** Comparison of a cell value with one value (or two for `between` / `notBetween`). */
9
+ type ConditionalFormatOperator = 'between' | 'notBetween' | 'equal' | 'notEqual' | 'greaterThan' | 'lessThan' | 'greaterThanOrEqual' | 'lessThanOrEqual';
10
+ /**
11
+ * The look a matching rule adds to a cell. Colours are CSS colours, ideally
12
+ * `#rrggbb`. Only the parts that are set apply, so several rules can combine
13
+ * (a fill from one, bold from another).
14
+ */
15
+ interface ConditionalFormatStyle {
16
+ fill?: string;
17
+ color?: string;
18
+ bold?: boolean;
19
+ italic?: boolean;
20
+ underline?: boolean;
21
+ strikethrough?: boolean;
22
+ }
23
+ /**
24
+ * An anchor of a colour scale, data bar or icon set: the lowest / highest
25
+ * number in the range, a fixed number, a percent of the min..max span, a
26
+ * percentile of the values, or a formula (written for the range's top-left
27
+ * cell, like formula rules).
28
+ */
29
+ type ConditionalFormatValue = {
30
+ type: 'min';
31
+ } | {
32
+ type: 'max';
33
+ } | {
34
+ type: 'number';
35
+ value: number;
36
+ } | {
37
+ type: 'percent';
38
+ value: number;
39
+ } | {
40
+ type: 'percentile';
41
+ value: number;
42
+ } | {
43
+ type: 'formula';
44
+ formula: string;
45
+ };
46
+ /** `dates occurring` periods (weeks start on Sunday, as in Excel's US locale). */
47
+ type ConditionalFormatTimePeriod = 'yesterday' | 'today' | 'tomorrow' | 'last7Days' | 'lastWeek' | 'thisWeek' | 'nextWeek' | 'lastMonth' | 'thisMonth' | 'nextMonth';
48
+ /** Built-in icon sets (the number of icons is the leading digit). */
49
+ type ConditionalFormatIconSet = '3Arrows' | '3ArrowsGray' | '3TrafficLights1' | '3Flags' | '3Symbols' | '3Stars' | '4Arrows' | '4Rating' | '4TrafficLights' | '5Arrows' | '5Rating' | '5Quarters';
50
+ /** The condition of a rule: what it checks and the look it gives. */
51
+ type ConditionalFormatCondition = {
52
+ /**
53
+ * Cell value compared with `value` (and `value2` for between). A value
54
+ * starting with `=` is a formula, relative to the range's top-left
55
+ * cell; anything else is typed input (`10`, `5%`, `3/4/2026`, `Done`).
56
+ */
57
+ type: 'cellIs';
58
+ operator: ConditionalFormatOperator;
59
+ value: string;
60
+ value2?: string;
61
+ style: ConditionalFormatStyle;
62
+ } | {
63
+ /** A formula written for the range's top-left cell: `=$B2>100` formats whole rows. */
64
+ type: 'expression';
65
+ formula: string;
66
+ style: ConditionalFormatStyle;
67
+ } | {
68
+ /** Case-insensitive text tests on the cell's value as text. */
69
+ type: 'containsText' | 'notContainsText' | 'beginsWith' | 'endsWith';
70
+ text: string;
71
+ style: ConditionalFormatStyle;
72
+ } | {
73
+ type: 'blanks' | 'noBlanks' | 'errors' | 'noErrors' | 'duplicate' | 'unique';
74
+ style: ConditionalFormatStyle;
75
+ } | {
76
+ /** Top/bottom `rank` values, or `rank` percent of them. */
77
+ type: 'top10';
78
+ bottom?: boolean;
79
+ percent?: boolean;
80
+ rank: number;
81
+ style: ConditionalFormatStyle;
82
+ } | {
83
+ /** Above (or below) the average, optionally by `stdDev` standard deviations. */
84
+ type: 'aboveAverage';
85
+ below?: boolean;
86
+ equal?: boolean;
87
+ stdDev?: number;
88
+ style: ConditionalFormatStyle;
89
+ } | {
90
+ type: 'timePeriod';
91
+ period: ConditionalFormatTimePeriod;
92
+ style: ConditionalFormatStyle;
93
+ } | {
94
+ /** Two or three stops (low, [mid,] high) with colours; the fill blends between them. */
95
+ type: 'colorScale';
96
+ stops: Array<{
97
+ value: ConditionalFormatValue;
98
+ color: string;
99
+ }>;
100
+ } | {
101
+ type: 'dataBar';
102
+ min?: ConditionalFormatValue;
103
+ max?: ConditionalFormatValue;
104
+ color?: string;
105
+ gradient?: boolean;
106
+ showValue?: boolean;
107
+ } | {
108
+ type: 'iconSet';
109
+ set?: ConditionalFormatIconSet;
110
+ /**
111
+ * One threshold per icon, the first being the lower bound (as in
112
+ * files), or one fewer (the lower bound left out). Default: even
113
+ * percent steps (0, 33, 67 for three icons).
114
+ */
115
+ thresholds?: ConditionalFormatValue[];
116
+ reverse?: boolean;
117
+ showValue?: boolean;
118
+ };
119
+ type ConditionalFormatType = ConditionalFormatCondition['type'];
120
+ /**
121
+ * A conditional format: a condition applied to one or more ranges. Rules
122
+ * are kept in priority order (the first rule has the highest priority).
123
+ * Ranges are 0-based and belong to the sheet that stores the rule.
124
+ */
125
+ type ConditionalFormatRule = ConditionalFormatCondition & {
126
+ id: string;
127
+ ranges: CellRange[];
128
+ /** When this rule matches a cell, lower-priority rules are not applied to it. */
129
+ stopIfTrue?: boolean;
130
+ };
131
+ /** A rule to add: the id is generated when left out. */
132
+ type NewConditionalFormatRule = ConditionalFormatCondition & {
133
+ id?: string;
134
+ ranges: CellRange[];
135
+ stopIfTrue?: boolean;
136
+ };
137
+ /** The conditional look of one cell, combined from every rule that applies. */
138
+ interface ConditionalCellFormat {
139
+ fill?: string;
140
+ color?: string;
141
+ bold?: boolean;
142
+ italic?: boolean;
143
+ underline?: boolean;
144
+ strikethrough?: boolean;
145
+ /** Data bar: `fraction` (0..1) of the cell width. */
146
+ dataBar?: {
147
+ fraction: number;
148
+ color: string;
149
+ gradient: boolean;
150
+ };
151
+ /** Icon of an icon set: `index` 0 is the lowest icon; `id` is `"<set>:<index>"`. */
152
+ icon?: {
153
+ set: ConditionalFormatIconSet;
154
+ index: number;
155
+ id: string;
156
+ };
157
+ /** A data bar or icon set with `showValue: false`: show the bar / icon only. */
158
+ hideValue?: boolean;
159
+ }
160
+ /** Per-cell results of evaluating the conditional formats of a sheet. */
161
+ interface ConditionalFormatOverlay {
162
+ /** The conditional look of (row, col), or undefined when no rule applies. */
163
+ get(row: number, col: number): ConditionalCellFormat | undefined;
164
+ /** Number of cells with a conditional look. */
165
+ readonly size: number;
166
+ /** Every formatted cell. */
167
+ entries(): IterableIterator<[{
168
+ row: number;
169
+ col: number;
170
+ }, ConditionalCellFormat]>;
171
+ }
172
+ /** What evaluation needs to know about a sheet. Rows and columns are 0-based. */
173
+ interface ConditionalFormatSheet {
174
+ rowCount: number;
175
+ colCount: number;
176
+ /** The cell's value: number, text (dates are ISO text), boolean, error code or ''. */
177
+ getValue(row: number, col: number): unknown;
178
+ /**
179
+ * Evaluates a formula (with a leading `=`) as if it were in (row, col).
180
+ * Without it, formula rules never match and formula anchors count as 0.
181
+ */
182
+ evaluateFormula?(formula: string, row: number, col: number): unknown;
183
+ /** The current date, for `timePeriod` rules (default: now). */
184
+ today?(): Date;
185
+ }
186
+
187
+ /**
188
+ * Data validation rule model.
189
+ *
190
+ * Portions ported from gridcraft/crates/model/src/features.rs (MIT OR
191
+ * Apache-2.0, © ArtCraft Team and contributors). See THIRD_PARTY_NOTICES.md.
192
+ */
193
+
194
+ /** What a validated cell may hold. `any` only shows the input message. */
195
+ type DataValidationType = 'any' | 'whole' | 'decimal' | 'list' | 'date' | 'time' | 'textLength' | 'custom';
196
+ type DataValidationOperator = 'between' | 'notBetween' | 'equal' | 'notEqual' | 'greaterThan' | 'lessThan' | 'greaterThanOrEqual' | 'lessThanOrEqual';
197
+ /**
198
+ * How invalid input is handled: `stop` rejects it; `warning` asks whether to
199
+ * keep it (Yes keeps, No returns to editing, Cancel discards); `information`
200
+ * tells and keeps it unless cancelled.
201
+ */
202
+ type DataValidationErrorStyle = 'stop' | 'warning' | 'information';
203
+ interface DataValidationRule {
204
+ id: string;
205
+ /** Cells the rule applies to (0-based, on the sheet that stores the rule). */
206
+ ranges: CellRange[];
207
+ type: DataValidationType;
208
+ /** For whole, decimal, date, time and text length (default `between`). */
209
+ operator?: DataValidationOperator;
210
+ /**
211
+ * First value: a number, date (`2026-01-31`, `1/31/2026`), time (`9:00`)
212
+ * or a formula (`=B1`, relative to the range's top-left cell). For `list`,
213
+ * comma-separated items (`Low,Medium,High`) or a range / formula
214
+ * (`=$H$1:$H$5`). For `custom`, a formula that must be TRUE; it sees the
215
+ * value being entered.
216
+ */
217
+ formula1?: string;
218
+ /** Second value, for `between` / `notBetween`. */
219
+ formula2?: string;
220
+ /** Blank input is always valid (default true). */
221
+ ignoreBlank?: boolean;
222
+ /** Show a dropdown arrow on list cells (default true). */
223
+ inCellDropdown?: boolean;
224
+ inputTitle?: string;
225
+ /** Shown while a cell of the rule is selected. */
226
+ inputMessage?: string;
227
+ /** Default true. */
228
+ showInputMessage?: boolean;
229
+ errorTitle?: string;
230
+ errorMessage?: string;
231
+ /** Default `stop`. */
232
+ errorStyle?: DataValidationErrorStyle;
233
+ /** When false, any input is accepted (the rule still drives dropdowns and circles). Default true. */
234
+ showErrorAlert?: boolean;
235
+ }
236
+ /** A rule to add: the id is generated when left out. */
237
+ type NewDataValidationRule = Omit<DataValidationRule, 'id'> & {
238
+ id?: string;
239
+ };
240
+ /** The outcome of checking input against a cell's validation. */
241
+ interface DataValidationResult {
242
+ valid: boolean;
243
+ /** The rule that applied, if any. */
244
+ rule?: DataValidationRule;
245
+ /** For invalid input: how to alert. */
246
+ errorStyle?: DataValidationErrorStyle;
247
+ /** Alert title and message (defaults filled in). */
248
+ title?: string;
249
+ message?: string;
250
+ }
251
+ /** What validation needs to know about a sheet. Rows and columns are 0-based. */
252
+ interface DataValidationSheet {
253
+ rowCount: number;
254
+ colCount: number;
255
+ getValue(row: number, col: number): unknown;
256
+ /** Typed input of a cell (`raw`), used by `findInvalidCells`. Formulas are checked through their value. */
257
+ getInput?(row: number, col: number): string;
258
+ /**
259
+ * Evaluates a formula (with a leading `=`) as if it were in (row, col).
260
+ * `entered`, when given, is the value being typed into that cell: the
261
+ * formula must see it instead of the cell's current value.
262
+ */
263
+ evaluateFormula?(formula: string, row: number, col: number, entered?: {
264
+ row: number;
265
+ col: number;
266
+ value: unknown;
267
+ }): unknown;
268
+ }
269
+
270
+ type CellFormat = 'text' | 'number' | 'currency' | 'percentage' | 'date' | 'badge' | 'status' | 'assignee';
271
+ type ColumnType = 'bound' | 'freeform' | 'formula';
272
+ interface ColumnBinding {
273
+ dataSource: string;
274
+ field: string;
275
+ }
276
+ interface SpreadsheetColumn {
277
+ id: string;
278
+ key: string;
279
+ title: string;
280
+ width?: number;
281
+ type: ColumnType;
282
+ binding?: ColumnBinding;
283
+ formula?: string;
284
+ format?: CellFormat;
285
+ /**
286
+ * Number format code for the column's cells (e.g. `#,##0.00`,
287
+ * `"$"#,##0.00;[Red]("$"#,##0.00)`, `m/d/yyyy`). Cells without an explicit
288
+ * code of their own use it instead of the automatic one chosen for typed
289
+ * input. See `SpreadsheetController.setColumnNumberFormat`.
290
+ */
291
+ numberFormat?: string;
292
+ readOnly?: boolean;
293
+ hidden?: boolean;
294
+ }
295
+ type RowType = 'record' | 'freeform';
296
+ interface SpreadsheetRow {
297
+ id: string;
298
+ index: number;
299
+ height?: number;
300
+ recordId?: string;
301
+ type: RowType;
302
+ hidden?: boolean;
303
+ }
304
+ interface CellCoordinate {
305
+ row: number;
306
+ col: number;
307
+ rowId?: string;
308
+ colId?: string;
309
+ }
310
+ interface CellRange {
311
+ startRow: number;
312
+ startCol: number;
313
+ endRow: number;
314
+ endCol: number;
315
+ }
316
+ interface CellData {
317
+ raw: string;
318
+ /**
319
+ * Evaluated value. Typed (non-formula) input is parsed: `"120"` → 120,
320
+ * `"TRUE"` → true, `"3/4/2026"` → `"2026-03-04"` (dates are ISO text),
321
+ * `"10:30"` → 0.4375 (a time alone is a fraction of a day); `'120` forces
322
+ * the text `"120"`. Formulas store their result.
323
+ */
324
+ value: any;
325
+ error?: string;
326
+ /** Why the formula failed, e.g. `Argument 2 of SUMIF must be a range.` Set alongside `error`. */
327
+ errorMessage?: string;
328
+ format?: CellFormat;
329
+ /**
330
+ * Excel number format code used to display the value (see
331
+ * `formatCellDisplay`). Set explicitly (`explicitNumberFormat`), inherited
332
+ * from the column's `numberFormat`, or chosen automatically for typed input,
333
+ * e.g. `"$"#,##0.00` for `$1,200.50`, `0%` for `10%`, `#,##0` for `1,234`,
334
+ * `m/d/yyyy` for `3/4/2026`, `h:mm` for `10:30`. Absent for General.
335
+ */
336
+ numberFormat?: string;
337
+ /**
338
+ * True when `numberFormat` was set explicitly (`setCellNumberFormat`):
339
+ * typing into the cell keeps it instead of choosing an automatic format.
340
+ */
341
+ explicitNumberFormat?: boolean;
342
+ readOnly?: boolean;
343
+ /**
344
+ * Set (only) on cells showing a value spilled from a dynamic array: the
345
+ * anchor cell holding the formula, e.g. `A1`. Spilled cells keep an empty
346
+ * `raw` and are never stored in the document.
347
+ */
348
+ spillAnchor?: string;
349
+ }
350
+ /** A dynamic array spilled from its anchor cell (the cell holding the formula). */
351
+ interface SpreadsheetSpill {
352
+ /** Anchor cell key, e.g. `A1`. */
353
+ key: string;
354
+ anchor: {
355
+ row: number;
356
+ col: number;
357
+ };
358
+ /** Every cell the array covers, anchor included. */
359
+ range: CellRange;
360
+ /** The anchor's formula. */
361
+ formula: string;
362
+ }
363
+ interface SpreadsheetDocument {
364
+ id: string;
365
+ name: string;
366
+ columns: SpreadsheetColumn[];
367
+ rows: SpreadsheetRow[];
368
+ cells: Record<string, Record<string, CellData>>;
369
+ createdAt?: number;
370
+ updatedAt?: number;
371
+ table?: SpreadsheetTableSettings;
372
+ }
373
+ type SortDirection = 'asc' | 'desc';
374
+ interface SortKey {
375
+ colId: string;
376
+ direction?: SortDirection;
377
+ }
378
+ type FilterOperator = 'equals' | 'notEquals' | 'contains' | 'notContains' | 'greaterThan' | 'greaterThanOrEqual' | 'lessThan' | 'lessThanOrEqual' | 'between' | 'isBlank' | 'isNotBlank' | 'oneOf';
379
+ interface FilterRule {
380
+ id: string;
381
+ colId: string;
382
+ operator: FilterOperator;
383
+ value?: string | number;
384
+ value2?: string | number;
385
+ values?: string[];
386
+ }
387
+ interface SpreadsheetFilterState {
388
+ enabled: boolean;
389
+ rules: FilterRule[];
390
+ }
391
+ type GroupAggregate = 'sum' | 'count' | 'average' | 'min' | 'max';
392
+ interface GroupSummary {
393
+ colId: string;
394
+ aggregate: GroupAggregate;
395
+ }
396
+ interface SpreadsheetGrouping {
397
+ colId: string;
398
+ summaries: GroupSummary[];
399
+ collapsed: string[];
400
+ }
401
+ interface SpreadsheetTableSettings {
402
+ headerRowCount?: number;
403
+ footerRowCount?: number;
404
+ headerColumnCount?: number;
405
+ frozenRowCount?: number;
406
+ frozenColumnCount?: number;
407
+ merges?: CellRange[];
408
+ filter?: SpreadsheetFilterState;
409
+ grouping?: SpreadsheetGrouping;
410
+ /**
411
+ * Conditional formats of this sheet, highest priority first. Kept with the
412
+ * other per-sheet table state (undoable through document snapshots).
413
+ */
414
+ conditionalFormats?: ConditionalFormatRule[];
415
+ /** Data validation rules of this sheet; a cell uses the first rule containing it. */
416
+ dataValidations?: DataValidationRule[];
417
+ }
418
+ interface SpreadsheetDataSourceField {
419
+ key: string;
420
+ label: string;
421
+ type: 'string' | 'number' | 'date' | 'boolean' | 'enum';
422
+ options?: Array<{
423
+ key: string;
424
+ label: string;
425
+ color?: string;
426
+ }>;
427
+ }
428
+ interface SpreadsheetDataSource {
429
+ id: string;
430
+ name: string;
431
+ getRecords(): Array<{
432
+ id: string;
433
+ [key: string]: any;
434
+ }>;
435
+ getFields(): SpreadsheetDataSourceField[];
436
+ updateRecord(recordId: string, field: string, value: any): Promise<void> | void;
437
+ }
438
+ /**
439
+ * A defined name (Formulas › Name Manager): a range, constant, formula or
440
+ * LAMBDA that formulas can use by name, e.g. `=Price*(1+Rate)`,
441
+ * `=SUM(Sales)`, `=Double(4)`.
442
+ */
443
+ interface SpreadsheetDefinedName {
444
+ /** The name, e.g. `Rate`. Unique per scope, compared case-insensitively. */
445
+ name: string;
446
+ /**
447
+ * What the name refers to, as a formula: `=Data!$A$2:$A$20`, `=0.07`,
448
+ * `=Rate*2` or `=LAMBDA(x, x*2)`. Unqualified references refer to the
449
+ * name's sheet (sheet scope) or to the sheet of the formula using it.
450
+ */
451
+ refersTo: string;
452
+ /** Id of the sheet for a sheet-scoped name; unset for workbook scope. */
453
+ sheetId?: string;
454
+ comment?: string;
455
+ }
456
+ /**
457
+ * A workbook: several sheets plus defined names. A `SpreadsheetController`
458
+ * created from a single document is a workbook with one sheet.
459
+ */
460
+ interface SpreadsheetWorkbook {
461
+ /** The sheets in tab order. A sheet's `name` is its tab name (unique, case-insensitively). */
462
+ sheets: SpreadsheetDocument[];
463
+ /** Id of the sheet shown (default: the first). */
464
+ activeSheetId?: string;
465
+ names?: SpreadsheetDefinedName[];
466
+ }
467
+ /** A sheet tab: what sheet-tab bars render. */
468
+ interface SpreadsheetSheetInfo {
469
+ id: string;
470
+ name: string;
471
+ /** Position in tab order (0-based). */
472
+ index: number;
473
+ active: boolean;
474
+ }
475
+
476
+ type FormulaTokenType = 'NUMBER' | 'STRING' | 'BOOLEAN' | 'ERROR' | 'CELL_REF' | 'RANGE' | 'SPILL_REF' | 'PROPERTY_REF' | 'IDENTIFIER' | 'OPERATOR' | 'LPAREN' | 'RPAREN' | 'COMMA' | 'EOF';
477
+ interface FormulaToken {
478
+ type: FormulaTokenType;
479
+ value: string;
480
+ /** Offset of the token in the formula (for a sheet-qualified reference, of its sheet prefix). */
481
+ position: number;
482
+ /** Offset just past the token. */
483
+ end?: number;
484
+ /**
485
+ * Sheet of a sheet-qualified reference or name (`Sheet2!A1`, `'My Sheet'!A1:B2`,
486
+ * `Data!Rate`), unquoted. Unset for references to the formula's own sheet.
487
+ */
488
+ sheet?: string;
489
+ /** Last sheet of a 3-D reference (`Sheet1:Sheet3!A1`). */
490
+ sheetEnd?: string;
491
+ /** Offset where the reference itself starts, after the sheet prefix and `!`. */
492
+ refStart?: number;
493
+ }
494
+ declare function tokenizeFormula(formula: string): FormulaToken[];
495
+
496
+ /** Row number used for the open end of whole-column ranges such as `A:A`. */
497
+ declare const WHOLE_COLUMN_END_ROW = 1048576;
498
+ type ASTNode = LiteralNode | CellRefNode | RangeNode | SpillRefNode | NameNode | PropertyRefNode | BinaryOpNode | UnaryOpNode | FunctionCallNode | InvokeNode | MissingNode;
499
+ /**
500
+ * Sheet qualification of a reference: `Sheet2!A1` has `sheet: 'Sheet2'`;
501
+ * a 3-D reference `Sheet1:Sheet3!A1` also has `sheetEnd: 'Sheet3'`. Unset
502
+ * for references to the formula's own sheet.
503
+ */
504
+ interface SheetQualifier {
505
+ sheet?: string;
506
+ sheetEnd?: string;
507
+ }
508
+ interface LiteralNode {
509
+ type: 'Literal';
510
+ value: number | string | boolean;
511
+ }
512
+ interface CellRefNode extends SheetQualifier {
513
+ type: 'CellRef';
514
+ ref: string;
515
+ col: string;
516
+ row: number;
517
+ }
518
+ interface RangeNode extends SheetQualifier {
519
+ type: 'Range';
520
+ raw: string;
521
+ startCol: string;
522
+ startRow: number;
523
+ endCol: string;
524
+ endRow: number;
525
+ }
526
+ /** `A1#`: the whole spill range of the dynamic array anchored at A1. */
527
+ interface SpillRefNode extends SheetQualifier {
528
+ type: 'SpillRef';
529
+ /** Anchor cell, e.g. `A1`. */
530
+ ref: string;
531
+ col: string;
532
+ row: number;
533
+ }
534
+ /**
535
+ * A bare name: a LET or LAMBDA variable, a defined name (`Rate`,
536
+ * `Data!Rate` with `sheet`), or `#NAME?` when nothing defines it.
537
+ */
538
+ interface NameNode {
539
+ type: 'Name';
540
+ name: string;
541
+ /** Sheet of a sheet-qualified name (`Data!Rate`). */
542
+ sheet?: string;
543
+ }
544
+ interface PropertyRefNode {
545
+ type: 'PropertyRef';
546
+ property: string;
547
+ }
548
+ interface BinaryOpNode {
549
+ type: 'BinaryOp';
550
+ op: string;
551
+ left: ASTNode;
552
+ right: ASTNode;
553
+ }
554
+ interface UnaryOpNode {
555
+ type: 'UnaryOp';
556
+ op: string;
557
+ argument: ASTNode;
558
+ }
559
+ interface FunctionCallNode {
560
+ type: 'FunctionCall';
561
+ name: string;
562
+ args: ASTNode[];
563
+ }
564
+ /**
565
+ * A call of a computed function: `LAMBDA(x, x+1)(2)` or `(f)(2)`. Calls of a
566
+ * named function, defined name or variable (`F(2)`) are `FunctionCall`s.
567
+ */
568
+ interface InvokeNode {
569
+ type: 'Invoke';
570
+ callee: ASTNode;
571
+ args: ASTNode[];
572
+ }
573
+ /** An argument left empty, as in `IF(A1,,1)` or `LAMBDA(x, y, x)(1,)`. */
574
+ interface MissingNode {
575
+ type: 'Missing';
576
+ }
577
+ declare function parseCellReference(ref: string): {
578
+ col: string;
579
+ row: number;
580
+ };
581
+ declare function parseRange(rangeStr: string): RangeNode;
582
+ declare class FormulaParser {
583
+ private tokens;
584
+ private current;
585
+ constructor(tokens: FormulaToken[]);
586
+ parse(): ASTNode;
587
+ private expression;
588
+ private comparison;
589
+ private concatenation;
590
+ private addition;
591
+ private multiplication;
592
+ private exponentiation;
593
+ private unary;
594
+ /** Arguments after `(` up to and including `)`. Empty positions are `Missing`. */
595
+ private argumentList;
596
+ private primary;
597
+ private match;
598
+ private matchOperator;
599
+ private check;
600
+ private advance;
601
+ private isAtEnd;
602
+ private peek;
603
+ private previous;
604
+ private consume;
605
+ }
606
+ declare function parseFormula(formula: string): ASTNode;
607
+
608
+ /** Spreadsheet error values. They propagate through operators and functions. */
609
+ declare const FORMULA_ERRORS: Set<string>;
610
+ type FormulaErrorCode = '#DIV/0!' | '#VALUE!' | '#REF!' | '#NAME?' | '#N/A' | '#NUM!' | '#CYCLE!' | '#ERROR!' | '#SPILL!' | '#CALC!';
611
+ declare function isFormulaError(value: unknown): value is string;
612
+ /**
613
+ * Number to text as Excel converts it in `&` and General display: up to 15
614
+ * significant digits, scientific for very large or very small magnitudes.
615
+ */
616
+ declare function numberToText(n: number): string;
617
+ /**
618
+ * Compares numbers the way Excel does: both are rounded to 15 significant
619
+ * digits first, so binary noise such as `0.1+0.2` versus `0.3` counts as equal.
620
+ */
621
+ declare function compareNumbers(a: number, b: number): number;
622
+ /**
623
+ * Excel's comparison for the `=`, `<>`, `<`… operators: numbers < text <
624
+ * booleans < errors, numbers compared at 15 significant digits, text
625
+ * case-insensitively. A blank acts as 0, "" or FALSE depending on the other
626
+ * side. Dates are ISO text: two ISO dates compare chronologically
627
+ * ("2026-1-5" is before "2026-01-10"), and an ISO date against a number
628
+ * compares as its serial number.
629
+ */
630
+ declare function compareValues(left: unknown, right: unknown): number;
631
+ /**
632
+ * Sort order (ascending): numbers, text, booleans, errors, then blanks last.
633
+ * Errors are equal to each other, so sorting keeps their order.
634
+ */
635
+ declare function sortCompareValues(left: unknown, right: unknown): number;
636
+ declare function colNameToIndex(col: string): number;
637
+ declare function indexToColName(index: number): string;
638
+ /**
639
+ * A rectangular block of values. `values` is column-major (the order in which
640
+ * `EvaluationContext.resolveRange` returns cells): `values[col * rows + row]`.
641
+ */
642
+ interface FormulaRange {
643
+ rows: number;
644
+ cols: number;
645
+ values: any[];
646
+ }
647
+
648
+ /** What a defined name refers to, as returned by `EvaluationContext.resolveName`. */
649
+ interface FormulaNameDefinition {
650
+ /** Formula text (`=Sheet1!$A$1:$A$9`, `=0.07`, `=LAMBDA(x, x*2)`) or a parsed formula. */
651
+ formula: string | ASTNode;
652
+ /** Sheet that unqualified references in the formula refer to (a sheet-scoped name's sheet). */
653
+ sheet?: string;
654
+ /** A key identifying the name (for cycle detection), e.g. `Data!RATE`. Defaults to the name. */
655
+ key?: string;
656
+ }
657
+ /** Hints for `EvaluationContext.resolveRange`. */
658
+ interface RangeResolveOptions {
659
+ /** The values are only aggregated by a function that ignores blank cells. */
660
+ skipBlanks?: boolean;
661
+ }
662
+ interface EvaluationContext {
663
+ /**
664
+ * Value of a cell. `sheet` is set for sheet-qualified references
665
+ * (`Sheet2!A1`); undefined means the formula's own sheet. Return `#REF!`
666
+ * for a sheet that doesn't exist.
667
+ */
668
+ resolveCell?: (col: string, row: number, sheet?: string) => any;
669
+ /**
670
+ * Values of a rectangular range, column by column (all rows of the first
671
+ * column, then the next column). Lookup functions rely on this order.
672
+ * `sheet` as in `resolveCell`; return an error code for a missing sheet.
673
+ * `options.skipBlanks` is a hint that the caller ignores blank cells
674
+ * (SUM, COUNT, AVERAGE, …): a resolver may then leave them out, so sparse
675
+ * ranges cost no array slots. Returning every value is always correct.
676
+ */
677
+ resolveRange?: (startCol: string, startRow: number, endCol: string, endRow: number, sheet?: string, options?: RangeResolveOptions) => any[] | string;
678
+ resolveProperty?: (property: string) => any;
679
+ /**
680
+ * The spilled array anchored at a cell, for `A1#` references: its shape and
681
+ * values (column-major, like `resolveRange`), or an error code (e.g.
682
+ * `#REF!` when the cell holds no array).
683
+ */
684
+ resolveSpill?: (col: string, row: number, sheet?: string) => FormulaRange | string;
685
+ /**
686
+ * The sheets of a 3-D reference (`Sheet1:Sheet3!A1`), from `first` to
687
+ * `last` in tab order, or an error code when either sheet is missing.
688
+ */
689
+ resolveSheetSpan?: (first: string, last: string) => string[] | string;
690
+ /**
691
+ * A defined name (`Rate`, `Data!Rate`), or null when none is visible.
692
+ * `sheet` is the qualifying sheet, or the sheet whose names apply (when a
693
+ * sheet-scoped name refers to another name); undefined means the formula's
694
+ * own sheet. Sheet-scoped names come before workbook-scoped ones.
695
+ */
696
+ resolveName?: (name: string, sheet?: string) => FormulaNameDefinition | null;
697
+ /**
698
+ * The cell holding the formula being evaluated, used by the implicit
699
+ * intersection operator (`=@A:A` reads the cell in the formula's row).
700
+ */
701
+ getFormulaCell?: () => {
702
+ col: string;
703
+ row: number;
704
+ } | null;
705
+ }
706
+ /** A human-readable reason for an error value. */
707
+ interface FormulaDiagnostic {
708
+ code: FormulaErrorCode;
709
+ message: string;
710
+ }
711
+ interface FormulaEvaluationResult {
712
+ /** The computed value; an error code such as `#VALUE!` when the formula fails. */
713
+ value: any;
714
+ /** The error code when `value` is an error. */
715
+ error?: FormulaErrorCode;
716
+ /** Why the formula failed, e.g. `Argument 2 of SUMIF must be a range.` */
717
+ message?: string;
718
+ /**
719
+ * Set when the formula returned an array of more than one value (a
720
+ * dynamic array). `value` is then its top-left value; a spreadsheet spills
721
+ * the whole array into the cells below and to the right.
722
+ */
723
+ array?: FormulaRange;
724
+ }
725
+ /** Generic explanation of an error code, used when no specific reason was recorded. */
726
+ declare function describeFormulaError(code: string): string;
727
+ /** Largest array a formula may build (SEQUENCE, RANDARRAY, broadcasting). */
728
+ declare const MAX_FORMULA_ARRAY_SIZE = 1000000;
729
+ declare class FormulaEvaluator {
730
+ private context;
731
+ private diagnostics;
732
+ private env;
733
+ private defaultSheet;
734
+ private lambdaDepth;
735
+ private nameStack;
736
+ private parsedNames;
737
+ constructor(context?: EvaluationContext);
738
+ /**
739
+ * Evaluates a formula. Errors in the formula are returned as error values
740
+ * (`#VALUE!` etc.); malformed formulas and missing resolvers throw.
741
+ */
742
+ evaluate(astOrFormula: ASTNode | string): any;
743
+ /**
744
+ * Evaluates a formula and explains errors. Never throws: malformed formulas
745
+ * return `#ERROR!` with the parser's message. A result with several values
746
+ * (a range or a dynamic array) is returned in `array`, with its top-left
747
+ * value as `value`; a one-value array is just that value.
748
+ */
749
+ evaluateWithDiagnostics(astOrFormula: ASTNode | string): FormulaEvaluationResult;
750
+ /** Records why an error happened and returns the error code. */
751
+ private fail;
752
+ private evaluateNode;
753
+ private unary;
754
+ /** A binary operator on two single values. */
755
+ private binary;
756
+ /**
757
+ * Dates are ISO text: date +/- days is a date, date - date is a number of
758
+ * days (fractional when times are involved).
759
+ */
760
+ private dateArithmetic;
761
+ /**
762
+ * `@` (implicit intersection): a range reference reads the cell in the
763
+ * formula's row (one column) or column (one row); arrays give their
764
+ * top-left value.
765
+ */
766
+ private implicitIntersection;
767
+ private evaluateSpillRef;
768
+ private evaluateRange;
769
+ private callFunction;
770
+ private finishCall;
771
+ /**
772
+ * Arguments evaluated on first use. With `skipBlanks` (the function ignores
773
+ * blank cells), range arguments may come back without their blanks.
774
+ */
775
+ private lazyArguments;
776
+ /**
777
+ * Applies a scalar function element by element when it receives arrays
778
+ * (`=LEN(A1:A3)`, `=IF(A1:A3>1, "y", "n")`). Arguments typed `range` are
779
+ * passed whole. Returns undefined when no trigger argument is a
780
+ * multi-value array.
781
+ */
782
+ private liftOverArrays;
783
+ /** A bare name: a variable, a defined name, or #NAME?. */
784
+ private evaluateName;
785
+ private lookupDefinedName;
786
+ /**
787
+ * Evaluates a defined name's formula, outside any LET/LAMBDA variables, with
788
+ * unqualified references pointing at the name's sheet (for sheet-scoped
789
+ * names).
790
+ */
791
+ private evaluateDefinedName;
792
+ /** A 3-D reference (`Sheet1:Sheet3!A1`, `Sheet1:Sheet3!A1:B2`): every sheet's values, in tab order. */
793
+ private evaluate3d;
794
+ /** Calls a lambda with argument expressions, evaluated in the caller's scope. */
795
+ private invokeLambda;
796
+ /** Calls a lambda with argument values (`omitted`: positions left out, for ISOMITTED). */
797
+ private invokeWithValues;
798
+ private evaluateSpecialForm;
799
+ /** LET(name1, value1, [name2, value2, ...], calculation). */
800
+ private evaluateLet;
801
+ /** LAMBDA([parameter1, ...], calculation): a function value closing over the current variables. */
802
+ private evaluateLambda;
803
+ /**
804
+ * The function argument of a LAMBDA helper: a lambda, or a built-in
805
+ * function given by name (`BYROW(A1:C3, SUM)`) unless a variable or defined
806
+ * name has that name. Returns an error string when it is neither.
807
+ */
808
+ private lambdaArgument;
809
+ /** Calls a built-in function with already evaluated arguments. */
810
+ private callBuiltinWithValues;
811
+ /** Checks a lambda takes `count` parameters (native functions take any count). */
812
+ private checkArity;
813
+ /** MAP(array1, [array2, ...], lambda): calls the lambda with each element. */
814
+ private evaluateMap;
815
+ /**
816
+ * REDUCE([initial_value], array, lambda) / SCAN(...): folds the array row
817
+ * by row with lambda(accumulator, value). SCAN returns every intermediate
818
+ * value, in the array's shape.
819
+ */
820
+ private evaluateReduce;
821
+ /** BYROW(array, lambda) / BYCOL(array, lambda): one result per row (a column) or per column (a row). */
822
+ private evaluateByLine;
823
+ /** MAKEARRAY(rows, columns, lambda): lambda(row, column) for every 1-based position. */
824
+ private evaluateMakeArray;
825
+ private createContext;
826
+ }
827
+
828
+ interface CellDep {
829
+ col: string;
830
+ /** Row number; 0 for a whole-column dependency (`A:A`). */
831
+ row: number;
832
+ /** Sheet of a sheet-qualified reference (`Sheet2!A1`); unset for the formula's own sheet. */
833
+ sheet?: string;
834
+ /** Last sheet of a 3-D reference (`Sheet1:Sheet3!A1`). */
835
+ sheetEnd?: string;
836
+ }
837
+ /** A name used by a formula: a defined name, LET/LAMBDA variable or (with `call`) a function. */
838
+ interface NameDep {
839
+ /** Upper-case name. */
840
+ name: string;
841
+ /** Sheet of a sheet-qualified name (`Data!Rate`). */
842
+ sheet?: string;
843
+ /** Used as a function (`Double(4)`). */
844
+ call: boolean;
845
+ }
846
+ /**
847
+ * Names a formula uses (bare names and calls), for dependencies on defined
848
+ * names. LET/LAMBDA variables are included; callers ignore names that are
849
+ * not defined.
850
+ */
851
+ declare function extractNameDependencies(node: ASTNode): NameDep[];
852
+ /**
853
+ * Dependency key for "every cell in column `col`", used by whole-column ranges
854
+ * (`A:A`) instead of expanding a million cell keys.
855
+ */
856
+ declare const columnDependencyKey: (col: string) => string;
857
+ declare function extractCellDependencies(node: ASTNode): CellDep[];
858
+ /**
859
+ * A reference a formula reads, without expanding ranges: a single cell or
860
+ * a rectangle (`A1:B9`; a whole column `A:A` runs to `WHOLE_COLUMN_END_ROW`).
861
+ * Columns are letters, rows are 1-based; ranges are normalised (start ≤ end).
862
+ */
863
+ type ReferenceDep = ({
864
+ kind: 'cell';
865
+ col: string;
866
+ row: number;
867
+ } & Pick<CellDep, 'sheet' | 'sheetEnd'>) | ({
868
+ kind: 'range';
869
+ startCol: string;
870
+ startRow: number;
871
+ endCol: string;
872
+ endRow: number;
873
+ } & Pick<CellDep, 'sheet' | 'sheetEnd'>);
874
+ /**
875
+ * The cells and ranges a formula reads, ranges kept whole (unlike
876
+ * `extractCellDependencies`, which lists every cell of a range). `A1#`
877
+ * depends on its anchor `A1`.
878
+ */
879
+ declare function extractReferenceDependencies(node: ASTNode): ReferenceDep[];
880
+ /**
881
+ * Dependency key of a rectangle (`A1:B9`, or `SHEET!A1:B9` with a sheet
882
+ * prefix), for `DependencyGraph.setCellDependencies`. The graph stores it as
883
+ * one range, however many cells it covers.
884
+ */
885
+ declare function rangeDependencyKey(startCol: string, startRow: number, endCol: string, endRow: number, sheetPrefix?: string): string;
886
+ interface IntervalEntry<T> {
887
+ r0: number;
888
+ r1: number;
889
+ id: string;
890
+ payload: T;
891
+ }
892
+ /**
893
+ * Row intervals `[r0, r1]` with payloads, answering "which intervals overlap
894
+ * rows `a..b`?" in O(log n + k). Entries are sorted by start, with an
895
+ * implicit segment tree of the largest end below each node, so a query only
896
+ * descends into subtrees holding a match. Removals mark entries dead;
897
+ * insertions wait in a small pending set. Both are merged in (on the next
898
+ * query) once either grows, so mutations cost O(log n) amortised.
899
+ */
900
+ declare class IntervalIndex<T> {
901
+ private items;
902
+ private dead;
903
+ private deadCount;
904
+ private maxEnd;
905
+ private leaves;
906
+ private position;
907
+ private pending;
908
+ /** Live entries. */
909
+ get size(): number;
910
+ /** Adds (or revives) the entry `id`. An id always names the same interval. */
911
+ insert(r0: number, r1: number, id: string, payload: T): void;
912
+ remove(id: string): void;
913
+ /** Merges pending insertions and drops dead entries when there are enough of them. */
914
+ private settle;
915
+ /** Calls `fn` for every live interval overlapping rows `a..b` (`r0 <= b && r1 >= a`). */
916
+ query(a: number, b: number, fn: (payload: T, entry: IntervalEntry<T>) => void): void;
917
+ private walk;
918
+ }
919
+ /** Sizes of the dependency index (see `DependencyGraph.getIndexStats`). */
920
+ interface DependencyIndexStats {
921
+ /** Cells with registered dependencies (formulas). */
922
+ formulas: number;
923
+ /** Single-cell edges (formula → cell it reads). */
924
+ cellEdges: number;
925
+ /** Range entries: one per range (per column for ranges up to 64 columns wide), however many cells it covers. */
926
+ rangeEntries: number;
927
+ /** Formulas that use a volatile function. */
928
+ volatile: number;
929
+ }
930
+ declare class DependencyGraph {
931
+ private nodes;
932
+ private cellDependents;
933
+ private rangeIndex;
934
+ private volatile;
935
+ private spillDependencies;
936
+ private spillDependents;
937
+ private spillEdges;
938
+ private blockingEdges;
939
+ private parsed;
940
+ private parse;
941
+ private sheetIndex;
942
+ private removeNode;
943
+ /**
944
+ * Sets what `cellKey` depends on directly, replacing its previous
945
+ * dependencies. Keys are single cells (`B2`), rectangles (`A1:B9`) or
946
+ * whole columns (`A:`, see `columnDependencyKey`), each optionally
947
+ * sheet-qualified (`SHEET!A1:A9`). Ranges are stored whole in an interval
948
+ * index, never expanded cell by cell. `setCellFormula` derives the keys
949
+ * from a formula.
950
+ */
951
+ setCellDependencies(cellKey: string, dependencyKeys: Iterable<string>): void;
952
+ /**
953
+ * Marks `cellKey` as volatile (its formula uses NOW, RAND, …): it is
954
+ * recalculated by every plan made with `includeVolatile`, whatever changed.
955
+ */
956
+ setVolatile(cellKey: string, volatile: boolean): void;
957
+ /** Cells whose formulas are volatile. */
958
+ getVolatileKeys(): string[];
959
+ setCellFormula(cellKey: string, formulaStr: string | null): void;
960
+ /** Removes every registered formula and dependency. */
961
+ clear(): void;
962
+ /**
963
+ * Records the dynamic-array edges of the anchor `anchorKey`, replacing its
964
+ * previous ones: every key in `spilledKeys` (cells holding its spilled
965
+ * values) depends on the anchor, and the anchor depends on every key in
966
+ * `blockingKeys` (cells that stop it spilling). Pass empty lists to remove
967
+ * the anchor's edges.
968
+ */
969
+ setSpillEdges(anchorKey: string, spilledKeys: Iterable<string>, blockingKeys?: Iterable<string>): void;
970
+ /**
971
+ * Drops the edge from a spilled cell to the anchor whose values it holds,
972
+ * for a cell that just got input of its own: its value no longer comes
973
+ * from the anchor (which recalculates and becomes `#SPILL!`), and the
974
+ * stale edge could otherwise close a false cycle with the cell's new
975
+ * formula before the anchor is evaluated again.
976
+ */
977
+ detachSpilledCell(cellKey: string): void;
978
+ /** The spilled cells registered for `anchorKey` by `setSpillEdges`. */
979
+ getSpilledKeys(anchorKey: string): string[];
980
+ /**
981
+ * What a cell depends on directly: single cells, ranges (as registered,
982
+ * e.g. `A1:A9` or `A:`, not expanded) and dynamic-array (spill) edges.
983
+ */
984
+ getDependencies(cellKey: string): string[];
985
+ /**
986
+ * Whether the formula in `formulaKey` reads `cellKey` directly: as a cell,
987
+ * inside one of its ranges, or through a spill edge.
988
+ */
989
+ dependsOn(formulaKey: string, cellKey: string): boolean;
990
+ /**
991
+ * Formulas (and spilled cells) reading `cellKey` directly, through formulas
992
+ * or spills. Found in O(log n + k) through the range index.
993
+ */
994
+ getDependents(cellKey: string): string[];
995
+ private collectDependents;
996
+ /** Sizes of the index: ranges count once (per column), not once per cell. */
997
+ getIndexStats(): DependencyIndexStats;
998
+ /**
999
+ * Detects if there is a cycle containing cellKey.
1000
+ */
1001
+ hasCycle(cellKey: string): boolean;
1002
+ /**
1003
+ * Returns cells affected by updating cellKey in topological order.
1004
+ */
1005
+ getEvaluationOrder(startCellKey: string): {
1006
+ order: string[];
1007
+ hasCycle: boolean;
1008
+ };
1009
+ /**
1010
+ * Plans a recalculation over `cellKeys` (and, with `includeDependents`, every
1011
+ * cell that transitively depends on them; with `includeVolatile`, every
1012
+ * volatile formula and its dependents too). Returns the keys in evaluation
1013
+ * order (dependencies first) and the set of keys that are part of a cycle,
1014
+ * which must be marked `#CYCLE!` instead of evaluated. Every member of a
1015
+ * cycle is reported, not just the cell that closed it.
1016
+ *
1017
+ * Only the planned cells are ordered: a range a formula reads becomes one
1018
+ * node whose edges are the planned cells inside it (found by binary
1019
+ * search), so a range shared by many formulas is resolved once.
1020
+ */
1021
+ getEvaluationPlan(cellKeys: Iterable<string>, options?: {
1022
+ includeDependents?: boolean;
1023
+ includeVolatile?: boolean;
1024
+ }): {
1025
+ order: string[];
1026
+ cyclic: Set<string>;
1027
+ };
1028
+ }
1029
+
1030
+ /**
1031
+ * A row or column insertion/deletion. `index` is the 0-based position of the
1032
+ * inserted or deleted row/column.
1033
+ */
1034
+ interface StructuralChange {
1035
+ axis: 'row' | 'col';
1036
+ index: number;
1037
+ type: 'insert' | 'delete';
1038
+ }
1039
+ /**
1040
+ * Rewrites the cell and range references in `formula` after a row or column
1041
+ * is inserted or deleted, the way spreadsheet apps do: references after the
1042
+ * change shift, ranges grow or shrink, and references to a deleted row/column
1043
+ * become `#REF!`. Absolute (`$`) markers are kept. String literals, property
1044
+ * references and function names are left untouched.
1045
+ */
1046
+ declare function shiftFormulaReferences(formula: string, change: StructuralChange, options?: FormulaReferenceFilter): string;
1047
+ /**
1048
+ * Limits a rewrite to some references, e.g. only those pointing at the sheet
1049
+ * that changed: `appliesTo(sheet)` gets the reference's sheet (undefined for
1050
+ * the formula's own sheet) and, for 3-D references, the last sheet.
1051
+ */
1052
+ interface FormulaReferenceFilter {
1053
+ appliesTo?: (sheet: string | undefined, sheetEnd: string | undefined) => boolean;
1054
+ }
1055
+ /** Where a reference passed to a `mapFormulaReferences` callback points. */
1056
+ interface FormulaReferenceInfo {
1057
+ /** Sheet of a qualified reference (`Sheet2!A1`), unquoted; undefined for the formula's own sheet. */
1058
+ sheet?: string;
1059
+ /** Last sheet of a 3-D reference. */
1060
+ sheetEnd?: string;
1061
+ }
1062
+ /**
1063
+ * Calls `rewrite` with the source text of every cell or range reference in
1064
+ * `formula` (e.g. `"$A1"`, `"B2:C10"`, `"A:A"`) and splices in its result.
1065
+ * For a spill reference (`A1#`) it receives the anchor (`"A1"`) and the `#`
1066
+ * is kept, unless the rewrite returns `#REF!`. A sheet prefix (`Sheet2!`,
1067
+ * `'My Sheet'!`) is not part of the text: `info` says which sheet the
1068
+ * reference points at, and the prefix is kept unless the rewrite returns
1069
+ * `#REF!`. String literals, property references and function names (e.g.
1070
+ * `LOG10(`) are skipped. Formulas that fail to tokenize are returned unchanged.
1071
+ */
1072
+ declare function mapFormulaReferences(formula: string, rewrite: (reference: string, info: FormulaReferenceInfo) => string): string;
1073
+ /**
1074
+ * Moves a formula by (`rowOffset`, `colOffset`), as copy/paste and autofill
1075
+ * do: relative row/column parts shift, `$`-absolute parts stay. A reference
1076
+ * pushed above row 1 or left of column A becomes `#REF!`.
1077
+ */
1078
+ declare function offsetFormulaReferences(formula: string, rowOffset: number, colOffset: number): string;
1079
+ /** A 0-based cell position. */
1080
+ interface CellPosition {
1081
+ row: number;
1082
+ col: number;
1083
+ }
1084
+ /**
1085
+ * Rewrites references when cells *move* (sort, transpose): references follow
1086
+ * the cell they point at, whether relative or absolute. `moveCell` returns a
1087
+ * cell's new position, or null when it did not move. A range is remapped only
1088
+ * when its cells moved together as a rectangle of the same size (e.g. a
1089
+ * one-row range inside a sorted row, or a range inside a transposed block);
1090
+ * otherwise it is kept, since it still covers the same rows and columns.
1091
+ */
1092
+ declare function remapFormulaReferences(formula: string, moveCell: (position: CellPosition) => CellPosition | null, options?: FormulaReferenceFilter): string;
1093
+ /**
1094
+ * Whether a sheet name must be quoted in a formula (`'My Sheet'!A1`): names
1095
+ * with spaces or punctuation, starting with a digit, or that look like a
1096
+ * cell reference (`A1`, `R1C1`) or a boolean.
1097
+ */
1098
+ declare function sheetNameNeedsQuotes(name: string): boolean;
1099
+ /** A sheet name as written in formulas: `Data`, `'My Sheet'`, `'Bob''s'`. */
1100
+ declare function quoteSheetName(name: string): string;
1101
+ /** The prefix of a reference to `sheet` (or the 3-D span `sheet:sheetEnd`), with `!`. */
1102
+ declare function formatSheetPrefix(sheet: string, sheetEnd?: string): string;
1103
+ /**
1104
+ * Rewrites references to the sheet `oldName` (cell, range, spill and 3-D
1105
+ * references, and sheet-qualified names such as `Old!Rate`) after it is
1106
+ * renamed to `newName`, quoting the new name when needed.
1107
+ */
1108
+ declare function renameSheetInFormula(formula: string, oldName: string, newName: string): string;
1109
+ /**
1110
+ * Rewrites a formula after the sheet `name` is deleted: references to it
1111
+ * become `#REF!`. `order` lists the sheet names before the deletion, in tab
1112
+ * order: a 3-D reference losing an end sheet shrinks to the neighbouring
1113
+ * sheet, as in Excel (`Sheet1:Sheet3!A1` without Sheet1 is `Sheet2:Sheet3!A1`).
1114
+ */
1115
+ declare function deleteSheetInFormula(formula: string, name: string, order?: readonly string[]): string;
1116
+ /**
1117
+ * Renames uses of the defined name `oldName` (`Rate`, `Rate*2`, `Double(4)`,
1118
+ * `Data!Rate`) to `newName`. `appliesTo(sheet)` decides, for a
1119
+ * sheet-qualified use, whether that sheet's name is the renamed one; unset,
1120
+ * every use is renamed. With `qualifiedOnly`, unqualified uses are kept (the
1121
+ * formula is on a sheet where the name means something else).
1122
+ */
1123
+ declare function renameNameInFormula(formula: string, oldName: string, newName: string, options?: {
1124
+ appliesTo?: (sheet: string) => boolean;
1125
+ qualifiedOnly?: boolean;
1126
+ }): string;
1127
+ /** Upper-case names used in a formula (bare names, calls and sheet-qualified names). */
1128
+ declare function formulaIdentifiers(formula: string): Array<{
1129
+ name: string;
1130
+ sheet?: string;
1131
+ call: boolean;
1132
+ }>;
1133
+
1134
+ declare class DataSourceBinder {
1135
+ private dataSources;
1136
+ register(dataSource: SpreadsheetDataSource): void;
1137
+ unregister(dataSourceId: string): void;
1138
+ getDataSource(id: string): SpreadsheetDataSource | undefined;
1139
+ /**
1140
+ * Generates or reconciles spreadsheet rows from a primary data source.
1141
+ */
1142
+ syncRows(currentRows: SpreadsheetRow[], dataSourceId: string): SpreadsheetRow[];
1143
+ /**
1144
+ * Resolves a record's bound field value.
1145
+ */
1146
+ resolveBoundValue(dataSourceId: string, recordId: string, field: string): any;
1147
+ /**
1148
+ * Dispatches an update to the underlying data source.
1149
+ */
1150
+ commitBoundValue(dataSourceId: string, recordId: string, field: string, value: any): Promise<void>;
1151
+ }
1152
+
1153
+ /**
1154
+ * Spreadsheet clipboard formats. Copying writes three representations:
1155
+ *
1156
+ * - `text/plain`: TSV of the displayed values (pastes into any app)
1157
+ * - `text/html`: an HTML `<table>` (pastes into docs, mail, other sheets)
1158
+ * - `application/x.pixerate.spreadsheet+json`: raw inputs and formulas, so a
1159
+ * paste into a pixerate spreadsheet is lossless; formulas are re-based to
1160
+ * the paste position like a spreadsheet copy/paste
1161
+ *
1162
+ * Pasting prefers the custom format, then an HTML table, then TSV. All
1163
+ * functions here are pure and DOM-free.
1164
+ */
1165
+
1166
+ declare const SPREADSHEET_CLIPBOARD_MIME = "application/x.pixerate.spreadsheet+json";
1167
+ interface SpreadsheetClipboardCell {
1168
+ raw: string;
1169
+ value: unknown;
1170
+ /** Display text for `text/plain` and `text/html` (e.g. `10%` for 0.1); defaults to the value as text. Not stored in the JSON payload. */
1171
+ text?: string;
1172
+ }
1173
+ interface SpreadsheetClipboardPayload {
1174
+ type: 'pixerate-spreadsheet';
1175
+ version: 1;
1176
+ /** Position of the copied block's top-left cell, used to re-base formulas. */
1177
+ origin: CellPosition;
1178
+ cells: SpreadsheetClipboardCell[][];
1179
+ }
1180
+ /** MIME type -> data, as written to `DataTransfer.setData`. */
1181
+ type SpreadsheetClipboardData = Record<string, string>;
1182
+ /** Anything clipboard data can be read from: a `DataTransfer` or a plain record. */
1183
+ type SpreadsheetClipboardSource = {
1184
+ getData(format: string): string;
1185
+ } | Record<string, string | undefined>;
1186
+ interface ParsedSpreadsheetClipboard {
1187
+ format: 'internal' | 'html' | 'text';
1188
+ /** Raw inputs to write, row by row. */
1189
+ rows: string[][];
1190
+ /** For internal pastes: where the block was copied from. */
1191
+ origin?: CellPosition;
1192
+ }
1193
+ /** Serializes displayed values as an HTML table. Line breaks become `<br>`. */
1194
+ declare function serializeHtmlTable(values: ReadonlyArray<ReadonlyArray<unknown>>): string;
1195
+ /**
1196
+ * Extracts cell texts from the first `<table>` in `html` (as written by
1197
+ * spreadsheet apps and browsers). `colspan`/`rowspan` cells are expanded with
1198
+ * blank cells so positions line up. Returns null when there is no table.
1199
+ */
1200
+ declare function parseHtmlTable(html: string): string[][] | null;
1201
+ /** Builds the three clipboard representations of a copied block. */
1202
+ declare function createSpreadsheetClipboardData(cells: SpreadsheetClipboardCell[][], origin: CellPosition): SpreadsheetClipboardData;
1203
+ /**
1204
+ * Reads clipboard data, preferring the lossless internal format, then an
1205
+ * HTML table, then TSV text. Returns null when there is nothing to paste.
1206
+ */
1207
+ declare function readSpreadsheetClipboard(source: SpreadsheetClipboardSource): ParsedSpreadsheetClipboard | null;
1208
+ /**
1209
+ * Moves formulas copied from `origin` so they keep their relative references
1210
+ * when pasted at `target`. Non-formula inputs are returned unchanged.
1211
+ */
1212
+ declare function rebaseClipboardRows(rows: string[][], origin: CellPosition, target: CellPosition): string[][];
1213
+
1214
+ /**
1215
+ * The render model of a spreadsheet: which rows and columns are shown, in
1216
+ * which order, with group header rows, frozen (sticky) offsets and merged
1217
+ * cell spans. Filters, hidden rows/columns and collapsed groups only affect
1218
+ * this view; the document keeps every row.
1219
+ */
1220
+
1221
+ declare const DEFAULT_ROW_HEIGHT = 32;
1222
+ declare const DEFAULT_COLUMN_WIDTH = 130;
1223
+ type SpreadsheetRowSection = 'header' | 'body' | 'footer';
1224
+ interface SpreadsheetRowGroup {
1225
+ key: string;
1226
+ label: string;
1227
+ rowIndices: number[];
1228
+ collapsed: boolean;
1229
+ summaries: Record<string, number | null>;
1230
+ }
1231
+ type SpreadsheetViewRow = {
1232
+ kind: 'row';
1233
+ row: SpreadsheetRow;
1234
+ index: number;
1235
+ section: SpreadsheetRowSection;
1236
+ frozen: boolean;
1237
+ stickyTop: number;
1238
+ groupKey?: string;
1239
+ } | {
1240
+ kind: 'group';
1241
+ group: SpreadsheetRowGroup;
1242
+ };
1243
+ interface SpreadsheetViewColumn {
1244
+ column: SpreadsheetColumn;
1245
+ index: number;
1246
+ header: boolean;
1247
+ frozen: boolean;
1248
+ stickyLeft: number;
1249
+ }
1250
+ interface SpreadsheetCellSpan {
1251
+ rowSpan: number;
1252
+ colSpan: number;
1253
+ /** The cell whose content is shown (a merge's top-left cell). */
1254
+ source: CellPosition;
1255
+ merge?: CellRange;
1256
+ }
1257
+ interface SpreadsheetViewModel {
1258
+ rows: SpreadsheetViewRow[];
1259
+ columns: SpreadsheetViewColumn[];
1260
+ groups: SpreadsheetRowGroup[];
1261
+ /** Visible document row indices in display order (for keyboard navigation). */
1262
+ rowOrder: number[];
1263
+ /** Visible document column indices in display order. */
1264
+ columnOrder: number[];
1265
+ filteredOutCount: number;
1266
+ hiddenRowCount: number;
1267
+ hiddenColumnCount: number;
1268
+ /**
1269
+ * Span of the cell rendered at (row, col): `{ rowSpan: 1, colSpan: 1 }` for
1270
+ * an ordinary cell, the visible extent for a merge's first visible cell, and
1271
+ * null for cells covered by a merge (render nothing).
1272
+ */
1273
+ getCellSpan(row: number, col: number): SpreadsheetCellSpan | null;
1274
+ }
1275
+ type CellValueReader = (rowIndex: number, colIndex: number) => unknown;
1276
+ /** Header and footer row counts, clamped so they never overlap. */
1277
+ declare function getTableSections(doc: SpreadsheetDocument): {
1278
+ headerRows: number;
1279
+ footerRows: number;
1280
+ };
1281
+ declare function getRowSection(doc: SpreadsheetDocument, rowIndex: number): SpreadsheetRowSection;
1282
+ /** Whether a body row passes the active filters. Header/footer rows always do. */
1283
+ declare function rowPassesFilters(doc: SpreadsheetDocument, rowIndex: number, getValue: CellValueReader): boolean;
1284
+ /** Category groups of the (unhidden, unfiltered) body rows. */
1285
+ declare function computeRowGroups(doc: SpreadsheetDocument, getValue: CellValueReader): SpreadsheetRowGroup[];
1286
+ declare function buildSpreadsheetView(doc: SpreadsheetDocument, getValue: CellValueReader): SpreadsheetViewModel;
1287
+
1288
+ interface CsvExportOptions {
1289
+ range?: CellRange | null;
1290
+ delimiter?: string;
1291
+ lineEnding?: string;
1292
+ bom?: boolean;
1293
+ /** Export formulas as typed (`=SUM(A1:A3)`) instead of their values. */
1294
+ formulas?: boolean;
1295
+ }
1296
+ interface CsvImportOptions {
1297
+ startRow?: number;
1298
+ startCol?: number;
1299
+ delimiter?: string;
1300
+ /** Sheet (id or name) to import into; default the active sheet. */
1301
+ sheet?: string;
1302
+ }
1303
+ type NewFilterRule = Omit<FilterRule, 'id'> & {
1304
+ id?: string;
1305
+ };
1306
+ /**
1307
+ * Invalid input waiting for the user: a `stop` alert (retry or cancel) or a
1308
+ * `warning` / `information` prompt (accept, retry or cancel). See
1309
+ * `SpreadsheetController.resolveValidationPrompt`.
1310
+ */
1311
+ interface SpreadsheetValidationPrompt {
1312
+ rowId: string;
1313
+ colId: string;
1314
+ row: number;
1315
+ col: number;
1316
+ /** The input that failed validation. */
1317
+ raw: string;
1318
+ /** The failed check: rule, alert style, title and message. */
1319
+ result: DataValidationResult;
1320
+ /** True when the input came from the cell editor (which stays open meanwhile). */
1321
+ editing: boolean;
1322
+ }
1323
+ /**
1324
+ * Outcome of committing input: `committed`; `rejected` (a `stop` rule) or
1325
+ * `confirm` (a `warning` / `information` rule), with `prompt` now waiting
1326
+ * in `validationPrompt`; `pending` when an earlier prompt is still open;
1327
+ * `none` when nothing was being edited.
1328
+ */
1329
+ type SpreadsheetCommitResult = {
1330
+ status: 'committed' | 'none';
1331
+ } | {
1332
+ status: 'rejected' | 'confirm' | 'pending';
1333
+ prompt: SpreadsheetValidationPrompt;
1334
+ };
1335
+ /** How the user answered a validation prompt. */
1336
+ type SpreadsheetValidationAction = 'accept' | 'retry' | 'cancel';
1337
+ interface SpreadsheetControllerOptions {
1338
+ document?: Partial<SpreadsheetDocument>;
1339
+ dataSources?: SpreadsheetDataSource[];
1340
+ primaryDataSourceId?: string;
1341
+ onDocumentChange?: (doc: SpreadsheetDocument) => void;
1342
+ onSelectionChange?: (activeCell: CellCoordinate | null, range: CellRange | null) => void;
1343
+ onCellCommit?: (rowId: string, colId: string, raw: string, value: any) => void;
1344
+ /**
1345
+ * Start from a workbook with several sheets and defined names instead of
1346
+ * `document`. `document` then names nothing; the active sheet is
1347
+ * `workbook.activeSheetId` (default the first sheet).
1348
+ */
1349
+ workbook?: SpreadsheetWorkbook;
1350
+ /**
1351
+ * Called after any change, like `onDocumentChange`, with the whole
1352
+ * workbook. The object holds the live sheet documents: copy it (or use
1353
+ * `getWorkbook()`) before keeping it.
1354
+ */
1355
+ onWorkbookChange?: (workbook: SpreadsheetWorkbook) => void;
1356
+ /** Called when another sheet becomes active. */
1357
+ onActiveSheetChange?: (sheetId: string) => void;
1358
+ /**
1359
+ * Approximate memory budget for undo/redo snapshots, in bytes (UTF-16 size of
1360
+ * the serialized documents). The oldest undo steps beyond it are dropped, but
1361
+ * the most recent one is always kept. Defaults to 64 MiB; 0 = unlimited.
1362
+ */
1363
+ maxHistoryBytes?: number;
1364
+ }
1365
+ /** Work done by a recalculation (see `SpreadsheetController.getRecalculationStats`). */
1366
+ interface SpreadsheetRecalculationStats {
1367
+ /** Formulas evaluated. */
1368
+ evaluated: number;
1369
+ /** Cells in the evaluation plans: formulas, their dependents and spilled cells. */
1370
+ planned: number;
1371
+ /** Evaluation passes (another pass runs when spill ranges change). */
1372
+ passes: number;
1373
+ }
1374
+ /** A defined name as listed by `getNames()`. */
1375
+ interface SpreadsheetNameInfo extends SpreadsheetDefinedName {
1376
+ /** Name of the sheet a sheet-scoped name belongs to; unset for workbook scope. */
1377
+ sheetName?: string;
1378
+ /** Whether the name holds a LAMBDA (it is called like a function). */
1379
+ isLambda: boolean;
1380
+ }
1381
+ /** Where a defined name lives: `sheet` (id or name) for a sheet-scoped name. */
1382
+ interface SpreadsheetNameScope {
1383
+ sheet?: string;
1384
+ }
1385
+ declare class SpreadsheetController {
1386
+ activeCell: CellCoordinate | null;
1387
+ selectedRange: CellRange | null;
1388
+ editingCell: CellCoordinate | null;
1389
+ draftValue: string;
1390
+ readonly binder: DataSourceBinder;
1391
+ readonly depGraph: DependencyGraph;
1392
+ readonly evaluator: FormulaEvaluator;
1393
+ private primaryDataSourceId?;
1394
+ private onDocumentChange?;
1395
+ private onWorkbookChange?;
1396
+ private onActiveSheetChange?;
1397
+ private runtimes;
1398
+ private active;
1399
+ private ctx;
1400
+ private boundSheetId;
1401
+ private names;
1402
+ private onSelectionChange?;
1403
+ private onCellCommit?;
1404
+ private undoStack;
1405
+ private redoStack;
1406
+ private isApplyingHistory;
1407
+ private readonly maxHistoryBytes;
1408
+ private batching;
1409
+ private pendingCommits;
1410
+ private evaluatingRowIndex;
1411
+ private evaluatingCell;
1412
+ private spillChanges;
1413
+ private recalcStats;
1414
+ private astCache;
1415
+ private rangeCache;
1416
+ /** The active sheet's document (the sheet the editor shows). */
1417
+ get document(): SpreadsheetDocument;
1418
+ set document(doc: SpreadsheetDocument);
1419
+ private get spills();
1420
+ private get spilledBy();
1421
+ private get spillCells();
1422
+ private cfEngine;
1423
+ private cfDirty;
1424
+ private cfIncremental;
1425
+ private valueOverride;
1426
+ private circlesShown;
1427
+ private invalidCircles;
1428
+ /** Invalid input waiting for the user's answer (see `resolveValidationPrompt`). */
1429
+ validationPrompt: SpreadsheetValidationPrompt | null;
1430
+ constructor(options?: SpreadsheetControllerOptions);
1431
+ private get boundRuntime();
1432
+ /** Runs `fn` with `rt` as the sheet `this.document` (and spills) refer to. */
1433
+ private withSheet;
1434
+ /**
1435
+ * Runs `fn` on the sheet named `sheet` (a sheet-qualified reference), or
1436
+ * on the current sheet when undefined. `#REF!` when no sheet has that name.
1437
+ */
1438
+ private onSheet;
1439
+ private findRuntimeByName;
1440
+ private findRuntimeById;
1441
+ /** A sheet by id or name. */
1442
+ private findRuntime;
1443
+ /** Dependency-graph key of a cell (`A1`) on a sheet: sheet-qualified, so keys are unique in the workbook. */
1444
+ private qualify;
1445
+ /** The sheet and A1 key of a qualified key. */
1446
+ private unqualify;
1447
+ private resolveSheetSpan;
1448
+ /** The defined name `name` visible from `rt`: its sheet-scoped name first, then the workbook one. */
1449
+ private findName;
1450
+ private resolveDefinedName;
1451
+ /**
1452
+ * Replaces the active sheet with `document` (its name becomes the sheet's
1453
+ * name, made unique). Clears undo history.
1454
+ */
1455
+ loadDocument(document: SpreadsheetDocument): void;
1456
+ /** A deep copy of the workbook: every sheet, the active sheet and the defined names. */
1457
+ getWorkbook(): SpreadsheetWorkbook;
1458
+ /** Replaces the whole workbook (sheets, names, active sheet). Clears undo history. */
1459
+ loadWorkbook(workbook: SpreadsheetWorkbook): void;
1460
+ private workbookSnapshot;
1461
+ /**
1462
+ * Installs a workbook's sheets and names (taking ownership of the objects).
1463
+ * Duplicate sheet ids and names are made unique.
1464
+ */
1465
+ private setWorkbookState;
1466
+ /**
1467
+ * Re-parses the value of every stored typed (non-formula) cell from its
1468
+ * `raw` input, so documents saved before typed input was parsed (whose
1469
+ * values are text such as `"120"`) compare and sort as numbers. Cells of
1470
+ * bound columns in record rows keep their value: it belongs to the data
1471
+ * source.
1472
+ */
1473
+ private rederiveTypedValues;
1474
+ /**
1475
+ * Value of typed (non-formula) input: a number, boolean, ISO date, error
1476
+ * or text (see `parseCellInput`), its automatic number format, and the
1477
+ * `CellFormat` to use: the automatic one (currency, percentage, date,
1478
+ * number) when `format` is unset or `text` (the default of new columns).
1479
+ */
1480
+ private typedCell;
1481
+ /**
1482
+ * The number format a cell keeps whatever is typed into it: its explicit
1483
+ * one, else its column's. Undefined lets typed input choose one.
1484
+ */
1485
+ private fixedNumberFormat;
1486
+ /** `numberFormat` / `explicitNumberFormat` fields for a formula, bound or spilled cell. */
1487
+ private fixedNumberFormatFields;
1488
+ /**
1489
+ * Typed input for a bound field, coerced by the field's declared type:
1490
+ * number, boolean and date fields get a number, boolean or ISO date when
1491
+ * the input parses as one; string and enum fields (and unknown fields)
1492
+ * keep the text exactly as typed.
1493
+ */
1494
+ private boundInputValue;
1495
+ registerDataSource(ds: SpreadsheetDataSource): void;
1496
+ setPrimaryDataSource(dataSourceId: string | undefined): void;
1497
+ syncWithDataSource(): void;
1498
+ private recomputeRowIndices;
1499
+ getColumn(colIdOrKey: string): SpreadsheetColumn | undefined;
1500
+ getRow(rowIdOrIndex: string | number): SpreadsheetRow | undefined;
1501
+ /** The row with this id on the current sheet (constant time, see `PositionCache`). */
1502
+ private findRow;
1503
+ /** The column with this id on the current sheet. */
1504
+ private findColumn;
1505
+ /** The column whose key is `key` (`A`, `B`, …): keys follow column positions. */
1506
+ private columnByKey;
1507
+ getCell(rowId: string, colId: string): CellData;
1508
+ /** `getCell` for a row and column already looked up. */
1509
+ private cellOf;
1510
+ /** A cell with no value of its own: derived (bound, column formula, blank), keeping an explicit number format. */
1511
+ private finishCell;
1512
+ /** Value of a cell with no stored data: bound record value, column formula, or blank. */
1513
+ private getDerivedCell;
1514
+ setCellValue(rowId: string, colId: string, raw: string): void;
1515
+ private getCellKey;
1516
+ /**
1517
+ * Recalculates a cell and everything that depends on it, in dependency
1518
+ * order. Every cell in a reference cycle is marked `#CYCLE!`.
1519
+ */
1520
+ recalculateCell(rowId: string, colId: string): void;
1521
+ /**
1522
+ * Registers the dependencies of the formula in `cellKey` (A1 key on the
1523
+ * current sheet), or removes them when `formula` is null: its references
1524
+ * (sheet-qualified ones on their sheet, 3-D ones on every sheet of the
1525
+ * span) and, through defined names, the cells those names refer to.
1526
+ */
1527
+ private registerFormula;
1528
+ /**
1529
+ * Spill edges made stale by new input in `cellKey`: the edges of the array
1530
+ * it anchored (its new formula re-spills when evaluated; spill changes
1531
+ * are recalculated in a further pass) and, when it now holds input, its
1532
+ * edge to the anchor whose values it held. Left in place they can close
1533
+ * false cycles with the new formulas before the anchors are evaluated.
1534
+ */
1535
+ private dropStaleSpillEdges;
1536
+ /**
1537
+ * The parsed formula, shared by dependency registration and evaluation (so
1538
+ * a load parses each formula once). ASTs are never mutated.
1539
+ */
1540
+ private parseCached;
1541
+ /**
1542
+ * Adds the qualified keys `ast` depends on, with unqualified references on
1543
+ * `home`: cells, and ranges kept whole (`SHEETID!A1:A50000`), which the
1544
+ * graph indexes as intervals instead of one key per cell. Sets
1545
+ * `volatile.found` when a volatile function (NOW, RAND, …) is used,
1546
+ * directly or through a defined name.
1547
+ */
1548
+ private collectDependencies;
1549
+ /**
1550
+ * Recalculates `keys` (and, with `includeDependents`, their dependents) in
1551
+ * dependency order. Spill ranges are only known after evaluating their
1552
+ * anchors, so when a pass changes which cells hold spilled values (and so
1553
+ * the dependency graph), the dependents of those cells are recalculated in
1554
+ * another pass, until nothing changes.
1555
+ */
1556
+ private recalculateKeys;
1557
+ /**
1558
+ * Recalculates cells of the current sheet whose stored input changed (their
1559
+ * formulas already registered), with their dependents, in one plan.
1560
+ */
1561
+ private recalculateWrittenCells;
1562
+ /**
1563
+ * Work done by the last recalculation (an edit, paste, import, load or
1564
+ * full recalculation): formulas evaluated, cells planned (formulas, their
1565
+ * dependents and spilled cells) and passes (more than one when spill
1566
+ * ranges changed). Deterministic, unlike timings: use it to check that an
1567
+ * edit only recalculates what depends on it.
1568
+ */
1569
+ getRecalculationStats(): SpreadsheetRecalculationStats;
1570
+ /**
1571
+ * Rebuilds the dependency graph from scratch and recalculates every formula
1572
+ * in dependency order.
1573
+ */
1574
+ recalculateAll(): void;
1575
+ private runEvaluationPlan;
1576
+ /**
1577
+ * Drops cached ranges of `sheetId` that cover column `col` (whose cell was
1578
+ * just evaluated), or all of the sheet's when `col` is null (spilled
1579
+ * values moved or changed).
1580
+ */
1581
+ private invalidateRangeCache;
1582
+ private locateCellKey;
1583
+ private markCycle;
1584
+ private evalSingleCellByKey;
1585
+ /**
1586
+ * Spills `array` from the anchor at (row, col) into the cells below and to
1587
+ * the right. Returns why it can't (the anchor then shows `#SPILL!`), or
1588
+ * null once placed. The grid never grows to fit an array, as in Excel.
1589
+ */
1590
+ private placeSpill;
1591
+ /** Removes the array spilled from `anchor`. With `keepEdges`, its dependency edges stay. */
1592
+ private clearSpill;
1593
+ private forgetSpilledCell;
1594
+ private resolveSpillByCoord;
1595
+ private toSpill;
1596
+ /**
1597
+ * The dynamic array covering (row, col), whether it is the anchor (the cell
1598
+ * holding the formula) or a spilled cell; null when there is none.
1599
+ */
1600
+ getSpillAt(row: number, col: number): SpreadsheetSpill | null;
1601
+ /** Every dynamic array currently spilled. */
1602
+ getSpills(): SpreadsheetSpill[];
1603
+ /** Whether `range` overlaps a spilled array (its anchor or spilled cells). */
1604
+ private intersectsSpill;
1605
+ private resolveCellByCoord;
1606
+ /**
1607
+ * Values of a range, column by column. With `skipBlanks` (functions that
1608
+ * ignore blank cells: SUM, COUNT, AVERAGE, …) blank cells are left out, so
1609
+ * a sparse column costs one lookup per row and no array slot.
1610
+ */
1611
+ private resolveRangeByCoords;
1612
+ private resolveCurrentRowProperty;
1613
+ selectCell(row: number, col: number, extendSelection?: boolean): void;
1614
+ selectRange(range: CellRange): void;
1615
+ startEditing(row?: number, col?: number, initialValue?: string): void;
1616
+ /**
1617
+ * Commits the cell editor's draft (or `valueToCommit`). Input that breaks
1618
+ * the cell's data validation is not committed: the editor stays open and
1619
+ * `validationPrompt` holds the alert until `resolveValidationPrompt`.
1620
+ * Unchanged input is not validated.
1621
+ */
1622
+ commitEditing(valueToCommit?: string): SpreadsheetCommitResult;
1623
+ /**
1624
+ * Commits typed input to a cell (e.g. from the formula bar or a list
1625
+ * dropdown) with data validation, like `commitEditing` without an open
1626
+ * editor. `setCellValue` never validates (paste, import and code bypass
1627
+ * validation, as in Excel).
1628
+ */
1629
+ commitCellInput(rowId: string, colId: string, raw: string): SpreadsheetCommitResult;
1630
+ /** Validates input; when it fails, records and returns the prompt. */
1631
+ private checkInput;
1632
+ /**
1633
+ * Answers `validationPrompt`: `accept` keeps the input (warning and
1634
+ * information alerts only; for a stop alert it acts as `retry`), `retry`
1635
+ * returns to editing it, `cancel` discards it.
1636
+ */
1637
+ resolveValidationPrompt(action: SpreadsheetValidationAction): void;
1638
+ cancelEditing(): void;
1639
+ moveCursor(direction: 'up' | 'down' | 'left' | 'right', extendSelection?: boolean): void;
1640
+ insertColumn(index: number, config?: Partial<SpreadsheetColumn>): void;
1641
+ deleteColumn(colId: string): void;
1642
+ insertRow(index: number, config?: Partial<SpreadsheetRow>): void;
1643
+ deleteRow(rowId: string): void;
1644
+ private generateId;
1645
+ /**
1646
+ * Rewrites references in every cell formula (and, for column changes, every
1647
+ * column formula) so they keep pointing at the same cells.
1648
+ */
1649
+ private shiftReferences;
1650
+ /** Filter for references, in formulas on sheet `on`, that point at sheet `target`. */
1651
+ private referencesTo;
1652
+ setColumnWidth(colId: string, width: number): void;
1653
+ autoFitColumnWidth(colId: string, customWidth?: number): void;
1654
+ /**
1655
+ * Exports cell values as TSV: the whole sheet, or only `range` (e.g. the
1656
+ * current selection) when given.
1657
+ */
1658
+ exportToTsv(range?: CellRange | null): string;
1659
+ /**
1660
+ * Pastes tab-separated values starting at (startRow, startCol), adding rows
1661
+ * and columns as needed. The whole paste is a single undo step.
1662
+ */
1663
+ importFromTsv(tsvData: string, startRow?: number, startCol?: number): void;
1664
+ /** Adds rows/columns at the end until (rowIndex, colIndex) exists. */
1665
+ private growGrid;
1666
+ /**
1667
+ * Writes raw inputs starting at (startRow, startCol), growing the grid as
1668
+ * needed, as a single undo step with one recalculation.
1669
+ */
1670
+ private writeMatrix;
1671
+ /**
1672
+ * Runs `fn` as one undo step: cell writes inside it are batched and
1673
+ * recalculated once, then listeners are notified.
1674
+ */
1675
+ private runBatch;
1676
+ /**
1677
+ * Exports the sheet (or `range`) as RFC 4180 CSV. Values are exported as
1678
+ * displayed unless `formulas` is set.
1679
+ */
1680
+ exportToCsv(options?: CsvExportOptions): string;
1681
+ /**
1682
+ * Imports CSV text at (startRow, startCol) (default A1), growing the grid
1683
+ * as needed. The whole import is a single undo step.
1684
+ */
1685
+ importFromCsv(csv: string, options?: CsvImportOptions): void;
1686
+ /** Runs `fn` on the sheet `sheet` (id or name), default the active one. Throws for an unknown sheet. */
1687
+ private onTargetSheet;
1688
+ /**
1689
+ * Writes already-parsed rows of raw inputs (e.g. from an import adapter)
1690
+ * starting at (startRow, startCol), as a single undo step.
1691
+ */
1692
+ importRows(rows: string[][], options?: Omit<CsvImportOptions, 'delimiter'>): void;
1693
+ /** The cells of `range` (or the whole sheet), row by row. */
1694
+ private readMatrix;
1695
+ /**
1696
+ * Builds clipboard data for `range` (default: the selection) as TSV,
1697
+ * an HTML table and the lossless internal JSON format. Write every entry
1698
+ * with `clipboardData.setData(type, data)` in a `copy` event.
1699
+ */
1700
+ copyToClipboardData(range?: CellRange | null): SpreadsheetClipboardData;
1701
+ /**
1702
+ * Pastes clipboard data at `target` (default: the selection's top-left).
1703
+ * Prefers the internal format (formulas re-based to the target), then an
1704
+ * HTML table, then TSV. Returns false when there was nothing to paste.
1705
+ */
1706
+ pasteClipboardData(source: SpreadsheetClipboardSource, target?: CellPosition): boolean;
1707
+ private spillAnchorInRange;
1708
+ private getSelectionTopLeft;
1709
+ /** The table settings object, created on first use. */
1710
+ private get table();
1711
+ /** Records an undo step, applies `fn`, then notifies listeners. */
1712
+ private applyTableChange;
1713
+ /** First and last (inclusive) body row: rows between header and footer rows. */
1714
+ private getBodyRowBounds;
1715
+ private getCellValueAt;
1716
+ /** Rewrites every formula so references follow cells that moved. */
1717
+ private remapAllFormulas;
1718
+ /**
1719
+ * Keeps merges in place when rows/columns are inserted or deleted:
1720
+ * merges after the change shift, merges across it grow or shrink, and
1721
+ * merges reduced to a single cell are dropped.
1722
+ */
1723
+ private adjustTableForStructuralChange;
1724
+ /**
1725
+ * Sorts rows by one or more columns (stable; numbers before text, blanks
1726
+ * last). Without a range (or with a range spanning every column) whole rows
1727
+ * move; with a range only the cells inside it move. Header and footer rows
1728
+ * never move. References follow the moved cells. Returns false when the
1729
+ * sort is rejected (no valid keys, a key outside the range, or merged
1730
+ * cells in the sorted area).
1731
+ */
1732
+ sortRows(keys: SortKey[], options?: {
1733
+ range?: CellRange | null;
1734
+ }): boolean;
1735
+ getFilterState(): SpreadsheetFilterState;
1736
+ /** Replaces all filter rules (and turns filters on when there are any). */
1737
+ setFilterRules(rules: NewFilterRule[]): void;
1738
+ /** Adds a filter rule (AND-combined with the others) and turns filters on. Returns its id. */
1739
+ addFilterRule(rule: NewFilterRule): string;
1740
+ updateFilterRule(ruleId: string, changes: Partial<Omit<FilterRule, 'id'>>): void;
1741
+ removeFilterRule(ruleId: string): void;
1742
+ clearFilters(): void;
1743
+ /** Turns filtering on or off, keeping the rules. */
1744
+ setFiltersEnabled(enabled: boolean): void;
1745
+ toggleFilters(): void;
1746
+ private generateFilterId;
1747
+ setHeaderRowCount(count: number): void;
1748
+ setFooterRowCount(count: number): void;
1749
+ setHeaderColumnCount(count: number): void;
1750
+ /** Keeps the first `count` rows visible while scrolling. 0 unfreezes. */
1751
+ setFrozenRowCount(count: number): void;
1752
+ /** Keeps the first `count` columns visible while scrolling. 0 unfreezes. */
1753
+ setFrozenColumnCount(count: number): void;
1754
+ private setTableCount;
1755
+ /**
1756
+ * Sets an explicit number format code (e.g. `0.00`, `"$"#,##0.00`,
1757
+ * `m/d/yyyy`, `[Red]0;[Blue]-0`) on every cell in `range`, including blank
1758
+ * cells, so values typed later keep it. `null` removes explicit formats: the
1759
+ * cells go back to their column's format or the one chosen for typed input.
1760
+ * Undoable as one step. Returns false when there is no range.
1761
+ */
1762
+ setCellNumberFormat(range: CellRange | null, code: string | null): boolean;
1763
+ /**
1764
+ * Sets the number format code of a column (`null` or `General` clears it).
1765
+ * Its cells without an explicit format of their own use it, including
1766
+ * values typed later; when cleared they go back to the format chosen for
1767
+ * typed input. Undoable.
1768
+ */
1769
+ setColumnNumberFormat(colId: string, code: string | null): void;
1770
+ /** The column's format, or the one typed input chose (typed cells only). */
1771
+ private implicitNumberFormat;
1772
+ /** A copy of `cell` with `numberFormat` set, or removed when undefined. */
1773
+ private withNumberFormat;
1774
+ /** Re-applies the stored cell's (or the column's) format to a spilled value shown there. */
1775
+ private refreshSpilledNumberFormat;
1776
+ hideRows(indices: number[]): void;
1777
+ unhideRows(indices: number[]): void;
1778
+ hideColumns(indices: number[]): void;
1779
+ unhideColumns(indices: number[]): void;
1780
+ /** Unhides every hidden row and column (filters are unaffected). */
1781
+ unhideAll(): void;
1782
+ private setHidden;
1783
+ getMerges(): CellRange[];
1784
+ /** The merge containing (row, col), or null. */
1785
+ getMergeAt(row: number, col: number): CellRange | null;
1786
+ /** Grows `range` until no merge crosses its edge. Keeps the drag direction. */
1787
+ expandRangeToMerges(range: CellRange): CellRange;
1788
+ /**
1789
+ * Merges `range` (default: the selection) into one cell anchored on its
1790
+ * top-left cell; the other cells are cleared. Merges fully inside the range
1791
+ * are absorbed. Returns false for single cells and for ranges that
1792
+ * partially overlap an existing merge.
1793
+ */
1794
+ mergeCells(range?: CellRange | null): boolean;
1795
+ /** Removes every merge intersecting `range` (default: the selection). */
1796
+ unmergeCells(range?: CellRange | null): boolean;
1797
+ /**
1798
+ * Fills `target` from `source` like dragging the fill handle. `target` is
1799
+ * the extended range (source included) and must extend `source` down, up,
1800
+ * right or left. Numbers and dates continue their series, text ending in a
1801
+ * number counts up, other text repeats, and formulas are copied with
1802
+ * their relative references shifted (`$` parts stay). Returns false when
1803
+ * the ranges don't line up.
1804
+ */
1805
+ autofill(source: CellRange, target: CellRange): boolean;
1806
+ /**
1807
+ * Groups body rows by the value in `colId`, with optional per-group
1808
+ * summaries (e.g. `[{ colId, aggregate: 'sum' }]`).
1809
+ */
1810
+ groupRowsBy(colId: string, summaries?: GroupSummary[]): void;
1811
+ ungroupRows(): void;
1812
+ /** Sets (or with `null`, removes) the group summary for a column. */
1813
+ setGroupSummary(colId: string, aggregate: GroupAggregate | null): void;
1814
+ setGroupCollapsed(key: string, collapsed: boolean): void;
1815
+ toggleGroupCollapsed(key: string): void;
1816
+ /** The current row groups with their summaries (empty when not grouped). */
1817
+ getGroups(): SpreadsheetRowGroup[];
1818
+ /**
1819
+ * Transposes `range` (default: the selection) in place around its top-left
1820
+ * cell: rows become columns. Cells left uncovered are cleared, the grid
1821
+ * grows if needed, and references follow the moved cells. Returns false
1822
+ * for single cells or when merged cells are involved.
1823
+ */
1824
+ transposeRange(range?: CellRange | null): boolean;
1825
+ /**
1826
+ * What to render: visible rows (with group headers) and columns in display
1827
+ * order, frozen offsets and merged-cell spans. Filters, hidden rows/columns
1828
+ * and collapsed groups only affect this view, never the document.
1829
+ */
1830
+ getViewModel(): SpreadsheetViewModel;
1831
+ /** The sheets in tab order. */
1832
+ getSheets(): SpreadsheetSheetInfo[];
1833
+ /** Id of the active sheet (the one `document` is). */
1834
+ get activeSheetId(): string;
1835
+ /** A sheet's document by id or name (live: don't mutate it directly). */
1836
+ getSheetDocument(idOrName: string): SpreadsheetDocument | undefined;
1837
+ /** Why `name` can't name a sheet (or null): see `validateSheetName`. `exceptSheet` is the sheet being renamed. */
1838
+ validateSheetName(name: string, exceptSheet?: string): string | null;
1839
+ /**
1840
+ * Shows another sheet (by id or name). The current edit is committed and
1841
+ * each sheet keeps its own selection. Returns false for an unknown sheet.
1842
+ */
1843
+ setActiveSheet(idOrName: string): boolean;
1844
+ private activateRuntime;
1845
+ /**
1846
+ * Adds a sheet (default: `Sheet N`, empty, after the last sheet) and
1847
+ * activates it unless `activate` is false. Returns its id. Throws when
1848
+ * `name` is invalid or taken. Undoable.
1849
+ */
1850
+ addSheet(options?: {
1851
+ name?: string;
1852
+ index?: number;
1853
+ document?: Partial<SpreadsheetDocument>;
1854
+ activate?: boolean;
1855
+ }): string;
1856
+ /**
1857
+ * Renames a sheet. Formulas on every sheet and defined names that refer to
1858
+ * it follow (`=Old!A1` becomes `='New Name'!A1`). Throws when the name is
1859
+ * invalid or taken. Undoable.
1860
+ */
1861
+ renameSheet(idOrName: string, newName: string): void;
1862
+ /** Moves a sheet to position `toIndex` in tab order. Returns false for an unknown sheet. Undoable. */
1863
+ moveSheet(idOrName: string, toIndex: number): boolean;
1864
+ /**
1865
+ * Deletes a sheet and its sheet-scoped names. References to it become
1866
+ * `#REF!` (a 3-D reference losing an end sheet shrinks). The last sheet
1867
+ * can't be deleted (returns false). Undoable.
1868
+ */
1869
+ deleteSheet(idOrName: string): boolean;
1870
+ /**
1871
+ * Copies a sheet (default name `Name (2)`, placed after it) with its
1872
+ * sheet-scoped names, which refer to the copy. Activates the copy unless
1873
+ * `activate` is false. Returns the new sheet's id, or null for an unknown
1874
+ * sheet. Undoable.
1875
+ */
1876
+ duplicateSheet(idOrName: string, options?: {
1877
+ name?: string;
1878
+ index?: number;
1879
+ activate?: boolean;
1880
+ }): string | null;
1881
+ /** Applies `rewrite` to every formula: cells and column formulas on every sheet, and defined names. */
1882
+ private rewriteAllFormulas;
1883
+ private generateSheetId;
1884
+ /** Every defined name, workbook-scoped and sheet-scoped. */
1885
+ getNames(): SpreadsheetNameInfo[];
1886
+ /** The defined name `name` visible from the active sheet (its own sheet-scoped name first), or undefined. */
1887
+ getName(name: string, scope?: SpreadsheetNameScope): SpreadsheetNameInfo | undefined;
1888
+ /** Why `name` can't be a defined name (or null): see `validateDefinedName`. */
1889
+ validateDefinedName(name: string): string | null;
1890
+ private scopeRuntime;
1891
+ /**
1892
+ * Defines (or redefines) a name in the workbook, or on one sheet with
1893
+ * `sheet`. `refersTo` is a formula: a range (`=Data!$A$2:$A$20`), a
1894
+ * constant (`=0.07`), a formula or a LAMBDA (`=LAMBDA(x, x*2)`, called as
1895
+ * `=Double(4)`). Formulas using the name recalculate. Throws when the name
1896
+ * is invalid or the formula can't be read. Undoable.
1897
+ */
1898
+ defineName(name: string, refersTo: string, options?: SpreadsheetNameScope & {
1899
+ comment?: string;
1900
+ }): void;
1901
+ /**
1902
+ * Renames a defined name. Formulas that use it (cells, column formulas and
1903
+ * other names) follow, on the sheets where the old name meant this one.
1904
+ * Throws when the name doesn't exist or the new name is invalid or taken.
1905
+ * Undoable.
1906
+ */
1907
+ renameName(oldName: string, newName: string, options?: SpreadsheetNameScope): void;
1908
+ /**
1909
+ * Deletes a defined name. Formulas still using it show `#NAME?`. Returns
1910
+ * false when there is no such name. Undoable.
1911
+ */
1912
+ deleteName(name: string, options?: SpreadsheetNameScope): boolean;
1913
+ /**
1914
+ * Names formula autocomplete can offer on the active sheet: its
1915
+ * sheet-scoped names and the workbook names they don't hide.
1916
+ */
1917
+ getNameSuggestions(): Array<{
1918
+ name: string;
1919
+ description: string;
1920
+ isLambda: boolean;
1921
+ }>;
1922
+ /**
1923
+ * Evaluates a formula (e.g. `=Rate*2`, `=SUM(Sales)`) as if it were in a
1924
+ * cell of `sheet` (id or name; default the active sheet), without storing
1925
+ * it. Used by the Name Manager to show a name's current value.
1926
+ */
1927
+ evaluateFormula(formula: string, options?: {
1928
+ sheet?: string;
1929
+ }): FormulaEvaluationResult;
1930
+ private recordSnapshot;
1931
+ /** Records the stored state of one cell, for undoing a single-cell edit. */
1932
+ private recordCellSnapshot;
1933
+ private cellHistory;
1934
+ private recordWorkbookSnapshot;
1935
+ private pushUndo;
1936
+ /** Drops the oldest snapshots beyond `maxHistoryBytes`, always keeping the newest. */
1937
+ private trimHistory;
1938
+ /** Approximate bytes held by the undo/redo snapshots (UTF-16 size). */
1939
+ getHistoryByteSize(): number;
1940
+ /** Number of undo / redo snapshots currently held. */
1941
+ getHistoryDepth(): {
1942
+ undo: number;
1943
+ redo: number;
1944
+ };
1945
+ undo(): void;
1946
+ redo(): void;
1947
+ /** Restores the newest entry of `from`, saving the current state of the same scope on `to`. */
1948
+ private applyHistory;
1949
+ private notifyChange;
1950
+ /** The sheet as rule evaluation sees it. */
1951
+ private ruleSheet;
1952
+ /**
1953
+ * Evaluates `formula` as if it were in (row, col), without storing it:
1954
+ * relative references and `[property]` resolve from that cell. With
1955
+ * `entered`, that cell reads as the given value (input being validated).
1956
+ * Returns the value, or an array's values (column-major) for a range.
1957
+ */
1958
+ evaluateFormulaAt(formula: string, row: number, col: number, entered?: {
1959
+ row: number;
1960
+ col: number;
1961
+ value: unknown;
1962
+ }): unknown;
1963
+ /** Records that the value of `cellKey` (and of the array it spills) may have changed. */
1964
+ private markValueChanged;
1965
+ private generateRuleId;
1966
+ /** Moves rule ranges and rule formulas with inserted / deleted rows and columns. */
1967
+ private adjustRulesForStructuralChange;
1968
+ /** Conditional formats of the sheet, highest priority first. */
1969
+ getConditionalFormats(): ConditionalFormatRule[];
1970
+ /**
1971
+ * Adds a conditional format (one undo step). New rules get the highest
1972
+ * priority, as in Excel; pass `priority: 'last'` to add it below the
1973
+ * others. Returns the rule id.
1974
+ */
1975
+ addConditionalFormat(rule: NewConditionalFormatRule, options?: {
1976
+ priority?: 'first' | 'last';
1977
+ }): string;
1978
+ /** Changes a conditional format (its condition, ranges or stop-if-true). Returns false when not found. */
1979
+ updateConditionalFormat(id: string, changes: Partial<NewConditionalFormatRule>): boolean;
1980
+ /** Removes a conditional format. Returns false when not found. */
1981
+ deleteConditionalFormat(id: string): boolean;
1982
+ /**
1983
+ * Moves a conditional format to priority `to` (0 = highest), or by
1984
+ * `{ by: -1 }` (up) / `{ by: 1 }` (down). Returns false when nothing moved.
1985
+ */
1986
+ moveConditionalFormat(id: string, to: number | {
1987
+ by: number;
1988
+ }): boolean;
1989
+ /**
1990
+ * Removes conditional formatting from the cells of `range` (rules keep
1991
+ * their other cells; rules left without cells are deleted), or every rule
1992
+ * when `range` is null.
1993
+ */
1994
+ clearConditionalFormats(range?: CellRange | null): void;
1995
+ /**
1996
+ * The conditional look of every formatted cell. Evaluated on demand and
1997
+ * cached: after a cell edit only the affected cells are re-evaluated.
1998
+ */
1999
+ getConditionalFormatOverlay(): ConditionalFormatOverlay;
2000
+ /** The conditional look of (row, col), if any. */
2001
+ getConditionalFormat(row: number, col: number): ConditionalCellFormat | undefined;
2002
+ /** Data validation rules of the sheet. */
2003
+ getDataValidations(): DataValidationRule[];
2004
+ /** The rule that applies to (row, col), if any. */
2005
+ getDataValidationAt(row: number, col: number): DataValidationRule | undefined;
2006
+ /**
2007
+ * Adds a data validation rule (one undo step). Its cells are first
2008
+ * removed from other rules, so each cell has at most one. Returns the id.
2009
+ */
2010
+ addDataValidation(rule: NewDataValidationRule): string;
2011
+ /** Changes a data validation rule. Returns false when not found. */
2012
+ updateDataValidation(id: string, changes: Partial<NewDataValidationRule>): boolean;
2013
+ /** Removes a data validation rule. Returns false when not found. */
2014
+ deleteDataValidation(id: string): boolean;
2015
+ /** Removes validation from the cells of `range`, or every rule when `range` is null. */
2016
+ clearDataValidation(range?: CellRange | null): void;
2017
+ /** Checks input for (row, col) against its data validation, without committing it. */
2018
+ validateCellInput(row: number, col: number, raw: string): DataValidationResult;
2019
+ /**
2020
+ * Dropdown items of a list-validated cell, or null when the cell has no
2021
+ * list rule (or its in-cell dropdown is off).
2022
+ */
2023
+ getValidationListValues(row: number, col: number): string[] | null;
2024
+ /** Cells whose current value breaks their validation rule. */
2025
+ findInvalidCells(): CellPosition[];
2026
+ /**
2027
+ * Turns "circle invalid data" on or off. View state, not part of the
2028
+ * document (not undoable, not saved); listeners are notified so the grid
2029
+ * redraws.
2030
+ */
2031
+ setInvalidDataCircles(show: boolean): void;
2032
+ /** Whether invalid cells are circled. */
2033
+ getInvalidDataCircles(): boolean;
2034
+ /** Whether (row, col) is circled as invalid (always false while circles are off). */
2035
+ isInvalidDataCircled(row: number, col: number): boolean;
2036
+ }
2037
+
2038
+ export { type GroupAggregate as $, type ASTNode as A, type BinaryOpNode as B, type CellCoordinate as C, DEFAULT_COLUMN_WIDTH as D, type DataValidationResult as E, type DataValidationRule as F, type DataValidationSheet as G, type DataValidationType as H, DependencyGraph as I, type DependencyIndexStats as J, type EvaluationContext as K, FORMULA_ERRORS as L, type FilterOperator as M, type FilterRule as N, type FormulaDiagnostic as O, type FormulaErrorCode as P, type FormulaEvaluationResult as Q, FormulaEvaluator as R, SpreadsheetController as S, type FormulaNameDefinition as T, FormulaParser as U, type FormulaRange as V, type FormulaReferenceFilter as W, type FormulaReferenceInfo as X, type FormulaToken as Y, type FormulaTokenType as Z, type FunctionCallNode as _, type CellData as a, extractCellDependencies as a$, type GroupSummary as a0, IntervalIndex as a1, type InvokeNode as a2, type LiteralNode as a3, MAX_FORMULA_ARRAY_SIZE as a4, type MissingNode as a5, type NameDep as a6, type NameNode as a7, type NewConditionalFormatRule as a8, type NewDataValidationRule as a9, type SpreadsheetNameInfo as aA, type SpreadsheetNameScope as aB, type SpreadsheetRecalculationStats as aC, type SpreadsheetRow as aD, type SpreadsheetRowGroup as aE, type SpreadsheetRowSection as aF, type SpreadsheetSheetInfo as aG, type SpreadsheetSpill as aH, type SpreadsheetTableSettings as aI, type SpreadsheetValidationAction as aJ, type SpreadsheetValidationPrompt as aK, type SpreadsheetViewColumn as aL, type SpreadsheetViewModel as aM, type SpreadsheetViewRow as aN, type SpreadsheetWorkbook as aO, type StructuralChange as aP, type UnaryOpNode as aQ, WHOLE_COLUMN_END_ROW as aR, buildSpreadsheetView as aS, colNameToIndex as aT, columnDependencyKey as aU, compareNumbers as aV, compareValues as aW, computeRowGroups as aX, createSpreadsheetClipboardData as aY, deleteSheetInFormula as aZ, describeFormulaError as a_, type NewFilterRule as aa, type ParsedSpreadsheetClipboard as ab, type PropertyRefNode as ac, type RangeNode as ad, type RangeResolveOptions as ae, type ReferenceDep as af, type RowType as ag, SPREADSHEET_CLIPBOARD_MIME as ah, type SheetQualifier as ai, type SortDirection as aj, type SortKey as ak, type SpillRefNode as al, type SpreadsheetCellSpan as am, type SpreadsheetClipboardCell as an, type SpreadsheetClipboardData as ao, type SpreadsheetClipboardPayload as ap, type SpreadsheetClipboardSource as aq, type SpreadsheetColumn as ar, type SpreadsheetCommitResult as as, type SpreadsheetControllerOptions as at, type SpreadsheetDataSource as au, type SpreadsheetDataSourceField as av, type SpreadsheetDefinedName as aw, type SpreadsheetDocument as ax, type SpreadsheetFilterState as ay, type SpreadsheetGrouping as az, type CellDep as b, extractNameDependencies as b0, extractReferenceDependencies as b1, formatSheetPrefix as b2, formulaIdentifiers as b3, getRowSection as b4, getTableSections as b5, indexToColName as b6, isFormulaError as b7, mapFormulaReferences as b8, numberToText as b9, offsetFormulaReferences as ba, parseCellReference as bb, parseFormula as bc, parseHtmlTable as bd, parseRange as be, quoteSheetName as bf, rangeDependencyKey as bg, readSpreadsheetClipboard as bh, rebaseClipboardRows as bi, remapFormulaReferences as bj, renameNameInFormula as bk, renameSheetInFormula as bl, rowPassesFilters as bm, serializeHtmlTable as bn, sheetNameNeedsQuotes as bo, shiftFormulaReferences as bp, sortCompareValues as bq, tokenizeFormula as br, type CellFormat as c, type CellPosition as d, type CellRange as e, type CellRefNode as f, type CellValueReader as g, type ColumnBinding as h, type ColumnType as i, type ConditionalCellFormat as j, type ConditionalFormatCondition as k, type ConditionalFormatIconSet as l, type ConditionalFormatOperator as m, type ConditionalFormatOverlay as n, type ConditionalFormatRule as o, type ConditionalFormatSheet as p, type ConditionalFormatStyle as q, type ConditionalFormatTimePeriod as r, type ConditionalFormatType as s, type ConditionalFormatValue as t, type CsvExportOptions as u, type CsvImportOptions as v, DEFAULT_ROW_HEIGHT as w, DataSourceBinder as x, type DataValidationErrorStyle as y, type DataValidationOperator as z };