@pixerate/editor 0.19.0 → 0.20.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 (112) hide show
  1. package/README.md +91 -2
  2. package/dist/agent/index.cjs +625 -2
  3. package/dist/agent/index.cjs.map +1 -1
  4. package/dist/agent/index.d.cts +286 -2
  5. package/dist/agent/index.d.ts +286 -2
  6. package/dist/agent/index.js +624 -1
  7. package/dist/agent/index.js.map +1 -1
  8. package/dist/canvas/index.cjs +1240 -22
  9. package/dist/canvas/index.cjs.map +1 -1
  10. package/dist/canvas/index.d.cts +515 -3
  11. package/dist/canvas/index.d.ts +515 -3
  12. package/dist/canvas/index.js +1219 -1
  13. package/dist/canvas/index.js.map +1 -1
  14. package/dist/chunk-3TYMNULT.js +1367 -0
  15. package/dist/chunk-3TYMNULT.js.map +1 -0
  16. package/dist/chunk-4QPLEUL2.cjs +4480 -0
  17. package/dist/chunk-4QPLEUL2.cjs.map +1 -0
  18. package/dist/chunk-4SUNJZWB.cjs +553 -0
  19. package/dist/chunk-4SUNJZWB.cjs.map +1 -0
  20. package/dist/chunk-A7DKIA72.js +2657 -0
  21. package/dist/chunk-A7DKIA72.js.map +1 -0
  22. package/dist/chunk-AXV2ZW34.cjs +118 -0
  23. package/dist/chunk-AXV2ZW34.cjs.map +1 -0
  24. package/dist/chunk-B2ZRLN4S.js +118 -0
  25. package/dist/chunk-B2ZRLN4S.js.map +1 -0
  26. package/dist/chunk-CYFJCKC4.js +4480 -0
  27. package/dist/chunk-CYFJCKC4.js.map +1 -0
  28. package/dist/chunk-GVW4P7BG.js +2706 -0
  29. package/dist/chunk-GVW4P7BG.js.map +1 -0
  30. package/dist/chunk-JACER6TE.cjs +1 -0
  31. package/dist/chunk-JACER6TE.cjs.map +1 -0
  32. package/dist/chunk-JYRIOFEN.cjs +2657 -0
  33. package/dist/chunk-JYRIOFEN.cjs.map +1 -0
  34. package/dist/chunk-KYRZDWM4.js +299 -0
  35. package/dist/chunk-KYRZDWM4.js.map +1 -0
  36. package/dist/chunk-LA7PEGU3.cjs +299 -0
  37. package/dist/chunk-LA7PEGU3.cjs.map +1 -0
  38. package/dist/chunk-N7FG6CBO.js +1 -0
  39. package/dist/chunk-N7FG6CBO.js.map +1 -0
  40. package/dist/chunk-OYXSKQFR.js +553 -0
  41. package/dist/chunk-OYXSKQFR.js.map +1 -0
  42. package/dist/chunk-TVRC4KVT.cjs +1367 -0
  43. package/dist/chunk-TVRC4KVT.cjs.map +1 -0
  44. package/dist/chunk-U6NDQFOK.cjs +2706 -0
  45. package/dist/chunk-U6NDQFOK.cjs.map +1 -0
  46. package/dist/controller-OUdxPY-X.d.cts +754 -0
  47. package/dist/controller-OUdxPY-X.d.ts +754 -0
  48. package/dist/extensions/index.cjs +144 -3
  49. package/dist/extensions/index.cjs.map +1 -1
  50. package/dist/extensions/index.d.cts +9 -144
  51. package/dist/extensions/index.d.ts +9 -144
  52. package/dist/extensions/index.js +145 -4
  53. package/dist/grammar/index.cjs +31 -3
  54. package/dist/grammar/index.cjs.map +1 -1
  55. package/dist/grammar/index.d.cts +239 -19
  56. package/dist/grammar/index.d.ts +239 -19
  57. package/dist/grammar/index.js +31 -3
  58. package/dist/history/index.d.cts +2 -41
  59. package/dist/history/index.d.ts +2 -41
  60. package/dist/index-Ng1pG7JE.d.ts +899 -0
  61. package/dist/index-k3mFbPx_.d.cts +899 -0
  62. package/dist/index.cjs +457 -20
  63. package/dist/index.cjs.map +1 -1
  64. package/dist/index.d.cts +99 -12
  65. package/dist/index.d.ts +99 -12
  66. package/dist/index.js +457 -20
  67. package/dist/index.js.map +1 -1
  68. package/dist/registry-iAHbqkYt.d.cts +128 -0
  69. package/dist/registry-iAHbqkYt.d.ts +128 -0
  70. package/dist/serializers/index.cjs +26 -3
  71. package/dist/serializers/index.cjs.map +1 -1
  72. package/dist/serializers/index.d.cts +119 -6
  73. package/dist/serializers/index.d.ts +119 -6
  74. package/dist/serializers/index.js +24 -1
  75. package/dist/spreadsheet/index.cjs +122 -2
  76. package/dist/spreadsheet/index.cjs.map +1 -1
  77. package/dist/spreadsheet/index.d.cts +371 -313
  78. package/dist/spreadsheet/index.d.ts +371 -313
  79. package/dist/spreadsheet/index.js +127 -7
  80. package/dist/tokens-CyLZmIei.d.cts +76 -0
  81. package/dist/tokens-CyLZmIei.d.ts +76 -0
  82. package/dist/track-changes-G8JcWB8b.d.cts +306 -0
  83. package/dist/track-changes-G8JcWB8b.d.ts +306 -0
  84. package/dist/types-BZgcDsC5.d.cts +42 -0
  85. package/dist/types-BZgcDsC5.d.ts +42 -0
  86. package/dist/{types-JV3S8VeR.d.cts → types-DMe0vFB1.d.cts} +1 -1
  87. package/dist/{types-JV3S8VeR.d.ts → types-DMe0vFB1.d.ts} +1 -1
  88. package/package.json +1 -1
  89. package/dist/chunk-7FWEWE6T.js +0 -1888
  90. package/dist/chunk-7FWEWE6T.js.map +0 -1
  91. package/dist/chunk-AIZUKWTL.js +0 -1715
  92. package/dist/chunk-AIZUKWTL.js.map +0 -1
  93. package/dist/chunk-GLSIZKOX.js +0 -17
  94. package/dist/chunk-GLSIZKOX.js.map +0 -1
  95. package/dist/chunk-LDES3EOS.cjs +0 -1888
  96. package/dist/chunk-LDES3EOS.cjs.map +0 -1
  97. package/dist/chunk-LLUAKTLW.cjs +0 -532
  98. package/dist/chunk-LLUAKTLW.cjs.map +0 -1
  99. package/dist/chunk-MPPXH7U5.cjs +0 -336
  100. package/dist/chunk-MPPXH7U5.cjs.map +0 -1
  101. package/dist/chunk-O7LOPQMH.js +0 -336
  102. package/dist/chunk-O7LOPQMH.js.map +0 -1
  103. package/dist/chunk-QGVMBCT5.js +0 -532
  104. package/dist/chunk-QGVMBCT5.js.map +0 -1
  105. package/dist/chunk-SEDR75VH.cjs +0 -17
  106. package/dist/chunk-SEDR75VH.cjs.map +0 -1
  107. package/dist/chunk-YQCI4CCN.cjs +0 -1715
  108. package/dist/chunk-YQCI4CCN.cjs.map +0 -1
  109. package/dist/mention-Dcevh3ff.d.cts +0 -32
  110. package/dist/mention-Dcevh3ff.d.ts +0 -32
  111. package/dist/tokens-7kRTEtPb.d.cts +0 -39
  112. package/dist/tokens-7kRTEtPb.d.ts +0 -39
