@rowsncolumns/spreadsheet-state 29.1.4 → 29.1.7

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 (225) hide show
  1. package/dist/cjs/api/circular-reference.d.ts +31 -0
  2. package/dist/cjs/api/circular-reference.d.ts.map +1 -0
  3. package/dist/cjs/api/circular-reference.js +85 -0
  4. package/dist/cjs/api/copy-paste.d.ts +6 -0
  5. package/dist/cjs/api/copy-paste.d.ts.map +1 -1
  6. package/dist/cjs/api/copy-paste.js +24 -15
  7. package/dist/cjs/api/datatype.d.ts +2 -0
  8. package/dist/cjs/api/datatype.d.ts.map +1 -1
  9. package/dist/cjs/api/datatype.js +61 -35
  10. package/dist/cjs/api/date.d.ts.map +1 -1
  11. package/dist/cjs/api/date.js +23 -14
  12. package/dist/cjs/api/decimals.d.ts +10 -0
  13. package/dist/cjs/api/decimals.d.ts.map +1 -1
  14. package/dist/cjs/api/decimals.js +34 -11
  15. package/dist/cjs/api/dependency.d.ts +19 -1
  16. package/dist/cjs/api/dependency.d.ts.map +1 -1
  17. package/dist/cjs/api/dependency.js +30 -14
  18. package/dist/cjs/api/filter-condition.d.ts +58 -0
  19. package/dist/cjs/api/filter-condition.d.ts.map +1 -0
  20. package/dist/cjs/api/filter-condition.js +157 -0
  21. package/dist/cjs/api/formula.d.ts.map +1 -1
  22. package/dist/cjs/api/formula.js +9 -7
  23. package/dist/cjs/api/image-embed.d.ts +41 -0
  24. package/dist/cjs/api/image-embed.d.ts.map +1 -0
  25. package/dist/cjs/api/image-embed.js +55 -0
  26. package/dist/cjs/api/immer-utils.d.ts.map +1 -1
  27. package/dist/cjs/api/immer-utils.js +43 -15
  28. package/dist/cjs/api/named-range-structural.d.ts +29 -3
  29. package/dist/cjs/api/named-range-structural.d.ts.map +1 -1
  30. package/dist/cjs/api/named-range-structural.js +36 -11
  31. package/dist/cjs/api/parse-html.d.ts.map +1 -1
  32. package/dist/cjs/api/parse-html.js +11 -5
  33. package/dist/cjs/api/structural-formula-update.d.ts +20 -1
  34. package/dist/cjs/api/structural-formula-update.d.ts.map +1 -1
  35. package/dist/cjs/api/structural-formula-update.js +264 -90
  36. package/dist/cjs/api/structural-guards.d.ts +11 -0
  37. package/dist/cjs/api/structural-guards.d.ts.map +1 -1
  38. package/dist/cjs/api/structural-guards.js +45 -1
  39. package/dist/cjs/api/structural-table-refs.d.ts +15 -2
  40. package/dist/cjs/api/structural-table-refs.d.ts.map +1 -1
  41. package/dist/cjs/api/structural-table-refs.js +79 -35
  42. package/dist/cjs/commands.d.ts +17 -3
  43. package/dist/cjs/commands.d.ts.map +1 -1
  44. package/dist/cjs/components/editors/conditional-format-rule-editor.d.ts.map +1 -1
  45. package/dist/cjs/components/editors/conditional-format-rule-editor.js +19 -7
  46. package/dist/cjs/constants.d.ts +4 -1
  47. package/dist/cjs/constants.d.ts.map +1 -1
  48. package/dist/cjs/constants.js +4 -0
  49. package/dist/cjs/helpers/sheet-title.d.ts +2 -1
  50. package/dist/cjs/helpers/sheet-title.d.ts.map +1 -1
  51. package/dist/cjs/helpers/sheet-title.js +3 -1
  52. package/dist/cjs/hooks/use-can-edit-cellrange.d.ts +1 -1
  53. package/dist/cjs/hooks/use-can-edit-cellrange.d.ts.map +1 -1
  54. package/dist/cjs/hooks/use-can-edit-cellrange.js +1 -1
  55. package/dist/cjs/hooks/use-on-calculation-success.d.ts +5 -1
  56. package/dist/cjs/hooks/use-on-calculation-success.d.ts.map +1 -1
  57. package/dist/cjs/hooks/use-on-calculation-success.js +20 -3
  58. package/dist/cjs/hooks/use-on-copy.d.ts.map +1 -1
  59. package/dist/cjs/hooks/use-on-copy.js +23 -25
  60. package/dist/cjs/hooks/use-on-create-sheet.d.ts.map +1 -1
  61. package/dist/cjs/hooks/use-on-create-sheet.js +11 -1
  62. package/dist/cjs/hooks/use-on-delete.d.ts.map +1 -1
  63. package/dist/cjs/hooks/use-on-delete.js +15 -3
  64. package/dist/cjs/hooks/use-on-drag-n-drop.d.ts +5 -0
  65. package/dist/cjs/hooks/use-on-drag-n-drop.d.ts.map +1 -1
  66. package/dist/cjs/hooks/use-on-drag-n-drop.js +6 -5
  67. package/dist/cjs/hooks/use-on-filter-table.d.ts.map +1 -1
  68. package/dist/cjs/hooks/use-on-filter-table.js +6 -1
  69. package/dist/cjs/hooks/use-on-find-replace.d.ts.map +1 -1
  70. package/dist/cjs/hooks/use-on-find-replace.js +111 -23
  71. package/dist/cjs/hooks/use-on-insert-image.d.ts.map +1 -1
  72. package/dist/cjs/hooks/use-on-insert-image.js +20 -33
  73. package/dist/cjs/hooks/use-on-paste.d.ts +2 -1
  74. package/dist/cjs/hooks/use-on-paste.d.ts.map +1 -1
  75. package/dist/cjs/hooks/use-on-paste.js +53 -24
  76. package/dist/cjs/hooks/use-on-rename-sheet.d.ts +3 -1
  77. package/dist/cjs/hooks/use-on-rename-sheet.d.ts.map +1 -1
  78. package/dist/cjs/hooks/use-on-rename-sheet.js +19 -9
  79. package/dist/cjs/hooks/use-on-sort-column.d.ts +7 -1
  80. package/dist/cjs/hooks/use-on-sort-column.d.ts.map +1 -1
  81. package/dist/cjs/hooks/use-on-sort-column.js +25 -8
  82. package/dist/cjs/hooks/use-on-sort-range.d.ts +16 -2
  83. package/dist/cjs/hooks/use-on-sort-range.d.ts.map +1 -1
  84. package/dist/cjs/hooks/use-on-sort-range.js +72 -40
  85. package/dist/cjs/hooks/use-on-sort-table.d.ts +7 -2
  86. package/dist/cjs/hooks/use-on-sort-table.d.ts.map +1 -1
  87. package/dist/cjs/hooks/use-on-sort-table.js +25 -4
  88. package/dist/cjs/hooks/use-spreadsheet-state.d.ts +5 -3
  89. package/dist/cjs/hooks/use-spreadsheet-state.d.ts.map +1 -1
  90. package/dist/cjs/hooks/use-spreadsheet-state.js +7 -0
  91. package/dist/cjs/hooks/utils/sort-rows.d.ts +15 -0
  92. package/dist/cjs/hooks/utils/sort-rows.d.ts.map +1 -1
  93. package/dist/cjs/hooks/utils/sort-rows.js +16 -0
  94. package/dist/cjs/index.d.ts +3 -0
  95. package/dist/cjs/index.d.ts.map +1 -1
  96. package/dist/cjs/index.js +3 -0
  97. package/dist/cjs/interface/delete-column.d.ts.map +1 -1
  98. package/dist/cjs/interface/delete-column.js +254 -101
  99. package/dist/cjs/interface/delete-row.d.ts.map +1 -1
  100. package/dist/cjs/interface/delete-row.js +233 -81
  101. package/dist/cjs/interface/duplicate-sheet.d.ts.map +1 -1
  102. package/dist/cjs/interface/duplicate-sheet.js +4 -9
  103. package/dist/cjs/interface/insert-column.d.ts.map +1 -1
  104. package/dist/cjs/interface/insert-column.js +1 -1
  105. package/dist/cjs/interface/insert-row.d.ts.map +1 -1
  106. package/dist/cjs/interface/insert-row.js +1 -1
  107. package/dist/cjs/interface/new-sheet.d.ts.map +1 -1
  108. package/dist/cjs/interface/new-sheet.js +6 -13
  109. package/dist/cjs/sheet-cell.d.ts +9 -0
  110. package/dist/cjs/sheet-cell.d.ts.map +1 -1
  111. package/dist/cjs/sheet-cell.js +46 -9
  112. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  113. package/dist/esm/api/circular-reference.d.ts +31 -0
  114. package/dist/esm/api/circular-reference.d.ts.map +1 -0
  115. package/dist/esm/api/circular-reference.js +55 -0
  116. package/dist/esm/api/copy-paste.d.ts +6 -0
  117. package/dist/esm/api/copy-paste.d.ts.map +1 -1
  118. package/dist/esm/api/copy-paste.js +26 -14
  119. package/dist/esm/api/datatype.d.ts +2 -0
  120. package/dist/esm/api/datatype.d.ts.map +1 -1
  121. package/dist/esm/api/datatype.js +61 -35
  122. package/dist/esm/api/date.d.ts.map +1 -1
  123. package/dist/esm/api/date.js +23 -14
  124. package/dist/esm/api/decimals.d.ts +10 -0
  125. package/dist/esm/api/decimals.d.ts.map +1 -1
  126. package/dist/esm/api/decimals.js +31 -10
  127. package/dist/esm/api/dependency.d.ts +19 -1
  128. package/dist/esm/api/dependency.d.ts.map +1 -1
  129. package/dist/esm/api/dependency.js +15 -10
  130. package/dist/esm/api/filter-condition.d.ts +58 -0
  131. package/dist/esm/api/filter-condition.d.ts.map +1 -0
  132. package/dist/esm/api/filter-condition.js +146 -0
  133. package/dist/esm/api/formula.d.ts.map +1 -1
  134. package/dist/esm/api/formula.js +9 -7
  135. package/dist/esm/api/image-embed.d.ts +41 -0
  136. package/dist/esm/api/image-embed.d.ts.map +1 -0
  137. package/dist/esm/api/image-embed.js +52 -0
  138. package/dist/esm/api/immer-utils.d.ts.map +1 -1
  139. package/dist/esm/api/immer-utils.js +43 -14
  140. package/dist/esm/api/named-range-structural.d.ts +29 -3
  141. package/dist/esm/api/named-range-structural.d.ts.map +1 -1
  142. package/dist/esm/api/named-range-structural.js +35 -11
  143. package/dist/esm/api/parse-html.d.ts.map +1 -1
  144. package/dist/esm/api/parse-html.js +14 -5
  145. package/dist/esm/api/structural-formula-update.d.ts +20 -1
  146. package/dist/esm/api/structural-formula-update.d.ts.map +1 -1
  147. package/dist/esm/api/structural-formula-update.js +151 -55
  148. package/dist/esm/api/structural-guards.d.ts +11 -0
  149. package/dist/esm/api/structural-guards.d.ts.map +1 -1
  150. package/dist/esm/api/structural-guards.js +31 -0
  151. package/dist/esm/api/structural-table-refs.d.ts +15 -2
  152. package/dist/esm/api/structural-table-refs.d.ts.map +1 -1
  153. package/dist/esm/api/structural-table-refs.js +49 -18
  154. package/dist/esm/commands.d.ts +17 -3
  155. package/dist/esm/commands.d.ts.map +1 -1
  156. package/dist/esm/components/editors/conditional-format-rule-editor.d.ts.map +1 -1
  157. package/dist/esm/components/editors/conditional-format-rule-editor.js +18 -7
  158. package/dist/esm/constants.d.ts +4 -1
  159. package/dist/esm/constants.d.ts.map +1 -1
  160. package/dist/esm/constants.js +4 -0
  161. package/dist/esm/helpers/sheet-title.d.ts +2 -1
  162. package/dist/esm/helpers/sheet-title.d.ts.map +1 -1
  163. package/dist/esm/helpers/sheet-title.js +3 -1
  164. package/dist/esm/hooks/use-can-edit-cellrange.d.ts +1 -1
  165. package/dist/esm/hooks/use-can-edit-cellrange.d.ts.map +1 -1
  166. package/dist/esm/hooks/use-can-edit-cellrange.js +1 -1
  167. package/dist/esm/hooks/use-on-calculation-success.d.ts +5 -1
  168. package/dist/esm/hooks/use-on-calculation-success.d.ts.map +1 -1
  169. package/dist/esm/hooks/use-on-calculation-success.js +19 -3
  170. package/dist/esm/hooks/use-on-copy.d.ts.map +1 -1
  171. package/dist/esm/hooks/use-on-copy.js +17 -17
  172. package/dist/esm/hooks/use-on-create-sheet.d.ts.map +1 -1
  173. package/dist/esm/hooks/use-on-create-sheet.js +11 -1
  174. package/dist/esm/hooks/use-on-delete.d.ts.map +1 -1
  175. package/dist/esm/hooks/use-on-delete.js +15 -3
  176. package/dist/esm/hooks/use-on-drag-n-drop.d.ts +5 -0
  177. package/dist/esm/hooks/use-on-drag-n-drop.d.ts.map +1 -1
  178. package/dist/esm/hooks/use-on-drag-n-drop.js +7 -4
  179. package/dist/esm/hooks/use-on-filter-table.d.ts.map +1 -1
  180. package/dist/esm/hooks/use-on-filter-table.js +13 -2
  181. package/dist/esm/hooks/use-on-find-replace.d.ts.map +1 -1
  182. package/dist/esm/hooks/use-on-find-replace.js +111 -23
  183. package/dist/esm/hooks/use-on-insert-image.d.ts.map +1 -1
  184. package/dist/esm/hooks/use-on-insert-image.js +15 -25
  185. package/dist/esm/hooks/use-on-paste.d.ts +2 -1
  186. package/dist/esm/hooks/use-on-paste.d.ts.map +1 -1
  187. package/dist/esm/hooks/use-on-paste.js +46 -15
  188. package/dist/esm/hooks/use-on-rename-sheet.d.ts +3 -1
  189. package/dist/esm/hooks/use-on-rename-sheet.d.ts.map +1 -1
  190. package/dist/esm/hooks/use-on-rename-sheet.js +19 -9
  191. package/dist/esm/hooks/use-on-sort-column.d.ts +7 -1
  192. package/dist/esm/hooks/use-on-sort-column.d.ts.map +1 -1
  193. package/dist/esm/hooks/use-on-sort-column.js +18 -1
  194. package/dist/esm/hooks/use-on-sort-range.d.ts +16 -2
  195. package/dist/esm/hooks/use-on-sort-range.d.ts.map +1 -1
  196. package/dist/esm/hooks/use-on-sort-range.js +30 -3
  197. package/dist/esm/hooks/use-on-sort-table.d.ts +7 -2
  198. package/dist/esm/hooks/use-on-sort-table.d.ts.map +1 -1
  199. package/dist/esm/hooks/use-on-sort-table.js +25 -4
  200. package/dist/esm/hooks/use-spreadsheet-state.d.ts +5 -3
  201. package/dist/esm/hooks/use-spreadsheet-state.d.ts.map +1 -1
  202. package/dist/esm/hooks/use-spreadsheet-state.js +7 -0
  203. package/dist/esm/hooks/utils/sort-rows.d.ts +15 -0
  204. package/dist/esm/hooks/utils/sort-rows.d.ts.map +1 -1
  205. package/dist/esm/hooks/utils/sort-rows.js +15 -0
  206. package/dist/esm/index.d.ts +3 -0
  207. package/dist/esm/index.d.ts.map +1 -1
  208. package/dist/esm/index.js +3 -0
  209. package/dist/esm/interface/delete-column.d.ts.map +1 -1
  210. package/dist/esm/interface/delete-column.js +111 -80
  211. package/dist/esm/interface/delete-row.d.ts.map +1 -1
  212. package/dist/esm/interface/delete-row.js +91 -59
  213. package/dist/esm/interface/duplicate-sheet.d.ts.map +1 -1
  214. package/dist/esm/interface/duplicate-sheet.js +4 -9
  215. package/dist/esm/interface/insert-column.d.ts.map +1 -1
  216. package/dist/esm/interface/insert-column.js +1 -1
  217. package/dist/esm/interface/insert-row.d.ts.map +1 -1
  218. package/dist/esm/interface/insert-row.js +1 -1
  219. package/dist/esm/interface/new-sheet.d.ts.map +1 -1
  220. package/dist/esm/interface/new-sheet.js +6 -13
  221. package/dist/esm/sheet-cell.d.ts +9 -0
  222. package/dist/esm/sheet-cell.d.ts.map +1 -1
  223. package/dist/esm/sheet-cell.js +46 -7
  224. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  225. package/package.json +9 -9
