@rowsncolumns/spreadsheet-state 28.0.75 → 28.0.76

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 (201) hide show
  1. package/dist/cjs/api/anchored-objects.d.ts +66 -0
  2. package/dist/cjs/api/anchored-objects.d.ts.map +1 -0
  3. package/dist/cjs/api/anchored-objects.js +259 -0
  4. package/dist/cjs/api/dependency.d.ts +13 -2
  5. package/dist/cjs/api/dependency.d.ts.map +1 -1
  6. package/dist/cjs/api/dependency.js +11 -5
  7. package/dist/cjs/api/formula.d.ts +61 -4
  8. package/dist/cjs/api/formula.d.ts.map +1 -1
  9. package/dist/cjs/api/formula.js +250 -61
  10. package/dist/cjs/api/merges.d.ts +8 -0
  11. package/dist/cjs/api/merges.d.ts.map +1 -1
  12. package/dist/cjs/api/merges.js +64 -1
  13. package/dist/cjs/api/named-range-structural.d.ts +62 -0
  14. package/dist/cjs/api/named-range-structural.d.ts.map +1 -0
  15. package/dist/cjs/api/named-range-structural.js +197 -0
  16. package/dist/cjs/api/range-rule-helpers.d.ts +45 -1
  17. package/dist/cjs/api/range-rule-helpers.d.ts.map +1 -1
  18. package/dist/cjs/api/range-rule-helpers.js +159 -6
  19. package/dist/cjs/api/structural-formula-update.d.ts.map +1 -1
  20. package/dist/cjs/api/structural-formula-update.js +24 -6
  21. package/dist/cjs/api/structural-guards.d.ts +78 -0
  22. package/dist/cjs/api/structural-guards.d.ts.map +1 -0
  23. package/dist/cjs/api/structural-guards.js +202 -0
  24. package/dist/cjs/api/structural-table-refs.d.ts +94 -0
  25. package/dist/cjs/api/structural-table-refs.d.ts.map +1 -0
  26. package/dist/cjs/api/structural-table-refs.js +313 -0
  27. package/dist/cjs/constants.d.ts +25 -0
  28. package/dist/cjs/constants.d.ts.map +1 -0
  29. package/dist/cjs/constants.js +26 -0
  30. package/dist/cjs/hooks/use-calculation-worker.d.ts.map +1 -1
  31. package/dist/cjs/hooks/use-calculation-worker.js +64 -6
  32. package/dist/cjs/hooks/use-calculation.d.ts +7 -0
  33. package/dist/cjs/hooks/use-calculation.d.ts.map +1 -1
  34. package/dist/cjs/hooks/use-calculation.js +15 -0
  35. package/dist/cjs/hooks/use-on-calculation-success.d.ts +7 -0
  36. package/dist/cjs/hooks/use-on-calculation-success.d.ts.map +1 -1
  37. package/dist/cjs/hooks/use-on-calculation-success.js +7 -1
  38. package/dist/cjs/hooks/use-on-delete-cells-shift-left.d.ts +13 -3
  39. package/dist/cjs/hooks/use-on-delete-cells-shift-left.d.ts.map +1 -1
  40. package/dist/cjs/hooks/use-on-delete-cells-shift-left.js +27 -2
  41. package/dist/cjs/hooks/use-on-delete-cells-shift-up.d.ts +13 -3
  42. package/dist/cjs/hooks/use-on-delete-cells-shift-up.d.ts.map +1 -1
  43. package/dist/cjs/hooks/use-on-delete-cells-shift-up.js +27 -2
  44. package/dist/cjs/hooks/use-on-delete-column.d.ts +13 -4
  45. package/dist/cjs/hooks/use-on-delete-column.d.ts.map +1 -1
  46. package/dist/cjs/hooks/use-on-delete-column.js +14 -2
  47. package/dist/cjs/hooks/use-on-delete-row.d.ts +13 -4
  48. package/dist/cjs/hooks/use-on-delete-row.d.ts.map +1 -1
  49. package/dist/cjs/hooks/use-on-delete-row.js +14 -2
  50. package/dist/cjs/hooks/use-on-insert-cells-shift-down.d.ts +13 -3
  51. package/dist/cjs/hooks/use-on-insert-cells-shift-down.d.ts.map +1 -1
  52. package/dist/cjs/hooks/use-on-insert-cells-shift-down.js +27 -2
  53. package/dist/cjs/hooks/use-on-insert-cells-shift-right.d.ts +13 -3
  54. package/dist/cjs/hooks/use-on-insert-cells-shift-right.d.ts.map +1 -1
  55. package/dist/cjs/hooks/use-on-insert-cells-shift-right.js +27 -2
  56. package/dist/cjs/hooks/use-on-insert-column.d.ts +10 -3
  57. package/dist/cjs/hooks/use-on-insert-column.d.ts.map +1 -1
  58. package/dist/cjs/hooks/use-on-insert-column.js +33 -7
  59. package/dist/cjs/hooks/use-on-insert-row.d.ts +10 -3
  60. package/dist/cjs/hooks/use-on-insert-row.d.ts.map +1 -1
  61. package/dist/cjs/hooks/use-on-insert-row.js +32 -7
  62. package/dist/cjs/hooks/use-spreadsheet-state.d.ts +2 -2
  63. package/dist/cjs/hooks/use-spreadsheet-state.d.ts.map +1 -1
  64. package/dist/cjs/hooks/use-spreadsheet-state.js +61 -15
  65. package/dist/cjs/hooks/use-structured-reference.d.ts.map +1 -1
  66. package/dist/cjs/hooks/use-structured-reference.js +10 -6
  67. package/dist/cjs/index.d.ts +3 -0
  68. package/dist/cjs/index.d.ts.map +1 -1
  69. package/dist/cjs/index.js +3 -0
  70. package/dist/cjs/interface/calculation-interface.d.ts +9 -0
  71. package/dist/cjs/interface/calculation-interface.d.ts.map +1 -1
  72. package/dist/cjs/interface/calculation-interface.js +31 -2
  73. package/dist/cjs/interface/delete-cells-shift-left.d.ts +8 -1
  74. package/dist/cjs/interface/delete-cells-shift-left.d.ts.map +1 -1
  75. package/dist/cjs/interface/delete-cells-shift-left.js +158 -80
  76. package/dist/cjs/interface/delete-cells-shift-up.d.ts +9 -1
  77. package/dist/cjs/interface/delete-cells-shift-up.d.ts.map +1 -1
  78. package/dist/cjs/interface/delete-cells-shift-up.js +155 -73
  79. package/dist/cjs/interface/delete-column.d.ts +1 -1
  80. package/dist/cjs/interface/delete-column.d.ts.map +1 -1
  81. package/dist/cjs/interface/delete-column.js +90 -31
  82. package/dist/cjs/interface/delete-row.d.ts +1 -1
  83. package/dist/cjs/interface/delete-row.d.ts.map +1 -1
  84. package/dist/cjs/interface/delete-row.js +85 -26
  85. package/dist/cjs/interface/insert-cells-shift-down.d.ts +10 -1
  86. package/dist/cjs/interface/insert-cells-shift-down.d.ts.map +1 -1
  87. package/dist/cjs/interface/insert-cells-shift-down.js +147 -52
  88. package/dist/cjs/interface/insert-cells-shift-right.d.ts +10 -1
  89. package/dist/cjs/interface/insert-cells-shift-right.d.ts.map +1 -1
  90. package/dist/cjs/interface/insert-cells-shift-right.js +154 -58
  91. package/dist/cjs/interface/insert-column.d.ts +1 -1
  92. package/dist/cjs/interface/insert-column.d.ts.map +1 -1
  93. package/dist/cjs/interface/insert-column.js +46 -8
  94. package/dist/cjs/interface/insert-row.d.ts +1 -1
  95. package/dist/cjs/interface/insert-row.d.ts.map +1 -1
  96. package/dist/cjs/interface/insert-row.js +47 -10
  97. package/dist/cjs/interface/spreadsheet-interface.d.ts.map +1 -1
  98. package/dist/cjs/interface/spreadsheet-interface.js +33 -0
  99. package/dist/cjs/sheet-cell.d.ts.map +1 -1
  100. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  101. package/dist/esm/api/anchored-objects.d.ts +66 -0
  102. package/dist/esm/api/anchored-objects.d.ts.map +1 -0
  103. package/dist/esm/api/anchored-objects.js +212 -0
  104. package/dist/esm/api/dependency.d.ts +13 -2
  105. package/dist/esm/api/dependency.d.ts.map +1 -1
  106. package/dist/esm/api/dependency.js +10 -4
  107. package/dist/esm/api/formula.d.ts +61 -4
  108. package/dist/esm/api/formula.d.ts.map +1 -1
  109. package/dist/esm/api/formula.js +238 -60
  110. package/dist/esm/api/merges.d.ts +8 -0
  111. package/dist/esm/api/merges.d.ts.map +1 -1
  112. package/dist/esm/api/merges.js +51 -0
  113. package/dist/esm/api/named-range-structural.d.ts +62 -0
  114. package/dist/esm/api/named-range-structural.d.ts.map +1 -0
  115. package/dist/esm/api/named-range-structural.js +176 -0
  116. package/dist/esm/api/range-rule-helpers.d.ts +45 -1
  117. package/dist/esm/api/range-rule-helpers.d.ts.map +1 -1
  118. package/dist/esm/api/range-rule-helpers.js +153 -1
  119. package/dist/esm/api/structural-formula-update.d.ts.map +1 -1
  120. package/dist/esm/api/structural-formula-update.js +24 -6
  121. package/dist/esm/api/structural-guards.d.ts +78 -0
  122. package/dist/esm/api/structural-guards.d.ts.map +1 -0
  123. package/dist/esm/api/structural-guards.js +186 -0
  124. package/dist/esm/api/structural-table-refs.d.ts +94 -0
  125. package/dist/esm/api/structural-table-refs.d.ts.map +1 -0
  126. package/dist/esm/api/structural-table-refs.js +219 -0
  127. package/dist/esm/constants.d.ts +25 -0
  128. package/dist/esm/constants.d.ts.map +1 -0
  129. package/dist/esm/constants.js +26 -0
  130. package/dist/esm/hooks/use-calculation-worker.d.ts.map +1 -1
  131. package/dist/esm/hooks/use-calculation-worker.js +45 -0
  132. package/dist/esm/hooks/use-calculation.d.ts +7 -0
  133. package/dist/esm/hooks/use-calculation.d.ts.map +1 -1
  134. package/dist/esm/hooks/use-calculation.js +15 -0
  135. package/dist/esm/hooks/use-on-calculation-success.d.ts +7 -0
  136. package/dist/esm/hooks/use-on-calculation-success.d.ts.map +1 -1
  137. package/dist/esm/hooks/use-on-calculation-success.js +7 -1
  138. package/dist/esm/hooks/use-on-delete-cells-shift-left.d.ts +13 -3
  139. package/dist/esm/hooks/use-on-delete-cells-shift-left.d.ts.map +1 -1
  140. package/dist/esm/hooks/use-on-delete-cells-shift-left.js +26 -2
  141. package/dist/esm/hooks/use-on-delete-cells-shift-up.d.ts +13 -3
  142. package/dist/esm/hooks/use-on-delete-cells-shift-up.d.ts.map +1 -1
  143. package/dist/esm/hooks/use-on-delete-cells-shift-up.js +26 -2
  144. package/dist/esm/hooks/use-on-delete-column.d.ts +13 -4
  145. package/dist/esm/hooks/use-on-delete-column.d.ts.map +1 -1
  146. package/dist/esm/hooks/use-on-delete-column.js +14 -2
  147. package/dist/esm/hooks/use-on-delete-row.d.ts +13 -4
  148. package/dist/esm/hooks/use-on-delete-row.d.ts.map +1 -1
  149. package/dist/esm/hooks/use-on-delete-row.js +14 -2
  150. package/dist/esm/hooks/use-on-insert-cells-shift-down.d.ts +13 -3
  151. package/dist/esm/hooks/use-on-insert-cells-shift-down.d.ts.map +1 -1
  152. package/dist/esm/hooks/use-on-insert-cells-shift-down.js +26 -2
  153. package/dist/esm/hooks/use-on-insert-cells-shift-right.d.ts +13 -3
  154. package/dist/esm/hooks/use-on-insert-cells-shift-right.d.ts.map +1 -1
  155. package/dist/esm/hooks/use-on-insert-cells-shift-right.js +26 -2
  156. package/dist/esm/hooks/use-on-insert-column.d.ts +10 -3
  157. package/dist/esm/hooks/use-on-insert-column.d.ts.map +1 -1
  158. package/dist/esm/hooks/use-on-insert-column.js +33 -7
  159. package/dist/esm/hooks/use-on-insert-row.d.ts +10 -3
  160. package/dist/esm/hooks/use-on-insert-row.d.ts.map +1 -1
  161. package/dist/esm/hooks/use-on-insert-row.js +32 -7
  162. package/dist/esm/hooks/use-spreadsheet-state.d.ts +2 -2
  163. package/dist/esm/hooks/use-spreadsheet-state.d.ts.map +1 -1
  164. package/dist/esm/hooks/use-spreadsheet-state.js +61 -15
  165. package/dist/esm/hooks/use-structured-reference.d.ts.map +1 -1
  166. package/dist/esm/hooks/use-structured-reference.js +10 -6
  167. package/dist/esm/index.d.ts +3 -0
  168. package/dist/esm/index.d.ts.map +1 -1
  169. package/dist/esm/index.js +3 -0
  170. package/dist/esm/interface/calculation-interface.d.ts +9 -0
  171. package/dist/esm/interface/calculation-interface.d.ts.map +1 -1
  172. package/dist/esm/interface/calculation-interface.js +33 -2
  173. package/dist/esm/interface/delete-cells-shift-left.d.ts +8 -1
  174. package/dist/esm/interface/delete-cells-shift-left.d.ts.map +1 -1
  175. package/dist/esm/interface/delete-cells-shift-left.js +135 -59
  176. package/dist/esm/interface/delete-cells-shift-up.d.ts +9 -1
  177. package/dist/esm/interface/delete-cells-shift-up.d.ts.map +1 -1
  178. package/dist/esm/interface/delete-cells-shift-up.js +133 -53
  179. package/dist/esm/interface/delete-column.d.ts +1 -1
  180. package/dist/esm/interface/delete-column.d.ts.map +1 -1
  181. package/dist/esm/interface/delete-column.js +80 -11
  182. package/dist/esm/interface/delete-row.d.ts +1 -1
  183. package/dist/esm/interface/delete-row.d.ts.map +1 -1
  184. package/dist/esm/interface/delete-row.js +81 -11
  185. package/dist/esm/interface/insert-cells-shift-down.d.ts +10 -1
  186. package/dist/esm/interface/insert-cells-shift-down.d.ts.map +1 -1
  187. package/dist/esm/interface/insert-cells-shift-down.js +116 -47
  188. package/dist/esm/interface/insert-cells-shift-right.d.ts +10 -1
  189. package/dist/esm/interface/insert-cells-shift-right.d.ts.map +1 -1
  190. package/dist/esm/interface/insert-cells-shift-right.js +120 -51
  191. package/dist/esm/interface/insert-column.d.ts +1 -1
  192. package/dist/esm/interface/insert-column.d.ts.map +1 -1
  193. package/dist/esm/interface/insert-column.js +46 -8
  194. package/dist/esm/interface/insert-row.d.ts +1 -1
  195. package/dist/esm/interface/insert-row.d.ts.map +1 -1
  196. package/dist/esm/interface/insert-row.js +47 -10
  197. package/dist/esm/interface/spreadsheet-interface.d.ts.map +1 -1
  198. package/dist/esm/interface/spreadsheet-interface.js +29 -0
  199. package/dist/esm/sheet-cell.d.ts.map +1 -1
  200. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  201. package/package.json +16 -16
