@rowsncolumns/spreadsheet-state 29.0.0 → 29.1.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 (603) hide show
  1. package/dist/cjs/api/anchored-objects.d.ts +122 -6
  2. package/dist/cjs/api/anchored-objects.d.ts.map +1 -1
  3. package/dist/cjs/api/anchored-objects.js +464 -43
  4. package/dist/cjs/api/copy-paste.d.ts +1 -2
  5. package/dist/cjs/api/copy-paste.d.ts.map +1 -1
  6. package/dist/cjs/api/copy-paste.js +1 -3
  7. package/dist/cjs/api/filter.d.ts +15 -1
  8. package/dist/cjs/api/filter.d.ts.map +1 -1
  9. package/dist/cjs/api/filter.js +32 -2
  10. package/dist/cjs/api/formula.d.ts +63 -0
  11. package/dist/cjs/api/formula.d.ts.map +1 -1
  12. package/dist/cjs/api/formula.js +278 -8
  13. package/dist/cjs/api/paint-format.d.ts +22 -1
  14. package/dist/cjs/api/paint-format.d.ts.map +1 -1
  15. package/dist/cjs/api/paint-format.js +57 -1
  16. package/dist/cjs/api/sort.d.ts +23 -1
  17. package/dist/cjs/api/sort.d.ts.map +1 -1
  18. package/dist/cjs/api/sort.js +52 -6
  19. package/dist/cjs/api/structural-guards.d.ts +57 -0
  20. package/dist/cjs/api/structural-guards.d.ts.map +1 -1
  21. package/dist/cjs/api/structural-guards.js +93 -1
  22. package/dist/cjs/api/structural-table-refs.d.ts +58 -3
  23. package/dist/cjs/api/structural-table-refs.d.ts.map +1 -1
  24. package/dist/cjs/api/structural-table-refs.js +177 -16
  25. package/dist/cjs/api/table.d.ts +26 -2
  26. package/dist/cjs/api/table.d.ts.map +1 -1
  27. package/dist/cjs/api/table.js +93 -60
  28. package/dist/cjs/api/validation.d.ts.map +1 -1
  29. package/dist/cjs/api/validation.js +53 -8
  30. package/dist/cjs/atoms/creating-table.atom.d.ts +22 -0
  31. package/dist/cjs/atoms/creating-table.atom.d.ts.map +1 -0
  32. package/dist/cjs/atoms/creating-table.atom.js +4 -0
  33. package/dist/cjs/atoms/dialog-state.atom.d.ts +8 -0
  34. package/dist/cjs/atoms/dialog-state.atom.d.ts.map +1 -1
  35. package/dist/cjs/atoms/dialog-state.atom.js +28 -0
  36. package/dist/cjs/atoms/editing-slicer.atom.d.ts +9 -0
  37. package/dist/cjs/atoms/editing-slicer.atom.d.ts.map +1 -0
  38. package/dist/cjs/atoms/editing-slicer.atom.js +6 -0
  39. package/dist/cjs/atoms/index.d.ts +4 -0
  40. package/dist/cjs/atoms/index.d.ts.map +1 -1
  41. package/dist/cjs/atoms/index.js +4 -0
  42. package/dist/cjs/atoms/inserting-slicer.atom.d.ts +8 -0
  43. package/dist/cjs/atoms/inserting-slicer.atom.d.ts.map +1 -0
  44. package/dist/cjs/atoms/inserting-slicer.atom.js +5 -0
  45. package/dist/cjs/atoms/resizing-table.atom.d.ts +8 -0
  46. package/dist/cjs/atoms/resizing-table.atom.d.ts.map +1 -0
  47. package/dist/cjs/atoms/resizing-table.atom.js +5 -0
  48. package/dist/cjs/commands.d.ts +129 -2
  49. package/dist/cjs/commands.d.ts.map +1 -1
  50. package/dist/cjs/components/editors/embed-editor.d.ts +4 -2
  51. package/dist/cjs/components/editors/embed-editor.d.ts.map +1 -1
  52. package/dist/cjs/components/editors/embed-editor.js +38 -9
  53. package/dist/cjs/components/editors/slicer-editor.d.ts +15 -0
  54. package/dist/cjs/components/editors/slicer-editor.d.ts.map +1 -0
  55. package/dist/cjs/components/editors/slicer-editor.js +87 -0
  56. package/dist/cjs/components/editors/table-editor.d.ts +58 -2
  57. package/dist/cjs/components/editors/table-editor.d.ts.map +1 -1
  58. package/dist/cjs/components/editors/table-editor.js +261 -20
  59. package/dist/cjs/components/index.d.ts +1 -0
  60. package/dist/cjs/components/index.d.ts.map +1 -1
  61. package/dist/cjs/components/index.js +1 -0
  62. package/dist/cjs/constants.d.ts +9 -1
  63. package/dist/cjs/constants.d.ts.map +1 -1
  64. package/dist/cjs/constants.js +12 -0
  65. package/dist/cjs/generated-names.d.ts +13 -3
  66. package/dist/cjs/generated-names.d.ts.map +1 -1
  67. package/dist/cjs/generated-names.js +3 -1
  68. package/dist/cjs/helpers.d.ts +5 -0
  69. package/dist/cjs/helpers.d.ts.map +1 -1
  70. package/dist/cjs/helpers.js +10 -1
  71. package/dist/cjs/hooks/use-on-change-batch.d.ts +19 -2
  72. package/dist/cjs/hooks/use-on-change-batch.d.ts.map +1 -1
  73. package/dist/cjs/hooks/use-on-change-batch.js +43 -35
  74. package/dist/cjs/hooks/use-on-change-calculated-column.d.ts +10 -1
  75. package/dist/cjs/hooks/use-on-change-calculated-column.d.ts.map +1 -1
  76. package/dist/cjs/hooks/use-on-change-calculated-column.js +17 -5
  77. package/dist/cjs/hooks/use-on-change-table-column.d.ts +6 -1
  78. package/dist/cjs/hooks/use-on-change-table-column.d.ts.map +1 -1
  79. package/dist/cjs/hooks/use-on-change-table-column.js +17 -5
  80. package/dist/cjs/hooks/use-on-change.d.ts +36 -3
  81. package/dist/cjs/hooks/use-on-change.d.ts.map +1 -1
  82. package/dist/cjs/hooks/use-on-change.js +218 -136
  83. package/dist/cjs/hooks/use-on-create-custom-table-style.d.ts +17 -0
  84. package/dist/cjs/hooks/use-on-create-custom-table-style.d.ts.map +1 -0
  85. package/dist/cjs/hooks/use-on-create-custom-table-style.js +28 -0
  86. package/dist/cjs/hooks/use-on-create-named-range.d.ts +4 -2
  87. package/dist/cjs/hooks/use-on-create-named-range.d.ts.map +1 -1
  88. package/dist/cjs/hooks/use-on-create-named-range.js +11 -1
  89. package/dist/cjs/hooks/use-on-delete-cells-shift-left.d.ts +2 -1
  90. package/dist/cjs/hooks/use-on-delete-cells-shift-left.d.ts.map +1 -1
  91. package/dist/cjs/hooks/use-on-delete-cells-shift-left.js +3 -1
  92. package/dist/cjs/hooks/use-on-delete-cells-shift-up.d.ts +2 -1
  93. package/dist/cjs/hooks/use-on-delete-cells-shift-up.d.ts.map +1 -1
  94. package/dist/cjs/hooks/use-on-delete-cells-shift-up.js +3 -1
  95. package/dist/cjs/hooks/use-on-delete-column.d.ts +2 -1
  96. package/dist/cjs/hooks/use-on-delete-column.d.ts.map +1 -1
  97. package/dist/cjs/hooks/use-on-delete-column.js +3 -1
  98. package/dist/cjs/hooks/use-on-delete-row.d.ts +2 -1
  99. package/dist/cjs/hooks/use-on-delete-row.d.ts.map +1 -1
  100. package/dist/cjs/hooks/use-on-delete-row.js +3 -1
  101. package/dist/cjs/hooks/use-on-delete-sheet.d.ts +9 -1
  102. package/dist/cjs/hooks/use-on-delete-sheet.d.ts.map +1 -1
  103. package/dist/cjs/hooks/use-on-delete-sheet.js +17 -1
  104. package/dist/cjs/hooks/use-on-delete-table-row.d.ts +4 -1
  105. package/dist/cjs/hooks/use-on-delete-table-row.d.ts.map +1 -1
  106. package/dist/cjs/hooks/use-on-delete-table-row.js +19 -1
  107. package/dist/cjs/hooks/use-on-delete.d.ts +5 -2
  108. package/dist/cjs/hooks/use-on-delete.d.ts.map +1 -1
  109. package/dist/cjs/hooks/use-on-delete.js +5 -1
  110. package/dist/cjs/hooks/use-on-embeds.d.ts +7 -4
  111. package/dist/cjs/hooks/use-on-embeds.d.ts.map +1 -1
  112. package/dist/cjs/hooks/use-on-embeds.js +26 -24
  113. package/dist/cjs/hooks/use-on-fill.d.ts +17 -2
  114. package/dist/cjs/hooks/use-on-fill.d.ts.map +1 -1
  115. package/dist/cjs/hooks/use-on-fill.js +29 -15
  116. package/dist/cjs/hooks/use-on-filter-table.d.ts.map +1 -1
  117. package/dist/cjs/hooks/use-on-filter-table.js +209 -103
  118. package/dist/cjs/hooks/use-on-import-excel.d.ts +2 -1
  119. package/dist/cjs/hooks/use-on-import-excel.d.ts.map +1 -1
  120. package/dist/cjs/hooks/use-on-import-excel.js +22 -19
  121. package/dist/cjs/hooks/use-on-insert-cells-shift-down.d.ts +2 -1
  122. package/dist/cjs/hooks/use-on-insert-cells-shift-down.d.ts.map +1 -1
  123. package/dist/cjs/hooks/use-on-insert-cells-shift-down.js +3 -1
  124. package/dist/cjs/hooks/use-on-insert-cells-shift-right.d.ts +2 -1
  125. package/dist/cjs/hooks/use-on-insert-cells-shift-right.d.ts.map +1 -1
  126. package/dist/cjs/hooks/use-on-insert-cells-shift-right.js +3 -1
  127. package/dist/cjs/hooks/use-on-insert-column.d.ts +2 -1
  128. package/dist/cjs/hooks/use-on-insert-column.d.ts.map +1 -1
  129. package/dist/cjs/hooks/use-on-insert-column.js +3 -1
  130. package/dist/cjs/hooks/use-on-insert-row.d.ts +2 -1
  131. package/dist/cjs/hooks/use-on-insert-row.d.ts.map +1 -1
  132. package/dist/cjs/hooks/use-on-insert-row.js +3 -1
  133. package/dist/cjs/hooks/use-on-insert-table-row.d.ts +5 -2
  134. package/dist/cjs/hooks/use-on-insert-table-row.d.ts.map +1 -1
  135. package/dist/cjs/hooks/use-on-insert-table-row.js +19 -1
  136. package/dist/cjs/hooks/use-on-merge-unmerge-cells.d.ts +3 -2
  137. package/dist/cjs/hooks/use-on-merge-unmerge-cells.d.ts.map +1 -1
  138. package/dist/cjs/hooks/use-on-merge-unmerge-cells.js +14 -1
  139. package/dist/cjs/hooks/use-on-move-columns.d.ts +3 -1
  140. package/dist/cjs/hooks/use-on-move-columns.d.ts.map +1 -1
  141. package/dist/cjs/hooks/use-on-move-columns.js +14 -1
  142. package/dist/cjs/hooks/use-on-move-rows.d.ts +3 -1
  143. package/dist/cjs/hooks/use-on-move-rows.d.ts.map +1 -1
  144. package/dist/cjs/hooks/use-on-move-rows.js +14 -1
  145. package/dist/cjs/hooks/use-on-move-selection.d.ts +3 -1
  146. package/dist/cjs/hooks/use-on-move-selection.d.ts.map +1 -1
  147. package/dist/cjs/hooks/use-on-move-selection.js +88 -25
  148. package/dist/cjs/hooks/use-on-paste.d.ts +22 -1
  149. package/dist/cjs/hooks/use-on-paste.d.ts.map +1 -1
  150. package/dist/cjs/hooks/use-on-paste.js +993 -776
  151. package/dist/cjs/hooks/use-on-remove-duplicates.d.ts +5 -2
  152. package/dist/cjs/hooks/use-on-remove-duplicates.d.ts.map +1 -1
  153. package/dist/cjs/hooks/use-on-remove-duplicates.js +5 -1
  154. package/dist/cjs/hooks/use-on-request-create-table.d.ts +13 -0
  155. package/dist/cjs/hooks/use-on-request-create-table.d.ts.map +1 -0
  156. package/dist/cjs/hooks/use-on-request-create-table.js +44 -0
  157. package/dist/cjs/hooks/use-on-request-insert-slicer.d.ts +7 -0
  158. package/dist/cjs/hooks/use-on-request-insert-slicer.d.ts.map +1 -0
  159. package/dist/cjs/hooks/use-on-request-insert-slicer.js +15 -0
  160. package/dist/cjs/hooks/use-on-request-resize-table.d.ts +7 -0
  161. package/dist/cjs/hooks/use-on-request-resize-table.d.ts.map +1 -0
  162. package/dist/cjs/hooks/use-on-request-resize-table.js +15 -0
  163. package/dist/cjs/hooks/use-on-resize-table.d.ts +5 -1
  164. package/dist/cjs/hooks/use-on-resize-table.d.ts.map +1 -1
  165. package/dist/cjs/hooks/use-on-resize-table.js +110 -33
  166. package/dist/cjs/hooks/use-on-sort-column.d.ts +28 -3
  167. package/dist/cjs/hooks/use-on-sort-column.d.ts.map +1 -1
  168. package/dist/cjs/hooks/use-on-sort-column.js +136 -90
  169. package/dist/cjs/hooks/use-on-sort-range.d.ts +26 -3
  170. package/dist/cjs/hooks/use-on-sort-range.d.ts.map +1 -1
  171. package/dist/cjs/hooks/use-on-sort-range.js +113 -67
  172. package/dist/cjs/hooks/use-on-sort-table.d.ts +18 -1
  173. package/dist/cjs/hooks/use-on-sort-table.d.ts.map +1 -1
  174. package/dist/cjs/hooks/use-on-sort-table.js +128 -98
  175. package/dist/cjs/hooks/use-on-subtotal.d.ts +10 -3
  176. package/dist/cjs/hooks/use-on-subtotal.d.ts.map +1 -1
  177. package/dist/cjs/hooks/use-on-subtotal.js +13 -9
  178. package/dist/cjs/hooks/use-on-table.d.ts +39 -7
  179. package/dist/cjs/hooks/use-on-table.d.ts.map +1 -1
  180. package/dist/cjs/hooks/use-on-table.js +257 -49
  181. package/dist/cjs/hooks/use-on-undo-calculated-column.d.ts +23 -0
  182. package/dist/cjs/hooks/use-on-undo-calculated-column.d.ts.map +1 -0
  183. package/dist/cjs/hooks/use-on-undo-calculated-column.js +70 -0
  184. package/dist/cjs/hooks/use-on-undo-table-auto-expansion.d.ts +28 -0
  185. package/dist/cjs/hooks/use-on-undo-table-auto-expansion.d.ts.map +1 -0
  186. package/dist/cjs/hooks/use-on-undo-table-auto-expansion.js +96 -0
  187. package/dist/cjs/hooks/use-on-update-named-range.d.ts +4 -2
  188. package/dist/cjs/hooks/use-on-update-named-range.d.ts.map +1 -1
  189. package/dist/cjs/hooks/use-on-update-named-range.js +13 -1
  190. package/dist/cjs/hooks/use-sheet-properties.d.ts +1 -0
  191. package/dist/cjs/hooks/use-sheet-properties.d.ts.map +1 -1
  192. package/dist/cjs/hooks/use-sheet-properties.js +54 -34
  193. package/dist/cjs/hooks/use-slicers.d.ts +2 -2
  194. package/dist/cjs/hooks/use-slicers.d.ts.map +1 -1
  195. package/dist/cjs/hooks/use-slicers.js +17 -26
  196. package/dist/cjs/hooks/use-sparkline-groups.d.ts +50 -0
  197. package/dist/cjs/hooks/use-sparkline-groups.d.ts.map +1 -0
  198. package/dist/cjs/hooks/use-sparkline-groups.js +192 -0
  199. package/dist/cjs/hooks/use-spreadsheet-state.d.ts +56 -10
  200. package/dist/cjs/hooks/use-spreadsheet-state.d.ts.map +1 -1
  201. package/dist/cjs/hooks/use-spreadsheet-state.js +322 -100
  202. package/dist/cjs/hooks/use-structured-reference.d.ts.map +1 -1
  203. package/dist/cjs/hooks/use-structured-reference.js +17 -0
  204. package/dist/cjs/hooks/use-undo-redo-actions.d.ts +2 -1
  205. package/dist/cjs/hooks/use-undo-redo-actions.d.ts.map +1 -1
  206. package/dist/cjs/hooks/use-undo-redo-actions.js +10 -2
  207. package/dist/cjs/hooks/use-undo-redo.d.ts +12 -0
  208. package/dist/cjs/hooks/use-undo-redo.d.ts.map +1 -1
  209. package/dist/cjs/hooks/use-undo-redo.js +169 -10
  210. package/dist/cjs/hooks/utils/sort-rows.d.ts.map +1 -1
  211. package/dist/cjs/hooks/utils/sort-rows.js +4 -3
  212. package/dist/cjs/index.d.ts +7 -0
  213. package/dist/cjs/index.d.ts.map +1 -1
  214. package/dist/cjs/index.js +8 -0
  215. package/dist/cjs/interface/apply-fill.d.ts +26 -3
  216. package/dist/cjs/interface/apply-fill.d.ts.map +1 -1
  217. package/dist/cjs/interface/apply-fill.js +207 -98
  218. package/dist/cjs/interface/change-batch.d.ts +1 -1
  219. package/dist/cjs/interface/change-batch.d.ts.map +1 -1
  220. package/dist/cjs/interface/change-batch.js +112 -15
  221. package/dist/cjs/interface/change-calculated-column.d.ts +6 -2
  222. package/dist/cjs/interface/change-calculated-column.d.ts.map +1 -1
  223. package/dist/cjs/interface/change-calculated-column.js +87 -17
  224. package/dist/cjs/interface/change-table-column.d.ts +81 -7
  225. package/dist/cjs/interface/change-table-column.d.ts.map +1 -1
  226. package/dist/cjs/interface/change-table-column.js +336 -76
  227. package/dist/cjs/interface/create-table.d.ts +15 -3
  228. package/dist/cjs/interface/create-table.d.ts.map +1 -1
  229. package/dist/cjs/interface/create-table.js +100 -25
  230. package/dist/cjs/interface/delete-cells-shift-left.d.ts +1 -1
  231. package/dist/cjs/interface/delete-cells-shift-left.d.ts.map +1 -1
  232. package/dist/cjs/interface/delete-cells-shift-left.js +10 -1
  233. package/dist/cjs/interface/delete-cells-shift-up.d.ts +1 -1
  234. package/dist/cjs/interface/delete-cells-shift-up.d.ts.map +1 -1
  235. package/dist/cjs/interface/delete-cells-shift-up.js +10 -1
  236. package/dist/cjs/interface/delete-cells.d.ts +1 -1
  237. package/dist/cjs/interface/delete-cells.d.ts.map +1 -1
  238. package/dist/cjs/interface/delete-cells.js +81 -25
  239. package/dist/cjs/interface/delete-column.d.ts +1 -1
  240. package/dist/cjs/interface/delete-column.d.ts.map +1 -1
  241. package/dist/cjs/interface/delete-column.js +9 -2
  242. package/dist/cjs/interface/delete-row.d.ts +1 -1
  243. package/dist/cjs/interface/delete-row.d.ts.map +1 -1
  244. package/dist/cjs/interface/delete-row.js +223 -18
  245. package/dist/cjs/interface/delete-sheet.d.ts +2 -2
  246. package/dist/cjs/interface/delete-sheet.d.ts.map +1 -1
  247. package/dist/cjs/interface/delete-sheet.js +118 -1
  248. package/dist/cjs/interface/delete-table-column.d.ts +1 -1
  249. package/dist/cjs/interface/delete-table-column.d.ts.map +1 -1
  250. package/dist/cjs/interface/delete-table-column.js +11 -1
  251. package/dist/cjs/interface/delete-table-row.d.ts +1 -1
  252. package/dist/cjs/interface/delete-table-row.d.ts.map +1 -1
  253. package/dist/cjs/interface/delete-table-row.js +361 -275
  254. package/dist/cjs/interface/duplicate-sheet.d.ts.map +1 -1
  255. package/dist/cjs/interface/duplicate-sheet.js +83 -31
  256. package/dist/cjs/interface/embeds.d.ts +10 -1
  257. package/dist/cjs/interface/embeds.d.ts.map +1 -1
  258. package/dist/cjs/interface/embeds.js +120 -6
  259. package/dist/cjs/interface/insert-cells-shift-down.d.ts +1 -1
  260. package/dist/cjs/interface/insert-cells-shift-down.d.ts.map +1 -1
  261. package/dist/cjs/interface/insert-cells-shift-down.js +10 -1
  262. package/dist/cjs/interface/insert-cells-shift-right.d.ts +1 -1
  263. package/dist/cjs/interface/insert-cells-shift-right.d.ts.map +1 -1
  264. package/dist/cjs/interface/insert-cells-shift-right.js +10 -1
  265. package/dist/cjs/interface/insert-column.d.ts +2 -2
  266. package/dist/cjs/interface/insert-column.d.ts.map +1 -1
  267. package/dist/cjs/interface/insert-column.js +67 -38
  268. package/dist/cjs/interface/insert-row.d.ts +1 -1
  269. package/dist/cjs/interface/insert-row.d.ts.map +1 -1
  270. package/dist/cjs/interface/insert-row.js +9 -2
  271. package/dist/cjs/interface/insert-table-row.d.ts +2 -1
  272. package/dist/cjs/interface/insert-table-row.d.ts.map +1 -1
  273. package/dist/cjs/interface/insert-table-row.js +70 -19
  274. package/dist/cjs/interface/remove-duplicates.d.ts +1 -1
  275. package/dist/cjs/interface/remove-duplicates.d.ts.map +1 -1
  276. package/dist/cjs/interface/remove-duplicates.js +46 -6
  277. package/dist/cjs/interface/remove-table.d.ts +1 -1
  278. package/dist/cjs/interface/remove-table.d.ts.map +1 -1
  279. package/dist/cjs/interface/remove-table.js +72 -16
  280. package/dist/cjs/interface/slicers.d.ts +12 -1
  281. package/dist/cjs/interface/slicers.d.ts.map +1 -1
  282. package/dist/cjs/interface/slicers.js +47 -2
  283. package/dist/cjs/interface/spreadsheet-interface.d.ts +1 -1
  284. package/dist/cjs/interface/spreadsheet-interface.d.ts.map +1 -1
  285. package/dist/cjs/interface/spreadsheet-interface.js +64 -1
  286. package/dist/cjs/interface/table-totalrow.d.ts +13 -1
  287. package/dist/cjs/interface/table-totalrow.d.ts.map +1 -1
  288. package/dist/cjs/interface/table-totalrow.js +107 -73
  289. package/dist/cjs/interface/table-utils.d.ts +59 -6
  290. package/dist/cjs/interface/table-utils.d.ts.map +1 -1
  291. package/dist/cjs/interface/table-utils.js +211 -15
  292. package/dist/cjs/interface/update-table.d.ts +16 -1
  293. package/dist/cjs/interface/update-table.d.ts.map +1 -1
  294. package/dist/cjs/interface/update-table.js +190 -44
  295. package/dist/cjs/sheet-cell.d.ts.map +1 -1
  296. package/dist/cjs/test-setup.d.ts.map +1 -1
  297. package/dist/cjs/test-setup.js +6 -0
  298. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  299. package/dist/cjs/validation-schema/table.schema.d.ts +11 -0
  300. package/dist/cjs/validation-schema/table.schema.d.ts.map +1 -1
  301. package/dist/cjs/validation-schema/table.schema.js +20 -3
  302. package/dist/esm/api/anchored-objects.d.ts +122 -6
  303. package/dist/esm/api/anchored-objects.d.ts.map +1 -1
  304. package/dist/esm/api/anchored-objects.js +375 -15
  305. package/dist/esm/api/copy-paste.d.ts +1 -2
  306. package/dist/esm/api/copy-paste.d.ts.map +1 -1
  307. package/dist/esm/api/copy-paste.js +1 -3
  308. package/dist/esm/api/filter.d.ts +15 -1
  309. package/dist/esm/api/filter.d.ts.map +1 -1
  310. package/dist/esm/api/filter.js +28 -0
  311. package/dist/esm/api/formula.d.ts +63 -0
  312. package/dist/esm/api/formula.d.ts.map +1 -1
  313. package/dist/esm/api/formula.js +235 -8
  314. package/dist/esm/api/paint-format.d.ts +22 -1
  315. package/dist/esm/api/paint-format.d.ts.map +1 -1
  316. package/dist/esm/api/paint-format.js +44 -1
  317. package/dist/esm/api/sort.d.ts +23 -1
  318. package/dist/esm/api/sort.d.ts.map +1 -1
  319. package/dist/esm/api/sort.js +45 -6
  320. package/dist/esm/api/structural-guards.d.ts +57 -0
  321. package/dist/esm/api/structural-guards.d.ts.map +1 -1
  322. package/dist/esm/api/structural-guards.js +85 -0
  323. package/dist/esm/api/structural-table-refs.d.ts +58 -3
  324. package/dist/esm/api/structural-table-refs.d.ts.map +1 -1
  325. package/dist/esm/api/structural-table-refs.js +126 -6
  326. package/dist/esm/api/table.d.ts +26 -2
  327. package/dist/esm/api/table.d.ts.map +1 -1
  328. package/dist/esm/api/table.js +70 -48
  329. package/dist/esm/api/validation.d.ts.map +1 -1
  330. package/dist/esm/api/validation.js +53 -8
  331. package/dist/esm/atoms/creating-table.atom.d.ts +22 -0
  332. package/dist/esm/atoms/creating-table.atom.d.ts.map +1 -0
  333. package/dist/esm/atoms/creating-table.atom.js +4 -0
  334. package/dist/esm/atoms/dialog-state.atom.d.ts +8 -0
  335. package/dist/esm/atoms/dialog-state.atom.d.ts.map +1 -1
  336. package/dist/esm/atoms/dialog-state.atom.js +12 -0
  337. package/dist/esm/atoms/editing-slicer.atom.d.ts +9 -0
  338. package/dist/esm/atoms/editing-slicer.atom.d.ts.map +1 -0
  339. package/dist/esm/atoms/editing-slicer.atom.js +6 -0
  340. package/dist/esm/atoms/index.d.ts +4 -0
  341. package/dist/esm/atoms/index.d.ts.map +1 -1
  342. package/dist/esm/atoms/index.js +4 -0
  343. package/dist/esm/atoms/inserting-slicer.atom.d.ts +8 -0
  344. package/dist/esm/atoms/inserting-slicer.atom.d.ts.map +1 -0
  345. package/dist/esm/atoms/inserting-slicer.atom.js +5 -0
  346. package/dist/esm/atoms/resizing-table.atom.d.ts +8 -0
  347. package/dist/esm/atoms/resizing-table.atom.d.ts.map +1 -0
  348. package/dist/esm/atoms/resizing-table.atom.js +5 -0
  349. package/dist/esm/commands.d.ts +129 -2
  350. package/dist/esm/commands.d.ts.map +1 -1
  351. package/dist/esm/components/editors/embed-editor.d.ts +4 -2
  352. package/dist/esm/components/editors/embed-editor.d.ts.map +1 -1
  353. package/dist/esm/components/editors/embed-editor.js +40 -6
  354. package/dist/esm/components/editors/slicer-editor.d.ts +15 -0
  355. package/dist/esm/components/editors/slicer-editor.d.ts.map +1 -0
  356. package/dist/esm/components/editors/slicer-editor.js +85 -0
  357. package/dist/esm/components/editors/table-editor.d.ts +58 -2
  358. package/dist/esm/components/editors/table-editor.d.ts.map +1 -1
  359. package/dist/esm/components/editors/table-editor.js +243 -19
  360. package/dist/esm/components/index.d.ts +1 -0
  361. package/dist/esm/components/index.d.ts.map +1 -1
  362. package/dist/esm/components/index.js +1 -0
  363. package/dist/esm/constants.d.ts +9 -1
  364. package/dist/esm/constants.d.ts.map +1 -1
  365. package/dist/esm/constants.js +12 -0
  366. package/dist/esm/generated-names.d.ts +13 -3
  367. package/dist/esm/generated-names.d.ts.map +1 -1
  368. package/dist/esm/generated-names.js +3 -1
  369. package/dist/esm/helpers.d.ts +5 -0
  370. package/dist/esm/helpers.d.ts.map +1 -1
  371. package/dist/esm/helpers.js +7 -1
  372. package/dist/esm/hooks/use-on-change-batch.d.ts +19 -2
  373. package/dist/esm/hooks/use-on-change-batch.d.ts.map +1 -1
  374. package/dist/esm/hooks/use-on-change-batch.js +19 -3
  375. package/dist/esm/hooks/use-on-change-calculated-column.d.ts +10 -1
  376. package/dist/esm/hooks/use-on-change-calculated-column.d.ts.map +1 -1
  377. package/dist/esm/hooks/use-on-change-calculated-column.js +17 -5
  378. package/dist/esm/hooks/use-on-change-table-column.d.ts +6 -1
  379. package/dist/esm/hooks/use-on-change-table-column.d.ts.map +1 -1
  380. package/dist/esm/hooks/use-on-change-table-column.js +17 -5
  381. package/dist/esm/hooks/use-on-change.d.ts +36 -3
  382. package/dist/esm/hooks/use-on-change.d.ts.map +1 -1
  383. package/dist/esm/hooks/use-on-change.js +214 -124
  384. package/dist/esm/hooks/use-on-create-custom-table-style.d.ts +17 -0
  385. package/dist/esm/hooks/use-on-create-custom-table-style.d.ts.map +1 -0
  386. package/dist/esm/hooks/use-on-create-custom-table-style.js +26 -0
  387. package/dist/esm/hooks/use-on-create-named-range.d.ts +4 -2
  388. package/dist/esm/hooks/use-on-create-named-range.d.ts.map +1 -1
  389. package/dist/esm/hooks/use-on-create-named-range.js +11 -1
  390. package/dist/esm/hooks/use-on-delete-cells-shift-left.d.ts +2 -1
  391. package/dist/esm/hooks/use-on-delete-cells-shift-left.d.ts.map +1 -1
  392. package/dist/esm/hooks/use-on-delete-cells-shift-left.js +3 -1
  393. package/dist/esm/hooks/use-on-delete-cells-shift-up.d.ts +2 -1
  394. package/dist/esm/hooks/use-on-delete-cells-shift-up.d.ts.map +1 -1
  395. package/dist/esm/hooks/use-on-delete-cells-shift-up.js +3 -1
  396. package/dist/esm/hooks/use-on-delete-column.d.ts +2 -1
  397. package/dist/esm/hooks/use-on-delete-column.d.ts.map +1 -1
  398. package/dist/esm/hooks/use-on-delete-column.js +3 -1
  399. package/dist/esm/hooks/use-on-delete-row.d.ts +2 -1
  400. package/dist/esm/hooks/use-on-delete-row.d.ts.map +1 -1
  401. package/dist/esm/hooks/use-on-delete-row.js +3 -1
  402. package/dist/esm/hooks/use-on-delete-sheet.d.ts +9 -1
  403. package/dist/esm/hooks/use-on-delete-sheet.d.ts.map +1 -1
  404. package/dist/esm/hooks/use-on-delete-sheet.js +17 -1
  405. package/dist/esm/hooks/use-on-delete-table-row.d.ts +4 -1
  406. package/dist/esm/hooks/use-on-delete-table-row.d.ts.map +1 -1
  407. package/dist/esm/hooks/use-on-delete-table-row.js +19 -1
  408. package/dist/esm/hooks/use-on-delete.d.ts +5 -2
  409. package/dist/esm/hooks/use-on-delete.d.ts.map +1 -1
  410. package/dist/esm/hooks/use-on-delete.js +5 -1
  411. package/dist/esm/hooks/use-on-embeds.d.ts +7 -4
  412. package/dist/esm/hooks/use-on-embeds.d.ts.map +1 -1
  413. package/dist/esm/hooks/use-on-embeds.js +23 -6
  414. package/dist/esm/hooks/use-on-fill.d.ts +17 -2
  415. package/dist/esm/hooks/use-on-fill.d.ts.map +1 -1
  416. package/dist/esm/hooks/use-on-fill.js +27 -1
  417. package/dist/esm/hooks/use-on-filter-table.d.ts.map +1 -1
  418. package/dist/esm/hooks/use-on-filter-table.js +97 -26
  419. package/dist/esm/hooks/use-on-import-excel.d.ts +2 -1
  420. package/dist/esm/hooks/use-on-import-excel.d.ts.map +1 -1
  421. package/dist/esm/hooks/use-on-import-excel.js +4 -1
  422. package/dist/esm/hooks/use-on-insert-cells-shift-down.d.ts +2 -1
  423. package/dist/esm/hooks/use-on-insert-cells-shift-down.d.ts.map +1 -1
  424. package/dist/esm/hooks/use-on-insert-cells-shift-down.js +3 -1
  425. package/dist/esm/hooks/use-on-insert-cells-shift-right.d.ts +2 -1
  426. package/dist/esm/hooks/use-on-insert-cells-shift-right.d.ts.map +1 -1
  427. package/dist/esm/hooks/use-on-insert-cells-shift-right.js +3 -1
  428. package/dist/esm/hooks/use-on-insert-column.d.ts +2 -1
  429. package/dist/esm/hooks/use-on-insert-column.d.ts.map +1 -1
  430. package/dist/esm/hooks/use-on-insert-column.js +3 -1
  431. package/dist/esm/hooks/use-on-insert-row.d.ts +2 -1
  432. package/dist/esm/hooks/use-on-insert-row.d.ts.map +1 -1
  433. package/dist/esm/hooks/use-on-insert-row.js +3 -1
  434. package/dist/esm/hooks/use-on-insert-table-row.d.ts +5 -2
  435. package/dist/esm/hooks/use-on-insert-table-row.d.ts.map +1 -1
  436. package/dist/esm/hooks/use-on-insert-table-row.js +19 -1
  437. package/dist/esm/hooks/use-on-merge-unmerge-cells.d.ts +3 -2
  438. package/dist/esm/hooks/use-on-merge-unmerge-cells.d.ts.map +1 -1
  439. package/dist/esm/hooks/use-on-merge-unmerge-cells.js +12 -1
  440. package/dist/esm/hooks/use-on-move-columns.d.ts +3 -1
  441. package/dist/esm/hooks/use-on-move-columns.d.ts.map +1 -1
  442. package/dist/esm/hooks/use-on-move-columns.js +14 -1
  443. package/dist/esm/hooks/use-on-move-rows.d.ts +3 -1
  444. package/dist/esm/hooks/use-on-move-rows.d.ts.map +1 -1
  445. package/dist/esm/hooks/use-on-move-rows.js +14 -1
  446. package/dist/esm/hooks/use-on-move-selection.d.ts +3 -1
  447. package/dist/esm/hooks/use-on-move-selection.d.ts.map +1 -1
  448. package/dist/esm/hooks/use-on-move-selection.js +44 -1
  449. package/dist/esm/hooks/use-on-paste.d.ts +22 -1
  450. package/dist/esm/hooks/use-on-paste.d.ts.map +1 -1
  451. package/dist/esm/hooks/use-on-paste.js +815 -672
  452. package/dist/esm/hooks/use-on-remove-duplicates.d.ts +5 -2
  453. package/dist/esm/hooks/use-on-remove-duplicates.d.ts.map +1 -1
  454. package/dist/esm/hooks/use-on-remove-duplicates.js +5 -1
  455. package/dist/esm/hooks/use-on-request-create-table.d.ts +13 -0
  456. package/dist/esm/hooks/use-on-request-create-table.d.ts.map +1 -0
  457. package/dist/esm/hooks/use-on-request-create-table.js +43 -0
  458. package/dist/esm/hooks/use-on-request-insert-slicer.d.ts +7 -0
  459. package/dist/esm/hooks/use-on-request-insert-slicer.d.ts.map +1 -0
  460. package/dist/esm/hooks/use-on-request-insert-slicer.js +15 -0
  461. package/dist/esm/hooks/use-on-request-resize-table.d.ts +7 -0
  462. package/dist/esm/hooks/use-on-request-resize-table.d.ts.map +1 -0
  463. package/dist/esm/hooks/use-on-request-resize-table.js +15 -0
  464. package/dist/esm/hooks/use-on-resize-table.d.ts +5 -1
  465. package/dist/esm/hooks/use-on-resize-table.d.ts.map +1 -1
  466. package/dist/esm/hooks/use-on-resize-table.js +107 -27
  467. package/dist/esm/hooks/use-on-sort-column.d.ts +28 -3
  468. package/dist/esm/hooks/use-on-sort-column.d.ts.map +1 -1
  469. package/dist/esm/hooks/use-on-sort-column.js +105 -68
  470. package/dist/esm/hooks/use-on-sort-range.d.ts +26 -3
  471. package/dist/esm/hooks/use-on-sort-range.d.ts.map +1 -1
  472. package/dist/esm/hooks/use-on-sort-range.js +100 -64
  473. package/dist/esm/hooks/use-on-sort-table.d.ts +18 -1
  474. package/dist/esm/hooks/use-on-sort-table.d.ts.map +1 -1
  475. package/dist/esm/hooks/use-on-sort-table.js +107 -86
  476. package/dist/esm/hooks/use-on-subtotal.d.ts +10 -3
  477. package/dist/esm/hooks/use-on-subtotal.d.ts.map +1 -1
  478. package/dist/esm/hooks/use-on-subtotal.js +7 -5
  479. package/dist/esm/hooks/use-on-table.d.ts +39 -7
  480. package/dist/esm/hooks/use-on-table.d.ts.map +1 -1
  481. package/dist/esm/hooks/use-on-table.js +234 -26
  482. package/dist/esm/hooks/use-on-undo-calculated-column.d.ts +23 -0
  483. package/dist/esm/hooks/use-on-undo-calculated-column.d.ts.map +1 -0
  484. package/dist/esm/hooks/use-on-undo-calculated-column.js +62 -0
  485. package/dist/esm/hooks/use-on-undo-table-auto-expansion.d.ts +28 -0
  486. package/dist/esm/hooks/use-on-undo-table-auto-expansion.d.ts.map +1 -0
  487. package/dist/esm/hooks/use-on-undo-table-auto-expansion.js +75 -0
  488. package/dist/esm/hooks/use-on-update-named-range.d.ts +4 -2
  489. package/dist/esm/hooks/use-on-update-named-range.d.ts.map +1 -1
  490. package/dist/esm/hooks/use-on-update-named-range.js +13 -1
  491. package/dist/esm/hooks/use-sheet-properties.d.ts +1 -0
  492. package/dist/esm/hooks/use-sheet-properties.d.ts.map +1 -1
  493. package/dist/esm/hooks/use-sheet-properties.js +38 -19
  494. package/dist/esm/hooks/use-slicers.d.ts +2 -2
  495. package/dist/esm/hooks/use-slicers.d.ts.map +1 -1
  496. package/dist/esm/hooks/use-slicers.js +16 -8
  497. package/dist/esm/hooks/use-sparkline-groups.d.ts +50 -0
  498. package/dist/esm/hooks/use-sparkline-groups.d.ts.map +1 -0
  499. package/dist/esm/hooks/use-sparkline-groups.js +146 -0
  500. package/dist/esm/hooks/use-spreadsheet-state.d.ts +56 -10
  501. package/dist/esm/hooks/use-spreadsheet-state.d.ts.map +1 -1
  502. package/dist/esm/hooks/use-spreadsheet-state.js +259 -30
  503. package/dist/esm/hooks/use-structured-reference.d.ts.map +1 -1
  504. package/dist/esm/hooks/use-structured-reference.js +17 -0
  505. package/dist/esm/hooks/use-undo-redo-actions.d.ts +2 -1
  506. package/dist/esm/hooks/use-undo-redo-actions.d.ts.map +1 -1
  507. package/dist/esm/hooks/use-undo-redo-actions.js +8 -2
  508. package/dist/esm/hooks/use-undo-redo.d.ts +12 -0
  509. package/dist/esm/hooks/use-undo-redo.d.ts.map +1 -1
  510. package/dist/esm/hooks/use-undo-redo.js +158 -7
  511. package/dist/esm/hooks/utils/sort-rows.d.ts.map +1 -1
  512. package/dist/esm/hooks/utils/sort-rows.js +4 -3
  513. package/dist/esm/index.d.ts +7 -0
  514. package/dist/esm/index.d.ts.map +1 -1
  515. package/dist/esm/index.js +8 -0
  516. package/dist/esm/interface/apply-fill.d.ts +26 -3
  517. package/dist/esm/interface/apply-fill.d.ts.map +1 -1
  518. package/dist/esm/interface/apply-fill.js +188 -88
  519. package/dist/esm/interface/change-batch.d.ts +1 -1
  520. package/dist/esm/interface/change-batch.d.ts.map +1 -1
  521. package/dist/esm/interface/change-batch.js +89 -8
  522. package/dist/esm/interface/change-calculated-column.d.ts +6 -2
  523. package/dist/esm/interface/change-calculated-column.d.ts.map +1 -1
  524. package/dist/esm/interface/change-calculated-column.js +81 -16
  525. package/dist/esm/interface/change-table-column.d.ts +81 -7
  526. package/dist/esm/interface/change-table-column.d.ts.map +1 -1
  527. package/dist/esm/interface/change-table-column.js +295 -67
  528. package/dist/esm/interface/create-table.d.ts +15 -3
  529. package/dist/esm/interface/create-table.d.ts.map +1 -1
  530. package/dist/esm/interface/create-table.js +103 -27
  531. package/dist/esm/interface/delete-cells-shift-left.d.ts +1 -1
  532. package/dist/esm/interface/delete-cells-shift-left.d.ts.map +1 -1
  533. package/dist/esm/interface/delete-cells-shift-left.js +10 -1
  534. package/dist/esm/interface/delete-cells-shift-up.d.ts +1 -1
  535. package/dist/esm/interface/delete-cells-shift-up.d.ts.map +1 -1
  536. package/dist/esm/interface/delete-cells-shift-up.js +10 -1
  537. package/dist/esm/interface/delete-cells.d.ts +1 -1
  538. package/dist/esm/interface/delete-cells.d.ts.map +1 -1
  539. package/dist/esm/interface/delete-cells.js +47 -14
  540. package/dist/esm/interface/delete-column.d.ts +1 -1
  541. package/dist/esm/interface/delete-column.d.ts.map +1 -1
  542. package/dist/esm/interface/delete-column.js +9 -2
  543. package/dist/esm/interface/delete-row.d.ts +1 -1
  544. package/dist/esm/interface/delete-row.d.ts.map +1 -1
  545. package/dist/esm/interface/delete-row.js +173 -15
  546. package/dist/esm/interface/delete-sheet.d.ts +2 -2
  547. package/dist/esm/interface/delete-sheet.d.ts.map +1 -1
  548. package/dist/esm/interface/delete-sheet.js +113 -1
  549. package/dist/esm/interface/delete-table-column.d.ts +1 -1
  550. package/dist/esm/interface/delete-table-column.d.ts.map +1 -1
  551. package/dist/esm/interface/delete-table-column.js +11 -1
  552. package/dist/esm/interface/delete-table-row.d.ts +1 -1
  553. package/dist/esm/interface/delete-table-row.d.ts.map +1 -1
  554. package/dist/esm/interface/delete-table-row.js +312 -232
  555. package/dist/esm/interface/duplicate-sheet.d.ts.map +1 -1
  556. package/dist/esm/interface/duplicate-sheet.js +73 -26
  557. package/dist/esm/interface/embeds.d.ts +10 -1
  558. package/dist/esm/interface/embeds.d.ts.map +1 -1
  559. package/dist/esm/interface/embeds.js +84 -5
  560. package/dist/esm/interface/insert-cells-shift-down.d.ts +1 -1
  561. package/dist/esm/interface/insert-cells-shift-down.d.ts.map +1 -1
  562. package/dist/esm/interface/insert-cells-shift-down.js +10 -1
  563. package/dist/esm/interface/insert-cells-shift-right.d.ts +1 -1
  564. package/dist/esm/interface/insert-cells-shift-right.d.ts.map +1 -1
  565. package/dist/esm/interface/insert-cells-shift-right.js +10 -1
  566. package/dist/esm/interface/insert-column.d.ts +2 -2
  567. package/dist/esm/interface/insert-column.d.ts.map +1 -1
  568. package/dist/esm/interface/insert-column.js +48 -23
  569. package/dist/esm/interface/insert-row.d.ts +1 -1
  570. package/dist/esm/interface/insert-row.d.ts.map +1 -1
  571. package/dist/esm/interface/insert-row.js +9 -2
  572. package/dist/esm/interface/insert-table-row.d.ts +2 -1
  573. package/dist/esm/interface/insert-table-row.d.ts.map +1 -1
  574. package/dist/esm/interface/insert-table-row.js +67 -12
  575. package/dist/esm/interface/remove-duplicates.d.ts +1 -1
  576. package/dist/esm/interface/remove-duplicates.d.ts.map +1 -1
  577. package/dist/esm/interface/remove-duplicates.js +41 -6
  578. package/dist/esm/interface/remove-table.d.ts +1 -1
  579. package/dist/esm/interface/remove-table.d.ts.map +1 -1
  580. package/dist/esm/interface/remove-table.js +58 -10
  581. package/dist/esm/interface/slicers.d.ts +12 -1
  582. package/dist/esm/interface/slicers.d.ts.map +1 -1
  583. package/dist/esm/interface/slicers.js +44 -2
  584. package/dist/esm/interface/spreadsheet-interface.d.ts +1 -1
  585. package/dist/esm/interface/spreadsheet-interface.d.ts.map +1 -1
  586. package/dist/esm/interface/spreadsheet-interface.js +73 -1
  587. package/dist/esm/interface/table-totalrow.d.ts +13 -1
  588. package/dist/esm/interface/table-totalrow.d.ts.map +1 -1
  589. package/dist/esm/interface/table-totalrow.js +98 -68
  590. package/dist/esm/interface/table-utils.d.ts +59 -6
  591. package/dist/esm/interface/table-utils.d.ts.map +1 -1
  592. package/dist/esm/interface/table-utils.js +155 -14
  593. package/dist/esm/interface/update-table.d.ts +16 -1
  594. package/dist/esm/interface/update-table.d.ts.map +1 -1
  595. package/dist/esm/interface/update-table.js +203 -42
  596. package/dist/esm/sheet-cell.d.ts.map +1 -1
  597. package/dist/esm/test-setup.d.ts.map +1 -1
  598. package/dist/esm/test-setup.js +6 -0
  599. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  600. package/dist/esm/validation-schema/table.schema.d.ts +11 -0
  601. package/dist/esm/validation-schema/table.schema.d.ts.map +1 -1
  602. package/dist/esm/validation-schema/table.schema.js +15 -2
  603. package/package.json +19 -11
