@rowsncolumns/spreadsheet-state 29.1.3 → 29.1.6

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 (221) 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 +50 -27
  10. package/dist/cjs/api/decimals.d.ts +10 -0
  11. package/dist/cjs/api/decimals.d.ts.map +1 -1
  12. package/dist/cjs/api/decimals.js +34 -11
  13. package/dist/cjs/api/dependency.d.ts +19 -1
  14. package/dist/cjs/api/dependency.d.ts.map +1 -1
  15. package/dist/cjs/api/dependency.js +30 -14
  16. package/dist/cjs/api/filter-condition.d.ts +58 -0
  17. package/dist/cjs/api/filter-condition.d.ts.map +1 -0
  18. package/dist/cjs/api/filter-condition.js +157 -0
  19. package/dist/cjs/api/formula.d.ts.map +1 -1
  20. package/dist/cjs/api/formula.js +9 -7
  21. package/dist/cjs/api/image-embed.d.ts +41 -0
  22. package/dist/cjs/api/image-embed.d.ts.map +1 -0
  23. package/dist/cjs/api/image-embed.js +55 -0
  24. package/dist/cjs/api/immer-utils.d.ts.map +1 -1
  25. package/dist/cjs/api/immer-utils.js +43 -15
  26. package/dist/cjs/api/named-range-structural.d.ts +29 -3
  27. package/dist/cjs/api/named-range-structural.d.ts.map +1 -1
  28. package/dist/cjs/api/named-range-structural.js +36 -11
  29. package/dist/cjs/api/parse-html.d.ts.map +1 -1
  30. package/dist/cjs/api/parse-html.js +11 -5
  31. package/dist/cjs/api/structural-formula-update.d.ts +20 -1
  32. package/dist/cjs/api/structural-formula-update.d.ts.map +1 -1
  33. package/dist/cjs/api/structural-formula-update.js +264 -90
  34. package/dist/cjs/api/structural-guards.d.ts +11 -0
  35. package/dist/cjs/api/structural-guards.d.ts.map +1 -1
  36. package/dist/cjs/api/structural-guards.js +45 -1
  37. package/dist/cjs/api/structural-table-refs.d.ts +15 -2
  38. package/dist/cjs/api/structural-table-refs.d.ts.map +1 -1
  39. package/dist/cjs/api/structural-table-refs.js +79 -35
  40. package/dist/cjs/commands.d.ts +17 -3
  41. package/dist/cjs/commands.d.ts.map +1 -1
  42. package/dist/cjs/components/editors/conditional-format-rule-editor.d.ts.map +1 -1
  43. package/dist/cjs/components/editors/conditional-format-rule-editor.js +19 -7
  44. package/dist/cjs/constants.d.ts +4 -1
  45. package/dist/cjs/constants.d.ts.map +1 -1
  46. package/dist/cjs/constants.js +4 -0
  47. package/dist/cjs/helpers/sheet-title.d.ts +2 -1
  48. package/dist/cjs/helpers/sheet-title.d.ts.map +1 -1
  49. package/dist/cjs/helpers/sheet-title.js +3 -1
  50. package/dist/cjs/hooks/use-can-edit-cellrange.d.ts +1 -1
  51. package/dist/cjs/hooks/use-can-edit-cellrange.d.ts.map +1 -1
  52. package/dist/cjs/hooks/use-can-edit-cellrange.js +1 -1
  53. package/dist/cjs/hooks/use-on-calculation-success.d.ts +5 -1
  54. package/dist/cjs/hooks/use-on-calculation-success.d.ts.map +1 -1
  55. package/dist/cjs/hooks/use-on-calculation-success.js +20 -3
  56. package/dist/cjs/hooks/use-on-copy.d.ts.map +1 -1
  57. package/dist/cjs/hooks/use-on-copy.js +23 -25
  58. package/dist/cjs/hooks/use-on-create-sheet.d.ts.map +1 -1
  59. package/dist/cjs/hooks/use-on-create-sheet.js +11 -1
  60. package/dist/cjs/hooks/use-on-delete.d.ts.map +1 -1
  61. package/dist/cjs/hooks/use-on-delete.js +15 -3
  62. package/dist/cjs/hooks/use-on-drag-n-drop.d.ts +5 -0
  63. package/dist/cjs/hooks/use-on-drag-n-drop.d.ts.map +1 -1
  64. package/dist/cjs/hooks/use-on-drag-n-drop.js +6 -5
  65. package/dist/cjs/hooks/use-on-filter-table.d.ts.map +1 -1
  66. package/dist/cjs/hooks/use-on-filter-table.js +6 -1
  67. package/dist/cjs/hooks/use-on-find-replace.d.ts.map +1 -1
  68. package/dist/cjs/hooks/use-on-find-replace.js +111 -23
  69. package/dist/cjs/hooks/use-on-insert-image.d.ts.map +1 -1
  70. package/dist/cjs/hooks/use-on-insert-image.js +20 -33
  71. package/dist/cjs/hooks/use-on-paste.d.ts +2 -1
  72. package/dist/cjs/hooks/use-on-paste.d.ts.map +1 -1
  73. package/dist/cjs/hooks/use-on-paste.js +53 -24
  74. package/dist/cjs/hooks/use-on-rename-sheet.d.ts +3 -1
  75. package/dist/cjs/hooks/use-on-rename-sheet.d.ts.map +1 -1
  76. package/dist/cjs/hooks/use-on-rename-sheet.js +19 -9
  77. package/dist/cjs/hooks/use-on-sort-column.d.ts +7 -1
  78. package/dist/cjs/hooks/use-on-sort-column.d.ts.map +1 -1
  79. package/dist/cjs/hooks/use-on-sort-column.js +25 -8
  80. package/dist/cjs/hooks/use-on-sort-range.d.ts +16 -2
  81. package/dist/cjs/hooks/use-on-sort-range.d.ts.map +1 -1
  82. package/dist/cjs/hooks/use-on-sort-range.js +72 -40
  83. package/dist/cjs/hooks/use-on-sort-table.d.ts +7 -2
  84. package/dist/cjs/hooks/use-on-sort-table.d.ts.map +1 -1
  85. package/dist/cjs/hooks/use-on-sort-table.js +25 -4
  86. package/dist/cjs/hooks/use-spreadsheet-state.d.ts +5 -3
  87. package/dist/cjs/hooks/use-spreadsheet-state.d.ts.map +1 -1
  88. package/dist/cjs/hooks/use-spreadsheet-state.js +7 -0
  89. package/dist/cjs/hooks/utils/sort-rows.d.ts +15 -0
  90. package/dist/cjs/hooks/utils/sort-rows.d.ts.map +1 -1
  91. package/dist/cjs/hooks/utils/sort-rows.js +16 -0
  92. package/dist/cjs/index.d.ts +3 -0
  93. package/dist/cjs/index.d.ts.map +1 -1
  94. package/dist/cjs/index.js +3 -0
  95. package/dist/cjs/interface/delete-column.d.ts.map +1 -1
  96. package/dist/cjs/interface/delete-column.js +254 -101
  97. package/dist/cjs/interface/delete-row.d.ts.map +1 -1
  98. package/dist/cjs/interface/delete-row.js +233 -81
  99. package/dist/cjs/interface/duplicate-sheet.d.ts.map +1 -1
  100. package/dist/cjs/interface/duplicate-sheet.js +4 -9
  101. package/dist/cjs/interface/insert-column.d.ts.map +1 -1
  102. package/dist/cjs/interface/insert-column.js +1 -1
  103. package/dist/cjs/interface/insert-row.d.ts.map +1 -1
  104. package/dist/cjs/interface/insert-row.js +1 -1
  105. package/dist/cjs/interface/new-sheet.d.ts.map +1 -1
  106. package/dist/cjs/interface/new-sheet.js +6 -13
  107. package/dist/cjs/sheet-cell.d.ts +9 -0
  108. package/dist/cjs/sheet-cell.d.ts.map +1 -1
  109. package/dist/cjs/sheet-cell.js +46 -9
  110. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  111. package/dist/esm/api/circular-reference.d.ts +31 -0
  112. package/dist/esm/api/circular-reference.d.ts.map +1 -0
  113. package/dist/esm/api/circular-reference.js +55 -0
  114. package/dist/esm/api/copy-paste.d.ts +6 -0
  115. package/dist/esm/api/copy-paste.d.ts.map +1 -1
  116. package/dist/esm/api/copy-paste.js +26 -14
  117. package/dist/esm/api/datatype.d.ts +2 -0
  118. package/dist/esm/api/datatype.d.ts.map +1 -1
  119. package/dist/esm/api/datatype.js +50 -27
  120. package/dist/esm/api/decimals.d.ts +10 -0
  121. package/dist/esm/api/decimals.d.ts.map +1 -1
  122. package/dist/esm/api/decimals.js +31 -10
  123. package/dist/esm/api/dependency.d.ts +19 -1
  124. package/dist/esm/api/dependency.d.ts.map +1 -1
  125. package/dist/esm/api/dependency.js +15 -10
  126. package/dist/esm/api/filter-condition.d.ts +58 -0
  127. package/dist/esm/api/filter-condition.d.ts.map +1 -0
  128. package/dist/esm/api/filter-condition.js +146 -0
  129. package/dist/esm/api/formula.d.ts.map +1 -1
  130. package/dist/esm/api/formula.js +9 -7
  131. package/dist/esm/api/image-embed.d.ts +41 -0
  132. package/dist/esm/api/image-embed.d.ts.map +1 -0
  133. package/dist/esm/api/image-embed.js +52 -0
  134. package/dist/esm/api/immer-utils.d.ts.map +1 -1
  135. package/dist/esm/api/immer-utils.js +43 -14
  136. package/dist/esm/api/named-range-structural.d.ts +29 -3
  137. package/dist/esm/api/named-range-structural.d.ts.map +1 -1
  138. package/dist/esm/api/named-range-structural.js +35 -11
  139. package/dist/esm/api/parse-html.d.ts.map +1 -1
  140. package/dist/esm/api/parse-html.js +14 -5
  141. package/dist/esm/api/structural-formula-update.d.ts +20 -1
  142. package/dist/esm/api/structural-formula-update.d.ts.map +1 -1
  143. package/dist/esm/api/structural-formula-update.js +151 -55
  144. package/dist/esm/api/structural-guards.d.ts +11 -0
  145. package/dist/esm/api/structural-guards.d.ts.map +1 -1
  146. package/dist/esm/api/structural-guards.js +31 -0
  147. package/dist/esm/api/structural-table-refs.d.ts +15 -2
  148. package/dist/esm/api/structural-table-refs.d.ts.map +1 -1
  149. package/dist/esm/api/structural-table-refs.js +49 -18
  150. package/dist/esm/commands.d.ts +17 -3
  151. package/dist/esm/commands.d.ts.map +1 -1
  152. package/dist/esm/components/editors/conditional-format-rule-editor.d.ts.map +1 -1
  153. package/dist/esm/components/editors/conditional-format-rule-editor.js +18 -7
  154. package/dist/esm/constants.d.ts +4 -1
  155. package/dist/esm/constants.d.ts.map +1 -1
  156. package/dist/esm/constants.js +4 -0
  157. package/dist/esm/helpers/sheet-title.d.ts +2 -1
  158. package/dist/esm/helpers/sheet-title.d.ts.map +1 -1
  159. package/dist/esm/helpers/sheet-title.js +3 -1
  160. package/dist/esm/hooks/use-can-edit-cellrange.d.ts +1 -1
  161. package/dist/esm/hooks/use-can-edit-cellrange.d.ts.map +1 -1
  162. package/dist/esm/hooks/use-can-edit-cellrange.js +1 -1
  163. package/dist/esm/hooks/use-on-calculation-success.d.ts +5 -1
  164. package/dist/esm/hooks/use-on-calculation-success.d.ts.map +1 -1
  165. package/dist/esm/hooks/use-on-calculation-success.js +19 -3
  166. package/dist/esm/hooks/use-on-copy.d.ts.map +1 -1
  167. package/dist/esm/hooks/use-on-copy.js +17 -17
  168. package/dist/esm/hooks/use-on-create-sheet.d.ts.map +1 -1
  169. package/dist/esm/hooks/use-on-create-sheet.js +11 -1
  170. package/dist/esm/hooks/use-on-delete.d.ts.map +1 -1
  171. package/dist/esm/hooks/use-on-delete.js +15 -3
  172. package/dist/esm/hooks/use-on-drag-n-drop.d.ts +5 -0
  173. package/dist/esm/hooks/use-on-drag-n-drop.d.ts.map +1 -1
  174. package/dist/esm/hooks/use-on-drag-n-drop.js +7 -4
  175. package/dist/esm/hooks/use-on-filter-table.d.ts.map +1 -1
  176. package/dist/esm/hooks/use-on-filter-table.js +13 -2
  177. package/dist/esm/hooks/use-on-find-replace.d.ts.map +1 -1
  178. package/dist/esm/hooks/use-on-find-replace.js +111 -23
  179. package/dist/esm/hooks/use-on-insert-image.d.ts.map +1 -1
  180. package/dist/esm/hooks/use-on-insert-image.js +15 -25
  181. package/dist/esm/hooks/use-on-paste.d.ts +2 -1
  182. package/dist/esm/hooks/use-on-paste.d.ts.map +1 -1
  183. package/dist/esm/hooks/use-on-paste.js +46 -15
  184. package/dist/esm/hooks/use-on-rename-sheet.d.ts +3 -1
  185. package/dist/esm/hooks/use-on-rename-sheet.d.ts.map +1 -1
  186. package/dist/esm/hooks/use-on-rename-sheet.js +19 -9
  187. package/dist/esm/hooks/use-on-sort-column.d.ts +7 -1
  188. package/dist/esm/hooks/use-on-sort-column.d.ts.map +1 -1
  189. package/dist/esm/hooks/use-on-sort-column.js +18 -1
  190. package/dist/esm/hooks/use-on-sort-range.d.ts +16 -2
  191. package/dist/esm/hooks/use-on-sort-range.d.ts.map +1 -1
  192. package/dist/esm/hooks/use-on-sort-range.js +30 -3
  193. package/dist/esm/hooks/use-on-sort-table.d.ts +7 -2
  194. package/dist/esm/hooks/use-on-sort-table.d.ts.map +1 -1
  195. package/dist/esm/hooks/use-on-sort-table.js +25 -4
  196. package/dist/esm/hooks/use-spreadsheet-state.d.ts +5 -3
  197. package/dist/esm/hooks/use-spreadsheet-state.d.ts.map +1 -1
  198. package/dist/esm/hooks/use-spreadsheet-state.js +7 -0
  199. package/dist/esm/hooks/utils/sort-rows.d.ts +15 -0
  200. package/dist/esm/hooks/utils/sort-rows.d.ts.map +1 -1
  201. package/dist/esm/hooks/utils/sort-rows.js +15 -0
  202. package/dist/esm/index.d.ts +3 -0
  203. package/dist/esm/index.d.ts.map +1 -1
  204. package/dist/esm/index.js +3 -0
  205. package/dist/esm/interface/delete-column.d.ts.map +1 -1
  206. package/dist/esm/interface/delete-column.js +111 -80
  207. package/dist/esm/interface/delete-row.d.ts.map +1 -1
  208. package/dist/esm/interface/delete-row.js +91 -59
  209. package/dist/esm/interface/duplicate-sheet.d.ts.map +1 -1
  210. package/dist/esm/interface/duplicate-sheet.js +4 -9
  211. package/dist/esm/interface/insert-column.d.ts.map +1 -1
  212. package/dist/esm/interface/insert-column.js +1 -1
  213. package/dist/esm/interface/insert-row.d.ts.map +1 -1
  214. package/dist/esm/interface/insert-row.js +1 -1
  215. package/dist/esm/interface/new-sheet.d.ts.map +1 -1
  216. package/dist/esm/interface/new-sheet.js +6 -13
  217. package/dist/esm/sheet-cell.d.ts +9 -0
  218. package/dist/esm/sheet-cell.d.ts.map +1 -1
  219. package/dist/esm/sheet-cell.js +46 -7
  220. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  221. package/package.json +15 -15
