@dxos/plugin-sheet 0.6.12-main.5cc132e → 0.6.12-main.7907542

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 (273) hide show
  1. package/dist/lib/browser/SheetContainer-T2QWJOFD.mjs +262 -0
  2. package/dist/lib/browser/SheetContainer-T2QWJOFD.mjs.map +7 -0
  3. package/dist/lib/browser/{chunk-WUPTZUTX.mjs → chunk-5ZMVZYGB.mjs} +21 -19
  4. package/dist/lib/browser/chunk-5ZMVZYGB.mjs.map +7 -0
  5. package/dist/lib/browser/{chunk-GNNVBNCX.mjs → chunk-GSV5QNLD.mjs} +409 -686
  6. package/dist/lib/browser/chunk-GSV5QNLD.mjs.map +7 -0
  7. package/dist/lib/browser/{chunk-JRL5LGCE.mjs → chunk-QILRZNE5.mjs} +2 -5
  8. package/dist/lib/browser/chunk-QILRZNE5.mjs.map +7 -0
  9. package/dist/lib/browser/{SheetContainer-Y7ZMFBAP.mjs → chunk-ZL2V5UJR.mjs} +982 -508
  10. package/dist/lib/browser/chunk-ZL2V5UJR.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 +86 -59
  14. package/dist/lib/browser/index.mjs.map +4 -4
  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 -6
  18. package/dist/lib/node/SheetContainer-PV5ET4UJ.cjs +280 -0
  19. package/dist/lib/node/SheetContainer-PV5ET4UJ.cjs.map +7 -0
  20. package/dist/lib/node/{SheetContainer-KEOKUKAQ.cjs → chunk-2K53Z2TU.cjs} +1036 -558
  21. package/dist/lib/node/chunk-2K53Z2TU.cjs.map +7 -0
  22. package/dist/lib/node/{chunk-ZRQZFV5T.cjs → chunk-5XPK2V4A.cjs} +418 -691
  23. package/dist/lib/node/chunk-5XPK2V4A.cjs.map +7 -0
  24. package/dist/lib/node/{chunk-BJ6ZD7MN.cjs → chunk-BNARJ5GM.cjs} +5 -18
  25. package/dist/lib/node/chunk-BNARJ5GM.cjs.map +7 -0
  26. package/dist/lib/node/{chunk-VJU3NPUJ.cjs → chunk-STAVQ2JE.cjs} +25 -24
  27. package/dist/lib/node/chunk-STAVQ2JE.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 +98 -66
  31. package/dist/lib/node/index.cjs.map +4 -4
  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 +10 -12
  36. package/dist/lib/node/types.cjs.map +2 -2
  37. package/dist/lib/node-esm/SheetContainer-FOZD2WLT.mjs +263 -0
  38. package/dist/lib/node-esm/SheetContainer-FOZD2WLT.mjs.map +7 -0
  39. package/dist/lib/node-esm/{chunk-WUPTZUTX.mjs → chunk-2HAM45RC.mjs} +22 -19
  40. package/dist/lib/node-esm/chunk-2HAM45RC.mjs.map +7 -0
  41. package/dist/lib/node-esm/{chunk-GNNVBNCX.mjs → chunk-5WPZCXNS.mjs} +411 -686
  42. package/dist/lib/node-esm/chunk-5WPZCXNS.mjs.map +7 -0
  43. package/dist/lib/node-esm/{chunk-JRL5LGCE.mjs → chunk-IU2L277A.mjs} +4 -5
  44. package/dist/lib/node-esm/chunk-IU2L277A.mjs.map +7 -0
  45. package/dist/lib/node-esm/{SheetContainer-Y7ZMFBAP.mjs → chunk-QEUCIHIN.mjs} +983 -508
  46. package/dist/lib/node-esm/chunk-QEUCIHIN.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 +87 -59
  50. package/dist/lib/node-esm/index.mjs.map +4 -4
  51. package/dist/lib/node-esm/meta.json +1 -1
  52. package/dist/lib/node-esm/meta.mjs +2 -1
  53. package/dist/lib/node-esm/types.mjs +5 -6
  54. package/dist/types/src/SheetPlugin.d.ts.map +1 -1
  55. package/dist/types/src/components/CellEditor/CellEditor.d.ts +23 -3
  56. package/dist/types/src/components/CellEditor/CellEditor.d.ts.map +1 -1
  57. package/dist/types/src/components/CellEditor/CellEditor.stories.d.ts +2 -2
  58. package/dist/types/src/components/CellEditor/CellEditor.stories.d.ts.map +1 -1
  59. package/dist/types/src/components/CellEditor/extension.d.ts +1 -1
  60. package/dist/types/src/components/CellEditor/extension.d.ts.map +1 -1
  61. package/dist/types/src/components/ComputeGraph/ComputeGraphContextProvider.d.ts +11 -0
  62. package/dist/types/src/components/ComputeGraph/ComputeGraphContextProvider.d.ts.map +1 -0
  63. package/dist/types/src/components/ComputeGraph/index.d.ts +1 -3
  64. package/dist/types/src/components/ComputeGraph/index.d.ts.map +1 -1
  65. package/dist/types/src/components/GridSheet/GridSheet.d.ts +10 -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/GridSheet/util.d.ts +16 -0
  70. package/dist/types/src/components/GridSheet/util.d.ts.map +1 -0
  71. package/dist/types/src/components/Sheet/Sheet.d.ts +1 -1
  72. package/dist/types/src/components/Sheet/Sheet.d.ts.map +1 -1
  73. package/dist/types/src/components/Sheet/Sheet.stories.d.ts +5 -6
  74. package/dist/types/src/components/Sheet/Sheet.stories.d.ts.map +1 -1
  75. package/dist/types/src/components/Sheet/grid.d.ts +2 -2
  76. package/dist/types/src/components/Sheet/grid.d.ts.map +1 -1
  77. package/dist/types/src/components/Sheet/nav.d.ts +3 -3
  78. package/dist/types/src/components/Sheet/nav.d.ts.map +1 -1
  79. package/dist/types/src/components/Sheet/sheet-context.d.ts +6 -7
  80. package/dist/types/src/components/Sheet/sheet-context.d.ts.map +1 -1
  81. package/dist/types/src/components/Sheet/threads.d.ts.map +1 -1
  82. package/dist/types/src/components/SheetContainer.d.ts +1 -1
  83. package/dist/types/src/components/SheetContainer.d.ts.map +1 -1
  84. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -1
  85. package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts +1 -1
  86. package/dist/types/src/components/index.d.ts +2 -1
  87. package/dist/types/src/components/index.d.ts.map +1 -1
  88. package/dist/types/src/defs/index.d.ts +3 -0
  89. package/dist/types/src/defs/index.d.ts.map +1 -0
  90. package/dist/types/src/{model → defs}/types.d.ts +8 -3
  91. package/dist/types/src/defs/types.d.ts.map +1 -0
  92. package/dist/types/src/defs/types.test.d.ts.map +1 -0
  93. package/dist/types/src/{model → defs}/util.d.ts +8 -4
  94. package/dist/types/src/defs/util.d.ts.map +1 -0
  95. package/dist/types/src/extensions/compute.d.ts +6 -0
  96. package/dist/types/src/extensions/compute.d.ts.map +1 -0
  97. package/dist/types/src/extensions/compute.stories.d.ts +26 -0
  98. package/dist/types/src/extensions/compute.stories.d.ts.map +1 -0
  99. package/dist/types/src/extensions/index.d.ts +2 -0
  100. package/dist/types/src/extensions/index.d.ts.map +1 -0
  101. package/dist/types/src/graph/compute-graph-registry.d.ts +34 -0
  102. package/dist/types/src/graph/compute-graph-registry.d.ts.map +1 -0
  103. package/dist/types/src/graph/compute-graph.d.ts +64 -0
  104. package/dist/types/src/graph/compute-graph.d.ts.map +1 -0
  105. package/dist/types/src/graph/compute-graph.stories.d.ts +10 -0
  106. package/dist/types/src/graph/compute-graph.stories.d.ts.map +1 -0
  107. package/dist/types/src/graph/compute-graph.test.d.ts +2 -0
  108. package/dist/types/src/graph/compute-graph.test.d.ts.map +1 -0
  109. package/dist/types/src/graph/compute-node.d.ts +26 -0
  110. package/dist/types/src/graph/compute-node.d.ts.map +1 -0
  111. package/dist/types/src/{components/ComputeGraph → graph/functions}/async-function.d.ts +14 -5
  112. package/dist/types/src/graph/functions/async-function.d.ts.map +1 -0
  113. package/dist/types/src/graph/functions/edge-function.d.ts +21 -0
  114. package/dist/types/src/graph/functions/edge-function.d.ts.map +1 -0
  115. package/dist/types/src/{model/functions.d.ts → graph/functions/function-defs.d.ts} +1 -1
  116. package/dist/types/src/graph/functions/function-defs.d.ts.map +1 -0
  117. package/dist/types/src/graph/functions/index.d.ts +4 -0
  118. package/dist/types/src/graph/functions/index.d.ts.map +1 -0
  119. package/dist/types/src/graph/hyperformula.test.d.ts +2 -0
  120. package/dist/types/src/graph/hyperformula.test.d.ts.map +1 -0
  121. package/dist/types/src/graph/index.d.ts +5 -0
  122. package/dist/types/src/graph/index.d.ts.map +1 -0
  123. package/dist/types/src/graph/testing/index.d.ts +3 -0
  124. package/dist/types/src/graph/testing/index.d.ts.map +1 -0
  125. package/dist/types/src/graph/testing/test-builder.d.ts +15 -0
  126. package/dist/types/src/graph/testing/test-builder.d.ts.map +1 -0
  127. package/dist/types/src/graph/testing/test-plugin.d.ts +36 -0
  128. package/dist/types/src/graph/testing/test-plugin.d.ts.map +1 -0
  129. package/dist/types/src/graph/util.d.ts +2 -0
  130. package/dist/types/src/graph/util.d.ts.map +1 -0
  131. package/dist/types/src/hooks/hooks.stories.d.ts +11 -0
  132. package/dist/types/src/hooks/hooks.stories.d.ts.map +1 -0
  133. package/dist/types/src/hooks/index.d.ts +4 -0
  134. package/dist/types/src/hooks/index.d.ts.map +1 -0
  135. package/dist/types/src/hooks/useComputeGraph.d.ts +7 -0
  136. package/dist/types/src/hooks/useComputeGraph.d.ts.map +1 -0
  137. package/dist/types/src/hooks/useFormattingModel.d.ts +3 -0
  138. package/dist/types/src/hooks/useFormattingModel.d.ts.map +1 -0
  139. package/dist/types/src/hooks/useSheetModel.d.ts +8 -0
  140. package/dist/types/src/hooks/useSheetModel.d.ts.map +1 -0
  141. package/dist/types/src/meta.d.ts +1 -4
  142. package/dist/types/src/meta.d.ts.map +1 -1
  143. package/dist/types/src/model/formatting-model.d.ts +16 -0
  144. package/dist/types/src/model/formatting-model.d.ts.map +1 -0
  145. package/dist/types/src/model/index.d.ts +2 -4
  146. package/dist/types/src/model/index.d.ts.map +1 -1
  147. package/dist/types/src/model/{model.d.ts → sheet-model.d.ts} +10 -49
  148. package/dist/types/src/model/sheet-model.d.ts.map +1 -0
  149. package/dist/types/src/model/sheet-model.test.d.ts +2 -0
  150. package/dist/types/src/model/sheet-model.test.d.ts.map +1 -0
  151. package/dist/types/src/sanity.test.d.ts +2 -0
  152. package/dist/types/src/sanity.test.d.ts.map +1 -0
  153. package/dist/types/src/testing/index.d.ts +2 -0
  154. package/dist/types/src/testing/index.d.ts.map +1 -0
  155. package/dist/types/src/testing/testing.d.ts +8 -0
  156. package/dist/types/src/testing/testing.d.ts.map +1 -0
  157. package/dist/types/src/types.d.ts +15 -4
  158. package/dist/types/src/types.d.ts.map +1 -1
  159. package/dist/vendor/hyperformula.mjs +37145 -0
  160. package/package.json +48 -44
  161. package/src/SheetPlugin.tsx +46 -62
  162. package/src/components/CellEditor/CellEditor.stories.tsx +6 -6
  163. package/src/components/CellEditor/CellEditor.tsx +59 -9
  164. package/src/components/CellEditor/extension.test.ts +3 -4
  165. package/src/components/CellEditor/extension.ts +5 -6
  166. package/src/components/ComputeGraph/ComputeGraphContextProvider.tsx +20 -0
  167. package/src/components/ComputeGraph/index.ts +1 -3
  168. package/src/components/GridSheet/GridSheet.stories.tsx +36 -0
  169. package/src/components/GridSheet/GridSheet.tsx +171 -0
  170. package/src/components/GridSheet/util.ts +148 -0
  171. package/src/components/Sheet/Sheet.stories.tsx +48 -88
  172. package/src/components/Sheet/Sheet.tsx +42 -24
  173. package/src/components/Sheet/grid.ts +3 -3
  174. package/src/components/Sheet/nav.ts +19 -19
  175. package/src/components/Sheet/sheet-context.tsx +12 -82
  176. package/src/components/Sheet/threads.tsx +10 -6
  177. package/src/components/SheetContainer.tsx +13 -15
  178. package/src/components/Toolbar/Toolbar.tsx +1 -2
  179. package/src/components/index.ts +1 -0
  180. package/src/defs/index.ts +6 -0
  181. package/src/{model → defs}/types.test.ts +7 -7
  182. package/src/{model → defs}/types.ts +24 -14
  183. package/src/{model → defs}/util.ts +65 -17
  184. package/src/extensions/compute.stories.tsx +151 -0
  185. package/src/extensions/compute.ts +147 -0
  186. package/src/extensions/index.ts +5 -0
  187. package/src/graph/compute-graph-registry.ts +90 -0
  188. package/src/graph/compute-graph.stories.tsx +93 -0
  189. package/src/graph/compute-graph.test.ts +87 -0
  190. package/src/graph/compute-graph.ts +242 -0
  191. package/src/graph/compute-node.ts +63 -0
  192. package/src/{components/ComputeGraph → graph/functions}/async-function.ts +25 -15
  193. package/src/{components/ComputeGraph → graph/functions}/edge-function.ts +16 -14
  194. package/src/graph/functions/index.ts +7 -0
  195. package/src/graph/hyperformula.test.ts +14 -0
  196. package/src/graph/index.ts +8 -0
  197. package/src/graph/testing/index.ts +6 -0
  198. package/src/graph/testing/test-builder.ts +54 -0
  199. package/src/{components/ComputeGraph/custom.ts → graph/testing/test-plugin.ts} +44 -14
  200. package/src/graph/util.ts +8 -0
  201. package/src/hooks/hooks.stories.tsx +50 -0
  202. package/src/hooks/index.ts +7 -0
  203. package/src/hooks/useComputeGraph.ts +28 -0
  204. package/src/hooks/useFormattingModel.ts +11 -0
  205. package/src/hooks/useSheetModel.ts +40 -0
  206. package/src/meta.tsx +1 -5
  207. package/src/{components/Sheet/formatting.ts → model/formatting-model.ts} +20 -13
  208. package/src/model/index.ts +2 -4
  209. package/src/model/sheet-model.test.ts +57 -0
  210. package/src/model/{model.ts → sheet-model.ts} +88 -188
  211. package/src/sanity.test.ts +40 -0
  212. package/src/testing/index.ts +5 -0
  213. package/src/testing/testing.tsx +68 -0
  214. package/src/types.ts +19 -17
  215. package/dist/lib/browser/SheetContainer-Y7ZMFBAP.mjs.map +0 -7
  216. package/dist/lib/browser/chunk-GNNVBNCX.mjs.map +0 -7
  217. package/dist/lib/browser/chunk-JRL5LGCE.mjs.map +0 -7
  218. package/dist/lib/browser/chunk-PGKZPKUD.mjs +0 -175
  219. package/dist/lib/browser/chunk-PGKZPKUD.mjs.map +0 -7
  220. package/dist/lib/browser/chunk-VBF7YENS.mjs +0 -8
  221. package/dist/lib/browser/chunk-VBF7YENS.mjs.map +0 -7
  222. package/dist/lib/browser/chunk-WUPTZUTX.mjs.map +0 -7
  223. package/dist/lib/browser/testing.mjs +0 -92
  224. package/dist/lib/browser/testing.mjs.map +0 -7
  225. package/dist/lib/node/SheetContainer-KEOKUKAQ.cjs.map +0 -7
  226. package/dist/lib/node/chunk-57PB2HPY.cjs +0 -40
  227. package/dist/lib/node/chunk-57PB2HPY.cjs.map +0 -7
  228. package/dist/lib/node/chunk-6LWBQAQZ.cjs +0 -202
  229. package/dist/lib/node/chunk-6LWBQAQZ.cjs.map +0 -7
  230. package/dist/lib/node/chunk-BJ6ZD7MN.cjs.map +0 -7
  231. package/dist/lib/node/chunk-VJU3NPUJ.cjs.map +0 -7
  232. package/dist/lib/node/chunk-ZRQZFV5T.cjs.map +0 -7
  233. package/dist/lib/node/testing.cjs +0 -111
  234. package/dist/lib/node/testing.cjs.map +0 -7
  235. package/dist/lib/node-esm/SheetContainer-Y7ZMFBAP.mjs.map +0 -7
  236. package/dist/lib/node-esm/chunk-GNNVBNCX.mjs.map +0 -7
  237. package/dist/lib/node-esm/chunk-JRL5LGCE.mjs.map +0 -7
  238. package/dist/lib/node-esm/chunk-PGKZPKUD.mjs +0 -175
  239. package/dist/lib/node-esm/chunk-PGKZPKUD.mjs.map +0 -7
  240. package/dist/lib/node-esm/chunk-VBF7YENS.mjs +0 -8
  241. package/dist/lib/node-esm/chunk-VBF7YENS.mjs.map +0 -7
  242. package/dist/lib/node-esm/chunk-WUPTZUTX.mjs.map +0 -7
  243. package/dist/lib/node-esm/testing.mjs +0 -92
  244. package/dist/lib/node-esm/testing.mjs.map +0 -7
  245. package/dist/types/src/components/ComputeGraph/async-function.d.ts.map +0 -1
  246. package/dist/types/src/components/ComputeGraph/custom.d.ts +0 -21
  247. package/dist/types/src/components/ComputeGraph/custom.d.ts.map +0 -1
  248. package/dist/types/src/components/ComputeGraph/edge-function.d.ts +0 -20
  249. package/dist/types/src/components/ComputeGraph/edge-function.d.ts.map +0 -1
  250. package/dist/types/src/components/ComputeGraph/graph-context.d.ts +0 -12
  251. package/dist/types/src/components/ComputeGraph/graph-context.d.ts.map +0 -1
  252. package/dist/types/src/components/ComputeGraph/graph.browser.test.d.ts +0 -2
  253. package/dist/types/src/components/ComputeGraph/graph.browser.test.d.ts.map +0 -1
  254. package/dist/types/src/components/ComputeGraph/graph.d.ts +0 -26
  255. package/dist/types/src/components/ComputeGraph/graph.d.ts.map +0 -1
  256. package/dist/types/src/components/Sheet/formatting.d.ts +0 -14
  257. package/dist/types/src/components/Sheet/formatting.d.ts.map +0 -1
  258. package/dist/types/src/model/functions.d.ts.map +0 -1
  259. package/dist/types/src/model/model.browser.test.d.ts +0 -2
  260. package/dist/types/src/model/model.browser.test.d.ts.map +0 -1
  261. package/dist/types/src/model/model.d.ts.map +0 -1
  262. package/dist/types/src/model/types.d.ts.map +0 -1
  263. package/dist/types/src/model/types.test.d.ts.map +0 -1
  264. package/dist/types/src/model/util.d.ts.map +0 -1
  265. package/dist/types/src/testing.d.ts +0 -9
  266. package/dist/types/src/testing.d.ts.map +0 -1
  267. package/src/components/ComputeGraph/graph-context.tsx +0 -50
  268. package/src/components/ComputeGraph/graph.browser.test.ts +0 -49
  269. package/src/components/ComputeGraph/graph.ts +0 -62
  270. package/src/model/model.browser.test.ts +0 -99
  271. package/src/testing.ts +0 -50
  272. /package/dist/types/src/{model → defs}/types.test.d.ts +0 -0
  273. /package/src/{model/functions.ts → graph/functions/function-defs.ts} +0 -0
