@dxos/plugin-sheet 0.6.12 → 0.6.13-main.548ca8d

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 (325) hide show
  1. package/dist/lib/browser/SheetContainer-NDNIS44E.mjs +265 -0
  2. package/dist/lib/browser/SheetContainer-NDNIS44E.mjs.map +7 -0
  3. package/dist/lib/browser/chunk-AQSGDA4X.mjs +1614 -0
  4. package/dist/lib/browser/chunk-AQSGDA4X.mjs.map +7 -0
  5. package/dist/lib/browser/chunk-D3QTX46O.mjs +14 -0
  6. package/dist/lib/browser/chunk-D3QTX46O.mjs.map +7 -0
  7. package/dist/lib/browser/chunk-GKI67SEF.mjs +69 -0
  8. package/dist/lib/browser/chunk-GKI67SEF.mjs.map +7 -0
  9. package/dist/lib/browser/chunk-GSV5QNLD.mjs +2966 -0
  10. package/dist/lib/browser/chunk-GSV5QNLD.mjs.map +7 -0
  11. package/dist/lib/browser/graph-M4IQ76QX.mjs +33 -0
  12. package/dist/lib/browser/graph-M4IQ76QX.mjs.map +7 -0
  13. package/dist/lib/browser/index.mjs +93 -62
  14. package/dist/lib/browser/index.mjs.map +3 -3
  15. package/dist/lib/browser/meta.json +1 -1
  16. package/dist/lib/browser/meta.mjs +1 -1
  17. package/dist/lib/browser/types.mjs +4 -10
  18. package/dist/lib/node/SheetContainer-YSQGJD7K.cjs +276 -0
  19. package/dist/lib/node/SheetContainer-YSQGJD7K.cjs.map +7 -0
  20. package/dist/lib/node/{chunk-5KKJ4NPP.cjs → chunk-5XPK2V4A.cjs} +418 -678
  21. package/dist/lib/node/chunk-5XPK2V4A.cjs.map +7 -0
  22. package/dist/lib/node/chunk-6F43RV45.cjs +1610 -0
  23. package/dist/lib/node/chunk-6F43RV45.cjs.map +7 -0
  24. package/dist/lib/node/{chunk-DSYKOI4E.cjs → chunk-ER3PM7GD.cjs} +29 -45
  25. package/dist/lib/node/chunk-ER3PM7GD.cjs.map +7 -0
  26. package/dist/lib/node/chunk-QIFIGEKV.cjs +37 -0
  27. package/dist/lib/node/chunk-QIFIGEKV.cjs.map +7 -0
  28. package/dist/lib/node/graph-Q3N2X26H.cjs +55 -0
  29. package/dist/lib/node/graph-Q3N2X26H.cjs.map +7 -0
  30. package/dist/lib/node/index.cjs +105 -69
  31. package/dist/lib/node/index.cjs.map +3 -3
  32. package/dist/lib/node/meta.cjs +3 -3
  33. package/dist/lib/node/meta.cjs.map +1 -1
  34. package/dist/lib/node/meta.json +1 -1
  35. package/dist/lib/node/types.cjs +8 -14
  36. package/dist/lib/node/types.cjs.map +2 -2
  37. package/dist/lib/node-esm/SheetContainer-M7WRMZDU.mjs +266 -0
  38. package/dist/lib/node-esm/SheetContainer-M7WRMZDU.mjs.map +7 -0
  39. package/dist/lib/{browser/chunk-D5AGLXJP.mjs → node-esm/chunk-5WPZCXNS.mjs} +411 -678
  40. package/dist/lib/node-esm/chunk-5WPZCXNS.mjs.map +7 -0
  41. package/dist/lib/node-esm/chunk-ELTFPX5B.mjs +1615 -0
  42. package/dist/lib/node-esm/chunk-ELTFPX5B.mjs.map +7 -0
  43. package/dist/lib/node-esm/chunk-VCYJWE3O.mjs +16 -0
  44. package/dist/lib/node-esm/chunk-VCYJWE3O.mjs.map +7 -0
  45. package/dist/lib/node-esm/chunk-ZVLLQ2PJ.mjs +70 -0
  46. package/dist/lib/node-esm/chunk-ZVLLQ2PJ.mjs.map +7 -0
  47. package/dist/lib/node-esm/graph-SMPUMOV2.mjs +34 -0
  48. package/dist/lib/node-esm/graph-SMPUMOV2.mjs.map +7 -0
  49. package/dist/lib/node-esm/index.mjs +280 -0
  50. package/dist/lib/node-esm/index.mjs.map +7 -0
  51. package/dist/lib/node-esm/meta.json +1 -0
  52. package/dist/lib/node-esm/meta.mjs +10 -0
  53. package/dist/lib/node-esm/meta.mjs.map +7 -0
  54. package/dist/lib/node-esm/types.mjs +17 -0
  55. package/dist/lib/node-esm/types.mjs.map +7 -0
  56. package/dist/types/src/SheetPlugin.d.ts.map +1 -1
  57. package/dist/types/src/components/ComputeGraph/ComputeGraphContextProvider.d.ts +11 -0
  58. package/dist/types/src/components/ComputeGraph/ComputeGraphContextProvider.d.ts.map +1 -0
  59. package/dist/types/src/components/ComputeGraph/index.d.ts +1 -3
  60. package/dist/types/src/components/ComputeGraph/index.d.ts.map +1 -1
  61. package/dist/types/src/components/FunctionEditor/FunctionEditor.d.ts +3 -0
  62. package/dist/types/src/components/FunctionEditor/FunctionEditor.d.ts.map +1 -0
  63. package/dist/types/src/components/FunctionEditor/index.d.ts +2 -0
  64. package/dist/types/src/components/FunctionEditor/index.d.ts.map +1 -0
  65. package/dist/types/src/components/GridSheet/GridSheet.d.ts +3 -0
  66. package/dist/types/src/components/GridSheet/GridSheet.d.ts.map +1 -0
  67. package/dist/types/src/components/GridSheet/GridSheet.stories.d.ts +9 -0
  68. package/dist/types/src/components/GridSheet/GridSheet.stories.d.ts.map +1 -0
  69. package/dist/types/src/components/{CellEditor/CellEditor.stories.d.ts → GridSheet/SheetCellEditor.stories.d.ts} +4 -4
  70. package/dist/types/src/components/GridSheet/SheetCellEditor.stories.d.ts.map +1 -0
  71. package/dist/types/src/components/GridSheet/index.d.ts +2 -0
  72. package/dist/types/src/components/GridSheet/index.d.ts.map +1 -0
  73. package/dist/types/src/components/GridSheet/util.d.ts +16 -0
  74. package/dist/types/src/components/GridSheet/util.d.ts.map +1 -0
  75. package/dist/types/src/components/SheetContainer/SheetContainer.d.ts +6 -0
  76. package/dist/types/src/components/SheetContainer/SheetContainer.d.ts.map +1 -0
  77. package/dist/types/src/components/SheetContainer/SheetContainer.stories.d.ts +11 -0
  78. package/dist/types/src/components/SheetContainer/SheetContainer.stories.d.ts.map +1 -0
  79. package/dist/types/src/components/SheetContainer/index.d.ts +3 -0
  80. package/dist/types/src/components/SheetContainer/index.d.ts.map +1 -0
  81. package/dist/types/src/components/SheetContext/SheetContext.d.ts +27 -0
  82. package/dist/types/src/components/SheetContext/SheetContext.d.ts.map +1 -0
  83. package/dist/types/src/components/SheetContext/index.d.ts +2 -0
  84. package/dist/types/src/components/SheetContext/index.d.ts.map +1 -0
  85. package/dist/types/src/components/Toolbar/Toolbar.d.ts +36 -6
  86. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -1
  87. package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts +19 -14
  88. package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +1 -1
  89. package/dist/types/src/components/index.d.ts +3 -2
  90. package/dist/types/src/components/index.d.ts.map +1 -1
  91. package/dist/types/src/defs/index.d.ts +3 -0
  92. package/dist/types/src/defs/index.d.ts.map +1 -0
  93. package/dist/types/src/{model → defs}/types.d.ts +8 -3
  94. package/dist/types/src/defs/types.d.ts.map +1 -0
  95. package/dist/types/src/defs/types.test.d.ts.map +1 -0
  96. package/dist/types/src/defs/util.d.ts +43 -0
  97. package/dist/types/src/defs/util.d.ts.map +1 -0
  98. package/dist/types/src/extensions/compute.d.ts +6 -0
  99. package/dist/types/src/extensions/compute.d.ts.map +1 -0
  100. package/dist/types/src/extensions/compute.stories.d.ts +26 -0
  101. package/dist/types/src/extensions/compute.stories.d.ts.map +1 -0
  102. package/dist/types/src/{components/CellEditor → extensions/editor}/extension.d.ts +1 -1
  103. package/dist/types/src/extensions/editor/extension.d.ts.map +1 -0
  104. package/dist/types/src/extensions/editor/extension.test.d.ts.map +1 -0
  105. package/dist/types/src/extensions/editor/index.d.ts +2 -0
  106. package/dist/types/src/extensions/editor/index.d.ts.map +1 -0
  107. package/dist/types/src/extensions/index.d.ts +3 -0
  108. package/dist/types/src/extensions/index.d.ts.map +1 -0
  109. package/dist/types/src/graph/compute-graph-registry.d.ts +34 -0
  110. package/dist/types/src/graph/compute-graph-registry.d.ts.map +1 -0
  111. package/dist/types/src/graph/compute-graph.d.ts +64 -0
  112. package/dist/types/src/graph/compute-graph.d.ts.map +1 -0
  113. package/dist/types/src/graph/compute-graph.stories.d.ts +10 -0
  114. package/dist/types/src/graph/compute-graph.stories.d.ts.map +1 -0
  115. package/dist/types/src/graph/compute-graph.test.d.ts +2 -0
  116. package/dist/types/src/graph/compute-graph.test.d.ts.map +1 -0
  117. package/dist/types/src/graph/compute-node.d.ts +26 -0
  118. package/dist/types/src/graph/compute-node.d.ts.map +1 -0
  119. package/dist/types/src/{components/ComputeGraph → graph/functions}/async-function.d.ts +14 -5
  120. package/dist/types/src/graph/functions/async-function.d.ts.map +1 -0
  121. package/dist/types/src/graph/functions/edge-function.d.ts +21 -0
  122. package/dist/types/src/graph/functions/edge-function.d.ts.map +1 -0
  123. package/dist/types/src/{model/functions.d.ts → graph/functions/function-defs.d.ts} +1 -1
  124. package/dist/types/src/graph/functions/function-defs.d.ts.map +1 -0
  125. package/dist/types/src/graph/functions/index.d.ts +4 -0
  126. package/dist/types/src/graph/functions/index.d.ts.map +1 -0
  127. package/dist/types/src/graph/hyperformula.test.d.ts +2 -0
  128. package/dist/types/src/graph/hyperformula.test.d.ts.map +1 -0
  129. package/dist/types/src/graph/index.d.ts +5 -0
  130. package/dist/types/src/graph/index.d.ts.map +1 -0
  131. package/dist/types/src/graph/testing/index.d.ts +3 -0
  132. package/dist/types/src/graph/testing/index.d.ts.map +1 -0
  133. package/dist/types/src/graph/testing/test-builder.d.ts +15 -0
  134. package/dist/types/src/graph/testing/test-builder.d.ts.map +1 -0
  135. package/dist/types/src/graph/testing/test-plugin.d.ts +36 -0
  136. package/dist/types/src/graph/testing/test-plugin.d.ts.map +1 -0
  137. package/dist/types/src/graph/util.d.ts +2 -0
  138. package/dist/types/src/graph/util.d.ts.map +1 -0
  139. package/dist/types/src/hooks/hooks.stories.d.ts +11 -0
  140. package/dist/types/src/hooks/hooks.stories.d.ts.map +1 -0
  141. package/dist/types/src/hooks/index.d.ts +5 -0
  142. package/dist/types/src/hooks/index.d.ts.map +1 -0
  143. package/dist/types/src/hooks/threads.d.ts +8 -0
  144. package/dist/types/src/hooks/threads.d.ts.map +1 -0
  145. package/dist/types/src/hooks/useComputeGraph.d.ts +7 -0
  146. package/dist/types/src/hooks/useComputeGraph.d.ts.map +1 -0
  147. package/dist/types/src/hooks/useFormattingModel.d.ts +3 -0
  148. package/dist/types/src/hooks/useFormattingModel.d.ts.map +1 -0
  149. package/dist/types/src/hooks/useSheetModel.d.ts +8 -0
  150. package/dist/types/src/hooks/useSheetModel.d.ts.map +1 -0
  151. package/dist/types/src/meta.d.ts +3 -9
  152. package/dist/types/src/meta.d.ts.map +1 -1
  153. package/dist/types/src/model/decorations.d.ts +25 -0
  154. package/dist/types/src/model/decorations.d.ts.map +1 -0
  155. package/dist/types/src/model/formatting-model.d.ts +19 -0
  156. package/dist/types/src/model/formatting-model.d.ts.map +1 -0
  157. package/dist/types/src/model/index.d.ts +3 -3
  158. package/dist/types/src/model/index.d.ts.map +1 -1
  159. package/dist/types/src/model/{model.d.ts → sheet-model.d.ts} +13 -67
  160. package/dist/types/src/model/sheet-model.d.ts.map +1 -0
  161. package/dist/types/src/model/sheet-model.test.d.ts +2 -0
  162. package/dist/types/src/model/sheet-model.test.d.ts.map +1 -0
  163. package/dist/types/src/sanity.test.d.ts +2 -0
  164. package/dist/types/src/sanity.test.d.ts.map +1 -0
  165. package/dist/types/src/testing/index.d.ts +2 -0
  166. package/dist/types/src/testing/index.d.ts.map +1 -0
  167. package/dist/types/src/testing/testing.d.ts +8 -0
  168. package/dist/types/src/testing/testing.d.ts.map +1 -0
  169. package/dist/types/src/translations.d.ts +17 -12
  170. package/dist/types/src/translations.d.ts.map +1 -1
  171. package/dist/types/src/types.d.ts +98 -32
  172. package/dist/types/src/types.d.ts.map +1 -1
  173. package/dist/vendor/hyperformula.mjs +37145 -0
  174. package/package.json +57 -52
  175. package/src/SheetPlugin.tsx +52 -74
  176. package/src/components/ComputeGraph/ComputeGraphContextProvider.tsx +20 -0
  177. package/src/components/ComputeGraph/index.ts +1 -3
  178. package/src/components/FunctionEditor/FunctionEditor.tsx +45 -0
  179. package/src/components/FunctionEditor/index.ts +5 -0
  180. package/src/components/GridSheet/GridSheet.stories.tsx +41 -0
  181. package/src/components/GridSheet/GridSheet.tsx +161 -0
  182. package/src/components/{CellEditor/CellEditor.stories.tsx → GridSheet/SheetCellEditor.stories.tsx} +8 -8
  183. package/src/components/GridSheet/index.ts +5 -0
  184. package/src/components/GridSheet/util.ts +144 -0
  185. package/src/components/SheetContainer/SheetContainer.stories.tsx +40 -0
  186. package/src/components/SheetContainer/SheetContainer.tsx +52 -0
  187. package/src/components/SheetContainer/index.ts +7 -0
  188. package/src/components/SheetContext/SheetContext.tsx +108 -0
  189. package/src/components/SheetContext/index.ts +5 -0
  190. package/src/components/Toolbar/Toolbar.tsx +167 -85
  191. package/src/components/index.ts +2 -0
  192. package/src/defs/index.ts +6 -0
  193. package/src/{model → defs}/types.test.ts +8 -9
  194. package/src/{model → defs}/types.ts +24 -14
  195. package/src/defs/util.ts +151 -0
  196. package/src/extensions/compute.stories.tsx +151 -0
  197. package/src/extensions/compute.ts +147 -0
  198. package/src/{components/CellEditor → extensions/editor}/extension.test.ts +4 -6
  199. package/src/{components/CellEditor → extensions/editor}/extension.ts +5 -6
  200. package/src/{components/CellEditor → extensions/editor}/index.ts +0 -1
  201. package/src/extensions/index.ts +6 -0
  202. package/src/graph/compute-graph-registry.ts +90 -0
  203. package/src/graph/compute-graph.stories.tsx +93 -0
  204. package/src/graph/compute-graph.test.ts +87 -0
  205. package/src/graph/compute-graph.ts +242 -0
  206. package/src/graph/compute-node.ts +63 -0
  207. package/src/{components/ComputeGraph → graph/functions}/async-function.ts +25 -15
  208. package/src/{components/ComputeGraph → graph/functions}/edge-function.ts +16 -14
  209. package/src/graph/functions/index.ts +7 -0
  210. package/src/graph/hyperformula.test.ts +14 -0
  211. package/src/graph/index.ts +8 -0
  212. package/src/graph/testing/index.ts +6 -0
  213. package/src/graph/testing/test-builder.ts +54 -0
  214. package/src/{components/ComputeGraph/custom.ts → graph/testing/test-plugin.ts} +44 -14
  215. package/src/graph/util.ts +8 -0
  216. package/src/hooks/hooks.stories.tsx +50 -0
  217. package/src/hooks/index.ts +8 -0
  218. package/src/hooks/threads.ts +147 -0
  219. package/src/hooks/useComputeGraph.ts +28 -0
  220. package/src/hooks/useFormattingModel.ts +11 -0
  221. package/src/hooks/useSheetModel.ts +40 -0
  222. package/src/meta.ts +14 -0
  223. package/src/model/decorations.ts +64 -0
  224. package/src/{components/Sheet/formatting.ts → model/formatting-model.ts} +30 -20
  225. package/src/model/index.ts +3 -3
  226. package/src/model/sheet-model.test.ts +57 -0
  227. package/src/model/sheet-model.ts +418 -0
  228. package/src/sanity.test.ts +40 -0
  229. package/src/{components/Sheet → testing}/index.ts +1 -1
  230. package/src/testing/testing.tsx +68 -0
  231. package/src/translations.ts +6 -1
  232. package/src/types.ts +40 -41
  233. package/dist/lib/browser/SheetContainer-U4H5D34A.mjs +0 -1772
  234. package/dist/lib/browser/SheetContainer-U4H5D34A.mjs.map +0 -7
  235. package/dist/lib/browser/chunk-APHOLYUB.mjs +0 -175
  236. package/dist/lib/browser/chunk-APHOLYUB.mjs.map +0 -7
  237. package/dist/lib/browser/chunk-D5AGLXJP.mjs.map +0 -7
  238. package/dist/lib/browser/chunk-FUAGSXA4.mjs +0 -82
  239. package/dist/lib/browser/chunk-FUAGSXA4.mjs.map +0 -7
  240. package/dist/lib/browser/chunk-JRL5LGCE.mjs +0 -18
  241. package/dist/lib/browser/chunk-JRL5LGCE.mjs.map +0 -7
  242. package/dist/lib/browser/chunk-NU4PBN33.mjs +0 -8
  243. package/dist/lib/browser/chunk-NU4PBN33.mjs.map +0 -7
  244. package/dist/lib/browser/testing.mjs +0 -92
  245. package/dist/lib/browser/testing.mjs.map +0 -7
  246. package/dist/lib/node/SheetContainer-AXQV3ZT5.cjs +0 -1765
  247. package/dist/lib/node/SheetContainer-AXQV3ZT5.cjs.map +0 -7
  248. package/dist/lib/node/chunk-5KKJ4NPP.cjs.map +0 -7
  249. package/dist/lib/node/chunk-BJ6ZD7MN.cjs +0 -51
  250. package/dist/lib/node/chunk-BJ6ZD7MN.cjs.map +0 -7
  251. package/dist/lib/node/chunk-CN3RPESU.cjs +0 -202
  252. package/dist/lib/node/chunk-CN3RPESU.cjs.map +0 -7
  253. package/dist/lib/node/chunk-DSYKOI4E.cjs.map +0 -7
  254. package/dist/lib/node/chunk-PYXHNAAK.cjs +0 -40
  255. package/dist/lib/node/chunk-PYXHNAAK.cjs.map +0 -7
  256. package/dist/lib/node/testing.cjs +0 -111
  257. package/dist/lib/node/testing.cjs.map +0 -7
  258. package/dist/types/src/components/CellEditor/CellEditor.d.ts +0 -14
  259. package/dist/types/src/components/CellEditor/CellEditor.d.ts.map +0 -1
  260. package/dist/types/src/components/CellEditor/CellEditor.stories.d.ts.map +0 -1
  261. package/dist/types/src/components/CellEditor/extension.d.ts.map +0 -1
  262. package/dist/types/src/components/CellEditor/extension.test.d.ts.map +0 -1
  263. package/dist/types/src/components/CellEditor/index.d.ts +0 -3
  264. package/dist/types/src/components/CellEditor/index.d.ts.map +0 -1
  265. package/dist/types/src/components/ComputeGraph/async-function.d.ts.map +0 -1
  266. package/dist/types/src/components/ComputeGraph/custom.d.ts +0 -21
  267. package/dist/types/src/components/ComputeGraph/custom.d.ts.map +0 -1
  268. package/dist/types/src/components/ComputeGraph/edge-function.d.ts +0 -20
  269. package/dist/types/src/components/ComputeGraph/edge-function.d.ts.map +0 -1
  270. package/dist/types/src/components/ComputeGraph/graph-context.d.ts +0 -12
  271. package/dist/types/src/components/ComputeGraph/graph-context.d.ts.map +0 -1
  272. package/dist/types/src/components/ComputeGraph/graph.browser.test.d.ts +0 -2
  273. package/dist/types/src/components/ComputeGraph/graph.browser.test.d.ts.map +0 -1
  274. package/dist/types/src/components/ComputeGraph/graph.d.ts +0 -26
  275. package/dist/types/src/components/ComputeGraph/graph.d.ts.map +0 -1
  276. package/dist/types/src/components/Sheet/Sheet.d.ts +0 -55
  277. package/dist/types/src/components/Sheet/Sheet.d.ts.map +0 -1
  278. package/dist/types/src/components/Sheet/Sheet.stories.d.ts +0 -54
  279. package/dist/types/src/components/Sheet/Sheet.stories.d.ts.map +0 -1
  280. package/dist/types/src/components/Sheet/formatting.d.ts +0 -14
  281. package/dist/types/src/components/Sheet/formatting.d.ts.map +0 -1
  282. package/dist/types/src/components/Sheet/grid.d.ts +0 -52
  283. package/dist/types/src/components/Sheet/grid.d.ts.map +0 -1
  284. package/dist/types/src/components/Sheet/index.d.ts +0 -2
  285. package/dist/types/src/components/Sheet/index.d.ts.map +0 -1
  286. package/dist/types/src/components/Sheet/nav.d.ts +0 -29
  287. package/dist/types/src/components/Sheet/nav.d.ts.map +0 -1
  288. package/dist/types/src/components/Sheet/sheet-context.d.ts +0 -25
  289. package/dist/types/src/components/Sheet/sheet-context.d.ts.map +0 -1
  290. package/dist/types/src/components/Sheet/util.d.ts +0 -18
  291. package/dist/types/src/components/Sheet/util.d.ts.map +0 -1
  292. package/dist/types/src/components/SheetContainer.d.ts +0 -9
  293. package/dist/types/src/components/SheetContainer.d.ts.map +0 -1
  294. package/dist/types/src/components/Toolbar/common.d.ts +0 -20
  295. package/dist/types/src/components/Toolbar/common.d.ts.map +0 -1
  296. package/dist/types/src/model/functions.d.ts.map +0 -1
  297. package/dist/types/src/model/model.browser.test.d.ts +0 -2
  298. package/dist/types/src/model/model.browser.test.d.ts.map +0 -1
  299. package/dist/types/src/model/model.d.ts.map +0 -1
  300. package/dist/types/src/model/types.d.ts.map +0 -1
  301. package/dist/types/src/model/types.test.d.ts.map +0 -1
  302. package/dist/types/src/model/util.d.ts +0 -15
  303. package/dist/types/src/model/util.d.ts.map +0 -1
  304. package/dist/types/src/testing.d.ts +0 -9
  305. package/dist/types/src/testing.d.ts.map +0 -1
  306. package/src/components/CellEditor/CellEditor.tsx +0 -113
  307. package/src/components/ComputeGraph/graph-context.tsx +0 -50
  308. package/src/components/ComputeGraph/graph.browser.test.ts +0 -50
  309. package/src/components/ComputeGraph/graph.ts +0 -62
  310. package/src/components/Sheet/Sheet.stories.tsx +0 -287
  311. package/src/components/Sheet/Sheet.tsx +0 -1160
  312. package/src/components/Sheet/grid.ts +0 -191
  313. package/src/components/Sheet/nav.ts +0 -157
  314. package/src/components/Sheet/sheet-context.tsx +0 -150
  315. package/src/components/Sheet/util.ts +0 -56
  316. package/src/components/SheetContainer.tsx +0 -34
  317. package/src/components/Toolbar/common.tsx +0 -72
  318. package/src/meta.tsx +0 -18
  319. package/src/model/model.browser.test.ts +0 -100
  320. package/src/model/model.ts +0 -550
  321. package/src/model/util.ts +0 -36
  322. package/src/testing.ts +0 -50
  323. /package/dist/types/src/{model → defs}/types.test.d.ts +0 -0
  324. /package/dist/types/src/{components/CellEditor → extensions/editor}/extension.test.d.ts +0 -0
  325. /package/src/{model/functions.ts → graph/functions/function-defs.ts} +0 -0
