@rowsncolumns/spreadsheet 10.2.74 → 10.2.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 (280) hide show
  1. package/dist/cjs/api/excel-validation-kinds.d.ts +71 -0
  2. package/dist/cjs/api/excel-validation-kinds.d.ts.map +1 -0
  3. package/dist/cjs/api/excel-validation-kinds.js +304 -0
  4. package/dist/cjs/api/fill-series.d.ts +38 -0
  5. package/dist/cjs/api/fill-series.d.ts.map +1 -0
  6. package/dist/cjs/api/fill-series.js +89 -0
  7. package/dist/cjs/api/go-to-special.d.ts +32 -0
  8. package/dist/cjs/api/go-to-special.d.ts.map +1 -0
  9. package/dist/cjs/api/go-to-special.js +111 -0
  10. package/dist/cjs/api/spreadsheet-api.d.ts +6 -2
  11. package/dist/cjs/api/spreadsheet-api.d.ts.map +1 -1
  12. package/dist/cjs/api/spreadsheet-api.js +9 -3
  13. package/dist/cjs/api/validation-tooltip.d.ts +17 -0
  14. package/dist/cjs/api/validation-tooltip.d.ts.map +1 -0
  15. package/dist/cjs/api/validation-tooltip.js +42 -0
  16. package/dist/cjs/atoms/advanced-filter-dialog.atom.d.ts +28 -0
  17. package/dist/cjs/atoms/advanced-filter-dialog.atom.d.ts.map +1 -0
  18. package/dist/cjs/atoms/advanced-filter-dialog.atom.js +32 -0
  19. package/dist/cjs/atoms/fill-options.atom.d.ts +36 -0
  20. package/dist/cjs/atoms/fill-options.atom.d.ts.map +1 -0
  21. package/dist/cjs/atoms/fill-options.atom.js +11 -0
  22. package/dist/cjs/atoms/fill-series-dialog.atom.d.ts +26 -0
  23. package/dist/cjs/atoms/fill-series-dialog.atom.d.ts.map +1 -0
  24. package/dist/cjs/atoms/fill-series-dialog.atom.js +14 -0
  25. package/dist/cjs/atoms/go-to-dialog.atom.d.ts +11 -1
  26. package/dist/cjs/atoms/go-to-dialog.atom.d.ts.map +1 -1
  27. package/dist/cjs/atoms/goal-seek-dialog.atom.d.ts +29 -0
  28. package/dist/cjs/atoms/goal-seek-dialog.atom.d.ts.map +1 -0
  29. package/dist/cjs/atoms/goal-seek-dialog.atom.js +30 -0
  30. package/dist/cjs/atoms/index.d.ts +3 -0
  31. package/dist/cjs/atoms/index.d.ts.map +1 -1
  32. package/dist/cjs/atoms/index.js +3 -0
  33. package/dist/cjs/atoms/subtotal-dialog.atom.d.ts +39 -0
  34. package/dist/cjs/atoms/subtotal-dialog.atom.d.ts.map +1 -0
  35. package/dist/cjs/atoms/subtotal-dialog.atom.js +30 -0
  36. package/dist/cjs/atoms/text-to-columns-dialog.atom.d.ts +34 -0
  37. package/dist/cjs/atoms/text-to-columns-dialog.atom.d.ts.map +1 -0
  38. package/dist/cjs/atoms/text-to-columns-dialog.atom.js +36 -0
  39. package/dist/cjs/atoms/watch-window.atom.d.ts +37 -0
  40. package/dist/cjs/atoms/watch-window.atom.d.ts.map +1 -0
  41. package/dist/cjs/atoms/watch-window.atom.js +61 -0
  42. package/dist/cjs/components/advanced-filter-dialog/index.d.ts +28 -0
  43. package/dist/cjs/components/advanced-filter-dialog/index.d.ts.map +1 -0
  44. package/dist/cjs/components/advanced-filter-dialog/index.js +134 -0
  45. package/dist/cjs/components/calculation-options-dialog/index.d.ts +33 -0
  46. package/dist/cjs/components/calculation-options-dialog/index.d.ts.map +1 -0
  47. package/dist/cjs/components/calculation-options-dialog/index.js +69 -0
  48. package/dist/cjs/components/canvas-grid/index.d.ts.map +1 -1
  49. package/dist/cjs/components/canvas-grid/index.js +328 -71
  50. package/dist/cjs/components/canvas-grid/typings.d.ts +31 -5
  51. package/dist/cjs/components/canvas-grid/typings.d.ts.map +1 -1
  52. package/dist/cjs/components/cell/alignment.d.ts +30 -0
  53. package/dist/cjs/components/cell/alignment.d.ts.map +1 -1
  54. package/dist/cjs/components/cell/alignment.js +56 -1
  55. package/dist/cjs/components/cell/index.d.ts.map +1 -1
  56. package/dist/cjs/components/cell/index.js +15 -7
  57. package/dist/cjs/components/cell-diff/index.d.ts +3 -2
  58. package/dist/cjs/components/cell-diff/index.d.ts.map +1 -1
  59. package/dist/cjs/components/cell-editor/helpers.d.ts +9 -0
  60. package/dist/cjs/components/cell-editor/helpers.d.ts.map +1 -1
  61. package/dist/cjs/components/cell-editor/helpers.js +8 -1
  62. package/dist/cjs/components/cell-editor/helpers.spec.js +14 -0
  63. package/dist/cjs/components/cell-editor/index.d.ts.map +1 -1
  64. package/dist/cjs/components/cell-editor/index.js +7 -3
  65. package/dist/cjs/components/context-menu/index.d.ts +6 -1
  66. package/dist/cjs/components/context-menu/index.d.ts.map +1 -1
  67. package/dist/cjs/components/context-menu/index.js +146 -3
  68. package/dist/cjs/components/embeds/embed-component.d.ts.map +1 -1
  69. package/dist/cjs/components/embeds/embed-component.js +16 -1
  70. package/dist/cjs/components/fill-series-dialog/index.d.ts +29 -0
  71. package/dist/cjs/components/fill-series-dialog/index.d.ts.map +1 -0
  72. package/dist/cjs/components/fill-series-dialog/index.js +156 -0
  73. package/dist/cjs/components/go-to-dialog/index.d.ts +11 -1
  74. package/dist/cjs/components/go-to-dialog/index.d.ts.map +1 -1
  75. package/dist/cjs/components/go-to-dialog/index.js +67 -24
  76. package/dist/cjs/components/goal-seek-dialog/index.d.ts +32 -0
  77. package/dist/cjs/components/goal-seek-dialog/index.d.ts.map +1 -0
  78. package/dist/cjs/components/goal-seek-dialog/index.js +149 -0
  79. package/dist/cjs/components/selection/fill-options-menu.d.ts +32 -0
  80. package/dist/cjs/components/selection/fill-options-menu.d.ts.map +1 -0
  81. package/dist/cjs/components/selection/fill-options-menu.js +65 -0
  82. package/dist/cjs/components/selection/index.d.ts +1 -1
  83. package/dist/cjs/components/selection/index.d.ts.map +1 -1
  84. package/dist/cjs/components/selection/index.js +4 -2
  85. package/dist/cjs/components/selection/types.d.ts +11 -1
  86. package/dist/cjs/components/selection/types.d.ts.map +1 -1
  87. package/dist/cjs/components/subtotal-dialog/index.d.ts +30 -0
  88. package/dist/cjs/components/subtotal-dialog/index.d.ts.map +1 -0
  89. package/dist/cjs/components/subtotal-dialog/index.js +126 -0
  90. package/dist/cjs/components/text-to-columns-dialog/index.d.ts +37 -0
  91. package/dist/cjs/components/text-to-columns-dialog/index.d.ts.map +1 -0
  92. package/dist/cjs/components/text-to-columns-dialog/index.js +166 -0
  93. package/dist/cjs/components/toolbar/background-color-selector.d.ts +13 -1
  94. package/dist/cjs/components/toolbar/background-color-selector.d.ts.map +1 -1
  95. package/dist/cjs/components/toolbar/background-color-selector.js +57 -11
  96. package/dist/cjs/components/toolbar/cell-style-selector.d.ts +15 -2
  97. package/dist/cjs/components/toolbar/cell-style-selector.d.ts.map +1 -1
  98. package/dist/cjs/components/toolbar/cell-style-selector.js +56 -3
  99. package/dist/cjs/components/toolbar/fill-selectors.d.ts +49 -0
  100. package/dist/cjs/components/toolbar/fill-selectors.d.ts.map +1 -0
  101. package/dist/cjs/components/toolbar/fill-selectors.js +196 -0
  102. package/dist/cjs/components/toolbar/index.d.ts +1 -0
  103. package/dist/cjs/components/toolbar/index.d.ts.map +1 -1
  104. package/dist/cjs/components/toolbar/index.js +1 -0
  105. package/dist/cjs/components/toolbar/text-format-selector.d.ts +9 -0
  106. package/dist/cjs/components/toolbar/text-format-selector.d.ts.map +1 -1
  107. package/dist/cjs/components/toolbar/text-format-selector.js +15 -3
  108. package/dist/cjs/components/toolbar/text-horizontal-align-selector.d.ts +8 -0
  109. package/dist/cjs/components/toolbar/text-horizontal-align-selector.d.ts.map +1 -1
  110. package/dist/cjs/components/toolbar/text-horizontal-align-selector.js +23 -4
  111. package/dist/cjs/components/watch-window/index.d.ts +25 -0
  112. package/dist/cjs/components/watch-window/index.d.ts.map +1 -0
  113. package/dist/cjs/components/watch-window/index.js +63 -0
  114. package/dist/cjs/hooks/use-cell-renderer.d.ts.map +1 -1
  115. package/dist/cjs/hooks/use-cell-renderer.js +17 -6
  116. package/dist/cjs/hooks/use-editable.d.ts +11 -2
  117. package/dist/cjs/hooks/use-editable.d.ts.map +1 -1
  118. package/dist/cjs/hooks/use-editable.js +8 -0
  119. package/dist/cjs/hooks/use-editor-submit.d.ts +32 -3
  120. package/dist/cjs/hooks/use-editor-submit.d.ts.map +1 -1
  121. package/dist/cjs/hooks/use-editor-submit.js +111 -2
  122. package/dist/cjs/hooks/use-get-tooltip.d.ts.map +1 -1
  123. package/dist/cjs/hooks/use-get-tooltip.js +7 -2
  124. package/dist/cjs/hooks/use-keyboard-handler.d.ts.map +1 -1
  125. package/dist/cjs/hooks/use-keyboard-handler.js +27 -14
  126. package/dist/cjs/hooks/use-selection-renderer.d.ts +13 -2
  127. package/dist/cjs/hooks/use-selection-renderer.d.ts.map +1 -1
  128. package/dist/cjs/hooks/use-selection-renderer.js +21 -4
  129. package/dist/cjs/hooks/use-selection.d.ts +54 -4
  130. package/dist/cjs/hooks/use-selection.d.ts.map +1 -1
  131. package/dist/cjs/hooks/use-selection.js +232 -37
  132. package/dist/cjs/index.d.ts +12 -0
  133. package/dist/cjs/index.d.ts.map +1 -1
  134. package/dist/cjs/index.js +11 -0
  135. package/dist/cjs/release-date.js +1 -1
  136. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  137. package/dist/cjs/types.d.ts +156 -5
  138. package/dist/cjs/types.d.ts.map +1 -1
  139. package/dist/cjs/types.js +19 -1
  140. package/dist/esm/api/excel-validation-kinds.d.ts +71 -0
  141. package/dist/esm/api/excel-validation-kinds.d.ts.map +1 -0
  142. package/dist/esm/api/excel-validation-kinds.js +287 -0
  143. package/dist/esm/api/fill-series.d.ts +38 -0
  144. package/dist/esm/api/fill-series.d.ts.map +1 -0
  145. package/dist/esm/api/fill-series.js +78 -0
  146. package/dist/esm/api/go-to-special.d.ts +32 -0
  147. package/dist/esm/api/go-to-special.d.ts.map +1 -0
  148. package/dist/esm/api/go-to-special.js +96 -0
  149. package/dist/esm/api/spreadsheet-api.d.ts +6 -2
  150. package/dist/esm/api/spreadsheet-api.d.ts.map +1 -1
  151. package/dist/esm/api/spreadsheet-api.js +8 -3
  152. package/dist/esm/api/validation-tooltip.d.ts +17 -0
  153. package/dist/esm/api/validation-tooltip.d.ts.map +1 -0
  154. package/dist/esm/api/validation-tooltip.js +34 -0
  155. package/dist/esm/atoms/advanced-filter-dialog.atom.d.ts +28 -0
  156. package/dist/esm/atoms/advanced-filter-dialog.atom.d.ts.map +1 -0
  157. package/dist/esm/atoms/advanced-filter-dialog.atom.js +21 -0
  158. package/dist/esm/atoms/fill-options.atom.d.ts +36 -0
  159. package/dist/esm/atoms/fill-options.atom.d.ts.map +1 -0
  160. package/dist/esm/atoms/fill-options.atom.js +5 -0
  161. package/dist/esm/atoms/fill-series-dialog.atom.d.ts +26 -0
  162. package/dist/esm/atoms/fill-series-dialog.atom.d.ts.map +1 -0
  163. package/dist/esm/atoms/fill-series-dialog.atom.js +9 -0
  164. package/dist/esm/atoms/go-to-dialog.atom.d.ts +11 -1
  165. package/dist/esm/atoms/go-to-dialog.atom.d.ts.map +1 -1
  166. package/dist/esm/atoms/goal-seek-dialog.atom.d.ts +29 -0
  167. package/dist/esm/atoms/goal-seek-dialog.atom.d.ts.map +1 -0
  168. package/dist/esm/atoms/goal-seek-dialog.atom.js +21 -0
  169. package/dist/esm/atoms/index.d.ts +3 -0
  170. package/dist/esm/atoms/index.d.ts.map +1 -1
  171. package/dist/esm/atoms/index.js +3 -0
  172. package/dist/esm/atoms/subtotal-dialog.atom.d.ts +39 -0
  173. package/dist/esm/atoms/subtotal-dialog.atom.d.ts.map +1 -0
  174. package/dist/esm/atoms/subtotal-dialog.atom.js +21 -0
  175. package/dist/esm/atoms/text-to-columns-dialog.atom.d.ts +34 -0
  176. package/dist/esm/atoms/text-to-columns-dialog.atom.d.ts.map +1 -0
  177. package/dist/esm/atoms/text-to-columns-dialog.atom.js +25 -0
  178. package/dist/esm/atoms/watch-window.atom.d.ts +37 -0
  179. package/dist/esm/atoms/watch-window.atom.d.ts.map +1 -0
  180. package/dist/esm/atoms/watch-window.atom.js +37 -0
  181. package/dist/esm/components/advanced-filter-dialog/index.d.ts +28 -0
  182. package/dist/esm/components/advanced-filter-dialog/index.d.ts.map +1 -0
  183. package/dist/esm/components/advanced-filter-dialog/index.js +125 -0
  184. package/dist/esm/components/calculation-options-dialog/index.d.ts +33 -0
  185. package/dist/esm/components/calculation-options-dialog/index.d.ts.map +1 -0
  186. package/dist/esm/components/calculation-options-dialog/index.js +61 -0
  187. package/dist/esm/components/canvas-grid/index.d.ts.map +1 -1
  188. package/dist/esm/components/canvas-grid/index.js +266 -26
  189. package/dist/esm/components/canvas-grid/typings.d.ts +31 -5
  190. package/dist/esm/components/canvas-grid/typings.d.ts.map +1 -1
  191. package/dist/esm/components/cell/alignment.d.ts +30 -0
  192. package/dist/esm/components/cell/alignment.d.ts.map +1 -1
  193. package/dist/esm/components/cell/alignment.js +51 -0
  194. package/dist/esm/components/cell/index.d.ts.map +1 -1
  195. package/dist/esm/components/cell/index.js +16 -8
  196. package/dist/esm/components/cell-diff/index.d.ts +3 -2
  197. package/dist/esm/components/cell-diff/index.d.ts.map +1 -1
  198. package/dist/esm/components/cell-editor/helpers.d.ts +9 -0
  199. package/dist/esm/components/cell-editor/helpers.d.ts.map +1 -1
  200. package/dist/esm/components/cell-editor/helpers.js +6 -0
  201. package/dist/esm/components/cell-editor/helpers.spec.js +15 -1
  202. package/dist/esm/components/cell-editor/index.d.ts.map +1 -1
  203. package/dist/esm/components/cell-editor/index.js +8 -4
  204. package/dist/esm/components/context-menu/index.d.ts +6 -1
  205. package/dist/esm/components/context-menu/index.d.ts.map +1 -1
  206. package/dist/esm/components/context-menu/index.js +139 -4
  207. package/dist/esm/components/embeds/embed-component.d.ts.map +1 -1
  208. package/dist/esm/components/embeds/embed-component.js +17 -1
  209. package/dist/esm/components/fill-series-dialog/index.d.ts +29 -0
  210. package/dist/esm/components/fill-series-dialog/index.d.ts.map +1 -0
  211. package/dist/esm/components/fill-series-dialog/index.js +151 -0
  212. package/dist/esm/components/go-to-dialog/index.d.ts +11 -1
  213. package/dist/esm/components/go-to-dialog/index.d.ts.map +1 -1
  214. package/dist/esm/components/go-to-dialog/index.js +63 -23
  215. package/dist/esm/components/goal-seek-dialog/index.d.ts +32 -0
  216. package/dist/esm/components/goal-seek-dialog/index.d.ts.map +1 -0
  217. package/dist/esm/components/goal-seek-dialog/index.js +125 -0
  218. package/dist/esm/components/selection/fill-options-menu.d.ts +32 -0
  219. package/dist/esm/components/selection/fill-options-menu.d.ts.map +1 -0
  220. package/dist/esm/components/selection/fill-options-menu.js +63 -0
  221. package/dist/esm/components/selection/index.d.ts +1 -1
  222. package/dist/esm/components/selection/index.d.ts.map +1 -1
  223. package/dist/esm/components/selection/index.js +4 -2
  224. package/dist/esm/components/selection/types.d.ts +11 -1
  225. package/dist/esm/components/selection/types.d.ts.map +1 -1
  226. package/dist/esm/components/subtotal-dialog/index.d.ts +30 -0
  227. package/dist/esm/components/subtotal-dialog/index.d.ts.map +1 -0
  228. package/dist/esm/components/subtotal-dialog/index.js +115 -0
  229. package/dist/esm/components/text-to-columns-dialog/index.d.ts +37 -0
  230. package/dist/esm/components/text-to-columns-dialog/index.d.ts.map +1 -0
  231. package/dist/esm/components/text-to-columns-dialog/index.js +147 -0
  232. package/dist/esm/components/toolbar/background-color-selector.d.ts +13 -1
  233. package/dist/esm/components/toolbar/background-color-selector.d.ts.map +1 -1
  234. package/dist/esm/components/toolbar/background-color-selector.js +61 -11
  235. package/dist/esm/components/toolbar/cell-style-selector.d.ts +15 -2
  236. package/dist/esm/components/toolbar/cell-style-selector.d.ts.map +1 -1
  237. package/dist/esm/components/toolbar/cell-style-selector.js +46 -2
  238. package/dist/esm/components/toolbar/fill-selectors.d.ts +49 -0
  239. package/dist/esm/components/toolbar/fill-selectors.d.ts.map +1 -0
  240. package/dist/esm/components/toolbar/fill-selectors.js +162 -0
  241. package/dist/esm/components/toolbar/index.d.ts +1 -0
  242. package/dist/esm/components/toolbar/index.d.ts.map +1 -1
  243. package/dist/esm/components/toolbar/index.js +1 -0
  244. package/dist/esm/components/toolbar/text-format-selector.d.ts +9 -0
  245. package/dist/esm/components/toolbar/text-format-selector.d.ts.map +1 -1
  246. package/dist/esm/components/toolbar/text-format-selector.js +14 -2
  247. package/dist/esm/components/toolbar/text-horizontal-align-selector.d.ts +8 -0
  248. package/dist/esm/components/toolbar/text-horizontal-align-selector.d.ts.map +1 -1
  249. package/dist/esm/components/toolbar/text-horizontal-align-selector.js +21 -5
  250. package/dist/esm/components/watch-window/index.d.ts +25 -0
  251. package/dist/esm/components/watch-window/index.d.ts.map +1 -0
  252. package/dist/esm/components/watch-window/index.js +54 -0
  253. package/dist/esm/hooks/use-cell-renderer.d.ts.map +1 -1
  254. package/dist/esm/hooks/use-cell-renderer.js +17 -6
  255. package/dist/esm/hooks/use-editable.d.ts +11 -2
  256. package/dist/esm/hooks/use-editable.d.ts.map +1 -1
  257. package/dist/esm/hooks/use-editable.js +8 -0
  258. package/dist/esm/hooks/use-editor-submit.d.ts +32 -3
  259. package/dist/esm/hooks/use-editor-submit.d.ts.map +1 -1
  260. package/dist/esm/hooks/use-editor-submit.js +82 -3
  261. package/dist/esm/hooks/use-get-tooltip.d.ts.map +1 -1
  262. package/dist/esm/hooks/use-get-tooltip.js +7 -2
  263. package/dist/esm/hooks/use-keyboard-handler.d.ts.map +1 -1
  264. package/dist/esm/hooks/use-keyboard-handler.js +27 -14
  265. package/dist/esm/hooks/use-selection-renderer.d.ts +13 -2
  266. package/dist/esm/hooks/use-selection-renderer.d.ts.map +1 -1
  267. package/dist/esm/hooks/use-selection-renderer.js +22 -5
  268. package/dist/esm/hooks/use-selection.d.ts +54 -4
  269. package/dist/esm/hooks/use-selection.d.ts.map +1 -1
  270. package/dist/esm/hooks/use-selection.js +220 -36
  271. package/dist/esm/index.d.ts +12 -0
  272. package/dist/esm/index.d.ts.map +1 -1
  273. package/dist/esm/index.js +11 -0
  274. package/dist/esm/release-date.js +1 -1
  275. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  276. package/dist/esm/types.d.ts +156 -5
  277. package/dist/esm/types.d.ts.map +1 -1
  278. package/dist/esm/types.js +18 -0
  279. package/dist/spreadsheet.min.css +1 -1
  280. package/package.json +7 -7