@@ -0,0 +1,62 @@
1
+ import type { NamedRange, SheetPrintSettings } from "@rowsncolumns/spreadsheet";
2
+ import type { WritableDraft } from "immer";
3
+ export type StructuralAxis = "row" | "column";
4
+ export type StructuralOp = "insert" | "delete";
5
+ /**
6
+ * The `value` a defined name carries once every cell of its range has been
7
+ * deleted. Excel keeps the name in the Name Manager as `=Sheet1!#REF!` and
8
+ * every formula that uses it evaluates to `#REF!` (not `#NAME?`), so the
9
+ * name survives with no range and this error marker as its value; the
10
+ * calculation worker's name resolver turns it into `FormulaError.REF`.
11
+ */
12
+ export declare const NAMED_RANGE_REF_ERROR = "#REF!";
13
+ export declare const isRefErrorNamedRange: (namedRange: Pick<NamedRange, "range" | "value">) => boolean;
14
+ /**
15
+ * Shift the inclusive `[start, end]` band of a defined name / print band for
16
+ * an insert or delete of `count` rows or columns at `index` (1-based).
17
+ * Excel's rule for a name's RefersTo, identical to the Rust engine's
18
+ * `shift_named_ranges`:
19
+ *
20
+ * - insert at or above the first index → the whole band shifts;
21
+ * - insert strictly inside → the band grows;
22
+ * - insert at the boundary directly below → unchanged;
23
+ * - delete wholly above → shifts back; delete overlapping → shrinks by the
24
+ * deleted indices inside the band; delete covering the band → `null`.
25
+ */
26
+ export declare const shiftNamedBand: (start: number, end: number, op: StructuralOp, index: number, count: number) => [number, number] | null;
27
+ export type NamedRangeStructuralUpdate<N extends NamedRange> = {
28
+ /** Names whose range moved, grew, or shrank. */
29
+ changed: N[];
30
+ /** Names whose whole range was deleted — kept, now `=#REF!`. */
31
+ refErrored: N[];
32
+ };
33
+ /**
34
+ * Adjust defined names for a sheet-level insert/delete on `sheetId`,
35
+ * mutating the immer `draft` in place. Only names whose `range.sheetId` is
36
+ * the edited sheet move — a name's scope (`scopeSheetId`) governs how it is
37
+ * resolved, not which sheet's edits shift it (a Sheet2-scoped name pointing
38
+ * at Sheet2!$B$4 shifts on Sheet2 edits, never on Sheet1 edits). Value
39
+ * names (`=SUM(...)*2`, `0.1`) have no grid range and pass through.
40
+ *
41
+ * A name whose entire range is deleted is NOT dropped: it keeps its entry
42
+ * with `range` cleared and `value: "#REF!"`, so `=SUM(Data)` evaluates to
43
+ * `#REF!` like Excel rather than `#NAME?`.
44
+ */
45
+ export declare const updateNamedRangesOnStructuralChange: (draft: WritableDraft<NamedRange>[], axis: StructuralAxis, op: StructuralOp, index: number, count: number, sheetId: number) => NamedRangeStructuralUpdate<WritableDraft<NamedRange>>;
46
+ /**
47
+ * Pure variant of {@link updateNamedRangesOnStructuralChange}: returns the
48
+ * adjusted list (sharing untouched entries) plus the names that changed.
49
+ */
50
+ export declare const shiftNamedRangesOnStructuralChange: <N extends NamedRange>(namedRanges: readonly N[], axis: StructuralAxis, op: StructuralOp, index: number, count: number, sheetId: number) => {
51
+ next: N[];
52
+ } & NamedRangeStructuralUpdate<N>;
53
+ /**
54
+ * `_xlnm.Print_Area` / `_xlnm.Print_Titles` are sheet-scoped defined names
55
+ * in Excel and follow the same RefersTo rule as any other name. Mutates the
56
+ * sheet's `printSettings` draft: each print-area rectangle shifts / grows /
57
+ * shrinks (a rectangle wholly deleted is removed; an emptied print area is
58
+ * cleared), and the repeated title rows / columns shift as a band along the
59
+ * edited axis (cleared when every title row / column is deleted).
60
+ */
61
+ export declare const updatePrintSettingsOnStructuralChange: (printSettings: WritableDraft<SheetPrintSettings>, axis: StructuralAxis, op: StructuralOp, index: number, count: number) => boolean;
62
+ //# sourceMappingURL=named-range-structural.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"named-range-structural.d.ts","sourceRoot":"","sources":["../../../api/named-range-structural.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,UAAU,EAEV,kBAAkB,EACnB,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAE3C,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,QAAQ,CAAC;AAC9C,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE/C;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,UAAU,CAAC;AAE7C,eAAO,MAAM,oBAAoB,GAC/B,YAAY,IAAI,CAAC,UAAU,EAAE,OAAO,GAAG,OAAO,CAAC,YACmB,CAAC;AAErE;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,cAAc,GACzB,OAAO,MAAM,EACb,KAAK,MAAM,EACX,IAAI,YAAY,EAChB,OAAO,MAAM,EACb,OAAO,MAAM,KACZ,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAgBrB,CAAC;AAmBF,MAAM,MAAM,0BAA0B,CAAC,CAAC,SAAS,UAAU,IAAI;IAC7D,gDAAgD;IAChD,OAAO,EAAE,CAAC,EAAE,CAAC;IACb,gEAAgE;IAChE,UAAU,EAAE,CAAC,EAAE,CAAC;CACjB,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,mCAAmC,GAC9C,OAAO,aAAa,CAAC,UAAU,CAAC,EAAE,EAClC,MAAM,cAAc,EACpB,IAAI,YAAY,EAChB,OAAO,MAAM,EACb,OAAO,MAAM,EACb,SAAS,MAAM,KACd,0BAA0B,CAAC,aAAa,CAAC,UAAU,CAAC,CAmBtD,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,kCAAkC,GAAI,CAAC,SAAS,UAAU,EACrE,aAAa,SAAS,CAAC,EAAE,EACzB,MAAM,cAAc,EACpB,IAAI,YAAY,EAChB,OAAO,MAAM,EACb,OAAO,MAAM,EACb,SAAS,MAAM,KACd;IAAE,IAAI,EAAE,CAAC,EAAE,CAAA;CAAE,GAAG,0BAA0B,CAAC,CAAC,CAsB9C,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,qCAAqC,GAChD,eAAe,aAAa,CAAC,kBAAkB,CAAC,EAChD,MAAM,cAAc,EACpB,IAAI,YAAY,EAChB,OAAO,MAAM,EACb,OAAO,MAAM,KACZ,OAiDF,CAAC"}
@@ -0,0 +1,176 @@
1
+ /**
2
+ * The `value` a defined name carries once every cell of its range has been
3
+ * deleted. Excel keeps the name in the Name Manager as `=Sheet1!#REF!` and
4
+ * every formula that uses it evaluates to `#REF!` (not `#NAME?`), so the
5
+ * name survives with no range and this error marker as its value; the
6
+ * calculation worker's name resolver turns it into `FormulaError.REF`.
7
+ */
8
+ export const NAMED_RANGE_REF_ERROR = "#REF!";
9
+ export const isRefErrorNamedRange = (namedRange) => !namedRange.range && namedRange.value === NAMED_RANGE_REF_ERROR;
10
+ /**
11
+ * Shift the inclusive `[start, end]` band of a defined name / print band for
12
+ * an insert or delete of `count` rows or columns at `index` (1-based).
13
+ * Excel's rule for a name's RefersTo, identical to the Rust engine's
14
+ * `shift_named_ranges`:
15
+ *
16
+ * - insert at or above the first index → the whole band shifts;
17
+ * - insert strictly inside → the band grows;
18
+ * - insert at the boundary directly below → unchanged;
19
+ * - delete wholly above → shifts back; delete overlapping → shrinks by the
20
+ * deleted indices inside the band; delete covering the band → `null`.
21
+ */
22
+ export const shiftNamedBand = (start, end, op, index, count) => {
23
+ if (count <= 0)
24
+ return [start, end];
25
+ const s = Math.max(1, start);
26
+ const e = Math.max(s, end);
27
+ if (op === "insert") {
28
+ if (index <= s)
29
+ return [s + count, e + count];
30
+ if (index <= e)
31
+ return [s, e + count];
32
+ return [s, e];
33
+ }
34
+ const deleteEnd = index + count - 1;
35
+ if (deleteEnd < s)
36
+ return [s - count, e - count];
37
+ if (index > e)
38
+ return [s, e];
39
+ if (index <= s && deleteEnd >= e)
40
+ return null;
41
+ const before = Math.max(s - index, 0);
42
+ const inside = Math.min(deleteEnd, e) - Math.max(index, s) + 1;
43
+ return [s - before, e - before - inside];
44
+ };
45
+ const shiftGridRange = (range, axis, op, index, count) => {
46
+ const [startKey, endKey] = axis === "row"
47
+ ? ["startRowIndex", "endRowIndex"]
48
+ : ["startColumnIndex", "endColumnIndex"];
49
+ const next = shiftNamedBand(range[startKey], range[endKey], op, index, count);
50
+ if (!next)
51
+ return null;
52
+ if (next[0] === range[startKey] && next[1] === range[endKey])
53
+ return range;
54
+ return { ...range, [startKey]: next[0], [endKey]: next[1] };
55
+ };
56
+ /**
57
+ * Adjust defined names for a sheet-level insert/delete on `sheetId`,
58
+ * mutating the immer `draft` in place. Only names whose `range.sheetId` is
59
+ * the edited sheet move — a name's scope (`scopeSheetId`) governs how it is
60
+ * resolved, not which sheet's edits shift it (a Sheet2-scoped name pointing
61
+ * at Sheet2!$B$4 shifts on Sheet2 edits, never on Sheet1 edits). Value
62
+ * names (`=SUM(...)*2`, `0.1`) have no grid range and pass through.
63
+ *
64
+ * A name whose entire range is deleted is NOT dropped: it keeps its entry
65
+ * with `range` cleared and `value: "#REF!"`, so `=SUM(Data)` evaluates to
66
+ * `#REF!` like Excel rather than `#NAME?`.
67
+ */
68
+ export const updateNamedRangesOnStructuralChange = (draft, axis, op, index, count, sheetId) => {
69
+ const changed = [];
70
+ const refErrored = [];
71
+ if (count <= 0)
72
+ return { changed, refErrored };
73
+ for (const namedRange of draft) {
74
+ const range = namedRange.range;
75
+ if (!range || range.sheetId !== sheetId)
76
+ continue;
77
+ const next = shiftGridRange(range, axis, op, index, count);
78
+ if (next === range)
79
+ continue;
80
+ if (next === null) {
81
+ namedRange.range = undefined;
82
+ namedRange.value = NAMED_RANGE_REF_ERROR;
83
+ refErrored.push(namedRange);
84
+ continue;
85
+ }
86
+ namedRange.range = next;
87
+ changed.push(namedRange);
88
+ }
89
+ return { changed, refErrored };
90
+ };
91
+ /**
92
+ * Pure variant of {@link updateNamedRangesOnStructuralChange}: returns the
93
+ * adjusted list (sharing untouched entries) plus the names that changed.
94
+ */
95
+ export const shiftNamedRangesOnStructuralChange = (namedRanges, axis, op, index, count, sheetId) => {
96
+ const changed = [];
97
+ const refErrored = [];
98
+ const next = namedRanges.map((namedRange) => {
99
+ const range = namedRange.range;
100
+ if (!range || range.sheetId !== sheetId || count <= 0)
101
+ return namedRange;
102
+ const shifted = shiftGridRange(range, axis, op, index, count);
103
+ if (shifted === range)
104
+ return namedRange;
105
+ if (shifted === null) {
106
+ const broken = {
107
+ ...namedRange,
108
+ range: undefined,
109
+ value: NAMED_RANGE_REF_ERROR,
110
+ };
111
+ refErrored.push(broken);
112
+ return broken;
113
+ }
114
+ const moved = { ...namedRange, range: shifted };
115
+ changed.push(moved);
116
+ return moved;
117
+ });
118
+ return { next, changed, refErrored };
119
+ };
120
+ /**
121
+ * `_xlnm.Print_Area` / `_xlnm.Print_Titles` are sheet-scoped defined names
122
+ * in Excel and follow the same RefersTo rule as any other name. Mutates the
123
+ * sheet's `printSettings` draft: each print-area rectangle shifts / grows /
124
+ * shrinks (a rectangle wholly deleted is removed; an emptied print area is
125
+ * cleared), and the repeated title rows / columns shift as a band along the
126
+ * edited axis (cleared when every title row / column is deleted).
127
+ */
128
+ export const updatePrintSettingsOnStructuralChange = (printSettings, axis, op, index, count) => {
129
+ if (count <= 0)
130
+ return false;
131
+ let changed = false;
132
+ if (printSettings.printArea?.length) {
133
+ const nextAreas = [];
134
+ for (const area of printSettings.printArea) {
135
+ const next = shiftGridRange(area, axis, op, index, count);
136
+ if (next !== area)
137
+ changed = true;
138
+ if (next)
139
+ nextAreas.push(next);
140
+ }
141
+ if (changed) {
142
+ if (nextAreas.length) {
143
+ printSettings.printArea = nextAreas;
144
+ }
145
+ else {
146
+ delete printSettings.printArea;
147
+ }
148
+ }
149
+ }
150
+ const titles = printSettings.printTitles;
151
+ if (titles) {
152
+ const [startKey, endKey] = axis === "row" ? ["rowStart", "rowEnd"] : ["columnStart", "columnEnd"];
153
+ const start = titles[startKey];
154
+ const end = titles[endKey];
155
+ if (start != null && end != null) {
156
+ const next = shiftNamedBand(start, end, op, index, count);
157
+ if (!next) {
158
+ delete titles[startKey];
159
+ delete titles[endKey];
160
+ changed = true;
161
+ if (titles.rowStart == null &&
162
+ titles.rowEnd == null &&
163
+ titles.columnStart == null &&
164
+ titles.columnEnd == null) {
165
+ delete printSettings.printTitles;
166
+ }
167
+ }
168
+ else if (next[0] !== start || next[1] !== end) {
169
+ titles[startKey] = next[0];
170
+ titles[endKey] = next[1];
171
+ changed = true;
172
+ }
173
+ }
174
+ }
175
+ return changed;
176
+ };
@@ -1,17 +1,61 @@
1
1
  import type { GridRange, SheetRange } from "@rowsncolumns/common-types";