@@ -6,6 +6,7 @@ import { isSelectionACell, useGetEffectiveValuesFromRange, } from "@rowsncolumns
6
6
  import { error, getCellFormattedValue, getCellUserEnteredFormat, getCellUserEnteredValue, getExtendedValueBool, getExtendedValueFormula, getExtendedValueNumber, getExtendedValueString, isNil, iterateCellsInRange, uuidString, } from "@rowsncolumns/utils";
7
7
  import { produceWithPatches } from "immer";
8
8
  import { useCallback } from "react";
9
+ import { moveChartsOnRangeMove } from "../api/anchored-objects";
9
10
  import { processSideEffectDependentCells } from "../api/dependency";
10
11
  import { createSheetCellIdentifier } from "../api/formula";
11
12
  import { createSheetDraft } from "../api/immer-utils";
@@ -13,9 +14,12 @@ import { findPartiallyCoveredMerge, MERGED_CELL_MOVE_ERROR } from "../api/merges
13
14
  import { moveRange } from "../api/selection";
14
15
  import { useShowError } from "../atoms/error-state.atom";
15
16
  import { applyPasteOperation, isBlankClipboardCell, resolvePasteSpecialOptions, } from "../api/paste-special";
16
- import { findAdjacentTable, findTableColumnIndex } from "../api/table";
17
- import { addCalculatedColumnsForRowExpansion } from "../interface/change-table-column";
17
+ import { getMoveRangeRefusal } from "../api/structural-guards";
18
+ import { renameHeaderCellsInFormulas } from "../api/structural-table-refs";
19
+ import { findAdjacentTable } from "../api/table";
20
+ import { getNextTableTitle } from "../helpers";
18
21
  import { collectDataValidationTarget, extendDataValidationRanges, } from "../interface/data-validation-utils";