@@ -1,15 +1,19 @@
1
1
  import { Direction, isCellWithinBounds, selectionFromActiveCell, } from "@rowsncolumns/grid";
2
2
  import { ArrowLeftIcon, ArrowRightIcon, CheckIcon, ChevronRightIcon, ClipboardIcon, CodeIcon, CopyIcon, Cross1Icon, DotsVerticalIcon, EyeNoneIcon, EyeOpenIcon, FunnelIcon, MdBrush, MdOutlineFactCheck, PaintBrush, PlusIcon, ReaderIcon, RemoveDuplicatesIcon, ScissorsIcon, SizeIcon, SortDownIcon, SortUpIcon, SpaceBetweenHorizontallyIcon, TableIcon, TrashIcon, ViewGridIcon, WandIcon, } from "@rowsncolumns/icons";
3
3
  import { DropdownLeftSlot, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuItem, DropdownMenuItemIndicator, DropdownMenuPortal, DropdownMenuSeparator, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownRightSlot, } from "@rowsncolumns/ui";
4
- import { number2Alpha } from "@rowsncolumns/utils";
4
+ import { addressToCell, cellToAddress, number2Alpha } from "@rowsncolumns/utils";
5
5
  import React, { useCallback, useMemo, useRef } from "react";
6
6
  import { getProtectedRange, isProtectedRange } from "../../api/validation";
