@svgrid/enterprise 3.0.1 → 3.0.2

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 (197) hide show
  1. package/dist/SvFormulaBar.svelte +606 -0
  2. package/dist/SvFormulaBar.svelte.d.ts +62 -0
  3. package/dist/SvPivotDesigner.svelte +65 -14
  4. package/dist/SvRibbonIcon.svelte +46 -0
  5. package/dist/SvRibbonIcon.svelte.d.ts +17 -0
  6. package/dist/SvSchemaChart.svelte +4 -2
  7. package/dist/SvSheet.svelte +4114 -0
  8. package/dist/SvSheet.svelte.d.ts +142 -0
  9. package/dist/SvSheetComment.svelte +98 -0
  10. package/dist/SvSheetComment.svelte.d.ts +22 -0
  11. package/dist/SvSheetConditionalFormat.svelte +162 -0
  12. package/dist/SvSheetConditionalFormat.svelte.d.ts +14 -0
  13. package/dist/SvSheetDataValidation.svelte +249 -0
  14. package/dist/SvSheetDataValidation.svelte.d.ts +14 -0
  15. package/dist/SvSheetFilterMenu.svelte +217 -0
  16. package/dist/SvSheetFilterMenu.svelte.d.ts +17 -0
  17. package/dist/SvSheetFindReplace.svelte +132 -0
  18. package/dist/SvSheetFindReplace.svelte.d.ts +10 -0
  19. package/dist/SvSheetFormatCells.svelte +421 -0
  20. package/dist/SvSheetFormatCells.svelte.d.ts +17 -0
  21. package/dist/SvSheetGoalSeek.svelte +144 -0
  22. package/dist/SvSheetGoalSeek.svelte.d.ts +12 -0
  23. package/dist/SvSheetInsertFunction.svelte +147 -0
  24. package/dist/SvSheetInsertFunction.svelte.d.ts +8 -0
  25. package/dist/SvSheetListPicker.svelte +89 -0
  26. package/dist/SvSheetListPicker.svelte.d.ts +16 -0
  27. package/dist/SvSheetManageRules.svelte +185 -0
  28. package/dist/SvSheetManageRules.svelte.d.ts +16 -0
  29. package/dist/SvSheetNameManager.svelte +225 -0
  30. package/dist/SvSheetNameManager.svelte.d.ts +11 -0
  31. package/dist/SvSheetPasteSpecial.svelte +105 -0
  32. package/dist/SvSheetPasteSpecial.svelte.d.ts +12 -0
  33. package/dist/SvSheetRemoveDuplicates.svelte +149 -0
  34. package/dist/SvSheetRemoveDuplicates.svelte.d.ts +12 -0
  35. package/dist/SvSheetRibbon.svelte +1201 -0
  36. package/dist/SvSheetRibbon.svelte.d.ts +34 -0
  37. package/dist/SvSheetSizeDialog.svelte +58 -0
  38. package/dist/SvSheetSizeDialog.svelte.d.ts +11 -0
  39. package/dist/SvSheetTabs.svelte +441 -0
  40. package/dist/SvSheetTabs.svelte.d.ts +36 -0
  41. package/dist/SvSheetTabs.test-harness.svelte.d.ts +17 -0
  42. package/dist/SvSheetTabs.test-harness.svelte.js +22 -0
  43. package/dist/SvSheetTextToColumns.svelte +172 -0
  44. package/dist/SvSheetTextToColumns.svelte.d.ts +13 -0
  45. package/dist/SvSheetValidationAlert.svelte +83 -0
  46. package/dist/SvSheetValidationAlert.svelte.d.ts +15 -0
  47. package/dist/cdn/svgrid-enterprise.svelte-external.js +18997 -5396
  48. package/dist/designer/assets/GridMenus-BlsvL_aU.js +8 -0
  49. package/dist/designer/assets/SvChartMenu-BYO9cYdy.css +1 -0
  50. package/dist/designer/assets/SvChartMenu-D9hEeHar.js +1 -0
  51. package/dist/designer/assets/SvDateRangeInput-BBRzrQeg.js +1 -0
  52. package/dist/designer/assets/SvDateTimePicker-DARvKUL2.js +1 -0
  53. package/dist/designer/assets/SvGridCellEditor-C7uQXYds.js +4 -0
  54. package/dist/designer/assets/SvGridChart-B8j1SSy3.js +3 -0
  55. package/dist/designer/assets/SvGridChart-BgLuPO7I.css +1 -0
  56. package/dist/designer/assets/SvGridChartBuilder-08YWWeqY.css +1 -0
  57. package/dist/designer/assets/SvGridChartBuilder-kvyIU_Rl.js +1 -0
  58. package/dist/designer/assets/SvGridChartPanel-4Pc8y5yO.css +1 -0
  59. package/dist/designer/assets/SvGridChartPanel-pT6ITc2P.js +4 -0
  60. package/dist/designer/assets/{SvGridChartView-DUc-1RUf.css → SvGridChartView-7msfnWZT.css} +1 -1
  61. package/dist/designer/assets/SvGridChartView-bg281UA1.js +1 -0
  62. package/dist/designer/assets/SvListBox-BDS66lmZ.js +110 -0
  63. package/dist/designer/assets/SvMenuList-DJ47ba1h.css +1 -0
  64. package/dist/designer/assets/SvMenuList-Dgq2D5VN.js +1 -0
  65. package/dist/designer/assets/SvTabs-DKmwb5p1.css +1 -0
  66. package/dist/designer/assets/SvTabs-UFCMTHXS.js +1 -0
  67. package/dist/designer/assets/chart-cIPUsbM5.js +1 -0
  68. package/dist/designer/assets/chart-export-B6bkQ3X8.js +11 -0
  69. package/dist/designer/assets/chart-export-pdf-BbA28-gt.js +11 -0
  70. package/dist/designer/assets/chart-panel-messages-DtTxpBUU.js +1 -0
  71. package/dist/designer/assets/chart-summary-Czu_5epb.js +1 -0
  72. package/dist/designer/assets/chart-trend-D5I5VEe8.js +1 -0
  73. package/dist/designer/assets/chart-validate-BMqM-qkF.js +1 -0
  74. package/dist/designer/assets/column-resize-BYDzR1Ve.js +1 -0
  75. package/dist/designer/assets/date-format-B8JbEtIG.js +1 -0
  76. package/dist/designer/assets/date-format-DKS-z0xS.css +1 -0
  77. package/dist/designer/assets/editor-contract-Bpoa7A5g.js +1 -0
  78. package/dist/designer/assets/focus-trap-CAreAhlU.js +1 -0
  79. package/dist/designer/assets/index-CMFgAoVV.css +1 -0
  80. package/dist/designer/assets/{index-C_a9Cj8Y.js → index-DwU7CAMm.js} +291 -290
  81. package/dist/designer/assets/list-option-BP_dWS66.js +1 -0
  82. package/dist/designer/assets/row-resize-DLktcqUK.js +1 -0
  83. package/dist/designer/assets/src-CITpcm6b.js +1 -0
  84. package/dist/designer/assets/src-EdI3Xqds.js +58 -0
  85. package/dist/designer/index.html +23 -14
  86. package/dist/export-pdf.d.ts +89 -0
  87. package/dist/export-pdf.js +130 -0
  88. package/dist/export.js +17 -10
  89. package/dist/index.d.ts +64 -1
  90. package/dist/index.js +68 -1
  91. package/dist/install.js +5 -0
  92. package/dist/node/studio.js +64 -2
  93. package/dist/pivot-chart.d.ts +25 -1
  94. package/dist/pivot-chart.js +25 -69
  95. package/dist/sheet/address.d.ts +43 -0
  96. package/dist/sheet/address.js +81 -0
  97. package/dist/sheet/ast.d.ts +94 -0
  98. package/dist/sheet/ast.js +56 -0
  99. package/dist/sheet/auto-filter.d.ts +66 -0
  100. package/dist/sheet/auto-filter.js +147 -0
  101. package/dist/sheet/autocomplete.d.ts +42 -0
  102. package/dist/sheet/autocomplete.js +162 -0
  103. package/dist/sheet/coerce.d.ts +31 -0
  104. package/dist/sheet/coerce.js +122 -0
  105. package/dist/sheet/commands.d.ts +89 -0
  106. package/dist/sheet/commands.js +230 -0
  107. package/dist/sheet/comments.d.ts +29 -0
  108. package/dist/sheet/comments.js +73 -0
  109. package/dist/sheet/conditional-formats.d.ts +144 -0
  110. package/dist/sheet/conditional-formats.js +316 -0
  111. package/dist/sheet/deps.d.ts +60 -0
  112. package/dist/sheet/deps.js +199 -0
  113. package/dist/sheet/document.d.ts +150 -0
  114. package/dist/sheet/document.js +264 -0
  115. package/dist/sheet/edit-keys.d.ts +14 -0
  116. package/dist/sheet/edit-keys.js +40 -0
  117. package/dist/sheet/entry.d.ts +31 -0
  118. package/dist/sheet/entry.js +76 -0
  119. package/dist/sheet/evaluate.d.ts +61 -0
  120. package/dist/sheet/evaluate.js +337 -0
  121. package/dist/sheet/find-replace.d.ts +62 -0
  122. package/dist/sheet/find-replace.js +152 -0
  123. package/dist/sheet/format-store.d.ts +99 -0
  124. package/dist/sheet/format-store.js +233 -0
  125. package/dist/sheet/freeze.d.ts +54 -0
  126. package/dist/sheet/freeze.js +58 -0
  127. package/dist/sheet/function-catalog.d.ts +10 -0
  128. package/dist/sheet/function-catalog.js +94 -0
  129. package/dist/sheet/functions.d.ts +28 -0
  130. package/dist/sheet/functions.js +362 -0
  131. package/dist/sheet/goal-seek.d.ts +73 -0
  132. package/dist/sheet/goal-seek.js +153 -0
  133. package/dist/sheet/index.d.ts +53 -0
  134. package/dist/sheet/index.js +53 -0
  135. package/dist/sheet/merges.d.ts +71 -0
  136. package/dist/sheet/merges.js +137 -0
  137. package/dist/sheet/names.d.ts +31 -0
  138. package/dist/sheet/names.js +87 -0
  139. package/dist/sheet/navigate.d.ts +52 -0
  140. package/dist/sheet/navigate.js +135 -0
  141. package/dist/sheet/number-format.d.ts +63 -0
  142. package/dist/sheet/number-format.js +508 -0
  143. package/dist/sheet/palette.d.ts +19 -0
  144. package/dist/sheet/palette.js +84 -0
  145. package/dist/sheet/parse.d.ts +13 -0
  146. package/dist/sheet/parse.js +108 -0
  147. package/dist/sheet/paste-special.d.ts +164 -0
  148. package/dist/sheet/paste-special.js +592 -0
  149. package/dist/sheet/protection.d.ts +21 -0
  150. package/dist/sheet/protection.js +48 -0
  151. package/dist/sheet/rects.d.ts +45 -0
  152. package/dist/sheet/rects.js +112 -0
  153. package/dist/sheet/refs.d.ts +82 -0
  154. package/dist/sheet/refs.js +266 -0
  155. package/dist/sheet/ribbon-icons.d.ts +31 -0
  156. package/dist/sheet/ribbon-icons.js +350 -0
  157. package/dist/sheet/ribbon.d.ts +173 -0
  158. package/dist/sheet/ribbon.js +753 -0
  159. package/dist/sheet/shortcuts.d.ts +164 -0
  160. package/dist/sheet/shortcuts.js +623 -0
  161. package/dist/sheet/structure.d.ts +87 -0
  162. package/dist/sheet/structure.js +166 -0
  163. package/dist/sheet/tables.d.ts +70 -0
  164. package/dist/sheet/tables.js +147 -0
  165. package/dist/sheet/tokenize.d.ts +54 -0
  166. package/dist/sheet/tokenize.js +304 -0
  167. package/dist/sheet/transforms.d.ts +76 -0
  168. package/dist/sheet/transforms.js +154 -0
  169. package/dist/sheet/validation.d.ts +92 -0
  170. package/dist/sheet/validation.js +241 -0
  171. package/dist/sheet/workbook.d.ts +72 -0
  172. package/dist/sheet/workbook.js +409 -0
  173. package/dist/sheet-enable.d.ts +6 -0
  174. package/dist/sheet-enable.js +46 -0
  175. package/dist/studio/ui-components.generated.js +63 -1
  176. package/dist/version.d.ts +1 -1
  177. package/dist/version.js +1 -1
  178. package/package.json +9 -4
  179. package/dist/designer/assets/GridMenus-B1JtIN21.js +0 -8
  180. package/dist/designer/assets/SvDateRangeInput-CjO7nn_x.js +0 -1
  181. package/dist/designer/assets/SvDateTimePicker-ByBD_ov6.js +0 -1
  182. package/dist/designer/assets/SvField-YDLipR6O.css +0 -1
  183. package/dist/designer/assets/SvField-cj1PFNgZ.js +0 -1
  184. package/dist/designer/assets/SvGridCellEditor-0W1L2hJ1.js +0 -2
  185. package/dist/designer/assets/SvGridChart-DBOR4xcz.js +0 -2
  186. package/dist/designer/assets/SvGridChart-fkMWeh1J.css +0 -1
  187. package/dist/designer/assets/SvGridChartPanel-symrhNnR.js +0 -11
  188. package/dist/designer/assets/SvGridChartView-BmRxq6mU.js +0 -1
  189. package/dist/designer/assets/SvListBox-1oUF6Iav.js +0 -110
  190. package/dist/designer/assets/chart-DXFganU8.js +0 -1
  191. package/dist/designer/assets/column-resize-C_inr5zT.js +0 -1
  192. package/dist/designer/assets/date-format-DGagAqRc.css +0 -1
  193. package/dist/designer/assets/date-format-onlYDsrY.js +0 -1
  194. package/dist/designer/assets/easing-zaypKrr0.js +0 -3
  195. package/dist/designer/assets/index-k2stW6L8.css +0 -1
  196. package/dist/designer/assets/row-resize-B0FWHcNr.js +0 -1
  197. package/dist/designer/assets/src-D9p27OGC.js +0 -58