@@ -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
  };
@@ -3,13 +3,24 @@
3
3
  //
4
4
 
5
5
  import { randomBytes } from '@dxos/crypto';
6
+ import { create } from '@dxos/echo-schema';
6
7
 
7
- import { type CellRange, type CellAddress } from '.';
8
- import { type SheetType } from '../types';
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';
9
18
 
10
19
  // TODO(burdon): Factor out from dxos/protocols to new common package.
11
20
  export class ApiError extends Error {}
21
+
12
22
  export class ReadonlyException extends ApiError {}
23
+
13
24
  export class RangeException extends ApiError {
14
25
  constructor(n: number) {
15
26
  super();
@@ -28,11 +39,55 @@ export const createIndex = (length = 8): string => {
28
39
 
29
40
  export const createIndices = (length: number): string[] => Array.from({ length }).map(() => createIndex());
30
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
+
31
86
  /**
32
87
  * E.g., "A1" => "CA2@CB3".
33
88
  */
34
89
  export const addressToIndex = (sheet: SheetType, cell: CellAddress): string => {
35
- return `${sheet.columns[cell.column]}@${sheet.rows[cell.row]}`;
90
+ return `${sheet.columns[cell.col]}@${sheet.rows[cell.row]}`;
36
91
  };
37
92
 
38
93
  /**
@@ -41,7 +96,7 @@ export const addressToIndex = (sheet: SheetType, cell: CellAddress): string => {
41
96
  export const addressFromIndex = (sheet: SheetType, idx: string): CellAddress => {
42
97
  const [column, row] = idx.split('@');
43
98
  return {
44
- column: sheet.columns.indexOf(column),
99
+ col: sheet.columns.indexOf(column),
45
100
  row: sheet.rows.indexOf(row),
46
101
  };
47
102
  };
@@ -61,22 +116,15 @@ export const rangeFromIndex = (sheet: SheetType, idx: string): CellRange => {
61
116
  return { from, to };
62
117
  };
63
118
 
64
- // TODO(burdon): Factor out.
65
- export const pickOne = <T>(values: T[]): T => values[Math.floor(Math.random() * values.length)];
66
- export const pickSome = <T>(values: T[], n = 1): T[] => {
67
- const result = new Set<T>();
68
- while (result.size < n) {
69
- result.add(pickOne(values));
70
- }
71
- return Array.from(result.values());
72
- };
73
-
119
+ /**
120
+ * Find closest cell to cursor.
121
+ */
74
122
  export const closest = (cursor: CellAddress, cells: CellAddress[]): CellAddress | undefined => {
75
123
  let closestCell: CellAddress | undefined;
76
124
  let closestDistance = Number.MAX_SAFE_INTEGER;
77
125
 
78
126
  for (const cell of cells) {
79
- const distance = Math.abs(cell.row - cursor.row) + Math.abs(cell.column - cursor.column);
127
+ const distance = Math.abs(cell.row - cursor.row) + Math.abs(cell.col - cursor.col);
80
128
  if (distance < closestDistance) {
81
129
  closestCell = cell;
82
130
  closestDistance = distance;
@@ -91,8 +139,8 @@ export const closest = (cursor: CellAddress, cells: CellAddress[]): CellAddress
91
139
  * Sorts primarily by row, then by column if rows are equal.
92
140
  */
93
141
  export const compareIndexPositions = (sheet: SheetType, indexA: string, indexB: string): number => {
94
- const { row: rowA, column: columnA } = addressFromIndex(sheet, indexA);
95
- const { row: rowB, column: columnB } = addressFromIndex(sheet, indexB);
142
+ const { row: rowA, col: columnA } = addressFromIndex(sheet, indexA);
143
+ const { row: rowB, col: columnB } = addressFromIndex(sheet, indexB);
96
144
 
97
145
  // Sort by row first, then by column.
98
146
  if (rowA !== rowB) {
@@ -0,0 +1,151 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import '@dxos-theme';
6
+ import React, { useEffect, useMemo } from 'react';
7
+
8
+ import { PublicKey } from '@dxos/keys';
9
+ import { useSpace } from '@dxos/react-client/echo';
10
+ import { withClientProvider } from '@dxos/react-client/testing';
11
+ import { useThemeContext } from '@dxos/react-ui';
12
+ import {
13
+ createBasicExtensions,
14
+ createMarkdownExtensions,
15
+ createThemeExtensions,
16
+ decorateMarkdown,
17
+ documentId,
18
+ useTextEditor,
19
+ } from '@dxos/react-ui-editor';
20
+ import { withTheme, withLayout } from '@dxos/storybook-utils';
21
+ import { nonNullable } from '@dxos/util';
22
+
23
+ import { compute, computeGraphFacet } from './compute';
24
+ import { Sheet } from '../components';
25
+ import { useComputeGraph, useSheetModel } from '../hooks';
26
+ import { useTestSheet, withComputeGraphDecorator } from '../testing';
27
+ import { SheetType } from '../types';
28
+
29
+ const str = (...lines: string[]) => lines.join('\n');
30
+
31
+ type EditorProps = {
32
+ text?: string;
33
+ };
34
+
35
+ // TODO(burdon): Implement named expressions.
36
+ // https://hyperformula.handsontable.com/guide/cell-references.html
37
+
38
+ // TODO(burdon): Inline Adobe eCharts.
39
+
40
+ const SHEET_NAME = 'Test Sheet';
41
+
42
+ const Editor = ({ text }: EditorProps) => {
43
+ const id = useMemo(() => PublicKey.random(), []);
44
+ const { themeMode } = useThemeContext();
45
+ const space = useSpace();
46
+ const computeGraph = useComputeGraph(space);
47
+ const { parentRef, focusAttributes } = useTextEditor(
48
+ () => ({
49
+ initialValue: text,
50
+ extensions: [
51
+ createBasicExtensions(),
52
+ createMarkdownExtensions({ themeMode }),
53
+ createThemeExtensions({ themeMode, syntaxHighlighting: true }),
54
+ documentId.of(id.toHex()),
55
+ computeGraph && computeGraphFacet.of(computeGraph),
56
+ compute(),
57
+ decorateMarkdown(),
58
+ ].filter(nonNullable),
59
+ }),
60
+ [computeGraph, themeMode],
61
+ );
62
+
63
+ return <div className='w-[40rem] overflow-hidden' ref={parentRef} {...focusAttributes} />;
64
+ };
65
+
66
+ const Grid = () => {
67
+ const space = useSpace();
68
+ const graph = useComputeGraph(space);
69
+ const sheet = useTestSheet(space, graph, { name: SHEET_NAME });
70
+ const model = useSheetModel(graph, sheet);
71
+ useEffect(() => {
72
+ if (model) {
73
+ model.setValues({ A1: { value: 100 }, A2: { value: 200 }, A3: { value: 300 }, A5: { value: '=SUM(A1:A3)' } });
74
+ }
75
+ }, [model]);
76
+
77
+ if (!graph || !sheet) {
78
+ return null;
79
+ }
80
+
81
+ return (
82
+ <div className='flex w-[40rem] overflow-hidden'>
83
+ <Sheet.Root graph={graph} sheet={sheet}>
84
+ <Sheet.Main classNames='border border-separator' />
85
+ </Sheet.Root>
86
+ </div>
87
+ );
88
+ };
89
+
90
+ const Story = (props: EditorProps) => {
91
+ return (
92
+ <div className='grid grid-rows-2'>
93
+ <Editor {...props} />
94
+ <Grid />
95
+ </div>
96
+ );
97
+ };
98
+
99
+ export default {
100
+ title: 'plugin-sheet/extensions',
101
+ decorators: [
102
+ withClientProvider({ types: [SheetType], createIdentity: true, createSpace: true }),
103
+ withComputeGraphDecorator(),
104
+ withTheme,
105
+ withLayout({ fullscreen: true, classNames: 'justify-center' }),
106
+ ],
107
+ parameters: { layout: 'fullscreen' },
108
+ };
109
+
110
+ // TODO(burdon): Inline formulae.
111
+ export const Default = {
112
+ render: Editor,
113
+ args: {
114
+ text: str(
115
+ //
116
+ '# Compute Graph',
117
+ '',
118
+ 'This is a compute expression:',
119
+ '',
120
+ '```dx',
121
+ '=SUM(1, 2)',
122
+ '```',
123
+ '',
124
+ 'It should change in realtime.',
125
+ '',
126
+ '```dx',
127
+ '=SUM(3, 5)',
128
+ '```',
129
+ '',
130
+ '',
131
+ ),
132
+ },
133
+ };
134
+
135
+ export const Graph = {
136
+ render: Story,
137
+ args: {
138
+ text: str(
139
+ //
140
+ '# Compute Graph',
141
+ '',
142
+ 'The total projected cost is:',
143
+ '',
144
+ '```dx',
145
+ `="${SHEET_NAME}"!A5`,
146
+ '```',
147
+ '',
148
+ '',
149
+ ),
150
+ },
151
+ };
@@ -0,0 +1,147 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import { syntaxTree } from '@codemirror/language';
6
+ import {
7
+ type EditorState,
8
+ type Extension,
9
+ type RangeSet,
10
+ RangeSetBuilder,
11
+ StateEffect,
12
+ StateField,
13
+ type Transaction,
14
+ } from '@codemirror/state';
15
+ import { Decoration, EditorView, ViewPlugin, WidgetType } from '@codemirror/view';
16
+
17
+ import { type UnsubscribeCallback, debounce } from '@dxos/async';
18
+ import { invariant } from '@dxos/invariant';
19
+ import { documentId, singleValueFacet } from '@dxos/react-ui-editor/state';
20
+
21
+ import { type CellAddress } from '../defs';
22
+ import { type ComputeGraph, type ComputeNode, createSheetName } from '../graph';
23
+ import { type CellScalarValue } from '../types';
24
+
25
+ const LANGUAGE_TAG = 'dx';
26
+
27
+ // TODO(burdon): Create marker just for our decorator?
28
+ const updateAllDecorations = StateEffect.define<void>();
29
+
30
+ export const computeGraphFacet = singleValueFacet<ComputeGraph>();
31
+
32
+ export type ComputeOptions = {};
33
+
34
+ export const compute = (options: ComputeOptions = {}): Extension => {
35
+ let computeNode: ComputeNode | undefined;
36
+
37
+ const update = (state: EditorState, current?: RangeSet<Decoration>) => {
38
+ const builder = new RangeSetBuilder<Decoration>();
39
+ if (computeNode) {
40
+ computeNode.clear();
41
+ syntaxTree(state).iterate({
42
+ enter: (node) => {
43
+ switch (node.name) {
44
+ case 'FencedCode': {
45
+ const cursor = state.selection.main.head;
46
+ if (state.readOnly || cursor < node.from || cursor > node.to) {
47
+ const info = node.node.getChild('CodeInfo');
48
+ if (info) {
49
+ const type = state.sliceDoc(info.from, info.to);
50
+ const text = node.node.getChild('CodeText');
51
+ if (type === LANGUAGE_TAG && text) {
52
+ const formula = state.sliceDoc(text.from, text.to);
53
+
54
+ const iter = current?.iter(node.node.from);
55
+ if (iter?.value && iter?.value.spec.formula === formula) {
56
+ // Add existing widget.
57
+ builder.add(node.from, node.to, iter.value);
58
+ } else {
59
+ // TODO(burdon): Create ordered list of cells on each decoration run.
60
+ const cell: CellAddress = { col: node.node.from, row: 0 };
61
+ invariant(computeNode);
62
+ // NOTE: This triggers re-render (below).
63
+ computeNode.setValue(cell, formula);
64
+ const value = computeNode.getValue(cell);
65
+ builder.add(
66
+ node.from,
67
+ node.to,
68
+ Decoration.replace({
69
+ widget: new ComputeWidget(formula, value),
70
+ formula,
71
+ }),
72
+ );
73
+ }
74
+ }
75
+ }
76
+ }
77
+
78
+ break;
79
+ }
80
+ }
81
+ },
82
+ });
83
+ }
84
+
85
+ return builder.finish();
86
+ };
87
+
88
+ return [
89
+ ViewPlugin.fromClass(
90
+ class {
91
+ // Graph subscription.
92
+ private _subscription?: UnsubscribeCallback;
93
+ constructor(view: EditorView) {
94
+ const id = view.state.facet(documentId);
95
+ const computeGraph = view.state.facet(computeGraphFacet);
96
+ if (id && computeGraph) {
97
+ queueMicrotask(async () => {
98
+ computeNode = computeGraph.getOrCreateNode(createSheetName({ type: '', id }));
99
+ await computeNode.open();
100
+
101
+ // Trigger re-render if values updated.
102
+ // TODO(burdon): Trigger only if formula value updated (currently triggered during render).
103
+ this._subscription = computeNode.update.on(
104
+ debounce(({ type, ...rest }) => {
105
+ if (type === 'valuesUpdated') {
106
+ view.dispatch({
107
+ effects: updateAllDecorations.of(),
108
+ });
109
+ }
110
+ }, 250),
111
+ );
112
+ });
113
+ }
114
+ }
115
+
116
+ destroy() {
117
+ this._subscription?.();
118
+ void computeNode?.close();
119
+ computeNode = undefined;
120
+ }
121
+ },
122
+ ),
123
+
124
+ StateField.define<RangeSet<Decoration>>({
125
+ create: (state) => update(state),
126
+ update: (rangeSet: RangeSet<Decoration>, tr: Transaction) => update(tr.state, rangeSet),
127
+ provide: (field) => EditorView.decorations.from(field),
128
+ }),
129
+ ];
130
+ };
131
+
132
+ // TODO(burdon): Click to edit.
133
+ class ComputeWidget extends WidgetType {
134
+ constructor(
135
+ private readonly formula: string,
136
+ private readonly value: CellScalarValue,
137
+ ) {
138
+ super();
139
+ }
140
+
141
+ override toDOM(_view: EditorView) {
142
+ const div = document.createElement('div');
143
+ div.setAttribute('title', this.formula);
144
+ div.innerText = String(this.value);
145
+ return div;
146
+ }
147
+ }
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ export * from './compute';
@@ -0,0 +1,90 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import type { FunctionPluginDefinition } from 'hyperformula';
6
+ import type { ConfigParams } from 'hyperformula/typings/ConfigParams';
7
+ import type { FunctionTranslationsPackage } from 'hyperformula/typings/interpreter';
8
+ import defaultsDeep from 'lodash.defaultsdeep';
9
+
10
+ import { type SpaceId, type Space } from '@dxos/client/echo';
11
+ import { Resource } from '@dxos/context';
12
+ import { invariant } from '@dxos/invariant';
13
+ import { log } from '@dxos/log';
14
+
15
+ import { HyperFormula } from '#hyperformula';
16
+ import { ComputeGraph } from './compute-graph';
17
+ import { EdgeFunctionPlugin, EdgeFunctionPluginTranslations, type FunctionContextOptions } from './functions';
18
+
19
+ export type ComputeGraphPlugin = {
20
+ plugin: FunctionPluginDefinition;
21
+ translations: FunctionTranslationsPackage;
22
+ };
23
+
24
+ export type ComputeGraphOptions = {
25
+ plugins?: ComputeGraphPlugin[];
26
+ } & Partial<FunctionContextOptions> &
27
+ Partial<ConfigParams>;
28
+
29
+ export const defaultOptions: ComputeGraphOptions = {
30
+ licenseKey: 'gpl-v3',
31
+ };
32
+
33
+ export const defaultPlugins: ComputeGraphPlugin[] = [
34
+ {
35
+ plugin: EdgeFunctionPlugin,
36
+ translations: EdgeFunctionPluginTranslations,
37
+ },
38
+ ];
39
+
40
+ /**
41
+ * Manages a collection of ComputeGraph instances for each space.
42
+ *
43
+ * [ComputePlugin] => [ComputeGraphRegistry] => [ComputeGraph(Space)] => [ComputeNode(Object)]
44
+ *
45
+ * NOTE: The ComputeGraphRegistry manages the hierarchy of resources via its root Context.
46
+ * NOTE: The package.json file defines the packaged #hyperformula module.
47
+ */
48
+ // TODO(burdon): Move graph into separate plugin; isolate HF deps.
49
+ export class ComputeGraphRegistry extends Resource {
50
+ private readonly _graphs = new Map<SpaceId, ComputeGraph>();
51
+
52
+ private readonly _options: ComputeGraphOptions;
53
+
54
+ constructor(options: ComputeGraphOptions = { plugins: defaultPlugins }) {
55
+ super();
56
+ this._options = defaultsDeep({}, options, defaultOptions);
57
+ this._options.plugins?.forEach(({ plugin, translations }) => {
58
+ HyperFormula.registerFunctionPlugin(plugin, translations);
59
+ });
60
+ }
61
+
62
+ getGraph(spaceId: SpaceId): ComputeGraph | undefined {
63
+ return this._graphs.get(spaceId);
64
+ }
65
+
66
+ getOrCreateGraph(space: Space): ComputeGraph {
67
+ let graph = this._graphs.get(space.id);
68
+ if (!graph) {
69
+ log('create graph', { space: space.id });
70
+ graph = this.createGraph(space);
71
+ }
72
+
73
+ return graph;
74
+ }
75
+
76
+ createGraph(space: Space): ComputeGraph {
77
+ invariant(!this._graphs.has(space.id), `ComputeGraph already exists for space: ${space.id}`);
78
+ const hf = HyperFormula.buildEmpty(this._options);
79
+ const graph = new ComputeGraph(hf, space, this._options);
80
+ this._graphs.set(space.id, graph);
81
+ return graph;
82
+ }
83
+
84
+ protected override async _close() {
85
+ for (const graph of this._graphs.values()) {
86
+ await graph.close();
87
+ }
88
+ this._graphs.clear();
89
+ }
90
+ }
@@ -0,0 +1,93 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import '@dxos-theme';
6
+
7
+ import React, { useEffect, useRef, useState } from 'react';
8
+
9
+ import { FunctionType } from '@dxos/plugin-script/types';
10
+ import { create, useSpace, Filter } from '@dxos/react-client/echo';
11
+ import { withClientProvider } from '@dxos/react-client/testing';
12
+ import { Toolbar, Button, Input } from '@dxos/react-ui';
13
+ import { SyntaxHighlighter } from '@dxos/react-ui-syntax-highlighter';
14
+ import { withTheme } from '@dxos/storybook-utils';
15
+
16
+ import { testFunctionPlugins } from './testing';
17
+ import { createSheet } from '../defs';
18
+ import { useComputeGraph, useSheetModel } from '../hooks';
19
+ import { withComputeGraphDecorator } from '../testing';
20
+ import { SheetType } from '../types';
21
+
22
+ const FUNCTION_NAME = 'TEST';
23
+
24
+ const Story = () => {
25
+ const space = useSpace();
26
+ const graph = useComputeGraph(space);
27
+ const [sheet, setSheet] = useState<SheetType>();
28
+ const [text, setText] = useState(`${FUNCTION_NAME}(100)`);
29
+ const [result, setResult] = useState<any>();
30
+ const model = useSheetModel(graph, sheet);
31
+ useEffect(() => {
32
+ if (space) {
33
+ const sheet = space.db.add(createSheet());
34
+ setSheet(sheet);
35
+ }
36
+ }, [space]);
37
+
38
+ useEffect(() => {
39
+ if (space && graph) {
40
+ graph.update.on(() => {
41
+ const f1 = graph.getFunctions({ standard: true, echo: false });
42
+ const f2 = graph.getFunctions({ standard: false, echo: true });
43
+ setResult({ functions: { standard: f1.length, echo: f2.length } });
44
+ });
45
+
46
+ space.db.add(create(FunctionType, { version: 1, binding: FUNCTION_NAME }));
47
+ }
48
+ }, [space, graph]);
49
+
50
+ const inputRef = useRef<HTMLInputElement | null>(null);
51
+ const handleTest = async () => {
52
+ if (space && graph) {
53
+ const { objects } = await space.db.query(Filter.schema(FunctionType)).run();
54
+ const mapped = graph.mapFunctionBindingToId(text);
55
+ const unmapped = graph.mapFunctionBindingFromId(mapped);
56
+ const internal = graph.mapFormulaToNative(text);
57
+ setResult({ mapped, unmapped, internal, functions: objects.map((object) => object.id) });
58
+ }
59
+
60
+ inputRef.current?.focus();
61
+ };
62
+
63
+ return (
64
+ <div className='flex flex-col gap-2 '>
65
+ <Toolbar.Root>
66
+ <Input.Root>
67
+ <Input.TextInput
68
+ ref={inputRef}
69
+ placeholder='Formula'
70
+ value={text}
71
+ onChange={(ev) => setText(ev.target.value)}
72
+ />
73
+ </Input.Root>
74
+ <Button onClick={handleTest}>Test</Button>
75
+ </Toolbar.Root>
76
+ <SyntaxHighlighter language='json'>
77
+ {JSON.stringify({ space: space?.id, graph: graph?.id, sheet: sheet?.id, model: model?.id, result }, null, 2)}
78
+ </SyntaxHighlighter>
79
+ </div>
80
+ );
81
+ };
82
+
83
+ export default {
84
+ title: 'plugin-sheet/functions',
85
+ decorators: [
86
+ withClientProvider({ types: [FunctionType, SheetType], createIdentity: true, createSpace: true }),
87
+ withComputeGraphDecorator({ plugins: testFunctionPlugins }),
88
+ withTheme,
89
+ ],
90
+ render: (args: any) => <Story {...args} />,
91
+ };
92
+
93
+ export const Default = {};