7
7
  import { useGetContentfulRangeAroundCell } from "../../atoms";
8
+ import { useIsAdvancedFilterDialogMounted, useOpenAdvancedFilterDialog, } from "../../atoms/advanced-filter-dialog.atom";
9
+ import { useIsGoalSeekDialogMounted, useOpenGoalSeekDialog, } from "../../atoms/goal-seek-dialog.atom";
8
10
  import { useIsRemoveDuplicatesDialogMounted, useOpenRemoveDuplicatesDialog, } from "../../atoms/remove-duplicates-dialog.atom";
11
+ import { useIsSubtotalDialogMounted, useOpenSubtotalDialog, } from "../../atoms/subtotal-dialog.atom";
12
+ import { useIsTextToColumnsDialogMounted, useOpenTextToColumnsDialog, } from "../../atoms/text-to-columns-dialog.atom";
9
13
  import { BLANK_LABEL } from "../../config";
10
14
  import { createArrayRange, generateMultiDimTitle } from "../../helpers";
11
15
  import { getTotalRowFunctionFormula, getTotalRowFunctionFromFormula, TOTAL_ROW_FUNCTIONS, } from "./total-row-functions";
12
- export const ContextMenu = ({ isRowHeader, isColumnHeader, activeCell, selections, basicFilter, isTableHeader, onClearContents, onHideColumn, onHideRow, onGroupRows, onUngroupRows, onGroupColumns, onUngroupColumns, onDeleteRow, onDeleteColumn, onInsertColumn, onInsertRow, onInsertCellsShiftDown, onInsertCellsShiftRight, onDeleteCellsShiftLeft, onDeleteCellsShiftUp, onFreezeRow, onFreezeColumn, onCopy, onCut, onPaste, onRequestPasteSpecial, onRequestEvaluateFormula, isActiveCellFormula, onInsertNote, onProtectRange, onUnProtectRange, onSortRange, onSortColumn, onRequestDefineNamedRange, onRequestResize, onRequestEditTable, onRequestEditPivotTable, onRequestDeletePivotTable, onPivotDrillDown, onRequestFormatCells, onRequestConditionalFormat, onRequestDataValidation, onRemoveTable, onClearFormatting, onCreateTable, onCreateBasicFilter, onFilterTable, onSortTable, getFormattedValuesFromRange, focusSheet, isSheetFocused, getFormattedValue, onInsertTableColumn, onDeleteTableColumn, onInsertTableRow, onDeleteTableRow, onSplitTextToColumns, onRemoveDuplicates, onChange, getCellData, isHiddenColumn, isHiddenRow, onShowColumn, onShowRow, tables, pivotTables, protectedRanges, sheetId, frozenRows, frozenColumns, selectedRowHeadersIds, selectedColumnHeadersIds, readonly = false, onAddQuickEdit, enableMagicFill, }) => {
16
+ export const ContextMenu = ({ isRowHeader, isColumnHeader, activeCell, selections, basicFilter, isTableHeader, onClearContents, onHideColumn, onHideRow, onGroupRows, onUngroupRows, onGroupColumns, onUngroupColumns, onDeleteRow, onDeleteColumn, onInsertColumn, onInsertRow, onInsertCellsShiftDown, onInsertCellsShiftRight, onDeleteCellsShiftLeft, onDeleteCellsShiftUp, onFreezeRow, onFreezeColumn, onCopy, onCut, onPaste, onRequestPasteSpecial, onRequestEvaluateFormula, onRequestAddWatch, isActiveCellFormula, onInsertNote, onProtectRange, onUnProtectRange, onSortRange, onSortColumn, onRequestDefineNamedRange, onRequestResize, onRequestEditTable, onRequestEditPivotTable, onRequestDeletePivotTable, onPivotDrillDown, onRequestFormatCells, onRequestConditionalFormat, onRequestDataValidation, onRemoveTable, onClearFormatting, onCreateTable, onCreateBasicFilter, onFilterTable, onSortTable, getFormattedValuesFromRange, focusSheet, isSheetFocused, getFormattedValue, onInsertTableColumn, onDeleteTableColumn, onInsertTableRow, onDeleteTableRow, onSplitTextToColumns, onRemoveDuplicates, onGoalSeek, onSubtotal, onAdvancedFilter, onChange, getCellData, isHiddenColumn, isHiddenRow, onShowColumn, onShowRow, tables, pivotTables, protectedRanges, sheetId, frozenRows, frozenColumns, selectedRowHeadersIds, selectedColumnHeadersIds, readonly = false, onAddQuickEdit, enableMagicFill, }) => {
13
17
  const isHeader = isColumnHeader || isRowHeader;
14
18
  const shouldFocusSheetRef = useRef(true);
15
19
  const multiColumnTitle = generateMultiDimTitle(selectedColumnHeadersIds, "y");
@@ -39,6 +43,114 @@ export const ContextMenu = ({ isRowHeader, isColumnHeader, activeCell, selection
39
43
  const lastSelectedRowIndex = selectedRowHeadersIds.reduce((m, v) => (v > m ? v : m), -Infinity);
40
44
  // Get contentful range
41
45
  const getContentfulRangeAroundCell = useGetContentfulRangeAroundCell();
46
+ // The data block the data tools act on: a table's own rows, the selection,
47
+ // or (from a lone cell) the contentful region around it — like Excel.
48
+ const dataRangeAroundSelection = useCallback(() => {
49
+ if (activeTable) {
50
+ return {
51
+ ...activeTable.range,
52
+ endRowIndex: activeTable.range.endRowIndex - (activeTable.totalRow ? 1 : 0),
53
+ };
54
+ }
55
+ if (selections.length) {
56
+ return selection.range;
57
+ }
58
+ return getContentfulRangeAroundCell?.(sheetId, activeCell) ?? selection.range;
59
+ }, [activeTable, selections.length, selection.range, getContentfulRangeAroundCell, sheetId, activeCell]);
60
+ // Excel pre-ticks "my data has headers" when the first row reads as labels:
61
+ // every cell filled and none of them a number.
62
+ const headerColumnsOf = useCallback((range) => {
63
+ const columns = [];
64
+ for (let columnIndex = range.startColumnIndex; columnIndex <= range.endColumnIndex; columnIndex++) {
65
+ const header = activeTable?.columns?.[columnIndex - activeTable.range.startColumnIndex]
66
+ ?.name ?? getFormattedValue(sheetId, range.startRowIndex, columnIndex);
67
+ columns.push({
68
+ columnIndex,
69
+ label: `Column ${number2Alpha(columnIndex - 1)}`,
70
+ header: header || undefined,
71
+ });
72
+ }
73
+ const hasHeader = activeTable
74
+ ? (activeTable.headerRow ?? true)
75
+ : range.endRowIndex > range.startRowIndex &&
76
+ columns.every((column) => !!column.header && Number.isNaN(Number(column.header)));
77
+ return { columns, hasHeader };
78
+ }, [activeTable, getFormattedValue, sheetId]);
79
+ const rangeAddress = (range) => `${cellToAddress({ rowIndex: range.startRowIndex, columnIndex: range.startColumnIndex })}:${cellToAddress({ rowIndex: range.endRowIndex, columnIndex: range.endColumnIndex })}`;
80
+ // Text to Columns → Fixed width (dialog with a ruler over the selected column).
81
+ const isTextToColumnsDialogMounted = useIsTextToColumnsDialogMounted();
82
+ const openTextToColumnsDialog = useOpenTextToColumnsDialog();
83
+ const handleTextToColumnsDialog = useCallback(() => {
84
+ const range = selections.length ? selection.range : dataRangeAroundSelection();
85
+ const columnIndex = selections.length ? range.startColumnIndex : activeCell.columnIndex;
86
+ const preview = [];
87
+ const firstRow = selections.length ? range.startRowIndex : activeCell.rowIndex;
88
+ const lastRow = selections.length ? range.endRowIndex : range.endRowIndex;
89
+ for (let rowIndex = firstRow; rowIndex <= lastRow && preview.length < 8; rowIndex++) {
90
+ preview.push(getFormattedValue(sheetId, rowIndex, columnIndex) ?? "");
91
+ }
92
+ const target = selections.length
93
+ ? selections
94
+ : [
95
+ {
96
+ range: {
97
+ startRowIndex: activeCell.rowIndex,
98
+ endRowIndex: range.endRowIndex,
99
+ startColumnIndex: columnIndex,
100
+ endColumnIndex: columnIndex,
101
+ },
102
+ },
103
+ ];
104
+ openTextToColumnsDialog({
105
+ preview,
106
+ onApply: ({ delimiter, columnBreaks }) => onSplitTextToColumns?.(sheetId, activeCell, target, delimiter, { columnBreaks }),
107
+ });
108
+ }, [
109
+ selections,
110
+ selection.range,
111
+ dataRangeAroundSelection,
112
+ activeCell,
113
+ getFormattedValue,
114
+ sheetId,
115
+ openTextToColumnsDialog,
116
+ onSplitTextToColumns,
117
+ ]);
118
+ // Data → Subtotal.
119
+ const isSubtotalDialogMounted = useIsSubtotalDialogMounted();
120
+ const openSubtotalDialog = useOpenSubtotalDialog();
121
+ const handleSubtotal = useCallback(() => {
122
+ const range = dataRangeAroundSelection();
123
+ const { columns, hasHeader } = headerColumnsOf(range);
124
+ openSubtotalDialog({
125
+ columns,
126
+ hasHeader,
127
+ onApply: (choices) => onSubtotal?.(sheetId, { range, ...choices }),
128
+ });
129
+ }, [dataRangeAroundSelection, headerColumnsOf, openSubtotalDialog, onSubtotal, sheetId]);
130
+ // Data → Advanced filter.
131
+ const isAdvancedFilterDialogMounted = useIsAdvancedFilterDialogMounted();
132
+ const openAdvancedFilterDialog = useOpenAdvancedFilterDialog();
133
+ const handleAdvancedFilter = useCallback(() => {
134
+ openAdvancedFilterDialog({
135
+ listRange: rangeAddress(dataRangeAroundSelection()),
136
+ onApply: (options) => onAdvancedFilter?.(sheetId, options),
137
+ });
138
+ }, [openAdvancedFilterDialog, dataRangeAroundSelection, onAdvancedFilter, sheetId]);
139
+ // Data → What-If Analysis → Goal Seek.
140
+ const isGoalSeekDialogMounted = useIsGoalSeekDialogMounted();
141
+ const openGoalSeekDialog = useOpenGoalSeekDialog();
142
+ const handleGoalSeek = useCallback(() => {
143
+ openGoalSeekDialog({
144
+ setCell: cellToAddress(activeCell) ?? "",
145
+ onApply: async (setCellAddress, targetValue, changingCellAddress) => {
146
+ const setCell = addressToCell(setCellAddress);
147
+ const changingCell = addressToCell(changingCellAddress);
148
+ if (!setCell || !changingCell || !onGoalSeek)
149
+ return undefined;
150
+ return onGoalSeek(sheetId, setCell, targetValue, changingCell);
151
+ },
152
+ });
153
+ }, [openGoalSeekDialog, activeCell, onGoalSeek, sheetId]);
42
154
  // Remove duplicates — Excel's dialog (column checklist + "my data has
43
155
  // headers") when a host mounts `RemoveDuplicatesDialogHost`, otherwise the
44
156
  // one-click de-dupe over the selection.
@@ -654,7 +766,14 @@ export const ContextMenu = ({ isRowHeader, isColumnHeader, activeCell, selection
654
766
  } },
655
767
  React.createElement(DropdownLeftSlot, null,
656
768
  React.createElement(CodeIcon, null)),
657
- "Evaluate formula")) : null)),
769
+ "Evaluate formula")) : null,
770
+ onRequestAddWatch ? (React.createElement(DropdownMenuItem, { onClick: () => {
771
+ shouldFocusSheetRef.current = false;
772
+ onRequestAddWatch(sheetId, activeCell);
773
+ } },
774
+ React.createElement(DropdownLeftSlot, null,
775
+ React.createElement(EyeOpenIcon, null)),
776
+ "Add to Watch Window")) : null)),
658
777
  React.createElement(DropdownMenuSeparator, null),
