@pixerate/editor 0.21.0 → 0.23.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 (114) hide show
  1. package/README.md +100 -13
  2. package/THIRD_PARTY_NOTICES.md +88 -0
  3. package/dist/agent/index.cjs +86 -111
  4. package/dist/agent/index.cjs.map +1 -1
  5. package/dist/agent/index.d.cts +69 -211
  6. package/dist/agent/index.d.ts +69 -211
  7. package/dist/agent/index.js +77 -102
  8. package/dist/agent/index.js.map +1 -1
  9. package/dist/arrangeShortcuts-B8O3f8-P.d.cts +184 -0
  10. package/dist/arrangeShortcuts-sLlD2rSX.d.ts +184 -0
  11. package/dist/canvas/index.cjs +2112 -60
  12. package/dist/canvas/index.cjs.map +1 -1
  13. package/dist/canvas/index.d.cts +712 -181
  14. package/dist/canvas/index.d.ts +712 -181
  15. package/dist/canvas/index.js +2105 -53
  16. package/dist/canvas/index.js.map +1 -1
  17. package/dist/chunk-26BVFKHU.cjs +453 -0
  18. package/dist/chunk-26BVFKHU.cjs.map +1 -0
  19. package/dist/chunk-2H7ZHPEJ.js +762 -0
  20. package/dist/chunk-2H7ZHPEJ.js.map +1 -0
  21. package/dist/chunk-7DWMJCAT.js +453 -0
  22. package/dist/chunk-7DWMJCAT.js.map +1 -0
  23. package/dist/{chunk-TVRC4KVT.cjs → chunk-AA4ZEVCC.cjs} +845 -90
  24. package/dist/chunk-AA4ZEVCC.cjs.map +1 -0
  25. package/dist/chunk-ARRTP33I.js +101 -0
  26. package/dist/chunk-ARRTP33I.js.map +1 -0
  27. package/dist/{chunk-LA7PEGU3.cjs → chunk-CL37JGFW.cjs} +4 -4
  28. package/dist/{chunk-LA7PEGU3.cjs.map → chunk-CL37JGFW.cjs.map} +1 -1
  29. package/dist/chunk-CPOKFNBG.cjs +101 -0
  30. package/dist/chunk-CPOKFNBG.cjs.map +1 -0
  31. package/dist/chunk-G2I4QJOT.cjs +762 -0
  32. package/dist/chunk-G2I4QJOT.cjs.map +1 -0
  33. package/dist/{chunk-4QPLEUL2.cjs → chunk-GVSMRPHB.cjs} +1046 -54
  34. package/dist/chunk-GVSMRPHB.cjs.map +1 -0
  35. package/dist/{chunk-KYRZDWM4.js → chunk-JJDLPEWL.js} +2 -2
  36. package/dist/{chunk-GVW4P7BG.js → chunk-K3R5NG2D.js} +448 -54
  37. package/dist/chunk-K3R5NG2D.js.map +1 -0
  38. package/dist/{chunk-3TYMNULT.js → chunk-MJZBNWG7.js} +807 -52
  39. package/dist/chunk-MJZBNWG7.js.map +1 -0
  40. package/dist/{chunk-A7DKIA72.js → chunk-QBJ22YZR.js} +1059 -93
  41. package/dist/chunk-QBJ22YZR.js.map +1 -0
  42. package/dist/{chunk-CYFJCKC4.js → chunk-QGHGJ56O.js} +997 -5
  43. package/dist/chunk-QGHGJ56O.js.map +1 -0
  44. package/dist/{chunk-JYRIOFEN.cjs → chunk-RIKBJLS2.cjs} +1064 -98
  45. package/dist/chunk-RIKBJLS2.cjs.map +1 -0
  46. package/dist/{chunk-U6NDQFOK.cjs → chunk-XDMXXC4Z.cjs} +569 -175
  47. package/dist/chunk-XDMXXC4Z.cjs.map +1 -0
  48. package/dist/commands/index.cjs +860 -0
  49. package/dist/commands/index.cjs.map +1 -0
  50. package/dist/commands/index.d.cts +592 -0
  51. package/dist/commands/index.d.ts +592 -0
  52. package/dist/commands/index.js +860 -0
  53. package/dist/commands/index.js.map +1 -0
  54. package/dist/{controller-OUdxPY-X.d.ts → controller-pePCJLT1.d.cts} +216 -11
  55. package/dist/{controller-OUdxPY-X.d.cts → controller-pePCJLT1.d.ts} +216 -11
  56. package/dist/extensions/index.cjs +14 -4
  57. package/dist/extensions/index.cjs.map +1 -1
  58. package/dist/extensions/index.d.cts +3 -3
  59. package/dist/extensions/index.d.ts +3 -3
  60. package/dist/extensions/index.js +13 -3
  61. package/dist/history/index.cjs +12 -2
  62. package/dist/history/index.cjs.map +1 -1
  63. package/dist/history/index.d.cts +211 -7
  64. package/dist/history/index.d.ts +211 -7
  65. package/dist/history/index.js +13 -3
  66. package/dist/image-editor/index.cjs +418 -13
  67. package/dist/image-editor/index.cjs.map +1 -1
  68. package/dist/image-editor/index.d.cts +154 -3
  69. package/dist/image-editor/index.d.ts +154 -3
  70. package/dist/image-editor/index.js +417 -12
  71. package/dist/image-editor/index.js.map +1 -1
  72. package/dist/{index-k3mFbPx_.d.cts → index-CCr_z9kF.d.cts} +3 -3
  73. package/dist/{index-Ng1pG7JE.d.ts → index-Ck6ajwXh.d.ts} +3 -3
  74. package/dist/index.cjs +275 -83
  75. package/dist/index.cjs.map +1 -1
  76. package/dist/index.d.cts +296 -47
  77. package/dist/index.d.ts +296 -47
  78. package/dist/index.js +266 -74
  79. package/dist/index.js.map +1 -1
  80. package/dist/registry-D5-R90p0.d.cts +209 -0
  81. package/dist/registry-D5-R90p0.d.ts +209 -0
  82. package/dist/{registry-iAHbqkYt.d.cts → registry-GJI4gToU.d.cts} +15 -4
  83. package/dist/{registry-iAHbqkYt.d.ts → registry-GJI4gToU.d.ts} +15 -4
  84. package/dist/serializers/index.cjs +3 -3
  85. package/dist/serializers/index.d.cts +1 -1
  86. package/dist/serializers/index.d.ts +1 -1
  87. package/dist/serializers/index.js +2 -2
  88. package/dist/spreadsheet/index.cjs +23 -3
  89. package/dist/spreadsheet/index.cjs.map +1 -1
  90. package/dist/spreadsheet/index.d.cts +97 -10
  91. package/dist/spreadsheet/index.d.ts +97 -10
  92. package/dist/spreadsheet/index.js +22 -2
  93. package/dist/{track-changes-G8JcWB8b.d.cts → track-changes-BSF58RK0.d.cts} +92 -9
  94. package/dist/{track-changes-G8JcWB8b.d.ts → track-changes-BSF58RK0.d.ts} +92 -9
  95. package/dist/{types-DMe0vFB1.d.cts → types-DX4Mh4SL.d.cts} +1 -1
  96. package/dist/{types-DMe0vFB1.d.ts → types-DX4Mh4SL.d.ts} +1 -1
  97. package/dist/types-GT5a5YAX.d.cts +86 -0
  98. package/dist/types-GT5a5YAX.d.ts +86 -0
  99. package/package.json +8 -2
  100. package/dist/chunk-2TWGLC5K.cjs +0 -262
  101. package/dist/chunk-2TWGLC5K.cjs.map +0 -1
  102. package/dist/chunk-3TYMNULT.js.map +0 -1
  103. package/dist/chunk-4QPLEUL2.cjs.map +0 -1
  104. package/dist/chunk-A7DKIA72.js.map +0 -1
  105. package/dist/chunk-CYFJCKC4.js.map +0 -1
  106. package/dist/chunk-GVW4P7BG.js.map +0 -1
  107. package/dist/chunk-JYRIOFEN.cjs.map +0 -1
  108. package/dist/chunk-KAADNAPF.js +0 -262
  109. package/dist/chunk-KAADNAPF.js.map +0 -1
  110. package/dist/chunk-TVRC4KVT.cjs.map +0 -1
  111. package/dist/chunk-U6NDQFOK.cjs.map +0 -1
  112. package/dist/types-BZgcDsC5.d.cts +0 -42
  113. package/dist/types-BZgcDsC5.d.ts +0 -42
  114. /package/dist/{chunk-KYRZDWM4.js.map → chunk-JJDLPEWL.js.map} +0 -0
@@ -10,7 +10,15 @@
10
10
 
11
11
 
12
12
 
13
- var _chunkJYRIOFENcjs = require('./chunk-JYRIOFEN.cjs');
13
+
14
+
15
+
16
+
17
+
18
+
19
+
20
+
21
+ var _chunkRIKBJLS2cjs = require('./chunk-RIKBJLS2.cjs');
14
22
 
15
23
  // src/spreadsheet/formula/dependency-graph.ts
16
24
  var columnDependencyKey = (col) => `${col.toUpperCase()}:`;