@@ -0,0 +1,362 @@
1
+ /**
2
+ * The function table.
3
+ *
4
+ * Each entry receives its arguments already evaluated, in two shapes:
5
+ * - `flat` every argument flattened into one list, ranges expanded. What
6
+ * SUM and COUNT want.
7
+ * - `args` one list per argument, so a function can tell `SUM(A1:A3, 5)`
8
+ * from `SUM(A1:A3)` and `SUMIF` can line a range up against a
9
+ * parallel one.
10
+ * - `grids` the 2-D shape of any range argument, kept for VLOOKUP / INDEX /
11
+ * MATCH, which lose meaning once flattened.
12
+ *
13
+ * Functions that must NOT evaluate every argument (IF, IFERROR, AND, OR with
14
+ * short-circuit semantics) are handled in the evaluator instead, because by the
15
+ * time a table entry runs, evaluation has already happened.
16
+ */
17
+ import { FormulaError, isError, err } from './ast.js';
18
+ import { toNumber, toBool, toText, looseEquals, compare, numericOnly, isBlank, matchesCriterion, } from './coerce.js';
19
+ const first = (a) => a.flat[0] ?? '';
20
+ const nth = (a, i) => a.args[i]?.[0] ?? '';
21
+ function sum(values) {
22
+ return numericOnly(values).reduce((x, y) => x + y, 0);
23
+ }
24
+ function average(values) {
25
+ const ns = numericOnly(values);
26
+ if (ns.length === 0)
27
+ return err('#DIV/0!');
28
+ return ns.reduce((x, y) => x + y, 0) / ns.length;
29
+ }
30
+ function roundTo(value, digits) {
31
+ const f = Math.pow(10, digits);
32
+ // Scale, round, unscale. The epsilon nudge keeps 1.005 -> 1.01 rather than
33
+ // 1.00, which is the binary-float surprise users report as a bug.
34
+ return Math.round((value * f) * (1 + Number.EPSILON)) / f;
35
+ }
36
+ function toDate(v) {
37
+ if (typeof v === 'number') {
38
+ // Excel serial: day 1 is 1900-01-01, with the famous phantom leap day.
39
+ return new Date(Date.UTC(1899, 11, 30) + v * 86400000);
40
+ }
41
+ const d = new Date(toText(v));
42
+ if (Number.isNaN(d.getTime()))
43
+ throw new FormulaError('#VALUE!');
44
+ return d;
45
+ }
46
+ const iso = (d) => d.toISOString().slice(0, 10);
47
+ /** Sum / count / average over a criterion range, optionally summing a parallel
48
+ * range. The three IF functions differ only in what they do with the hits. */
49
+ function criteriaHits(range, criterion) {
50
+ const out = [];
51
+ for (let i = 0; i < range.length; i += 1) {
52
+ if (matchesCriterion(range[i], criterion))
53
+ out.push(i);
54
+ }
55
+ return out;
56
+ }
57
+ /** SUMIFS / COUNTIFS: every (range, criterion) pair must match at an index. */
58
+ function multiCriteriaHits(pairs) {
59
+ const firstPair = pairs[0];
60
+ if (!firstPair)
61
+ return [];
62
+ const out = [];
63
+ for (let i = 0; i < firstPair[0].length; i += 1) {
64
+ if (pairs.every(([range, crit]) => matchesCriterion(range[i] ?? '', crit)))
65
+ out.push(i);
66
+ }
67
+ return out;
68
+ }
69
+ export const FUNCTIONS = {
70
+ // ---- Math and aggregation -------------------------------------------
71
+ SUM: (a) => sum(a.flat),
72
+ AVERAGE: (a) => average(a.flat),
73
+ AVG: (a) => average(a.flat),
74
+ MIN: (a) => { const n = numericOnly(a.flat); return n.length ? Math.min(...n) : 0; },
75
+ MAX: (a) => { const n = numericOnly(a.flat); return n.length ? Math.max(...n) : 0; },
76
+ COUNT: (a) => a.flat.filter((v) => typeof v === 'number').length,
77
+ COUNTA: (a) => a.flat.filter((v) => !isBlank(v)).length,
78
+ COUNTBLANK: (a) => a.flat.filter((v) => isBlank(v)).length,
79
+ ABS: (a) => Math.abs(toNumber(first(a))),
80
+ INT: (a) => Math.floor(toNumber(first(a))),
81
+ MOD: (a) => {
82
+ const d = toNumber(nth(a, 1));
83
+ if (d === 0)
84
+ return err('#DIV/0!');
85
+ // Excel's MOD follows the sign of the divisor, unlike JavaScript's %.
86
+ const n = toNumber(nth(a, 0));
87
+ return n - d * Math.floor(n / d);
88
+ },
89
+ POWER: (a) => Math.pow(toNumber(nth(a, 0)), toNumber(nth(a, 1))),
90
+ SQRT: (a) => {
91
+ const n = toNumber(first(a));
92
+ return n < 0 ? err('#NUM!') : Math.sqrt(n);
93
+ },
94
+ ROUND: (a) => roundTo(toNumber(nth(a, 0)), Math.round(toNumber(nth(a, 1) || 0))),
95
+ ROUNDUP: (a) => {
96
+ const d = Math.round(toNumber(nth(a, 1) || 0));
97
+ const f = Math.pow(10, d);
98
+ const v = toNumber(nth(a, 0));
99
+ return (v < 0 ? -Math.ceil(-v * f) : Math.ceil(v * f)) / f;
100
+ },
101
+ ROUNDDOWN: (a) => {
102
+ const d = Math.round(toNumber(nth(a, 1) || 0));
103
+ const f = Math.pow(10, d);
104
+ const v = toNumber(nth(a, 0));
105
+ return (v < 0 ? -Math.floor(-v * f) : Math.floor(v * f)) / f;
106
+ },
107
+ MEDIAN: (a) => {
108
+ const n = numericOnly(a.flat).sort((x, y) => x - y);
109
+ if (!n.length)
110
+ return err('#NUM!');
111
+ const mid = Math.floor(n.length / 2);
112
+ return n.length % 2 ? n[mid] : (n[mid - 1] + n[mid]) / 2;
113
+ },
114
+ STDEV: (a) => {
115
+ const n = numericOnly(a.flat);
116
+ if (n.length < 2)
117
+ return err('#DIV/0!');
118
+ const mean = n.reduce((x, y) => x + y, 0) / n.length;
119
+ const variance = n.reduce((acc, v) => acc + (v - mean) ** 2, 0) / (n.length - 1);
120
+ return Math.sqrt(variance);
121
+ },
122
+ RANK: (a) => {
123
+ const value = toNumber(nth(a, 0));
124
+ const pool = numericOnly(a.args[1] ?? []);
125
+ const ascending = a.args[2] !== undefined && toBool(nth(a, 2));
126
+ const sorted = pool.slice().sort((x, y) => (ascending ? x - y : y - x));
127
+ const at = sorted.indexOf(value);
128
+ return at < 0 ? err('#N/A') : at + 1;
129
+ },
130
+ // ---- Conditional aggregation ----------------------------------------
131
+ SUMIF: (a) => {
132
+ const range = a.args[0] ?? [];
133
+ const hits = criteriaHits(range, nth(a, 1));
134
+ // The optional third argument is the range actually summed.
135
+ const target = a.args[2] ?? range;
136
+ return sum(hits.map((i) => target[i] ?? ''));
137
+ },
138
+ COUNTIF: (a) => criteriaHits(a.args[0] ?? [], nth(a, 1)).length,
139
+ AVERAGEIF: (a) => {
140
+ const range = a.args[0] ?? [];
141
+ const hits = criteriaHits(range, nth(a, 1));
142
+ const target = a.args[2] ?? range;
143
+ return average(hits.map((i) => target[i] ?? ''));
144
+ },
145
+ SUMIFS: (a) => {
146
+ const target = a.args[0] ?? [];
147
+ const pairs = [];
148
+ for (let i = 1; i + 1 < a.args.length + 1; i += 2) {
149
+ const range = a.args[i];
150
+ if (!range)
151
+ break;
152
+ pairs.push([range, a.args[i + 1]?.[0] ?? '']);
153
+ }
154
+ return sum(multiCriteriaHits(pairs).map((i) => target[i] ?? ''));
155
+ },
156
+ COUNTIFS: (a) => {
157
+ const pairs = [];
158
+ for (let i = 0; i < a.args.length; i += 2) {
159
+ const range = a.args[i];
160
+ if (!range)
161
+ break;
162
+ pairs.push([range, a.args[i + 1]?.[0] ?? '']);
163
+ }
164
+ return multiCriteriaHits(pairs).length;
165
+ },
166
+ // ---- Logical ---------------------------------------------------------
167
+ NOT: (a) => !toBool(first(a)),
168
+ AND: (a) => a.flat.every((v) => toBool(v)),
169
+ OR: (a) => a.flat.some((v) => toBool(v)),
170
+ XOR: (a) => a.flat.filter((v) => toBool(v)).length % 2 === 1,
171
+ // ---- Information -----------------------------------------------------
172
+ // What a value IS, not what it can be coerced to: "12" typed as text is
173
+ // text here, the way Excel answers, and a blank is neither.
174
+ ISNUMBER: (a) => typeof first(a) === 'number',
175
+ ISTEXT: (a) => typeof first(a) === 'string' && first(a) !== '',
176
+ ISLOGICAL: (a) => typeof first(a) === 'boolean',
177
+ ISBLANK: (a) => first(a) === '',
178
+ // ---- Text ------------------------------------------------------------
179
+ LEN: (a) => toText(first(a)).length,
180
+ LEFT: (a) => toText(nth(a, 0)).slice(0, Math.max(0, Math.round(toNumber(a.args[1] ? nth(a, 1) : 1)))),
181
+ RIGHT: (a) => {
182
+ const s = toText(nth(a, 0));
183
+ const n = Math.max(0, Math.round(toNumber(a.args[1] ? nth(a, 1) : 1)));
184
+ return n >= s.length ? s : s.slice(s.length - n);
185
+ },
186
+ MID: (a) => {
187
+ const s = toText(nth(a, 0));
188
+ const start = Math.round(toNumber(nth(a, 1)));
189
+ if (start < 1)
190
+ return err('#VALUE!');
191
+ return s.slice(start - 1, start - 1 + Math.max(0, Math.round(toNumber(nth(a, 2)))));
192
+ },
193
+ UPPER: (a) => toText(first(a)).toUpperCase(),
194
+ LOWER: (a) => toText(first(a)).toLowerCase(),
195
+ TRIM: (a) => toText(first(a)).trim().replace(/\s+/g, ' '),
196
+ CONCAT: (a) => a.flat.map((v) => toText(v)).join(''),
197
+ CONCATENATE: (a) => a.flat.map((v) => toText(v)).join(''),
198
+ TEXTJOIN: (a) => {
199
+ const sep = toText(nth(a, 0));
200
+ const skipEmpty = toBool(nth(a, 1));
201
+ const rest = a.args.slice(2).flat();
202
+ return rest.filter((v) => !skipEmpty || !isBlank(v)).map((v) => toText(v)).join(sep);
203
+ },
204
+ SUBSTITUTE: (a) => {
205
+ const s = toText(nth(a, 0));
206
+ const find = toText(nth(a, 1));
207
+ const replace = toText(nth(a, 2));
208
+ if (find === '')
209
+ return s;
210
+ return s.split(find).join(replace);
211
+ },
212
+ FIND: (a) => {
213
+ // Case sensitive, 1-based, #VALUE! when absent. SEARCH is its
214
+ // case-insensitive twin.
215
+ const at = toText(nth(a, 1)).indexOf(toText(nth(a, 0)));
216
+ return at < 0 ? err('#VALUE!') : at + 1;
217
+ },
218
+ SEARCH: (a) => {
219
+ const at = toText(nth(a, 1)).toLowerCase().indexOf(toText(nth(a, 0)).toLowerCase());
220
+ return at < 0 ? err('#VALUE!') : at + 1;
221
+ },
222
+ TEXT: (a) => {
223
+ // Minimal: the full Excel format grammar arrives with per-cell number
224
+ // formats. Until then this covers the common fixed-decimal case.
225
+ const v = toNumber(nth(a, 0));
226
+ const pattern = toText(nth(a, 1));
227
+ const decimals = /\.(0+)/.exec(pattern)?.[1]?.length ?? 0;
228
+ const body = v.toFixed(decimals);
229
+ if (pattern.includes(',')) {
230
+ const [int = '', frac] = body.split('.');
231
+ const grouped = int.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
232
+ return frac ? `${grouped}.${frac}` : grouped;
233
+ }
234
+ return body;
235
+ },
236
+ // ---- Date ------------------------------------------------------------
237
+ TODAY: () => iso(new Date()),
238
+ NOW: () => new Date().toISOString().slice(0, 19).replace('T', ' '),
239
+ YEAR: (a) => toDate(first(a)).getUTCFullYear(),
240
+ MONTH: (a) => toDate(first(a)).getUTCMonth() + 1,
241
+ DAY: (a) => toDate(first(a)).getUTCDate(),
242
+ DATE: (a) => iso(new Date(Date.UTC(Math.round(toNumber(nth(a, 0))), Math.round(toNumber(nth(a, 1))) - 1, Math.round(toNumber(nth(a, 2)))))),
243
+ EOMONTH: (a) => {
244
+ const d = toDate(nth(a, 0));
245
+ const months = Math.round(toNumber(nth(a, 1)));
246
+ // Day 0 of the following month is the last day of the target month.
247
+ return iso(new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth() + months + 1, 0)));
248
+ },
249
+ // DAYS(end, start): whole days, negative when the end comes first.
250
+ DAYS: (a) => Math.round((toDate(nth(a, 0)).getTime() - toDate(nth(a, 1)).getTime()) / 86400000),
251
+ // DATEDIF(start, end, unit): Excel's "d", "m" and "y", completed units
252
+ // only, and #NUM! when the start comes after the end, as Excel gives.
253
+ DATEDIF: (a) => {
254
+ const start = toDate(nth(a, 0));
255
+ const end = toDate(nth(a, 1));
256
+ if (end.getTime() < start.getTime())
257
+ return err('#NUM!');
258
+ const unit = toText(nth(a, 2)).toUpperCase();
259
+ if (unit === 'D')
260
+ return Math.floor((end.getTime() - start.getTime()) / 86400000);
261
+ let months = (end.getUTCFullYear() - start.getUTCFullYear()) * 12 + (end.getUTCMonth() - start.getUTCMonth());
262
+ if (end.getUTCDate() < start.getUTCDate())
263
+ months -= 1;
264
+ if (unit === 'M')
265
+ return months;
266
+ if (unit === 'Y')
267
+ return Math.floor(months / 12);
268
+ return err('#NUM!');
269
+ },
270
+ // ---- Lookup ----------------------------------------------------------
271
+ VLOOKUP: (a) => {
272
+ const needle = nth(a, 0);
273
+ const grid = a.grids[1];
274
+ if (!grid)
275
+ return err('#REF!');
276
+ const col = Math.round(toNumber(nth(a, 2)));
277
+ if (col < 1)
278
+ return err('#VALUE!');
279
+ for (const row of grid) {
280
+ if (row[0] !== undefined && looseEquals(row[0], needle)) {
281
+ const cell = row[col - 1];
282
+ return cell === undefined ? err('#REF!') : cell;
283
+ }
284
+ }
285
+ return err('#N/A');
286
+ },
287
+ HLOOKUP: (a) => {
288
+ const needle = nth(a, 0);
289
+ const grid = a.grids[1];
290
+ if (!grid)
291
+ return err('#REF!');
292
+ const rowIndex = Math.round(toNumber(nth(a, 2)));
293
+ if (rowIndex < 1)
294
+ return err('#VALUE!');
295
+ const header = grid[0] ?? [];
296
+ for (let c = 0; c < header.length; c += 1) {
297
+ if (looseEquals(header[c], needle)) {
298
+ const cell = grid[rowIndex - 1]?.[c];
299
+ return cell === undefined ? err('#REF!') : cell;
300
+ }
301
+ }
302
+ return err('#N/A');
303
+ },
304
+ MATCH: (a) => {
305
+ const needle = nth(a, 0);
306
+ const pool = a.args[1] ?? [];
307
+ const mode = a.args[2] ? Math.round(toNumber(nth(a, 2))) : 1;
308
+ if (mode === 0) {
309
+ const at = pool.findIndex((v) => looseEquals(v, needle));
310
+ return at < 0 ? err('#N/A') : at + 1;
311
+ }
312
+ // Ordered search: the last value not past the needle.
313
+ let best = -1;
314
+ for (let i = 0; i < pool.length; i += 1) {
315
+ const cmp = compare(pool[i], needle);
316
+ if (mode === 1 ? cmp <= 0 : cmp >= 0)
317
+ best = i;
318
+ }
319
+ return best < 0 ? err('#N/A') : best + 1;
320
+ },
321
+ INDEX: (a) => {
322
+ const grid = a.grids[0];
323
+ if (!grid) {
324
+ const at = Math.round(toNumber(nth(a, 1)));
325
+ const v = (a.args[0] ?? [])[at - 1];
326
+ return v === undefined ? err('#REF!') : v;
327
+ }
328
+ const given = Math.round(toNumber(nth(a, 1)));
329
+ // With one number, a one-column range indexes by row and a one-row range
330
+ // by column, as Excel does: =INDEX(B4:D4, 2) is the second scenario
331
+ // heading, not #REF!.
332
+ const oneRow = grid.length === 1 && !a.args[2];
333
+ const rowIndex = oneRow ? 1 : given;
334
+ const colIndex = oneRow ? given : a.args[2] ? Math.round(toNumber(nth(a, 2))) : 1;
335
+ const row = grid[rowIndex - 1];
336
+ if (!row)
337
+ return err('#REF!');
338
+ const cell = row[colIndex - 1];
339
+ return cell === undefined ? err('#REF!') : cell;
340
+ },
341
+ XLOOKUP: (a) => {
342
+ const needle = nth(a, 0);
343
+ const haystack = a.args[1] ?? [];
344
+ const results = a.args[2] ?? [];
345
+ const at = haystack.findIndex((v) => looseEquals(v, needle));
346
+ if (at < 0)
347
+ return a.args[3] ? nth(a, 3) : err('#N/A');
348
+ const cell = results[at];
349
+ return cell === undefined ? err('#REF!') : cell;
350
+ },
351
+ };
352
+ /** Merge caller-supplied functions over the built-ins. Keys are uppercased so
353
+ * a consumer can register `myFn` and write `=MYFN()`. */
354
+ export function withCustomFunctions(custom) {
355
+ if (!custom)
356
+ return FUNCTIONS;
357
+ const out = { ...FUNCTIONS };
358
+ for (const [name, fn] of Object.entries(custom))
359
+ out[name.toUpperCase()] = fn;
360
+ return out;
361
+ }
362
+ export { isError };
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Goal Seek: find the input value that makes a formula cell hit a target.
3
+ *
4
+ * "What interest rate makes the monthly payment 1500?" You know the answer
5
+ * you want and one cell you are willing to change; the solver finds it.
6
+ *
7
+ * The method is secant with a bisection fallback, not Newton. Newton needs a
8
+ * derivative, and the function here is "recalculate a spreadsheet", which has
9
+ * no analytic one. Secant approximates the slope from two evaluations, which
10
+ * is the same information a numerical derivative would cost anyway.
11
+ *
12
+ * Bisection is the fallback because secant is fast but not safe: it can step
13
+ * to infinity on a flat stretch or oscillate on a kink. When a bracket is
14
+ * known - two inputs whose results straddle the target - bisection cannot
15
+ * fail, only be slow. Trying secant first and falling back keeps the common
16
+ * case quick and the awkward case terminating.
17
+ */
18
+ export type GoalSeekOptions = {
19
+ /** Stop once the result is this close to the target. */
20
+ tolerance?: number;
21
+ /** Give up after this many recalculations. */
22
+ maxIterations?: number;
23
+ /** Where to start looking. Defaults to the input cell's current value. */
24
+ initialGuess?: number;
25
+ /** Keep the answer inside these bounds. A rate solver wants [0, 1]. */
26
+ min?: number;
27
+ max?: number;
28
+ };
29
+ export type GoalSeekResult = {
30
+ /** Whether the target was reached within tolerance. */
31
+ converged: boolean;
32
+ /** The input value found. Present even when it did not converge, so a
33
+ * caller can show the closest attempt rather than nothing. */
34
+ value: number;
35
+ /** What the formula produced at that input. */
36
+ result: number;
37
+ iterations: number;
38
+ /** Why it stopped, when it did not converge. */
39
+ reason?: 'maxIterations' | 'notNumeric' | 'flat' | 'outOfBounds';
40
+ };
41
+ /**
42
+ * Solve `evaluate(input) = target` for `input`.
43
+ *
44
+ * `evaluate` sets the input cell, recalculates, and returns the formula
45
+ * cell's value. It is called many times, so it should be the workbook's own
46
+ * recalculation rather than anything that touches the DOM.
47
+ *
48
+ * The caller owns the input cell: this never writes. It reports the value it
49
+ * found and lets the caller decide whether to keep it, which is what makes
50
+ * Excel's "Goal Seek found a solution / OK or Cancel" dialog possible.
51
+ */
52
+ export declare function goalSeek(evaluate: (input: number) => unknown, target: number, start: number, options?: GoalSeekOptions): GoalSeekResult;
53
+ /** What `goalSeekCell` needs of a workbook. */
54
+ export type GoalSeekSheet = {
55
+ getRaw(sheet: string, row: number, col: number): string;
56
+ setRaw(sheet: string, row: number, col: number, text: string): void;
57
+ getValue(sheet: string, row: number, col: number): unknown;
58
+ };
59
+ export type CellAddress = {
60
+ sheet: string;
61
+ row: number;
62
+ col: number;
63
+ };
64
+ /**
65
+ * Goal Seek over a workbook: change `input` until `formula` reads `target`.
66
+ *
67
+ * The input cell is RESTORED before returning, whatever the outcome. The
68
+ * solver writes to it dozens of times while searching, and leaving the last
69
+ * probe behind would be worse than not running: Excel shows you the answer
70
+ * and asks before keeping it, which it cannot do if the sheet has already
71
+ * moved. Apply `result.value` yourself once the user says yes.
72
+ */
73
+ export declare function goalSeekCell(book: GoalSeekSheet, formula: CellAddress, input: CellAddress, target: number, options?: GoalSeekOptions): GoalSeekResult;
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Goal Seek: find the input value that makes a formula cell hit a target.
3
+ *
4
+ * "What interest rate makes the monthly payment 1500?" You know the answer
5
+ * you want and one cell you are willing to change; the solver finds it.
6
+ *
7
+ * The method is secant with a bisection fallback, not Newton. Newton needs a
8
+ * derivative, and the function here is "recalculate a spreadsheet", which has
9
+ * no analytic one. Secant approximates the slope from two evaluations, which
10
+ * is the same information a numerical derivative would cost anyway.
11
+ *
12
+ * Bisection is the fallback because secant is fast but not safe: it can step
13
+ * to infinity on a flat stretch or oscillate on a kink. When a bracket is
14
+ * known - two inputs whose results straddle the target - bisection cannot
15
+ * fail, only be slow. Trying secant first and falling back keeps the common
16
+ * case quick and the awkward case terminating.
17
+ */
18
+ const DEFAULTS = {
19
+ tolerance: 1e-7,
20
+ maxIterations: 100,
21
+ };
22
+ /**
23
+ * Solve `evaluate(input) = target` for `input`.
24
+ *
25
+ * `evaluate` sets the input cell, recalculates, and returns the formula
26
+ * cell's value. It is called many times, so it should be the workbook's own
27
+ * recalculation rather than anything that touches the DOM.
28
+ *
29
+ * The caller owns the input cell: this never writes. It reports the value it
30
+ * found and lets the caller decide whether to keep it, which is what makes
31
+ * Excel's "Goal Seek found a solution / OK or Cancel" dialog possible.
32
+ */
33
+ export function goalSeek(evaluate, target, start, options = {}) {
34
+ const tolerance = options.tolerance ?? DEFAULTS.tolerance;
35
+ const maxIterations = options.maxIterations ?? DEFAULTS.maxIterations;
36
+ const min = options.min ?? Number.NEGATIVE_INFINITY;
37
+ const max = options.max ?? Number.POSITIVE_INFINITY;
38
+ let iterations = 0;
39
+ const clamp = (x) => Math.min(Math.max(x, min), max);
40
+ /** The signed distance from the target. Zero is the answer. */
41
+ const f = (x) => {
42
+ iterations += 1;
43
+ const raw = evaluate(x);
44
+ const n = typeof raw === 'number' ? raw : Number(raw);
45
+ return Number.isFinite(n) ? n - target : null;
46
+ };
47
+ let x0 = clamp(options.initialGuess ?? start);
48
+ let f0 = f(x0);
49
+ if (f0 === null) {
50
+ return { converged: false, value: x0, result: NaN, iterations, reason: 'notNumeric' };
51
+ }
52
+ if (Math.abs(f0) <= tolerance) {
53
+ return { converged: true, value: x0, result: f0 + target, iterations };
54
+ }
55
+ // A second point, offset enough to see a slope. Scaling with the guess
56
+ // matters: a fixed step of 1 is enormous next to an interest rate of 0.05
57
+ // and invisible next to a loan of 300000.
58
+ let x1 = clamp(x0 !== 0 ? x0 * 1.1 : 1);
59
+ if (x1 === x0)
60
+ x1 = clamp(x0 + 1);
61
+ let f1 = f(x1);
62
+ if (f1 === null) {
63
+ return { converged: false, value: x0, result: f0 + target, iterations, reason: 'notNumeric' };
64
+ }
65
+ /** Best seen so far, so a failure still reports the closest attempt. */
66
+ let best = Math.abs(f0) <= Math.abs(f1) ? { x: x0, fx: f0 } : { x: x1, fx: f1 };
67
+ const bracket = { lo: null, hi: null };
68
+ const noteBracket = (a, b) => {
69
+ if (a.fx === 0 || b.fx === 0)
70
+ return;
71
+ if ((a.fx < 0) !== (b.fx < 0)) {
72
+ bracket.lo = a.fx < 0 ? a : b;
73
+ bracket.hi = a.fx < 0 ? b : a;
74
+ }
75
+ };
76
+ noteBracket({ x: x0, fx: f0 }, { x: x1, fx: f1 });
77
+ while (iterations < maxIterations) {
78
+ if (Math.abs(f1) <= tolerance) {
79
+ return { converged: true, value: x1, result: f1 + target, iterations };
80
+ }
81
+ let next;
82
+ const slope = f1 - f0;
83
+ if (slope === 0) {
84
+ // Flat between the two points. Secant divides by this, so bisect if a
85
+ // bracket exists and give up if not - a genuinely flat function has no
86
+ // solution to find.
87
+ const { lo, hi } = bracket;
88
+ if (!lo || !hi) {
89
+ return { converged: false, value: best.x, result: best.fx + target, iterations, reason: 'flat' };
90
+ }
91
+ next = (lo.x + hi.x) / 2;
92
+ }
93
+ else {
94
+ next = x1 - f1 * ((x1 - x0) / slope);
95
+ // Secant can step anywhere, including outside a bracket we already
96
+ // trust. Bisect instead when it does.
97
+ const { lo, hi } = bracket;
98
+ const outside = !Number.isFinite(next) ||
99
+ (lo !== null && hi !== null && (next < Math.min(lo.x, hi.x) || next > Math.max(lo.x, hi.x)));
100
+ if (outside)
101
+ next = lo && hi ? (lo.x + hi.x) / 2 : clamp(next);
102
+ }
103
+ next = clamp(next);
104
+ if (next === x1) {
105
+ // Clamped against a bound and cannot move.
106
+ return {
107
+ converged: false, value: best.x, result: best.fx + target, iterations,
108
+ reason: Number.isFinite(min) || Number.isFinite(max) ? 'outOfBounds' : 'flat',
109
+ };
110
+ }
111
+ const fNext = f(next);
112
+ if (fNext === null) {
113
+ return { converged: false, value: best.x, result: best.fx + target, iterations, reason: 'notNumeric' };
114
+ }
115
+ if (Math.abs(fNext) < Math.abs(best.fx))
116
+ best = { x: next, fx: fNext };
117
+ noteBracket({ x: x1, fx: f1 }, { x: next, fx: fNext });
118
+ x0 = x1;
119
+ f0 = f1;
120
+ x1 = next;
121
+ f1 = fNext;
122
+ }
123
+ if (Math.abs(f1) <= tolerance) {
124
+ return { converged: true, value: x1, result: f1 + target, iterations };
125
+ }
126
+ return {
127
+ converged: false, value: best.x, result: best.fx + target,
128
+ iterations, reason: 'maxIterations',
129
+ };
130
+ }
131
+ /**
132
+ * Goal Seek over a workbook: change `input` until `formula` reads `target`.
133
+ *
134
+ * The input cell is RESTORED before returning, whatever the outcome. The
135
+ * solver writes to it dozens of times while searching, and leaving the last
136
+ * probe behind would be worse than not running: Excel shows you the answer
137
+ * and asks before keeping it, which it cannot do if the sheet has already
138
+ * moved. Apply `result.value` yourself once the user says yes.
139
+ */
140
+ export function goalSeekCell(book, formula, input, target, options = {}) {
141
+ const original = book.getRaw(input.sheet, input.row, input.col);
142
+ const startText = original.trim();
143
+ const start = Number(startText);
144
+ try {
145
+ return goalSeek((x) => {
146
+ book.setRaw(input.sheet, input.row, input.col, String(x));
147
+ return book.getValue(formula.sheet, formula.row, formula.col);
148
+ }, target, Number.isFinite(start) ? start : 0, options);
149
+ }
150
+ finally {
151
+ book.setRaw(input.sheet, input.row, input.col, original);
152
+ }
153
+ }
@@ -0,0 +1,53 @@
1
+ /**
2
+ * `@svgrid/enterprise/sheet` - the Excel keyboard layer on its own subpath.
3
+ *
4
+ * Importing the package barrel pulls every module it reaches into the chunk
5
+ * (the package sets no `sideEffects` flag), which for an app that only wants
6
+ * the shortcuts would mean shipping export, pivot, the scheduler and the board
7
+ * as well. This subpath is the shortcuts and nothing else. It matters more once
8
+ * the formula engine lands beside them in phase 2.
9
+ */
10
+ export { enableSheet } from '../sheet-enable.js';
11
+ export { createTableRegistry, isValidTableName, resolveTableRange, columnIndexOf, rowCountOf, type TableRegion, type TableRegistry, type TableRange, type TableSpecifier, } from './tables.js';
12
+ export { goalSeek, goalSeekCell, type GoalSeekOptions, type GoalSeekResult, type GoalSeekSheet, type CellAddress as GoalSeekCellAddress, } from './goal-seek.js';
13
+ export { default as SvSheetTabs } from '../SvSheetTabs.svelte';
14
+ export { createWorkbook, isValidSheetName, type Workbook, type SheetData, type WorkbookOptions, } from './workbook.js';
15
+ export { setWorkbook, getWorkbook } from './shortcuts.js';
16
+ export { createSheetDocument, type SheetDocument, type SheetDocumentInit, type SheetState, type SheetStateEntry, type PerSheetState, type SheetChangeReason, } from './document.js';
17
+ export { shiftRect, shiftRects, subtractRect, rectContains, rectsIntersect, remapNotes, lineShift, type NotesMap } from './rects.js';
18
+ export { isLocked, rectsHaveLocked, rectsMixLocked, PROTECTED_MESSAGE } from './protection.js';
19
+ export { commentAt, withComment, listComments, nextComment } from './comments.js';
20
+ export { ruleAt, rulesIn, checkEntry, listChoices, shiftValidation, removeValidation, describeRule, dateValue, validationId, DEFAULT_ALERT_MESSAGE, OPERATOR_LABELS, type ValidationRule, type ValidationAllow, type ValidationOperator, type ValidationContext, type ValidationVerdict, type ValidationSpec, } from './validation.js';
21
+ export { ruleStats, evaluateCf, shiftCf, removeCf, cfIn, describeCf, scaleColor, iconIndex, hasStyle, cfId, CF_PRESET_STYLES, COLOR_SCALES, DATA_BAR_COLOR, type CfRule, type CfRuleBody, type CfStyledRule, type CfBody, type CfPreset, type CfStyle, type CfStats, type CfResult, type CfContext, type CfOperator, type CfTextMatch, type CfIconSet, type CfScaleColors, type CfKind, } from './conditional-formats.js';
22
+ export { mergePlan, unmergePlan, mergeDropsValues, mergesIn, mergeAt as sheetMergeAt, isCoveredCell, selectionMerged, toGridMerges, sortBlockedByMerges, reorderMerges, normalRect, type MergeKind, type MergePlan, } from './merges.js';
23
+ export { distinctValues, hiddenRowsFor, passesFilter, isFiltering, withColumnFilter, valuesFilter, shiftAutoFilter, describeFilter, type AutoFilterState, type ColumnFilter, type FilterCondition, type FilterValue, } from './auto-filter.js';
24
+ export { splitText, textToColumns, guessDelimiter, findDuplicates, removeDuplicates, type SplitOptions, type DuplicateOptions, type DuplicateReport, } from './transforms.js';
25
+ export { insertRows, deleteRows, insertColumns, deleteColumns, axisForSelection, setStructureTarget, getStructureTarget, rewriteFormulas, type StructureTarget, } from './structure.js';
26
+ export { findAll, findNext, replaceOne, replaceAll, replaceInText, cellMatches, setFindTarget, getFindTarget, type FindOptions, type FindHit, type FindTarget, } from './find-replace.js';
27
+ export { splitFrozenRows, frozenColumnIds, applyFreeze, freezeAtActiveCell, freezeTopRow, freezeFirstColumn, unfreeze, type FreezeState, type FreezeSplit, } from './freeze.js';
28
+ export { buildClipboardPayload, parseClipboard, parseClipboardText, parseClipboardHtml, readClipboardOrigin, anchorForeignFormulas, resolvePasteCell, planPaste, msoNumberFormat, numFmtFromMso, isR1C1, r1c1ToA1, type PasteSpecialOptions, type PasteWhat, type PasteOperation, type ClipboardCell, type ClipboardGrid, type PasteResolution, } from './paste-special.js';
29
+ export { setFindReplaceHandler, setPasteSpecialHandler } from './shortcuts.js';
30
+ export { default as SvFormulaBar } from '../SvFormulaBar.svelte';
31
+ export { default as SvSheet } from '../SvSheet.svelte';
32
+ export { default as SvSheetRibbon } from '../SvSheetRibbon.svelte';
33
+ export { RIBBON_TABS, ribbonItems, withDecimals, applyBorders, type RibbonTab, type RibbonGroup, type RibbonItem, type RibbonOption, type RibbonItemKind, type RibbonActionId, type BorderPreset, } from './ribbon.js';
34
+ export { RIBBON_ICONS, RIBBON_ICON_NAMES, type RibbonIconName, type IconPath } from './ribbon-icons.js';
35
+ export { THEME_COLOURS, STANDARD_COLOURS, ALL_COLOURS, tint, type PaletteColour } from './palette.js';
36
+ export { default as SvRibbonIcon } from '../SvRibbonIcon.svelte';
37
+ export { move, selectRegion, selectLine, applyFormat, toggleFormat, preset, autoSum, structural, switchSheet, gridOf, } from './shortcuts.js';
38
+ export { compileNumberFormat, formatWithPattern, FORMAT_PRESETS, type CompiledFormat, type FormatPresetName, } from './number-format.js';
39
+ export { createFormatStore, entryToStyle, type SheetFormatStore, type CellFormatEntry, type CellAddressLookup, } from './format-store.js';
40
+ export { createNames, isValidName, type SheetNames, type DefinedName, } from './names.js';
41
+ export { suggestFunctions, applySuggestion, signatureAt, partialAt, SIGNATURES, type FunctionSuggestion, } from './autocomplete.js';
42
+ export { setFormatTarget, getFormatTarget, setFormatDialogHandler, type SheetFormatTarget, } from './shortcuts.js';
43
+ export { parseFormula, parse, } from './parse.js';
44
+ export { tokenize, type Token } from './tokenize.js';
45
+ export { evaluate, formatValue, type EvalContext } from './evaluate.js';
46
+ export { FUNCTIONS, withCustomFunctions, type SheetFunction, type FnArgs, } from './functions.js';
47
+ export { translateFormula, fixupReferences, renameSheetReferences, formatFormula, referenceSpans, REFERENCE_COLOURS, type StructuralEdit, type EditScope, type ReferenceSpan, } from './refs.js';
48
+ export { createDependencyGraph, precedentsOf, cellKey, parseCellKey, type DependencyGraph, type CellKey, } from './deps.js';
49
+ export { parseA1, formatA1, colToLetters, lettersToCol, type CellRef, } from './address.js';
50
+ export { isError, type CellValue, type SheetError, type Node as FormulaNode, } from './ast.js';
51
+ export { SHEET_BINDINGS, handleSheetKey, type SheetBinding, type SheetCommand, } from './shortcuts.js';
52
+ export { edgeOfRegion, currentRegion, isWholeSheet, wholeSheet, isBlankValue, type Direction, type Grid, type Cell, type Rect, } from './navigate.js';
53
+ export { fillDown, fillRight, fillSelection, stampDate, stampNow, copyFromAbove, copyValueFromAbove, guessSumRange, looksNumeric, numericAt, targetRect, setFillTranslator, setSheetValueProbe, getSheetValueProbe, type FillTranslator, type SheetValueProbe, } from './commands.js';