@@ -1,1715 +0,0 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2; var _class3; var _class4;// src/spreadsheet/formula/lexer.ts
2
- function tokenizeFormula(formula) {
3
- const tokens = [];
4
- let input = formula.trim();
5
- let offset = 0;
6
- if (input.startsWith("=")) {
7
- input = input.slice(1);
8
- offset = 1;
9
- }
10
- let i = 0;
11
- while (i < input.length) {
12
- const char = input[i];
13
- if (/\s/.test(char)) {
14
- i++;
15
- continue;
16
- }
17
- if (/\d/.test(char) || char === "." && i + 1 < input.length && /\d/.test(input[i + 1])) {
18
- const start = i;
19
- let hasDot = char === ".";
20
- i++;
21
- while (i < input.length && (/\d/.test(input[i]) || input[i] === "." && !hasDot)) {
22
- if (input[i] === ".") hasDot = true;
23
- i++;
24
- }
25
- tokens.push({
26
- type: "NUMBER",
27
- value: input.slice(start, i),
28
- position: start + offset
29
- });
30
- continue;
31
- }
32
- if (char === '"' || char === "'") {
33
- const quote = char;
34
- const start = i;
35
- i++;
36
- let str = "";
37
- while (i < input.length && input[i] !== quote) {
38
- if (input[i] === "\\" && i + 1 < input.length) {
39
- i++;
40
- }
41
- str += input[i];
42
- i++;
43
- }
44
- if (i >= input.length) {
45
- throw new Error(`Unterminated string starting at position ${start + offset}`);
46
- }
47
- i++;
48
- tokens.push({
49
- type: "STRING",
50
- value: str,
51
- position: start + offset
52
- });
53
- continue;
54
- }
55
- if (char === "#") {
56
- const match = /^#(?:REF!|DIV\/0!|VALUE!|NAME\?|N\/A|NUM!|CYCLE!|ERROR!)/.exec(input.slice(i));
57
- if (!match) {
58
- throw new Error(`Unexpected character '#' at position ${i + offset}`);
59
- }
60
- tokens.push({ type: "ERROR", value: match[0], position: i + offset });
61
- i += match[0].length;
62
- continue;
63
- }
64
- if (char === "[") {
65
- const start = i;
66
- i++;
67
- let prop = "";
68
- while (i < input.length && input[i] !== "]") {
69
- prop += input[i];
70
- i++;
71
- }
72
- if (i < input.length && input[i] === "]") {
73
- i++;
74
- }
75
- tokens.push({
76
- type: "PROPERTY_REF",
77
- value: prop.trim(),
78
- position: start + offset
79
- });
80
- continue;
81
- }
82
- if (char === "(") {
83
- tokens.push({ type: "LPAREN", value: "(", position: i + offset });
84
- i++;
85
- continue;
86
- }
87
- if (char === ")") {
88
- tokens.push({ type: "RPAREN", value: ")", position: i + offset });
89
- i++;
90
- continue;
91
- }
92
- if (char === ",") {
93
- tokens.push({ type: "COMMA", value: ",", position: i + offset });
94
- i++;
95
- continue;
96
- }
97
- const twoChars = input.slice(i, i + 2);
98
- if (["<=", ">=", "<>", "!="].includes(twoChars)) {
99
- tokens.push({
100
- type: "OPERATOR",
101
- value: twoChars === "!=" ? "<>" : twoChars,
102
- position: i + offset
103
- });
104
- i += 2;
105
- continue;
106
- }
107
- if (["+", "-", "*", "/", "^", "&", "=", "<", ">"].includes(char)) {
108
- tokens.push({ type: "OPERATOR", value: char, position: i + offset });
109
- i++;
110
- continue;
111
- }
112
- if (/[a-zA-Z_$]/.test(char)) {
113
- const start = i;
114
- while (i < input.length && /[a-zA-Z0-9_$.]/.test(input[i])) {
115
- i++;
116
- }
117
- const rawWord = input.slice(start, i);
118
- if (i < input.length && input[i] === ":") {
119
- const colonPos = i;
120
- i++;
121
- const secondStart = i;
122
- while (i < input.length && /[a-zA-Z0-9_$.]/.test(input[i])) {
123
- i++;
124
- }
125
- const secondWord = input.slice(secondStart, i);
126
- if (secondWord.length > 0) {
127
- tokens.push({
128
- type: "RANGE",
129
- value: `${rawWord}:${secondWord}`.toUpperCase(),
130
- position: start + offset
131
- });
132
- continue;
133
- } else {
134
- i = colonPos;
135
- }
136
- }
137
- const upper = rawWord.toUpperCase();
138
- if (upper === "TRUE" || upper === "FALSE") {
139
- tokens.push({
140
- type: "BOOLEAN",
141
- value: upper,
142
- position: start + offset
143
- });
144
- continue;
145
- }
146
- if (/^\$?[A-Za-z]+\$?[0-9]+$/.test(rawWord)) {
147
- tokens.push({
148
- type: "CELL_REF",
149
- value: upper.replace(/\$/g, ""),
150
- position: start + offset
151
- });
152
- continue;
153
- }
154
- tokens.push({
155
- type: "IDENTIFIER",
156
- value: upper,
157
- position: start + offset
158
- });
159
- continue;
160
- }
161
- throw new Error(`Unexpected character '${char}' at position ${i + offset}`);
162
- }
163
- tokens.push({ type: "EOF", value: "", position: input.length + offset });
164
- return tokens;
165
- }
166
-
167
- // src/spreadsheet/formula/parser.ts
168
- var WHOLE_COLUMN_END_ROW = 1048576;
169
- function parseCellReference(ref) {
170
- const match = ref.match(/^([A-Za-z]+)(\d+)$/);
171
- if (!match) {
172
- throw new Error(`Invalid cell reference: ${ref}`);
173
- }
174
- return {
175
- col: match[1].toUpperCase(),
176
- row: parseInt(match[2], 10)
177
- };
178
- }
179
- function parseRange(rangeStr) {
180
- const [start, end] = rangeStr.replace(/\$/g, "").split(":");
181
- const raw = rangeStr.toUpperCase();
182
- if (/^[A-Za-z]+$/.test(start) && /^[A-Za-z]+$/.test(end)) {
183
- return {
184
- type: "Range",
185
- raw,
186
- startCol: start.toUpperCase(),
187
- startRow: 1,
188
- endCol: end.toUpperCase(),
189
- endRow: WHOLE_COLUMN_END_ROW
190
- };
191
- }
192
- const startRef = parseCellReference(start);
193
- const endRef = parseCellReference(end);
194
- return {
195
- type: "Range",
196
- raw,
197
- startCol: startRef.col,
198
- startRow: startRef.row,
199
- endCol: endRef.col,
200
- endRow: endRef.row
201
- };
202
- }
203
- var FormulaParser = (_class = class {
204
- __init() {this.tokens = []}
205
- __init2() {this.current = 0}
206
- constructor(tokens) {;_class.prototype.__init.call(this);_class.prototype.__init2.call(this);
207
- this.tokens = tokens;
208
- }
209
- parse() {
210
- if (this.peek().type === "EOF") {
211
- return { type: "Literal", value: "" };
212
- }
213
- const expr = this.expression();
214
- if (this.peek().type !== "EOF") {
215
- throw new Error(`Unexpected token at position ${this.peek().position}: ${this.peek().value}`);
216
- }
217
- return expr;
218
- }
219
- expression() {
220
- return this.comparison();
221
- }
222
- comparison() {
223
- let expr = this.concatenation();
224
- while (this.matchOperator("=", "<>", "<", ">", "<=", ">=")) {
225
- const op = this.previous().value;
226
- const right = this.concatenation();
227
- expr = { type: "BinaryOp", op, left: expr, right };
228
- }
229
- return expr;
230
- }
231
- concatenation() {
232
- let expr = this.addition();
233
- while (this.matchOperator("&")) {
234
- const op = this.previous().value;
235
- const right = this.addition();
236
- expr = { type: "BinaryOp", op, left: expr, right };
237
- }
238
- return expr;
239
- }
240
- addition() {
241
- let expr = this.multiplication();
242
- while (this.matchOperator("+", "-")) {
243
- const op = this.previous().value;
244
- const right = this.multiplication();
245
- expr = { type: "BinaryOp", op, left: expr, right };
246
- }
247
- return expr;
248
- }
249
- multiplication() {
250
- let expr = this.exponentiation();
251
- while (this.matchOperator("*", "/")) {
252
- const op = this.previous().value;
253
- const right = this.exponentiation();
254
- expr = { type: "BinaryOp", op, left: expr, right };
255
- }
256
- return expr;
257
- }
258
- exponentiation() {
259
- let expr = this.unary();
260
- while (this.matchOperator("^")) {
261
- const op = this.previous().value;
262
- const right = this.unary();
263
- expr = { type: "BinaryOp", op, left: expr, right };
264
- }
265
- return expr;
266
- }
267
- unary() {
268
- if (this.matchOperator("-", "+")) {
269
- const op = this.previous().value;
270
- const argument = this.unary();
271
- return { type: "UnaryOp", op, argument };
272
- }
273
- return this.primary();
274
- }
275
- primary() {
276
- const token = this.peek();
277
- if (token.type === "NUMBER") {
278
- this.advance();
279
- return { type: "Literal", value: parseFloat(token.value) };
280
- }
281
- if (token.type === "STRING") {
282
- this.advance();
283
- return { type: "Literal", value: token.value };
284
- }
285
- if (token.type === "BOOLEAN") {
286
- this.advance();
287
- return { type: "Literal", value: token.value === "TRUE" };
288
- }
289
- if (token.type === "ERROR") {
290
- this.advance();
291
- return { type: "Literal", value: token.value };
292
- }
293
- if (token.type === "CELL_REF") {
294
- this.advance();
295
- const parsed = parseCellReference(token.value);
296
- return {
297
- type: "CellRef",
298
- ref: token.value,
299
- col: parsed.col,
300
- row: parsed.row
301
- };
302
- }
303
- if (token.type === "RANGE") {
304
- this.advance();
305
- return parseRange(token.value);
306
- }
307
- if (token.type === "PROPERTY_REF") {
308
- this.advance();
309
- return {
310
- type: "PropertyRef",
311
- property: token.value
312
- };
313
- }
314
- if (token.type === "IDENTIFIER") {
315
- const name = token.value;
316
- this.advance();
317
- if (this.check("LPAREN")) {
318
- this.consume("LPAREN", `Expected '(' after function ${name}`);
319
- const args = [];
320
- if (!this.check("RPAREN")) {
321
- do {
322
- args.push(this.expression());
323
- } while (this.match("COMMA"));
324
- }
325
- this.consume("RPAREN", `Expected ')' after function arguments`);
326
- return {
327
- type: "FunctionCall",
328
- name,
329
- args
330
- };
331
- }
332
- return { type: "Literal", value: "#NAME?" };
333
- }
334
- if (this.match("LPAREN")) {
335
- const expr = this.expression();
336
- this.consume("RPAREN", `Expected ')' after expression`);
337
- return expr;
338
- }
339
- throw new Error(`Unexpected token at position ${token.position}: ${token.value || token.type}`);
340
- }
341
- match(...types) {
342
- for (const type of types) {
343
- if (this.check(type)) {
344
- this.advance();
345
- return true;
346
- }
347
- }
348
- return false;
349
- }
350
- matchOperator(...ops) {
351
- if (this.check("OPERATOR") && ops.includes(this.peek().value)) {
352
- this.advance();
353
- return true;
354
- }
355
- return false;
356
- }
357
- check(type) {
358
- if (this.isAtEnd()) return false;
359
- return this.peek().type === type;
360
- }
361
- advance() {
362
- if (!this.isAtEnd()) this.current++;
363
- return this.previous();
364
- }
365
- isAtEnd() {
366
- return this.peek().type === "EOF";
367
- }
368
- peek() {
369
- return this.tokens[this.current];
370
- }
371
- previous() {
372
- return this.tokens[this.current - 1];
373
- }
374
- consume(type, message) {
375
- if (this.check(type)) return this.advance();
376
- throw new Error(message);
377
- }
378
- }, _class);
379
- function parseFormula(formula) {
380
- const tokens = tokenizeFormula(formula);
381
- const parser = new FormulaParser(tokens);
382
- return parser.parse();
383
- }
384
-
385
- // src/spreadsheet/formula/evaluator.ts
386
- var FORMULA_ERRORS = /* @__PURE__ */ new Set([
387
- "#DIV/0!",
388
- "#VALUE!",
389
- "#REF!",
390
- "#NAME?",
391
- "#N/A",
392
- "#NUM!",
393
- "#CYCLE!",
394
- "#ERROR!"
395
- ]);
396
- function isFormulaError(value) {
397
- return typeof value === "string" && FORMULA_ERRORS.has(value);
398
- }
399
- var isBlank = (value) => value === "" || value === null || value === void 0;
400
- function toNumber(value) {
401
- if (isFormulaError(value)) return value;
402
- if (isBlank(value)) return 0;
403
- if (typeof value === "boolean") return value ? 1 : 0;
404
- if (typeof value === "number") return value;
405
- const trimmed = String(value).trim();
406
- const num = trimmed === "" ? NaN : Number(trimmed);
407
- return isNaN(num) ? "#VALUE!" : num;
408
- }
409
- function toBoolean(value) {
410
- if (isFormulaError(value)) return value;
411
- if (isBlank(value)) return false;
412
- if (typeof value === "boolean") return value;
413
- if (typeof value === "number") return value !== 0;
414
- const upper = String(value).trim().toUpperCase();
415
- if (upper === "TRUE") return true;
416
- if (upper === "FALSE") return false;
417
- return "#VALUE!";
418
- }
419
- var toText = (value) => isBlank(value) ? "" : typeof value === "boolean" ? value ? "TRUE" : "FALSE" : String(value);
420
- function compareValues(left, right) {
421
- const rank = (v) => typeof v === "boolean" ? 2 : typeof v === "string" ? 1 : 0;
422
- const l = isBlank(left) ? typeof right === "string" ? "" : 0 : left;
423
- const r = isBlank(right) ? typeof l === "string" ? "" : 0 : right;
424
- if (rank(l) !== rank(r)) return rank(l) - rank(r);
425
- if (typeof l === "string") {
426
- const a = l.toLowerCase();
427
- const b = r.toLowerCase();
428
- return a < b ? -1 : a > b ? 1 : 0;
429
- }
430
- return Number(l) - Number(r);
431
- }
432
- function roundHalfAwayFromZero(value, decimals) {
433
- const factor = Math.pow(10, decimals);
434
- const scaled = Number((Math.abs(value) * factor).toPrecision(15));
435
- return Math.sign(value) * Math.round(scaled) / factor;
436
- }
437
- function colNameToIndex(col) {
438
- let index = 0;
439
- const upper = col.toUpperCase();
440
- for (let i = 0; i < upper.length; i++) {
441
- index = index * 26 + (upper.charCodeAt(i) - 65 + 1);
442
- }
443
- return index - 1;
444
- }
445
- function indexToColName(index) {
446
- let num = index + 1;
447
- let name = "";
448
- while (num > 0) {
449
- const mod = (num - 1) % 26;
450
- name = String.fromCharCode(65 + mod) + name;
451
- num = Math.floor((num - mod) / 26);
452
- }
453
- return name;
454
- }
455
- var FormulaEvaluator = class {
456
-
457
- constructor(context = {}) {
458
- this.context = context;
459
- }
460
- evaluate(astOrFormula) {
461
- const ast = typeof astOrFormula === "string" ? parseFormula(astOrFormula) : astOrFormula;
462
- return this.evaluateNode(ast);
463
- }
464
- evaluateNode(node) {
465
- switch (node.type) {
466
- case "Literal":
467
- return node.value;
468
- case "CellRef": {
469
- if (!this.context.resolveCell) {
470
- throw new Error(`Cannot resolve cell reference ${node.ref}: no cell resolver provided`);
471
- }
472
- return this.context.resolveCell(node.col, node.row);
473
- }
474
- case "Range": {
475
- if (!this.context.resolveRange) {
476
- throw new Error(`Cannot resolve range ${node.raw}: no range resolver provided`);
477
- }
478
- return this.context.resolveRange(node.startCol, node.startRow, node.endCol, node.endRow);
479
- }
480
- case "PropertyRef": {
481
- if (!this.context.resolveProperty) {
482
- throw new Error(`Cannot resolve property [${node.property}]: no property resolver provided`);
483
- }
484
- return this.context.resolveProperty(node.property);
485
- }
486
- case "UnaryOp": {
487
- const val = toNumber(this.evaluateNode(node.argument));
488
- if (isFormulaError(val)) return val;
489
- if (node.op === "-") return -val;
490
- if (node.op === "+") return val;
491
- throw new Error(`Unsupported unary operator: ${node.op}`);
492
- }
493
- case "BinaryOp": {
494
- const left = this.evaluateNode(node.left);
495
- if (isFormulaError(left)) return left;
496
- const right = this.evaluateNode(node.right);
497
- if (isFormulaError(right)) return right;
498
- if (["+", "-", "*", "/", "^"].includes(node.op)) {
499
- const a = toNumber(left);
500
- if (isFormulaError(a)) return a;
501
- const b = toNumber(right);
502
- if (isFormulaError(b)) return b;
503
- const x = a;
504
- const y = b;
505
- let result;
506
- switch (node.op) {
507
- case "+":
508
- result = x + y;
509
- break;
510
- case "-":
511
- result = x - y;
512
- break;
513
- case "*":
514
- result = x * y;
515
- break;
516
- case "/":
517
- if (y === 0) return "#DIV/0!";
518
- result = x / y;
519
- break;
520
- default:
521
- result = Math.pow(x, y);
522
- }
523
- return Number.isFinite(result) ? result : "#NUM!";
524
- }
525
- switch (node.op) {
526
- case "&":
527
- return toText(left) + toText(right);
528
- case "=":
529
- return compareValues(left, right) === 0;
530
- case "<>":
531
- return compareValues(left, right) !== 0;
532
- case "<":
533
- return compareValues(left, right) < 0;
534
- case "<=":
535
- return compareValues(left, right) <= 0;
536
- case ">":
537
- return compareValues(left, right) > 0;
538
- case ">=":
539
- return compareValues(left, right) >= 0;
540
- default:
541
- throw new Error(`Unsupported binary operator: ${node.op}`);
542
- }
543
- }
544
- case "FunctionCall": {
545
- return this.callFunction(node.name, node.args);
546
- }
547
- default:
548
- throw new Error(`Unknown AST node: ${node.type}`);
549
- }
550
- }
551
- callFunction(name, args) {
552
- const fnName = name.toUpperCase();
553
- const evaluateAndFlatten = () => {
554
- const items = [];
555
- for (const arg of args) {
556
- const val = this.evaluateNode(arg);
557
- if (Array.isArray(val)) {
558
- for (const item of val) items.push(item);
559
- } else {
560
- items.push(val);
561
- }
562
- }
563
- return items;
564
- };
565
- const numericArgs = () => {
566
- const nums = [];
567
- for (const item of evaluateAndFlatten()) {
568
- if (isFormulaError(item)) return item;
569
- if (isBlank(item) || typeof item === "boolean") continue;
570
- const num = typeof item === "number" ? item : Number(String(item).trim());
571
- if (String(item).trim() !== "" && !isNaN(num)) nums.push(num);
572
- }
573
- return nums;
574
- };
575
- const evaluateArg = (index) => this.evaluateNode(args[index]);
576
- switch (fnName) {
577
- case "SUM": {
578
- const nums = numericArgs();
579
- if (typeof nums === "string") return nums;
580
- let total = 0;
581
- for (const num of nums) total += num;
582
- return total;
583
- }
584
- case "AVERAGE": {
585
- const items = evaluateAndFlatten();
586
- const error = items.find(isFormulaError);
587
- if (error) return error;
588
- let total = 0;
589
- let count = 0;
590
- for (const item of items) {
591
- const num = Number(item);
592
- if (!isNaN(num) && item !== "" && item !== null && item !== void 0) {
593
- total += num;
594
- count++;
595
- }
596
- }
597
- return count === 0 ? 0 : total / count;
598
- }
599
- case "COUNT": {
600
- const items = evaluateAndFlatten();
601
- let count = 0;
602
- for (const item of items) {
603
- const num = Number(item);
604
- if (!isNaN(num) && item !== "" && item !== null && item !== void 0) {
605
- count++;
606
- }
607
- }
608
- return count;
609
- }
610
- case "COUNTA": {
611
- const items = evaluateAndFlatten();
612
- let count = 0;
613
- for (const item of items) {
614
- if (item !== "" && item !== null && item !== void 0) {
615
- count++;
616
- }
617
- }
618
- return count;
619
- }
620
- case "MIN":
621
- case "MAX": {
622
- const nums = numericArgs();
623
- if (typeof nums === "string") return nums;
624
- if (nums.length === 0) return 0;
625
- let result = nums[0];
626
- for (const num of nums) {
627
- result = fnName === "MIN" ? Math.min(result, num) : Math.max(result, num);
628
- }
629
- return result;
630
- }
631
- case "IF": {
632
- if (args.length < 2) throw new Error("IF requires at least 2 arguments");
633
- const condition = toBoolean(evaluateArg(0));
634
- if (isFormulaError(condition)) return condition;
635
- if (condition) {
636
- return this.evaluateNode(args[1]);
637
- } else {
638
- return args.length > 2 ? this.evaluateNode(args[2]) : false;
639
- }
640
- }
641
- case "CONCAT": {
642
- const items = evaluateAndFlatten();
643
- const error = items.find(isFormulaError);
644
- if (error) return error;
645
- return items.map(toText).join("");
646
- }
647
- case "UPPER": {
648
- if (args.length !== 1) throw new Error("UPPER requires 1 argument");
649
- const val = evaluateArg(0);
650
- if (isFormulaError(val)) return val;
651
- return toText(val).toUpperCase();
652
- }
653
- case "LOWER": {
654
- if (args.length !== 1) throw new Error("LOWER requires 1 argument");
655
- const val = evaluateArg(0);
656
- if (isFormulaError(val)) return val;
657
- return toText(val).toLowerCase();
658
- }
659
- case "TRIM": {
660
- if (args.length !== 1) throw new Error("TRIM requires 1 argument");
661
- const val = evaluateArg(0);
662
- if (isFormulaError(val)) return val;
663
- return toText(val).trim();
664
- }
665
- case "LEN": {
666
- if (args.length !== 1) throw new Error("LEN requires 1 argument");
667
- const val = evaluateArg(0);
668
- if (isFormulaError(val)) return val;
669
- return toText(val).length;
670
- }
671
- case "ROUND": {
672
- if (args.length < 1) throw new Error("ROUND requires at least 1 argument");
673
- const num = toNumber(evaluateArg(0));
674
- if (isFormulaError(num)) return num;
675
- const decimals = args.length > 1 ? toNumber(evaluateArg(1)) : 0;
676
- if (isFormulaError(decimals)) return decimals;
677
- return roundHalfAwayFromZero(num, Math.trunc(decimals));
678
- }
679
- case "ABS": {
680
- if (args.length !== 1) throw new Error("ABS requires 1 argument");
681
- const num = toNumber(evaluateArg(0));
682
- return isFormulaError(num) ? num : Math.abs(num);
683
- }
684
- case "TODAY": {
685
- const now = /* @__PURE__ */ new Date();
686
- const pad = (n) => String(n).padStart(2, "0");
687
- return `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}`;
688
- }
689
- case "DAYS": {
690
- if (args.length !== 2) throw new Error("DAYS requires 2 arguments (end_date, start_date)");
691
- const d1 = new Date(this.evaluateNode(args[0]));
692
- const d2 = new Date(this.evaluateNode(args[1]));
693
- const diffTime = d1.getTime() - d2.getTime();
694
- return Math.round(diffTime / (1e3 * 60 * 60 * 24));
695
- }
696
- default:
697
- return "#NAME?";
698
- }
699
- }
700
- };
701
-
702
- // src/spreadsheet/formula/dependency-graph.ts
703
- var columnDependencyKey = (col) => `${col.toUpperCase()}:`;
704
- function extractCellDependencies(node) {
705
- const deps = [];
706
- const visit = (curr) => {
707
- if (curr.type === "CellRef") {
708
- deps.push({ col: curr.col, row: curr.row });
709
- } else if (curr.type === "Range" && curr.endRow >= WHOLE_COLUMN_END_ROW) {
710
- const startC = colNameToIndex(curr.startCol);
711
- const endC = colNameToIndex(curr.endCol);
712
- for (let c = Math.min(startC, endC); c <= Math.max(startC, endC); c++) {
713
- deps.push({ col: indexToColName(c), row: 0 });
714
- }
715
- } else if (curr.type === "Range") {
716
- const startC = colNameToIndex(curr.startCol);
717
- const endC = colNameToIndex(curr.endCol);
718
- const minC = Math.min(startC, endC);
719
- const maxC = Math.max(startC, endC);
720
- const minR = Math.min(curr.startRow, curr.endRow);
721
- const maxR = Math.max(curr.startRow, curr.endRow);
722
- for (let c = minC; c <= maxC; c++) {
723
- for (let r = minR; r <= maxR; r++) {
724
- deps.push({ col: indexToColName(c), row: r });
725
- }
726
- }
727
- } else if (curr.type === "BinaryOp") {
728
- visit(curr.left);
729
- visit(curr.right);
730
- } else if (curr.type === "UnaryOp") {
731
- visit(curr.argument);
732
- } else if (curr.type === "FunctionCall") {
733
- curr.args.forEach(visit);
734
- }
735
- };
736
- visit(node);
737
- return deps;
738
- }
739
- var DependencyGraph = (_class2 = class {constructor() { _class2.prototype.__init3.call(this);_class2.prototype.__init4.call(this); }
740
- // Map of cellKey (e.g. "B2") -> Set of cellKeys that this cell depends ON
741
- __init3() {this.dependencies = /* @__PURE__ */ new Map()}
742
- // Map of cellKey (e.g. "A1") -> Set of cellKeys that depend ON this cell (dependents)
743
- __init4() {this.dependents = /* @__PURE__ */ new Map()}
744
- setCellFormula(cellKey, formulaStr) {
745
- const key = cellKey.toUpperCase();
746
- const oldDeps = this.dependencies.get(key) || /* @__PURE__ */ new Set();
747
- for (const dep of oldDeps) {
748
- _optionalChain([this, 'access', _2 => _2.dependents, 'access', _3 => _3.get, 'call', _4 => _4(dep), 'optionalAccess', _5 => _5.delete, 'call', _6 => _6(key)]);
749
- }
750
- this.dependencies.delete(key);
751
- if (!formulaStr || !formulaStr.startsWith("=")) {
752
- return;
753
- }
754
- try {
755
- const ast = parseFormula(formulaStr);
756
- const deps = extractCellDependencies(ast);
757
- const newDeps = /* @__PURE__ */ new Set();
758
- for (const d of deps) {
759
- const depKey = d.row === 0 ? columnDependencyKey(d.col) : `${d.col}${d.row}`.toUpperCase();
760
- newDeps.add(depKey);
761
- if (!this.dependents.has(depKey)) {
762
- this.dependents.set(depKey, /* @__PURE__ */ new Set());
763
- }
764
- this.dependents.get(depKey).add(key);
765
- }
766
- this.dependencies.set(key, newDeps);
767
- } catch (e) {
768
- }
769
- }
770
- /** Removes every registered formula and dependency. */
771
- clear() {
772
- this.dependencies.clear();
773
- this.dependents.clear();
774
- }
775
- getDependencies(cellKey) {
776
- return Array.from(this.dependencies.get(cellKey.toUpperCase()) || []);
777
- }
778
- getDependents(cellKey) {
779
- return Array.from(this.dependents.get(cellKey.toUpperCase()) || []);
780
- }
781
- /**
782
- * Detects if there is a cycle containing cellKey.
783
- */
784
- hasCycle(cellKey) {
785
- const key = cellKey.toUpperCase();
786
- const visited = /* @__PURE__ */ new Set();
787
- const recStack = /* @__PURE__ */ new Set();
788
- const dfs = (node) => {
789
- visited.add(node);
790
- recStack.add(node);
791
- const deps = this.dependencies.get(node) || /* @__PURE__ */ new Set();
792
- for (const neighbor of deps) {
793
- if (!visited.has(neighbor)) {
794
- if (dfs(neighbor)) return true;
795
- } else if (recStack.has(neighbor)) {
796
- return true;
797
- }
798
- }
799
- recStack.delete(node);
800
- return false;
801
- };
802
- return dfs(key);
803
- }
804
- /**
805
- * Returns cells affected by updating cellKey in topological order.
806
- */
807
- getEvaluationOrder(startCellKey) {
808
- const start = startCellKey.toUpperCase();
809
- const visited = /* @__PURE__ */ new Set();
810
- const recStack = /* @__PURE__ */ new Set();
811
- const order = [];
812
- let cycleDetected = false;
813
- const affected = /* @__PURE__ */ new Set();
814
- const collectAffected = (node) => {
815
- affected.add(node);
816
- const directDependents = this.dependents.get(node) || /* @__PURE__ */ new Set();
817
- for (const dep of directDependents) {
818
- if (!affected.has(dep)) {
819
- collectAffected(dep);
820
- }
821
- }
822
- };
823
- collectAffected(start);
824
- const visit = (node) => {
825
- if (recStack.has(node)) {
826
- cycleDetected = true;
827
- return;
828
- }
829
- if (visited.has(node)) return;
830
- recStack.add(node);
831
- visited.add(node);
832
- const deps = this.dependencies.get(node) || /* @__PURE__ */ new Set();
833
- for (const neighbor of deps) {
834
- if (affected.has(neighbor)) {
835
- visit(neighbor);
836
- }
837
- }
838
- recStack.delete(node);
839
- order.push(node);
840
- };
841
- for (const node of affected) {
842
- if (!visited.has(node)) {
843
- visit(node);
844
- }
845
- }
846
- return { order, hasCycle: cycleDetected };
847
- }
848
- /**
849
- * Plans a recalculation over `cellKeys` (and, with `includeDependents`, every
850
- * cell that transitively depends on them). Returns the keys in evaluation
851
- * order (dependencies first) and the set of keys that are part of a cycle,
852
- * which must be marked `#CYCLE!` instead of evaluated. Every member of a
853
- * cycle is reported, not just the cell that closed it.
854
- */
855
- getEvaluationPlan(cellKeys, options = {}) {
856
- const nodes = /* @__PURE__ */ new Set();
857
- const queue = [];
858
- for (const key of cellKeys) {
859
- const upper = key.toUpperCase();
860
- if (!nodes.has(upper)) {
861
- nodes.add(upper);
862
- queue.push(upper);
863
- }
864
- }
865
- if (options.includeDependents) {
866
- while (queue.length > 0) {
867
- const node = queue.pop();
868
- const direct = [
869
- ..._nullishCoalesce(this.dependents.get(node), () => ( [])),
870
- ..._nullishCoalesce(this.dependents.get(columnDependencyKey(node.replace(/\d+$/, ""))), () => ( []))
871
- ];
872
- for (const dep of direct) {
873
- if (!nodes.has(dep)) {
874
- nodes.add(dep);
875
- queue.push(dep);
876
- }
877
- }
878
- }
879
- }
880
- const neighbors = (node) => {
881
- const result = [];
882
- for (const dep of _nullishCoalesce(this.dependencies.get(node), () => ( []))) {
883
- if (dep.endsWith(":")) {
884
- const col = dep.slice(0, -1);
885
- for (const candidate of nodes) {
886
- if (candidate.replace(/\d+$/, "") === col) result.push(candidate);
887
- }
888
- } else if (nodes.has(dep)) {
889
- result.push(dep);
890
- }
891
- }
892
- return result;
893
- };
894
- const order = [];
895
- const cyclic = /* @__PURE__ */ new Set();
896
- const index = /* @__PURE__ */ new Map();
897
- const low = /* @__PURE__ */ new Map();
898
- const stack = [];
899
- const onStack = /* @__PURE__ */ new Set();
900
- let counter = 0;
901
- for (const root of nodes) {
902
- if (index.has(root)) continue;
903
- const work = [];
904
- const enter = (node) => {
905
- index.set(node, counter);
906
- low.set(node, counter);
907
- counter++;
908
- stack.push(node);
909
- onStack.add(node);
910
- work.push({ node, edges: neighbors(node), next: 0 });
911
- };
912
- enter(root);
913
- while (work.length > 0) {
914
- const frame = work[work.length - 1];
915
- if (frame.next < frame.edges.length) {
916
- const target = frame.edges[frame.next++];
917
- if (!index.has(target)) {
918
- enter(target);
919
- } else if (onStack.has(target)) {
920
- low.set(frame.node, Math.min(low.get(frame.node), index.get(target)));
921
- }
922
- continue;
923
- }
924
- work.pop();
925
- if (work.length > 0) {
926
- const parent = work[work.length - 1].node;
927
- low.set(parent, Math.min(low.get(parent), low.get(frame.node)));
928
- }
929
- if (low.get(frame.node) === index.get(frame.node)) {
930
- const component = [];
931
- let member;
932
- do {
933
- member = stack.pop();
934
- onStack.delete(member);
935
- component.push(member);
936
- } while (member !== frame.node);
937
- const isCycle = component.length > 1 || frame.edges.includes(frame.node);
938
- for (const key of component) {
939
- order.push(key);
940
- if (isCycle) cyclic.add(key);
941
- }
942
- }
943
- }
944
- }
945
- return { order, cyclic };
946
- }
947
- }, _class2);
948
-
949
- // src/spreadsheet/formula/references.ts
950
- var CELL_PART = /^(\$?)([A-Za-z]+)(\$?)(\d+)$/;
951
- var COLUMN_PART = /^(\$?)([A-Za-z]+)$/;
952
- var REF_CHAR = /[A-Za-z0-9_$.:]/;
953
- function parsePart(text) {
954
- const cell = CELL_PART.exec(text);
955
- if (cell) {
956
- return {
957
- colAbs: cell[1],
958
- col: colNameToIndex(cell[2]),
959
- rowAbs: cell[3],
960
- row: parseInt(cell[4], 10) - 1
961
- };
962
- }
963
- const column = COLUMN_PART.exec(text);
964
- if (column) {
965
- return { colAbs: column[1], col: colNameToIndex(column[2]), rowAbs: "", row: null };
966
- }
967
- return null;
968
- }
969
- function formatPart(part) {
970
- const col = `${part.colAbs}${indexToColName(part.col)}`;
971
- return part.row === null ? col : `${col}${part.rowAbs}${part.row + 1}`;
972
- }
973
- function shiftCoordinate(value, change) {
974
- if (change.type === "insert") {
975
- return value >= change.index ? value + 1 : value;
976
- }
977
- if (value === change.index) return null;
978
- return value > change.index ? value - 1 : value;
979
- }
980
- function shiftSpan(lo, hi, change) {
981
- if (change.type === "insert") {
982
- return [lo >= change.index ? lo + 1 : lo, hi >= change.index ? hi + 1 : hi];
983
- }
984
- if (lo === change.index && hi === change.index) return null;
985
- return [lo > change.index ? lo - 1 : lo, hi >= change.index ? hi - 1 : hi];
986
- }
987
- function rewriteReference(text, change) {
988
- const [startText, endText] = text.split(":");
989
- const start = parsePart(startText);
990
- if (!start) return text;
991
- const key = change.axis === "row" ? "row" : "col";
992
- if (endText === void 0) {
993
- if (start[key] === null) return text;
994
- const shifted = shiftCoordinate(start[key], change);
995
- if (shifted === null) return "#REF!";
996
- return formatPart({ ...start, [key]: shifted });
997
- }
998
- const end = parsePart(endText);
999
- if (!end) return text;
1000
- if (start[key] === null || end[key] === null) return text;
1001
- const startValue = start[key];
1002
- const endValue = end[key];
1003
- const span = shiftSpan(Math.min(startValue, endValue), Math.max(startValue, endValue), change);
1004
- if (span === null) return "#REF!";
1005
- const [lo, hi] = span;
1006
- const newStart = { ...start, [key]: startValue <= endValue ? lo : hi };
1007
- const newEnd = { ...end, [key]: startValue <= endValue ? hi : lo };
1008
- return `${formatPart(newStart)}:${formatPart(newEnd)}`;
1009
- }
1010
- function shiftFormulaReferences(formula, change) {
1011
- if (!formula.startsWith("=")) return formula;
1012
- let tokens;
1013
- try {
1014
- tokens = tokenizeFormula(formula);
1015
- } catch (e2) {
1016
- return formula;
1017
- }
1018
- let result = "";
1019
- let cursor = 0;
1020
- for (let i = 0; i < tokens.length; i++) {
1021
- const token = tokens[i];
1022
- if (token.type !== "CELL_REF" && token.type !== "RANGE") continue;
1023
- if (_optionalChain([tokens, 'access', _7 => _7[i + 1], 'optionalAccess', _8 => _8.type]) === "LPAREN") continue;
1024
- let end = token.position;
1025
- while (end < formula.length && REF_CHAR.test(formula[end])) end++;
1026
- const original = formula.slice(token.position, end);
1027
- result += formula.slice(cursor, token.position) + rewriteReference(original, change);
1028
- cursor = end;
1029
- }
1030
- return result + formula.slice(cursor);
1031
- }
1032
-
1033
- // src/spreadsheet/datasource/index.ts
1034
- var DataSourceBinder = (_class3 = class {constructor() { _class3.prototype.__init5.call(this); }
1035
- __init5() {this.dataSources = /* @__PURE__ */ new Map()}
1036
- register(dataSource) {
1037
- this.dataSources.set(dataSource.id, dataSource);
1038
- }
1039
- unregister(dataSourceId) {
1040
- this.dataSources.delete(dataSourceId);
1041
- }
1042
- getDataSource(id) {
1043
- return this.dataSources.get(id);
1044
- }
1045
- /**
1046
- * Generates or reconciles spreadsheet rows from a primary data source.
1047
- */
1048
- syncRows(currentRows, dataSourceId) {
1049
- const ds = this.dataSources.get(dataSourceId);
1050
- if (!ds) return currentRows;
1051
- const records = ds.getRecords();
1052
- const existingRecordRowMap = /* @__PURE__ */ new Map();
1053
- const freeformRows = [];
1054
- for (const row of currentRows) {
1055
- if (row.type === "record" && row.recordId) {
1056
- existingRecordRowMap.set(row.recordId, row);
1057
- } else {
1058
- freeformRows.push(row);
1059
- }
1060
- }
1061
- const nextRows = [];
1062
- let rowIndex = 0;
1063
- for (const record of records) {
1064
- const existing = existingRecordRowMap.get(record.id);
1065
- nextRows.push({
1066
- id: _optionalChain([existing, 'optionalAccess', _9 => _9.id]) || `row_${record.id}`,
1067
- index: rowIndex++,
1068
- height: _optionalChain([existing, 'optionalAccess', _10 => _10.height]) || 32,
1069
- recordId: record.id,
1070
- type: "record"
1071
- });
1072
- existingRecordRowMap.delete(record.id);
1073
- }
1074
- for (const freeform of freeformRows) {
1075
- nextRows.push({
1076
- ...freeform,
1077
- index: rowIndex++
1078
- });
1079
- }
1080
- return nextRows;
1081
- }
1082
- /**
1083
- * Resolves a record's bound field value.
1084
- */
1085
- resolveBoundValue(dataSourceId, recordId, field) {
1086
- const ds = this.dataSources.get(dataSourceId);
1087
- if (!ds) return void 0;
1088
- const records = ds.getRecords();
1089
- const record = records.find((r) => r.id === recordId);
1090
- return record ? record[field] : void 0;
1091
- }
1092
- /**
1093
- * Dispatches an update to the underlying data source.
1094
- */
1095
- async commitBoundValue(dataSourceId, recordId, field, value) {
1096
- const ds = this.dataSources.get(dataSourceId);
1097
- if (!ds) return;
1098
- await ds.updateRecord(recordId, field, value);
1099
- }
1100
- }, _class3);
1101
-
1102
- // src/spreadsheet/controller.ts
1103
- var SpreadsheetController = (_class4 = class {
1104
-
1105
- __init6() {this.activeCell = null}
1106
- __init7() {this.selectedRange = null}
1107
- __init8() {this.editingCell = null}
1108
- __init9() {this.draftValue = ""}
1109
- __init10() {this.binder = new DataSourceBinder()}
1110
- __init11() {this.depGraph = new DependencyGraph()}
1111
-
1112
-
1113
-
1114
-
1115
-
1116
- // History stack for undo/redo
1117
- __init12() {this.undoStack = []}
1118
- __init13() {this.redoStack = []}
1119
- __init14() {this.isApplyingHistory = false}
1120
- // Set while importing TSV: history and recalculation are done once at the end.
1121
- __init15() {this.batching = false}
1122
- __init16() {this.pendingCommits = []}
1123
- // Row being evaluated, so [property] references resolve per row.
1124
- __init17() {this.evaluatingRowIndex = null}
1125
- constructor(options = {}) {;_class4.prototype.__init6.call(this);_class4.prototype.__init7.call(this);_class4.prototype.__init8.call(this);_class4.prototype.__init9.call(this);_class4.prototype.__init10.call(this);_class4.prototype.__init11.call(this);_class4.prototype.__init12.call(this);_class4.prototype.__init13.call(this);_class4.prototype.__init14.call(this);_class4.prototype.__init15.call(this);_class4.prototype.__init16.call(this);_class4.prototype.__init17.call(this);
1126
- const defaultCols = [
1127
- { id: "col_a", key: "A", title: "A", width: 120, type: "freeform" },
1128
- { id: "col_b", key: "B", title: "B", width: 120, type: "freeform" },
1129
- { id: "col_c", key: "C", title: "C", width: 120, type: "freeform" },
1130
- { id: "col_d", key: "D", title: "D", width: 120, type: "freeform" }
1131
- ];
1132
- const defaultRows = options.primaryDataSourceId ? [] : Array.from({ length: 10 }, (_, i) => ({
1133
- id: `row_${i + 1}`,
1134
- index: i,
1135
- height: 32,
1136
- type: "freeform"
1137
- }));
1138
- this.document = {
1139
- id: _optionalChain([options, 'access', _11 => _11.document, 'optionalAccess', _12 => _12.id]) || `sheet_${Date.now()}`,
1140
- name: _optionalChain([options, 'access', _13 => _13.document, 'optionalAccess', _14 => _14.name]) || "Sheet 1",
1141
- columns: _optionalChain([options, 'access', _15 => _15.document, 'optionalAccess', _16 => _16.columns]) || defaultCols,
1142
- rows: _optionalChain([options, 'access', _17 => _17.document, 'optionalAccess', _18 => _18.rows]) || defaultRows,
1143
- cells: _optionalChain([options, 'access', _19 => _19.document, 'optionalAccess', _20 => _20.cells]) || {},
1144
- createdAt: _optionalChain([options, 'access', _21 => _21.document, 'optionalAccess', _22 => _22.createdAt]) || Date.now(),
1145
- updatedAt: _optionalChain([options, 'access', _23 => _23.document, 'optionalAccess', _24 => _24.updatedAt]) || Date.now()
1146
- };
1147
- this.primaryDataSourceId = options.primaryDataSourceId;
1148
- this.onDocumentChange = options.onDocumentChange;
1149
- this.onSelectionChange = options.onSelectionChange;
1150
- this.onCellCommit = options.onCellCommit;
1151
- if (options.dataSources) {
1152
- options.dataSources.forEach((ds) => this.binder.register(ds));
1153
- }
1154
- this.evaluator = new FormulaEvaluator({
1155
- resolveCell: (colStr, rowNum) => this.resolveCellByCoord(colStr, rowNum),
1156
- resolveRange: (sCol, sRow, eCol, eRow) => this.resolveRangeByCoords(sCol, sRow, eCol, eRow),
1157
- resolveProperty: (prop) => this.resolveCurrentRowProperty(prop)
1158
- });
1159
- this.syncWithDataSource();
1160
- this.recalculateAll();
1161
- }
1162
- loadDocument(document) {
1163
- this.document = JSON.parse(JSON.stringify(document));
1164
- this.activeCell = null;
1165
- this.selectedRange = null;
1166
- this.editingCell = null;
1167
- this.draftValue = "";
1168
- this.undoStack = [];
1169
- this.redoStack = [];
1170
- this.syncWithDataSource();
1171
- this.recalculateAll();
1172
- this.notifyChange();
1173
- }
1174
- registerDataSource(ds) {
1175
- this.binder.register(ds);
1176
- this.syncWithDataSource();
1177
- this.recalculateAll();
1178
- }
1179
- setPrimaryDataSource(dataSourceId) {
1180
- this.primaryDataSourceId = dataSourceId;
1181
- this.syncWithDataSource();
1182
- this.recalculateAll();
1183
- }
1184
- syncWithDataSource() {
1185
- if (!this.primaryDataSourceId) return;
1186
- this.document.rows = this.binder.syncRows(this.document.rows, this.primaryDataSourceId);
1187
- this.recomputeRowIndices();
1188
- }
1189
- recomputeRowIndices() {
1190
- this.document.rows.forEach((r, idx) => {
1191
- r.index = idx;
1192
- });
1193
- this.document.columns.forEach((c, idx) => {
1194
- c.key = indexToColName(idx);
1195
- });
1196
- }
1197
- getColumn(colIdOrKey) {
1198
- return this.document.columns.find(
1199
- (c) => c.id === colIdOrKey || c.key.toUpperCase() === colIdOrKey.toUpperCase()
1200
- );
1201
- }
1202
- getRow(rowIdOrIndex) {
1203
- if (typeof rowIdOrIndex === "number") {
1204
- return this.document.rows[rowIdOrIndex];
1205
- }
1206
- return this.document.rows.find((r) => r.id === rowIdOrIndex);
1207
- }
1208
- getCell(rowId, colId) {
1209
- const existing = _optionalChain([this, 'access', _25 => _25.document, 'access', _26 => _26.cells, 'access', _27 => _27[rowId], 'optionalAccess', _28 => _28[colId]]);
1210
- if (existing) return existing;
1211
- const col = this.document.columns.find((c) => c.id === colId);
1212
- const row = this.document.rows.find((r) => r.id === rowId);
1213
- return this.getDerivedCell(row, col);
1214
- }
1215
- /** Value of a cell with no stored data: bound record value, column formula, or blank. */
1216
- getDerivedCell(row, col) {
1217
- if (col && row && col.type === "bound" && col.binding && row.recordId) {
1218
- const boundVal = this.binder.resolveBoundValue(
1219
- col.binding.dataSource,
1220
- row.recordId,
1221
- col.binding.field
1222
- );
1223
- return {
1224
- raw: boundVal !== void 0 ? String(boundVal) : "",
1225
- value: _nullishCoalesce(boundVal, () => ( "")),
1226
- format: col.format
1227
- };
1228
- }
1229
- if (col && col.type === "formula" && col.formula) {
1230
- return {
1231
- raw: col.formula,
1232
- value: "",
1233
- format: col.format
1234
- };
1235
- }
1236
- return { raw: "", value: "", format: _optionalChain([col, 'optionalAccess', _29 => _29.format]) };
1237
- }
1238
- setCellValue(rowId, colId, raw) {
1239
- this.recordSnapshot();
1240
- if (!this.document.cells[rowId]) {
1241
- this.document.cells[rowId] = {};
1242
- }
1243
- const col = this.document.columns.find((c) => c.id === colId);
1244
- const row = this.document.rows.find((r) => r.id === rowId);
1245
- if (_optionalChain([col, 'optionalAccess', _30 => _30.type]) === "bound" && col.binding && _optionalChain([row, 'optionalAccess', _31 => _31.recordId])) {
1246
- this.binder.commitBoundValue(
1247
- col.binding.dataSource,
1248
- row.recordId,
1249
- col.binding.field,
1250
- raw
1251
- );
1252
- }
1253
- const cellKey = this.getCellKey(rowId, colId);
1254
- this.depGraph.setCellFormula(cellKey, raw.startsWith("=") ? raw : null);
1255
- this.document.cells[rowId][colId] = {
1256
- raw,
1257
- value: raw,
1258
- format: _optionalChain([col, 'optionalAccess', _32 => _32.format])
1259
- };
1260
- this.document.updatedAt = Date.now();
1261
- if (this.batching) {
1262
- this.pendingCommits.push([rowId, colId, raw]);
1263
- return;
1264
- }
1265
- this.recalculateCell(rowId, colId);
1266
- this.notifyChange();
1267
- const evaluatedVal = _optionalChain([this, 'access', _33 => _33.document, 'access', _34 => _34.cells, 'access', _35 => _35[rowId], 'access', _36 => _36[colId], 'optionalAccess', _37 => _37.value]);
1268
- _optionalChain([this, 'access', _38 => _38.onCellCommit, 'optionalCall', _39 => _39(rowId, colId, raw, evaluatedVal)]);
1269
- }
1270
- getCellKey(rowId, colId) {
1271
- const row = this.document.rows.find((r) => r.id === rowId);
1272
- const col = this.document.columns.find((c) => c.id === colId);
1273
- if (!row || !col) return `${colId}_${rowId}`;
1274
- return `${col.key}${row.index + 1}`.toUpperCase();
1275
- }
1276
- /**
1277
- * Recalculates a cell and everything that depends on it, in dependency
1278
- * order. Every cell in a reference cycle is marked `#CYCLE!`.
1279
- */
1280
- recalculateCell(rowId, colId) {
1281
- const cellKey = this.getCellKey(rowId, colId);
1282
- this.runEvaluationPlan(this.depGraph.getEvaluationPlan([cellKey], { includeDependents: true }));
1283
- }
1284
- /**
1285
- * Rebuilds the dependency graph from scratch and recalculates every formula
1286
- * in dependency order.
1287
- */
1288
- recalculateAll() {
1289
- this.depGraph.clear();
1290
- const formulaKeys = [];
1291
- for (const row of this.document.rows) {
1292
- for (const col of this.document.columns) {
1293
- const cell = _nullishCoalesce(_optionalChain([this, 'access', _40 => _40.document, 'access', _41 => _41.cells, 'access', _42 => _42[row.id], 'optionalAccess', _43 => _43[col.id]]), () => ( this.getDerivedCell(row, col)));
1294
- if (cell.raw.startsWith("=")) {
1295
- const cellKey = `${col.key}${row.index + 1}`.toUpperCase();
1296
- this.depGraph.setCellFormula(cellKey, cell.raw);
1297
- formulaKeys.push(cellKey);
1298
- }
1299
- }
1300
- }
1301
- this.runEvaluationPlan(this.depGraph.getEvaluationPlan(formulaKeys));
1302
- }
1303
- runEvaluationPlan(plan) {
1304
- for (const key of plan.order) {
1305
- if (plan.cyclic.has(key)) {
1306
- this.markCycle(key);
1307
- } else {
1308
- this.evalSingleCellByKey(key);
1309
- }
1310
- }
1311
- }
1312
- locateCellKey(cellKey) {
1313
- const match = cellKey.match(/^([A-Za-z]+)(\d+)$/);
1314
- if (!match) return null;
1315
- const col = this.document.columns.find((c) => c.key.toUpperCase() === match[1].toUpperCase());
1316
- const row = this.document.rows[parseInt(match[2], 10) - 1];
1317
- return col && row ? { row, col } : null;
1318
- }
1319
- markCycle(cellKey) {
1320
- const located = this.locateCellKey(cellKey);
1321
- if (!located) return;
1322
- const { row, col } = located;
1323
- const cell = this.getCell(row.id, col.id);
1324
- if (!cell.raw.startsWith("=")) return;
1325
- if (!this.document.cells[row.id]) this.document.cells[row.id] = {};
1326
- this.document.cells[row.id][col.id] = { ...cell, value: "#CYCLE!", error: "#CYCLE!" };
1327
- }
1328
- evalSingleCellByKey(cellKey) {
1329
- const match = cellKey.match(/^([A-Za-z]+)(\d+)$/);
1330
- if (!match) return;
1331
- const colName = match[1].toUpperCase();
1332
- const rowNum = parseInt(match[2], 10);
1333
- const col = this.document.columns.find((c) => c.key.toUpperCase() === colName);
1334
- const row = this.document.rows[rowNum - 1];
1335
- if (!col || !row) return;
1336
- const cell = this.getCell(row.id, col.id);
1337
- if (!cell.raw.startsWith("=")) {
1338
- if (cell.error === "#CYCLE!") {
1339
- cell.error = void 0;
1340
- }
1341
- return;
1342
- }
1343
- try {
1344
- this.evaluatingRowIndex = rowNum - 1;
1345
- const computed = this.evaluator.evaluate(cell.raw);
1346
- if (!this.document.cells[row.id]) {
1347
- this.document.cells[row.id] = {};
1348
- }
1349
- this.document.cells[row.id][col.id] = {
1350
- ...cell,
1351
- value: computed,
1352
- error: void 0
1353
- };
1354
- } catch (err) {
1355
- if (!this.document.cells[row.id]) {
1356
- this.document.cells[row.id] = {};
1357
- }
1358
- this.document.cells[row.id][col.id] = {
1359
- ...cell,
1360
- value: "#ERROR!",
1361
- error: _optionalChain([err, 'optionalAccess', _44 => _44.message]) || "Formula error"
1362
- };
1363
- } finally {
1364
- this.evaluatingRowIndex = null;
1365
- }
1366
- }
1367
- resolveCellByCoord(colStr, rowNum) {
1368
- const col = this.document.columns.find((c) => c.key.toUpperCase() === colStr.toUpperCase());
1369
- const row = this.document.rows[rowNum - 1];
1370
- if (!col || !row) return 0;
1371
- return _nullishCoalesce(this.getCell(row.id, col.id).value, () => ( ""));
1372
- }
1373
- resolveRangeByCoords(sCol, sRow, eCol, eRow) {
1374
- const startC = colNameToIndex(sCol);
1375
- const endC = colNameToIndex(eCol);
1376
- const minC = Math.min(startC, endC);
1377
- const maxC = Math.max(startC, endC);
1378
- const minR = Math.min(sRow, eRow);
1379
- const maxR = Math.min(Math.max(sRow, eRow), WHOLE_COLUMN_END_ROW, this.document.rows.length);
1380
- const results = [];
1381
- for (let c = minC; c <= maxC; c++) {
1382
- const colName = indexToColName(c);
1383
- const col = this.document.columns.find((colDef) => colDef.key.toUpperCase() === colName);
1384
- if (!col) continue;
1385
- for (let r = minR; r <= maxR; r++) {
1386
- const row = this.document.rows[r - 1];
1387
- if (!row) continue;
1388
- results.push(_nullishCoalesce(this.getCell(row.id, col.id).value, () => ( "")));
1389
- }
1390
- }
1391
- return results;
1392
- }
1393
- resolveCurrentRowProperty(prop) {
1394
- const rowIndex = _nullishCoalesce(this.evaluatingRowIndex, () => ( _optionalChain([this, 'access', _45 => _45.activeCell, 'optionalAccess', _46 => _46.row])));
1395
- if (rowIndex === void 0 || rowIndex === null) return 0;
1396
- const row = this.document.rows[rowIndex];
1397
- if (!row || !row.recordId || !this.primaryDataSourceId) return 0;
1398
- return _nullishCoalesce(this.binder.resolveBoundValue(this.primaryDataSourceId, row.recordId, prop), () => ( 0));
1399
- }
1400
- // --- Selection and Navigation ---
1401
- selectCell(row, col, extendSelection = false) {
1402
- const clampedRow = Math.max(0, Math.min(row, this.document.rows.length - 1));
1403
- const clampedCol = Math.max(0, Math.min(col, this.document.columns.length - 1));
1404
- const rowObj = this.document.rows[clampedRow];
1405
- const colObj = this.document.columns[clampedCol];
1406
- this.activeCell = {
1407
- row: clampedRow,
1408
- col: clampedCol,
1409
- rowId: _optionalChain([rowObj, 'optionalAccess', _47 => _47.id]),
1410
- colId: _optionalChain([colObj, 'optionalAccess', _48 => _48.id])
1411
- };
1412
- if (extendSelection && this.selectedRange) {
1413
- this.selectedRange = {
1414
- startRow: this.selectedRange.startRow,
1415
- startCol: this.selectedRange.startCol,
1416
- endRow: clampedRow,
1417
- endCol: clampedCol
1418
- };
1419
- } else {
1420
- this.selectedRange = {
1421
- startRow: clampedRow,
1422
- startCol: clampedCol,
1423
- endRow: clampedRow,
1424
- endCol: clampedCol
1425
- };
1426
- }
1427
- _optionalChain([this, 'access', _49 => _49.onSelectionChange, 'optionalCall', _50 => _50(this.activeCell, this.selectedRange)]);
1428
- }
1429
- selectRange(range) {
1430
- this.selectedRange = range;
1431
- _optionalChain([this, 'access', _51 => _51.onSelectionChange, 'optionalCall', _52 => _52(this.activeCell, this.selectedRange)]);
1432
- }
1433
- startEditing(row, col, initialValue) {
1434
- const targetRow = _nullishCoalesce(_nullishCoalesce(row, () => ( _optionalChain([this, 'access', _53 => _53.activeCell, 'optionalAccess', _54 => _54.row]))), () => ( 0));
1435
- const targetCol = _nullishCoalesce(_nullishCoalesce(col, () => ( _optionalChain([this, 'access', _55 => _55.activeCell, 'optionalAccess', _56 => _56.col]))), () => ( 0));
1436
- this.selectCell(targetRow, targetCol);
1437
- const rowObj = this.document.rows[targetRow];
1438
- const colObj = this.document.columns[targetCol];
1439
- if (!rowObj || !colObj) return;
1440
- this.editingCell = {
1441
- row: targetRow,
1442
- col: targetCol,
1443
- rowId: rowObj.id,
1444
- colId: colObj.id
1445
- };
1446
- const cell = this.getCell(rowObj.id, colObj.id);
1447
- this.draftValue = initialValue !== void 0 ? initialValue : cell.raw;
1448
- }
1449
- commitEditing(valueToCommit) {
1450
- if (!this.editingCell) return;
1451
- const val = valueToCommit !== void 0 ? valueToCommit : this.draftValue;
1452
- if (this.editingCell.rowId && this.editingCell.colId) {
1453
- this.setCellValue(this.editingCell.rowId, this.editingCell.colId, val);
1454
- }
1455
- this.editingCell = null;
1456
- this.draftValue = "";
1457
- }
1458
- cancelEditing() {
1459
- this.editingCell = null;
1460
- this.draftValue = "";
1461
- }
1462
- moveCursor(direction, extendSelection = false) {
1463
- if (!this.activeCell) {
1464
- this.selectCell(0, 0);
1465
- return;
1466
- }
1467
- let nextRow = this.activeCell.row;
1468
- let nextCol = this.activeCell.col;
1469
- switch (direction) {
1470
- case "up":
1471
- nextRow = Math.max(0, nextRow - 1);
1472
- break;
1473
- case "down":
1474
- nextRow = Math.min(this.document.rows.length - 1, nextRow + 1);
1475
- break;
1476
- case "left":
1477
- nextCol = Math.max(0, nextCol - 1);
1478
- break;
1479
- case "right":
1480
- nextCol = Math.min(this.document.columns.length - 1, nextCol + 1);
1481
- break;
1482
- }
1483
- this.selectCell(nextRow, nextCol, extendSelection);
1484
- }
1485
- // --- Grid Structure Mutations ---
1486
- insertColumn(index, config) {
1487
- this.recordSnapshot();
1488
- const newId = _optionalChain([config, 'optionalAccess', _57 => _57.id]) || this.generateId("col");
1489
- const newCol = {
1490
- id: newId,
1491
- key: indexToColName(index),
1492
- title: _optionalChain([config, 'optionalAccess', _58 => _58.title]) || indexToColName(index),
1493
- width: _optionalChain([config, 'optionalAccess', _59 => _59.width]) || 130,
1494
- type: _optionalChain([config, 'optionalAccess', _60 => _60.type]) || "freeform",
1495
- binding: _optionalChain([config, 'optionalAccess', _61 => _61.binding]),
1496
- formula: _optionalChain([config, 'optionalAccess', _62 => _62.formula]),
1497
- format: _optionalChain([config, 'optionalAccess', _63 => _63.format]) || "text",
1498
- readOnly: _optionalChain([config, 'optionalAccess', _64 => _64.readOnly])
1499
- };
1500
- this.shiftReferences({ axis: "col", index, type: "insert" });
1501
- this.document.columns.splice(index, 0, newCol);
1502
- this.recomputeRowIndices();
1503
- this.recalculateAll();
1504
- this.notifyChange();
1505
- }
1506
- deleteColumn(colId) {
1507
- this.recordSnapshot();
1508
- const colIndex = this.document.columns.findIndex((c) => c.id === colId);
1509
- if (colIndex === -1) return;
1510
- this.shiftReferences({ axis: "col", index: colIndex, type: "delete" });
1511
- this.document.columns = this.document.columns.filter((c) => c.id !== colId);
1512
- for (const rowId of Object.keys(this.document.cells)) {
1513
- delete this.document.cells[rowId][colId];
1514
- }
1515
- this.recomputeRowIndices();
1516
- this.recalculateAll();
1517
- this.notifyChange();
1518
- }
1519
- insertRow(index, config) {
1520
- this.recordSnapshot();
1521
- const newId = _optionalChain([config, 'optionalAccess', _65 => _65.id]) || this.generateId("row");
1522
- const newRow = {
1523
- id: newId,
1524
- index,
1525
- height: _optionalChain([config, 'optionalAccess', _66 => _66.height]) || 32,
1526
- recordId: _optionalChain([config, 'optionalAccess', _67 => _67.recordId]),
1527
- type: _optionalChain([config, 'optionalAccess', _68 => _68.type]) || "freeform"
1528
- };
1529
- this.shiftReferences({ axis: "row", index, type: "insert" });
1530
- this.document.rows.splice(index, 0, newRow);
1531
- this.recomputeRowIndices();
1532
- this.recalculateAll();
1533
- this.notifyChange();
1534
- }
1535
- deleteRow(rowId) {
1536
- this.recordSnapshot();
1537
- const rowIndex = this.document.rows.findIndex((r) => r.id === rowId);
1538
- if (rowIndex === -1) return;
1539
- this.shiftReferences({ axis: "row", index: rowIndex, type: "delete" });
1540
- this.document.rows = this.document.rows.filter((r) => r.id !== rowId);
1541
- delete this.document.cells[rowId];
1542
- this.recomputeRowIndices();
1543
- this.recalculateAll();
1544
- this.notifyChange();
1545
- }
1546
- generateId(prefix) {
1547
- return `${prefix}_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
1548
- }
1549
- /**
1550
- * Rewrites references in every cell formula (and, for column changes, every
1551
- * column formula) so they keep pointing at the same cells.
1552
- */
1553
- shiftReferences(change) {
1554
- for (const rowCells of Object.values(this.document.cells)) {
1555
- for (const cell of Object.values(rowCells)) {
1556
- if (_optionalChain([cell, 'access', _69 => _69.raw, 'optionalAccess', _70 => _70.startsWith, 'call', _71 => _71("=")])) {
1557
- cell.raw = shiftFormulaReferences(cell.raw, change);
1558
- }
1559
- }
1560
- }
1561
- if (change.axis === "col") {
1562
- for (const col of this.document.columns) {
1563
- if (_optionalChain([col, 'access', _72 => _72.formula, 'optionalAccess', _73 => _73.startsWith, 'call', _74 => _74("=")])) {
1564
- col.formula = shiftFormulaReferences(col.formula, change);
1565
- }
1566
- }
1567
- }
1568
- }
1569
- setColumnWidth(colId, width) {
1570
- const col = this.document.columns.find((c) => c.id === colId);
1571
- if (col) {
1572
- col.width = Math.max(30, width);
1573
- this.notifyChange();
1574
- }
1575
- }
1576
- autoFitColumnWidth(colId, customWidth) {
1577
- if (customWidth !== void 0) {
1578
- this.setColumnWidth(colId, customWidth);
1579
- return;
1580
- }
1581
- const col = this.document.columns.find((c) => c.id === colId);
1582
- if (!col) return;
1583
- let maxLen = (col.title || "").length + (col.key ? col.key.length + 3 : 0);
1584
- for (const row of this.document.rows) {
1585
- const cell = this.getCell(row.id, col.id);
1586
- const valStr = cell.value != null ? String(cell.value) : "";
1587
- if (valStr.length > maxLen) {
1588
- maxLen = valStr.length;
1589
- }
1590
- }
1591
- const estimatedWidth = Math.min(600, Math.max(50, Math.ceil(maxLen * 8.5 + 32)));
1592
- this.setColumnWidth(colId, estimatedWidth);
1593
- }
1594
- // --- Clipboard TSV/CSV ---
1595
- /**
1596
- * Exports cell values as TSV: the whole sheet, or only `range` (e.g. the
1597
- * current selection) when given.
1598
- */
1599
- exportToTsv(range) {
1600
- const rows = range ? this.document.rows.slice(
1601
- Math.min(range.startRow, range.endRow),
1602
- Math.max(range.startRow, range.endRow) + 1
1603
- ) : this.document.rows;
1604
- const columns = range ? this.document.columns.slice(
1605
- Math.min(range.startCol, range.endCol),
1606
- Math.max(range.startCol, range.endCol) + 1
1607
- ) : this.document.columns;
1608
- return rows.map(
1609
- (row) => columns.map((col) => {
1610
- const cell = this.getCell(row.id, col.id);
1611
- return String(_nullishCoalesce(cell.value, () => ( ""))).replace(/\t/g, " ");
1612
- }).join(" ")
1613
- ).join("\n");
1614
- }
1615
- /**
1616
- * Pastes tab-separated values starting at (startRow, startCol), adding rows
1617
- * and columns as needed. The whole paste is a single undo step.
1618
- */
1619
- importFromTsv(tsvData, startRow = 0, startCol = 0) {
1620
- const normalized = tsvData.replace(/\r\n?/g, "\n").replace(/\n$/, "");
1621
- if (normalized === "") return;
1622
- this.recordSnapshot();
1623
- this.batching = true;
1624
- this.pendingCommits = [];
1625
- try {
1626
- normalized.split("\n").forEach((line, rIdx) => {
1627
- const targetR = startRow + rIdx;
1628
- while (targetR >= this.document.rows.length) {
1629
- const index = this.document.rows.length;
1630
- this.document.rows.push({ id: this.generateId("row"), index, height: 32, type: "freeform" });
1631
- }
1632
- const row = this.document.rows[targetR];
1633
- line.split(" ").forEach((val, cIdx) => {
1634
- const targetC = startCol + cIdx;
1635
- while (targetC >= this.document.columns.length) {
1636
- const key = indexToColName(this.document.columns.length);
1637
- this.document.columns.push({
1638
- id: this.generateId("col"),
1639
- key,
1640
- title: key,
1641
- width: 130,
1642
- type: "freeform",
1643
- format: "text"
1644
- });
1645
- }
1646
- this.setCellValue(row.id, this.document.columns[targetC].id, val);
1647
- });
1648
- });
1649
- } finally {
1650
- this.batching = false;
1651
- }
1652
- this.recalculateAll();
1653
- this.notifyChange();
1654
- const commits = this.pendingCommits;
1655
- this.pendingCommits = [];
1656
- for (const [rowId, colId, raw] of commits) {
1657
- _optionalChain([this, 'access', _75 => _75.onCellCommit, 'optionalCall', _76 => _76(rowId, colId, raw, _optionalChain([this, 'access', _77 => _77.document, 'access', _78 => _78.cells, 'access', _79 => _79[rowId], 'optionalAccess', _80 => _80[colId], 'optionalAccess', _81 => _81.value]))]);
1658
- }
1659
- }
1660
- // --- Undo/Redo Snapshots ---
1661
- recordSnapshot() {
1662
- if (this.isApplyingHistory || this.batching) return;
1663
- this.undoStack.push(JSON.stringify(this.document));
1664
- if (this.undoStack.length > 50) this.undoStack.shift();
1665
- this.redoStack = [];
1666
- }
1667
- undo() {
1668
- if (this.undoStack.length === 0) return;
1669
- this.isApplyingHistory = true;
1670
- try {
1671
- this.redoStack.push(JSON.stringify(this.document));
1672
- this.document = JSON.parse(this.undoStack.pop());
1673
- this.recalculateAll();
1674
- this.notifyChange();
1675
- } finally {
1676
- this.isApplyingHistory = false;
1677
- }
1678
- }
1679
- redo() {
1680
- if (this.redoStack.length === 0) return;
1681
- this.isApplyingHistory = true;
1682
- try {
1683
- this.undoStack.push(JSON.stringify(this.document));
1684
- this.document = JSON.parse(this.redoStack.pop());
1685
- this.recalculateAll();
1686
- this.notifyChange();
1687
- } finally {
1688
- this.isApplyingHistory = false;
1689
- }
1690
- }
1691
- notifyChange() {
1692
- _optionalChain([this, 'access', _82 => _82.onDocumentChange, 'optionalCall', _83 => _83(this.document)]);
1693
- }
1694
- }, _class4);
1695
-
1696
-
1697
-
1698
-
1699
-
1700
-
1701
-
1702
-
1703
-
1704
-
1705
-
1706
-
1707
-
1708
-
1709
-
1710
-
1711
-
1712
-
1713
-
1714
- exports.tokenizeFormula = tokenizeFormula; exports.WHOLE_COLUMN_END_ROW = WHOLE_COLUMN_END_ROW; exports.parseCellReference = parseCellReference; exports.parseRange = parseRange; exports.FormulaParser = FormulaParser; exports.parseFormula = parseFormula; exports.FORMULA_ERRORS = FORMULA_ERRORS; exports.isFormulaError = isFormulaError; exports.colNameToIndex = colNameToIndex; exports.indexToColName = indexToColName; exports.FormulaEvaluator = FormulaEvaluator; exports.columnDependencyKey = columnDependencyKey; exports.extractCellDependencies = extractCellDependencies; exports.DependencyGraph = DependencyGraph; exports.shiftFormulaReferences = shiftFormulaReferences; exports.DataSourceBinder = DataSourceBinder; exports.SpreadsheetController = SpreadsheetController;
1715
- //# sourceMappingURL=chunk-YQCI4CCN.cjs.map