@@ -2,71 +2,130 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import {
6
- type Icon,
7
- Calendar,
8
- ChatText,
9
- CurrencyDollar,
10
- Eraser,
11
- HighlighterCircle,
12
- TextAlignCenter,
13
- TextAlignLeft,
14
- TextAlignRight,
15
- } from '@phosphor-icons/react';
16
5
  import { createContext } from '@radix-ui/react-context';
17
6
  import React, { type PropsWithChildren } from 'react';
18
7
 
19
8
  import {
20
- DensityProvider,
21
- ElevationProvider,
9
+ Icon,
22
10
  Toolbar as NaturalToolbar,
23
- type ThemedClassName,
24
11
  useTranslation,
12
+ Tooltip,
13
+ type ToolbarToggleGroupItemProps as NaturalToolbarToggleGroupItemProps,
14
+ type ToolbarButtonProps as NaturalToolbarButtonProps,
15
+ type ToolbarToggleProps as NaturalToolbarToggleProps,
16
+ type ThemedClassName,
25
17
  } from '@dxos/react-ui';
18
+ import { useAttention } from '@dxos/react-ui-attention';
19
+ import { nonNullable } from '@dxos/util';
26
20
 
27
- import { ToolbarButton, ToolbarSeparator, ToolbarToggleButton } from './common';
21
+ import { addressToIndex } from '../../defs';
28
22
  import { SHEET_PLUGIN } from '../../meta';