@@ -6,16 +6,21 @@ import { updateNamedRangesOnStructuralChange, updatePrintSettingsOnStructuralCha
6
6
  import { shiftPivotsOnDelete } from "../api/pivot-range";
7
7
  import { updateRangedRulesOnStructuralChange } from "../api/range-rule-helpers";
8
8
  import { moveFilterView } from "../api/selection";
9
- import { updateFormulasForStructuralChange } from "../api/structural-formula-update";
9
+ import { contiguousRuns, updateFormulasForStructuralChange, } from "../api/structural-formula-update";
10
10
  import { breakStructuredRefsForRemovedTableParts, collectRemovedTableParts, removeSpillsOfDeletedAnchors, } from "../api/structural-table-refs";
11
11
  export const deleteColumn = ({ rowCount, columnCount, locale, cellXfsRegistry, sharedStringRegistry, getSheetName, getActiveCell, getSelections, getDependents, getGraphNodes, getGraphNodesInSheet, createHistory, enqueueGraphOperation, enqueueCalculation, enqueueStructureChange, onChangeSheetData, onChangeSheets, onChangeTables, onChangeActiveCell, onChangeSelections, onChangeConditionalFormats, onChangeDataValidations, onChangeCitations, onChangePivotTables, tables, getArrayRange, onChangeNamedRanges, onChangeEmbeds, onChangeSlicers, onChangeCharts, onChangeProtectedRanges, }) => {
12
12
  return (sheetId, columnIndexes) => {
13
13
  if (!columnIndexes.length)
14
14
  return;
15
- const sortedColumnIndexes = [...columnIndexes].sort((a, b) => a - b);
15
+ const sortedColumnIndexes = [...new Set(columnIndexes)].sort((a, b) => a - b);
16
16
  const minColumnIndex = sortedColumnIndexes[0];
17
17
  const maxColumnIndex = sortedColumnIndexes[sortedColumnIndexes.length - 1];
18
18
  const count = sortedColumnIndexes.length;
19
+ // A Ctrl-selected delete (columns B and D) is several contiguous bands;
20
+ // band-shaped updates run once per band, LAST band first (see `deleteRow`).
21
+ const runs = contiguousRuns(sortedColumnIndexes);
22
+ const runsDescending = [...runs].reverse();
23
+ const isDeleted = (columnIndex) => sortedColumnIndexes.includes(columnIndex);
19
24
  const saveHistory = createHistory();
20
25
  enqueueStructureChange?.({
21
26
  kind: "delete-column",
@@ -74,34 +79,37 @@ export const deleteColumn = ({ rowCount, columnCount, locale, cellXfsRegistry, s
74
79
  }
75
80
  if (minColumnIndex > endColumnIndex)
76
81
  continue;
77
- if (minColumnIndex <= startColumnIndex &&
78
- maxColumnIndex >= endColumnIndex) {
82
+ // The table's own columns that go — every one of them removes the table.
83
+ const removedOffsets = [];
84
+ for (let column = startColumnIndex; column <= endColumnIndex; column++) {
85
+ if (isDeleted(column))
86
+ removedOffsets.push(column - startColumnIndex);
87
+ }
88
+ if (removedOffsets.length === endColumnIndex - startColumnIndex + 1) {
79
89
  draft.splice(idx, 1);
80
90
  continue;
81
91
  }
82
92
  if (table.filterSpecs) {
83
93
  for (const spec of table.filterSpecs) {
84
- if (spec.columnIndex >= minColumnIndex) {
85
- spec.columnIndex -= count;
86
- }
94
+ spec.columnIndex -= deletedBefore(spec.columnIndex);
87
95
  }
88
96
  }
89
97
  if (table.sortSpecs) {
90
98
  for (const spec of table.sortSpecs) {
91
- if (spec.dimensionIndex >= minColumnIndex) {
92
- spec.dimensionIndex -= count;
93
- }
99
+ spec.dimensionIndex -= deletedBefore(spec.dimensionIndex);
94
100
  }
95
101
  }
96
- const overlapStart = Math.max(minColumnIndex, startColumnIndex);
97
- const overlapEnd = Math.min(maxColumnIndex, endColumnIndex);
98
- const removed = overlapEnd - overlapStart + 1;
99
- table.columns?.splice(overlapStart - startColumnIndex, removed);
100
- table.range.startColumnIndex = Math.min(startColumnIndex, minColumnIndex);
102
+ for (let i = removedOffsets.length - 1; i >= 0; i--) {
103
+ table.columns?.splice(removedOffsets[i], 1);
104
+ }
105
+ // The table moves left by the columns deleted before it (a deleted
106
+ // leading column is one of its own, so it counts as removed, not moved).
107
+ table.range.startColumnIndex =
108
+ startColumnIndex - deletedBefore(startColumnIndex);
101
109
  table.range.endColumnIndex =
102
110
  table.range.startColumnIndex +
103
111
  (endColumnIndex - startColumnIndex) -
104
- removed;
112
+ removedOffsets.length;
105
113
  }
106
114
  });
107
115
  saveHistory({ tables: { patches, inversePatches } });
@@ -110,7 +118,9 @@ export const deleteColumn = ({ rowCount, columnCount, locale, cellXfsRegistry, s
110
118
  // Data validations
111
119
  onChangeDataValidations?.((prevValidations) => {
112
120
  const [nextState, patches, inversePatches] = produceWithPatches(prevValidations, (draft) => {
113
- updateRangedRulesOnStructuralChange(draft, "delete", "column", minColumnIndex, count, sheetId, { getSheetName });
121
+ for (const run of runsDescending) {
122
+ updateRangedRulesOnStructuralChange(draft, "delete", "column", run.start, run.count, sheetId, { getSheetName });
123
+ }
114
124
  });
115
125
  saveHistory({ dataValidations: { patches, inversePatches } });
116
126
  return nextState;
@@ -118,7 +128,9 @@ export const deleteColumn = ({ rowCount, columnCount, locale, cellXfsRegistry, s
118
128
  // Conditional formats
119
129
  onChangeConditionalFormats?.((prevConditionalFormats) => {
120
130
  const [nextState, patches, inversePatches] = produceWithPatches(prevConditionalFormats, (draft) => {
121
- updateRangedRulesOnStructuralChange(draft, "delete", "column", minColumnIndex, count, sheetId, { getSheetName });
131
+ for (const run of runsDescending) {
132
+ updateRangedRulesOnStructuralChange(draft, "delete", "column", run.start, run.count, sheetId, { getSheetName });
133
+ }
122
134
  });
123
135
  saveHistory({ conditionalFormats: { patches, inversePatches } });
124
136
  return nextState;
@@ -127,7 +139,9 @@ export const deleteColumn = ({ rowCount, columnCount, locale, cellXfsRegistry, s
127
139
  // deleted is kept as `#REF!` so its users evaluate `#REF!`, like Excel.
128
140
  onChangeNamedRanges?.((prevNamedRanges) => {
129
141
  const [nextState, patches, inversePatches] = produceWithPatches(prevNamedRanges, (draft) => {
130
- updateNamedRangesOnStructuralChange(draft, "column", "delete", minColumnIndex, count, sheetId);
142
+ for (const run of runsDescending) {
143
+ updateNamedRangesOnStructuralChange(draft, "column", "delete", run.start, run.count, sheetId, { length: columnCount });
144
+ }
131
145
  });
132
146
  saveHistory({ namedRanges: { patches, inversePatches } });
133
147
  return nextState;
@@ -135,7 +149,9 @@ export const deleteColumn = ({ rowCount, columnCount, locale, cellXfsRegistry, s
135
149
  // Shift pivot tables.
136
150
  onChangePivotTables?.((prevPivots) => {
137
151
  const [nextState, patches, inversePatches] = produceWithPatches(prevPivots, (draft) => {
138
- shiftPivotsOnDelete(draft, sheetId, "column", minColumnIndex, count);
152
+ for (const run of runsDescending) {
153
+ shiftPivotsOnDelete(draft, sheetId, "column", run.start, run.count);
154
+ }
139
155
  });
140
156
  saveHistory({ pivotTables: { patches, inversePatches } });
141
157
  return nextState;
@@ -144,24 +160,26 @@ export const deleteColumn = ({ rowCount, columnCount, locale, cellXfsRegistry, s
144
160
  onChangeCitations?.((prevCitations) => {
145
161
  const updatedAt = new Date().toISOString();
146
162
  const [nextState, patches, inversePatches] = produceWithPatches(prevCitations, (draft) => {
147
- const deleteEnd = minColumnIndex + count - 1;
148
- for (let idx = draft.length - 1; idx >= 0; idx--) {
149
- const citation = draft[idx];
150
- if (citation.range.sheetId !== sheetId)
151
- continue;
152
- const citationStart = citation.range.startColumnIndex;
153
- const citationEnd = citation.range.endColumnIndex;
154
- if (citationStart <= deleteEnd && citationEnd >= minColumnIndex) {
155
- // Soft-delete: keep the record for provenance / undo, hide it from the UI
156
- if (citation.active !== false) {
157
- citation.active = false;
158
- citation.updated_at = updatedAt;
163
+ for (const run of runsDescending) {
164
+ const deleteEnd = run.start + run.count - 1;
165
+ for (let idx = draft.length - 1; idx >= 0; idx--) {
166
+ const citation = draft[idx];
167
+ if (citation.range.sheetId !== sheetId)
168
+ continue;
169
+ const citationStart = citation.range.startColumnIndex;
170
+ const citationEnd = citation.range.endColumnIndex;
171
+ if (citationStart <= deleteEnd && citationEnd >= run.start) {
172
+ // Soft-delete: keep the record for provenance / undo, hide it from the UI
173
+ if (citation.active !== false) {
174
+ citation.active = false;
175
+ citation.updated_at = updatedAt;
176
+ }
177
+ }
178
+ else if (citationStart > deleteEnd) {
179
+ citation.range.startColumnIndex -= run.count;
180
+ citation.range.endColumnIndex -= run.count;
181
+ refreshCitationAnchor(citation);
159
182
  }
160
- }
161
- else if (citationStart > deleteEnd) {
162
- citation.range.startColumnIndex -= count;
163
- citation.range.endColumnIndex -= count;
164
- refreshCitationAnchor(citation);
165
183
  }
166
184
  }
167
185
  });
@@ -174,28 +192,36 @@ export const deleteColumn = ({ rowCount, columnCount, locale, cellXfsRegistry, s
174
192
  // and are deliberately NOT touched here.
175
193
  onChangeEmbeds?.((prevEmbeds) => {
176
194
  const [nextState, patches, inversePatches] = produceWithPatches(prevEmbeds, (draft) => {
177
- shiftEmbedsOnStructuralChange(draft, sheetId, "column", "delete", minColumnIndex, count);
195
+ for (const run of runsDescending) {
196
+ shiftEmbedsOnStructuralChange(draft, sheetId, "column", "delete", run.start, run.count);
197
+ }
178
198
  });
179
199
  saveHistory({ embeds: { patches, inversePatches } });
180
200
  return nextState;
181
201
  });
182
202
  onChangeSlicers?.((prevSlicers) => {
183
203
  const [nextState, patches, inversePatches] = produceWithPatches(prevSlicers, (draft) => {
184
- shiftSlicersOnStructuralChange(draft, sheetId, "column", "delete", minColumnIndex, count);
204
+ for (const run of runsDescending) {
205
+ shiftSlicersOnStructuralChange(draft, sheetId, "column", "delete", run.start, run.count);
206
+ }
185
207
  });
186
208
  saveHistory({ slicers: { patches, inversePatches } });
187
209
  return nextState;
188
210
  });
189
211
  onChangeCharts?.((prevCharts) => {
190
212
  const [nextState, patches, inversePatches] = produceWithPatches(prevCharts, (draft) => {
191
- shiftChartsOnStructuralChange(draft, sheetId, "column", "delete", minColumnIndex, count);
213
+ for (const run of runsDescending) {
214
+ shiftChartsOnStructuralChange(draft, sheetId, "column", "delete", run.start, run.count);
215
+ }
192
216
  });
193
217
  saveHistory({ charts: { patches, inversePatches } });
194
218
  return nextState;
195
219
  });
196
220
  onChangeProtectedRanges?.((prevProtectedRanges) => {
197
221
  const [nextState, patches, inversePatches] = produceWithPatches(prevProtectedRanges, (draft) => {
198
- shiftProtectedRangesOnStructuralChange(draft, sheetId, "column", "delete", minColumnIndex, count);
222
+ for (const run of runsDescending) {
223
+ shiftProtectedRangesOnStructuralChange(draft, sheetId, "column", "delete", run.start, run.count);
224
+ }
199
225
  });
200
226
  saveHistory({ protectedRanges: { patches, inversePatches } });
201
227
  return nextState;
@@ -206,40 +232,41 @@ export const deleteColumn = ({ rowCount, columnCount, locale, cellXfsRegistry, s
206
232
  const sheet = draft.find((sheet) => sheet.sheetId === sheetId);
207
233
  if (!sheet)
208
234
  return;
209
- if (sheet.columnMetadata) {
210
- sheet.columnMetadata.splice(minColumnIndex, count);
211
- }
212
- if (sheet.basicFilter) {
213
- const { startColumnIndex, endColumnIndex } = sheet.basicFilter.range;
214
- if (minColumnIndex < startColumnIndex) {
215
- moveFilterView(sheet.basicFilter, count, Direction.Left);
235
+ for (const run of runsDescending) {
236
+ if (sheet.columnMetadata) {
237
+ sheet.columnMetadata.splice(run.start, run.count);
216
238
  }
217
- if (minColumnIndex > startColumnIndex &&
218
- minColumnIndex <= endColumnIndex) {
219
- if (sheet.basicFilter.filterSpecs) {
220
- for (const spec of sheet.basicFilter.filterSpecs) {
221
- if (spec.columnIndex >= minColumnIndex) {
222
- spec.columnIndex -= count;
239
+ if (sheet.basicFilter) {
240
+ const { startColumnIndex, endColumnIndex } = sheet.basicFilter.range;
241
+ if (run.start < startColumnIndex) {
242
+ moveFilterView(sheet.basicFilter, run.count, Direction.Left);
243
+ }
244
+ if (run.start > startColumnIndex && run.start <= endColumnIndex) {
245
+ if (sheet.basicFilter.filterSpecs) {
246
+ for (const spec of sheet.basicFilter.filterSpecs) {
247
+ if (spec.columnIndex >= run.start) {
248
+ spec.columnIndex -= run.count;
249
+ }
223
250
  }
224
251
  }
225
- }
226
- if (sheet.basicFilter.sortSpecs) {
227
- for (const spec of sheet.basicFilter.sortSpecs) {
228
- if (spec.dimensionIndex >= minColumnIndex) {
229
- spec.dimensionIndex -= count;
252
+ if (sheet.basicFilter.sortSpecs) {
253
+ for (const spec of sheet.basicFilter.sortSpecs) {
254
+ if (spec.dimensionIndex >= run.start) {
255
+ spec.dimensionIndex -= run.count;
256
+ }
230
257
  }
231
258
  }
259
+ const delta = Math.min(endColumnIndex - run.start + 1, run.count);
260
+ sheet.basicFilter.range.endColumnIndex -= delta;
232
261
  }
233
- const delta = Math.min(endColumnIndex - minColumnIndex + 1, count);
234
- sheet.basicFilter.range.endColumnIndex -= delta;
235
262
  }
236
- }
237
- if (sheet.merges) {
238
- sheet.merges = shrinkMergesOnColumnDelete(sheet.merges, minColumnIndex, count);
239
- }
240
- // `_xlnm.Print_Area` / `_xlnm.Print_Titles` follow the defined-name rule.
241
- if (sheet.printSettings) {
242
- updatePrintSettingsOnStructuralChange(sheet.printSettings, "column", "delete", minColumnIndex, count);
263
+ if (sheet.merges) {
264
+ sheet.merges = shrinkMergesOnColumnDelete(sheet.merges, run.start, run.count);
265
+ }
266
+ // `_xlnm.Print_Area` / `_xlnm.Print_Titles` follow the defined-name rule.
267
+ if (sheet.printSettings) {
268
+ updatePrintSettingsOnStructuralChange(sheet.printSettings, "column", "delete", run.start, run.count);
269
+ }
243
270
  }
244
271
  sheet.columnCount = Math.max(1, (sheet.columnCount ?? columnCount) - count);
245
272
  // Frozen panes are positional: the split stays where it is, only
@@ -254,27 +281,30 @@ export const deleteColumn = ({ rowCount, columnCount, locale, cellXfsRegistry, s
254
281
  });
255
282
  // Table columns spliced out above (and tables dropped whole): their
256
283
  // structured refs break to `#REF!`, computed from the PRE-edit definitions.
257
- const removedTableParts = collectRemovedTableParts(tables, sheetId, "column", minColumnIndex, maxColumnIndex);
284
+ const removedTableParts = collectRemovedTableParts(tables, sheetId, "column", minColumnIndex, maxColumnIndex, sortedColumnIndexes);
258
285
  // Sheet data: three-pass formula update, then per-row column splice.
259
286
  onChangeSheetData?.((prevSheetData) => {
260
287
  const [nextState, patches, inversePatches] = produceWithPatches(prevSheetData, (draft) => {
261
- removeSpillsOfDeletedAnchors({
262
- draft,
263
- sheetId,
264
- axis: "column",
265
- minIndex: minColumnIndex,
266
- maxIndex: maxColumnIndex,
267
- getArrayRange,
268
- locale,
269
- cellXfsRegistry,
270
- sharedStringRegistry,
271
- });
288
+ for (const run of runsDescending) {
289
+ removeSpillsOfDeletedAnchors({
290
+ draft,
291
+ sheetId,
292
+ axis: "column",
293
+ minIndex: run.start,
294
+ maxIndex: run.start + run.count - 1,
295
+ getArrayRange,
296
+ locale,
297
+ cellXfsRegistry,
298
+ sharedStringRegistry,
299
+ });
300
+ }
272
301
  breakStructuredRefsForRemovedTableParts({
273
302
  draft,
274
303
  sheetId,
275
304
  axis: "column",
276
305
  referenceIndex: minColumnIndex,
277
306
  count,
307
+ indexes: sortedColumnIndexes,
278
308
  removed: removedTableParts,
279
309
  getGraphNodes,
280
310
  enqueueCalculation,
@@ -291,6 +321,7 @@ export const deleteColumn = ({ rowCount, columnCount, locale, cellXfsRegistry, s
291
321
  sheetId,
292
322
  referenceIndex: minColumnIndex,
293
323
  count,
324
+ indexes: sortedColumnIndexes,
294
325
  rowCount,
295
326
  columnCount,
296
327
  getDependents,
@@ -1 +1 @@
1
- {"version":3,"file":"delete-row.d.ts","sourceRoot":"","sources":["../../../interface/delete-row.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAa,MAAM,2BAA2B,CAAC;AA2B5E,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAiCtE,eAAO,MAAM,SAAS,GAAI,CAAC,SAAS,QAAQ,EAAE,CAAC,SAAS,KAAK,EAAE,2iBAgC5D,mBAAmB,CAAC,CAAC,EAAE,CAAC,CAAC,MAClB,SAAS,MAAM,EAAE,YAAY,MAAM,EAAE,SAkkB9C,CAAC"}
1
+ {"version":3,"file":"delete-row.d.ts","sourceRoot":"","sources":["../../../interface/delete-row.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAa,MAAM,2BAA2B,CAAC;AA8B5E,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAiCtE,eAAO,MAAM,SAAS,GAAI,CAAC,SAAS,QAAQ,EAAE,CAAC,SAAS,KAAK,EAAE,2iBAgC5D,mBAAmB,CAAC,CAAC,EAAE,CAAC,CAAC,MAClB,SAAS,MAAM,EAAE,YAAY,MAAM,EAAE,SAomB9C,CAAC"}
@@ -6,7 +6,7 @@ import { updateNamedRangesOnStructuralChange, updatePrintSettingsOnStructuralCha
6
6
  import { shiftPivotsOnDelete } from "../api/pivot-range";
7
7
  import { updateRangedRulesOnStructuralChange } from "../api/range-rule-helpers";
8
8
  import { moveFilterView } from "../api/selection";
9
- import { updateFormulasForStructuralChange } from "../api/structural-formula-update";
9
+ import { contiguousRuns, updateFormulasForStructuralChange, } from "../api/structural-formula-update";
10
10
  import { breakStructuredRefsForRemovedTableParts, collectRemovedTableParts, removeSpillsOfDeletedAnchors, renameTableColumnsInFormulas, } from "../api/structural-table-refs";
11
11
  import { createSheetCellIdentifier } from "../api/formula";
12
12
  import { createSheetDraft } from "../api/immer-utils";
@@ -39,10 +39,17 @@ export const deleteRow = ({ rowCount, columnCount, locale, cellXfsRegistry, shar
39
39
  if (!rowIndexes.length)
40
40
  return;
41
41
  // Don't mutate caller's array.
42
- const sortedRowIndexes = [...rowIndexes].sort((a, b) => a - b);
42
+ const sortedRowIndexes = [...new Set(rowIndexes)].sort((a, b) => a - b);
43
43
  const minRowIndex = sortedRowIndexes[0];
44
44
  const maxRowIndex = sortedRowIndexes[sortedRowIndexes.length - 1];
45
45
  const count = sortedRowIndexes.length;
46
+ // A Ctrl-selected delete (rows 2 and 4) is several contiguous bands. Every
47
+ // band-shaped update below runs once per band, LAST band first, so each
48
+ // band's coordinates are still the original ones when its turn comes —
49
+ // Excel's result: a line loses exactly the deleted lines before it, and a
50
+ // reference into a deleted line breaks (#939 K-09).
51
+ const runs = contiguousRuns(sortedRowIndexes);
52
+ const runsDescending = [...runs].reverse();
46
53
  const saveHistory = createHistory();
47
54
  enqueueStructureChange?.({
48
55
  kind: "delete-row",
@@ -142,7 +149,9 @@ export const deleteRow = ({ rowCount, columnCount, locale, cellXfsRegistry, shar
142
149
  // Data validations
143
150
  onChangeDataValidations?.((prevValidations) => {
144
151
  const [nextState, patches, inversePatches] = produceWithPatches(prevValidations, (draft) => {
145
- updateRangedRulesOnStructuralChange(draft, "delete", "row", minRowIndex, count, sheetId, { getSheetName });
152
+ for (const run of runsDescending) {
153
+ updateRangedRulesOnStructuralChange(draft, "delete", "row", run.start, run.count, sheetId, { getSheetName });
154
+ }
146
155
  });
147
156
  saveHistory({ dataValidations: { patches, inversePatches } });
148
157
  return nextState;
@@ -150,7 +159,9 @@ export const deleteRow = ({ rowCount, columnCount, locale, cellXfsRegistry, shar
150
159
  // Conditional formats
151
160
  onChangeConditionalFormats?.((prevConditionalFormats) => {
152
161
  const [nextState, patches, inversePatches] = produceWithPatches(prevConditionalFormats, (draft) => {
153
- updateRangedRulesOnStructuralChange(draft, "delete", "row", minRowIndex, count, sheetId, { getSheetName });
162
+ for (const run of runsDescending) {
163
+ updateRangedRulesOnStructuralChange(draft, "delete", "row", run.start, run.count, sheetId, { getSheetName });
164
+ }
154
165
  });
155
166
  saveHistory({ conditionalFormats: { patches, inversePatches } });
156
167
  return nextState;
@@ -159,7 +170,9 @@ export const deleteRow = ({ rowCount, columnCount, locale, cellXfsRegistry, shar
159
170
  // deleted is kept as `#REF!` so its users evaluate `#REF!`, like Excel.
160
171
  onChangeNamedRanges?.((prevNamedRanges) => {
161
172
  const [nextState, patches, inversePatches] = produceWithPatches(prevNamedRanges, (draft) => {
162
- updateNamedRangesOnStructuralChange(draft, "row", "delete", minRowIndex, count, sheetId);
173
+ for (const run of runsDescending) {
174
+ updateNamedRangesOnStructuralChange(draft, "row", "delete", run.start, run.count, sheetId, { length: rowCount });
175
+ }
163
176
  });
164
177
  saveHistory({ namedRanges: { patches, inversePatches } });
165
178
  return nextState;
@@ -168,7 +181,9 @@ export const deleteRow = ({ rowCount, columnCount, locale, cellXfsRegistry, shar
168
181
  // the start of the deletion when its row falls inside the deletion.
169
182
  onChangePivotTables?.((prevPivots) => {
170
183
  const [nextState, patches, inversePatches] = produceWithPatches(prevPivots, (draft) => {
171
- shiftPivotsOnDelete(draft, sheetId, "row", minRowIndex, count);
184
+ for (const run of runsDescending) {
185
+ shiftPivotsOnDelete(draft, sheetId, "row", run.start, run.count);
186
+ }
172
187
  });
173
188
  saveHistory({ pivotTables: { patches, inversePatches } });
174
189
  return nextState;
@@ -178,24 +193,26 @@ export const deleteRow = ({ rowCount, columnCount, locale, cellXfsRegistry, shar
178
193
  onChangeCitations?.((prevCitations) => {
179
194
  const updatedAt = new Date().toISOString();
180
195
  const [nextState, patches, inversePatches] = produceWithPatches(prevCitations, (draft) => {
181
- const deleteEnd = minRowIndex + count - 1;
182
- for (let idx = draft.length - 1; idx >= 0; idx--) {
183
- const citation = draft[idx];
184
- if (citation.range.sheetId !== sheetId)
185
- continue;
186
- const citationStart = citation.range.startRowIndex;
187
- const citationEnd = citation.range.endRowIndex;
188
- if (citationStart <= deleteEnd && citationEnd >= minRowIndex) {
189
- // Soft-delete: keep the record for provenance / undo, hide it from the UI
190
- if (citation.active !== false) {
191
- citation.active = false;
192
- citation.updated_at = updatedAt;
196
+ for (const run of runsDescending) {
197
+ const deleteEnd = run.start + run.count - 1;
198
+ for (let idx = draft.length - 1; idx >= 0; idx--) {
199
+ const citation = draft[idx];
200
+ if (citation.range.sheetId !== sheetId)
201
+ continue;
202
+ const citationStart = citation.range.startRowIndex;
203
+ const citationEnd = citation.range.endRowIndex;
204
+ if (citationStart <= deleteEnd && citationEnd >= run.start) {
205
+ // Soft-delete: keep the record for provenance / undo, hide it from the UI
206
+ if (citation.active !== false) {
207
+ citation.active = false;
208
+ citation.updated_at = updatedAt;
209
+ }
210
+ }
211
+ else if (citationStart > deleteEnd) {
212
+ citation.range.startRowIndex -= run.count;
213
+ citation.range.endRowIndex -= run.count;
214
+ refreshCitationAnchor(citation);
193
215
  }
194
- }
195
- else if (citationStart > deleteEnd) {
196
- citation.range.startRowIndex -= count;
197
- citation.range.endRowIndex -= count;
198
- refreshCitationAnchor(citation);
199
216
  }
200
217
  }
201
218
  });
@@ -208,28 +225,36 @@ export const deleteRow = ({ rowCount, columnCount, locale, cellXfsRegistry, shar
208
225
  // and are deliberately NOT touched here.
209
226
  onChangeEmbeds?.((prevEmbeds) => {
210
227
  const [nextState, patches, inversePatches] = produceWithPatches(prevEmbeds, (draft) => {
211
- shiftEmbedsOnStructuralChange(draft, sheetId, "row", "delete", minRowIndex, count);
228
+ for (const run of runsDescending) {
229
+ shiftEmbedsOnStructuralChange(draft, sheetId, "row", "delete", run.start, run.count);
230
+ }
212
231
  });
213
232
  saveHistory({ embeds: { patches, inversePatches } });
214
233
  return nextState;
215
234
  });
216
235
  onChangeSlicers?.((prevSlicers) => {
217
236
  const [nextState, patches, inversePatches] = produceWithPatches(prevSlicers, (draft) => {
218
- shiftSlicersOnStructuralChange(draft, sheetId, "row", "delete", minRowIndex, count);
237
+ for (const run of runsDescending) {
238
+ shiftSlicersOnStructuralChange(draft, sheetId, "row", "delete", run.start, run.count);
239
+ }
219
240
  });
220
241
  saveHistory({ slicers: { patches, inversePatches } });
221
242
  return nextState;
222
243
  });
223
244
  onChangeCharts?.((prevCharts) => {
224
245
  const [nextState, patches, inversePatches] = produceWithPatches(prevCharts, (draft) => {
225
- shiftChartsOnStructuralChange(draft, sheetId, "row", "delete", minRowIndex, count);
246
+ for (const run of runsDescending) {
247
+ shiftChartsOnStructuralChange(draft, sheetId, "row", "delete", run.start, run.count);
248
+ }
226
249
  });
227
250
  saveHistory({ charts: { patches, inversePatches } });
228
251
  return nextState;
229
252
  });
230
253
  onChangeProtectedRanges?.((prevProtectedRanges) => {
231
254
  const [nextState, patches, inversePatches] = produceWithPatches(prevProtectedRanges, (draft) => {
232
- shiftProtectedRangesOnStructuralChange(draft, sheetId, "row", "delete", minRowIndex, count);
255
+ for (const run of runsDescending) {
256
+ shiftProtectedRangesOnStructuralChange(draft, sheetId, "row", "delete", run.start, run.count);
257
+ }
233
258
  });
234
259
  saveHistory({ protectedRanges: { patches, inversePatches } });
235
260
  return nextState;
@@ -240,30 +265,33 @@ export const deleteRow = ({ rowCount, columnCount, locale, cellXfsRegistry, shar
240
265
  const sheet = draft.find((sheet) => sheet.sheetId === sheetId);
241
266
  if (!sheet)
242
267
  return;
243
- if (sheet.rowMetadata) {
244
- sheet.rowMetadata.splice(minRowIndex, count);
245
- }
246
- if (sheet.basicFilter) {
247
- const { startRowIndex, endRowIndex } = sheet.basicFilter.range;
248
- if (minRowIndex < startRowIndex) {
249
- moveFilterView(sheet.basicFilter, count, Direction.Up);
268
+ for (const run of runsDescending) {
269
+ const runEnd = run.start + run.count - 1;
270
+ if (sheet.rowMetadata) {
271
+ sheet.rowMetadata.splice(run.start, run.count);
272
+ }
273
+ if (sheet.basicFilter) {
274
+ const { startRowIndex, endRowIndex } = sheet.basicFilter.range;
275
+ if (run.start < startRowIndex) {
276
+ moveFilterView(sheet.basicFilter, run.count, Direction.Up);
277
+ }
278
+ if (run.start > startRowIndex && run.start <= endRowIndex) {
279
+ const delta = Math.min(endRowIndex - run.start + 1, run.count);
280
+ sheet.basicFilter.range.endRowIndex -= delta;
281
+ }
282
+ if (sheet.basicFilter.range.startRowIndex >= run.start &&
283
+ sheet.basicFilter.range.startRowIndex <= runEnd) {
284
+ delete sheet.basicFilter;
285
+ }
250
286
  }
251
- if (minRowIndex > startRowIndex && minRowIndex <= endRowIndex) {
252
- const delta = Math.min(endRowIndex - minRowIndex + 1, count);
253
- sheet.basicFilter.range.endRowIndex -= delta;
287
+ if (sheet.merges) {
288
+ sheet.merges = shrinkMergesOnRowDelete(sheet.merges, run.start, run.count);
254
289
  }
255
- if (sheet.basicFilter.range.startRowIndex >= minRowIndex &&
256
- sheet.basicFilter.range.startRowIndex <= maxRowIndex) {
257
- delete sheet.basicFilter;
290
+ // `_xlnm.Print_Area` / `_xlnm.Print_Titles` follow the defined-name rule.
291
+ if (sheet.printSettings) {
292
+ updatePrintSettingsOnStructuralChange(sheet.printSettings, "row", "delete", run.start, run.count);
258
293
  }
259
294
  }
260
- if (sheet.merges) {
261
- sheet.merges = shrinkMergesOnRowDelete(sheet.merges, minRowIndex, count);
262
- }
263
- // `_xlnm.Print_Area` / `_xlnm.Print_Titles` follow the defined-name rule.
264
- if (sheet.printSettings) {
265
- updatePrintSettingsOnStructuralChange(sheet.printSettings, "row", "delete", minRowIndex, count);
266
- }
267
295
  sheet.rowCount = Math.max(1, (sheet.rowCount ?? rowCount) - count);
268
296
  // Frozen panes are positional: the split stays where it is, only
269
297
  // clamped so the freeze never exceeds the shrunk sheet.
@@ -276,29 +304,32 @@ export const deleteRow = ({ rowCount, columnCount, locale, cellXfsRegistry, shar
276
304
  });
277
305
  // Tables every row of which goes (dropped above): their structured refs
278
306
  // break to `#REF!`, computed from the PRE-edit definitions.
279
- const removedTableParts = collectRemovedTableParts(tables, sheetId, "row", minRowIndex, maxRowIndex);
307
+ const removedTableParts = collectRemovedTableParts(tables, sheetId, "row", minRowIndex, maxRowIndex, sortedRowIndexes);
280
308
  // Sheet data: three-pass formula update, then splice the rows out.
281
309
  onChangeSheetData?.((prevSheetData) => {
282
310
  const [nextState, patches, inversePatches] = produceWithPatches(prevSheetData, (draft) => {
283
311
  // A dynamic array whose anchor row is deleted takes its spill with
284
312
  // it — drop the projected cells before the rows close up.
285
- removeSpillsOfDeletedAnchors({
286
- draft,
287
- sheetId,
288
- axis: "row",
289
- minIndex: minRowIndex,
290
- maxIndex: maxRowIndex,
291
- getArrayRange,
292
- locale,
293
- cellXfsRegistry,
294
- sharedStringRegistry,
295
- });
313
+ for (const run of runsDescending) {
314
+ removeSpillsOfDeletedAnchors({
315
+ draft,
316
+ sheetId,
317
+ axis: "row",
318
+ minIndex: run.start,
319
+ maxIndex: run.start + run.count - 1,
320
+ getArrayRange,
321
+ locale,
322
+ cellXfsRegistry,
323
+ sharedStringRegistry,
324
+ });
325
+ }
296
326
  breakStructuredRefsForRemovedTableParts({
297
327
  draft,
298
328
  sheetId,
299
329
  axis: "row",
300
330
  referenceIndex: minRowIndex,
301
331
  count,
332
+ indexes: sortedRowIndexes,
302
333
  removed: removedTableParts,
303
334
  getGraphNodes,
304
335
  enqueueCalculation,
@@ -315,6 +346,7 @@ export const deleteRow = ({ rowCount, columnCount, locale, cellXfsRegistry, shar
315
346
  sheetId,
316
347
  referenceIndex: minRowIndex,
317
348
  count,
349
+ indexes: sortedRowIndexes,
318
350
  rowCount,
319
351
  columnCount,
320
352
  getDependents,
@@ -1 +1 @@
1
- {"version":3,"file":"duplicate-sheet.d.ts","sourceRoot":"","sources":["../../../interface/duplicate-sheet.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAc,MAAM,2BAA2B,CAAC;AAc7E,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAGhF,eAAO,MAAM,cAAc,GAAI,CAAC,SAAS,QAAQ,EAAE,CAAC,SAAS,KAAK,EAAE,sPAejE,wBAAwB,CAAC,CAAC,EAAE,CAAC,CAAC,MACvB,SAAS,MAAM,EAAE,0BAA0B,MAAM,uBAkT1D,CAAC"}
1
+ {"version":3,"file":"duplicate-sheet.d.ts","sourceRoot":"","sources":["../../../interface/duplicate-sheet.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAc,MAAM,2BAA2B,CAAC;AAe7E,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAGhF,eAAO,MAAM,cAAc,GAAI,CAAC,SAAS,QAAQ,EAAE,CAAC,SAAS,KAAK,EAAE,sPAejE,wBAAwB,CAAC,CAAC,EAAE,CAAC,CAAC,MACvB,SAAS,MAAM,EAAE,0BAA0B,MAAM,uBAkT1D,CAAC"}
@@ -1,4 +1,4 @@
1
- import { getCellUserEnteredValue, getExtendedValueFormula, getNextTableCopyName, uuid, } from "@rowsncolumns/utils";
1
+ import { getCellUserEnteredValue, getExtendedValueFormula, getNextTableCopyName, uniqueSheetTitle, uuid, } from "@rowsncolumns/utils";
2
2
  import { castDraft, produceWithPatches } from "immer";
3
3
  import { retargetChartSpecRanges } from "../api/anchored-objects";
4
4
  import { renameTablesInFormula } from "../api/formula";
@@ -242,12 +242,7 @@ export const duplicateSheet = ({ locale, maxSheetCount, sheets, idCreationStrate
242
242
  * @returns
243
243
  */
244
244
  function generateUniqueSheetName(existingSheets, originalName, generatedNames) {
245
- const baseName = getGeneratedSheetCopyName(originalName, generatedNames);
246
- let newName = baseName;
247
- let counter = 0;
248
- while (existingSheets.includes(newName)) {
249
- counter++;
250
- newName = counter === 1 ? baseName : `${baseName} ${counter - 1}`;
251
- }
252
- return newName;
245
+ // `Copy of X`, then `Copy of X 1`, `Copy of X 2`, … — compared the way Excel compares worksheet
246
+ // names (case-insensitively), so a copy never lands on a title that differs only by case.
247
+ return uniqueSheetTitle(getGeneratedSheetCopyName(originalName, generatedNames), existingSheets);
253
248
  }
@@ -1 +1 @@
1
- {"version":3,"file":"insert-column.d.ts","sourceRoot":"","sources":["../../../interface/insert-column.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,OAAO,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAqC5E,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAC5E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAI7D,eAAO,MAAM,YAAY,GAAI,CAAC,SAAS,QAAQ,EAAE,CAAC,SAAS,KAAK,EAAE,ohBA+B/D,sBAAsB,CAAC,CAAC,EAAE,CAAC,CAAC,MACrB,SAAS,MAAM,EAAE,sBAAsB,MAAM,EAAE,mBAAc,SAqbtE,CAAC;AAMF,eAAO,MAAM,iBAAiB,GAAI,CAAC,SAAS,QAAQ,EAAE,CAAC,SAAS,KAAK,EAAE,qRAkBpE,IAAI,CACL,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,EACnB,QAAQ,GACR,aAAa,GACb,UAAU,GACV,QAAQ,GACR,iBAAiB,GACjB,sBAAsB,GACtB,eAAe,GACf,gBAAgB,GAChB,gBAAgB,GAChB,mBAAmB,GACnB,gBAAgB,GAChB,oBAAoB,GACpB,wBAAwB,GACxB,uBAAuB,GACvB,eAAe,GACf,cAAc,GACd,gBAAgB,CACnB,MAEG,WAAW,SAAS,EACpB,gBAAgB,MAAM,EACtB,WAAW,SAAS,CAAC,IAAI,GAAG,SAAS,CAAC,KAAK,EAC3C,cAAS,SAwXZ,CAAC"}
1
+ {"version":3,"file":"insert-column.d.ts","sourceRoot":"","sources":["../../../interface/insert-column.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,OAAO,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAqC5E,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAC5E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAI7D,eAAO,MAAM,YAAY,GAAI,CAAC,SAAS,QAAQ,EAAE,CAAC,SAAS,KAAK,EAAE,ohBA+B/D,sBAAsB,CAAC,CAAC,EAAE,CAAC,CAAC,MACrB,SAAS,MAAM,EAAE,sBAAsB,MAAM,EAAE,mBAAc,SAsbtE,CAAC;AAMF,eAAO,MAAM,iBAAiB,GAAI,CAAC,SAAS,QAAQ,EAAE,CAAC,SAAS,KAAK,EAAE,qRAkBpE,IAAI,CACL,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,EACnB,QAAQ,GACR,aAAa,GACb,UAAU,GACV,QAAQ,GACR,iBAAiB,GACjB,sBAAsB,GACtB,eAAe,GACf,gBAAgB,GAChB,gBAAgB,GAChB,mBAAmB,GACnB,gBAAgB,GAChB,oBAAoB,GACpB,wBAAwB,GACxB,uBAAuB,GACvB,eAAe,GACf,cAAc,GACd,gBAAgB,CACnB,MAEG,WAAW,SAAS,EACpB,gBAAgB,MAAM,EACtB,WAAW,SAAS,CAAC,IAAI,GAAG,SAAS,CAAC,KAAK,EAC3C,cAAS,SAwXZ,CAAC"}