659
778
  React.createElement(DropdownMenuItem, { onClick: handleRemoveDuplicates, disabled: readonly },
660
779
  React.createElement(DropdownLeftSlot, null,
@@ -672,7 +791,23 @@ export const ContextMenu = ({ isRowHeader, isColumnHeader, activeCell, selection
672
791
  React.createElement(DropdownMenuItem, { onClick: () => onSplitTextToColumns?.(sheetId, activeCell, selections, ";") }, "Semicolon"),
673
792
  React.createElement(DropdownMenuItem, { onClick: () => onSplitTextToColumns?.(sheetId, activeCell, selections, ".") }, "Period"),
674
793
  React.createElement(DropdownMenuItem, { onClick: () => onSplitTextToColumns?.(sheetId, activeCell, selections, " ") }, "Space"),
675
- React.createElement(DropdownMenuItem, { onClick: () => onSplitTextToColumns?.(sheetId, activeCell, selections, "|") }, "Pipe"))),
794
+ React.createElement(DropdownMenuItem, { onClick: () => onSplitTextToColumns?.(sheetId, activeCell, selections, "|") }, "Pipe"),
795
+ isTextToColumnsDialogMounted ? (React.createElement(React.Fragment, null,
796
+ React.createElement(DropdownMenuSeparator, null),
797
+ React.createElement(DropdownMenuItem, { onClick: handleTextToColumnsDialog }, "Fixed width\u2026"))) : null)),
798
+ (isSubtotalDialogMounted && onSubtotal) ||
799
+ (isAdvancedFilterDialogMounted && onAdvancedFilter) ||
800
+ (isGoalSeekDialogMounted && onGoalSeek) ? (React.createElement(DropdownMenuSub, null,
801
+ React.createElement(DropdownMenuSubTrigger, { disabled: readonly },
802
+ React.createElement(DropdownLeftSlot, null,
803
+ React.createElement(SpaceBetweenHorizontallyIcon, null)),
804
+ "Data tools",
805
+ React.createElement(DropdownRightSlot, null,
806
+ React.createElement(ChevronRightIcon, null))),
807
+ React.createElement(DropdownMenuSubContent, { sideOffset: 2, alignOffset: -5 },
808
+ isSubtotalDialogMounted && onSubtotal ? (React.createElement(DropdownMenuItem, { onClick: handleSubtotal }, "Subtotal\u2026")) : null,
809
+ isAdvancedFilterDialogMounted && onAdvancedFilter ? (React.createElement(DropdownMenuItem, { onClick: handleAdvancedFilter }, "Advanced filter\u2026")) : null,
810
+ isGoalSeekDialogMounted && onGoalSeek ? (React.createElement(DropdownMenuItem, { onClick: handleGoalSeek }, "Goal seek\u2026")) : null))) : null,
676
811
  React.createElement(DropdownMenuSub, null,
677
812
  React.createElement(DropdownMenuSubTrigger, { disabled: readonly },
678
813
  React.createElement(DropdownLeftSlot, null,
@@ -1 +1 @@
1
- {"version":3,"file":"embed-component.d.ts","sourceRoot":"","sources":["../../../../components/embeds/embed-component.tsx"],"names":[],"mappings":"AASA,OAAO,KAAe,MAAM,OAAO,CAAC;AAEpC,OAAO,KAAK,EACV,cAAc,EAIf,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAIhF,MAAM,MAAM,mBAAmB,GAAG;IAChC,KAAK,EAAE,cAAc,CAAC;IACtB,KAAK,EAAE,gBAAgB,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,eAAe,CAAC,eAAe,CAAC,CAAC;IAChD,kBAAkB,EAAE,eAAe,CAAC,oBAAoB,CAAC,CAAC;CAC3D,CAAC;AAEF,eAAO,MAAM,cAAc,wHAUtB,mBAAmB,uBA+LvB,CAAC"}
1
+ {"version":3,"file":"embed-component.d.ts","sourceRoot":"","sources":["../../../../components/embeds/embed-component.tsx"],"names":[],"mappings":"AASA,OAAO,KAAe,MAAM,OAAO,CAAC;AAEpC,OAAO,KAAK,EACV,cAAc,EAKf,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAKhF,MAAM,MAAM,mBAAmB,GAAG;IAChC,KAAK,EAAE,cAAc,CAAC;IACtB,KAAK,EAAE,gBAAgB,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,eAAe,CAAC,eAAe,CAAC,CAAC;IAChD,kBAAkB,EAAE,eAAe,CAAC,oBAAoB,CAAC,CAAC;CAC3D,CAAC;AAEF,eAAO,MAAM,cAAc,wHAUtB,mBAAmB,uBA4NvB,CAAC"}
@@ -2,6 +2,7 @@ import { DotsVerticalIcon } from "@rowsncolumns/icons";
2
2
  import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuPortal, DropdownMenuTrigger, IconButton, } from "@rowsncolumns/ui";
3
3
  import React, { memo } from "react";
4
4
  import { getStringifiedColor } from "../../themes";
5
+ import { resolveCanvasTextAlign } from "../cell/alignment";
5
6
  import { ShapeSvg } from "./shape-svg";
6
7
  export const EmbedComponent = memo(({ embed, width, height, readonly, isSelected, onDeleteEmbed, onRequestEditEmbed, theme, }) => {
7
8
  const renderTextBox = (spec) => {
@@ -39,7 +40,9 @@ export const EmbedComponent = memo(({ embed, width, height, readonly, isSelected
39
40
  height: "100%",
40
41
  backgroundColor,
41
42
  padding: spec.padding ? `${spec.padding}px` : "4px",
42
- textAlign: spec.horizontalAlignment || undefined,
43
+ textAlign: spec.horizontalAlignment
44
+ ? resolveCanvasTextAlign(spec.horizontalAlignment)
45
+ : undefined,
43
46
  display: "flex",
44
47
  flexDirection: "column",
45
48
  justifyContent: spec.verticalAlignment === "top"
@@ -110,6 +113,19 @@ export const EmbedComponent = memo(({ embed, width, height, readonly, isSelected
110
113
  type: "textbox",
111
114
  ...embed.spec.textBody,
112
115
  }))) : null)) : null,
116
+ embed?.spec.type === "formControl" ? (
117
+ // Excel form controls round-trip but are not interactive here: draw
118
+ // the caption in a control-shaped placeholder so the layout reads.
119
+ React.createElement("div", { className: "flex h-full w-full items-center gap-1 overflow-hidden whitespace-nowrap px-1 text-xs", title: embed.spec.name ?? undefined },
120
+ embed.spec.objectType === "CheckBox" ||
121
+ embed.spec.objectType === "Radio" ? (React.createElement("span", { className: "inline-block h-3 w-3 shrink-0 border border-current", style: {
122
+ borderRadius: embed.spec.objectType === "Radio"
123
+ ? "50%"
124
+ : 2,
125
+ } })) : null,
126
+ React.createElement("span", { className: "truncate" }, embed.spec.text ??
127
+ embed.spec.name ??
128
+ embed.spec.objectType))) : null,
113
129
  readonly || !isSelected ? null : (React.createElement(DropdownMenu, null,
114
130
  React.createElement(DropdownMenuTrigger, { asChild: true, className: "print:hidden" },
115
131
  React.createElement(IconButton, { className: "absolute right-1 top-1 z-10" },
@@ -0,0 +1,29 @@
1
+ import React from "react";
2
+ import type { FillSeriesSpec } from "../../types";
3
+ export type FillSeriesDialogProps = {
4
+ /** Controls visibility. */
5
+ open: boolean;
6
+ onOpenChange(open: boolean): void;
7
+ /** Pre-selected axis (a right-drag seeds it from its direction). */
8
+ initialIn?: FillSeriesSpec["in"];
9
+ onApply(spec: FillSeriesSpec): void;
10
+ };
11
+ /**
12
+ * Excel's Series dialog (Home > Fill > Series…). Series in Rows/Columns, Type
13
+ * Linear/Growth/Date/AutoFill, Date unit (Type = Date only), Trend
14
+ * (Linear/Growth only — disables Step/Stop), Step value (default 1, may be
15
+ * negative or fractional) and Stop value. UI-only: the opener turns the spec
16
+ * into a fill.
17
+ */
18
+ export declare const FillSeriesDialog: React.MemoExoticComponent<({ open, onOpenChange, initialIn, onApply }: FillSeriesDialogProps) => React.JSX.Element>;
19
+ /**
20
+ * Host-mounted, atom-driven wrapper around {@link FillSeriesDialog}. Mount it
21
+ * once alongside the other editor dialogs; the grid opens it via
22
+ * `useOpenFillSeriesDialog` (right-drag menu "Series…", or
23
+ * `SpreadsheetApi.openFillSeriesDialog()` from a Fill toolbar/menu).
24
+ */
25
+ export declare const FillSeriesDialogHost: {
26
+ (): React.JSX.Element;
27
+ displayName: string;
28
+ };
29
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../components/fill-series-dialog/index.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAGtE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,MAAM,MAAM,qBAAqB,GAAG;IAClC,2BAA2B;IAC3B,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAC;IAClC,oEAAoE;IACpE,SAAS,CAAC,EAAE,cAAc,CAAC,IAAI,CAAC,CAAC;IACjC,OAAO,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI,CAAC;CACrC,CAAC;AA0BF;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,yEACkB,qBAAqB,uBA4MnE,CAAC;AAIF;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB;;;CAahC,CAAC"}
@@ -0,0 +1,151 @@
1
+ import { Button, Dialog, DialogBody, DialogCloseButton, DialogContent, DialogTitle, Input, Separator, } from "@rowsncolumns/ui";
2
+ import React, { memo, useCallback, useEffect, useState } from "react";
3
+ import { useFillSeriesDialogState } from "../../atoms/fill-series-dialog.atom";
4
+ const SERIES_TYPES = [
5
+ { value: "linear", label: "Linear" },
6
+ { value: "growth", label: "Growth" },
7
+ { value: "date", label: "Date" },
8
+ { value: "autofill", label: "AutoFill" },
9
+ ];
10
+ const DATE_UNITS = [
11
+ { value: "day", label: "Day" },
12
+ { value: "weekday", label: "Weekday" },
13
+ { value: "month", label: "Month" },
14
+ { value: "year", label: "Year" },
15
+ ];
16
+ const parseNumber = (text) => {
17
+ const trimmed = text.trim();
18
+ if (!trimmed)
19
+ return undefined;
20
+ const n = Number(trimmed);
21
+ return Number.isFinite(n) ? n : undefined;
22
+ };
23
+ /**
24
+ * Excel's Series dialog (Home > Fill > Series…). Series in Rows/Columns, Type
25
+ * Linear/Growth/Date/AutoFill, Date unit (Type = Date only), Trend
26
+ * (Linear/Growth only — disables Step/Stop), Step value (default 1, may be
27
+ * negative or fractional) and Stop value. UI-only: the opener turns the spec
28
+ * into a fill.
29
+ */
30
+ export const FillSeriesDialog = memo(({ open, onOpenChange, initialIn, onApply }) => {
31
+ const [axis, setAxis] = useState(initialIn ?? "columns");
32
+ const [type, setType] = useState("linear");
33
+ const [dateUnit, setDateUnit] = useState("day");
34
+ const [trend, setTrend] = useState(false);
35
+ const [step, setStep] = useState("1");
36
+ const [stop, setStop] = useState("");
37
+ const [error, setError] = useState(undefined);
38
+ // Re-seed on every open (the request decides the default axis).
39
+ useEffect(() => {
40
+ if (open) {
41
+ setAxis(initialIn ?? "columns");
42
+ setType("linear");
43
+ setDateUnit("day");
44
+ setTrend(false);
45
+ setStep("1");
46
+ setStop("");
47
+ setError(undefined);
48
+ }
49
+ }, [open, initialIn]);
50
+ const trendAllowed = type === "linear" || type === "growth";
51
+ const stepStopDisabled = trendAllowed && trend;
52
+ const apply = useCallback(() => {
53
+ const stepValue = parseNumber(step);
54
+ if (!stepStopDisabled && step.trim() && stepValue === undefined) {
55
+ setError("Step value must be a number.");
56
+ return;
57
+ }
58
+ const stopValue = parseNumber(stop);
59
+ if (!stepStopDisabled && stop.trim() && stopValue === undefined) {
60
+ setError("Stop value must be a number.");
61
+ return;
62
+ }
63
+ const spec = {
64
+ in: axis,
65
+ type,
66
+ ...(type === "date" ? { dateUnit } : {}),
67
+ ...(trendAllowed && trend ? { trend: true } : {}),
68
+ ...(!stepStopDisabled && stepValue !== undefined
69
+ ? { step: stepValue }
70
+ : {}),
71
+ ...(!stepStopDisabled && stopValue !== undefined
72
+ ? { stop: stopValue }
73
+ : {}),
74
+ };
75
+ onApply(spec);
76
+ onOpenChange(false);
77
+ }, [
78
+ axis,
79
+ type,
80
+ dateUnit,
81
+ trend,
82
+ trendAllowed,
83
+ step,
84
+ stop,
85
+ stepStopDisabled,
86
+ onApply,
87
+ onOpenChange,
88
+ ]);
89
+ return (React.createElement(Dialog, { open: open, onOpenChange: onOpenChange, modal: true },
90
+ React.createElement(DialogContent, { className: "w-[420px] max-w-[92vw] pointer-events-auto" },
91
+ React.createElement(DialogTitle, null, "Series"),
92
+ React.createElement(DialogCloseButton, null),
93
+ React.createElement(DialogBody, { className: "flex flex-col gap-3" },
94
+ React.createElement("form", { className: "flex flex-col gap-3", onSubmit: (e) => {
95
+ e.preventDefault();
96
+ apply();
97
+ } },
98
+ React.createElement("div", { className: "grid grid-cols-3 gap-3" },
99
+ React.createElement("fieldset", { className: "flex flex-col gap-1 border-0 p-0 m-0" },
100
+ React.createElement("legend", { className: "text-xs font-medium pb-1" }, "Series in"),
101
+ ["rows", "columns"].map((value) => (React.createElement("label", { key: value, className: "flex items-center gap-2 text-xs cursor-pointer" },
102
+ React.createElement("input", { type: "radio", name: "fillSeriesIn", value: value, checked: axis === value, onChange: () => setAxis(value) }),
103
+ value === "rows" ? "Rows" : "Columns")))),
104
+ React.createElement("fieldset", { className: "flex flex-col gap-1 border-0 p-0 m-0" },
105
+ React.createElement("legend", { className: "text-xs font-medium pb-1" }, "Type"),
106
+ SERIES_TYPES.map(({ value, label }) => (React.createElement("label", { key: value, className: "flex items-center gap-2 text-xs cursor-pointer" },
107
+ React.createElement("input", { type: "radio", name: "fillSeriesType", value: value, checked: type === value, onChange: () => setType(value) }),
108
+ label)))),
109
+ React.createElement("fieldset", { className: "flex flex-col gap-1 border-0 p-0 m-0", disabled: type !== "date" },
110
+ React.createElement("legend", { className: "text-xs font-medium pb-1" }, "Date unit"),
111
+ DATE_UNITS.map(({ value, label }) => (React.createElement("label", { key: value, className: "flex items-center gap-2 text-xs cursor-pointer disabled:opacity-50" },
112
+ React.createElement("input", { type: "radio", name: "fillSeriesDateUnit", value: value, checked: dateUnit === value, onChange: () => setDateUnit(value), disabled: type !== "date" }),
113
+ React.createElement("span", { className: type !== "date" ? "opacity-50" : "" }, label)))))),
114
+ React.createElement("label", { className: "flex items-center gap-2 text-xs cursor-pointer" },
115
+ React.createElement("input", { type: "checkbox", name: "fillSeriesTrend", checked: trendAllowed && trend, disabled: !trendAllowed, onChange: (e) => setTrend(e.target.checked) }),
116
+ React.createElement("span", { className: !trendAllowed ? "opacity-50" : "" }, "Trend")),
117
+ React.createElement("div", { className: "grid grid-cols-2 gap-3" },
118
+ React.createElement("label", { className: "flex flex-col gap-1 text-xs" },
119
+ "Step value",
120
+ React.createElement(Input, { name: "fillSeriesStep", value: step, disabled: stepStopDisabled, onChange: (e) => {
121
+ setStep(e.target.value);
122
+ setError(undefined);
123
+ }, inputMode: "decimal" })),
124
+ React.createElement("label", { className: "flex flex-col gap-1 text-xs" },
125
+ "Stop value",
126
+ React.createElement(Input, { name: "fillSeriesStop", value: stop, disabled: stepStopDisabled, onChange: (e) => {
127
+ setStop(e.target.value);
128
+ setError(undefined);
129
+ }, inputMode: "decimal" }))),
130
+ error ? (React.createElement("div", { role: "alert", className: "text-xs text-rnc-destructive" }, error)) : null,
131
+ React.createElement(Separator, null),
132
+ React.createElement("div", { className: "flex justify-end gap-2" },
133
+ React.createElement(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => onOpenChange(false) }, "Cancel"),
134
+ React.createElement(Button, { type: "submit", size: "sm" }, "OK")))))));
135
+ });
136
+ FillSeriesDialog.displayName = "FillSeriesDialog";
137
+ /**
138
+ * Host-mounted, atom-driven wrapper around {@link FillSeriesDialog}. Mount it
139
+ * once alongside the other editor dialogs; the grid opens it via
140
+ * `useOpenFillSeriesDialog` (right-drag menu "Series…", or
141
+ * `SpreadsheetApi.openFillSeriesDialog()` from a Fill toolbar/menu).
142
+ */
143
+ export const FillSeriesDialogHost = () => {
144
+ const [request, setRequest] = useFillSeriesDialogState();
145
+ const close = useCallback(() => setRequest(null), [setRequest]);
146
+ return (React.createElement(FillSeriesDialog, { open: request != null, onOpenChange: (open) => {
147
+ if (!open)
148
+ close();
149
+ }, initialIn: request?.initialIn, onApply: (spec) => request?.onApply(spec) }));
150
+ };
151
+ FillSeriesDialogHost.displayName = "FillSeriesDialogHost";
@@ -1,4 +1,6 @@
1
+ import type { GridRange } from "@rowsncolumns/grid";
1
2
  import React from "react";
3
+ import { type GoToSpecialKind } from "../../api/go-to-special";
2
4
  import type { NamedRange, SheetRange } from "../../types";
3
5
  export type GoToDialogProps = {
4
6
  /** Controls visibility. */
@@ -15,6 +17,14 @@ export type GoToDialogProps = {
15
17
  resolve(reference: string): SheetRange | undefined;
16
18
  /** Receives the resolved range; the host selects and scrolls to it. */
17
19
  onNavigate(range: SheetRange): void;
20
+ /**
21
+ * Go To Special. `resolve` returns the matching cell runs for a category;
22
+ * `onSelectRanges` receives them. Omit to hide the "Special…" panel.
23
+ */
24
+ special?: {
25
+ resolve(kind: GoToSpecialKind): GridRange[];
26
+ onSelectRanges(ranges: GridRange[]): void;
27
+ };
18
28
  };
19
29
  /**
20
30
  * Excel's Go To dialog (`Ctrl+G` / `F5`): type a cell or range reference,
@@ -22,7 +32,7 @@ export type GoToDialogProps = {
22
32
  * jumps there. Resolution is delegated to `resolve` so the dialog stays
23
33
  * UI-only.
24
34
  */
25
- export declare const GoToDialog: React.MemoExoticComponent<({ open, onOpenChange, namedRanges, currentAddress, resolve, onNavigate, }: GoToDialogProps) => React.JSX.Element>;
35
+ export declare const GoToDialog: React.MemoExoticComponent<({ open, onOpenChange, namedRanges, currentAddress, resolve, onNavigate, special, }: GoToDialogProps) => React.JSX.Element>;
26
36
  /**
27
37
  * Host-mounted, atom-driven wrapper around {@link GoToDialog}. Mount it once
28
38
  * in the host alongside the other editor dialogs; the grid opens it on
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../components/go-to-dialog/index.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAsC,MAAM,OAAO,CAAC;AAQ3D,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE1D,MAAM,MAAM,eAAe,GAAG;IAC5B,2BAA2B;IAC3B,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAC;IAClC,gFAAgF;IAChF,WAAW,CAAC,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC;IAClC,4EAA4E;IAC5E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAAC;IACnD,uEAAuE;IACvE,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;CACrC,CAAC;AAIF;;;;;GAKG;AACH,eAAO,MAAM,UAAU,wGAQlB,eAAe,uBA4GnB,CAAC;AAUF;;;;GAIG;AACH,eAAO,MAAM,cAAc;;;CA8B1B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../components/go-to-dialog/index.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAEpD,OAAO,KAAsC,MAAM,OAAO,CAAC;AAG3D,OAAO,EAEL,KAAK,eAAe,EACrB,MAAM,yBAAyB,CAAC;AAMjC,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE1D,MAAM,MAAM,eAAe,GAAG;IAC5B,2BAA2B;IAC3B,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAC;IAClC,gFAAgF;IAChF,WAAW,CAAC,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC;IAClC,4EAA4E;IAC5E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAAC;IACnD,uEAAuE;IACvE,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;IACpC;;;OAGG;IACH,OAAO,CAAC,EAAE;QACR,OAAO,CAAC,IAAI,EAAE,eAAe,GAAG,SAAS,EAAE,CAAC;QAC5C,cAAc,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC;KAC3C,CAAC;CACH,CAAC;AAKF;;;;;GAKG;AACH,eAAO,MAAM,UAAU,iHASlB,eAAe,uBA0MnB,CAAC;AAUF;;;;GAIG;AACH,eAAO,MAAM,cAAc;;;CA+B1B,CAAC"}
@@ -2,17 +2,32 @@ import { Button, cn, Dialog, DialogBody, DialogCloseButton, DialogContent, Dialo
2
2
  import { cellToAddress } from "@rowsncolumns/utils";
3
3
  import React, { memo, useCallback, useState } from "react";
4
4
  import { resolveGoToReference } from "../../api/go-to";
5
+ import { GO_TO_SPECIAL_OPTIONS, } from "../../api/go-to-special";
5
6
  import { useGoToDialogState, useRegisterGoToDialogHost, } from "../../atoms/go-to-dialog.atom";
6
7
  const INVALID_REFERENCE = "Reference is not valid.";
8
+ const NO_CELLS_FOUND = "No cells were found.";
7
9
  /**
8
10
  * Excel's Go To dialog (`Ctrl+G` / `F5`): type a cell or range reference,
9
11
  * optionally sheet-qualified, or pick a defined name, and the selection
10
12
  * jumps there. Resolution is delegated to `resolve` so the dialog stays
11
13
  * UI-only.
12
14
  */
13
- export const GoToDialog = memo(({ open, onOpenChange, namedRanges, currentAddress, resolve, onNavigate, }) => {
15
+ export const GoToDialog = memo(({ open, onOpenChange, namedRanges, currentAddress, resolve, onNavigate, special, }) => {
14
16
  const [reference, setReference] = useState("");
15
17
  const [error, setError] = useState(undefined);
18
+ const [showSpecial, setShowSpecial] = useState(false);
19
+ const [specialKind, setSpecialKind] = useState("blanks");
20
+ const selectSpecial = useCallback(() => {
21
+ if (!special)
22
+ return;
23
+ const ranges = special.resolve(specialKind);
24
+ if (!ranges.length) {
25
+ setError(NO_CELLS_FOUND);
26
+ return;
27
+ }
28
+ special.onSelectRanges(ranges);
29
+ onOpenChange(false);
30
+ }, [special, specialKind, onOpenChange]);
16
31
  const navigate = useCallback((text) => {
17
32
  const range = resolve(text);
18
33
  if (!range) {
@@ -25,30 +40,55 @@ export const GoToDialog = memo(({ open, onOpenChange, namedRanges, currentAddres
25
40
  const names = (namedRanges ?? []).filter((range) => range.range && !range.hidden);
26
41
  return (React.createElement(Dialog, { open: open, onOpenChange: onOpenChange, modal: true },
27
42
  React.createElement(DialogContent, { className: "w-[360px] max-w-[92vw] pointer-events-auto" },
28
- React.createElement(DialogTitle, null, "Go To"),
43
+ React.createElement(DialogTitle, null, showSpecial ? "Go To Special" : "Go To"),
29
44
  React.createElement(DialogCloseButton, null),
30
- React.createElement(DialogBody, { className: "flex flex-col gap-3" },
31
- React.createElement("form", { className: "flex flex-col gap-3", onSubmit: (e) => {
32
- e.preventDefault();
33
- navigate(reference);
34
- } },
35
- React.createElement("div", { className: "flex flex-col gap-1" },
36
- React.createElement("span", { className: "text-xs font-medium" }, "Go to:"),
37
- React.createElement("div", { role: "listbox", "aria-label": "Defined names", className: "h-[140px] overflow-auto rounded border border-rnc-border text-xs" }, names.length === 0 ? (React.createElement("div", { className: "px-2 py-1.5 text-rnc-foreground/60" }, "No defined names")) : (names.map((range) => (React.createElement("div", { key: String(range.namedRangeId), role: "option", "aria-selected": reference === range.name, className: cn("px-2 py-1 cursor-default select-none hover:bg-rnc-accent", reference === range.name && "bg-rnc-accent"), onClick: () => {
38
- setReference(range.name);
39
- setError(undefined);
40
- }, onDoubleClick: () => navigate(range.name) }, range.name)))))),
41
- React.createElement("label", { className: "flex flex-col gap-1 text-xs font-medium" },
42
- "Reference:",
43
- React.createElement(Input, { autoFocus: true, value: reference, placeholder: currentAddress, "aria-invalid": error ? true : undefined, onChange: (e) => {
44
- setReference(e.target.value);
45
+ React.createElement(DialogBody, { className: "flex flex-col gap-3" }, showSpecial && special ? (React.createElement("form", { className: "flex flex-col gap-3", onSubmit: (e) => {
46
+ e.preventDefault();
47
+ selectSpecial();
48
+ } },
49
+ React.createElement("fieldset", { className: "flex flex-col gap-1 border-0 p-0 m-0" },
50
+ React.createElement("legend", { className: "text-xs font-medium pb-1" }, "Select"),
51
+ GO_TO_SPECIAL_OPTIONS.map(({ kind, label }) => (React.createElement("label", { key: kind, className: "flex items-center gap-2 text-xs cursor-pointer" },
52
+ React.createElement("input", { type: "radio", name: "goToSpecial", value: kind, checked: specialKind === kind, onChange: () => {
53
+ setSpecialKind(kind);
45
54
  setError(undefined);
46
- } })),
47
- error ? (React.createElement("div", { role: "alert", className: "text-xs text-rnc-destructive" }, error)) : null,
48
- React.createElement(Separator, null),
49
- React.createElement("div", { className: "flex justify-end gap-2" },
55
+ } }),
56
+ label)))),
57
+ error ? (React.createElement("div", { role: "alert", className: "text-xs text-rnc-destructive" }, error)) : null,
58
+ React.createElement(Separator, null),
59
+ React.createElement("div", { className: "flex justify-between gap-2" },
60
+ React.createElement(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => {
61
+ setShowSpecial(false);
62
+ setError(undefined);
63
+ } }, "Back"),
64
+ React.createElement("div", { className: "flex gap-2" },
65
+ React.createElement(Button, { type: "button", variant: "outline", size: "sm", onClick: () => onOpenChange(false) }, "Cancel"),
66
+ React.createElement(Button, { type: "submit", size: "sm" }, "OK"))))) : (React.createElement("form", { className: "flex flex-col gap-3", onSubmit: (e) => {
67
+ e.preventDefault();
68
+ navigate(reference);
69
+ } },
70
+ React.createElement("div", { className: "flex flex-col gap-1" },
71
+ React.createElement("span", { className: "text-xs font-medium" }, "Go to:"),
72
+ React.createElement("div", { role: "listbox", "aria-label": "Defined names", className: "h-[140px] overflow-auto rounded border border-rnc-border text-xs" }, names.length === 0 ? (React.createElement("div", { className: "px-2 py-1.5 text-rnc-foreground/60" }, "No defined names")) : (names.map((range) => (React.createElement("div", { key: String(range.namedRangeId), role: "option", "aria-selected": reference === range.name, className: cn("px-2 py-1 cursor-default select-none hover:bg-rnc-accent", reference === range.name && "bg-rnc-accent"), onClick: () => {
73
+ setReference(range.name);
74
+ setError(undefined);
75
+ }, onDoubleClick: () => navigate(range.name) }, range.name)))))),
76
+ React.createElement("label", { className: "flex flex-col gap-1 text-xs font-medium" },
77
+ "Reference:",
78
+ React.createElement(Input, { autoFocus: true, value: reference, placeholder: currentAddress, "aria-invalid": error ? true : undefined, onChange: (e) => {
79
+ setReference(e.target.value);
80
+ setError(undefined);
81
+ } })),
82
+ error ? (React.createElement("div", { role: "alert", className: "text-xs text-rnc-destructive" }, error)) : null,
83
+ React.createElement(Separator, null),
84
+ React.createElement("div", { className: "flex justify-between gap-2" },
85
+ special ? (React.createElement(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => {
86
+ setShowSpecial(true);
87
+ setError(undefined);
88
+ } }, "Special\u2026")) : (React.createElement("span", null)),
89
+ React.createElement("div", { className: "flex gap-2" },
50
90
  React.createElement(Button, { type: "button", variant: "outline", size: "sm", onClick: () => onOpenChange(false) }, "Cancel"),
51
- React.createElement(Button, { type: "submit", size: "sm", disabled: !reference.trim() }, "OK")))))));
91
+ React.createElement(Button, { type: "submit", size: "sm", disabled: !reference.trim() }, "OK")))))))));
52
92
  });
53
93
  GoToDialog.displayName = "GoToDialog";
54
94
  const currentAddressOf = (request) => {
@@ -79,6 +119,6 @@ export const GoToDialogHost = () => {
79
119
  return (React.createElement(GoToDialog, { open: true, onOpenChange: (open) => {
80
120
  if (!open)
81
121
  close();
82
- }, namedRanges: request.namedRanges, currentAddress: currentAddressOf(request), resolve: resolve, onNavigate: request.onNavigate }));
122
+ }, namedRanges: request.namedRanges, currentAddress: currentAddressOf(request), resolve: resolve, onNavigate: request.onNavigate, special: request.special }));
83
123
  };
84
124
  GoToDialogHost.displayName = "GoToDialogHost";
@@ -0,0 +1,32 @@
1
+ import React from "react";
2
+ import type { GoalSeekResult } from "../../types";
3
+ export type GoalSeekDialogProps = {
4
+ /** Controls visibility. */
5
+ open: boolean;
6
+ onOpenChange(open: boolean): void;
7
+ /** Default "Set cell" (A1 reference of the active cell). */
8
+ initialSetCell: string;
9
+ /**
10
+ * Runs the search with the three fields (A1 references + the numeric
11
+ * target). Resolves to the result, or `undefined` when the engine reports
12
+ * none (the rnc engine iterates natively and streams the cells back).
13
+ */
14
+ onApply(setCell: string, targetValue: number, changingCell: string): Promise<GoalSeekResult | undefined>;
15
+ };
16
+ /** Excel's status sentence for a finished search. */
17
+ export declare const goalSeekStatusText: (setCell: string, result: GoalSeekResult | undefined) => string;
18
+ /**
19
+ * Excel's Goal Seek dialog: Set cell / To value / By changing cell, then the
20
+ * Goal Seek Status sentence with target and current value.
21
+ */
22
+ export declare const GoalSeekDialog: React.MemoExoticComponent<({ open, onOpenChange, initialSetCell, onApply }: GoalSeekDialogProps) => React.JSX.Element>;
23
+ /**
24
+ * Host-mounted, atom-driven wrapper around {@link GoalSeekDialog}. Mount
25
+ * once in the host; the context menu opens it via `useOpenGoalSeekDialog`
26
+ * and only offers the item while a host is mounted.
27
+ */
28
+ export declare const GoalSeekDialogHost: {
29
+ (): React.JSX.Element;
30
+ displayName: string;
31
+ };
32
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../components/goal-seek-dialog/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAMtE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,MAAM,MAAM,mBAAmB,GAAG;IAChC,2BAA2B;IAC3B,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAC;IAClC,4DAA4D;IAC5D,cAAc,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,OAAO,CACL,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CAAC;CACxC,CAAC;AAKF,qDAAqD;AACrD,eAAO,MAAM,kBAAkB,GAC7B,SAAS,MAAM,EACf,QAAQ,cAAc,GAAG,SAAS,KACjC,MAKF,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,cAAc,8EACyB,mBAAmB,uBAyJtE,CAAC;AAIF;;;;GAIG;AACH,eAAO,MAAM,kBAAkB;;;CAkB9B,CAAC"}