22
+ import { planHeaderCellRenames } from "../interface/change-table-column";
19
23
  import { SheetCell } from "../sheet-cell";
20
24
  import { extractFontFamily, generateDataFromClipboard, pickFormatting, pickFormula, pickValue, transpose, } from "./../api/copy-paste";
21
25
  import { useCalculationQueue } from "./use-calculation-queue";
@@ -36,7 +40,7 @@ export const buildDestinationRowAssignments = (sheetId, startRowIndex, endRowInd
36
40
  }
37
41
  return assignments;
38
42
  };
39
- export const useOnPaste = ({ rowCount, columnCount, locale, sheetData, tables: currentTables, maxRowCount = MAX_ROW_COUNT, maxColumnCount = MAX_COLUMN_COUNT, isHiddenByFilterRow, onRequestFonts, idCreationStrategy, createHistory, enqueueCalculation, enqueueStructureChange, enqueueGraphOperation, onChangeSheetData, onChangeSheets, onChangeTables, onChangeEmbeds, onChangeSelections, onChangeActiveCell, getDependents, getActiveCell, getUserEnteredValue, onChangeDataValidations, onChangeNamedRanges, getSheetMerges, preserveFormatting = true, cellXfsRegistry, sharedStringRegistry, getDataValidationById, getSheetName, onError, citations, onChangeCitations, sanitizeHtml, onCommand, generatedNames, }) => {
43
+ export const useOnPaste = ({ rowCount, columnCount, locale, sheetData, tables: currentTables, maxRowCount = MAX_ROW_COUNT, maxColumnCount = MAX_COLUMN_COUNT, isHiddenByFilterRow, onRequestFonts, idCreationStrategy, createHistory, enqueueCalculation, enqueueStructureChange, enqueueGraphOperation, onChangeSheetData, onChangeSheets, onChangeTables, onChangeEmbeds, onChangeSelections, onChangeActiveCell, getDependents, getActiveCell, getUserEnteredValue, onChangeDataValidations, onChangeNamedRanges, onChangeCharts, getSheetMerges, preserveFormatting = true, cellXfsRegistry, sharedStringRegistry, getDataValidationById, getSheetName, onError, citations, onChangeCitations, sanitizeHtml, onCommand, generatedNames, batchHistory = (action) => action(), autoExpandTables = true, autoCalculatedColumns = true, }) => {
40
44
  const canEditCellRange = useCanEditCellRange();
41
45
  const showError = useShowError();
42
46
  // Allowed values
@@ -51,6 +55,7 @@ export const useOnPaste = ({ rowCount, columnCount, locale, sheetData, tables: c
51
55
  onChangeTables,
52
56
  getSheetName,
53
57
  onCommand,
58
+ autoCalculatedColumns,
54
59
  });
55
60
  const onChangeTableColumn = useOnChangeTableColumn({
56
61
  locale,
@@ -59,9 +64,11 @@ export const useOnPaste = ({ rowCount, columnCount, locale, sheetData, tables: c
59
64
  enqueueGraphOperation,
60
65
  onChangeSheetData,
61
66
  onChangeTables,
67
+ onChangeCharts,
62
68
  getDependents,
63
69
  onCommand,
64
70
  generatedNames,
71
+ tables: currentTables,
65
72
  });
66
73
  const redrawGrid = useRedrawGrid();
67
74
  const getFinalRowHeight = useGetFinalRowHeight();
@@ -101,7 +108,7 @@ export const useOnPaste = ({ rowCount, columnCount, locale, sheetData, tables: c
101
108
  }
102
109
  }
103
110
  else {
104
- const pasteResults = await generateDataFromClipboard(e, activeCell, destinationSheetId, activeSheetName, preserveFormatting, locale, idCreationStrategy, forcePlainText, sanitizeHtml, generatedNames);
111
+ const pasteResults = await generateDataFromClipboard(e, activeCell, destinationSheetId, activeSheetName, preserveFormatting, locale, idCreationStrategy, forcePlainText, sanitizeHtml);
105
112
  selectedRowValues = pasteResults?.results ?? [];
106
113
  merges = pasteResults?.merges;
107
114
  embeds = pasteResults?.embeds;
@@ -125,8 +132,6 @@ export const useOnPaste = ({ rowCount, columnCount, locale, sheetData, tables: c
125
132
  else if (pasteMode === "values") {
126
133
  selectedRowValues = pickValue(selectedRowValues, destinationSheetId, locale);
127
134
  }
128
- const saveHistory = createHistory();
129
- const dataValidationTargets = new Map();
130
135
  const fontFamilies = extractFontFamily(selectedRowValues);
131
136
  // Wait for fonts to load
132
137
  if (fontFamilies.length && preserveFormatting) {
@@ -146,753 +151,887 @@ export const useOnPaste = ({ rowCount, columnCount, locale, sheetData, tables: c
146
151
  error("Error loading webfonts", fontFamilies, err);
147
152
  }
148
153
  }
149
- const [rowSpan, colSpan] = [
150
- selectedRowValues?.length ?? 0,
151
- // For cut operations, use range dimensions since data may be sparse
152
- isCutOperation && from
153
- ? from.range.endColumnIndex - from.range.startColumnIndex + 1
154
- : selectedRowValues[0]?.length ?? 0,
155
- ];
156
- const to = selections?.[selections?.length - 1] ??
157
- selectionFromActiveCell(activeCell)[0];
158
- const rowDelta = from && to ? to.range.startRowIndex - from.range.startRowIndex : -1;
159
- const columnDelta = from && to
160
- ? to.range.startColumnIndex - from.range.startColumnIndex
161
- : -1;
162
- // When user enters a value in the last row of a
163
- // table and if the entire row is empty
164
- const [adjacentTable, isRowExpansion, isColumnExpansion] = findAdjacentTable(destinationSheetId, activeCell, currentTables, getUserEnteredValue);
165
- const currentTable = isColumnExpansion && adjacentTable
166
- ? adjacentTable
167
- : findActiveTableWithinCell(destinationSheetId, activeCell, currentTables);
168
- // Next selections
169
- const nextSelections = finalSelections?.length ? finalSelections : [to];
170
- // Update range based on length of data
171
- to.range.endRowIndex = Math.min(maxRowCount, Math.max(to.range.endRowIndex, to.range.startRowIndex + rowSpan - 1));
172
- to.range.endColumnIndex = Math.min(maxColumnCount, Math.max(to.range.endColumnIndex, to.range.startColumnIndex + colSpan - 1));
173
- // Check for protected range
174
- if (!canEditCellRange(destinationSheetId, to.range)) {
175
- console.debug("Protected range, You cannot paste on to protected cells.");
176
- return;
177
- }
178
- // A cut is a move: Excel refuses it when the destination (or the source) covers a merged
179
- // cell only partially — writing into a non-anchor cell of a merge would tear it.
180
- if (isCutOperation &&
181
- from &&
182
- !isNil(sourceSheetId) &&
183
- (findPartiallyCoveredMerge(to.range, getSheetMerges?.(destinationSheetId)) ||
184
- findPartiallyCoveredMerge(from.range, getSheetMerges?.(sourceSheetId)))) {
185
- showError({ message: MERGED_CELL_MOVE_ERROR });
186
- return;
187
- }
188
- // Check if pasting a table would overlap with an existing table
189
- if (tables?.length) {
190
- const existingTable = currentTables?.find((table) => table.sheetId === destinationSheetId &&
191
- areaIntersects(to.range, table.range));
192
- if (existingTable) {
193
- onError?.("Cannot paste a table over another table. The paste range overlaps with an existing table.");
154
+ // From here on the paste is synchronous: its writes and the table growth / calculated-column
155
+ // fill they trigger open ONE undo entry.
156
+ batchHistory(() => {
157
+ const saveHistory = createHistory();
158
+ const dataValidationTargets = new Map();
159
+ const [rowSpan, colSpan] = [
160
+ selectedRowValues?.length ?? 0,
161
+ // For cut operations, use range dimensions since data may be sparse
162
+ isCutOperation && from
163
+ ? from.range.endColumnIndex - from.range.startColumnIndex + 1
164
+ : selectedRowValues[0]?.length ?? 0,
165
+ ];
166
+ const to = selections?.[selections?.length - 1] ??
167
+ selectionFromActiveCell(activeCell)[0];
168
+ const rowDelta = from && to ? to.range.startRowIndex - from.range.startRowIndex : -1;
169
+ const columnDelta = from && to
170
+ ? to.range.startColumnIndex - from.range.startColumnIndex
171
+ : -1;
172
+ // A cut is a move: a table the cut block covers whole travels with it (Excel; the rnc
173
+ // engine's `move-range` does the same), so it is neither the table the paste writes into
174
+ // nor one the paste grows.
175
+ const movedTables = isCutOperation && from && !isNil(sourceSheetId)
176
+ ? currentTables?.filter((table) => table.sheetId === sourceSheetId &&
177
+ areaInsideArea(table.range, from.range)) ?? []
178
+ : [];
179
+ const stayingTables = movedTables.length
180
+ ? currentTables?.filter((table) => !movedTables.includes(table))
181
+ : currentTables;
182
+ // When user enters a value in the last row of a
183
+ // table and if the entire row is empty
184
+ const [adjacentTable, isRowExpansion, isColumnExpansion] = autoExpandTables
185
+ ? findAdjacentTable(destinationSheetId, activeCell, stayingTables, getUserEnteredValue)
186
+ : [undefined, false, false];
187
+ const currentTable = isColumnExpansion && adjacentTable
188
+ ? adjacentTable
189
+ : findActiveTableWithinCell(destinationSheetId, activeCell, stayingTables);
190
+ // Next selections
191
+ const nextSelections = finalSelections?.length ? finalSelections : [to];
192
+ // Update range based on length of data
193
+ to.range.endRowIndex = Math.min(maxRowCount, Math.max(to.range.endRowIndex, to.range.startRowIndex + rowSpan - 1));
194
+ to.range.endColumnIndex = Math.min(maxColumnCount, Math.max(to.range.endColumnIndex, to.range.startColumnIndex + colSpan - 1));
195
+ // Check for protected range
196
+ if (!canEditCellRange(destinationSheetId, to.range)) {
197
+ console.debug("Protected range, You cannot paste on to protected cells.");
194
198
  return;
195
199
  }
196
- }
197
- const destinationRows = buildDestinationRowAssignments(destinationSheetId, to.range.startRowIndex, to.range.endRowIndex, rowSpan, isHiddenByFilterRow);
198
- if (!destinationRows.length) {
199
- return;
200
- }
201
- // Paste writes through `onChangeSheetData` directly, so the
202
- // calculator's per-cell invalidation never fires for the
203
- // destination cells. Invalidate the destination rect — and the
204
- // source on cut, since those cells are cleared too.
205
- enqueueStructureChange?.({
206
- kind: "invalidate-range",
207
- sheetId: destinationSheetId,
208
- startRowIndex: to.range.startRowIndex,
209
- endRowIndex: to.range.endRowIndex,
210
- startColumnIndex: to.range.startColumnIndex,
211
- endColumnIndex: to.range.endColumnIndex,
212
- });
213
- if (isCutOperation && from && !isNil(sourceSheetId)) {
200
+ // A cut is a move: Excel refuses it when the destination (or the source) covers a merged
201
+ // cell only partially — writing into a non-anchor cell of a merge would tear it.
202
+ if (isCutOperation &&
203
+ from &&
204
+ !isNil(sourceSheetId) &&
205
+ (findPartiallyCoveredMerge(to.range, getSheetMerges?.(destinationSheetId)) ||
206
+ findPartiallyCoveredMerge(from.range, getSheetMerges?.(sourceSheetId)))) {
207
+ showError({ message: MERGED_CELL_MOVE_ERROR });
208
+ return;
209
+ }
210
+ // …and Excel never moves PART of a table, nor lands a block on another table's cells — the
211
+ // drag-move refusals (T-46) apply to a cut + paste too, across sheets (T-79).
212
+ if (isCutOperation && from && !isNil(sourceSheetId)) {
213
+ const tableRefusal = getMoveRangeRefusal({
214
+ sheetId: sourceSheetId,
215
+ from: from.range,
216
+ to: to.range,
217
+ toSheetId: destinationSheetId,
218
+ tables: currentTables,
219
+ });
220
+ if (tableRefusal) {
221
+ showError({ title: tableRefusal.title, message: tableRefusal.message });
222
+ return;
223
+ }
224
+ }
225
+ // Check if pasting a table would overlap with an existing table
226
+ if (tables?.length) {
227
+ const existingTable = currentTables?.find((table) => table.sheetId === destinationSheetId &&
228
+ areaIntersects(to.range, table.range));
229
+ if (existingTable) {
230
+ onError?.("Cannot paste a table over another table. The paste range overlaps with an existing table.");
231
+ return;
232
+ }
233
+ }
234
+ const destinationRows = buildDestinationRowAssignments(destinationSheetId, to.range.startRowIndex, to.range.endRowIndex, rowSpan, isHiddenByFilterRow);
235
+ if (!destinationRows.length) {
236
+ return;
237
+ }
238
+ // Paste writes through `onChangeSheetData` directly, so the
239
+ // calculator's per-cell invalidation never fires for the
240
+ // destination cells. Invalidate the destination rect — and the
241
+ // source on cut, since those cells are cleared too.
214
242
  enqueueStructureChange?.({
215
243
  kind: "invalidate-range",
216
- sheetId: sourceSheetId,
217
- startRowIndex: from.range.startRowIndex,
218
- endRowIndex: from.range.endRowIndex,
219
- startColumnIndex: from.range.startColumnIndex,
220
- endColumnIndex: from.range.endColumnIndex,
244
+ sheetId: destinationSheetId,
245
+ startRowIndex: to.range.startRowIndex,
246
+ endRowIndex: to.range.endRowIndex,
247
+ startColumnIndex: to.range.startColumnIndex,
248
+ endColumnIndex: to.range.endColumnIndex,
221
249
  });
222
- }
223
- const visibleRowIndexes = destinationRows.map(({ rowIndex }) => rowIndex);
224
- // Check if the user is editing a table column
225
- const tableHeaderColumnIndex = findTableColumnIndex(destinationSheetId, activeCell, currentTables);
226
- // Adds new column to table and cell to sheet
227
- const cellValue = selectedRowValues?.[0]?.[0];
228
- const formattedValue = getCellFormattedValue(cellValue);
229
- const sharedStrings = sharedStringRegistry?.getSharedStrings();
230
- const sharedStringValue = cellValue?.ss == null || !sharedStrings
231
- ? undefined
232
- : sharedStrings.get(String(cellValue.ss));
233
- const activeCellValue = typeof formattedValue === "string"
234
- ? formattedValue
235
- : typeof sharedStringValue === "string"
236
- ? sharedStringValue
250
+ if (isCutOperation && from && !isNil(sourceSheetId)) {
251
+ enqueueStructureChange?.({
252
+ kind: "invalidate-range",
253
+ sheetId: sourceSheetId,
254
+ startRowIndex: from.range.startRowIndex,
255
+ endRowIndex: from.range.endRowIndex,
256
+ startColumnIndex: from.range.startColumnIndex,
257
+ endColumnIndex: from.range.endColumnIndex,
258
+ });
259
+ }
260
+ const visibleRowIndexes = destinationRows.map(({ rowIndex }) => rowIndex);
261
+ // Adds new column to table and cell to sheet
262
+ const sharedStrings = sharedStringRegistry?.getSharedStrings();
263
+ const pastedCellText = (cellValue) => {
264
+ const formattedValue = getCellFormattedValue(cellValue);
265
+ const sharedStringValue = cellValue?.ss == null || !sharedStrings
266
+ ? undefined
267
+ : sharedStrings.get(String(cellValue.ss));
268
+ return typeof formattedValue === "string"
269
+ ? formattedValue
270
+ : typeof sharedStringValue === "string"
271
+ ? sharedStringValue
272
+ : undefined;
273
+ };
274
+ const activeCellValue = pastedCellText(selectedRowValues?.[0]?.[0]);
275
+ // A block pasted right of the table names every new column from its own header cell.
276
+ const pastedHeaderValues = isColumnExpansion &&
277
+ adjacentTable &&
278
+ activeCell.rowIndex === adjacentTable.range.startRowIndex
279
+ ? selectedRowValues?.[0]?.map(pastedCellText)
237
280
  : undefined;
238
- // We need to track this for history. Precedent cells
239
- const recalcCells = new Map();
240
- // Expand table if user is pasting
241
- // table data
242
- // Same undo history
243
- if (!isNil(currentTable) && !isRowExpansion) {
244
- const newEndRowIndex = Math.max(currentTable.range.endRowIndex, activeCell.rowIndex + rowSpan - 1 + (currentTable.totalRow ? 1 : 0));
245
- // Update table range
246
- onChangeTables?.((prevTableData) => {
247
- const [nextState, patches, inversePatches] = produceWithPatches(prevTableData, (draft) => {
248
- const table = draft.find((table) => currentTable?.id === table.id);
249
- if (table) {
250
- table.range.endRowIndex = newEndRowIndex;
251
- // Update table name
252
- if (!isNil(tableHeaderColumnIndex)) {
253
- if (table.columns?.length) {
254
- if (!table.columns[tableHeaderColumnIndex]) {
255
- table.columns[tableHeaderColumnIndex] = {
256
- name: String(activeCellValue),
257
- };
258
- }
259
- else {
260
- // Update name
261
- table.columns[tableHeaderColumnIndex].name =
262
- String(activeCellValue);
263
- }
264
- }
265
- }
281
+ // Header cells of existing tables the paste lands on take the typed-header
282
+ // rule (text, de-duplicated, structured references following); a cut moves
283
+ // cells as they are and a formats-only paste writes no values.
284
+ const headerRenames = !isCutOperation && pasteMode !== "formats"
285
+ ? planHeaderCellRenames({
286
+ sheetId: destinationSheetId,
287
+ tables: stayingTables,
288
+ generatedNames,
289
+ cells: destinationRows.flatMap(({ rowIndex, dataRowIndex }) => Array.from({
290
+ length: to.range.endColumnIndex - to.range.startColumnIndex + 1,
291
+ }, (_, cursor) => ({
292
+ rowIndex,
293
+ columnIndex: to.range.startColumnIndex + cursor,
294
+ value: pastedCellText(selectedRowValues[dataRowIndex]?.[colSpan > 0 ? cursor % colSpan : 0]),
295
+ }))),
296
+ })
297
+ : [];
298
+ const headerRenameAt = new Map(headerRenames.map((rename) => [
299
+ `${rename.rowIndex}:${rename.columnIndex}`,
300
+ rename,
301
+ ]));
302
+ // We need to track this for history. Precedent cells
303
+ const recalcCells = new Map();
304
+ // Expand table if user is pasting
305
+ // table data
306
+ // Same undo history
307
+ if (!isNil(currentTable) && !isRowExpansion) {
308
+ // The overflow grows the table row by row and stops at the first row another table
309
+ // occupies (Excel; same rule as the adjacent-row growth in `changeTableColumn`). Cells
310
+ // pasted past that row stay plain cells.
311
+ let newEndRowIndex = currentTable.range.endRowIndex;
312
+ const lastOverflowRowIndex = activeCell.rowIndex + rowSpan - 1 + (currentTable.totalRow ? 1 : 0);
313
+ for (let rowIndex = currentTable.range.endRowIndex + 1; rowIndex <= lastOverflowRowIndex; rowIndex++) {
314
+ const line = {
315
+ ...currentTable.range,
316
+ startRowIndex: rowIndex,
317
+ endRowIndex: rowIndex,
318
+ };
319
+ if (stayingTables?.some((other) => other.id !== currentTable.id &&
320
+ other.sheetId === destinationSheetId &&
321
+ areaIntersects(other.range, line))) {
322
+ break;
266
323
  }
267
- });
268
- saveHistory({
269
- tables: { patches, inversePatches },
270
- });
271
- return nextState;
272
- });
273
- }
274
- // Update sheetdata
275
- // Capture the produced state so we can stream the exact written cells to an engine
276
- // consumer afterwards (branch-agnostic across cut / pure-paste / paste-special).
277
- let pastedSheetData;
278
- if (selectedRowValues.length) {
279
- onChangeSheetData?.((prevSheetData) => {
280
- const [nextState, patches, inversePatches] = produceWithPatches(prevSheetData, (draft) => {
281
- // For cut operation
282
- const movedKeys = new Set();
283
- /**
284
- * If user is deleting source cells,
285
- * let update its dependents and mark it as dirty
286
- */
287
- if (isCutOperation && from && to && !isNil(sourceSheetId)) {
288
- const sheetId = sourceSheetId;
289
- for (const [rowIndex, columnIndex] of iterateCellsInRange(from.range)) {
290
- // Process dependents
291
- processSideEffectDependentCells({
292
- draft,
293
- rowIndex,
294
- columnIndex,
295
- sheetId,
296
- destinationSheetId,
297
- columnDelta,
298
- enqueueGraphOperation,
299
- enqueueCalculation: enqueue,
300
- getDependents,
301
- recalcCells,
302
- rowDelta,
303
- sourceRange: from.range,
304
- movedKeys,
305
- locale,
306
- rowCount,
307
- columnCount,
308
- });
309
- }
310
- // Snapshot source after dependent/formula rewrites, before
311
- // clearing it. The pre-cut clipboard snapshot still contains
312
- // stale formulas, so writing that snapshot would discard the
313
- // reference updates performed above.
314
- const movedRowValues = [];
315
- const sourceStartColumn = from.range.startColumnIndex;
316
- const sourceEndColumn = from.range.endColumnIndex + 1;
317
- for (let rowIndex = from.range.startRowIndex; rowIndex <= from.range.endRowIndex; rowIndex++) {
318
- movedRowValues.push((draft[sheetId]?.[rowIndex]?.values?.slice(sourceStartColumn, sourceEndColumn) ?? []));
324
+ newEndRowIndex = rowIndex;
325
+ }
326
+ // Update table range
327
+ onChangeTables?.((prevTableData) => {
328
+ const [nextState, patches, inversePatches] = produceWithPatches(prevTableData, (draft) => {
329
+ const table = draft.find((table) => currentTable?.id === table.id);
330
+ if (table) {
331
+ table.range.endRowIndex = newEndRowIndex;
319
332
  }
320
- // Delete source if required
321
- // Move values
322
- for (let rowIndex = from.range.startRowIndex; rowIndex <= from.range.endRowIndex; rowIndex++) {
323
- for (let columnIndex = from.range.startColumnIndex; columnIndex <= from.range.endColumnIndex; columnIndex++) {
324
- if (!draft[sheetId][rowIndex]?.values?.[columnIndex]) {
325
- continue;
326
- }
327
- draft[sheetId][rowIndex].values[columnIndex] =
328
- {};
333
+ });
334
+ saveHistory({
335
+ tables: { patches, inversePatches },
336
+ });
337
+ return nextState;
338
+ });
339
+ }
340
+ if (headerRenames.length) {
341
+ onChangeTables?.((prevTables) => {
342
+ const [nextState, patches, inversePatches] = produceWithPatches(prevTables, (draft) => {
343
+ for (const { table, dimensionIndex, newName } of headerRenames) {
344
+ const current = draft.find((candidate) => candidate.id === table.id);
345
+ if (!current)
346
+ continue;
347
+ current.columns ??= [];
348
+ if (current.columns[dimensionIndex]) {
349
+ current.columns[dimensionIndex].name = newName;
350
+ }
351
+ else {
352
+ current.columns[dimensionIndex] = { name: newName };
329
353
  }
330
354
  }
331
- for (const { rowIndex, dataRowIndex } of destinationRows) {
332
- const currentSheet = createSheetDraft(draft, destinationSheetId, rowIndex);
333
- let columnCursor = 0;
334
- for (let columnIndex = to.range.startColumnIndex; columnIndex <= to.range.endColumnIndex; columnIndex++, columnCursor++) {
335
- const dataColumnIndex = colSpan > 0 ? columnCursor % colSpan : 0;
336
- currentSheet[rowIndex].values[columnIndex] =
337
- movedRowValues[dataRowIndex]?.[dataColumnIndex];
338
- for (const dependent of getDependents({
355
+ });
356
+ saveHistory({ tables: { patches, inversePatches } });
357
+ return nextState;
358
+ });
359
+ }
360
+ // Update sheetdata
361
+ // Capture the produced state so we can stream the exact written cells to an engine
362
+ // consumer afterwards (branch-agnostic across cut / pure-paste / paste-special).
363
+ let pastedSheetData;
364
+ if (selectedRowValues.length) {
365
+ onChangeSheetData?.((prevSheetData) => {
366
+ const [nextState, patches, inversePatches] = produceWithPatches(prevSheetData, (draft) => {
367
+ // For cut operation
368
+ const movedKeys = new Set();
369
+ /**
370
+ * If user is deleting source cells,
371
+ * let update its dependents and mark it as dirty
372
+ */
373
+ if (isCutOperation && from && to && !isNil(sourceSheetId)) {
374
+ const sheetId = sourceSheetId;
375
+ for (const [rowIndex, columnIndex] of iterateCellsInRange(from.range)) {
376
+ // Process dependents
377
+ processSideEffectDependentCells({
378
+ draft,
339
379
  rowIndex,
340
380
  columnIndex,
341
- sheetId: destinationSheetId,
342
- })) {
343
- if (isStaticNode(dependent)) {
381
+ sheetId,
382
+ destinationSheetId,
383
+ columnDelta,
384
+ enqueueGraphOperation,
385
+ enqueueCalculation: enqueue,
386
+ getDependents,
387
+ recalcCells,
388
+ rowDelta,
389
+ sourceRange: from.range,
390
+ movedKeys,
391
+ locale,
392
+ rowCount,
393
+ columnCount,
394
+ });
395
+ }
396
+ // Snapshot source after dependent/formula rewrites, before
397
+ // clearing it. The pre-cut clipboard snapshot still contains
398
+ // stale formulas, so writing that snapshot would discard the
399
+ // reference updates performed above.
400
+ const movedRowValues = [];
401
+ const sourceStartColumn = from.range.startColumnIndex;
402
+ const sourceEndColumn = from.range.endColumnIndex + 1;
403
+ for (let rowIndex = from.range.startRowIndex; rowIndex <= from.range.endRowIndex; rowIndex++) {
404
+ movedRowValues.push((draft[sheetId]?.[rowIndex]?.values?.slice(sourceStartColumn, sourceEndColumn) ?? []));
405
+ }
406
+ // Delete source if required
407
+ // Move values
408
+ for (let rowIndex = from.range.startRowIndex; rowIndex <= from.range.endRowIndex; rowIndex++) {
409
+ for (let columnIndex = from.range.startColumnIndex; columnIndex <= from.range.endColumnIndex; columnIndex++) {
410
+ if (!draft[sheetId][rowIndex]?.values?.[columnIndex]) {
344
411
  continue;
345
412
  }
346
- const { position } = dependent;
347
- enqueue({
348
- type: "add",
349
- position,
350
- force: true,
351
- });
352
- recalcCells.set(createSheetCellIdentifier(position.sheetId, position.rowIndex, position.columnIndex), position);
413
+ draft[sheetId][rowIndex].values[columnIndex] =
414
+ {};
353
415
  }
354
- collectDataValidationTarget(dataValidationTargets, destinationSheetId, rowIndex, columnIndex, currentSheet[rowIndex].values[columnIndex]);
355
416
  }
356
- }
357
- }
358
- if (currentTable && !isRowExpansion) {
359
- addCalculatedColumnsForRowExpansion({
360
- sheetId: destinationSheetId,
361
- currentTable,
362
- draft,
363
- enqueueCalculation: enqueue,
364
- recalcCells,
365
- locale,
366
- range: to.range,
367
- getDependents,
368
- });
369
- }
370
- // TBD: Move totalrow for tables
371
- // We are doing pure paste operation
372
- if (!isCutOperation) {
373
- const sheetCell = new SheetCell();
374
- const sourceCell = {
375
- rowIndex: to.range.startRowIndex,
376
- columnIndex: to.range.startColumnIndex,
377
- };
378
- for (const { rowIndex, dataRowIndex } of destinationRows) {
379
- const currentSheet = createSheetDraft(draft, destinationSheetId, rowIndex);
380
- let columnCursor = 0;
381
- for (let columnIndex = to.range.startColumnIndex; columnIndex <= to.range.endColumnIndex; columnIndex++, columnCursor++) {
382
- const dataColumnIndex = colSpan > 0 ? columnCursor % colSpan : 0;
383
- let cellValue = selectedRowValues[dataRowIndex]?.[dataColumnIndex];
384
- // Skip blanks: an empty clipboard cell leaves the
385
- // destination (value and format) untouched.
386
- if (pasteSpecial.skipBlanks &&
387
- isBlankClipboardCell(cellValue)) {
388
- continue;
389
- }
390
- // Operation: combine the pasted cell with the cell it
391
- // lands on. The clipboard is anchored at the FIRST tile,
392
- // so a source formula is relocated to the tile it lands
393
- // on first (the same `moveFormula` shift the plain paste
394
- // applies below); the composed `=(dest)op(source)` is
395
- // then anchored at the destination and must not be moved
396
- // again (that would shift the destination fragment too).
397
- if (pasteOperation) {
398
- const sourceFormula = getExtendedValueFormula(getCellUserEnteredValue(cellValue));
399
- if (!isNil(sourceFormula) &&
400
- dataRowIndex === 0 &&
401
- dataColumnIndex === 0 &&
402
- (rowIndex !== sourceCell.rowIndex ||
403
- columnIndex !== sourceCell.columnIndex)) {
404
- const tileCell = new SheetCell();
405
- tileCell.setLocale(locale);
406
- tileCell.assign(destinationSheetId, sourceCell, cellValue);
407
- tileCell.moveFormula(sourceCell, { rowIndex, columnIndex }, activeSheetName, { preserveAbsolutes: true });
408
- cellValue = {
409
- ...cellValue,
410
- ue: { ...cellValue?.ue, fv: tileCell.formula },
411
- };
417
+ for (const { rowIndex, dataRowIndex } of destinationRows) {
418
+ const currentSheet = createSheetDraft(draft, destinationSheetId, rowIndex);
419
+ let columnCursor = 0;
420
+ for (let columnIndex = to.range.startColumnIndex; columnIndex <= to.range.endColumnIndex; columnIndex++, columnCursor++) {
421
+ const dataColumnIndex = colSpan > 0 ? columnCursor % colSpan : 0;
422
+ currentSheet[rowIndex].values[columnIndex] =
423
+ movedRowValues[dataRowIndex]?.[dataColumnIndex];
424
+ for (const dependent of getDependents({
425
+ rowIndex,
426
+ columnIndex,
427
+ sheetId: destinationSheetId,
428
+ })) {
429
+ if (isStaticNode(dependent)) {
430
+ continue;
431
+ }
432
+ const { position } = dependent;
433
+ enqueue({
434
+ type: "add",
435
+ position,
436
+ force: true,
437
+ });
438
+ recalcCells.set(createSheetCellIdentifier(position.sheetId, position.rowIndex, position.columnIndex), position);
412
439
  }
413
- cellValue = applyPasteOperation(cellValue, prevSheetData[destinationSheetId]?.[rowIndex]?.values?.[columnIndex], pasteOperation, destinationSheetId, locale);
414
- }
415
- if (pasteMode === "formats") {
416
- const existingCellData = prevSheetData[destinationSheetId]?.[rowIndex]?.values?.[columnIndex];
417
- cellValue = { ...existingCellData, ...cellValue };
418
- sheetCell.extendCellData(cellValue);
440
+ collectDataValidationTarget(dataValidationTargets, destinationSheetId, rowIndex, columnIndex, currentSheet[rowIndex].values[columnIndex]);
419
441
  }
420
- if (pasteMode === "values" || forcePlainText) {
421
- const existingCellData = prevSheetData[destinationSheetId]?.[rowIndex]?.values?.[columnIndex];
422
- // Remove ss from existingCellData since we're replacing the value
423
- const { ss: _ss, ...existingWithoutSs } = existingCellData ?? {};
424
- cellValue = { ...existingWithoutSs, ...cellValue };
425
- sheetCell.extendCellData(cellValue);
426
- }
427
- if (pasteSpecial.transpose && pasteMode === "all") {
428
- sheetCell.assign(destinationSheetId, { rowIndex, columnIndex }, prevSheetData[destinationSheetId]?.[rowIndex]?.values?.[columnIndex], {
429
- locale,
430
- cellXfsRegistry,
431
- getDataValidationById,
432
- sharedStringRegistry,
433
- });
434
- const existingCellData = sheetCell.getUserCellData();
435
- cellValue = { ...existingCellData, ...cellValue };
436
- sheetCell.extendCellData(cellValue);
437
- }
438
- else {
439
- sheetCell.assign(destinationSheetId, { rowIndex, columnIndex }, typeof cellValue === "object"
440
- ? cellValue
441
- : undefined, {
442
- getRangeValues: getEffectiveValuesFromRange,
443
- locale,
444
- cellXfsRegistry,
445
- getDataValidationById,
446
- sharedStringRegistry,
447
- });
448
- }
449
- if (pasteMode === "formats") {
450
- sheetCell.refreshFormattedValue();
451
- }
452
- if (sheetCell.isFormula()) {
453
- if (dataRowIndex === 0 &&
454
- dataColumnIndex === 0 &&
455
- !pasteOperation) {
456
- sheetCell.moveFormula(sourceCell, {
457
- rowIndex,
458
- columnIndex,
459
- }, activeSheetName, { preserveAbsolutes: true });
442
+ }
443
+ }
444
+ // TBD: Move totalrow for tables
445
+ // We are doing pure paste operation
446
+ if (!isCutOperation) {
447
+ renameHeaderCellsInFormulas({
448
+ draft,
449
+ headerRenames,
450
+ enqueueCalculation: enqueue,
451
+ enqueueGraphOperation,
452
+ recalcCells,
453
+ locale,
454
+ cellXfsRegistry,
455
+ sharedStringRegistry,
456
+ });
457
+ const sheetCell = new SheetCell();
458
+ const sourceCell = {
459
+ rowIndex: to.range.startRowIndex,
460
+ columnIndex: to.range.startColumnIndex,
461
+ };
462
+ for (const { rowIndex, dataRowIndex } of destinationRows) {
463
+ const currentSheet = createSheetDraft(draft, destinationSheetId, rowIndex);
464
+ let columnCursor = 0;
465
+ for (let columnIndex = to.range.startColumnIndex; columnIndex <= to.range.endColumnIndex; columnIndex++, columnCursor++) {
466
+ const dataColumnIndex = colSpan > 0 ? columnCursor % colSpan : 0;
467
+ let cellValue = selectedRowValues[dataRowIndex]?.[dataColumnIndex];
468
+ // Skip blanks: an empty clipboard cell leaves the
469
+ // destination (value and format) untouched.
470
+ if (pasteSpecial.skipBlanks &&
471
+ isBlankClipboardCell(cellValue)) {
472
+ continue;
460
473
  }
461
- sheetCell.setLoading();
462
- enqueue({
463
- type: "add",
464
- position: {
474
+ // Operation: combine the pasted cell with the cell it
475
+ // lands on. The clipboard is anchored at the FIRST tile,
476
+ // so a source formula is relocated to the tile it lands
477
+ // on first (the same `moveFormula` shift the plain paste
478
+ // applies below); the composed `=(dest)op(source)` is
479
+ // then anchored at the destination and must not be moved
480
+ // again (that would shift the destination fragment too).
481
+ if (pasteOperation) {
482
+ const sourceFormula = getExtendedValueFormula(getCellUserEnteredValue(cellValue));
483
+ if (!isNil(sourceFormula) &&
484
+ dataRowIndex === 0 &&
485
+ dataColumnIndex === 0 &&
486
+ (rowIndex !== sourceCell.rowIndex ||
487
+ columnIndex !== sourceCell.columnIndex)) {
488
+ const tileCell = new SheetCell();
489
+ tileCell.setLocale(locale);
490
+ tileCell.assign(destinationSheetId, sourceCell, cellValue);
491
+ tileCell.moveFormula(sourceCell, { rowIndex, columnIndex }, activeSheetName, { preserveAbsolutes: true });
492
+ cellValue = {
493
+ ...cellValue,
494
+ ue: { ...cellValue?.ue, fv: tileCell.formula },
495
+ };
496
+ }
497
+ cellValue = applyPasteOperation(cellValue, prevSheetData[destinationSheetId]?.[rowIndex]?.values?.[columnIndex], pasteOperation, destinationSheetId, locale);
498
+ }
499
+ if (pasteMode === "formats") {
500
+ const existingCellData = prevSheetData[destinationSheetId]?.[rowIndex]?.values?.[columnIndex];
501
+ cellValue = { ...existingCellData, ...cellValue };
502
+ sheetCell.extendCellData(cellValue);
503
+ }
504
+ if (pasteMode === "values" || forcePlainText) {
505
+ const existingCellData = prevSheetData[destinationSheetId]?.[rowIndex]?.values?.[columnIndex];
506
+ // Remove ss from existingCellData since we're replacing the value
507
+ const { ss: _ss, ...existingWithoutSs } = existingCellData ?? {};
508
+ cellValue = { ...existingWithoutSs, ...cellValue };
509
+ sheetCell.extendCellData(cellValue);
510
+ }
511
+ if (pasteSpecial.transpose && pasteMode === "all") {
512
+ sheetCell.assign(destinationSheetId, { rowIndex, columnIndex }, prevSheetData[destinationSheetId]?.[rowIndex]?.values?.[columnIndex], {
513
+ locale,
514
+ cellXfsRegistry,
515
+ getDataValidationById,
516
+ sharedStringRegistry,
517
+ });
518
+ const existingCellData = sheetCell.getUserCellData();
519
+ cellValue = { ...existingCellData, ...cellValue };
520
+ sheetCell.extendCellData(cellValue);
521
+ }
522
+ else {
523
+ sheetCell.assign(destinationSheetId, { rowIndex, columnIndex }, typeof cellValue === "object"
524
+ ? cellValue
525
+ : undefined, {
526
+ getRangeValues: getEffectiveValuesFromRange,
527
+ locale,
528
+ cellXfsRegistry,
529
+ getDataValidationById,
530
+ sharedStringRegistry,
531
+ });
532
+ }
533
+ if (pasteMode === "formats") {
534
+ sheetCell.refreshFormattedValue();
535
+ }
536
+ if (sheetCell.isFormula()) {
537
+ if (dataRowIndex === 0 &&
538
+ dataColumnIndex === 0 &&
539
+ !pasteOperation) {
540
+ sheetCell.moveFormula(sourceCell, {
541
+ rowIndex,
542
+ columnIndex,
543
+ }, activeSheetName, { preserveAbsolutes: true });
544
+ }
545
+ sheetCell.setLoading();
546
+ enqueue({
547
+ type: "add",
548
+ position: {
549
+ rowIndex,
550
+ columnIndex,
551
+ sheetId: destinationSheetId,
552
+ },
553
+ force: true,
554
+ });
555
+ recalcCells.set(createSheetCellIdentifier(destinationSheetId, rowIndex, columnIndex), {
465
556
  rowIndex,
466
557
  columnIndex,
467
558
  sheetId: destinationSheetId,
468
- },
469
- force: true,
470
- });
471
- recalcCells.set(createSheetCellIdentifier(destinationSheetId, rowIndex, columnIndex), {
559
+ });
560
+ }
561
+ for (const dependent of getDependents({
472
562
  rowIndex,
473
563
  columnIndex,
474
564
  sheetId: destinationSheetId,
475
- });
476
- }
477
- for (const dependent of getDependents({
478
- rowIndex,
479
- columnIndex,
480
- sheetId: destinationSheetId,
481
- })) {
482
- if (isStaticNode(dependent)) {
483
- continue;
565
+ })) {
566
+ if (isStaticNode(dependent)) {
567
+ continue;
568
+ }
569
+ const { position } = dependent;
570
+ enqueue({
571
+ type: "add",
572
+ position,
573
+ force: true,
574
+ });
575
+ recalcCells.set(createSheetCellIdentifier(position.sheetId, position.rowIndex, position.columnIndex), position);
484
576
  }
485
- const { position } = dependent;
486
- enqueue({
487
- type: "add",
488
- position,
489
- force: true,
490
- });
491
- recalcCells.set(createSheetCellIdentifier(position.sheetId, position.rowIndex, position.columnIndex), position);
577
+ const headerRename = headerRenameAt.get(`${rowIndex}:${columnIndex}`);
578
+ if (headerRename) {
579
+ // A table header cell holds its column name as text.
580
+ sheetCell.setUserEnteredValue(headerRename.newName, undefined, { disableTypeInference: true });
581
+ }
582
+ sharedStringRegistry?.registerCell(sheetCell);
583
+ currentSheet[rowIndex].values[columnIndex] =
584
+ sheetCell.getCellData();
585
+ collectDataValidationTarget(dataValidationTargets, destinationSheetId, rowIndex, columnIndex, currentSheet[rowIndex].values[columnIndex]);
586
+ cellXfsRegistry?.registerCellXfs(sheetCell);
492
587
  }
493
- sharedStringRegistry?.registerCell(sheetCell);
494
- currentSheet[rowIndex].values[columnIndex] =
495
- sheetCell.getCellData();
496
- collectDataValidationTarget(dataValidationTargets, destinationSheetId, rowIndex, columnIndex, currentSheet[rowIndex].values[columnIndex]);
497
- cellXfsRegistry?.registerCellXfs(sheetCell);
498
588
  }
499
589
  }
500
- }
501
- });
502
- saveHistory({
503
- sheetData: { patches, inversePatches },
504
- recalcCells: { undo: recalcCells, redo: recalcCells },
505
- activeCell: {
506
- undo: getActiveCell(),
507
- redo: getActiveCell(),
508
- },
509
- selections: {
510
- undo: undefined,
511
- redo: isSelectionACell(nextSelections) ? undefined : [to],
512
- },
590
+ });
591
+ saveHistory({
592
+ sheetData: { patches, inversePatches },
593
+ recalcCells: { undo: recalcCells, redo: recalcCells },
594
+ activeCell: {
595
+ undo: getActiveCell(),
596
+ redo: getActiveCell(),
597
+ },
598
+ selections: {
599
+ undo: undefined,
600
+ redo: isSelectionACell(nextSelections) ? undefined : [to],
601
+ },
602
+ });
603
+ extendDataValidationRanges(dataValidationTargets, onChangeDataValidations, saveHistory);
604
+ processQueue();
605
+ pastedSheetData = nextState;
606
+ return nextState;
513
607
  });
514
- extendDataValidationRanges(dataValidationTargets, onChangeDataValidations, saveHistory);
515
- processQueue();
516
- pastedSheetData = nextState;
517
- return nextState;
518
- });
519
- // Save registries
520
- cellXfsRegistry?.getPatches(saveHistory);
521
- sharedStringRegistry?.getPatches(saveHistory);
522
- // Update row or column count
523
- // Change sheets
524
- onChangeSheets?.((prevSheets) => {
525
- const [nextState, patches, inversePatches] = produceWithPatches(prevSheets, (draft) => {
526
- const sheet = draft.find((sheet) => sheet.sheetId === destinationSheetId);
527
- if (sheet) {
528
- sheet.rowCount = Math.min(maxRowCount, Math.max(sheet.rowCount ?? DEFAULT_ROW_COUNT, to.range.endRowIndex));
529
- sheet.columnCount = Math.min(maxColumnCount, Math.max(sheet.columnCount ?? DEFAULT_COLUMN_COUNT, to.range.endColumnIndex));
530
- // Handle merges for cut operations
531
- let mergesToAdd = merges;
532
- if (isCutOperation && from && !isNil(sourceSheetId)) {
533
- const sourceSheet = prevSheets.find((s) => s.sheetId === sourceSheetId);
534
- if (sourceSheet?.merges) {
535
- // Extract merged cells from source range
536
- const cutMerges = [];
537
- for (const merge of sourceSheet.merges) {
538
- // Check if merge intersects with the cut range
539
- if (areaIntersects(merge, from.range)) {
540
- // Calculate new merge coordinates relative to destination
541
- cutMerges.push({
542
- startRowIndex: merge.startRowIndex + rowDelta,
543
- startColumnIndex: merge.startColumnIndex + columnDelta,
544
- endRowIndex: merge.endRowIndex + rowDelta,
545
- endColumnIndex: merge.endColumnIndex + columnDelta,
546
- });
608
+ // Save registries
609
+ cellXfsRegistry?.getPatches(saveHistory);
610
+ sharedStringRegistry?.getPatches(saveHistory);
611
+ // Update row or column count
612
+ // Change sheets
613
+ onChangeSheets?.((prevSheets) => {
614
+ const [nextState, patches, inversePatches] = produceWithPatches(prevSheets, (draft) => {
615
+ const sheet = draft.find((sheet) => sheet.sheetId === destinationSheetId);
616
+ if (sheet) {
617
+ sheet.rowCount = Math.min(maxRowCount, Math.max(sheet.rowCount ?? DEFAULT_ROW_COUNT, to.range.endRowIndex));
618
+ sheet.columnCount = Math.min(maxColumnCount, Math.max(sheet.columnCount ?? DEFAULT_COLUMN_COUNT, to.range.endColumnIndex));
619
+ // Handle merges for cut operations
620
+ let mergesToAdd = merges;
621
+ if (isCutOperation && from && !isNil(sourceSheetId)) {
622
+ const sourceSheet = prevSheets.find((s) => s.sheetId === sourceSheetId);
623
+ if (sourceSheet?.merges) {
624
+ // Extract merged cells from source range
625
+ const cutMerges = [];
626
+ for (const merge of sourceSheet.merges) {
627
+ // Check if merge intersects with the cut range
628
+ if (areaIntersects(merge, from.range)) {
629
+ // Calculate new merge coordinates relative to destination
630
+ cutMerges.push({
631
+ startRowIndex: merge.startRowIndex + rowDelta,
632
+ startColumnIndex: merge.startColumnIndex + columnDelta,
633
+ endRowIndex: merge.endRowIndex + rowDelta,
634
+ endColumnIndex: merge.endColumnIndex + columnDelta,
635
+ });
636
+ }
637
+ }
638
+ if (cutMerges.length > 0) {
639
+ mergesToAdd = cutMerges;
640
+ }
641
+ // Remove merges from source sheet
642
+ const sourceSheetDraft = draft.find((s) => s.sheetId === sourceSheetId);
643
+ if (sourceSheetDraft?.merges) {
644
+ sourceSheetDraft.merges = sourceSheetDraft.merges.filter((merge) => !areaIntersects(merge, from.range));
547
645
  }
548
- }
549
- if (cutMerges.length > 0) {
550
- mergesToAdd = cutMerges;
551
- }
552
- // Remove merges from source sheet
553
- const sourceSheetDraft = draft.find((s) => s.sheetId === sourceSheetId);
554
- if (sourceSheetDraft?.merges) {
555
- sourceSheetDraft.merges = sourceSheetDraft.merges.filter((merge) => !areaIntersects(merge, from.range));
556
646
  }
557
647
  }
558
- }
559
- // Update merges
560
- if (mergesToAdd) {
561
- sheet.merges = sheet.merges ?? [];
562
- for (const merge of mergesToAdd) {
563
- const exists = sheet.merges.find((range) => isAreasEqual(range, merge));
564
- if (!exists) {
565
- sheet.merges.push(merge);
648
+ // Update merges
649
+ if (mergesToAdd) {
650
+ sheet.merges = sheet.merges ?? [];
651
+ for (const merge of mergesToAdd) {
652
+ const exists = sheet.merges.find((range) => isAreasEqual(range, merge));
653
+ if (!exists) {
654
+ sheet.merges.push(merge);
655
+ }
566
656
  }
567
657
  }
568
- }
569
- // Row heights
570
- const clipboardSizedRows = new Set();
571
- if (rowHeights) {
572
- if (!sheet.rowMetadata) {
573
- sheet.rowMetadata = [];
574
- }
575
- for (let index = 0; index < rowHeights.length; index++) {
576
- const curHeight = rowHeights[index];
577
- if (isNil(curHeight) || curHeight === 0) {
578
- continue;
579
- }
580
- const rowIndex = visibleRowIndexes[index];
581
- if (isNil(rowIndex)) {
582
- break;
583
- }
584
- if (!sheet.rowMetadata[rowIndex]) {
585
- sheet.rowMetadata[rowIndex] = {};
658
+ // Row heights
659
+ const clipboardSizedRows = new Set();
660
+ if (rowHeights) {
661
+ if (!sheet.rowMetadata) {
662
+ sheet.rowMetadata = [];
586
663
  }
587
- sheet.rowMetadata[rowIndex].size = curHeight;
588
- clipboardSizedRows.add(rowIndex);
589
- }
590
- }
591
- // Auto-resize rows whose pasted content needs more room
592
- // (multi-line text or wrap). Mirrors use-on-change's
593
- // adjustRowHeight, but batched into this immer pass so the
594
- // whole paste collapses to one undo entry. Skip conditions
595
- // make the common single-line-text paste do zero work.
596
- // Skipped for paste-special variants since the destination
597
- // cell ends up as a merge of existing + pasted data, not
598
- // the raw pasted value we can read from selectedRowValues.
599
- const skipAutoResize = pasteSpecial.isSpecial;
600
- if (!skipAutoResize &&
601
- getFinalRowHeight &&
602
- selectedRowValues.length &&
603
- colSpan > 0) {
604
- for (const { rowIndex, dataRowIndex } of destinationRows) {
605
- // Clipboard-provided row heights win.
606
- if (clipboardSizedRows.has(rowIndex))
607
- continue;
608
- const rowData = selectedRowValues[dataRowIndex];
609
- if (!rowData)
610
- continue;
611
- // Find the cell most likely to drive row height —
612
- // most lines first, then any wrap. If no cell in
613
- // the row needs more than one line and no cell is
614
- // wrapped, the row's existing height already fits.
615
- let bestLines = 1;
616
- let bestColumnIndex;
617
- let bestCell;
618
- let bestHasWrap = false;
619
- let columnCursor = 0;
620
- for (let columnIndex = to.range.startColumnIndex; columnIndex <= to.range.endColumnIndex; columnIndex++, columnCursor++) {
621
- const dataColumnIndex = columnCursor % colSpan;
622
- const cellValue = rowData[dataColumnIndex];
623
- if (!cellValue || typeof cellValue !== "object")
664
+ for (let index = 0; index < rowHeights.length; index++) {
665
+ const curHeight = rowHeights[index];
666
+ if (isNil(curHeight) || curHeight === 0) {
624
667
  continue;
625
- const ue = getCellUserEnteredValue(cellValue);
626
- const text = getExtendedValueString(ue);
627
- const lines = typeof text === "string" && text.includes("\n")
628
- ? text.split("\n").length
629
- : 1;
630
- const uf = getCellUserEnteredFormat(cellValue);
631
- const wrap = uf
632
- ?.wrapStrategy === "wrap";
633
- if (lines > bestLines ||
634
- (lines === bestLines && wrap && !bestHasWrap)) {
635
- bestLines = lines;
636
- bestCell = cellValue;
637
- bestColumnIndex = columnIndex;
638
- bestHasWrap = wrap;
639
668
  }
640
- }
641
- if (!bestCell ||
642
- bestColumnIndex === undefined ||
643
- (bestLines === 1 && !bestHasWrap)) {
644
- continue;
645
- }
646
- const ue = getCellUserEnteredValue(bestCell);
647
- const overrideText = getExtendedValueString(ue) ?? "";
648
- const uf = getCellUserEnteredFormat(bestCell);
649
- const height = getFinalRowHeight(destinationSheetId, rowIndex, bestColumnIndex, {
650
- textOverride: String(overrideText),
651
- textFormatOverride: uf?.textFormat,
652
- shouldWrapOverride: bestHasWrap,
653
- });
654
- if (typeof height === "number" && height > 0) {
655
- if (!sheet.rowMetadata)
656
- sheet.rowMetadata = [];
669
+ const rowIndex = visibleRowIndexes[index];
670
+ if (isNil(rowIndex)) {
671
+ break;
672
+ }
657
673
  if (!sheet.rowMetadata[rowIndex]) {
658
674
  sheet.rowMetadata[rowIndex] = {};
659
675
  }
660
- sheet.rowMetadata[rowIndex].size = height;
661
- sheet.rowMetadata[rowIndex].resizedByUser = false;
676
+ sheet.rowMetadata[rowIndex].size = curHeight;
677
+ clipboardSizedRows.add(rowIndex);
662
678
  }
663
679
  }
664
- }
665
- // column widths
666
- if (columnWidths) {
667
- if (!sheet.columnMetadata) {
668
- sheet.columnMetadata = [];
680
+ // Auto-resize rows whose pasted content needs more room
681
+ // (multi-line text or wrap). Mirrors use-on-change's
682
+ // adjustRowHeight, but batched into this immer pass so the
683
+ // whole paste collapses to one undo entry. Skip conditions
684
+ // make the common single-line-text paste do zero work.
685
+ // Skipped for paste-special variants since the destination
686
+ // cell ends up as a merge of existing + pasted data, not
687
+ // the raw pasted value we can read from selectedRowValues.
688
+ const skipAutoResize = pasteSpecial.isSpecial;
689
+ if (!skipAutoResize &&
690
+ getFinalRowHeight &&
691
+ selectedRowValues.length &&
692
+ colSpan > 0) {
693
+ for (const { rowIndex, dataRowIndex } of destinationRows) {
694
+ // Clipboard-provided row heights win.
695
+ if (clipboardSizedRows.has(rowIndex))
696
+ continue;
697
+ const rowData = selectedRowValues[dataRowIndex];
698
+ if (!rowData)
699
+ continue;
700
+ // Find the cell most likely to drive row height —
701
+ // most lines first, then any wrap. If no cell in
702
+ // the row needs more than one line and no cell is
703
+ // wrapped, the row's existing height already fits.
704
+ let bestLines = 1;
705
+ let bestColumnIndex;
706
+ let bestCell;
707
+ let bestHasWrap = false;
708
+ let columnCursor = 0;
709
+ for (let columnIndex = to.range.startColumnIndex; columnIndex <= to.range.endColumnIndex; columnIndex++, columnCursor++) {
710
+ const dataColumnIndex = columnCursor % colSpan;
711
+ const cellValue = rowData[dataColumnIndex];
712
+ if (!cellValue || typeof cellValue !== "object")
713
+ continue;
714
+ const ue = getCellUserEnteredValue(cellValue);
715
+ const text = getExtendedValueString(ue);
716
+ const lines = typeof text === "string" && text.includes("\n")
717
+ ? text.split("\n").length
718
+ : 1;
719
+ const uf = getCellUserEnteredFormat(cellValue);
720
+ const wrap = uf
721
+ ?.wrapStrategy === "wrap";
722
+ if (lines > bestLines ||
723
+ (lines === bestLines && wrap && !bestHasWrap)) {
724
+ bestLines = lines;
725
+ bestCell = cellValue;
726
+ bestColumnIndex = columnIndex;
727
+ bestHasWrap = wrap;
728
+ }
729
+ }
730
+ if (!bestCell ||
731
+ bestColumnIndex === undefined ||
732
+ (bestLines === 1 && !bestHasWrap)) {
733
+ continue;
734
+ }
735
+ const ue = getCellUserEnteredValue(bestCell);
736
+ const overrideText = getExtendedValueString(ue) ?? "";
737
+ const uf = getCellUserEnteredFormat(bestCell);
738
+ const height = getFinalRowHeight(destinationSheetId, rowIndex, bestColumnIndex, {
739
+ textOverride: String(overrideText),
740
+ textFormatOverride: uf?.textFormat,
741
+ shouldWrapOverride: bestHasWrap,
742
+ });
743
+ if (typeof height === "number" && height > 0) {
744
+ if (!sheet.rowMetadata)
745
+ sheet.rowMetadata = [];
746
+ if (!sheet.rowMetadata[rowIndex]) {
747
+ sheet.rowMetadata[rowIndex] = {};
748
+ }
749
+ sheet.rowMetadata[rowIndex].size = height;
750
+ sheet.rowMetadata[rowIndex].resizedByUser = false;
751
+ }
752
+ }
669
753
  }
670
- for (let index = 0; index < columnWidths.length; index++) {
671
- const curWidth = columnWidths[index];
672
- if (isNil(curWidth) || curWidth === 0) {
673
- continue;
754
+ // column widths
755
+ if (columnWidths) {
756
+ if (!sheet.columnMetadata) {
757
+ sheet.columnMetadata = [];
674
758
  }
675
- const columnIndex = to.range.startColumnIndex + index;
676
- if (!sheet.columnMetadata?.[columnIndex]) {
677
- sheet.columnMetadata[columnIndex] = {};
759
+ for (let index = 0; index < columnWidths.length; index++) {
760
+ const curWidth = columnWidths[index];
761
+ if (isNil(curWidth) || curWidth === 0) {
762
+ continue;
763
+ }
764
+ const columnIndex = to.range.startColumnIndex + index;
765
+ if (!sheet.columnMetadata?.[columnIndex]) {
766
+ sheet.columnMetadata[columnIndex] = {};
767
+ }
768
+ sheet.columnMetadata[columnIndex].size =
769
+ columnWidths[index];
678
770
  }
679
- sheet.columnMetadata[columnIndex].size =
680
- columnWidths[index];
681
771
  }
682
772
  }
683
- }
684
- });
685
- saveHistory({
686
- sheets: { patches, inversePatches },
773
+ });
774
+ saveHistory({
775
+ sheets: { patches, inversePatches },
776
+ });
777
+ return nextState;
687
778
  });
688
- return nextState;
689
- });
690
- // For row expansions, add columns
691
- onChangeTableColumn(destinationSheetId, activeCell, activeCellValue ?? undefined, adjacentTable, isRowExpansion, isColumnExpansion, to.range);
692
- // Add calculated column
693
- onChangeCalculatedColumn(destinationSheetId, activeCell, activeCellValue ?? undefined, currentTable);
694
- // Update new selections
695
- if (!isSelectionACell(nextSelections)) {
696
- onChangeSelections?.(destinationSheetId, [to]);
697
- }
698
- // Update active cell
699
- onChangeActiveCell(destinationSheetId, { ...getActiveCell() });
700
- // Stream the paste to an engine consumer. The clipboard is a bounded payload (not
701
- // windowed), so paste can resolve the destination cells UI-side; we read back the
702
- // user-entered values the paste actually produced — relocated formulas, paste-special
703
- // merges, shared-string text — and replay them as a `change-batch` the engine recomputes
704
- // from. Reading the produced state (rather than re-deriving) keeps this correct across the
705
- // cut / pure-paste / paste-special branches without duplicating their logic.
706
- if (onCommand && pastedSheetData) {
707
- const values = [];
708
- for (let rowIndex = to.range.startRowIndex; rowIndex <= to.range.endRowIndex; rowIndex++) {
709
- const row = [];
710
- for (let columnIndex = to.range.startColumnIndex; columnIndex <= to.range.endColumnIndex; columnIndex++) {
711
- const cell = pastedSheetData[destinationSheetId]?.[rowIndex]?.values?.[columnIndex];
712
- const ue = cell ? getCellUserEnteredValue(cell) : undefined;
713
- // Formula text wins (e.g. "=SUM(A1:A2)"), else the literal string / number / bool.
714
- // `??` (not `||`) so 0 and false survive; `null` clears the cell.
715
- row.push(getExtendedValueFormula(ue) ??
716
- getExtendedValueString(ue) ??
717
- getExtendedValueNumber(ue) ??
718
- getExtendedValueBool(ue) ??
719
- null);
720
- }
721
- values.push(row);
779
+ // For row expansions, add columns
780
+ onChangeTableColumn(destinationSheetId, activeCell, activeCellValue ?? undefined, adjacentTable, isRowExpansion, isColumnExpansion, to.range, pastedHeaderValues);
781
+ // Add calculated column
782
+ onChangeCalculatedColumn(destinationSheetId, activeCell, activeCellValue ?? undefined, currentTable);
783
+ // Update new selections
784
+ if (!isSelectionACell(nextSelections)) {
785
+ onChangeSelections?.(destinationSheetId, [to]);
722
786
  }
723
- onCommand({
724
- command: "change-batch",
725
- sheetId: destinationSheetId,
726
- ranges: to.range,
727
- values,
728
- });
729
- // On cut, the source cells were cleared — mirror that so the engine drops them too.
730
- if (isCutOperation && from && !isNil(sourceSheetId)) {
787
+ // Update active cell
788
+ onChangeActiveCell(destinationSheetId, { ...getActiveCell() });
789
+ // Stream the paste to an engine consumer. The clipboard is a bounded payload (not
790
+ // windowed), so paste can resolve the destination cells UI-side; we read back the
791
+ // user-entered values the paste actually produced — relocated formulas, paste-special
792
+ // merges, shared-string text — and replay them as a `change-batch` the engine recomputes
793
+ // from. Reading the produced state (rather than re-deriving) keeps this correct across the
794
+ // cut / pure-paste / paste-special branches without duplicating their logic.
795
+ if (onCommand && pastedSheetData) {
796
+ const values = [];
797
+ for (let rowIndex = to.range.startRowIndex; rowIndex <= to.range.endRowIndex; rowIndex++) {
798
+ const row = [];
799
+ for (let columnIndex = to.range.startColumnIndex; columnIndex <= to.range.endColumnIndex; columnIndex++) {
800
+ const cell = pastedSheetData[destinationSheetId]?.[rowIndex]?.values?.[columnIndex];
801
+ const ue = cell ? getCellUserEnteredValue(cell) : undefined;
802
+ // Formula text wins (e.g. "=SUM(A1:A2)"), else the literal string / number / bool.
803
+ // `??` (not `||`) so 0 and false survive; `null` clears the cell.
804
+ row.push(getExtendedValueFormula(ue) ??
805
+ getExtendedValueString(ue) ??
806
+ getExtendedValueNumber(ue) ??
807
+ getExtendedValueBool(ue) ??
808
+ null);
809
+ }
810
+ values.push(row);
811
+ }
731
812
  onCommand({
732
- command: "delete-cells",
733
- sheetId: sourceSheetId,
734
- activeCell: {
735
- rowIndex: from.range.startRowIndex,
736
- columnIndex: from.range.startColumnIndex,
737
- },
738
- selections: [{ range: from.range }],
813
+ command: "change-batch",
814
+ sheetId: destinationSheetId,
815
+ ranges: to.range,
816
+ values,
817
+ ...(autoExpandTables ? {} : { autoExpandTables }),
818
+ ...(autoCalculatedColumns ? {} : { autoCalculatedColumns }),
739
819
  });
820
+ // On cut, the source cells were cleared — mirror that so the engine drops them too.
821
+ if (isCutOperation && from && !isNil(sourceSheetId)) {
822
+ onCommand({
823
+ command: "delete-cells",
824
+ sheetId: sourceSheetId,
825
+ activeCell: {
826
+ rowIndex: from.range.startRowIndex,
827
+ columnIndex: from.range.startColumnIndex,
828
+ },
829
+ selections: [{ range: from.range }],
830
+ });
831
+ }
740
832
  }
741
833
  }
742
- }
743
- // Defined names wholly inside the cut block follow it (Excel move semantics); a name the
744
- // block covers only partially keeps referring to its original area.
745
- if (isCutOperation && from && !isNil(sourceSheetId)) {
746
- onChangeNamedRanges?.((prevNamedRanges) => {
747
- const [nextState, patches, inversePatches] = produceWithPatches(prevNamedRanges, (draft) => {
748
- for (const namedRange of draft) {
749
- if (namedRange.range?.sheetId === sourceSheetId &&
750
- areaInsideArea(namedRange.range, from.range)) {
751
- namedRange.range = {
752
- ...moveRange(namedRange.range, from.range, to.range),
753
- sheetId: destinationSheetId,
754
- };
834
+ // Defined names wholly inside the cut block follow it (Excel move semantics); a name the
835
+ // block covers only partially keeps referring to its original area.
836
+ if (isCutOperation && from && !isNil(sourceSheetId)) {
837
+ onChangeNamedRanges?.((prevNamedRanges) => {
838
+ const [nextState, patches, inversePatches] = produceWithPatches(prevNamedRanges, (draft) => {
839
+ for (const namedRange of draft) {
840
+ if (namedRange.range?.sheetId === sourceSheetId &&
841
+ areaInsideArea(namedRange.range, from.range)) {
842
+ namedRange.range = {
843
+ ...moveRange(namedRange.range, from.range, to.range),
844
+ sheetId: destinationSheetId,
845
+ };
846
+ }
755
847
  }
848
+ });
849
+ if (!patches.length) {
850
+ return prevNamedRanges;
756
851
  }
852
+ saveHistory({ namedRanges: { patches, inversePatches } });
853
+ return nextState;
757
854
  });
758
- if (!patches.length) {
759
- return prevNamedRanges;
760
- }
761
- saveHistory({ namedRanges: { patches, inversePatches } });
762
- return nextState;
763
- });
764
- }
765
- // Embeds
766
- if (embeds?.length) {
767
- const firstEmbedId = embeds[0].embedId;
768
- onChangeEmbeds?.((prevEmbeds) => {
769
- const [nextState, patches, inversePatches] = produceWithPatches(prevEmbeds, (draft) => {
770
- draft.push(...embeds);
771
- });
772
- saveHistory({
773
- embeds: { patches, inversePatches },
774
- selectedEmbedOrChart: { redo: firstEmbedId, undo: undefined },
775
- });
776
- return nextState;
777
- });
778
- // Selected first embed
779
- focusEmbedOrChart(embeds[0].embedId);
780
- }
781
- // Tables
782
- if (tables?.length) {
783
- onChangeTables?.((prevTables) => {
784
- const [nextState, patches, inversePatches] = produceWithPatches(prevTables, (draft) => {
785
- draft.push(...tables);
786
- });
787
- saveHistory({
788
- tables: { patches, inversePatches },
789
- });
790
- return nextState;
791
- });
792
- }
793
- // Handle citations
794
- if (selectedRowValues.length && onChangeCitations) {
795
- // Collect citationIds from pasted cells
796
- const citationIdMap = new Map();
797
- for (let dataRowIndex = 0; dataRowIndex < rowSpan; dataRowIndex++) {
798
- const rowData = selectedRowValues[dataRowIndex];
799
- if (!rowData)
800
- continue;
801
- for (let dataColumnIndex = 0; dataColumnIndex < colSpan; dataColumnIndex++) {
802
- const cellValue = rowData[dataColumnIndex];
803
- if (cellValue &&
804
- typeof cellValue === "object" &&
805
- "citationId" in cellValue &&
806
- cellValue.citationId) {
807
- citationIdMap.set(cellValue.citationId, {
808
- sourceRowIndex: dataRowIndex,
809
- sourceColumnIndex: dataColumnIndex,
810
- });
855
+ onChangeCharts?.((prevCharts) => {
856
+ const [nextState, patches, inversePatches] = produceWithPatches(prevCharts, (draft) => {
857
+ moveChartsOnRangeMove(draft, sourceSheetId, from.range, destinationSheetId, to.range);
858
+ });
859
+ if (!patches.length) {
860
+ return prevCharts;
811
861
  }
812
- }
813
- }
814
- if (citationIdMap.size > 0) {
815
- if (isCutOperation && from && !isNil(sourceSheetId)) {
816
- // For cut operation: Move citations to new position
817
- onChangeCitations((prevCitations) => {
818
- const [nextState, patches, inversePatches] = produceWithPatches(prevCitations, (draft) => {
819
- for (const citationId of citationIdMap.keys()) {
820
- const citation = draft.find((c) => c.id === citationId);
821
- if (citation) {
822
- // Update citation range to new position
823
- citation.range.sheetId = destinationSheetId;
824
- citation.range.startRowIndex += rowDelta;
825
- citation.range.endRowIndex += rowDelta;
826
- citation.range.startColumnIndex += columnDelta;
827
- citation.range.endColumnIndex += columnDelta;
862
+ saveHistory({ charts: { patches, inversePatches } });
863
+ return nextState;
864
+ });
865
+ // The tables the cut block covers whole move with their cells (same history step): the
866
+ // range lands at the destination — on another sheet too — and the column-indexed filter
867
+ // and sort specs follow it, so the table's filters and its structured references keep
868
+ // resolving there.
869
+ if (movedTables.length) {
870
+ const columnDelta = to.range.startColumnIndex - from.range.startColumnIndex;
871
+ onChangeTables?.((prevTables) => {
872
+ const [nextState, patches, inversePatches] = produceWithPatches(prevTables, (draft) => {
873
+ for (const table of draft) {
874
+ if (!movedTables.some((moved) => moved.id === table.id)) {
875
+ continue;
876
+ }
877
+ table.sheetId = destinationSheetId;
878
+ const range = moveRange(table.range, from.range, to.range);
879
+ table.range =
880
+ "sheetId" in range
881
+ ? { ...range, sheetId: destinationSheetId }
882
+ : range;
883
+ for (const spec of table.filterSpecs ?? []) {
884
+ spec.columnIndex += columnDelta;
885
+ }
886
+ for (const spec of table.sortSpecs ?? []) {
887
+ spec.dimensionIndex += columnDelta;
828
888
  }
829
889
  }
830
890
  });
831
- saveHistory({
832
- citations: { patches, inversePatches },
833
- });
891
+ saveHistory({ tables: { patches, inversePatches } });
834
892
  return nextState;
835
893
  });
836
894
  }
837
- else if (!isCutOperation) {
838
- // For paste (copy) operation: Create new citations with new IDs
839
- const newCitations = [];
840
- const citationIdRemap = new Map();
841
- for (const [oldCitationId, { sourceRowIndex, sourceColumnIndex },] of citationIdMap.entries()) {
842
- const originalCitation = citations?.find((c) => c.id === oldCitationId);
843
- if (originalCitation) {
844
- const newId = uuidString();
845
- citationIdRemap.set(oldCitationId, newId);
846
- // Calculate the new range based on paste destination
847
- const newCitation = {
848
- ...originalCitation,
849
- id: newId,
850
- range: {
851
- sheetId: destinationSheetId,
852
- startRowIndex: to.range.startRowIndex + sourceRowIndex,
853
- endRowIndex: to.range.startRowIndex + sourceRowIndex,
854
- startColumnIndex: to.range.startColumnIndex + sourceColumnIndex,
855
- endColumnIndex: to.range.startColumnIndex + sourceColumnIndex,
856
- },
857
- };
858
- newCitations.push(newCitation);
895
+ }
896
+ // Embeds
897
+ if (embeds?.length) {
898
+ const firstEmbedId = embeds[0].embedId;
899
+ onChangeEmbeds?.((prevEmbeds) => {
900
+ const [nextState, patches, inversePatches] = produceWithPatches(prevEmbeds, (draft) => {
901
+ draft.push(...embeds);
902
+ });
903
+ saveHistory({
904
+ embeds: { patches, inversePatches },
905
+ selectedEmbedOrChart: { redo: firstEmbedId, undo: undefined },
906
+ });
907
+ return nextState;
908
+ });
909
+ // Selected first embed
910
+ focusEmbedOrChart(embeds[0].embedId);
911
+ }
912
+ // Tables
913
+ if (tables?.length) {
914
+ onChangeTables?.((prevTables) => {
915
+ const [nextState, patches, inversePatches] = produceWithPatches(prevTables, (draft) => {
916
+ // Excel names a pasted table like a new one — the next free `TableN` — never
917
+ // `Copy of <title>`, which is not a valid table name (it has a space).
918
+ for (const table of tables) {
919
+ draft.push({
920
+ ...table,
921
+ title: getNextTableTitle(draft, generatedNames),
922
+ });
923
+ }
924
+ });
925
+ saveHistory({
926
+ tables: { patches, inversePatches },
927
+ });
928
+ return nextState;
929
+ });
930
+ }
931
+ // Handle citations
932
+ if (selectedRowValues.length && onChangeCitations) {
933
+ // Collect citationIds from pasted cells
934
+ const citationIdMap = new Map();
935
+ for (let dataRowIndex = 0; dataRowIndex < rowSpan; dataRowIndex++) {
936
+ const rowData = selectedRowValues[dataRowIndex];
937
+ if (!rowData)
938
+ continue;
939
+ for (let dataColumnIndex = 0; dataColumnIndex < colSpan; dataColumnIndex++) {
940
+ const cellValue = rowData[dataColumnIndex];
941
+ if (cellValue &&
942
+ typeof cellValue === "object" &&
943
+ "citationId" in cellValue &&
944
+ cellValue.citationId) {
945
+ citationIdMap.set(cellValue.citationId, {
946
+ sourceRowIndex: dataRowIndex,
947
+ sourceColumnIndex: dataColumnIndex,
948
+ });
859
949
  }
860
950
  }
861
- if (newCitations.length > 0) {
862
- // Add new citations
951
+ }
952
+ if (citationIdMap.size > 0) {
953
+ if (isCutOperation && from && !isNil(sourceSheetId)) {
954
+ // For cut operation: Move citations to new position
863
955
  onChangeCitations((prevCitations) => {
864
956
  const [nextState, patches, inversePatches] = produceWithPatches(prevCitations, (draft) => {
865
- draft.push(...newCitations);
957
+ for (const citationId of citationIdMap.keys()) {
958
+ const citation = draft.find((c) => c.id === citationId);
959
+ if (citation) {
960
+ // Update citation range to new position
961
+ citation.range.sheetId = destinationSheetId;
962
+ citation.range.startRowIndex += rowDelta;
963
+ citation.range.endRowIndex += rowDelta;
964
+ citation.range.startColumnIndex += columnDelta;
965
+ citation.range.endColumnIndex += columnDelta;
966
+ }
967
+ }
866
968
  });
867
969
  saveHistory({
868
970
  citations: { patches, inversePatches },
869
971
  });
870
972
  return nextState;
871
973
  });
872
- // Update cell citationIds to point to new citations
873
- onChangeSheetData?.((prevSheetData) => {
874
- const [nextState, patches, inversePatches] = produceWithPatches(prevSheetData, (draft) => {
875
- for (const { rowIndex } of destinationRows) {
876
- for (let columnIndex = to.range.startColumnIndex; columnIndex <= to.range.endColumnIndex; columnIndex++) {
877
- const cellData = draft[destinationSheetId]?.[rowIndex]?.values?.[columnIndex];
878
- if (cellData?.citationId) {
879
- const newCitationId = citationIdRemap.get(cellData.citationId);
880
- if (newCitationId) {
881
- cellData.citationId = newCitationId;
974
+ }
975
+ else if (!isCutOperation) {
976
+ // For paste (copy) operation: Create new citations with new IDs
977
+ const newCitations = [];
978
+ const citationIdRemap = new Map();
979
+ for (const [oldCitationId, { sourceRowIndex, sourceColumnIndex },] of citationIdMap.entries()) {
980
+ const originalCitation = citations?.find((c) => c.id === oldCitationId);
981
+ if (originalCitation) {
982
+ const newId = uuidString();
983
+ citationIdRemap.set(oldCitationId, newId);
984
+ // Calculate the new range based on paste destination
985
+ const newCitation = {
986
+ ...originalCitation,
987
+ id: newId,
988
+ range: {
989
+ sheetId: destinationSheetId,
990
+ startRowIndex: to.range.startRowIndex + sourceRowIndex,
991
+ endRowIndex: to.range.startRowIndex + sourceRowIndex,
992
+ startColumnIndex: to.range.startColumnIndex + sourceColumnIndex,
993
+ endColumnIndex: to.range.startColumnIndex + sourceColumnIndex,
994
+ },
995
+ };
996
+ newCitations.push(newCitation);
997
+ }
998
+ }
999
+ if (newCitations.length > 0) {
1000
+ // Add new citations
1001
+ onChangeCitations((prevCitations) => {
1002
+ const [nextState, patches, inversePatches] = produceWithPatches(prevCitations, (draft) => {
1003
+ draft.push(...newCitations);
1004
+ });
1005
+ saveHistory({
1006
+ citations: { patches, inversePatches },
1007
+ });
1008
+ return nextState;
1009
+ });
1010
+ // Update cell citationIds to point to new citations
1011
+ onChangeSheetData?.((prevSheetData) => {
1012
+ const [nextState, patches, inversePatches] = produceWithPatches(prevSheetData, (draft) => {
1013
+ for (const { rowIndex } of destinationRows) {
1014
+ for (let columnIndex = to.range.startColumnIndex; columnIndex <= to.range.endColumnIndex; columnIndex++) {
1015
+ const cellData = draft[destinationSheetId]?.[rowIndex]?.values?.[columnIndex];
1016
+ if (cellData?.citationId) {
1017
+ const newCitationId = citationIdRemap.get(cellData.citationId);
1018
+ if (newCitationId) {
1019
+ cellData.citationId = newCitationId;
1020
+ }
882
1021
  }
883
1022
  }
884
1023
  }
885
- }
886
- });
887
- saveHistory({
888
- sheetData: { patches, inversePatches },
1024
+ });
1025
+ saveHistory({
1026
+ sheetData: { patches, inversePatches },
1027
+ });
1028
+ return nextState;
889
1029
  });
890
- return nextState;
891
- });
1030
+ }
892
1031
  }
893
1032
  }
894
1033
  }
895
- }
1034
+ });
896
1035
  }, [
897
1036
  rowCount,
898
1037
  columnCount,
@@ -909,6 +1048,9 @@ export const useOnPaste = ({ rowCount, columnCount, locale, sheetData, tables: c
909
1048
  onRequestFonts,
910
1049
  idCreationStrategy,
911
1050
  createHistory,
1051
+ batchHistory,
1052
+ autoExpandTables,
1053
+ autoCalculatedColumns,
912
1054
  enqueueStructureChange,
913
1055
  enqueueGraphOperation,
914
1056
  onChangeCalculatedColumn,
@@ -936,6 +1078,7 @@ export const useOnPaste = ({ rowCount, columnCount, locale, sheetData, tables: c
936
1078
  onCommand,
937
1079
  generatedNames,
938
1080
  onChangeNamedRanges,
1081
+ onChangeCharts,
939
1082
  getSheetMerges,
940
1083
  showError,
941
1084
  ]);