2
2
  import type { WritableDraft } from "immer";
3
3
  type RangedRuleAxis = "row" | "column";
4
+ /**
5
+ * Sheet-name lookup the rule-formula rewrite needs to scope references:
6
+ * unqualified references in a CF/DV formula resolve on the sheet the rule's
7
+ * applies-to range lives on, so only when that is the edited sheet do they
8
+ * move; `EditedSheet!`-qualified references move from any sheet.
9
+ */
10
+ export type RuleFormulaScope = {
11
+ getSheetName(sheetId: number): string;
12
+ };
13
+ export type RuleFormulaStructuralParams = {
14
+ op: "insert" | "delete";
15
+ axis: RangedRuleAxis;
16
+ /** 1-based index the rows/columns are inserted at / deleted from. */
17
+ index: number;
18
+ count: number;
19
+ /** Name of the sheet being edited. */
20
+ editedSheetName: string;
21
+ /** Name of the sheet the rule's applies-to range lives on. */
22
+ ruleSheetName: string;
23
+ /**
24
+ * How many rows/columns (along `axis`) the rule's top-left cell moved
25
+ * WITHIN the pre-edit grid because the previous top-left was deleted —
26
+ * the surviving top-left's instance formula becomes the rule text, so
27
+ * relative references are re-anchored by this delta first. 0 otherwise.
28
+ */
29
+ anchorRebase?: number;
30
+ };
31
+ /**
32
+ * Rewrite one CF / DV formula (`=…`) for a sheet-level insert or delete,
33
+ * exactly as Excel rewrites the rule text: the formula is read as if it
34
+ * were entered in the rule's top-left cell, so relative and absolute
35
+ * references alike are grid positions that shift when they sit at/after
36
+ * the edit (`=$A1>$C$10` + insert row 5 → `=$A1>$C$11`), ranges spanning
37
+ * the edit grow / shrink, and a reference inside a deleted band becomes
38
+ * `#REF!`. Returns the input unchanged when it is not a formula or when
39
+ * no reference moved.
40
+ */
41
+ export declare const shiftRuleFormulaForStructuralChange: (formula: string, { op, axis, index, count, editedSheetName, ruleSheetName, anchorRebase, }: RuleFormulaStructuralParams) => string;
4
42
  /**
5
43
  * Apply an insert or delete range adjustment to a list of rules whose
6
44
  * `ranges: SheetRange[]` field references cells. Used for tables, conditional
7
45
  * formats, data validations, etc. Mutates the immer draft in place; rules
8
46
  * whose ranges all collapse to nothing are spliced out.
9
47
  *
48
+ * When `formulaScope` is given, each rule's condition formulas
49
+ * (`booleanRule.condition.values[].userEnteredValue` for CF,
50
+ * `condition.values[].userEnteredValue` for DV — those starting with `=`)
51
+ * are rewritten as if entered in the rule's applies-to top-left cell, see
52
+ * {@link shiftRuleFormulaForStructuralChange}.
53
+ *
10
54
  * Walks `draft` from the end so splice indices don't shift mid-iteration.
11
55
  */