29
23
  import { type Formatting } from '../../types';
24
+ import { useSheetContext } from '../SheetContext';
30
25
 
31
26
  //
32
- // Root
27
+ // Buttons
28
+ //
29
+
30
+ const buttonStyles = 'min-bs-0 p-2';
31
+ const tooltipProps = { side: 'bottom' as const, classNames: 'z-10' };
32
+
33
+ const ToolbarSeparator = () => <div role='separator' className='grow' />;
34
+
35
+ //
36
+ // ToolbarItem
33
37
  //
34
38
 
35
- export type ToolbarActionType = 'clear' | 'highlight' | 'left' | 'center' | 'right' | 'date' | 'currency';
39
+ type ToolbarItemProps =
40
+ | (NaturalToolbarButtonProps & { itemType: 'button'; icon: string })
41
+ | (NaturalToolbarToggleGroupItemProps & { itemType: 'toggleGroupItem'; icon: string })
42
+ | (NaturalToolbarToggleProps & { itemType: 'toggle'; icon: string });
36
43
 
37
- export type ToolbarAction = {
38
- type: ToolbarActionType;
44
+ export const ToolbarItem = ({ itemType, icon, children, ...props }: ToolbarItemProps) => {
45
+ const Invoker =
46
+ itemType === 'toggleGroupItem'
47
+ ? NaturalToolbar.ToggleGroupItem
48
+ : itemType === 'toggle'
49
+ ? NaturalToolbar.Toggle
50
+ : NaturalToolbar.Button;
51
+ return (
52
+ <Tooltip.Root>
53
+ <Tooltip.Trigger asChild>
54
+ {/* TODO(thure): type the props spread better. */}
55
+ <Invoker variant='ghost' {...(props as any)} classNames={buttonStyles}>
56
+ <Icon icon={icon} size={5} />
57
+ <span className='sr-only'>{children}</span>
58
+ </Invoker>
59
+ </Tooltip.Trigger>
60
+ <Tooltip.Portal>
61
+ <Tooltip.Content {...tooltipProps}>
62
+ {children}
63
+ <Tooltip.Arrow />
64
+ </Tooltip.Content>
65
+ </Tooltip.Portal>
66
+ </Tooltip.Root>
67
+ );
39
68
  };
40
69
 
41
- export type ToolbarActionHandler = ({ type }: ToolbarAction) => void;
70
+ //
71
+ // Root
72
+ //
73
+
74
+ type AlignValue = 'left' | 'center' | 'right' | 'unset';
75
+ type AlignAction = { type: 'align'; value: AlignValue };
76
+
77
+ type CommentAction = { type: 'comment'; anchor: string; cellContent?: string };
78
+
79
+ type FormatValue = 'date' | 'currency' | 'unset';
80
+ type FormatAction = { type: 'format'; value: FormatValue };
81
+
82
+ type StyleValue = 'highlight' | 'unset';
83
+ type StyleAction = { type: 'style'; value: StyleValue };
84
+
85
+ export type ToolbarAction = StyleAction | AlignAction | FormatAction | CommentAction;
86
+
87
+ export type ToolbarActionType = ToolbarAction['type'];
88
+
89
+ export type ToolbarActionHandler = (action: ToolbarAction) => void;
42
90
 
43
91
  export type ToolbarProps = ThemedClassName<
44
92
  PropsWithChildren<{
45
93
  onAction?: ToolbarActionHandler;
94
+ role?: string;
46
95
  }>
47
96
  >;
48
97
 
49
98
  const [ToolbarContextProvider, useToolbarContext] = createContext<ToolbarProps>('Toolbar');
50
99
 
51
- const ToolbarRoot = ({ children, onAction, classNames }: ToolbarProps) => {
100
+ // TODO(Zan): Factor out, copied this from MarkdownPlugin.
101
+ const sectionToolbarLayout =
102
+ 'bs-[--rail-action] bg-[--sticky-bg] sticky block-start-0 __-block-start-px transition-opacity';
103
+
104
+ const ToolbarRoot = ({ children, onAction, role, classNames }: ToolbarProps) => {
105
+ const { id } = useSheetContext();
106
+ const { hasAttention } = useAttention(id);
107
+
52
108
  return (
53
109
  <ToolbarContextProvider onAction={onAction}>
54
- <DensityProvider density='fine'>
55
- <ElevationProvider elevation='chrome'>
56
- <NaturalToolbar.Root classNames={['is-full shrink-0 overflow-x-auto overflow-y-hidden p-1', classNames]}>
57
- {children}
58
- </NaturalToolbar.Root>
59
- </ElevationProvider>
60
- </DensityProvider>
110
+ <NaturalToolbar.Root
111
+ classNames={[
112
+ ...(role === 'section'
113
+ ? ['z-[2] group-focus-within/section:visible', !hasAttention && 'invisible', sectionToolbarLayout]
114
+ : ['attention-surface']),
115
+ classNames,
116
+ ]}
117
+ >
118
+ {children}
119
+ </NaturalToolbar.Root>
61
120
  </ToolbarContextProvider>
62
121
  );
63
122
  };
64
123
 
65
124
  // TODO(burdon): Generalize.
66
125
  // TODO(burdon): Detect and display current state.
67
- type ButtonProps = {
68
- type: ToolbarActionType;
69
- Icon: Icon;
126
+ type ButtonProps<T> = {
127
+ value: T;
128
+ icon: string;
70
129
  getState: (state: Formatting) => boolean;
71
130
  disabled?: (state: Formatting) => boolean;
72
131
  };
@@ -75,9 +134,9 @@ type ButtonProps = {
75
134
  // Alignment
76
135
  //
77
136
 
78
- const formatOptions: ButtonProps[] = [
79
- { type: 'date', Icon: Calendar, getState: (state) => false },
80
- { type: 'currency', Icon: CurrencyDollar, getState: (state) => false },
137
+ const formatOptions: ButtonProps<FormatValue>[] = [
138
+ { value: 'date', icon: 'ph--calendar--regular', getState: (state) => false },
139
+ { value: 'currency', icon: 'ph--currency-dollar--regular', getState: (state) => false },
81
140
  ];
82
141
 
83
142
  const Format = () => {
@@ -89,26 +148,25 @@ const Format = () => {
89
148
  type='single'
90
149
  // value={cellStyles.filter(({ getState }) => state && getState(state)).map(({ type }) => type)}
91
150
  >
92
- {formatOptions.map(({ type, getState, Icon }) => (
93
- <ToolbarToggleButton
94
- key={type}
95
- value={type}
96
- Icon={Icon}
97
- // disabled={state?.blockType === 'codeblock'}
98
- // onClick={state ? () => onAction?.({ type, data: !getState(state) }) : undefined}
99
- onClick={() => onAction?.({ type })}
151
+ {formatOptions.map(({ value, getState, icon }) => (
152
+ <ToolbarItem
153
+ itemType='toggleGroupItem'
154
+ key={value}
155
+ value={value}
156
+ icon={icon}
157
+ onClick={() => onAction?.({ type: 'format', value })}
100
158
  >
101
- {t(`toolbar ${type} label`)}
102
- </ToolbarToggleButton>
159
+ {t(`toolbar ${value} label`)}
160
+ </ToolbarItem>
103
161
  ))}
104
162
  </NaturalToolbar.ToggleGroup>
105
163
  );
106
164
  };
107
165
 
108
- const alignmentOptions: ButtonProps[] = [
109
- { type: 'left', Icon: TextAlignLeft, getState: (state) => false },
110
- { type: 'center', Icon: TextAlignCenter, getState: (state) => false },
111
- { type: 'right', Icon: TextAlignRight, getState: (state) => false },
166
+ const alignmentOptions: ButtonProps<AlignValue>[] = [
167
+ { value: 'left', icon: 'ph--text-align-left--regular', getState: (state) => false },
168
+ { value: 'center', icon: 'ph--text-align-center--regular', getState: (state) => false },
169
+ { value: 'right', icon: 'ph--text-align-right--regular', getState: (state) => false },
112
170
  ];
113
171
 
114
172
  const Alignment = () => {
@@ -119,50 +177,41 @@ const Alignment = () => {
119
177
  <NaturalToolbar.ToggleGroup
120
178
  type='single'
121
179
  // value={cellStyles.filter(({ getState }) => state && getState(state)).map(({ type }) => type)}
180
+ // disabled={state?.blockType === 'codeblock'}
181
+ onValueChange={(value: AlignValue) => onAction?.({ type: 'align', value })}
122
182
  >
123
- {alignmentOptions.map(({ type, getState, Icon }) => (
124
- <ToolbarToggleButton
125
- key={type}
126
- value={type}
127
- Icon={Icon}
128
- // disabled={state?.blockType === 'codeblock'}
129
- // onClick={state ? () => onAction?.({ type, data: !getState(state) }) : undefined}
130
- onClick={() => onAction?.({ type })}
131
- >
132
- {t(`toolbar ${type} label`)}
133
- </ToolbarToggleButton>
183
+ {alignmentOptions.map(({ value, getState, icon }) => (
184
+ <ToolbarItem itemType='toggleGroupItem' key={value} value={value} icon={icon}>
185
+ {t(`toolbar ${value} label`)}
186
+ </ToolbarItem>
134
187
  ))}
135
188
  </NaturalToolbar.ToggleGroup>
136
189
  );
137
190
  };
138
191
 
139
- const styleOptions: ButtonProps[] = [
140
- { type: 'clear', Icon: Eraser, getState: (state) => false },
141
- { type: 'highlight', Icon: HighlighterCircle, getState: (state) => false },
192
+ const styleOptions: ButtonProps<StyleValue>[] = [
193
+ { value: 'highlight', icon: 'ph--highlighter--regular', getState: (state) => false },
142
194
  ];
143
195
 
144
196
  const Styles = () => {
145
- const { onAction } = useToolbarContext('Alignment');
197
+ const { onAction } = useToolbarContext('Styles');
146
198
  const { t } = useTranslation(SHEET_PLUGIN);
147
199
 
148
200
  return (
149
- <NaturalToolbar.ToggleGroup
150
- type='single'
151
- // value={cellStyles.filter(({ getState }) => state && getState(state)).map(({ type }) => type)}
152
- >
153
- {styleOptions.map(({ type, getState, Icon }) => (
154
- <ToolbarToggleButton
155
- key={type}
156
- value={type}
157
- Icon={Icon}
158
- // disabled={state?.blockType === 'codeblock'}
159
- // onClick={state ? () => onAction?.({ type, data: !getState(state) }) : undefined}
160
- onClick={() => onAction?.({ type })}
201
+ <>
202
+ {styleOptions.map(({ value, getState, icon }) => (
203
+ <ToolbarItem
204
+ itemType='toggle'
205
+ key={value}
206
+ onPressedChange={(nextPressed: boolean) =>
207
+ onAction?.({ type: 'style', value: nextPressed ? 'highlight' : 'unset' })
208
+ }
209
+ icon={icon}
161
210
  >
162
- {t(`toolbar ${type} label`)}
163
- </ToolbarToggleButton>
211
+ {t(`toolbar ${value} label`)}
212
+ </ToolbarItem>
164
213
  ))}
165
- </NaturalToolbar.ToggleGroup>
214
+ </>
166
215
  );
167
216
  };
168
217
 
@@ -171,18 +220,51 @@ const Styles = () => {
171
220
  //
172
221
 
173
222
  const Actions = () => {
174
- // const { onAction } = useToolbarContext('Actions');
223
+ const { onAction } = useToolbarContext('Actions');
224
+ const { cursor, range, model } = useSheetContext();
175
225
  const { t } = useTranslation(SHEET_PLUGIN);
226
+
227
+ const overlapsCommentAnchor = (model.sheet.threads ?? [])
228
+ .filter(nonNullable)
229
+ .filter((thread) => thread.status !== 'resolved')
230
+ .some((thread) => {
231
+ if (!cursor) {
232
+ return false;
233
+ }
234
+ return addressToIndex(model.sheet, cursor) === thread.anchor;
235
+ });
236
+
237
+ const hasCursor = !!cursor;
238
+ const cursorOnly = hasCursor && !range && !overlapsCommentAnchor;
239
+
240
+ const tooltipLabelKey = !hasCursor
241
+ ? 'no cursor label'
242
+ : overlapsCommentAnchor
243
+ ? 'selection overlaps existing comment label'
244
+ : range
245
+ ? 'comment ranges not supported label'
246
+ : 'comment label';
247
+
176
248
  return (
177
- <ToolbarButton
249
+ <ToolbarItem
250
+ itemType='button'
178
251
  value='comment'
179
- Icon={ChatText}
252
+ icon='ph--chat-text--regular'
180
253
  data-testid='editor.toolbar.comment'
181
- // onClick={() => onAction?.({ type: 'comment' })}
182
- // disabled={!state || state.comment || !state.selection}
254
+ onClick={() => {
255
+ if (!cursor) {
256
+ return;
257
+ }
258
+ return onAction?.({
259
+ type: 'comment',
260
+ anchor: addressToIndex(model.sheet, cursor),
261
+ cellContent: model.getCellText(cursor),
262
+ });
263
+ }}
264
+ disabled={!cursorOnly || overlapsCommentAnchor}
183
265
  >
184
- {t('comment label')}
185
- </ToolbarButton>
266
+ {t(tooltipLabelKey)}
267
+ </ToolbarItem>
186
268
  );
187
269
  };
188
270
 
@@ -5,6 +5,8 @@
5
5
  import React from 'react';
6
6
 
7
7
  export * from './ComputeGraph';
8
+ export * from './GridSheet';
9
+ export * from './SheetContext';
8
10
 
9
11
  // Lazily load components for content surfaces.
10
12
  export const SheetContainer = React.lazy(() => import('./SheetContainer'));
@@ -0,0 +1,6 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ export * from './types';
6
+ export * from './util';
@@ -3,15 +3,14 @@
3
3
  //
4
4
 
5
5
  import { getIndices, sortByIndex, getIndicesBelow, getIndicesAbove, getIndicesBetween } from '@tldraw/indices';
6
- import { expect } from 'chai';
7
- import { describe, test } from 'vitest';
6
+ import { describe, expect, test } from 'vitest';
8
7
 
9
8
  import { inRange, addressFromA1Notation, addressToA1Notation, rangeFromA1Notation, rangeToA1Notation } from './types';
10
9
 
11
10
  describe('cell', () => {
12
11
  test('posToA1Notation', () => {
13
- expect(addressToA1Notation({ column: 0, row: 0 })).to.eq('A1');
14
- expect(addressFromA1Notation('C2')).to.deep.eq({ column: 2, row: 1 });
12
+ expect(addressToA1Notation({ col: 0, row: 0 })).to.eq('A1');
13
+ expect(addressFromA1Notation('C2')).to.deep.eq({ col: 2, row: 1 });
15
14
  });
16
15
 
17
16
  test('rangeToA1Notation', () => {
@@ -56,19 +55,19 @@ describe('cell', () => {
56
55
  // Values.
57
56
  const cells: Record<string, any> = {};
58
57
  const setCell = (cell: string, value: any) => {
59
- const { column, row } = addressFromA1Notation(cell);
58
+ const { col, row } = addressFromA1Notation(cell);
60
59
  // Reallocate if > current bounds.
61
- if (column >= columns.length) {
62
- insertIndex(columns, column);
60
+ if (col >= columns.length) {
61
+ insertIndex(columns, col);
63
62
  }
64
63
  if (row >= rows.length) {
65
64
  insertIndex(rows, row);
66
65
  }
67
- const index = `${columns[column]}@${rows[row]}`;
66
+ const index = `${columns[col]}@${rows[row]}`;
68
67
  cells[index] = value;
69
68
  };
70
69
 
71
- expect(addressFromA1Notation('A1')).to.deep.eq({ column: 0, row: 0 });
70
+ expect(addressFromA1Notation('A1')).to.deep.eq({ col: 0, row: 0 });
72
71
 
73
72
  expect(columns).to.deep.eq(['a1', 'a2', 'a3', 'a4', 'a5']);
74
73
  insertIndex(columns, 7);
@@ -4,33 +4,43 @@
4
4
 
5
5
  import { invariant } from '@dxos/invariant';
6
6
 
7
- export const MAX_COLUMNS = 26 * 26;
7
+ export const DEFAULT_ROWS = 50;
8
+ export const DEFAULT_COLUMNS = 26;
9
+
10
+ export const MAX_ROWS = 500;
11
+ export const MAX_COLUMNS = 26 * 2;
12
+
13
+ export type CellAddress = { col: number; row: number };
8
14
 
9
- export type CellAddress = { column: number; row: number };
10
15
  export type CellRange = { from: CellAddress; to?: CellAddress };
11
16
 
17
+ export type CellIndex = string;
18
+
19
+ export type CellContentValue = number | string | boolean | null;
20
+
12
21
  export const posEquals = (a: CellAddress | undefined, b: CellAddress | undefined) => {
13
- return a?.column === b?.column && a?.row === b?.row;
22
+ return a?.col === b?.col && a?.row === b?.row;
14
23
  };
15
24
 
16
- export const columnLetter = (column: number): string => {
17
- invariant(column < MAX_COLUMNS, `Invalid column: ${column}`);
25
+ export const columnLetter = (col: number): string => {
26
+ invariant(col < MAX_COLUMNS, `Invalid column: ${col}`);
18
27
  return (
19
- (column >= 26 ? String.fromCharCode('A'.charCodeAt(0) + Math.floor(column / 26) - 1) : '') +
20
- String.fromCharCode('A'.charCodeAt(0) + (column % 26))
28
+ (col >= 26 ? String.fromCharCode('A'.charCodeAt(0) + Math.floor(col / 26) - 1) : '') +
29
+ String.fromCharCode('A'.charCodeAt(0) + (col % 26))
21
30
  );
22
31
  };
23
32
 
24
- export const addressToA1Notation = ({ column, row }: CellAddress): string => {
25
- return `${columnLetter(column)}${row + 1}`;
33
+ export const addressToA1Notation = ({ col, row }: CellAddress): string => {
34
+ return `${columnLetter(col)}${row + 1}`;
26
35
  };
27
36
 
37
+ // TODO(burdon): See simpleCellAddressFromString
28
38
  export const addressFromA1Notation = (ref: string): CellAddress => {
29
39
  const match = ref.match(/([A-Z]+)(\d+)/);
30
40
  invariant(match, `Invalid notation: ${ref}`);
31
41
  return {
32
42
  row: parseInt(match[2], 10) - 1,
33
- column: match[1].split('').reduce((acc, c) => acc * 26 + c.charCodeAt(0) - 'A'.charCodeAt(0) + 1, 0) - 1,
43
+ col: match[1].split('').reduce((acc, c) => acc * 26 + c.charCodeAt(0) - 'A'.charCodeAt(0) + 1, 0) - 1,
34
44
  };
35
45
  };
36
46
 
@@ -59,13 +69,13 @@ export const inRange = (range: CellRange | undefined, cell: CellAddress): boolea
59
69
  return false;
60
70
  }
61
71
 
62
- const { column: c1, row: r1 } = from;
63
- const { column: c2, row: r2 } = to;
72
+ const { col: c1, row: r1 } = from;
73
+ const { col: c2, row: r2 } = to;
64
74
  const cMin = Math.min(c1, c2);
65
75
  const cMax = Math.max(c1, c2);
66
76
  const rMin = Math.min(r1, r2);
67
77
  const rMax = Math.max(r1, r2);
68
78
 
69
- const { column, row } = cell;
70
- return column >= cMin && column <= cMax && row >= rMin && row <= rMax;
79
+ const { col, row } = cell;
80
+ return col >= cMin && col <= cMax && row >= rMin && row <= rMax;
71
81
  };
@@ -0,0 +1,151 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import { randomBytes } from '@dxos/crypto';
6
+ import { create } from '@dxos/echo-schema';
7
+
8
+ import {
9
+ addressFromA1Notation,
10
+ type CellAddress,
11
+ type CellRange,
12
+ DEFAULT_COLUMNS,
13
+ DEFAULT_ROWS,
14
+ MAX_COLUMNS,
15
+ MAX_ROWS,
16
+ } from './types';
17
+ import { type CreateSheetOptions, type SheetSize, SheetType } from '../types';
18
+
19
+ // TODO(burdon): Factor out from dxos/protocols to new common package.
20
+ export class ApiError extends Error {}
21
+
22
+ export class ReadonlyException extends ApiError {}
23
+
24
+ export class RangeException extends ApiError {
25
+ constructor(n: number) {
26
+ super();
27
+ }
28
+ }
29
+
30
+ /**
31
+ * With a string length of 8, the chance of a collision is 0.02% for a sheet with 10,000 strings.
32
+ */
33
+ export const createIndex = (length = 8): string => {
34
+ const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
35
+ const charactersLength = characters.length;
36
+ const randomBuffer = randomBytes(length);
37
+ return Array.from(randomBuffer, (byte) => characters[byte % charactersLength]).join('');
38
+ };
39
+
40
+ export const createIndices = (length: number): string[] => Array.from({ length }).map(() => createIndex());
41
+
42
+ export const insertIndices = (indices: string[], i: number, n: number, max: number) => {
43
+ if (i + n > max) {
44
+ throw new RangeException(i + n);
45
+ }
46
+
47
+ const idx = createIndices(n);
48
+ indices.splice(i, 0, ...idx);
49
+ };
50
+
51
+ export const initialize = (
52
+ sheet: SheetType,
53
+ { rows = DEFAULT_ROWS, columns = DEFAULT_COLUMNS }: Partial<SheetSize> = {},
54
+ ) => {
55
+ if (!sheet.rows.length) {
56
+ insertIndices(sheet.rows, 0, rows, MAX_ROWS);
57
+ }
58
+ if (!sheet.columns.length) {
59
+ insertIndices(sheet.columns, 0, columns, MAX_COLUMNS);
60
+ }
61
+ };
62
+
63
+ export const createSheet = ({ name, cells, ...size }: CreateSheetOptions = {}): SheetType => {
64
+ const sheet = create(SheetType, {
65
+ name,
66
+ cells: {},
67
+ rows: [],
68
+ columns: [],
69
+ rowMeta: {},
70
+ columnMeta: {},
71
+ formatting: [],
72
+ });
73
+
74
+ initialize(sheet, size);
75
+
76
+ if (cells) {
77
+ Object.entries(cells).forEach(([key, { value }]) => {
78
+ const idx = addressToIndex(sheet, addressFromA1Notation(key));
79
+ sheet.cells[idx] = { value };
80
+ });
81
+ }
82
+
83
+ return sheet;
84
+ };
85
+
86
+ /**
87
+ * E.g., "A1" => "CA2@CB3".
88
+ */
89
+ export const addressToIndex = (sheet: SheetType, cell: CellAddress): string => {
90
+ return `${sheet.columns[cell.col]}@${sheet.rows[cell.row]}`;
91
+ };
92
+
93
+ /**
94
+ * E.g., "CA2@CB3" => "A1".
95
+ */
96
+ export const addressFromIndex = (sheet: SheetType, idx: string): CellAddress => {
97
+ const [column, row] = idx.split('@');
98
+ return {
99
+ col: sheet.columns.indexOf(column),
100
+ row: sheet.rows.indexOf(row),
101
+ };
102
+ };
103
+
104
+ /**
105
+ * E.g., "A1:B2" => "CA2@CB3:CC4@CD5".
106
+ */
107
+ export const rangeToIndex = (sheet: SheetType, range: CellRange): string => {
108
+ return [range.from, range.to ?? range.from].map((cell) => addressToIndex(sheet, cell)).join(':');
109
+ };
110
+
111
+ /**
112
+ * E.g., "CA2@CB3:CC4@CD5" => "A1:B2".
113
+ */
114
+ export const rangeFromIndex = (sheet: SheetType, idx: string): CellRange => {
115
+ const [from, to] = idx.split(':').map((index) => addressFromIndex(sheet, index));
116
+ return { from, to };
117
+ };
118
+
119
+ /**
120
+ * Find closest cell to cursor.
121
+ */
122
+ export const closest = (cursor: CellAddress, cells: CellAddress[]): CellAddress | undefined => {
123
+ let closestCell: CellAddress | undefined;
124
+ let closestDistance = Number.MAX_SAFE_INTEGER;
125
+
126
+ for (const cell of cells) {
127
+ const distance = Math.abs(cell.row - cursor.row) + Math.abs(cell.col - cursor.col);
128
+ if (distance < closestDistance) {
129
+ closestCell = cell;
130
+ closestDistance = distance;
131
+ }
132
+ }
133
+
134
+ return closestCell;
135
+ };
136
+
137
+ /**
138
+ * Compares the positions of two cell indexes in a sheet.
139
+ * Sorts primarily by row, then by column if rows are equal.
140
+ */
141
+ export const compareIndexPositions = (sheet: SheetType, indexA: string, indexB: string): number => {
142
+ const { row: rowA, col: columnA } = addressFromIndex(sheet, indexA);
143
+ const { row: rowB, col: columnB } = addressFromIndex(sheet, indexB);
144
+
145
+ // Sort by row first, then by column.
146
+ if (rowA !== rowB) {
147
+ return rowA - rowB;
148
+ } else {
149
+ return columnA - columnB;
150
+ }
151
+ };