@@ -32,12 +32,77 @@ import { createSheetDraft } from "./immer-utils";
32
32
  * and 3 don't double-process a cell.
33
33
  */
34
34
  export const updateFormulasForStructuralChange = (params) => {
35
- const { draft, axis, op, sheetId, referenceIndex, count, rowCount, columnCount, getDependents, getGraphNodes, getGraphNodesInSheet, getSheetName, enqueueCalculation, enqueueGraphOperation, recalcCells, locale, cellXfsRegistry, sharedStringRegistry, } = params;
35
+ const { draft, axis, op, sheetId, referenceIndex, count, indexes, rowCount, columnCount, getDependents, getGraphNodes, getGraphNodesInSheet, getSheetName, enqueueCalculation, enqueueGraphOperation, recalcCells, locale, cellXfsRegistry, sharedStringRegistry, } = params;
36
36
  if (count <= 0)
37
37
  return;
38
38
  const isRow = axis === "row";
39
39
  const isInsert = op === "insert";
40
40
  const delta = isInsert ? count : -count;
41
+ // The deleted bands, as contiguous runs. A contiguous delete (or an insert)
42
+ // is the single run at `referenceIndex`; a Ctrl-selected delete has one run
43
+ // per island. Rewrites apply the runs from the LAST to the first: a run's
44
+ // references then sit in their original coordinates when its turn comes
45
+ // (only lines beyond it have moved, and they stay beyond it).
46
+ const runs = !isInsert && indexes?.length
47
+ ? contiguousRuns(indexes)
48
+ : [{ start: referenceIndex, count }];
49
+ const runsDescending = [...runs].sort((a, b) => b.start - a.start);
50
+ const deletedIndexes = new Set();
51
+ for (const run of runs) {
52
+ for (let i = 0; i < run.count; i++)
53
+ deletedIndexes.add(run.start + i);
54
+ }
55
+ const sortedDeleted = [...deletedIndexes].sort((a, b) => a - b);
56
+ /** Where a line at `index` on the edited sheet ends up after the splice. */
57
+ const finalIndex = (index) => {
58
+ if (isInsert)
59
+ return index >= referenceIndex ? index + count : index;
60
+ let before = 0;
61
+ for (const deleted of sortedDeleted) {
62
+ if (deleted >= index)
63
+ break;
64
+ before++;
65
+ }
66
+ return index - before;
67
+ };
68
+ const finalPosition = (pos) => pos.sheetId !== sheetId
69
+ ? pos
70
+ : isRow
71
+ ? { ...pos, rowIndex: finalIndex(pos.rowIndex) }
72
+ : { ...pos, columnIndex: finalIndex(pos.columnIndex) };
73
+ const bandRange = (start, size) => isRow
74
+ ? {
75
+ startRowIndex: start,
76
+ endRowIndex: start + size - 1,
77
+ startColumnIndex: 1,
78
+ endColumnIndex: columnCount,
79
+ }
80
+ : {
81
+ startRowIndex: 1,
82
+ endRowIndex: rowCount,
83
+ startColumnIndex: start,
84
+ endColumnIndex: start + size - 1,
85
+ };
86
+ const tailRange = (from) => isRow
87
+ ? {
88
+ startRowIndex: from,
89
+ endRowIndex: rowCount,
90
+ startColumnIndex: 1,
91
+ endColumnIndex: columnCount,
92
+ }
93
+ : {
94
+ startRowIndex: 1,
95
+ endRowIndex: rowCount,
96
+ startColumnIndex: from,
97
+ endColumnIndex: columnCount,
98
+ };
99
+ // One reference shift per run, last run first (see `runs`).
100
+ const steps = runsDescending.map((run) => ({
101
+ rowDelta: isRow ? (isInsert ? run.count : -run.count) : 0,
102
+ columnDelta: isRow ? 0 : isInsert ? run.count : -run.count,
103
+ sourceRange: tailRange(isInsert ? run.start : run.start + run.count),
104
+ deletedRange: isInsert ? undefined : bandRange(run.start, run.count),
105
+ }));
41
106
  // The set of cells that ARE moving (Pass 3 target region). For both
42
107
  // insert and delete, this is everything from the reference index along
43
108
  // the affected axis; the splice happens after the formula updates.
@@ -72,32 +137,29 @@ export const updateFormulasForStructuralChange = (params) => {
72
137
  };
73
138
  // Pass 2's source range — the cells that will move under the splice.
74
139
  // For insert this is everything at-or-after the insertion point; for
75
- // delete this is everything strictly after the deleted block.
76
- const pass2SourceRange = isRow
77
- ? {
78
- startRowIndex: isInsert ? referenceIndex : referenceIndex + count,
79
- endRowIndex: rowCount,
80
- startColumnIndex: 1,
81
- endColumnIndex: columnCount,
82
- }
83
- : {
84
- startRowIndex: 1,
85
- endRowIndex: rowCount,
86
- startColumnIndex: isInsert ? referenceIndex : referenceIndex + count,
87
- endColumnIndex: columnCount,
88
- };
140
+ // delete this is everything strictly after the FIRST deleted band (a line
141
+ // between two bands of a Ctrl-selected delete moves too — by the bands
142
+ // before it — so its dependents must be collected).
143
+ const pass2SourceRange = tailRange(isInsert ? referenceIndex : runs[0].start + runs[0].count);
89
144
  // The cells a delete removes: any reference into them (that Pass 1 did not
90
145
  // already contract) is broken to `#REF!` instead of sliding onto the cell
91
146
  // that moves into its place.
92
147
  const deletedRange = isInsert ? undefined : pass1Range;
93
148
  const editedSheetName = getSheetName(sheetId);
94
149
  // ---- PASS 1 ----
95
- const pass1Formulas = collectUniqueDependentsForRange({
96
- draft,
97
- sheetId,
98
- sourceRange: pass1Range,
99
- getDependents,
100
- });
150
+ // Dependents of every deleted band (the single band for an insert).
151
+ const pass1Formulas = new Map();
152
+ for (const run of runs) {
153
+ for (const [key, pos] of collectUniqueDependentsForRange({
154
+ draft,
155
+ sheetId,
156
+ sourceRange: isInsert ? pass1Range : bandRange(run.start, run.count),
157
+ getDependents,
158
+ })) {
159
+ if (!pass1Formulas.has(key))
160
+ pass1Formulas.set(key, pos);
161
+ }
162
+ }
101
163
  if (pass1Formulas.size > 0) {
102
164
  const sheetCell = new SheetCell();
103
165
  for (const pos of pass1Formulas.values()) {
@@ -115,34 +177,28 @@ export const updateFormulasForStructuralChange = (params) => {
115
177
  const rangeOptions = {
116
178
  includeUnqualifiedReferences: pos.sheetId === sheetId,
117
179
  };
118
- const updatedFormula = isInsert
119
- ? expandRangesInFormula(formulaValue, referenceIndex, count, axis, editedSheetName, rangeOptions)
120
- : contractRangesInFormula(formulaValue, referenceIndex, count, axis, editedSheetName, rangeOptions);
180
+ let updatedFormula = formulaValue;
181
+ if (isInsert) {
182
+ updatedFormula = expandRangesInFormula(formulaValue, referenceIndex, count, axis, editedSheetName, rangeOptions);
183
+ }
184
+ else {
185
+ // Contract for each deleted band, last band first: a range spanning
186
+ // rows 2 and 4 loses row 4 (`A1:A5` → `A1:A4`), then row 2 (→ `A1:A3`).
187
+ for (const run of runsDescending) {
188
+ if (!updatedFormula)
189
+ break;
190
+ updatedFormula = contractRangesInFormula(updatedFormula, run.start, run.count, axis, editedSheetName, rangeOptions);
191
+ }
192
+ }
121
193
  if (!updatedFormula || updatedFormula === formulaValue)
122
194
  continue;
123
195
  sheetCell.setFormulaValue(updatedFormula, false);
124
196
  currentSheet[pos.rowIndex].values[pos.columnIndex] =
125
197
  sheetCell.getCellData();
126
198
  // Adjust the recalc position for cells that themselves shift in
127
- // the splice that follows. For insert: cells AT or after the
128
- // reference shift by +count along the axis. For delete: cells
129
- // STRICTLY after the deleted block shift by -count.
130
- const adjustedRowIndex = isRow
131
- ? pos.sheetId === sheetId &&
132
- (isInsert
133
- ? pos.rowIndex >= referenceIndex
134
- : pos.rowIndex >= referenceIndex + count)
135
- ? pos.rowIndex + delta
136
- : pos.rowIndex
137
- : pos.rowIndex;
138
- const adjustedColumnIndex = !isRow
139
- ? pos.sheetId === sheetId &&
140
- (isInsert
141
- ? pos.columnIndex >= referenceIndex
142
- : pos.columnIndex >= referenceIndex + count)
143
- ? pos.columnIndex + delta
144
- : pos.columnIndex
145
- : pos.columnIndex;
199
+ // the splice that follows: a cell on the edited sheet loses the deleted
200
+ // lines before it (or gains the inserted ones at or before it).
201
+ const { rowIndex: adjustedRowIndex, columnIndex: adjustedColumnIndex } = finalPosition(pos);
146
202
  enqueueCalculation?.({
147
203
  type: "add",
148
204
  position: {
@@ -184,6 +240,7 @@ export const updateFormulasForStructuralChange = (params) => {
184
240
  columnDelta,
185
241
  sourceRange: pass2SourceRange,
186
242
  deletedRange,
243
+ steps,
187
244
  locale,
188
245
  rowCount,
189
246
  columnCount,
@@ -204,6 +261,8 @@ export const updateFormulasForStructuralChange = (params) => {
204
261
  columnDelta,
205
262
  sourceRange: pass2SourceRange,
206
263
  deletedRange,
264
+ steps,
265
+ destinationPosition: finalPosition(pos),
207
266
  locale,
208
267
  rowCount,
209
268
  columnCount,
@@ -227,6 +286,7 @@ export const updateFormulasForStructuralChange = (params) => {
227
286
  columnDelta,
228
287
  sourceRange: pass2SourceRange,
229
288
  deletedRange,
289
+ steps,
230
290
  locale,
231
291
  rowCount,
232
292
  columnCount,
@@ -271,6 +331,12 @@ export const updateFormulasForStructuralChange = (params) => {
271
331
  columnDelta,
272
332
  sourceRange: pass2SourceRange,
273
333
  deletedRange,
334
+ steps,
335
+ destinationPosition: finalPosition({
336
+ sheetId,
337
+ rowIndex: pos.rowIndex,
338
+ columnIndex: pos.columnIndex,
339
+ }),
274
340
  locale,
275
341
  rowCount,
276
342
  columnCount,
@@ -309,6 +375,8 @@ export const updateFormulasForStructuralChange = (params) => {
309
375
  columnDelta,
310
376
  sourceRange: pass2SourceRange,
311
377
  deletedRange,
378
+ steps,
379
+ destinationPosition: finalPosition({ sheetId, rowIndex, columnIndex }),
312
380
  locale,
313
381
  rowCount,
314
382
  columnCount,
@@ -319,7 +387,27 @@ export const updateFormulasForStructuralChange = (params) => {
319
387
  }
320
388
  }
321
389
  };
322
- const shiftExternalDependentFormulaReferences = ({ draft, position, editedSheetName, enqueueCalculation, enqueueGraphOperation, recalcCells, movedKeys, rowDelta, columnDelta, sourceRange, deletedRange, locale, rowCount, columnCount, cellXfsRegistry, sharedStringRegistry, }) => {
390
+ /**
391
+ * The maximal contiguous runs of `indexes` (any order, duplicates ignored),
392
+ * ascending — the bands of a Ctrl-selected delete (rows 2 and 4 → two runs).
393
+ * Shared by `deleteRow` / `deleteColumn`, which apply every band-shaped update
394
+ * once per run.
395
+ */
396
+ export const contiguousRuns = (indexes) => {
397
+ const sorted = [...new Set(indexes)].sort((a, b) => a - b);
398
+ const runs = [];
399
+ for (const index of sorted) {
400
+ const last = runs[runs.length - 1];
401
+ if (last && last.start + last.count === index) {
402
+ last.count++;
403
+ }
404
+ else {
405
+ runs.push({ start: index, count: 1 });
406
+ }
407
+ }
408
+ return runs;
409
+ };
410
+ const shiftExternalDependentFormulaReferences = ({ draft, position, editedSheetName, enqueueCalculation, enqueueGraphOperation, recalcCells, movedKeys, rowDelta, columnDelta, sourceRange, deletedRange, steps, locale, rowCount, columnCount, cellXfsRegistry, sharedStringRegistry, }) => {
323
411
  const sheetCell = new SheetCell();
324
412
  const currentSheet = createSheetDraft(draft, position.sheetId, position.rowIndex);
325
413
  const cellData = currentSheet[position.rowIndex]?.values?.[position.columnIndex];
@@ -329,17 +417,25 @@ const shiftExternalDependentFormulaReferences = ({ draft, position, editedSheetN
329
417
  }
330
418
  movedKeys.add(sheetCell.key);
331
419
  const previousFormula = sheetCell.formula;
332
- const updatedFormula = formulaToRelativeReference(previousFormula, { rowIndex: position.rowIndex, columnIndex: position.columnIndex }, {
333
- rowIndex: position.rowIndex + rowDelta,
334
- columnIndex: position.columnIndex + columnDelta,
335
- }, editedSheetName, {
336
- exclusionRange: sourceRange,
337
- deletedRange,
338
- rowCount,
339
- columnCount,
340
- referenceSheetName: editedSheetName,
341
- includeUnqualifiedReferences: false,
342
- });
420
+ const moves = steps ?? [
421
+ { rowDelta, columnDelta, sourceRange, deletedRange },
422
+ ];
423
+ let updatedFormula = previousFormula;
424
+ for (const move of moves) {
425
+ if (!updatedFormula)
426
+ break;
427
+ updatedFormula = formulaToRelativeReference(updatedFormula, { rowIndex: position.rowIndex, columnIndex: position.columnIndex }, {
428
+ rowIndex: position.rowIndex + move.rowDelta,
429
+ columnIndex: position.columnIndex + move.columnDelta,
430
+ }, editedSheetName, {
431
+ exclusionRange: move.sourceRange,
432
+ deletedRange: move.deletedRange,
433
+ rowCount,
434
+ columnCount,
435
+ referenceSheetName: editedSheetName,
436
+ includeUnqualifiedReferences: false,
437
+ });
438
+ }
343
439
  if (!updatedFormula || updatedFormula === previousFormula) {
344
440
  return;
345
441
  }
@@ -132,4 +132,15 @@ export declare const getInsertLinesRefusal: <T extends CellData>({ axis, referen
132
132
  rows: SheetData<T>[number] | undefined;
133
133
  limit: number | undefined;
134
134
  }) => StructuralRefusal | undefined;
135
+ /**
136
+ * Excel's sort rule for merged cells: a sort may only reorder rows whose merge layout is identical —
137
+ * every merge touching the sorted range must lie wholly inside it, span a single row, and every row of
138
+ * the range must carry the same column spans. Otherwise the anchor values would move with their rows
139
+ * while the merge outlines stayed behind (stale merge geometry), so the sort is refused with Excel's
140
+ * "To do this, all the merged cells need to be the same size." Merges outside the range are untouched.
141
+ */
142
+ export declare const getSortMergeRefusal: ({ range, merges, }: {
143
+ range: GridRange;
144
+ merges: readonly GridRange[] | null | undefined;
145
+ }) => StructuralRefusal | undefined;
135
146
  //# sourceMappingURL=structural-guards.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"structural-guards.d.ts","sourceRoot":"","sources":["../../../api/structural-guards.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"structural-guards.d.ts","sourceRoot":"","sources":["../../../api/structural-guards.ts"],"names":[],"mappings":"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"}
@@ -269,3 +269,34 @@ export const getInsertLinesRefusal = ({ axis, referenceIndex, count, rows, limit
269
269
  ? structuralRefusal("off-sheet-push")
270
270
  : undefined;
271
271
  };
272
+ /**
273
+ * Excel's sort rule for merged cells: a sort may only reorder rows whose merge layout is identical —
274
+ * every merge touching the sorted range must lie wholly inside it, span a single row, and every row of
275
+ * the range must carry the same column spans. Otherwise the anchor values would move with their rows
276
+ * while the merge outlines stayed behind (stale merge geometry), so the sort is refused with Excel's
277
+ * "To do this, all the merged cells need to be the same size." Merges outside the range are untouched.
278
+ */
279
+ export const getSortMergeRefusal = ({ range, merges, }) => {
280
+ if (!merges?.length)
281
+ return undefined;
282
+ const touching = merges.filter((merge) => rangesIntersect(merge, range));
283
+ if (!touching.length)
284
+ return undefined;
285
+ const spansByRow = new Map();
286
+ for (const merge of touching) {
287
+ if (!rangeContains(range, merge) ||
288
+ merge.startRowIndex !== merge.endRowIndex) {
289
+ return structuralRefusal("sort-merged-cells");
290
+ }
291
+ const spans = spansByRow.get(merge.startRowIndex) ?? [];
292
+ spans.push(`${merge.startColumnIndex}:${merge.endColumnIndex}`);
293
+ spansByRow.set(merge.startRowIndex, spans);
294
+ }
295
+ const layoutOf = (rowIndex) => (spansByRow.get(rowIndex) ?? []).slice().sort().join(",");
296
+ const first = layoutOf(range.startRowIndex);
297
+ for (let r = range.startRowIndex + 1; r <= range.endRowIndex; r++) {
298
+ if (layoutOf(r) !== first)
299
+ return structuralRefusal("sort-merged-cells");
300
+ }
301
+ return undefined;
302
+ };
@@ -34,7 +34,14 @@ export type RemovedTableParts = {
34
34
  * `[minIndex, maxIndex]` on `sheetId`. Mirrors the table updates those
35
35
  * interfaces apply to `tables`.
36
36
  */
37
- export declare const collectRemovedTableParts: (tables: TableView[] | undefined, sheetId: number, axis: StructuralAxis, minIndex: number, maxIndex: number) => RemovedTableParts;
37
+ export declare const collectRemovedTableParts: (tables: TableView[] | undefined, sheetId: number, axis: StructuralAxis, minIndex: number, maxIndex: number,
38
+ /**
39
+ * The exact deleted indexes when the selection is not one contiguous band
40
+ * (Ctrl-selected rows 2 and 4): a table is removed only when EVERY one of
41
+ * its lines is deleted, and only the deleted columns are spliced out.
42
+ * Defaults to the band `[minIndex, maxIndex]`.
43
+ */
44
+ indexes?: number[]) => RemovedTableParts;
38
45
  export type BreakStructuredRefsParams<T extends CellData> = {
39
46
  draft: Draft<SheetData<T>>;
40
47
  /** The edited sheet. */
@@ -43,6 +50,12 @@ export type BreakStructuredRefsParams<T extends CellData> = {
43
50
  /** Smallest deleted index and the number of deleted rows/columns. */
44
51
  referenceIndex: number;
45
52
  count: number;
53
+ /**
54
+ * The exact deleted indexes of a non-contiguous delete (see
55
+ * `collectRemovedTableParts`); a formula cell then closes up by the deleted
56
+ * lines BEFORE it rather than by `count`.
57
+ */
58
+ indexes?: number[];
46
59
  removed: RemovedTableParts;
47
60
  getGraphNodes?: ReturnType<typeof useCalculation>["getGraphNodes"];
48
61
  enqueueCalculation?: ReturnType<typeof useCalculation>["enqueueCalculation"];
@@ -59,7 +72,7 @@ export type BreakStructuredRefsParams<T extends CellData> = {
59
72
  * formula's pre-edit position. Formula cells come from the dependency graph
60
73
  * when it is available (cost O(formula cells)); without one the draft is swept.
61
74
  */
62
- export declare const breakStructuredRefsForRemovedTableParts: <T extends CellData>({ draft, sheetId, axis, referenceIndex, count, removed, getGraphNodes, enqueueCalculation, enqueueGraphOperation, recalcCells, locale, cellXfsRegistry, sharedStringRegistry, }: BreakStructuredRefsParams<T>) => void;
75
+ export declare const breakStructuredRefsForRemovedTableParts: <T extends CellData>({ draft, sheetId, axis, referenceIndex, count, indexes, removed, getGraphNodes, enqueueCalculation, enqueueGraphOperation, recalcCells, locale, cellXfsRegistry, sharedStringRegistry, }: BreakStructuredRefsParams<T>) => void;
63
76
  export type RewriteFormulasParams<T extends CellData> = Pick<BreakStructuredRefsParams<T>, "draft" | "getGraphNodes" | "enqueueCalculation" | "enqueueGraphOperation" | "recalcCells" | "locale" | "cellXfsRegistry" | "sharedStringRegistry">;
64
77
  /**
65
78
  * Column `oldName` of `table` was renamed `newName` (a header-cell edit):
@@ -1 +1 @@
1
- {"version":3,"file":"structural-table-refs.d.ts","sourceRoot":"","sources":["../../../api/structural-table-refs.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"structural-table-refs.d.ts","sourceRoot":"","sources":["../../../api/structural-table-refs.ts"],"names":[],"mappings":"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"}
@@ -11,33 +11,51 @@ import { createSheetDraft } from "./immer-utils";
11
11
  * `[minIndex, maxIndex]` on `sheetId`. Mirrors the table updates those
12
12
  * interfaces apply to `tables`.
13
13
  */
14
- export const collectRemovedTableParts = (tables, sheetId, axis, minIndex, maxIndex) => {
14
+ export const collectRemovedTableParts = (tables, sheetId, axis, minIndex, maxIndex,
15
+ /**
16
+ * The exact deleted indexes when the selection is not one contiguous band
17
+ * (Ctrl-selected rows 2 and 4): a table is removed only when EVERY one of
18
+ * its lines is deleted, and only the deleted columns are spliced out.
19
+ * Defaults to the band `[minIndex, maxIndex]`.
20
+ */
21
+ indexes) => {
15
22
  const removed = { tables: [], columns: [] };
23
+ const deleted = new Set(indexes ?? []);
24
+ const isDeleted = (index) => indexes ? deleted.has(index) : index >= minIndex && index <= maxIndex;
16
25
  for (const table of tables ?? []) {
17
26
  if (table.sheetId !== sheetId || !table.title)
18
27
  continue;
19
28
  if (axis === "row") {
20
29
  const { startRowIndex, endRowIndex } = table.range;
21
- if (minIndex <= startRowIndex && maxIndex >= endRowIndex) {
22
- removed.tables.push(table.title);
30
+ let every = true;
31
+ for (let row = startRowIndex; row <= endRowIndex; row++) {
32
+ if (!isDeleted(row)) {
33
+ every = false;
34
+ break;
35
+ }
23
36
  }
37
+ if (every)
38
+ removed.tables.push(table.title);
24
39
  continue;
25
40
  }
26
41
  const { startColumnIndex, endColumnIndex } = table.range;
27
42
  if (maxIndex < startColumnIndex || minIndex > endColumnIndex)
28
43
  continue;
29
- if (minIndex <= startColumnIndex && maxIndex >= endColumnIndex) {
30
- removed.tables.push(table.title);
31
- continue;
32
- }
33
- const overlapStart = Math.max(minIndex, startColumnIndex);
34
- const overlapEnd = Math.min(maxIndex, endColumnIndex);
35
44
  const names = [];
36
- for (let column = overlapStart; column <= overlapEnd; column++) {
45
+ let every = true;
46
+ for (let column = startColumnIndex; column <= endColumnIndex; column++) {
47
+ if (!isDeleted(column)) {
48
+ every = false;
49
+ continue;
50
+ }
37
51
  const name = table.columns?.[column - startColumnIndex]?.name;
38
52
  if (name)
39
53
  names.push(name);
40
54
  }
55
+ if (every) {
56
+ removed.tables.push(table.title);
57
+ continue;
58
+ }
41
59
  if (names.length) {
42
60
  removed.columns.push({
43
61
  table: table.title,
@@ -61,12 +79,24 @@ const isWithinRange = (range, rowIndex, columnIndex) => rowIndex >= range.startR
61
79
  * formula's pre-edit position. Formula cells come from the dependency graph
62
80
  * when it is available (cost O(formula cells)); without one the draft is swept.
63
81
  */
64
- export const breakStructuredRefsForRemovedTableParts = ({ draft, sheetId, axis, referenceIndex, count, removed, getGraphNodes, enqueueCalculation, enqueueGraphOperation, recalcCells, locale, cellXfsRegistry, sharedStringRegistry, }) => {
82
+ export const breakStructuredRefsForRemovedTableParts = ({ draft, sheetId, axis, referenceIndex, count, indexes, removed, getGraphNodes, enqueueCalculation, enqueueGraphOperation, recalcCells, locale, cellXfsRegistry, sharedStringRegistry, }) => {
65
83
  if (isEmptyRemoval(removed))
66
84
  return;
67
85
  const sheetCell = new SheetCell();
68
86
  const isRow = axis === "row";
69
- const afterBand = referenceIndex + count;
87
+ const sortedDeleted = indexes
88
+ ? [...new Set(indexes)].sort((a, b) => a - b)
89
+ : Array.from({ length: count }, (_, i) => referenceIndex + i);
90
+ /** How many deleted lines lie strictly before `index`. */
91
+ const deletedBefore = (index) => {
92
+ let before = 0;
93
+ for (const deleted of sortedDeleted) {
94
+ if (deleted >= index)
95
+ break;
96
+ before++;
97
+ }
98
+ return before;
99
+ };
70
100
  for (const pos of collectFormulaPositions(draft, getGraphNodes)) {
71
101
  const currentSheet = createSheetDraft(draft, pos.sheetId, pos.rowIndex);
72
102
  const cellData = currentSheet[pos.rowIndex]?.values?.[pos.columnIndex];
@@ -91,14 +121,15 @@ export const breakStructuredRefsForRemovedTableParts = ({ draft, sheetId, axis,
91
121
  sheetCell.setFormulaValue(updated, false);
92
122
  currentSheet[pos.rowIndex].values[pos.columnIndex] =
93
123
  sheetCell.getCellData();
94
- // Where the cell ends up after the splice that follows (cells strictly
95
- // after the deleted band on the edited sheet close up by `count`).
96
- const shifts = pos.sheetId === sheetId &&
97
- (isRow ? pos.rowIndex : pos.columnIndex) >= afterBand;
124
+ // Where the cell ends up after the splice that follows (a cell on the
125
+ // edited sheet closes up by the deleted lines before it).
126
+ const shift = pos.sheetId === sheetId
127
+ ? deletedBefore(isRow ? pos.rowIndex : pos.columnIndex)
128
+ : 0;
98
129
  const nextPosition = {
99
130
  sheetId: pos.sheetId,
100
- rowIndex: pos.rowIndex - (shifts && isRow ? count : 0),
101
- columnIndex: pos.columnIndex - (shifts && !isRow ? count : 0),
131
+ rowIndex: pos.rowIndex - (isRow ? shift : 0),
132
+ columnIndex: pos.columnIndex - (isRow ? 0 : shift),
102
133
  };
103
134
  const enqueueOperation = sheetCell.ephemeral()
104
135
  ? enqueueCalculation
@@ -1,4 +1,4 @@
1
- import type { CellData, CellInterface, Citation, Color, Direction, GridRange, SelectionArea, SheetRange, SortOrder } from "@rowsncolumns/common-types";
1
+ import type { CellData, CellInterface, Citation, Color, Direction, ExtendedValue, GridRange, SelectionArea, SheetRange, SortOrder } from "@rowsncolumns/common-types";
2
2
  import type { AXIS, BandedDefinition, BandedRange, BorderLocation, BorderStyle, CellFormat, ColorFilterCriteria, ConditionalFormatRule, ConditionType, ConditionValue, DataValidationRuleRecord, EmbeddedChart, EmbeddedObject, FillModifier, FillSeriesSpec, FilterView, IconFilterCriteria, NamedRange, PivotTable, ProtectedRange, SelectionAttributes, Sheet, Slicer, SortSpecs, SpreadsheetTheme, CalculatedColumnPreviousCell, TableAutoExpansionWrites, TableTheme, TableView, TextFormatRun, BooleanCondition, FilterConditionJoin, CustomTableStyle } from "@rowsncolumns/spreadsheet";
3
3
  import type { AutoFillType } from "./api/fill";
4
4
  import type { ChangeBatchOptions } from "./interface/change-batch";
@@ -62,10 +62,18 @@ export type Command = {
62
62
  target: CellInterface;
63
63
  /** Source top-left of the copied range — relative formula refs shift by (target − source). */
64
64
  source: CellInterface;
65
- /** The copied rectangle, row-major. Each cell carries its user-entered value (formula text or a
66
- * literal, as a string) plus optional format and optional hyperlink target (a pasted link
65
+ /** The copied rectangle, row-major. Each cell carries its user-entered value (typed in `ue`,
66
+ * as a string in `value`) plus optional format and optional hyperlink target (a pasted link
67
67
  * stays clickable); `null` = a blank cell within the copied range. */
68
68
  cells: ({
69
+ /** The source cell's TYPED user-entered value (`{ sv }` / `{ nv }` / `{ bv }` / `{ fv }` /
70
+ * `{ ev }`, the `CellData.ue` shape). The engine lands it with that type — a text `0123`,
71
+ * `1/2`, `TRUE`, `1e3` or `=x` stays text, a number stays a number, a formula relocates
72
+ * like `value` — as Excel keeps each copied cell's stored type on copy / cut / paste-values.
73
+ * Absent → the engine infers `value` as if typed. */
74
+ ue?: ExtendedValue | null;
75
+ /** `ue` as a string (formula text or the literal) — the inference fallback for an engine
76
+ * build predating `ue`. */
69
77
  value: string | null;
70
78
  format?: CellFormat | null;
71
79
  hyperlink?: string | null;
@@ -396,6 +404,12 @@ export type Command = {
396
404
  } | {
397
405
  command: "sort-range";
398
406
  sheetId: number;
407
+ /**
408
+ * The cursor at sort time. Excel / Sheets key a one-click range sort on the
409
+ * column the active cell is in; absent (or outside the range's columns) the
410
+ * range's leftmost column keys the sort.
411
+ */
412
+ activeCell?: CellInterface;
399
413
  selections: SelectionArea<SelectionAttributes>[];
400
414
  sortOrder: SortOrder;
401
415
  } | {