12
56
  export declare const updateRangedRulesOnStructuralChange: <R extends {
13
57
  ranges?: SheetRange[] | null;
14
- }>(draft: WritableDraft<R>[], op: "insert" | "delete", axis: RangedRuleAxis, index: number, count: number, sheetId: number) => void;
58
+ }>(draft: WritableDraft<R>[], op: "insert" | "delete", axis: RangedRuleAxis, index: number, count: number, sheetId: number, formulaScope?: RuleFormulaScope) => void;
15
59
  /**
16
60
  * Returns true when a sheet range has any cells in the given grid bounds.
17
61
  * Cheap pre-check used by callers to skip patch generation for sheets that
@@ -1 +1 @@
1
- {"version":3,"file":"range-rule-helpers.d.ts","sourceRoot":"","sources":["../../../api/range-rule-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAI3C,KAAK,cAAc,GAAG,KAAK,GAAG,QAAQ,CAAC;AAEvC;;;;;;;GAOG;AACH,eAAO,MAAM,mCAAmC,GAC9C,CAAC,SAAS;IAAE,MAAM,CAAC,EAAE,UAAU,EAAE,GAAG,IAAI,CAAA;CAAE,EAE1C,OAAO,aAAa,CAAC,CAAC,CAAC,EAAE,EACzB,IAAI,QAAQ,GAAG,QAAQ,EACvB,MAAM,cAAc,EACpB,OAAO,MAAM,EACb,OAAO,MAAM,EACb,SAAS,MAAM,SAkBhB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAC5B,OAAO,UAAU,EACjB,SAAS,MAAM,EACf,QAAQ,SAAS,YASlB,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,aAAa,GACxB,OAAO,MAAM,EACb,YAAY,MAAM,EAClB,WAAW,MAAM,EACjB,gBAAgB,MAAM,KACrB,MAiBF,CAAC;AAEF,KAAK,WAAW,GAAG,KAAK,GAAG,QAAQ,CAAC;AAEpC;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,0BAA0B,GACrC,CAAC,SAAS;IAAE,MAAM,CAAC,EAAE,UAAU,EAAE,GAAG,IAAI,CAAA;CAAE,EAE1C,OAAO,aAAa,CAAC,CAAC,CAAC,EAAE,EACzB,MAAM,WAAW,EACjB,YAAY,MAAM,EAClB,WAAW,MAAM,EACjB,gBAAgB,MAAM,EACtB,SAAS,MAAM;AACf;;;;;;;;;GASG;AACH,qBAAqB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,SAkEpD,CAAC"}
1
+ {"version":3,"file":"range-rule-helpers.d.ts","sourceRoot":"","sources":["../../../api/range-rule-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,SAAS,EACT,UAAU,EACX,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAS3C,KAAK,cAAc,GAAG,KAAK,GAAG,QAAQ,CAAC;AAMvC;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;CACvC,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,EAAE,EAAE,QAAQ,GAAG,QAAQ,CAAC;IACxB,IAAI,EAAE,cAAc,CAAC;IACrB,qEAAqE;IACrE,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,sCAAsC;IACtC,eAAe,EAAE,MAAM,CAAC;IACxB,8DAA8D;IAC9D,aAAa,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,mCAAmC,GAC9C,SAAS,MAAM,EACf,2EAQG,2BAA2B,KAC7B,MAoHF,CAAC;AAsBF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,mCAAmC,GAC9C,CAAC,SAAS;IAAE,MAAM,CAAC,EAAE,UAAU,EAAE,GAAG,IAAI,CAAA;CAAE,EAE1C,OAAO,aAAa,CAAC,CAAC,CAAC,EAAE,EACzB,IAAI,QAAQ,GAAG,QAAQ,EACvB,MAAM,cAAc,EACpB,OAAO,MAAM,EACb,OAAO,MAAM,EACb,SAAS,MAAM,EACf,eAAe,gBAAgB,SA8ChC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAC5B,OAAO,UAAU,EACjB,SAAS,MAAM,EACf,QAAQ,SAAS,YASlB,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,aAAa,GACxB,OAAO,MAAM,EACb,YAAY,MAAM,EAClB,WAAW,MAAM,EACjB,gBAAgB,MAAM,KACrB,MAiBF,CAAC;AAEF,KAAK,WAAW,GAAG,KAAK,GAAG,QAAQ,CAAC;AAEpC;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,0BAA0B,GACrC,CAAC,SAAS;IAAE,MAAM,CAAC,EAAE,UAAU,EAAE,GAAG,IAAI,CAAA;CAAE,EAE1C,OAAO,aAAa,CAAC,CAAC,CAAC,EAAE,EACzB,MAAM,WAAW,EACjB,YAAY,MAAM,EAClB,WAAW,MAAM,EACjB,gBAAgB,MAAM,EACtB,SAAS,MAAM;AACf;;;;;;;;;GASG;AACH,qBAAqB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,SAkEpD,CAAC"}
@@ -1,16 +1,143 @@
1
+ import { contractRangesInFormula, expandRangesInFormula, formulaToRelativeReference, } from "./formula";
1
2
  import { updateSheetRangeOnDelete, updateSheetRangeOnInsert } from "./range";
3
+ /** Excel's grid bounds — the shift region for "every reference at/after the edit". */
4
+ const MAX_ROW_INDEX = 1_048_576;
5
+ const MAX_COLUMN_INDEX = 16_384;
6
+ /**
7
+ * Rewrite one CF / DV formula (`=…`) for a sheet-level insert or delete,
8
+ * exactly as Excel rewrites the rule text: the formula is read as if it
9
+ * were entered in the rule's top-left cell, so relative and absolute
10
+ * references alike are grid positions that shift when they sit at/after
11
+ * the edit (`=$A1>$C$10` + insert row 5 → `=$A1>$C$11`), ranges spanning
12
+ * the edit grow / shrink, and a reference inside a deleted band becomes
13
+ * `#REF!`. Returns the input unchanged when it is not a formula or when
14
+ * no reference moved.
15
+ */
16
+ export const shiftRuleFormulaForStructuralChange = (formula, { op, axis, index, count, editedSheetName, ruleSheetName, anchorRebase = 0, }) => {
17
+ if (!formula.startsWith("=") || count <= 0)
18
+ return formula;
19
+ const sameSheet = ruleSheetName.toLowerCase() === editedSheetName.toLowerCase();
20
+ const isRow = axis === "row";
21
+ const gridBounds = { rowCount: MAX_ROW_INDEX, columnCount: MAX_COLUMN_INDEX };
22
+ let next = formula;
23
+ // 1. The rule's previous top-left cell was deleted: the rule text is now
24
+ // the instance formula of the first surviving cell — relative
25
+ // references move with the anchor, absolutes stay.
26
+ if (anchorRebase > 0 && sameSheet) {
27
+ const source = { rowIndex: 1, columnIndex: 1 };
28
+ const destination = {
29
+ rowIndex: 1 + (isRow ? anchorRebase : 0),
30
+ columnIndex: 1 + (isRow ? 0 : anchorRebase),
31
+ };
32
+ next =
33
+ formulaToRelativeReference(next, source, destination, ruleSheetName, {
34
+ preserveAbsolutes: true,
35
+ ignoreCircular: true,
36
+ ignoreReferenceError: true,
37
+ ...gridBounds,
38
+ }) ?? next;
39
+ }
40
+ // 2. Delete: references wholly inside the deleted band are gone → `#REF!`.
41
+ // Shifting the band far off-grid lets `formulaToRelativeReference`'s
42
+ // reference-error path emit the token.
43
+ if (op === "delete") {
44
+ const band = isRow
45
+ ? {
46
+ startRowIndex: index,
47
+ endRowIndex: index + count - 1,
48
+ startColumnIndex: 1,
49
+ endColumnIndex: MAX_COLUMN_INDEX,
50
+ }
51
+ : {
52
+ startRowIndex: 1,
53
+ endRowIndex: MAX_ROW_INDEX,
54
+ startColumnIndex: index,
55
+ endColumnIndex: index + count - 1,
56
+ };
57
+ const offGrid = -(index + count);
58
+ next =
59
+ formulaToRelativeReference(next, { rowIndex: index, columnIndex: index }, {
60
+ rowIndex: isRow ? offGrid : index,
61
+ columnIndex: isRow ? index : offGrid,
62
+ }, editedSheetName, {
63
+ exclusionRange: band,
64
+ ignoreCircular: true,
65
+ ignoreReferenceError: true,
66
+ referenceSheetName: editedSheetName,
67
+ includeUnqualifiedReferences: sameSheet,
68
+ // Deliberately NOT the grid bounds: a whole-row / whole-column
69
+ // reference inside the band would otherwise be pushed to a
70
+ // negative index instead of `#REF!`; those stay put and are
71
+ // handled by the range contraction below.
72
+ rowCount: MAX_ROW_INDEX + 1,
73
+ columnCount: MAX_COLUMN_INDEX + 1,
74
+ }) ?? next;
75
+ }
76
+ // 3. Ranges that span the edit grow (insert) / shrink (delete).
77
+ next =
78
+ (op === "insert" ? expandRangesInFormula : contractRangesInFormula)(next, index, count, axis, editedSheetName, { includeUnqualifiedReferences: sameSheet }) ?? next;
79
+ // 4. Everything at/after the edit shifts by ±count along the axis.
80
+ const delta = op === "insert" ? count : -count;
81
+ const regionStart = op === "insert" ? index : index + count;
82
+ const region = isRow
83
+ ? {
84
+ startRowIndex: regionStart,
85
+ endRowIndex: MAX_ROW_INDEX,
86
+ startColumnIndex: 1,
87
+ endColumnIndex: MAX_COLUMN_INDEX,
88
+ }
89
+ : {
90
+ startRowIndex: 1,
91
+ endRowIndex: MAX_ROW_INDEX,
92
+ startColumnIndex: regionStart,
93
+ endColumnIndex: MAX_COLUMN_INDEX,
94
+ };
95
+ next =
96
+ formulaToRelativeReference(next, { rowIndex: regionStart, columnIndex: regionStart }, {
97
+ rowIndex: regionStart + (isRow ? delta : 0),
98
+ columnIndex: regionStart + (isRow ? 0 : delta),
99
+ }, editedSheetName, {
100
+ exclusionRange: region,
101
+ ignoreCircular: true,
102
+ ignoreReferenceError: true,
103
+ referenceSheetName: editedSheetName,
104
+ includeUnqualifiedReferences: sameSheet,
105
+ ...gridBounds,
106
+ }) ?? next;
107
+ return next;
108
+ };
109
+ const rewriteConditionFormulas = (condition, params) => {
110
+ if (!condition?.values)
111
+ return;
112
+ for (const value of condition.values) {
113
+ const text = value.userEnteredValue;
114
+ if (typeof text !== "string" || !text.startsWith("="))
115
+ continue;
116
+ const next = shiftRuleFormulaForStructuralChange(text, params);
117
+ if (next !== text)
118
+ value.userEnteredValue = next;
119
+ }
120
+ };
2
121
  /**
3
122
  * Apply an insert or delete range adjustment to a list of rules whose
4
123
  * `ranges: SheetRange[]` field references cells. Used for tables, conditional
5
124
  * formats, data validations, etc. Mutates the immer draft in place; rules
6
125
  * whose ranges all collapse to nothing are spliced out.
7
126
  *
127
+ * When `formulaScope` is given, each rule's condition formulas
128
+ * (`booleanRule.condition.values[].userEnteredValue` for CF,
129
+ * `condition.values[].userEnteredValue` for DV — those starting with `=`)
130
+ * are rewritten as if entered in the rule's applies-to top-left cell, see
131
+ * {@link shiftRuleFormulaForStructuralChange}.
132
+ *
8
133
  * Walks `draft` from the end so splice indices don't shift mid-iteration.
9
134
  */