@@ -19,22 +27,24 @@ function extractCellDependencies(node) {
19
27
  const visit = (curr) => {
20
28
  if (curr.type === "CellRef") {
21
29
  deps.push({ col: curr.col, row: curr.row });
22
- } else if (curr.type === "Range" && curr.endRow >= _chunkJYRIOFENcjs.WHOLE_COLUMN_END_ROW) {
23
- const startC = _chunkJYRIOFENcjs.colNameToIndex.call(void 0, curr.startCol);
24
- const endC = _chunkJYRIOFENcjs.colNameToIndex.call(void 0, curr.endCol);
30
+ } else if (curr.type === "SpillRef") {
31
+ deps.push({ col: curr.col, row: curr.row });
32
+ } else if (curr.type === "Range" && curr.endRow >= _chunkRIKBJLS2cjs.WHOLE_COLUMN_END_ROW) {
33
+ const startC = _chunkRIKBJLS2cjs.colNameToIndex.call(void 0, curr.startCol);
34
+ const endC = _chunkRIKBJLS2cjs.colNameToIndex.call(void 0, curr.endCol);
25
35
  for (let c = Math.min(startC, endC); c <= Math.max(startC, endC); c++) {
26
- deps.push({ col: _chunkJYRIOFENcjs.indexToColName.call(void 0, c), row: 0 });
36
+ deps.push({ col: _chunkRIKBJLS2cjs.indexToColName.call(void 0, c), row: 0 });
27
37
  }
28
38
  } else if (curr.type === "Range") {
29
- const startC = _chunkJYRIOFENcjs.colNameToIndex.call(void 0, curr.startCol);
30
- const endC = _chunkJYRIOFENcjs.colNameToIndex.call(void 0, curr.endCol);
39
+ const startC = _chunkRIKBJLS2cjs.colNameToIndex.call(void 0, curr.startCol);
40
+ const endC = _chunkRIKBJLS2cjs.colNameToIndex.call(void 0, curr.endCol);
31
41
  const minC = Math.min(startC, endC);
32
42
  const maxC = Math.max(startC, endC);
33
43
  const minR = Math.min(curr.startRow, curr.endRow);
34
44
  const maxR = Math.max(curr.startRow, curr.endRow);
35
45
  for (let c = minC; c <= maxC; c++) {
36
46
  for (let r = minR; r <= maxR; r++) {
37
- deps.push({ col: _chunkJYRIOFENcjs.indexToColName.call(void 0, c), row: r });
47
+ deps.push({ col: _chunkRIKBJLS2cjs.indexToColName.call(void 0, c), row: r });
38
48
  }
39
49
  }
40
50
  } else if (curr.type === "BinaryOp") {
@@ -49,11 +59,19 @@ function extractCellDependencies(node) {
49
59
  visit(node);
50
60
  return deps;
51
61
  }
52
- var DependencyGraph = (_class = class {constructor() { _class.prototype.__init.call(this);_class.prototype.__init2.call(this); }
62
+ var DependencyGraph = (_class = class {constructor() { _class.prototype.__init.call(this);_class.prototype.__init2.call(this);_class.prototype.__init3.call(this);_class.prototype.__init4.call(this);_class.prototype.__init5.call(this); }
53
63
  // Map of cellKey (e.g. "B2") -> Set of cellKeys that this cell depends ON
54
64
  __init() {this.dependencies = /* @__PURE__ */ new Map()}
55
65
  // Map of cellKey (e.g. "A1") -> Set of cellKeys that depend ON this cell (dependents)
56
66
  __init2() {this.dependents = /* @__PURE__ */ new Map()}
67
+ // Dynamic-array edges, set by the controller after evaluating an anchor:
68
+ // spilled cells depend on their anchor, and a blocked (#SPILL!) anchor
69
+ // depends on the cells blocking it. Kept apart from formula dependencies,
70
+ // so re-entering a formula doesn't drop them.
71
+ __init3() {this.spillDependencies = /* @__PURE__ */ new Map()}
72
+ __init4() {this.spillDependents = /* @__PURE__ */ new Map()}
73
+ // anchor -> the edges it registered (so they can be replaced).
74
+ __init5() {this.spillEdges = /* @__PURE__ */ new Map()}
57
75
  setCellFormula(cellKey, formulaStr) {
58
76
  const key = cellKey.toUpperCase();
59
77
  const oldDeps = this.dependencies.get(key) || /* @__PURE__ */ new Set();
@@ -65,7 +83,7 @@ var DependencyGraph = (_class = class {constructor() { _class.prototype.__init.c
65
83
  return;
66
84
  }
67
85
  try {
68
- const ast = _chunkJYRIOFENcjs.parseFormula.call(void 0, formulaStr);
86
+ const ast = _chunkRIKBJLS2cjs.parseFormula.call(void 0, formulaStr);
69
87
  const deps = extractCellDependencies(ast);
70
88
  const newDeps = /* @__PURE__ */ new Set();
71
89
  for (const d of deps) {
@@ -84,12 +102,49 @@ var DependencyGraph = (_class = class {constructor() { _class.prototype.__init.c
84
102
  clear() {
85
103
  this.dependencies.clear();
86
104
  this.dependents.clear();
105
+ this.spillDependencies.clear();
106
+ this.spillDependents.clear();
107
+ this.spillEdges.clear();
87
108
  }
109
+ /**
110
+ * Records the dynamic-array edges of the anchor `anchorKey`, replacing its
111
+ * previous ones: every key in `spilledKeys` (cells holding its spilled
112
+ * values) depends on the anchor, and the anchor depends on every key in
113
+ * `blockingKeys` (cells that stop it spilling). Pass empty lists to remove
114
+ * the anchor's edges.
115
+ */
116
+ setSpillEdges(anchorKey, spilledKeys, blockingKeys = []) {
117
+ const anchor = anchorKey.toUpperCase();
118
+ for (const [from, to] of _nullishCoalesce(this.spillEdges.get(anchor), () => ( []))) {
119
+ _optionalChain([this, 'access', _7 => _7.spillDependencies, 'access', _8 => _8.get, 'call', _9 => _9(from), 'optionalAccess', _10 => _10.delete, 'call', _11 => _11(to)]);
120
+ _optionalChain([this, 'access', _12 => _12.spillDependents, 'access', _13 => _13.get, 'call', _14 => _14(to), 'optionalAccess', _15 => _15.delete, 'call', _16 => _16(from)]);
121
+ }
122
+ const edges = [];
123
+ for (const key of spilledKeys) edges.push([key.toUpperCase(), anchor]);
124
+ for (const key of blockingKeys) edges.push([anchor, key.toUpperCase()]);
125
+ for (const [from, to] of edges) {
126
+ if (!this.spillDependencies.has(from)) this.spillDependencies.set(from, /* @__PURE__ */ new Set());
127
+ this.spillDependencies.get(from).add(to);
128
+ if (!this.spillDependents.has(to)) this.spillDependents.set(to, /* @__PURE__ */ new Set());
129
+ this.spillDependents.get(to).add(from);
130
+ }
131
+ if (edges.length > 0) this.spillEdges.set(anchor, edges);
132
+ else this.spillEdges.delete(anchor);
133
+ }
134
+ /** The spilled cells registered for `anchorKey` by `setSpillEdges`. */
135
+ getSpilledKeys(anchorKey) {
136
+ const anchor = anchorKey.toUpperCase();
137
+ return (_nullishCoalesce(this.spillEdges.get(anchor), () => ( []))).filter(([, to]) => to === anchor).map(([from]) => from);
138
+ }
139
+ /** Formula dependencies plus dynamic-array (spill) dependencies of a cell. */
88
140
  getDependencies(cellKey) {
89
- return Array.from(this.dependencies.get(cellKey.toUpperCase()) || []);
141
+ const key = cellKey.toUpperCase();
142
+ return unionOf(this.dependencies.get(key), this.spillDependencies.get(key));
90
143
  }
144
+ /** Cells depending on `cellKey`, through formulas or spills. */
91
145
  getDependents(cellKey) {
92
- return Array.from(this.dependents.get(cellKey.toUpperCase()) || []);
146
+ const key = cellKey.toUpperCase();
147
+ return unionOf(this.dependents.get(key), this.spillDependents.get(key));
93
148
  }
94
149
  /**
95
150
  * Detects if there is a cycle containing cellKey.
@@ -101,7 +156,7 @@ var DependencyGraph = (_class = class {constructor() { _class.prototype.__init.c
101
156
  const dfs = (node) => {
102
157
  visited.add(node);
103
158
  recStack.add(node);
104
- const deps = this.dependencies.get(node) || /* @__PURE__ */ new Set();
159
+ const deps = this.getDependencies(node);
105
160
  for (const neighbor of deps) {
106
161
  if (!visited.has(neighbor)) {
107
162
  if (dfs(neighbor)) return true;
@@ -180,6 +235,7 @@ var DependencyGraph = (_class = class {constructor() { _class.prototype.__init.c
180
235
  const node = queue.pop();
181
236
  const direct = [
182
237
  ..._nullishCoalesce(this.dependents.get(node), () => ( [])),
238
+ ..._nullishCoalesce(this.spillDependents.get(node), () => ( [])),
183
239
  ..._nullishCoalesce(this.dependents.get(columnDependencyKey(node.replace(/\d+$/, ""))), () => ( []))
184
240
  ];
185
241
  for (const dep of direct) {
@@ -192,7 +248,7 @@ var DependencyGraph = (_class = class {constructor() { _class.prototype.__init.c
192
248
  }
193
249
  const neighbors = (node) => {
194
250
  const result = [];
195
- for (const dep of _nullishCoalesce(this.dependencies.get(node), () => ( []))) {
251
+ for (const dep of this.getDependencies(node)) {
196
252
  if (dep.endsWith(":")) {
197
253
  const col = dep.slice(0, -1);
198
254
  for (const candidate of nodes) {
@@ -258,6 +314,11 @@ var DependencyGraph = (_class = class {constructor() { _class.prototype.__init.c
258
314
  return { order, cyclic };
259
315
  }
260
316
  }, _class);
317
+ function unionOf(a, b) {
318
+ if (!b || b.size === 0) return Array.from(_nullishCoalesce(a, () => ( [])));
319
+ if (!a || a.size === 0) return Array.from(b);
320
+ return Array.from(/* @__PURE__ */ new Set([...a, ...b]));
321
+ }
261
322
 
262
323
  // src/spreadsheet/formula/references.ts
263
324
  var CELL_PART = /^(\$?)([A-Za-z]+)(\$?)(\d+)$/;
@@ -268,19 +329,19 @@ function parsePart(text) {
268
329
  if (cell) {
269
330
  return {
270
331
  colAbs: cell[1],
271
- col: _chunkJYRIOFENcjs.colNameToIndex.call(void 0, cell[2]),
332
+ col: _chunkRIKBJLS2cjs.colNameToIndex.call(void 0, cell[2]),
272
333
  rowAbs: cell[3],
273
334
  row: parseInt(cell[4], 10) - 1
274
335
  };
275
336
  }
276
337
  const column = COLUMN_PART.exec(text);
277
338
  if (column) {
278
- return { colAbs: column[1], col: _chunkJYRIOFENcjs.colNameToIndex.call(void 0, column[2]), rowAbs: "", row: null };
339
+ return { colAbs: column[1], col: _chunkRIKBJLS2cjs.colNameToIndex.call(void 0, column[2]), rowAbs: "", row: null };
279
340
  }
280
341
  return null;
281
342
  }
282
343
  function formatPart(part) {
283
- const col = `${part.colAbs}${_chunkJYRIOFENcjs.indexToColName.call(void 0, part.col)}`;
344
+ const col = `${part.colAbs}${_chunkRIKBJLS2cjs.indexToColName.call(void 0, part.col)}`;
284
345
  return part.row === null ? col : `${col}${part.rowAbs}${part.row + 1}`;
285
346
  }
286
347
  function shiftCoordinate(value, change) {
@@ -327,7 +388,7 @@ function mapFormulaReferences(formula, rewrite) {
327
388
  if (!formula.startsWith("=")) return formula;
328
389
  let tokens;
329
390
  try {
330
- tokens = _chunkJYRIOFENcjs.tokenizeFormula.call(void 0, formula);
391
+ tokens = _chunkRIKBJLS2cjs.tokenizeFormula.call(void 0, formula);
331
392
  } catch (e2) {
332
393
  return formula;
333
394
  }
@@ -335,11 +396,17 @@ function mapFormulaReferences(formula, rewrite) {
335
396
  let cursor = 0;
336
397
  for (let i = 0; i < tokens.length; i++) {
337
398
  const token = tokens[i];
338
- if (token.type !== "CELL_REF" && token.type !== "RANGE") continue;
339
- if (_optionalChain([tokens, 'access', _7 => _7[i + 1], 'optionalAccess', _8 => _8.type]) === "LPAREN") continue;
399
+ if (token.type !== "CELL_REF" && token.type !== "RANGE" && token.type !== "SPILL_REF") continue;
400
+ if (_optionalChain([tokens, 'access', _17 => _17[i + 1], 'optionalAccess', _18 => _18.type]) === "LPAREN") continue;
340
401
  let end = token.position;
341
402
  while (end < formula.length && REF_CHAR.test(formula[end])) end++;
342
403
  const original = formula.slice(token.position, end);
404
+ if (token.type === "SPILL_REF") {
405
+ const rewritten = rewrite(original);
406
+ result += formula.slice(cursor, token.position) + (rewritten === "#REF!" ? rewritten : `${rewritten}#`);
407
+ cursor = end + 1;
408
+ continue;
409
+ }
343
410
  result += formula.slice(cursor, token.position) + rewrite(original);
344
411
  cursor = end;
345
412
  }
@@ -459,7 +526,7 @@ function innermostCall(stack) {
459
526
  }
460
527
  var toSuggestion = (def) => ({
461
528
  name: def.name,
462
- signature: _chunkJYRIOFENcjs.getFormulaSignature.call(void 0, def),
529
+ signature: _chunkRIKBJLS2cjs.getFormulaSignature.call(void 0, def),
463
530
  description: def.description,
464
531
  category: def.category
465
532
  });
@@ -468,20 +535,20 @@ function getFormulaHints(input, caret = input.length, options = {}) {
468
535
  let suggestions = [];
469
536
  if (context.prefix) {
470
537
  const query = context.prefix.text.toUpperCase();
471
- suggestions = _chunkJYRIOFENcjs.searchFormulaFunctions.call(void 0, query, { limit: void 0 }).filter((def) => def.name.startsWith(query)).slice(0, _nullishCoalesce(options.limit, () => ( 8))).map(toSuggestion);
538
+ suggestions = _chunkRIKBJLS2cjs.searchFormulaFunctions.call(void 0, query, { limit: void 0 }).filter((def) => def.name.startsWith(query)).slice(0, _nullishCoalesce(options.limit, () => ( 8))).map(toSuggestion);
472
539
  const followedByParen = input.slice(context.prefix.end).trimStart().startsWith("(");
473
540
  if (followedByParen || suggestions.length === 1 && suggestions[0].name === query) suggestions = [];
474
541
  }
475
542
  let activeCall = null;
476
543
  if (context.call) {
477
- const def = _chunkJYRIOFENcjs.getFormulaFunction.call(void 0, context.call.name);
544
+ const def = _chunkRIKBJLS2cjs.getFormulaFunction.call(void 0, context.call.name);
478
545
  if (def) {
479
- const specIndex = _chunkJYRIOFENcjs.getFormulaArgumentSpecIndex.call(void 0, def, context.call.argIndex);
546
+ const specIndex = _chunkRIKBJLS2cjs.getFormulaArgumentSpecIndex.call(void 0, def, context.call.argIndex);
480
547
  activeCall = {
481
548
  name: def.name,
482
- signature: _chunkJYRIOFENcjs.getFormulaSignature.call(void 0, def),
549
+ signature: _chunkRIKBJLS2cjs.getFormulaSignature.call(void 0, def),
483
550
  description: def.description,
484
- parts: _chunkJYRIOFENcjs.getFormulaSignatureParts.call(void 0, def, context.call.argIndex),
551
+ parts: _chunkRIKBJLS2cjs.getFormulaSignatureParts.call(void 0, def, context.call.argIndex),
485
552
  argIndex: context.call.argIndex,
486
553
  argument: specIndex >= 0 ? def.args[specIndex] : null
487
554
  };
@@ -491,8 +558,8 @@ function getFormulaHints(input, caret = input.length, options = {}) {
491
558
  }
492
559
  function applyFormulaSuggestion(input, caret, name) {
493
560
  const context = getFormulaCaretContext(input, caret);
494
- const start = _nullishCoalesce(_optionalChain([context, 'access', _9 => _9.prefix, 'optionalAccess', _10 => _10.start]), () => ( caret));
495
- const end = _nullishCoalesce(_optionalChain([context, 'access', _11 => _11.prefix, 'optionalAccess', _12 => _12.end]), () => ( caret));
561
+ const start = _nullishCoalesce(_optionalChain([context, 'access', _19 => _19.prefix, 'optionalAccess', _20 => _20.start]), () => ( caret));
562
+ const end = _nullishCoalesce(_optionalChain([context, 'access', _21 => _21.prefix, 'optionalAccess', _22 => _22.end]), () => ( caret));
496
563
  const hasParen = input[end] === "(";
497
564
  const insert = hasParen ? name.toUpperCase() : `${name.toUpperCase()}(`;
498
565
  const value = input.slice(0, start) + insert + input.slice(end);
@@ -500,8 +567,8 @@ function applyFormulaSuggestion(input, caret, name) {
500
567
  }
501
568
 
502
569
  // src/spreadsheet/datasource/index.ts
503
- var DataSourceBinder = (_class2 = class {constructor() { _class2.prototype.__init3.call(this); }
504
- __init3() {this.dataSources = /* @__PURE__ */ new Map()}
570
+ var DataSourceBinder = (_class2 = class {constructor() { _class2.prototype.__init6.call(this); }
571
+ __init6() {this.dataSources = /* @__PURE__ */ new Map()}
505
572
  register(dataSource) {
506
573
  this.dataSources.set(dataSource.id, dataSource);
507
574
  }
@@ -532,10 +599,10 @@ var DataSourceBinder = (_class2 = class {constructor() { _class2.prototype.__ini
532
599
  for (const record of records) {
533
600
  const existing = existingRecordRowMap.get(record.id);
534
601
  nextRows.push({
535
- ..._optionalChain([existing, 'optionalAccess', _13 => _13.hidden]) ? { hidden: true } : {},
536
- id: _optionalChain([existing, 'optionalAccess', _14 => _14.id]) || `row_${record.id}`,
602
+ ..._optionalChain([existing, 'optionalAccess', _23 => _23.hidden]) ? { hidden: true } : {},
603
+ id: _optionalChain([existing, 'optionalAccess', _24 => _24.id]) || `row_${record.id}`,
537
604
  index: rowIndex++,
538
- height: _optionalChain([existing, 'optionalAccess', _15 => _15.height]) || 32,
605
+ height: _optionalChain([existing, 'optionalAccess', _25 => _25.height]) || 32,
539
606
  recordId: record.id,
540
607
  type: "record"
541
608
  });
@@ -617,28 +684,41 @@ function compareCellValues(a, b, direction = "asc") {
617
684
  const aBlank = isBlankValue(a);
618
685
  const bBlank = isBlankValue(b);
619
686
  if (aBlank || bBlank) return aBlank === bBlank ? 0 : aBlank ? 1 : -1;
620
- const aNum = toNumber(a);
621
- const bNum = toNumber(b);
622
687
  let result;
623
- if (aNum !== null && bNum !== null) result = aNum - bNum;
624
- else if (aNum !== null) result = -1;
625
- else if (bNum !== null) result = 1;
626
- else result = compareText(String(a), String(b));
688
+ if (isPlainText(a) && isPlainText(b) && !(_chunkRIKBJLS2cjs.parseIsoDate.call(void 0, a) && _chunkRIKBJLS2cjs.parseIsoDate.call(void 0, b))) {
689
+ result = compareText(a, b);
690
+ } else {
691
+ result = _chunkRIKBJLS2cjs.sortCompareValues.call(void 0, a, b);
692
+ }
627
693
  if (result === 0) return 0;
628
694
  return direction === "desc" ? -Math.sign(result) : Math.sign(result);
629
695
  }
696
+ var isPlainText = (value) => typeof value === "string" && !_chunkRIKBJLS2cjs.isFormulaError.call(void 0, value);
697
+ function filterValue(value) {
698
+ if (isBlankValue(value) || _chunkRIKBJLS2cjs.isFormulaError.call(void 0, value)) return null;
699
+ if (typeof value === "number") return Number.isFinite(value) ? { value, kind: "number" } : null;
700
+ if (typeof value === "boolean") return { value, kind: "boolean" };
701
+ const num = _chunkRIKBJLS2cjs.numericValue.call(void 0, value);
702
+ if (num !== null) return { value: num, kind: "number" };
703
+ const text = String(value);
704
+ return { value: text, kind: _chunkRIKBJLS2cjs.parseIsoDate.call(void 0, text) ? "number" : "text" };
705
+ }
706
+ function filterOperand(operand) {
707
+ if (typeof operand !== "string") return filterValue(operand);
708
+ if (operand.trim() === "") return null;
709
+ const parsed = _chunkRIKBJLS2cjs.parseCellInput.call(void 0, operand.trim());
710
+ if (parsed.type === "number" || parsed.type === "date" || parsed.type === "boolean") return filterValue(parsed.value);
711
+ return { value: operand, kind: "text" };
712
+ }
630
713
  function compareForFilter(value, operand) {
631
- if (isBlankValue(value) || isBlankValue(operand)) return null;
632
- const a = toNumber(value);
633
- const b = toNumber(operand);
634
- if (a !== null && b !== null) return a - b;
635
- if (a !== null || b !== null) return null;
636
- return compareText(String(value), String(operand));
714
+ const a = filterValue(value);
715
+ const b = filterOperand(operand);
716
+ if (!a || !b || a.kind !== b.kind) return null;
717
+ return _chunkRIKBJLS2cjs.compareValues.call(void 0, a.value, b.value);
637
718
  }
638
719
  function looselyEquals(value, operand) {
639
- const a = toNumber(value);
640
- const b = toNumber(operand);
641
- if (a !== null && b !== null) return a === b;
720
+ const c = compareForFilter(value, operand);
721
+ if (c !== null) return c === 0;
642
722
  return String(_nullishCoalesce(value, () => ( ""))).trim().toLowerCase() === String(_nullishCoalesce(operand, () => ( ""))).trim().toLowerCase();
643
723
  }
644
724
  function matchesFilterRule(value, rule) {
@@ -713,7 +793,8 @@ function classifyFillValue(raw) {
713
793
  if (raw.trim() === "") return { kind: "blank" };
714
794
  const num = toNumber(raw);
715
795
  if (num !== null) return { kind: "number", value: num };
716
- const date = ISO_DATE_PATTERN.exec(raw.trim());
796
+ const typed = _chunkRIKBJLS2cjs.parseCellInput.call(void 0, raw);
797
+ const date = ISO_DATE_PATTERN.exec(typed.type === "date" ? String(typed.value) : raw.trim());
717
798
  if (date) {
718
799
  const [year, month, day] = [Number(date[1]), Number(date[2]), Number(date[3])];
719
800
  const time = Date.UTC(year, month - 1, day);
@@ -991,8 +1072,8 @@ function parseHtmlTable(html) {
991
1072
  while (cellMatch = cellPattern.exec(rowMatch[1])) {
992
1073
  while (taken.has(col)) row[col++] = "";
993
1074
  const attrs = _nullishCoalesce(cellMatch[2], () => ( ""));
994
- const colspan = Math.max(1, parseInt(_nullishCoalesce(_optionalChain([/colspan\s*=\s*["']?(\d+)/i, 'access', _16 => _16.exec, 'call', _17 => _17(attrs), 'optionalAccess', _18 => _18[1]]), () => ( "1")), 10));
995
- const rowspan = Math.max(1, parseInt(_nullishCoalesce(_optionalChain([/rowspan\s*=\s*["']?(\d+)/i, 'access', _19 => _19.exec, 'call', _20 => _20(attrs), 'optionalAccess', _21 => _21[1]]), () => ( "1")), 10));
1075
+ const colspan = Math.max(1, parseInt(_nullishCoalesce(_optionalChain([/colspan\s*=\s*["']?(\d+)/i, 'access', _26 => _26.exec, 'call', _27 => _27(attrs), 'optionalAccess', _28 => _28[1]]), () => ( "1")), 10));
1076
+ const rowspan = Math.max(1, parseInt(_nullishCoalesce(_optionalChain([/rowspan\s*=\s*["']?(\d+)/i, 'access', _29 => _29.exec, 'call', _30 => _30(attrs), 'optionalAccess', _31 => _31[1]]), () => ( "1")), 10));
996
1077
  row[col] = cellHtmlToText(cellMatch[3]);
997
1078
  for (let c = col; c < col + colspan; c++) {
998
1079
  if (c > col) row[c] = "";
@@ -1010,11 +1091,16 @@ function parseHtmlTable(html) {
1010
1091
  return rows.length > 0 ? rows : null;
1011
1092
  }
1012
1093
  function createSpreadsheetClipboardData(cells, origin) {
1013
- const values = cells.map((row) => row.map((cell) => cell.value));
1014
- const payload = { type: "pixerate-spreadsheet", version: 1, origin, cells };
1094
+ const texts = cells.map((row) => row.map((cell) => _nullishCoalesce(cell.text, () => ( displayText(cell.value)))));
1095
+ const payload = {
1096
+ type: "pixerate-spreadsheet",
1097
+ version: 1,
1098
+ origin,
1099
+ cells: cells.map((row) => row.map(({ raw, value }) => ({ raw, value })))
1100
+ };
1015
1101
  return {
1016
- "text/plain": serializeTsv(values.map((row) => row.map(displayText))),
1017
- "text/html": serializeHtmlTable(values),
1102
+ "text/plain": serializeTsv(texts),
1103
+ "text/html": serializeHtmlTable(texts),
1018
1104
  [SPREADSHEET_CLIPBOARD_MIME]: JSON.stringify(payload)
1019
1105
  };
1020
1106
  }
@@ -1031,7 +1117,7 @@ function readFormat(source, format) {
1031
1117
  function parsePayload(json) {
1032
1118
  try {
1033
1119
  const payload = JSON.parse(json);
1034
- if (_optionalChain([payload, 'optionalAccess', _22 => _22.type]) !== "pixerate-spreadsheet" || !Array.isArray(payload.cells) || !payload.cells.every((row) => Array.isArray(row)) || typeof _optionalChain([payload, 'access', _23 => _23.origin, 'optionalAccess', _24 => _24.row]) !== "number" || typeof _optionalChain([payload, 'access', _25 => _25.origin, 'optionalAccess', _26 => _26.col]) !== "number") {
1120
+ if (_optionalChain([payload, 'optionalAccess', _32 => _32.type]) !== "pixerate-spreadsheet" || !Array.isArray(payload.cells) || !payload.cells.every((row) => Array.isArray(row)) || typeof _optionalChain([payload, 'access', _33 => _33.origin, 'optionalAccess', _34 => _34.row]) !== "number" || typeof _optionalChain([payload, 'access', _35 => _35.origin, 'optionalAccess', _36 => _36.col]) !== "number") {
1035
1121
  return null;
1036
1122
  }
1037
1123
  return payload;
@@ -1045,7 +1131,7 @@ function readSpreadsheetClipboard(source) {
1045
1131
  return {
1046
1132
  format: "internal",
1047
1133
  origin: payload.origin,
1048
- rows: payload.cells.map((row) => row.map((cell) => typeof _optionalChain([cell, 'optionalAccess', _27 => _27.raw]) === "string" ? cell.raw : displayText(_optionalChain([cell, 'optionalAccess', _28 => _28.value]))))
1134
+ rows: payload.cells.map((row) => row.map((cell) => typeof _optionalChain([cell, 'optionalAccess', _37 => _37.raw]) === "string" ? cell.raw : displayText(_optionalChain([cell, 'optionalAccess', _38 => _38.value]))))
1049
1135
  };
1050
1136
  }
1051
1137
  const html = readFormat(source, "text/html");
@@ -1074,8 +1160,8 @@ var DEFAULT_COLUMN_WIDTH = 130;
1074
1160
  var clampCount = (value, max) => Math.max(0, Math.min(Math.floor(_nullishCoalesce(value, () => ( 0))), max));
1075
1161
  function getTableSections(doc) {
1076
1162
  const total = doc.rows.length;
1077
- const headerRows = clampCount(_optionalChain([doc, 'access', _29 => _29.table, 'optionalAccess', _30 => _30.headerRowCount]), total);
1078
- const footerRows = clampCount(_optionalChain([doc, 'access', _31 => _31.table, 'optionalAccess', _32 => _32.footerRowCount]), total - headerRows);
1163
+ const headerRows = clampCount(_optionalChain([doc, 'access', _39 => _39.table, 'optionalAccess', _40 => _40.headerRowCount]), total);
1164
+ const footerRows = clampCount(_optionalChain([doc, 'access', _41 => _41.table, 'optionalAccess', _42 => _42.footerRowCount]), total - headerRows);
1079
1165
  return { headerRows, footerRows };
1080
1166
  }
1081
1167
  function getRowSection(doc, rowIndex) {
@@ -1085,8 +1171,8 @@ function getRowSection(doc, rowIndex) {
1085
1171
  return "body";
1086
1172
  }
1087
1173
  function rowPassesFilters(doc, rowIndex, getValue) {
1088
- const filter = _optionalChain([doc, 'access', _33 => _33.table, 'optionalAccess', _34 => _34.filter]);
1089
- if (!_optionalChain([filter, 'optionalAccess', _35 => _35.enabled]) || filter.rules.length === 0) return true;
1174
+ const filter = _optionalChain([doc, 'access', _43 => _43.table, 'optionalAccess', _44 => _44.filter]);
1175
+ if (!_optionalChain([filter, 'optionalAccess', _45 => _45.enabled]) || filter.rules.length === 0) return true;
1090
1176
  if (getRowSection(doc, rowIndex) !== "body") return true;
1091
1177
  return filter.rules.every((rule) => {
1092
1178
  const colIndex = doc.columns.findIndex((c) => c.id === rule.colId);
@@ -1095,7 +1181,7 @@ function rowPassesFilters(doc, rowIndex, getValue) {
1095
1181
  });
1096
1182
  }
1097
1183
  function computeRowGroups(doc, getValue) {
1098
- const grouping = _optionalChain([doc, 'access', _36 => _36.table, 'optionalAccess', _37 => _37.grouping]);
1184
+ const grouping = _optionalChain([doc, 'access', _46 => _46.table, 'optionalAccess', _47 => _47.grouping]);
1099
1185
  if (!grouping) return [];
1100
1186
  const groupCol = doc.columns.findIndex((c) => c.id === grouping.colId);
1101
1187
  if (groupCol === -1) return [];
@@ -1125,9 +1211,9 @@ function computeRowGroups(doc, getValue) {
1125
1211
  }
1126
1212
  function buildSpreadsheetView(doc, getValue) {
1127
1213
  const { headerRows, footerRows } = getTableSections(doc);
1128
- const frozenRows = clampCount(_optionalChain([doc, 'access', _38 => _38.table, 'optionalAccess', _39 => _39.frozenRowCount]), doc.rows.length);
1129
- const frozenCols = clampCount(_optionalChain([doc, 'access', _40 => _40.table, 'optionalAccess', _41 => _41.frozenColumnCount]), doc.columns.length);
1130
- const headerCols = clampCount(_optionalChain([doc, 'access', _42 => _42.table, 'optionalAccess', _43 => _43.headerColumnCount]), doc.columns.length);
1214
+ const frozenRows = clampCount(_optionalChain([doc, 'access', _48 => _48.table, 'optionalAccess', _49 => _49.frozenRowCount]), doc.rows.length);
1215
+ const frozenCols = clampCount(_optionalChain([doc, 'access', _50 => _50.table, 'optionalAccess', _51 => _51.frozenColumnCount]), doc.columns.length);
1216
+ const headerCols = clampCount(_optionalChain([doc, 'access', _52 => _52.table, 'optionalAccess', _53 => _53.headerColumnCount]), doc.columns.length);
1131
1217
  const columns = [];
1132
1218
  let left = 0;
1133
1219
  let hiddenColumnCount = 0;
@@ -1157,7 +1243,7 @@ function buildSpreadsheetView(doc, getValue) {
1157
1243
  if (doc.rows[r].hidden) hiddenRowCount++;
1158
1244
  else if (!rowPassesFilters(doc, r, getValue)) filteredOutCount++;
1159
1245
  }
1160
- const grouping = _optionalChain([doc, 'access', _44 => _44.table, 'optionalAccess', _45 => _45.grouping]);
1246
+ const grouping = _optionalChain([doc, 'access', _54 => _54.table, 'optionalAccess', _55 => _55.grouping]);
1161
1247
  if (grouping && doc.columns.some((c) => c.id === grouping.colId)) {
1162
1248
  for (const group of groups) {
1163
1249
  rows.push({ kind: "group", group });
@@ -1191,7 +1277,7 @@ function buildSpreadsheetView(doc, getValue) {
1191
1277
  while (run < visible.length && positions.get(visible[run]) === positions.get(visible[0]) + run) run++;
1192
1278
  return { first: visible[0], run };
1193
1279
  };
1194
- for (const raw of _nullishCoalesce(_optionalChain([doc, 'access', _46 => _46.table, 'optionalAccess', _47 => _47.merges]), () => ( []))) {
1280
+ for (const raw of _nullishCoalesce(_optionalChain([doc, 'access', _56 => _56.table, 'optionalAccess', _57 => _57.merges]), () => ( []))) {
1195
1281
  const merge = normalizeRange(raw);
1196
1282
  const rowIdx = [];
1197
1283
  const colIdx = [];
@@ -1228,29 +1314,45 @@ function buildSpreadsheetView(doc, getValue) {
1228
1314
 
1229
1315
  // src/spreadsheet/controller.ts
1230
1316
  var nextIdSequence = 0;
1317
+ var DEFAULT_MAX_HISTORY_BYTES = 64 * 1024 * 1024;
1318
+ var MAX_SPILL_PASSES = 25;
1319
+ var spillCellId = (rowId, colId) => `${rowId}\0${colId}`;
1231
1320
  var SpreadsheetController = (_class3 = class {
1232
1321
 
1233
- __init4() {this.activeCell = null}
1234
- __init5() {this.selectedRange = null}
1235
- __init6() {this.editingCell = null}
1236
- __init7() {this.draftValue = ""}
1237
- __init8() {this.binder = new DataSourceBinder()}
1238
- __init9() {this.depGraph = new DependencyGraph()}
1322
+ __init7() {this.activeCell = null}
1323
+ __init8() {this.selectedRange = null}
1324
+ __init9() {this.editingCell = null}
1325
+ __init10() {this.draftValue = ""}
1326
+ __init11() {this.binder = new DataSourceBinder()}
1327
+ __init12() {this.depGraph = new DependencyGraph()}
1239
1328
 
1240
1329
 
1241
1330
 
1242
1331
 
1243
1332
 
1244
1333
  // History stack for undo/redo
1245
- __init10() {this.undoStack = []}
1246
- __init11() {this.redoStack = []}
1247
- __init12() {this.isApplyingHistory = false}
1334
+ __init13() {this.undoStack = []}
1335
+ __init14() {this.redoStack = []}
1336
+ __init15() {this.isApplyingHistory = false}
1337
+
1248
1338
  // Set while importing TSV: history and recalculation are done once at the end.
1249
- __init13() {this.batching = false}
1250
- __init14() {this.pendingCommits = []}
1339
+ __init16() {this.batching = false}
1340
+ __init17() {this.pendingCommits = []}
1251
1341
  // Row being evaluated, so [property] references resolve per row.
1252
- __init15() {this.evaluatingRowIndex = null}
1253
- constructor(options = {}) {;_class3.prototype.__init4.call(this);_class3.prototype.__init5.call(this);_class3.prototype.__init6.call(this);_class3.prototype.__init7.call(this);_class3.prototype.__init8.call(this);_class3.prototype.__init9.call(this);_class3.prototype.__init10.call(this);_class3.prototype.__init11.call(this);_class3.prototype.__init12.call(this);_class3.prototype.__init13.call(this);_class3.prototype.__init14.call(this);_class3.prototype.__init15.call(this);_class3.prototype.__init16.call(this);
1342
+ __init18() {this.evaluatingRowIndex = null}
1343
+ // Cell being evaluated, for implicit intersection (`=@A:A`).
1344
+ __init19() {this.evaluatingCell = null}
1345
+ // Dynamic arrays. Spilled values are derived state: they live here, not in
1346
+ // the document, and every recalculation rebuilds them.
1347
+ __init20() {this.spills = /* @__PURE__ */ new Map()}
1348
+ // anchor key -> spill
1349
+ __init21() {this.spilledBy = /* @__PURE__ */ new Map()}
1350
+ // spilled cell key -> anchor key
1351
+ __init22() {this.spillCells = /* @__PURE__ */ new Map()}
1352
+ // spillCellId -> displayed cell
1353
+ // Cells whose spill ownership changed during the current pass.
1354
+ __init23() {this.spillChanges = null}
1355
+ constructor(options = {}) {;_class3.prototype.__init7.call(this);_class3.prototype.__init8.call(this);_class3.prototype.__init9.call(this);_class3.prototype.__init10.call(this);_class3.prototype.__init11.call(this);_class3.prototype.__init12.call(this);_class3.prototype.__init13.call(this);_class3.prototype.__init14.call(this);_class3.prototype.__init15.call(this);_class3.prototype.__init16.call(this);_class3.prototype.__init17.call(this);_class3.prototype.__init18.call(this);_class3.prototype.__init19.call(this);_class3.prototype.__init20.call(this);_class3.prototype.__init21.call(this);_class3.prototype.__init22.call(this);_class3.prototype.__init23.call(this);_class3.prototype.__init24.call(this);
1254
1356
  const defaultCols = [
1255
1357
  { id: "col_a", key: "A", title: "A", width: 120, type: "freeform" },
1256
1358
  { id: "col_b", key: "B", title: "B", width: 120, type: "freeform" },
@@ -1264,28 +1366,32 @@ var SpreadsheetController = (_class3 = class {
1264
1366
  type: "freeform"
1265
1367
  }));
1266
1368
  this.document = {
1267
- id: _optionalChain([options, 'access', _48 => _48.document, 'optionalAccess', _49 => _49.id]) || `sheet_${Date.now()}`,
1268
- name: _optionalChain([options, 'access', _50 => _50.document, 'optionalAccess', _51 => _51.name]) || "Sheet 1",
1269
- columns: _optionalChain([options, 'access', _52 => _52.document, 'optionalAccess', _53 => _53.columns]) || defaultCols,
1270
- rows: _optionalChain([options, 'access', _54 => _54.document, 'optionalAccess', _55 => _55.rows]) || defaultRows,
1271
- cells: _optionalChain([options, 'access', _56 => _56.document, 'optionalAccess', _57 => _57.cells]) || {},
1272
- createdAt: _optionalChain([options, 'access', _58 => _58.document, 'optionalAccess', _59 => _59.createdAt]) || Date.now(),
1273
- updatedAt: _optionalChain([options, 'access', _60 => _60.document, 'optionalAccess', _61 => _61.updatedAt]) || Date.now(),
1274
- ..._optionalChain([options, 'access', _62 => _62.document, 'optionalAccess', _63 => _63.table]) ? { table: options.document.table } : {}
1369
+ id: _optionalChain([options, 'access', _58 => _58.document, 'optionalAccess', _59 => _59.id]) || `sheet_${Date.now()}`,
1370
+ name: _optionalChain([options, 'access', _60 => _60.document, 'optionalAccess', _61 => _61.name]) || "Sheet 1",
1371
+ columns: _optionalChain([options, 'access', _62 => _62.document, 'optionalAccess', _63 => _63.columns]) || defaultCols,
1372
+ rows: _optionalChain([options, 'access', _64 => _64.document, 'optionalAccess', _65 => _65.rows]) || defaultRows,
1373
+ cells: _optionalChain([options, 'access', _66 => _66.document, 'optionalAccess', _67 => _67.cells]) || {},
1374
+ createdAt: _optionalChain([options, 'access', _68 => _68.document, 'optionalAccess', _69 => _69.createdAt]) || Date.now(),
1375
+ updatedAt: _optionalChain([options, 'access', _70 => _70.document, 'optionalAccess', _71 => _71.updatedAt]) || Date.now(),
1376
+ ..._optionalChain([options, 'access', _72 => _72.document, 'optionalAccess', _73 => _73.table]) ? { table: options.document.table } : {}
1275
1377
  };
1276
1378
  this.primaryDataSourceId = options.primaryDataSourceId;
1379
+ this.maxHistoryBytes = Math.max(0, _nullishCoalesce(options.maxHistoryBytes, () => ( DEFAULT_MAX_HISTORY_BYTES)));
1277
1380
  this.onDocumentChange = options.onDocumentChange;
1278
1381
  this.onSelectionChange = options.onSelectionChange;
1279
1382
  this.onCellCommit = options.onCellCommit;
1280
1383
  if (options.dataSources) {
1281
1384
  options.dataSources.forEach((ds) => this.binder.register(ds));
1282
1385
  }
1283
- this.evaluator = new (0, _chunkJYRIOFENcjs.FormulaEvaluator)({
1386
+ this.evaluator = new (0, _chunkRIKBJLS2cjs.FormulaEvaluator)({
1284
1387
  resolveCell: (colStr, rowNum) => this.resolveCellByCoord(colStr, rowNum),
1285
1388
  resolveRange: (sCol, sRow, eCol, eRow) => this.resolveRangeByCoords(sCol, sRow, eCol, eRow),
1286
- resolveProperty: (prop) => this.resolveCurrentRowProperty(prop)
1389
+ resolveProperty: (prop) => this.resolveCurrentRowProperty(prop),
1390
+ resolveSpill: (colStr, rowNum) => this.resolveSpillByCoord(colStr, rowNum),
1391
+ getFormulaCell: () => this.evaluatingCell
1287
1392
  });
1288
1393
  this.syncWithDataSource();
1394
+ this.rederiveTypedValues();
1289
1395
  this.recalculateAll();
1290
1396
  }
1291
1397
  loadDocument(document) {
@@ -1297,9 +1403,63 @@ var SpreadsheetController = (_class3 = class {
1297
1403
  this.undoStack = [];
1298
1404
  this.redoStack = [];
1299
1405
  this.syncWithDataSource();
1406
+ this.rederiveTypedValues();
1300
1407
  this.recalculateAll();
1301
1408
  this.notifyChange();
1302
1409
  }
1410
+ /**
1411
+ * Re-parses the value of every stored typed (non-formula) cell from its
1412
+ * `raw` input, so documents saved before typed input was parsed (whose
1413
+ * values are text such as `"120"`) compare and sort as numbers. Cells of
1414
+ * bound columns in record rows keep their value: it belongs to the data
1415
+ * source.
1416
+ */
1417
+ rederiveTypedValues() {
1418
+ for (const row of this.document.rows) {
1419
+ const cells = this.document.cells[row.id];
1420
+ if (!cells) continue;
1421
+ for (const col of this.document.columns) {
1422
+ const cell = cells[col.id];
1423
+ if (!cell || typeof cell.raw !== "string" || cell.raw.startsWith("=")) continue;
1424
+ if (col.type === "bound" && col.binding && row.recordId) continue;
1425
+ const typed = this.typedCell(cell.raw, cell.format);
1426
+ cell.value = typed.value;
1427
+ if (typed.numberFormat) cell.numberFormat = typed.numberFormat;
1428
+ else delete cell.numberFormat;
1429
+ if (typed.format) cell.format = typed.format;
1430
+ }
1431
+ }
1432
+ }
1433
+ /**
1434
+ * Value of typed (non-formula) input: a number, boolean, ISO date, error
1435
+ * or text (see `parseCellInput`), its automatic number format, and the
1436
+ * `CellFormat` to use: the automatic one (currency, percentage, date,
1437
+ * number) when `format` is unset or `text` (the default of new columns).
1438
+ */
1439
+ typedCell(raw, format) {
1440
+ const parsed = _chunkRIKBJLS2cjs.parseCellInput.call(void 0, raw);
1441
+ return {
1442
+ value: parsed.value,
1443
+ ...parsed.numberFormat ? { numberFormat: parsed.numberFormat } : {},
1444
+ format: parsed.cellFormat && (!format || format === "text") ? parsed.cellFormat : format
1445
+ };
1446
+ }
1447
+ /**
1448
+ * Typed input for a bound field, coerced by the field's declared type:
1449
+ * number, boolean and date fields get a number, boolean or ISO date when
1450
+ * the input parses as one; string and enum fields (and unknown fields)
1451
+ * keep the text exactly as typed.
1452
+ */
1453
+ boundInputValue(dataSourceId, field, raw) {
1454
+ if (raw.startsWith("=")) return raw;
1455
+ const type = _optionalChain([this, 'access', _74 => _74.binder, 'access', _75 => _75.getDataSource, 'call', _76 => _76(dataSourceId), 'optionalAccess', _77 => _77.getFields, 'call', _78 => _78(), 'access', _79 => _79.find, 'call', _80 => _80((f) => f.key === field), 'optionalAccess', _81 => _81.type]);
1456
+ if (type !== "number" && type !== "boolean" && type !== "date") return raw;
1457
+ const parsed = _chunkRIKBJLS2cjs.parseCellInput.call(void 0, raw);
1458
+ if (type === "number" && parsed.type === "number") return parsed.value;
1459
+ if (type === "boolean" && parsed.type === "boolean") return parsed.value;
1460
+ if (type === "date" && parsed.type === "date") return parsed.value;
1461
+ return raw;
1462
+ }
1303
1463
  registerDataSource(ds) {
1304
1464
  this.binder.register(ds);
1305
1465
  this.syncWithDataSource();
@@ -1320,7 +1480,7 @@ var SpreadsheetController = (_class3 = class {
1320
1480
  r.index = idx;
1321
1481
  });
1322
1482
  this.document.columns.forEach((c, idx) => {
1323
- c.key = _chunkJYRIOFENcjs.indexToColName.call(void 0, idx);
1483
+ c.key = _chunkRIKBJLS2cjs.indexToColName.call(void 0, idx);
1324
1484
  });
1325
1485
  }
1326
1486
  getColumn(colIdOrKey) {
@@ -1335,7 +1495,12 @@ var SpreadsheetController = (_class3 = class {
1335
1495
  return this.document.rows.find((r) => r.id === rowIdOrIndex);
1336
1496
  }
1337
1497
  getCell(rowId, colId) {
1338
- const existing = _optionalChain([this, 'access', _64 => _64.document, 'access', _65 => _65.cells, 'access', _66 => _66[rowId], 'optionalAccess', _67 => _67[colId]]);
1498
+ const existing = _optionalChain([this, 'access', _82 => _82.document, 'access', _83 => _83.cells, 'access', _84 => _84[rowId], 'optionalAccess', _85 => _85[colId]]);
1499
+ if (existing && existing.raw !== "") return existing;
1500
+ if (this.spillCells.size > 0) {
1501
+ const spilled = this.spillCells.get(spillCellId(rowId, colId));
1502
+ if (spilled) return spilled;
1503
+ }
1339
1504
  if (existing) return existing;
1340
1505
  const col = this.document.columns.find((c) => c.id === colId);
1341
1506
  const row = this.document.rows.find((r) => r.id === rowId);
@@ -1362,7 +1527,7 @@ var SpreadsheetController = (_class3 = class {
1362
1527
  format: col.format
1363
1528
  };
1364
1529
  }
1365
- return { raw: "", value: "", format: _optionalChain([col, 'optionalAccess', _68 => _68.format]) };
1530
+ return { raw: "", value: "", format: _optionalChain([col, 'optionalAccess', _86 => _86.format]) };
1366
1531
  }
1367
1532
  setCellValue(rowId, colId, raw) {
1368
1533
  this.recordSnapshot();
@@ -1371,21 +1536,20 @@ var SpreadsheetController = (_class3 = class {
1371
1536
  }
1372
1537
  const col = this.document.columns.find((c) => c.id === colId);
1373
1538
  const row = this.document.rows.find((r) => r.id === rowId);
1374
- if (_optionalChain([col, 'optionalAccess', _69 => _69.type]) === "bound" && col.binding && _optionalChain([row, 'optionalAccess', _70 => _70.recordId])) {
1375
- this.binder.commitBoundValue(
1376
- col.binding.dataSource,
1377
- row.recordId,
1378
- col.binding.field,
1379
- raw
1380
- );
1539
+ const isFormula = raw.startsWith("=");
1540
+ let cell;
1541
+ if (_optionalChain([col, 'optionalAccess', _87 => _87.type]) === "bound" && col.binding && _optionalChain([row, 'optionalAccess', _88 => _88.recordId])) {
1542
+ const value = this.boundInputValue(col.binding.dataSource, col.binding.field, raw);
1543
+ this.binder.commitBoundValue(col.binding.dataSource, row.recordId, col.binding.field, value);
1544
+ cell = { raw, value, format: col.format };
1545
+ } else if (isFormula) {
1546
+ cell = { raw, value: raw, format: _optionalChain([col, 'optionalAccess', _89 => _89.format]) };
1547
+ } else {
1548
+ cell = { raw, ...this.typedCell(raw, _optionalChain([col, 'optionalAccess', _90 => _90.format])) };
1381
1549
  }
1382
1550
  const cellKey = this.getCellKey(rowId, colId);
1383
- this.depGraph.setCellFormula(cellKey, raw.startsWith("=") ? raw : null);
1384
- this.document.cells[rowId][colId] = {
1385
- raw,
1386
- value: raw,
1387
- format: _optionalChain([col, 'optionalAccess', _71 => _71.format])
1388
- };
1551
+ this.depGraph.setCellFormula(cellKey, isFormula ? raw : null);
1552
+ this.document.cells[rowId][colId] = cell;
1389
1553
  this.document.updatedAt = Date.now();
1390
1554
  if (this.batching) {
1391
1555
  this.pendingCommits.push([rowId, colId, raw]);
@@ -1393,8 +1557,8 @@ var SpreadsheetController = (_class3 = class {
1393
1557
  }
1394
1558
  this.recalculateCell(rowId, colId);
1395
1559
  this.notifyChange();
1396
- const evaluatedVal = _optionalChain([this, 'access', _72 => _72.document, 'access', _73 => _73.cells, 'access', _74 => _74[rowId], 'access', _75 => _75[colId], 'optionalAccess', _76 => _76.value]);
1397
- _optionalChain([this, 'access', _77 => _77.onCellCommit, 'optionalCall', _78 => _78(rowId, colId, raw, evaluatedVal)]);
1560
+ const evaluatedVal = _optionalChain([this, 'access', _91 => _91.document, 'access', _92 => _92.cells, 'access', _93 => _93[rowId], 'access', _94 => _94[colId], 'optionalAccess', _95 => _95.value]);
1561
+ _optionalChain([this, 'access', _96 => _96.onCellCommit, 'optionalCall', _97 => _97(rowId, colId, raw, evaluatedVal)]);
1398
1562
  }
1399
1563
  getCellKey(rowId, colId) {
1400
1564
  const row = this.document.rows.find((r) => r.id === rowId);
@@ -1408,7 +1572,30 @@ var SpreadsheetController = (_class3 = class {
1408
1572
  */
1409
1573
  recalculateCell(rowId, colId) {
1410
1574
  const cellKey = this.getCellKey(rowId, colId);
1411
- this.runEvaluationPlan(this.depGraph.getEvaluationPlan([cellKey], { includeDependents: true }));
1575
+ const anchor = this.spilledBy.get(cellKey);
1576
+ this.recalculateKeys(anchor ? [cellKey, anchor] : [cellKey], true);
1577
+ }
1578
+ /**
1579
+ * Recalculates `keys` (and, with `includeDependents`, their dependents) in
1580
+ * dependency order. Spill ranges are only known after evaluating their
1581
+ * anchors, so when a pass changes which cells hold spilled values (and so
1582
+ * the dependency graph), the dependents of those cells are recalculated in
1583
+ * another pass, until nothing changes.
1584
+ */
1585
+ recalculateKeys(keys, includeDependents) {
1586
+ let pending = Array.from(keys);
1587
+ let withDependents = includeDependents;
1588
+ for (let pass = 0; pass < MAX_SPILL_PASSES && pending.length > 0; pass++) {
1589
+ const changed = /* @__PURE__ */ new Set();
1590
+ this.spillChanges = changed;
1591
+ try {
1592
+ this.runEvaluationPlan(this.depGraph.getEvaluationPlan(pending, { includeDependents: withDependents }));
1593
+ } finally {
1594
+ this.spillChanges = null;
1595
+ }
1596
+ pending = Array.from(changed);
1597
+ withDependents = true;
1598
+ }
1412
1599
  }
1413
1600
  /**
1414
1601
  * Rebuilds the dependency graph from scratch and recalculates every formula
@@ -1416,10 +1603,13 @@ var SpreadsheetController = (_class3 = class {
1416
1603
  */
1417
1604
  recalculateAll() {
1418
1605
  this.depGraph.clear();
1606
+ this.spills.clear();
1607
+ this.spilledBy.clear();
1608
+ this.spillCells.clear();
1419
1609
  const formulaKeys = [];
1420
1610
  for (const row of this.document.rows) {
1421
1611
  for (const col of this.document.columns) {
1422
- const cell = _nullishCoalesce(_optionalChain([this, 'access', _79 => _79.document, 'access', _80 => _80.cells, 'access', _81 => _81[row.id], 'optionalAccess', _82 => _82[col.id]]), () => ( this.getDerivedCell(row, col)));
1612
+ const cell = _nullishCoalesce(_optionalChain([this, 'access', _98 => _98.document, 'access', _99 => _99.cells, 'access', _100 => _100[row.id], 'optionalAccess', _101 => _101[col.id]]), () => ( this.getDerivedCell(row, col)));
1423
1613
  if (cell.raw.startsWith("=")) {
1424
1614
  const cellKey = `${col.key}${row.index + 1}`.toUpperCase();
1425
1615
  this.depGraph.setCellFormula(cellKey, cell.raw);
@@ -1427,7 +1617,7 @@ var SpreadsheetController = (_class3 = class {
1427
1617
  }
1428
1618
  }
1429
1619
  }
1430
- this.runEvaluationPlan(this.depGraph.getEvaluationPlan(formulaKeys));
1620
+ this.recalculateKeys(formulaKeys, false);
1431
1621
  }
1432
1622
  runEvaluationPlan(plan) {
1433
1623
  for (const key of plan.order) {
@@ -1454,7 +1644,10 @@ var SpreadsheetController = (_class3 = class {
1454
1644
  if (!this.document.cells[row.id]) this.document.cells[row.id] = {};
1455
1645
  const deps = this.depGraph.getDependencies(cellKey);
1456
1646
  const selfReference = deps.includes(cellKey) || deps.includes(`${col.key.toUpperCase()}:`);
1457
- const errorMessage = selfReference ? "This formula can't reference its own cell." : "This formula is part of a circular reference: it depends on its own result through other cells.";
1647
+ const spilledKeys = this.depGraph.getSpilledKeys(cellKey);
1648
+ const ownSpill = deps.find((dep) => spilledKeys.includes(dep));
1649
+ const errorMessage = selfReference ? "This formula can't reference its own cell." : ownSpill ? `This formula refers to ${ownSpill}, which holds its own spilled results (a circular reference).` : "This formula is part of a circular reference: it depends on its own result through other cells.";
1650
+ this.clearSpill(cellKey.toUpperCase(), true);
1458
1651
  this.document.cells[row.id][col.id] = { ...cell, value: "#CYCLE!", error: "#CYCLE!", errorMessage };
1459
1652
  }
1460
1653
  evalSingleCellByKey(cellKey) {
@@ -1471,26 +1664,177 @@ var SpreadsheetController = (_class3 = class {
1471
1664
  cell.error = void 0;
1472
1665
  cell.errorMessage = void 0;
1473
1666
  }
1667
+ this.clearSpill(`${colName}${rowNum}`);
1474
1668
  return;
1475
1669
  }
1476
1670
  try {
1477
1671
  this.evaluatingRowIndex = rowNum - 1;
1672
+ this.evaluatingCell = { col: colName, row: rowNum };
1478
1673
  const result = this.evaluator.evaluateWithDiagnostics(cell.raw);
1479
1674
  if (!this.document.cells[row.id]) {
1480
1675
  this.document.cells[row.id] = {};
1481
1676
  }
1677
+ let { value, error, message } = result;
1678
+ if (result.array) {
1679
+ const blocked = this.placeSpill(`${colName}${rowNum}`, rowNum - 1, this.document.columns.indexOf(col), result.array);
1680
+ if (blocked) {
1681
+ value = "#SPILL!";
1682
+ error = "#SPILL!";
1683
+ message = blocked;
1684
+ }
1685
+ } else {
1686
+ this.clearSpill(`${colName}${rowNum}`);
1687
+ }
1482
1688
  this.document.cells[row.id][col.id] = {
1483
1689
  ...cell,
1484
- value: result.value,
1690
+ value,
1485
1691
  // `#ERROR!` (malformed formula, wrong argument count) keeps its
1486
1692
  // message in `error`, as before; other errors store their code.
1487
- error: result.error === "#ERROR!" ? result.message : result.error,
1488
- errorMessage: result.message
1693
+ error: error === "#ERROR!" ? message : error,
1694
+ errorMessage: message
1489
1695
  };
1490
1696
  } finally {
1491
1697
  this.evaluatingRowIndex = null;
1698
+ this.evaluatingCell = null;
1492
1699
  }
1493
1700
  }
1701
+ // --- Dynamic arrays (spilling) ---
1702
+ /**
1703
+ * Spills `array` from the anchor at (row, col) into the cells below and to
1704
+ * the right. Returns why it can't (the anchor then shows `#SPILL!`), or
1705
+ * null once placed. The grid never grows to fit an array, as in Excel.
1706
+ */
1707
+ placeSpill(anchor, row, col, array) {
1708
+ const { rows, cols } = array;
1709
+ const area = { startRow: row, startCol: col, endRow: row + rows - 1, endCol: col + cols - 1 };
1710
+ const label = `${_chunkRIKBJLS2cjs.indexToColName.call(void 0, area.startCol)}${area.startRow + 1}:${_chunkRIKBJLS2cjs.indexToColName.call(void 0, area.endCol)}${area.endRow + 1}`;
1711
+ let reason = null;
1712
+ const blockers = [];
1713
+ if (area.endRow >= this.document.rows.length || area.endCol >= this.document.columns.length) {
1714
+ reason = `The ${rows}\xD7${cols} result needs ${label}, which extends past the edge of the sheet.`;
1715
+ } else if (this.getMerges().some((m) => rangesIntersect(m, area))) {
1716
+ reason = `The result can't spill into merged cells (it needs ${label}).`;
1717
+ } else {
1718
+ for (let c = area.startCol; c <= area.endCol; c++) {
1719
+ const column = this.document.columns[c];
1720
+ for (let r = area.startRow; r <= area.endRow; r++) {
1721
+ if (r === row && c === col) continue;
1722
+ const rowObj = this.document.rows[r];
1723
+ const key = `${column.key}${r + 1}`.toUpperCase();
1724
+ const stored = _optionalChain([this, 'access', _102 => _102.document, 'access', _103 => _103.cells, 'access', _104 => _104[rowObj.id], 'optionalAccess', _105 => _105[column.id]]);
1725
+ const raw = stored ? stored.raw : this.getDerivedCell(rowObj, column).raw;
1726
+ const owner = this.spilledBy.get(key);
1727
+ if (raw !== "") {
1728
+ blockers.push(key);
1729
+ reason ??= `The result needs ${label}, but ${key} isn't empty.`;
1730
+ } else if (owner && owner !== anchor) {
1731
+ blockers.push(key);
1732
+ reason ??= `The result needs ${label}, but ${key} already holds values spilled from ${owner}.`;
1733
+ }
1734
+ }
1735
+ }
1736
+ }
1737
+ if (reason) {
1738
+ this.clearSpill(anchor);
1739
+ this.depGraph.setSpillEdges(anchor, [], blockers);
1740
+ return reason;
1741
+ }
1742
+ const previous = this.spills.get(anchor);
1743
+ const cells = [];
1744
+ for (let c = 0; c < cols; c++) {
1745
+ const column = this.document.columns[col + c];
1746
+ for (let r = 0; r < rows; r++) {
1747
+ if (r === 0 && c === 0) continue;
1748
+ const rowObj = this.document.rows[row + r];
1749
+ const key = `${column.key}${row + r + 1}`.toUpperCase();
1750
+ const value = _nullishCoalesce(array.values[c * rows + r], () => ( ""));
1751
+ const display = { raw: "", value, format: column.format, spillAnchor: anchor };
1752
+ if (_chunkRIKBJLS2cjs.isFormulaError.call(void 0, value)) {
1753
+ display.error = value;
1754
+ display.errorMessage = _chunkRIKBJLS2cjs.describeFormulaError.call(void 0, value);
1755
+ }
1756
+ this.spillCells.set(spillCellId(rowObj.id, column.id), display);
1757
+ if (this.spilledBy.get(key) !== anchor) {
1758
+ this.spilledBy.set(key, anchor);
1759
+ _optionalChain([this, 'access', _106 => _106.spillChanges, 'optionalAccess', _107 => _107.add, 'call', _108 => _108(key)]);
1760
+ }
1761
+ cells.push({ key, rowId: rowObj.id, colId: column.id });
1762
+ }
1763
+ }
1764
+ if (previous) {
1765
+ const kept = new Set(cells.map((cell) => cell.key));
1766
+ for (const old of previous.cells) {
1767
+ if (kept.has(old.key)) continue;
1768
+ this.forgetSpilledCell(anchor, old);
1769
+ }
1770
+ }
1771
+ this.spills.set(anchor, { anchor, row, col, rows, cols, values: array.values, cells });
1772
+ this.depGraph.setSpillEdges(anchor, cells.map((cell) => cell.key));
1773
+ return null;
1774
+ }
1775
+ /** Removes the array spilled from `anchor`. With `keepEdges`, its dependency edges stay. */
1776
+ clearSpill(anchor, keepEdges = false) {
1777
+ const record = this.spills.get(anchor);
1778
+ if (record) {
1779
+ for (const cell of record.cells) this.forgetSpilledCell(anchor, cell);
1780
+ this.spills.delete(anchor);
1781
+ }
1782
+ if (!keepEdges) this.depGraph.setSpillEdges(anchor, []);
1783
+ }
1784
+ forgetSpilledCell(anchor, cell) {
1785
+ if (this.spilledBy.get(cell.key) !== anchor) return;
1786
+ this.spilledBy.delete(cell.key);
1787
+ this.spillCells.delete(spillCellId(cell.rowId, cell.colId));
1788
+ _optionalChain([this, 'access', _109 => _109.spillChanges, 'optionalAccess', _110 => _110.add, 'call', _111 => _111(cell.key)]);
1789
+ }
1790
+ resolveSpillByCoord(colStr, rowNum) {
1791
+ const record = this.spills.get(`${colStr}${rowNum}`.toUpperCase());
1792
+ if (record) return { rows: record.rows, cols: record.cols, values: record.values };
1793
+ const value = this.resolveCellByCoord(colStr, rowNum);
1794
+ return _chunkRIKBJLS2cjs.isFormulaError.call(void 0, value) ? value : "#REF!";
1795
+ }
1796
+ toSpill(record) {
1797
+ const row = this.document.rows[record.row];
1798
+ const col = this.document.columns[record.col];
1799
+ return {
1800
+ key: record.anchor,
1801
+ anchor: { row: record.row, col: record.col },
1802
+ range: {
1803
+ startRow: record.row,
1804
+ startCol: record.col,
1805
+ endRow: record.row + record.rows - 1,
1806
+ endCol: record.col + record.cols - 1
1807
+ },
1808
+ formula: row && col ? this.getCell(row.id, col.id).raw : ""
1809
+ };
1810
+ }
1811
+ /**
1812
+ * The dynamic array covering (row, col), whether it is the anchor (the cell
1813
+ * holding the formula) or a spilled cell; null when there is none.
1814
+ */
1815
+ getSpillAt(row, col) {
1816
+ if (this.spills.size === 0) return null;
1817
+ const key = `${_chunkRIKBJLS2cjs.indexToColName.call(void 0, col)}${row + 1}`;
1818
+ const record = _nullishCoalesce(this.spills.get(key), () => ( this.spills.get(_nullishCoalesce(this.spilledBy.get(key), () => ( "")))));
1819
+ return record ? this.toSpill(record) : null;
1820
+ }
1821
+ /** Every dynamic array currently spilled. */
1822
+ getSpills() {
1823
+ return Array.from(this.spills.values(), (record) => this.toSpill(record));
1824
+ }
1825
+ /** Whether `range` overlaps a spilled array (its anchor or spilled cells). */
1826
+ intersectsSpill(range) {
1827
+ for (const record of this.spills.values()) {
1828
+ const area = {
1829
+ startRow: record.row,
1830
+ startCol: record.col,
1831
+ endRow: record.row + record.rows - 1,
1832
+ endCol: record.col + record.cols - 1
1833
+ };
1834
+ if (rangesIntersect(area, range)) return true;
1835
+ }
1836
+ return false;
1837
+ }
1494
1838
  resolveCellByCoord(colStr, rowNum) {
1495
1839
  const col = this.document.columns.find((c) => c.key.toUpperCase() === colStr.toUpperCase());
1496
1840
  const row = this.document.rows[rowNum - 1];
@@ -1498,15 +1842,15 @@ var SpreadsheetController = (_class3 = class {
1498
1842
  return _nullishCoalesce(this.getCell(row.id, col.id).value, () => ( ""));
1499
1843
  }
1500
1844
  resolveRangeByCoords(sCol, sRow, eCol, eRow) {
1501
- const startC = _chunkJYRIOFENcjs.colNameToIndex.call(void 0, sCol);
1502
- const endC = _chunkJYRIOFENcjs.colNameToIndex.call(void 0, eCol);
1845
+ const startC = _chunkRIKBJLS2cjs.colNameToIndex.call(void 0, sCol);
1846
+ const endC = _chunkRIKBJLS2cjs.colNameToIndex.call(void 0, eCol);
1503
1847
  const minC = Math.min(startC, endC);
1504
1848
  const maxC = Math.max(startC, endC);
1505
1849
  const minR = Math.min(sRow, eRow);
1506
- const maxR = Math.min(Math.max(sRow, eRow), _chunkJYRIOFENcjs.WHOLE_COLUMN_END_ROW, this.document.rows.length);
1850
+ const maxR = Math.min(Math.max(sRow, eRow), _chunkRIKBJLS2cjs.WHOLE_COLUMN_END_ROW, this.document.rows.length);
1507
1851
  const results = [];
1508
1852
  for (let c = minC; c <= maxC; c++) {
1509
- const colName = _chunkJYRIOFENcjs.indexToColName.call(void 0, c);
1853
+ const colName = _chunkRIKBJLS2cjs.indexToColName.call(void 0, c);
1510
1854
  const col = this.document.columns.find((colDef) => colDef.key.toUpperCase() === colName);
1511
1855
  if (!col) continue;
1512
1856
  for (let r = minR; r <= maxR; r++) {
@@ -1518,7 +1862,7 @@ var SpreadsheetController = (_class3 = class {
1518
1862
  return results;
1519
1863
  }
1520
1864
  resolveCurrentRowProperty(prop) {
1521
- const rowIndex = _nullishCoalesce(this.evaluatingRowIndex, () => ( _optionalChain([this, 'access', _83 => _83.activeCell, 'optionalAccess', _84 => _84.row])));
1865
+ const rowIndex = _nullishCoalesce(this.evaluatingRowIndex, () => ( _optionalChain([this, 'access', _112 => _112.activeCell, 'optionalAccess', _113 => _113.row])));
1522
1866
  if (rowIndex === void 0 || rowIndex === null) return 0;
1523
1867
  const row = this.document.rows[rowIndex];
1524
1868
  if (!row || !row.recordId || !this.primaryDataSourceId) return 0;
@@ -1536,8 +1880,8 @@ var SpreadsheetController = (_class3 = class {
1536
1880
  this.activeCell = {
1537
1881
  row: activeRow,
1538
1882
  col: activeCol,
1539
- rowId: _optionalChain([rowObj, 'optionalAccess', _85 => _85.id]),
1540
- colId: _optionalChain([colObj, 'optionalAccess', _86 => _86.id])
1883
+ rowId: _optionalChain([rowObj, 'optionalAccess', _114 => _114.id]),
1884
+ colId: _optionalChain([colObj, 'optionalAccess', _115 => _115.id])
1541
1885
  };
1542
1886
  if (extendSelection && this.selectedRange) {
1543
1887
  this.selectedRange = this.expandRangeToMerges({
@@ -1556,16 +1900,16 @@ var SpreadsheetController = (_class3 = class {
1556
1900
  endCol: clampedCol
1557
1901
  };
1558
1902
  }
1559
- _optionalChain([this, 'access', _87 => _87.onSelectionChange, 'optionalCall', _88 => _88(this.activeCell, this.selectedRange)]);
1903
+ _optionalChain([this, 'access', _116 => _116.onSelectionChange, 'optionalCall', _117 => _117(this.activeCell, this.selectedRange)]);
1560
1904
  }
1561
1905
  selectRange(range) {
1562
1906
  this.selectedRange = range;
1563
- _optionalChain([this, 'access', _89 => _89.onSelectionChange, 'optionalCall', _90 => _90(this.activeCell, this.selectedRange)]);
1907
+ _optionalChain([this, 'access', _118 => _118.onSelectionChange, 'optionalCall', _119 => _119(this.activeCell, this.selectedRange)]);
1564
1908
  }
1565
1909
  startEditing(row, col, initialValue) {
1566
- this.selectCell(_nullishCoalesce(_nullishCoalesce(row, () => ( _optionalChain([this, 'access', _91 => _91.activeCell, 'optionalAccess', _92 => _92.row]))), () => ( 0)), _nullishCoalesce(_nullishCoalesce(col, () => ( _optionalChain([this, 'access', _93 => _93.activeCell, 'optionalAccess', _94 => _94.col]))), () => ( 0)));
1567
- const targetRow = _nullishCoalesce(_optionalChain([this, 'access', _95 => _95.activeCell, 'optionalAccess', _96 => _96.row]), () => ( 0));
1568
- const targetCol = _nullishCoalesce(_optionalChain([this, 'access', _97 => _97.activeCell, 'optionalAccess', _98 => _98.col]), () => ( 0));
1910
+ this.selectCell(_nullishCoalesce(_nullishCoalesce(row, () => ( _optionalChain([this, 'access', _120 => _120.activeCell, 'optionalAccess', _121 => _121.row]))), () => ( 0)), _nullishCoalesce(_nullishCoalesce(col, () => ( _optionalChain([this, 'access', _122 => _122.activeCell, 'optionalAccess', _123 => _123.col]))), () => ( 0)));
1911
+ const targetRow = _nullishCoalesce(_optionalChain([this, 'access', _124 => _124.activeCell, 'optionalAccess', _125 => _125.row]), () => ( 0));
1912
+ const targetCol = _nullishCoalesce(_optionalChain([this, 'access', _126 => _126.activeCell, 'optionalAccess', _127 => _127.col]), () => ( 0));
1569
1913
  const rowObj = this.document.rows[targetRow];
1570
1914
  const colObj = this.document.columns[targetCol];
1571
1915
  if (!rowObj || !colObj) return;
@@ -1619,17 +1963,17 @@ var SpreadsheetController = (_class3 = class {
1619
1963
  // --- Grid Structure Mutations ---
1620
1964
  insertColumn(index, config) {
1621
1965
  this.recordSnapshot();
1622
- const newId = _optionalChain([config, 'optionalAccess', _99 => _99.id]) || this.generateId("col");
1966
+ const newId = _optionalChain([config, 'optionalAccess', _128 => _128.id]) || this.generateId("col");
1623
1967
  const newCol = {
1624
1968
  id: newId,
1625
- key: _chunkJYRIOFENcjs.indexToColName.call(void 0, index),
1626
- title: _optionalChain([config, 'optionalAccess', _100 => _100.title]) || _chunkJYRIOFENcjs.indexToColName.call(void 0, index),
1627
- width: _optionalChain([config, 'optionalAccess', _101 => _101.width]) || 130,
1628
- type: _optionalChain([config, 'optionalAccess', _102 => _102.type]) || "freeform",
1629
- binding: _optionalChain([config, 'optionalAccess', _103 => _103.binding]),
1630
- formula: _optionalChain([config, 'optionalAccess', _104 => _104.formula]),
1631
- format: _optionalChain([config, 'optionalAccess', _105 => _105.format]) || "text",
1632
- readOnly: _optionalChain([config, 'optionalAccess', _106 => _106.readOnly])
1969
+ key: _chunkRIKBJLS2cjs.indexToColName.call(void 0, index),
1970
+ title: _optionalChain([config, 'optionalAccess', _129 => _129.title]) || _chunkRIKBJLS2cjs.indexToColName.call(void 0, index),
1971
+ width: _optionalChain([config, 'optionalAccess', _130 => _130.width]) || 130,
1972
+ type: _optionalChain([config, 'optionalAccess', _131 => _131.type]) || "freeform",
1973
+ binding: _optionalChain([config, 'optionalAccess', _132 => _132.binding]),
1974
+ formula: _optionalChain([config, 'optionalAccess', _133 => _133.formula]),
1975
+ format: _optionalChain([config, 'optionalAccess', _134 => _134.format]) || "text",
1976
+ readOnly: _optionalChain([config, 'optionalAccess', _135 => _135.readOnly])
1633
1977
  };
1634
1978
  this.shiftReferences({ axis: "col", index, type: "insert" });
1635
1979
  this.adjustTableForStructuralChange({ axis: "col", index, type: "insert" });
@@ -1654,13 +1998,13 @@ var SpreadsheetController = (_class3 = class {
1654
1998
  }
1655
1999
  insertRow(index, config) {
1656
2000
  this.recordSnapshot();
1657
- const newId = _optionalChain([config, 'optionalAccess', _107 => _107.id]) || this.generateId("row");
2001
+ const newId = _optionalChain([config, 'optionalAccess', _136 => _136.id]) || this.generateId("row");
1658
2002
  const newRow = {
1659
2003
  id: newId,
1660
2004
  index,
1661
- height: _optionalChain([config, 'optionalAccess', _108 => _108.height]) || 32,
1662
- recordId: _optionalChain([config, 'optionalAccess', _109 => _109.recordId]),
1663
- type: _optionalChain([config, 'optionalAccess', _110 => _110.type]) || "freeform"
2005
+ height: _optionalChain([config, 'optionalAccess', _137 => _137.height]) || 32,
2006
+ recordId: _optionalChain([config, 'optionalAccess', _138 => _138.recordId]),
2007
+ type: _optionalChain([config, 'optionalAccess', _139 => _139.type]) || "freeform"
1664
2008
  };
1665
2009
  this.shiftReferences({ axis: "row", index, type: "insert" });
1666
2010
  this.adjustTableForStructuralChange({ axis: "row", index, type: "insert" });
@@ -1691,14 +2035,14 @@ var SpreadsheetController = (_class3 = class {
1691
2035
  shiftReferences(change) {
1692
2036
  for (const rowCells of Object.values(this.document.cells)) {
1693
2037
  for (const cell of Object.values(rowCells)) {
1694
- if (_optionalChain([cell, 'access', _111 => _111.raw, 'optionalAccess', _112 => _112.startsWith, 'call', _113 => _113("=")])) {
2038
+ if (_optionalChain([cell, 'access', _140 => _140.raw, 'optionalAccess', _141 => _141.startsWith, 'call', _142 => _142("=")])) {
1695
2039
  cell.raw = shiftFormulaReferences(cell.raw, change);
1696
2040
  }
1697
2041
  }
1698
2042
  }
1699
2043
  if (change.axis === "col") {
1700
2044
  for (const col of this.document.columns) {
1701
- if (_optionalChain([col, 'access', _114 => _114.formula, 'optionalAccess', _115 => _115.startsWith, 'call', _116 => _116("=")])) {
2045
+ if (_optionalChain([col, 'access', _143 => _143.formula, 'optionalAccess', _144 => _144.startsWith, 'call', _145 => _145("=")])) {
1702
2046
  col.formula = shiftFormulaReferences(col.formula, change);
1703
2047
  }
1704
2048
  }
@@ -1721,7 +2065,7 @@ var SpreadsheetController = (_class3 = class {
1721
2065
  let maxLen = (col.title || "").length + (col.key ? col.key.length + 3 : 0);
1722
2066
  for (const row of this.document.rows) {
1723
2067
  const cell = this.getCell(row.id, col.id);
1724
- const valStr = cell.value != null ? String(cell.value) : "";
2068
+ const valStr = _chunkRIKBJLS2cjs.formatCellDisplay.call(void 0, cell);
1725
2069
  if (valStr.length > maxLen) {
1726
2070
  maxLen = valStr.length;
1727
2071
  }
@@ -1745,8 +2089,7 @@ var SpreadsheetController = (_class3 = class {
1745
2089
  ) : this.document.columns;
1746
2090
  return rows.map(
1747
2091
  (row) => columns.map((col) => {
1748
- const cell = this.getCell(row.id, col.id);
1749
- return String(_nullishCoalesce(cell.value, () => ( ""))).replace(/\t/g, " ");
2092
+ return _chunkRIKBJLS2cjs.formatCellDisplay.call(void 0, this.getCell(row.id, col.id)).replace(/\t/g, " ");
1750
2093
  }).join(" ")
1751
2094
  ).join("\n");
1752
2095
  }
@@ -1766,7 +2109,7 @@ var SpreadsheetController = (_class3 = class {
1766
2109
  this.document.rows.push({ id: this.generateId("row"), index, height: 32, type: "freeform" });
1767
2110
  }
1768
2111
  while (colIndex >= this.document.columns.length) {
1769
- const key = _chunkJYRIOFENcjs.indexToColName.call(void 0, this.document.columns.length);
2112
+ const key = _chunkRIKBJLS2cjs.indexToColName.call(void 0, this.document.columns.length);
1770
2113
  this.document.columns.push({
1771
2114
  id: this.generateId("col"),
1772
2115
  key,
@@ -1813,7 +2156,7 @@ var SpreadsheetController = (_class3 = class {
1813
2156
  const commits = this.pendingCommits;
1814
2157
  this.pendingCommits = [];
1815
2158
  for (const [rowId, colId, raw] of commits) {
1816
- _optionalChain([this, 'access', _117 => _117.onCellCommit, 'optionalCall', _118 => _118(rowId, colId, raw, _optionalChain([this, 'access', _119 => _119.document, 'access', _120 => _120.cells, 'access', _121 => _121[rowId], 'optionalAccess', _122 => _122[colId], 'optionalAccess', _123 => _123.value]))]);
2159
+ _optionalChain([this, 'access', _146 => _146.onCellCommit, 'optionalCall', _147 => _147(rowId, colId, raw, _optionalChain([this, 'access', _148 => _148.document, 'access', _149 => _149.cells, 'access', _150 => _150[rowId], 'optionalAccess', _151 => _151[colId], 'optionalAccess', _152 => _152.value]))]);
1817
2160
  }
1818
2161
  }
1819
2162
  // --- CSV ---
@@ -1823,7 +2166,7 @@ var SpreadsheetController = (_class3 = class {
1823
2166
  */
1824
2167
  exportToCsv(options = {}) {
1825
2168
  const matrix = this.readMatrix(_nullishCoalesce(options.range, () => ( null))).map(
1826
- (row) => row.map((cell) => options.formulas ? cell.raw : String(_nullishCoalesce(cell.value, () => ( ""))))
2169
+ (row) => row.map((cell) => options.formulas ? cell.raw : _chunkRIKBJLS2cjs.formatCellDisplay.call(void 0, cell))
1827
2170
  );
1828
2171
  return serializeCsv(matrix, {
1829
2172
  delimiter: options.delimiter,
@@ -1861,7 +2204,16 @@ var SpreadsheetController = (_class3 = class {
1861
2204
  */
1862
2205
  copyToClipboardData(range = this.selectedRange) {
1863
2206
  const r = range ? normalizeRange(range) : { startRow: 0, startCol: 0, endRow: this.document.rows.length - 1, endCol: this.document.columns.length - 1 };
1864
- const cells = this.readMatrix(r).map((row) => row.map((cell) => ({ raw: cell.raw, value: cell.error || cell.value })));
2207
+ const cells = this.readMatrix(r).map(
2208
+ (row) => row.map((cell) => {
2209
+ const value = cell.error || cell.value;
2210
+ const text = _chunkRIKBJLS2cjs.formatCellDisplay.call(void 0, cell);
2211
+ if (cell.spillAnchor && !this.spillAnchorInRange(cell.spillAnchor, r)) {
2212
+ return { raw: text, value, text };
2213
+ }
2214
+ return { raw: cell.raw, value, text };
2215
+ })
2216
+ );
1865
2217
  return createSpreadsheetClipboardData(cells, { row: r.startRow, col: r.startCol });
1866
2218
  }
1867
2219
  /**
@@ -1884,12 +2236,16 @@ var SpreadsheetController = (_class3 = class {
1884
2236
  this.selectRange(r);
1885
2237
  return true;
1886
2238
  }
2239
+ spillAnchorInRange(anchor, range) {
2240
+ const record = this.spills.get(anchor);
2241
+ return !!record && rangeContains(range, record.row, record.col);
2242
+ }
1887
2243
  getSelectionTopLeft() {
1888
2244
  if (this.selectedRange) {
1889
2245
  const r = normalizeRange(this.selectedRange);
1890
2246
  return { row: r.startRow, col: r.startCol };
1891
2247
  }
1892
- return { row: _nullishCoalesce(_optionalChain([this, 'access', _124 => _124.activeCell, 'optionalAccess', _125 => _125.row]), () => ( 0)), col: _nullishCoalesce(_optionalChain([this, 'access', _126 => _126.activeCell, 'optionalAccess', _127 => _127.col]), () => ( 0)) };
2248
+ return { row: _nullishCoalesce(_optionalChain([this, 'access', _153 => _153.activeCell, 'optionalAccess', _154 => _154.row]), () => ( 0)), col: _nullishCoalesce(_optionalChain([this, 'access', _155 => _155.activeCell, 'optionalAccess', _156 => _156.col]), () => ( 0)) };
1893
2249
  }
1894
2250
  // --- Table operations: shared helpers ---
1895
2251
  /** The table settings object, created on first use. */
@@ -1913,7 +2269,7 @@ var SpreadsheetController = (_class3 = class {
1913
2269
  const { headerRows, footerRows } = getTableSections(this.document);
1914
2270
  return { start: headerRows, end: this.document.rows.length - footerRows - 1 };
1915
2271
  }
1916
- __init16() {this.getCellValueAt = (rowIndex, colIndex) => {
2272
+ __init24() {this.getCellValueAt = (rowIndex, colIndex) => {
1917
2273
  const row = this.document.rows[rowIndex];
1918
2274
  const col = this.document.columns[colIndex];
1919
2275
  if (!row || !col) return "";
@@ -1923,7 +2279,7 @@ var SpreadsheetController = (_class3 = class {
1923
2279
  remapAllFormulas(moveCell) {
1924
2280
  for (const rowCells of Object.values(this.document.cells)) {
1925
2281
  for (const cell of Object.values(rowCells)) {
1926
- if (_optionalChain([cell, 'access', _128 => _128.raw, 'optionalAccess', _129 => _129.startsWith, 'call', _130 => _130("=")])) {
2282
+ if (_optionalChain([cell, 'access', _157 => _157.raw, 'optionalAccess', _158 => _158.startsWith, 'call', _159 => _159("=")])) {
1927
2283
  cell.raw = remapFormulaReferences(cell.raw, moveCell);
1928
2284
  }
1929
2285
  }
@@ -1935,8 +2291,8 @@ var SpreadsheetController = (_class3 = class {
1935
2291
  * merges reduced to a single cell are dropped.
1936
2292
  */
1937
2293
  adjustTableForStructuralChange(change) {
1938
- const merges = _optionalChain([this, 'access', _131 => _131.document, 'access', _132 => _132.table, 'optionalAccess', _133 => _133.merges]);
1939
- if (!_optionalChain([merges, 'optionalAccess', _134 => _134.length])) return;
2294
+ const merges = _optionalChain([this, 'access', _160 => _160.document, 'access', _161 => _161.table, 'optionalAccess', _162 => _162.merges]);
2295
+ if (!_optionalChain([merges, 'optionalAccess', _163 => _163.length])) return;
1940
2296
  const startKey = change.axis === "row" ? "startRow" : "startCol";
1941
2297
  const endKey = change.axis === "row" ? "endRow" : "endCol";
1942
2298
  const next = [];
@@ -1967,8 +2323,8 @@ var SpreadsheetController = (_class3 = class {
1967
2323
  const colCount = this.document.columns.length;
1968
2324
  const body = this.getBodyRowBounds();
1969
2325
  const range = options.range ? normalizeRange(options.range) : null;
1970
- const startRow = Math.max(_nullishCoalesce(_optionalChain([range, 'optionalAccess', _135 => _135.startRow]), () => ( body.start)), body.start);
1971
- const endRow = Math.min(_nullishCoalesce(_optionalChain([range, 'optionalAccess', _136 => _136.endRow]), () => ( body.end)), body.end);
2326
+ const startRow = Math.max(_nullishCoalesce(_optionalChain([range, 'optionalAccess', _164 => _164.startRow]), () => ( body.start)), body.start);
2327
+ const endRow = Math.min(_nullishCoalesce(_optionalChain([range, 'optionalAccess', _165 => _165.endRow]), () => ( body.end)), body.end);
1972
2328
  const startCol = range ? Math.max(0, range.startCol) : 0;
1973
2329
  const endCol = range ? Math.min(colCount - 1, range.endCol) : colCount - 1;
1974
2330
  if (endRow - startRow < 1 || startCol > endCol) return false;
@@ -1978,7 +2334,8 @@ var SpreadsheetController = (_class3 = class {
1978
2334
  }));
1979
2335
  if (keyCols.length === 0 || keyCols.some((k) => k.index < startCol || k.index > endCol)) return false;
1980
2336
  const area = { startRow, startCol, endRow, endCol };
1981
- if ((_nullishCoalesce(_optionalChain([this, 'access', _137 => _137.document, 'access', _138 => _138.table, 'optionalAccess', _139 => _139.merges]), () => ( []))).some((m) => rangesIntersect(m, area))) return false;
2337
+ if ((_nullishCoalesce(_optionalChain([this, 'access', _166 => _166.document, 'access', _167 => _167.table, 'optionalAccess', _168 => _168.merges]), () => ( []))).some((m) => rangesIntersect(m, area))) return false;
2338
+ if (this.intersectsSpill(area)) return false;
1982
2339
  const sourceRows = [];
1983
2340
  for (let r = startRow; r <= endRow; r++) sourceRows.push(r);
1984
2341
  const sorted = sourceRows.map((r) => ({ r, values: keyCols.map((k) => this.getCellValueAt(r, k.index)) })).sort((a, b) => {
@@ -2005,7 +2362,7 @@ var SpreadsheetController = (_class3 = class {
2005
2362
  const colIds = this.document.columns.slice(startCol, endCol + 1).map((c) => c.id);
2006
2363
  const snapshot = sorted.map((oldRow) => {
2007
2364
  const rowId = this.document.rows[oldRow].id;
2008
- return colIds.map((colId) => _optionalChain([this, 'access', _140 => _140.document, 'access', _141 => _141.cells, 'access', _142 => _142[rowId], 'optionalAccess', _143 => _143[colId]]));
2365
+ return colIds.map((colId) => _optionalChain([this, 'access', _169 => _169.document, 'access', _170 => _170.cells, 'access', _171 => _171[rowId], 'optionalAccess', _172 => _172[colId]]));
2009
2366
  });
2010
2367
  snapshot.forEach((cells, i) => {
2011
2368
  const rowId = this.document.rows[startRow + i].id;
@@ -2021,7 +2378,7 @@ var SpreadsheetController = (_class3 = class {
2021
2378
  }
2022
2379
  // --- Filters ---
2023
2380
  getFilterState() {
2024
- return _nullishCoalesce(_optionalChain([this, 'access', _144 => _144.document, 'access', _145 => _145.table, 'optionalAccess', _146 => _146.filter]), () => ( { enabled: false, rules: [] }));
2381
+ return _nullishCoalesce(_optionalChain([this, 'access', _173 => _173.document, 'access', _174 => _174.table, 'optionalAccess', _175 => _175.filter]), () => ( { enabled: false, rules: [] }));
2025
2382
  }
2026
2383
  /** Replaces all filter rules (and turns filters on when there are any). */
2027
2384
  setFilterRules(rules) {
@@ -2098,7 +2455,7 @@ var SpreadsheetController = (_class3 = class {
2098
2455
  }
2099
2456
  setTableCount(key, count, max) {
2100
2457
  const value = Math.max(0, Math.min(Math.floor(count), max));
2101
- if ((_nullishCoalesce(_optionalChain([this, 'access', _147 => _147.document, 'access', _148 => _148.table, 'optionalAccess', _149 => _149[key]]), () => ( 0))) === value) return;
2458
+ if ((_nullishCoalesce(_optionalChain([this, 'access', _176 => _176.document, 'access', _177 => _177.table, 'optionalAccess', _178 => _178[key]]), () => ( 0))) === value) return;
2102
2459
  this.applyTableChange(() => {
2103
2460
  this.table[key] = value;
2104
2461
  });
@@ -2139,7 +2496,7 @@ var SpreadsheetController = (_class3 = class {
2139
2496
  }
2140
2497
  // --- Merged cells ---
2141
2498
  getMerges() {
2142
- return _nullishCoalesce(_optionalChain([this, 'access', _150 => _150.document, 'access', _151 => _151.table, 'optionalAccess', _152 => _152.merges]), () => ( []));
2499
+ return _nullishCoalesce(_optionalChain([this, 'access', _179 => _179.document, 'access', _180 => _180.table, 'optionalAccess', _181 => _181.merges]), () => ( []));
2143
2500
  }
2144
2501
  /** The merge containing (row, col), or null. */
2145
2502
  getMergeAt(row, col) {
@@ -2186,12 +2543,13 @@ var SpreadsheetController = (_class3 = class {
2186
2543
  }
2187
2544
  const merges = this.getMerges();
2188
2545
  if (merges.some((m) => rangesIntersect(m, r) && !rangeContainsRange(r, m))) return false;
2546
+ if (this.intersectsSpill(r)) return false;
2189
2547
  this.applyTableChange(() => {
2190
2548
  for (let row = r.startRow; row <= r.endRow; row++) {
2191
2549
  const rowId = this.document.rows[row].id;
2192
2550
  for (let col = r.startCol; col <= r.endCol; col++) {
2193
2551
  if (row === r.startRow && col === r.startCol) continue;
2194
- _optionalChainDelete([this, 'access', _153 => _153.document, 'access', _154 => _154.cells, 'access', _155 => _155[rowId], 'optionalAccess', _156 => _156[this.document.columns[col].id]]);
2552
+ _optionalChainDelete([this, 'access', _182 => _182.document, 'access', _183 => _183.cells, 'access', _184 => _184[rowId], 'optionalAccess', _185 => _185[this.document.columns[col].id]]);
2195
2553
  }
2196
2554
  }
2197
2555
  this.table.merges = [...merges.filter((m) => !rangeContainsRange(r, m)), r];
@@ -2207,7 +2565,7 @@ var SpreadsheetController = (_class3 = class {
2207
2565
  if (remaining.length === merges.length) return false;
2208
2566
  this.applyTableChange(() => {
2209
2567
  this.table.merges = remaining;
2210
- });
2568
+ }, { recalculate: true });
2211
2569
  return true;
2212
2570
  }
2213
2571
  // --- Autofill ---
@@ -2277,14 +2635,14 @@ var SpreadsheetController = (_class3 = class {
2277
2635
  });
2278
2636
  }
2279
2637
  ungroupRows() {
2280
- if (!_optionalChain([this, 'access', _157 => _157.document, 'access', _158 => _158.table, 'optionalAccess', _159 => _159.grouping])) return;
2638
+ if (!_optionalChain([this, 'access', _186 => _186.document, 'access', _187 => _187.table, 'optionalAccess', _188 => _188.grouping])) return;
2281
2639
  this.applyTableChange(() => {
2282
2640
  delete this.table.grouping;
2283
2641
  });
2284
2642
  }
2285
2643
  /** Sets (or with `null`, removes) the group summary for a column. */
2286
2644
  setGroupSummary(colId, aggregate) {
2287
- const grouping = _optionalChain([this, 'access', _160 => _160.document, 'access', _161 => _161.table, 'optionalAccess', _162 => _162.grouping]);
2645
+ const grouping = _optionalChain([this, 'access', _189 => _189.document, 'access', _190 => _190.table, 'optionalAccess', _191 => _191.grouping]);
2288
2646
  if (!grouping) return;
2289
2647
  this.applyTableChange(() => {
2290
2648
  const others = grouping.summaries.filter((s) => s.colId !== colId);
@@ -2295,7 +2653,7 @@ var SpreadsheetController = (_class3 = class {
2295
2653
  });
2296
2654
  }
2297
2655
  setGroupCollapsed(key, collapsed) {
2298
- const grouping = _optionalChain([this, 'access', _163 => _163.document, 'access', _164 => _164.table, 'optionalAccess', _165 => _165.grouping]);
2656
+ const grouping = _optionalChain([this, 'access', _192 => _192.document, 'access', _193 => _193.table, 'optionalAccess', _194 => _194.grouping]);
2299
2657
  if (!grouping || grouping.collapsed.includes(key) === collapsed) return;
2300
2658
  this.applyTableChange(() => {
2301
2659
  this.table.grouping = {
@@ -2305,7 +2663,7 @@ var SpreadsheetController = (_class3 = class {
2305
2663
  });
2306
2664
  }
2307
2665
  toggleGroupCollapsed(key) {
2308
- const grouping = _optionalChain([this, 'access', _166 => _166.document, 'access', _167 => _167.table, 'optionalAccess', _168 => _168.grouping]);
2666
+ const grouping = _optionalChain([this, 'access', _195 => _195.document, 'access', _196 => _196.table, 'optionalAccess', _197 => _197.grouping]);
2309
2667
  if (!grouping) return;
2310
2668
  this.setGroupCollapsed(key, !grouping.collapsed.includes(key));
2311
2669
  }
@@ -2328,6 +2686,7 @@ var SpreadsheetController = (_class3 = class {
2328
2686
  const width = s.endCol - s.startCol + 1;
2329
2687
  const t = { startRow: s.startRow, startCol: s.startCol, endRow: s.startRow + width - 1, endCol: s.startCol + height - 1 };
2330
2688
  if (this.getMerges().some((m) => rangesIntersect(m, s) || rangesIntersect(m, t))) return false;
2689
+ if (this.intersectsSpill(s) || this.intersectsSpill(t)) return false;
2331
2690
  this.applyTableChange(() => {
2332
2691
  this.growGrid(t.endRow, t.endCol);
2333
2692
  this.remapAllFormulas(({ row, col }) => {
@@ -2342,9 +2701,9 @@ var SpreadsheetController = (_class3 = class {
2342
2701
  moved.push({
2343
2702
  row: s.startRow + (c - s.startCol),
2344
2703
  col: s.startCol + (r - s.startRow),
2345
- cell: _optionalChain([this, 'access', _169 => _169.document, 'access', _170 => _170.cells, 'access', _171 => _171[rowId(r)], 'optionalAccess', _172 => _172[colId(c)]])
2704
+ cell: _optionalChain([this, 'access', _198 => _198.document, 'access', _199 => _199.cells, 'access', _200 => _200[rowId(r)], 'optionalAccess', _201 => _201[colId(c)]])
2346
2705
  });
2347
- _optionalChainDelete([this, 'access', _173 => _173.document, 'access', _174 => _174.cells, 'access', _175 => _175[rowId(r)], 'optionalAccess', _176 => _176[colId(c)]]);
2706
+ _optionalChainDelete([this, 'access', _202 => _202.document, 'access', _203 => _203.cells, 'access', _204 => _204[rowId(r)], 'optionalAccess', _205 => _205[colId(c)]]);
2348
2707
  }
2349
2708
  }
2350
2709
  for (const { row, col, cell } of moved) {
@@ -2371,6 +2730,28 @@ var SpreadsheetController = (_class3 = class {
2371
2730
  this.undoStack.push(JSON.stringify(this.document));
2372
2731
  if (this.undoStack.length > 50) this.undoStack.shift();
2373
2732
  this.redoStack = [];
2733
+ this.trimHistory();
2734
+ }
2735
+ /** Drops the oldest snapshots beyond `maxHistoryBytes`, always keeping the newest. */
2736
+ trimHistory() {
2737
+ if (this.maxHistoryBytes <= 0 || this.undoStack.length <= 1) return;
2738
+ let total = 0;
2739
+ for (const s of this.undoStack) total += s.length * 2;
2740
+ for (const s of this.redoStack) total += s.length * 2;
2741
+ while (total > this.maxHistoryBytes && this.undoStack.length > 1) {
2742
+ total -= this.undoStack.shift().length * 2;
2743
+ }
2744
+ }
2745
+ /** Approximate bytes held by the undo/redo snapshots (UTF-16 size). */
2746
+ getHistoryByteSize() {
2747
+ let total = 0;
2748
+ for (const s of this.undoStack) total += s.length * 2;
2749
+ for (const s of this.redoStack) total += s.length * 2;
2750
+ return total;
2751
+ }
2752
+ /** Number of undo / redo snapshots currently held. */
2753
+ getHistoryDepth() {
2754
+ return { undo: this.undoStack.length, redo: this.redoStack.length };
2374
2755
  }
2375
2756
  undo() {
2376
2757
  if (this.undoStack.length === 0) return;
@@ -2397,7 +2778,7 @@ var SpreadsheetController = (_class3 = class {
2397
2778
  }
2398
2779
  }
2399
2780
  notifyChange() {
2400
- _optionalChain([this, 'access', _177 => _177.onDocumentChange, 'optionalCall', _178 => _178(this.document)]);
2781
+ _optionalChain([this, 'access', _206 => _206.onDocumentChange, 'optionalCall', _207 => _207(this.document)]);
2401
2782
  }
2402
2783
  }, _class3);
2403
2784
  function stepInOrder(order, from, delta) {
@@ -2412,6 +2793,17 @@ function stepInOrder(order, from, delta) {
2412
2793
  }
2413
2794
 
2414
2795
  // src/spreadsheet/menu.ts
2796
+ function clampMenuPosition(point, size, viewport, margin = 4) {
2797
+ const place = (start, length, limit) => {
2798
+ if (start + length <= limit - margin) return Math.max(margin, start);
2799
+ const flipped = start - length;
2800
+ return Math.max(margin, flipped >= margin ? flipped : limit - margin - length);
2801
+ };
2802
+ return {
2803
+ x: place(point.x, size.width, viewport.width),
2804
+ y: place(point.y, size.height, viewport.height)
2805
+ };
2806
+ }
2415
2807
  var quote = (value) => {
2416
2808
  const text = String(_nullishCoalesce(value, () => ( "")));
2417
2809
  return text.length > 24 ? `"${text.slice(0, 23)}\u2026"` : `"${text}"`;
@@ -2422,8 +2814,9 @@ function getSpreadsheetMenuItems(controller, cell) {
2422
2814
  const row = doc.rows[cell.row];
2423
2815
  if (!column || !row) return [];
2424
2816
  const selection = controller.selectedRange && rangeContains(controller.selectedRange, cell.row, cell.col) ? normalizeRange(controller.selectedRange) : { startRow: cell.row, startCol: cell.col, endRow: cell.row, endCol: cell.col };
2425
- const colName = _chunkJYRIOFENcjs.indexToColName.call(void 0, cell.col);
2426
- const value = controller.getCell(row.id, column.id).value;
2817
+ const colName = _chunkRIKBJLS2cjs.indexToColName.call(void 0, cell.col);
2818
+ const cellData = controller.getCell(row.id, column.id);
2819
+ const value = cellData.value;
2427
2820
  const table = _nullishCoalesce(doc.table, () => ( {}));
2428
2821
  const filter = controller.getFilterState();
2429
2822
  const grouping = table.grouping;
@@ -2445,7 +2838,7 @@ function getSpreadsheetMenuItems(controller, cell) {
2445
2838
  },
2446
2839
  {
2447
2840
  id: "filter-equals",
2448
- label: `Show only rows where ${colName} = ${quote(value)}`,
2841
+ label: `Show only rows where ${colName} = ${quote(_chunkRIKBJLS2cjs.formatCellDisplay.call(void 0, cellData))}`,
2449
2842
  separatorBefore: true,
2450
2843
  run: () => controller.addFilterRule({ colId: column.id, operator: "equals", value: String(_nullishCoalesce(value, () => ( ""))) })
2451
2844
  },
@@ -2702,5 +3095,6 @@ async function importFileIntoSpreadsheet(controller, input, options) {
2702
3095
 
2703
3096
 
2704
3097
 
2705
- exports.columnDependencyKey = columnDependencyKey; exports.extractCellDependencies = extractCellDependencies; exports.DependencyGraph = DependencyGraph; exports.shiftFormulaReferences = shiftFormulaReferences; exports.mapFormulaReferences = mapFormulaReferences; exports.offsetFormulaReferences = offsetFormulaReferences; exports.remapFormulaReferences = remapFormulaReferences; exports.getFormulaCaretContext = getFormulaCaretContext; exports.getFormulaHints = getFormulaHints; exports.applyFormulaSuggestion = applyFormulaSuggestion; exports.DataSourceBinder = DataSourceBinder; exports.normalizeRange = normalizeRange; exports.rangeContains = rangeContains; exports.rangesIntersect = rangesIntersect; exports.rangeContainsRange = rangeContainsRange; exports.isSingleCellRange = isSingleCellRange; exports.isBlankValue = isBlankValue; exports.toNumber = toNumber; exports.compareCellValues = compareCellValues; exports.matchesFilterRule = matchesFilterRule; exports.aggregateValues = aggregateValues; exports.roundFloat = roundFloat; exports.fillSeries = fillSeries; exports.computeFillTarget = computeFillTarget; exports.getFillDirection = getFillDirection; exports.parseCsv = parseCsv; exports.escapeCsvField = escapeCsvField; exports.serializeCsv = serializeCsv; exports.parseTsv = parseTsv; exports.serializeTsv = serializeTsv; exports.SPREADSHEET_CLIPBOARD_MIME = SPREADSHEET_CLIPBOARD_MIME; exports.serializeHtmlTable = serializeHtmlTable; exports.parseHtmlTable = parseHtmlTable; exports.createSpreadsheetClipboardData = createSpreadsheetClipboardData; exports.readSpreadsheetClipboard = readSpreadsheetClipboard; exports.rebaseClipboardRows = rebaseClipboardRows; exports.DEFAULT_ROW_HEIGHT = DEFAULT_ROW_HEIGHT; exports.DEFAULT_COLUMN_WIDTH = DEFAULT_COLUMN_WIDTH; exports.getTableSections = getTableSections; exports.getRowSection = getRowSection; exports.rowPassesFilters = rowPassesFilters; exports.computeRowGroups = computeRowGroups; exports.buildSpreadsheetView = buildSpreadsheetView; exports.SpreadsheetController = SpreadsheetController; exports.getSpreadsheetMenuItems = getSpreadsheetMenuItems; exports.SPREADSHEET_TABLE_ACTIONS = SPREADSHEET_TABLE_ACTIONS; exports.bindSpreadsheetTableActions = bindSpreadsheetTableActions; exports.csvImportAdapter = csvImportAdapter; exports.tsvImportAdapter = tsvImportAdapter; exports.SPREADSHEET_IMPORT_ADAPTERS = SPREADSHEET_IMPORT_ADAPTERS; exports.registerSpreadsheetImportAdapters = registerSpreadsheetImportAdapters; exports.importFileIntoSpreadsheet = importFileIntoSpreadsheet;
2706
- //# sourceMappingURL=chunk-U6NDQFOK.cjs.map
3098
+
3099
+ exports.columnDependencyKey = columnDependencyKey; exports.extractCellDependencies = extractCellDependencies; exports.DependencyGraph = DependencyGraph; exports.shiftFormulaReferences = shiftFormulaReferences; exports.mapFormulaReferences = mapFormulaReferences; exports.offsetFormulaReferences = offsetFormulaReferences; exports.remapFormulaReferences = remapFormulaReferences; exports.getFormulaCaretContext = getFormulaCaretContext; exports.getFormulaHints = getFormulaHints; exports.applyFormulaSuggestion = applyFormulaSuggestion; exports.DataSourceBinder = DataSourceBinder; exports.normalizeRange = normalizeRange; exports.rangeContains = rangeContains; exports.rangesIntersect = rangesIntersect; exports.rangeContainsRange = rangeContainsRange; exports.isSingleCellRange = isSingleCellRange; exports.isBlankValue = isBlankValue; exports.toNumber = toNumber; exports.compareCellValues = compareCellValues; exports.matchesFilterRule = matchesFilterRule; exports.aggregateValues = aggregateValues; exports.roundFloat = roundFloat; exports.fillSeries = fillSeries; exports.computeFillTarget = computeFillTarget; exports.getFillDirection = getFillDirection; exports.parseCsv = parseCsv; exports.escapeCsvField = escapeCsvField; exports.serializeCsv = serializeCsv; exports.parseTsv = parseTsv; exports.serializeTsv = serializeTsv; exports.SPREADSHEET_CLIPBOARD_MIME = SPREADSHEET_CLIPBOARD_MIME; exports.serializeHtmlTable = serializeHtmlTable; exports.parseHtmlTable = parseHtmlTable; exports.createSpreadsheetClipboardData = createSpreadsheetClipboardData; exports.readSpreadsheetClipboard = readSpreadsheetClipboard; exports.rebaseClipboardRows = rebaseClipboardRows; exports.DEFAULT_ROW_HEIGHT = DEFAULT_ROW_HEIGHT; exports.DEFAULT_COLUMN_WIDTH = DEFAULT_COLUMN_WIDTH; exports.getTableSections = getTableSections; exports.getRowSection = getRowSection; exports.rowPassesFilters = rowPassesFilters; exports.computeRowGroups = computeRowGroups; exports.buildSpreadsheetView = buildSpreadsheetView; exports.SpreadsheetController = SpreadsheetController; exports.clampMenuPosition = clampMenuPosition; exports.getSpreadsheetMenuItems = getSpreadsheetMenuItems; exports.SPREADSHEET_TABLE_ACTIONS = SPREADSHEET_TABLE_ACTIONS; exports.bindSpreadsheetTableActions = bindSpreadsheetTableActions; exports.csvImportAdapter = csvImportAdapter; exports.tsvImportAdapter = tsvImportAdapter; exports.SPREADSHEET_IMPORT_ADAPTERS = SPREADSHEET_IMPORT_ADAPTERS; exports.registerSpreadsheetImportAdapters = registerSpreadsheetImportAdapters; exports.importFileIntoSpreadsheet = importFileIntoSpreadsheet;
3100
+ //# sourceMappingURL=chunk-XDMXXC4Z.cjs.map