10
- export const updateRangedRulesOnStructuralChange = (draft, op, axis, index, count, sheetId) => {
135
+ export const updateRangedRulesOnStructuralChange = (draft, op, axis, index, count, sheetId, formulaScope) => {
11
136
  const updater = op === "insert" ? updateSheetRangeOnInsert : updateSheetRangeOnDelete;
137
+ const isRow = axis === "row";
12
138
  for (let i = draft.length - 1; i >= 0; i--) {
13
139
  const rule = draft[i];
140
+ const anchorRange = rule.ranges?.[0];
14
141
  const ranges = rule.ranges
15
142
  ?.map((range) => updater(range, axis, index, count, sheetId))
16
143
  .filter((range) => !!range) ?? [];
@@ -18,6 +145,31 @@ export const updateRangedRulesOnStructuralChange = (draft, op, axis, index, coun
18
145
  // immer's typing for nested-mutation assignment is flaky here; cast
19
146
  // through `unknown` since the runtime shape matches the rule type.
20
147
  rule.ranges = ranges;
148
+ if (formulaScope && anchorRange) {
149
+ // Excel anchors a rule's formula at its applies-to top-left. When
150
+ // that cell is deleted, the first surviving cell (right after the
151
+ // deleted band) becomes the anchor and its instance formula the
152
+ // rule text.
153
+ const anchorPosition = isRow
154
+ ? anchorRange.startRowIndex
155
+ : anchorRange.startColumnIndex;
156
+ const anchorDeleted = op === "delete" &&
157
+ anchorRange.sheetId === sheetId &&
158
+ anchorPosition >= index &&
159
+ anchorPosition <= index + count - 1;
160
+ const params = {
161
+ op,
162
+ axis,
163
+ index,
164
+ count,
165
+ editedSheetName: formulaScope.getSheetName(sheetId),
166
+ ruleSheetName: formulaScope.getSheetName(anchorRange.sheetId),
167
+ anchorRebase: anchorDeleted ? index + count - anchorPosition : 0,
168
+ };
169
+ const carrier = rule;
170
+ rewriteConditionFormulas(carrier.booleanRule?.condition, params);
171
+ rewriteConditionFormulas(carrier.condition, params);
172
+ }
21
173
  }
22
174
  else {
23
175
  draft.splice(i, 1);
@@ -1 +1 @@
1
- {"version":3,"file":"structural-formula-update.d.ts","sourceRoot":"","sources":["../../../api/structural-formula-update.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAK1D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAEnC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAErE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAarD,KAAK,cAAc,GAAG,KAAK,GAAG,QAAQ,CAAC;AACvC,KAAK,YAAY,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAExC,MAAM,MAAM,6BAA6B,CAAC,CAAC,SAAS,QAAQ,IAAI;IAC9D,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3B,IAAI,EAAE,cAAc,CAAC;IACrB,EAAE,EAAE,YAAY,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,cAAc,EAAE,MAAM,CAAC;IACvB,wDAAwD;IACxD,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IAEpB,aAAa,EAAE,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC,eAAe,CAAC,CAAC;IAClE;;;;OAIG;IACH,aAAa,CAAC,EAAE,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC,eAAe,CAAC,CAAC;IACnE;;;;;OAKG;IACH,oBAAoB,CAAC,EAAE,UAAU,CAC/B,OAAO,cAAc,CACtB,CAAC,sBAAsB,CAAC,CAAC;IAC1B,YAAY,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC;IAC1C,kBAAkB,CAAC,EAAE,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC,oBAAoB,CAAC,CAAC;IAC7E,qBAAqB,CAAC,EAAE,UAAU,CAChC,OAAO,cAAc,CACtB,CAAC,uBAAuB,CAAC,CAAC;IAE3B,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;IAE/C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;CAC7C,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,iCAAiC,GAAI,CAAC,SAAS,QAAQ,EAClE,QAAQ,6BAA6B,CAAC,CAAC,CAAC,SAuVzC,CAAC"}
1
+ {"version":3,"file":"structural-formula-update.d.ts","sourceRoot":"","sources":["../../../api/structural-formula-update.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAK1D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAEnC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAErE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAarD,KAAK,cAAc,GAAG,KAAK,GAAG,QAAQ,CAAC;AACvC,KAAK,YAAY,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAExC,MAAM,MAAM,6BAA6B,CAAC,CAAC,SAAS,QAAQ,IAAI;IAC9D,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3B,IAAI,EAAE,cAAc,CAAC;IACrB,EAAE,EAAE,YAAY,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,cAAc,EAAE,MAAM,CAAC;IACvB,wDAAwD;IACxD,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IAEpB,aAAa,EAAE,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC,eAAe,CAAC,CAAC;IAClE;;;;OAIG;IACH,aAAa,CAAC,EAAE,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC,eAAe,CAAC,CAAC;IACnE;;;;;OAKG;IACH,oBAAoB,CAAC,EAAE,UAAU,CAC/B,OAAO,cAAc,CACtB,CAAC,sBAAsB,CAAC,CAAC;IAC1B,YAAY,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC;IAC1C,kBAAkB,CAAC,EAAE,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC,oBAAoB,CAAC,CAAC;IAC7E,qBAAqB,CAAC,EAAE,UAAU,CAChC,OAAO,cAAc,CACtB,CAAC,uBAAuB,CAAC,CAAC;IAE3B,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;IAE/C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;CAC7C,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,iCAAiC,GAAI,CAAC,SAAS,QAAQ,EAClE,QAAQ,6BAA6B,CAAC,CAAC,CAAC,SA2WzC,CAAC"}
@@ -86,6 +86,11 @@ export const updateFormulasForStructuralChange = (params) => {
86
86
  startColumnIndex: isInsert ? referenceIndex : referenceIndex + count,
87
87
  endColumnIndex: columnCount,
88
88
  };
89
+ // The cells a delete removes: any reference into them (that Pass 1 did not
90
+ // already contract) is broken to `#REF!` instead of sliding onto the cell
91
+ // that moves into its place.
92
+ const deletedRange = isInsert ? undefined : pass1Range;
93
+ const editedSheetName = getSheetName(sheetId);
89
94
  // ---- PASS 1 ----
90
95
  const pass1Formulas = collectUniqueDependentsForRange({
91
96
  draft,
@@ -104,10 +109,15 @@ export const updateFormulasForStructuralChange = (params) => {
104
109
  const formulaValue = sheetCell.formula;
105
110
  if (!formulaValue)
106
111
  continue;
107
- const activeSheetName = getSheetName(pos.sheetId);
112
+ // Scope to the EDITED sheet: a qualified `Sheet1!A1:A3` on another
113
+ // sheet expands like a local range, while that other sheet's own bare
114
+ // `A1:A3` (which resolves to ITS sheet) is left alone.
115
+ const rangeOptions = {
116
+ includeUnqualifiedReferences: pos.sheetId === sheetId,
117
+ };
108
118
  const updatedFormula = isInsert
109
- ? expandRangesInFormula(formulaValue, referenceIndex, count, axis, activeSheetName)
110
- : contractRangesInFormula(formulaValue, referenceIndex, count, axis, activeSheetName);
119
+ ? expandRangesInFormula(formulaValue, referenceIndex, count, axis, editedSheetName, rangeOptions)
120
+ : contractRangesInFormula(formulaValue, referenceIndex, count, axis, editedSheetName, rangeOptions);
111
121
  if (!updatedFormula || updatedFormula === formulaValue)
112
122
  continue;
113
123
  sheetCell.setFormulaValue(updatedFormula, false);
@@ -165,7 +175,7 @@ export const updateFormulasForStructuralChange = (params) => {
165
175
  shiftExternalDependentFormulaReferences({
166
176
  draft,
167
177
  position: pos,
168
- editedSheetName: getSheetName(sheetId),
178
+ editedSheetName,
169
179
  enqueueCalculation,
170
180
  enqueueGraphOperation,
171
181
  recalcCells,
@@ -173,6 +183,7 @@ export const updateFormulasForStructuralChange = (params) => {
173
183
  rowDelta,
174
184
  columnDelta,
175
185
  sourceRange: pass2SourceRange,
186
+ deletedRange,
176
187
  locale,
177
188
  rowCount,
178
189
  columnCount,
@@ -192,6 +203,7 @@ export const updateFormulasForStructuralChange = (params) => {
192
203
  rowDelta,
193
204
  columnDelta,
194
205
  sourceRange: pass2SourceRange,
206
+ deletedRange,
195
207
  locale,
196
208
  rowCount,
197
209
  columnCount,
@@ -206,7 +218,7 @@ export const updateFormulasForStructuralChange = (params) => {
206
218
  shiftExternalDependentFormulaReferences({
207
219
  draft,
208
220
  position,
209
- editedSheetName: getSheetName(sheetId),
221
+ editedSheetName,
210
222
  enqueueCalculation,
211
223
  enqueueGraphOperation,
212
224
  recalcCells,
@@ -214,6 +226,7 @@ export const updateFormulasForStructuralChange = (params) => {
214
226
  rowDelta,
215
227
  columnDelta,
216
228
  sourceRange: pass2SourceRange,
229
+ deletedRange,
217
230
  locale,
218
231
  rowCount,
219
232
  columnCount,
@@ -249,6 +262,7 @@ export const updateFormulasForStructuralChange = (params) => {
249
262
  rowIndex: pos.rowIndex,
250
263
  columnIndex: pos.columnIndex,
251
264
  },
265
+ activeSheetName: editedSheetName,
252
266
  enqueueCalculation,
253
267
  enqueueGraphOperation,
254
268
  recalcCells,
@@ -256,6 +270,7 @@ export const updateFormulasForStructuralChange = (params) => {
256
270
  rowDelta,
257
271
  columnDelta,
258
272
  sourceRange: pass2SourceRange,
273
+ deletedRange,
259
274
  locale,
260
275
  rowCount,
261
276
  columnCount,
@@ -285,6 +300,7 @@ export const updateFormulasForStructuralChange = (params) => {
285
300
  moveFormulaAtPosition({
286
301
  draft,
287
302
  position: { sheetId, rowIndex, columnIndex },
303
+ activeSheetName: editedSheetName,
288
304
  enqueueCalculation,
289
305
  enqueueGraphOperation,
290
306
  recalcCells,
@@ -292,6 +308,7 @@ export const updateFormulasForStructuralChange = (params) => {
292
308
  rowDelta,
293
309
  columnDelta,
294
310
  sourceRange: pass2SourceRange,
311
+ deletedRange,
295
312
  locale,
296
313
  rowCount,
297
314
  columnCount,
@@ -302,7 +319,7 @@ export const updateFormulasForStructuralChange = (params) => {
302
319
  }
303
320
  }
304
321
  };
305
- const shiftExternalDependentFormulaReferences = ({ draft, position, editedSheetName, enqueueCalculation, enqueueGraphOperation, recalcCells, movedKeys, rowDelta, columnDelta, sourceRange, locale, rowCount, columnCount, cellXfsRegistry, sharedStringRegistry, }) => {
322
+ const shiftExternalDependentFormulaReferences = ({ draft, position, editedSheetName, enqueueCalculation, enqueueGraphOperation, recalcCells, movedKeys, rowDelta, columnDelta, sourceRange, deletedRange, locale, rowCount, columnCount, cellXfsRegistry, sharedStringRegistry, }) => {
306
323
  const sheetCell = new SheetCell();
307
324
  const currentSheet = createSheetDraft(draft, position.sheetId, position.rowIndex);
308
325
  const cellData = currentSheet[position.rowIndex]?.values?.[position.columnIndex];
@@ -317,6 +334,7 @@ const shiftExternalDependentFormulaReferences = ({ draft, position, editedSheetN
317
334
  columnIndex: position.columnIndex + columnDelta,
318
335
  }, editedSheetName, {
319
336
  exclusionRange: sourceRange,
337
+ deletedRange,
320
338
  rowCount,
321
339
  columnCount,
322
340
  referenceSheetName: editedSheetName,