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

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 (256) hide show
  1. package/dist/lib/browser/SheetContainer-V4GCCZTX.mjs +261 -0
  2. package/dist/lib/browser/SheetContainer-V4GCCZTX.mjs.map +7 -0
  3. package/dist/lib/browser/{chunk-GNNVBNCX.mjs → chunk-6ZMQVB4Z.mjs} +358 -678
  4. package/dist/lib/browser/chunk-6ZMQVB4Z.mjs.map +7 -0
  5. package/dist/lib/browser/{chunk-JRL5LGCE.mjs → chunk-QILRZNE5.mjs} +2 -5
  6. package/dist/lib/browser/chunk-QILRZNE5.mjs.map +7 -0
  7. package/dist/lib/{node-esm/chunk-WUPTZUTX.mjs → browser/chunk-T3NJFTD4.mjs} +4 -14
  8. package/dist/lib/browser/chunk-T3NJFTD4.mjs.map +7 -0
  9. package/dist/lib/browser/{SheetContainer-Y7ZMFBAP.mjs → chunk-U2JHW3L6.mjs} +819 -498
  10. package/dist/lib/browser/chunk-U2JHW3L6.mjs.map +7 -0
  11. package/dist/lib/browser/graph-T27BOBOV.mjs +21 -0
  12. package/dist/lib/browser/graph-T27BOBOV.mjs.map +7 -0
  13. package/dist/lib/browser/index.mjs +58 -55
  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 -6
  18. package/dist/lib/node/SheetContainer-3ZY7MPWJ.cjs +279 -0
  19. package/dist/lib/node/SheetContainer-3ZY7MPWJ.cjs.map +7 -0
  20. package/dist/lib/node/{chunk-BJ6ZD7MN.cjs → chunk-BNARJ5GM.cjs} +5 -18
  21. package/dist/lib/node/chunk-BNARJ5GM.cjs.map +7 -0
  22. package/dist/lib/node/{chunk-ZRQZFV5T.cjs → chunk-DD6FIXWC.cjs} +359 -679
  23. package/dist/lib/node/chunk-DD6FIXWC.cjs.map +7 -0
  24. package/dist/lib/node/{SheetContainer-KEOKUKAQ.cjs → chunk-OTTD7FBK.cjs} +875 -551
  25. package/dist/lib/node/chunk-OTTD7FBK.cjs.map +7 -0
  26. package/dist/lib/node/{chunk-VJU3NPUJ.cjs → chunk-Q3HBHPRL.cjs} +8 -19
  27. package/dist/lib/node/chunk-Q3HBHPRL.cjs.map +7 -0
  28. package/dist/lib/node/graph-SPKGX7W4.cjs +43 -0
  29. package/dist/lib/node/graph-SPKGX7W4.cjs.map +7 -0
  30. package/dist/lib/node/index.cjs +75 -64
  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 +10 -12
  36. package/dist/lib/node/types.cjs.map +2 -2
  37. package/dist/lib/node-esm/SheetContainer-PXSJX6XK.mjs +262 -0
  38. package/dist/lib/node-esm/SheetContainer-PXSJX6XK.mjs.map +7 -0
  39. package/dist/lib/node-esm/{SheetContainer-Y7ZMFBAP.mjs → chunk-7HVSOTGA.mjs} +820 -498
  40. package/dist/lib/node-esm/chunk-7HVSOTGA.mjs.map +7 -0
  41. package/dist/lib/{browser/chunk-WUPTZUTX.mjs → node-esm/chunk-BMNA27EX.mjs} +5 -14
  42. package/dist/lib/node-esm/chunk-BMNA27EX.mjs.map +7 -0
  43. package/dist/lib/node-esm/{chunk-GNNVBNCX.mjs → chunk-D6KU5MI7.mjs} +359 -677
  44. package/dist/lib/node-esm/chunk-D6KU5MI7.mjs.map +7 -0
  45. package/dist/lib/node-esm/{chunk-JRL5LGCE.mjs → chunk-IU2L277A.mjs} +4 -5
  46. package/dist/lib/node-esm/chunk-IU2L277A.mjs.map +7 -0
  47. package/dist/lib/node-esm/graph-U67IO4UC.mjs +22 -0
  48. package/dist/lib/node-esm/graph-U67IO4UC.mjs.map +7 -0
  49. package/dist/lib/node-esm/index.mjs +59 -55
  50. package/dist/lib/node-esm/index.mjs.map +3 -3
  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 +7 -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 +4 -5
  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 +5 -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/{components/ComputeGraph → graph}/async-function.d.ts +1 -1
  102. package/dist/types/src/graph/async-function.d.ts.map +1 -0
  103. package/dist/types/src/graph/compute-graph.browser.test.d.ts +2 -0
  104. package/dist/types/src/graph/compute-graph.browser.test.d.ts.map +1 -0
  105. package/dist/types/src/graph/compute-graph.d.ts +81 -0
  106. package/dist/types/src/graph/compute-graph.d.ts.map +1 -0
  107. package/dist/types/src/graph/compute-graph.stories.d.ts +10 -0
  108. package/dist/types/src/graph/compute-graph.stories.d.ts.map +1 -0
  109. package/dist/types/src/graph/compute-node.d.ts +19 -0
  110. package/dist/types/src/graph/compute-node.d.ts.map +1 -0
  111. package/dist/types/src/{components/ComputeGraph/custom.d.ts → graph/custom-function.d.ts} +1 -1
  112. package/dist/types/src/graph/custom-function.d.ts.map +1 -0
  113. package/dist/types/src/graph/edge-function.d.ts.map +1 -0
  114. package/dist/types/src/{model/functions.d.ts → graph/function-defs.d.ts} +1 -1
  115. package/dist/types/src/graph/function-defs.d.ts.map +1 -0
  116. package/dist/types/src/graph/hyperformula.test.d.ts +2 -0
  117. package/dist/types/src/graph/hyperformula.test.d.ts.map +1 -0
  118. package/dist/types/src/graph/index.d.ts +4 -0
  119. package/dist/types/src/graph/index.d.ts.map +1 -0
  120. package/dist/types/src/graph/util.d.ts +2 -0
  121. package/dist/types/src/graph/util.d.ts.map +1 -0
  122. package/dist/types/src/hooks/hooks.stories.d.ts +11 -0
  123. package/dist/types/src/hooks/hooks.stories.d.ts.map +1 -0
  124. package/dist/types/src/hooks/index.d.ts +4 -0
  125. package/dist/types/src/hooks/index.d.ts.map +1 -0
  126. package/dist/types/src/hooks/useComputeGraph.d.ts +7 -0
  127. package/dist/types/src/hooks/useComputeGraph.d.ts.map +1 -0
  128. package/dist/types/src/hooks/useFormattingModel.d.ts +3 -0
  129. package/dist/types/src/hooks/useFormattingModel.d.ts.map +1 -0
  130. package/dist/types/src/hooks/useSheetModel.d.ts +8 -0
  131. package/dist/types/src/hooks/useSheetModel.d.ts.map +1 -0
  132. package/dist/types/src/meta.d.ts +1 -4
  133. package/dist/types/src/meta.d.ts.map +1 -1
  134. package/dist/types/src/model/formatting-model.d.ts +16 -0
  135. package/dist/types/src/model/formatting-model.d.ts.map +1 -0
  136. package/dist/types/src/model/index.d.ts +2 -4
  137. package/dist/types/src/model/index.d.ts.map +1 -1
  138. package/dist/types/src/model/{model.d.ts → sheet-model.d.ts} +9 -48
  139. package/dist/types/src/model/sheet-model.d.ts.map +1 -0
  140. package/dist/types/src/sanity.test.d.ts +2 -0
  141. package/dist/types/src/sanity.test.d.ts.map +1 -0
  142. package/dist/types/src/testing/index.d.ts +2 -0
  143. package/dist/types/src/testing/index.d.ts.map +1 -0
  144. package/dist/types/src/testing/testing.d.ts +9 -0
  145. package/dist/types/src/testing/testing.d.ts.map +1 -0
  146. package/dist/types/src/types.d.ts +12 -2
  147. package/dist/types/src/types.d.ts.map +1 -1
  148. package/dist/vendor/hyperformula.mjs +37145 -0
  149. package/package.json +41 -38
  150. package/src/SheetPlugin.tsx +39 -59
  151. package/src/components/CellEditor/CellEditor.stories.tsx +4 -3
  152. package/src/components/CellEditor/CellEditor.tsx +59 -9
  153. package/src/components/CellEditor/extension.test.ts +3 -3
  154. package/src/components/CellEditor/extension.ts +1 -3
  155. package/src/components/ComputeGraph/ComputeGraphContextProvider.tsx +20 -0
  156. package/src/components/ComputeGraph/index.ts +1 -3
  157. package/src/components/GridSheet/GridSheet.stories.tsx +35 -0
  158. package/src/components/GridSheet/GridSheet.tsx +153 -0
  159. package/src/components/GridSheet/util.ts +108 -0
  160. package/src/components/Sheet/Sheet.stories.tsx +41 -82
  161. package/src/components/Sheet/Sheet.tsx +12 -10
  162. package/src/components/Sheet/grid.ts +3 -3
  163. package/src/components/Sheet/nav.ts +19 -19
  164. package/src/components/Sheet/sheet-context.tsx +10 -80
  165. package/src/components/Sheet/threads.tsx +10 -6
  166. package/src/components/SheetContainer.tsx +2 -2
  167. package/src/components/Toolbar/Toolbar.tsx +1 -2
  168. package/src/components/index.ts +1 -0
  169. package/src/defs/index.ts +6 -0
  170. package/src/{model → defs}/types.test.ts +7 -7
  171. package/src/{model → defs}/types.ts +23 -14
  172. package/src/{model → defs}/util.ts +49 -17
  173. package/src/extensions/compute.stories.tsx +151 -0
  174. package/src/extensions/compute.ts +98 -0
  175. package/src/extensions/index.ts +5 -0
  176. package/src/{components/ComputeGraph → graph}/async-function.ts +3 -1
  177. package/src/graph/compute-graph.browser.test.ts +104 -0
  178. package/src/graph/compute-graph.stories.tsx +92 -0
  179. package/src/graph/compute-graph.ts +290 -0
  180. package/src/graph/compute-node.ts +51 -0
  181. package/src/{components/ComputeGraph/custom.ts → graph/custom-function.ts} +2 -6
  182. package/src/{components/ComputeGraph → graph}/edge-function.ts +2 -1
  183. package/src/graph/hyperformula.test.ts +15 -0
  184. package/src/graph/index.ts +7 -0
  185. package/src/graph/util.ts +8 -0
  186. package/src/hooks/hooks.stories.tsx +50 -0
  187. package/src/hooks/index.ts +7 -0
  188. package/src/hooks/useComputeGraph.ts +20 -0
  189. package/src/hooks/useFormattingModel.ts +11 -0
  190. package/src/hooks/useSheetModel.ts +43 -0
  191. package/src/meta.tsx +1 -5
  192. package/src/{components/Sheet/formatting.ts → model/formatting-model.ts} +20 -13
  193. package/src/model/index.ts +2 -4
  194. package/src/model/{model.ts → sheet-model.ts} +67 -184
  195. package/src/sanity.test.ts +40 -0
  196. package/src/testing/index.ts +5 -0
  197. package/src/testing/testing.tsx +66 -0
  198. package/src/types.ts +14 -12
  199. package/dist/lib/browser/SheetContainer-Y7ZMFBAP.mjs.map +0 -7
  200. package/dist/lib/browser/chunk-GNNVBNCX.mjs.map +0 -7
  201. package/dist/lib/browser/chunk-JRL5LGCE.mjs.map +0 -7
  202. package/dist/lib/browser/chunk-PGKZPKUD.mjs +0 -175
  203. package/dist/lib/browser/chunk-PGKZPKUD.mjs.map +0 -7
  204. package/dist/lib/browser/chunk-VBF7YENS.mjs +0 -8
  205. package/dist/lib/browser/chunk-VBF7YENS.mjs.map +0 -7
  206. package/dist/lib/browser/chunk-WUPTZUTX.mjs.map +0 -7
  207. package/dist/lib/browser/testing.mjs +0 -92
  208. package/dist/lib/browser/testing.mjs.map +0 -7
  209. package/dist/lib/node/SheetContainer-KEOKUKAQ.cjs.map +0 -7
  210. package/dist/lib/node/chunk-57PB2HPY.cjs +0 -40
  211. package/dist/lib/node/chunk-57PB2HPY.cjs.map +0 -7
  212. package/dist/lib/node/chunk-6LWBQAQZ.cjs +0 -202
  213. package/dist/lib/node/chunk-6LWBQAQZ.cjs.map +0 -7
  214. package/dist/lib/node/chunk-BJ6ZD7MN.cjs.map +0 -7
  215. package/dist/lib/node/chunk-VJU3NPUJ.cjs.map +0 -7
  216. package/dist/lib/node/chunk-ZRQZFV5T.cjs.map +0 -7
  217. package/dist/lib/node/testing.cjs +0 -111
  218. package/dist/lib/node/testing.cjs.map +0 -7
  219. package/dist/lib/node-esm/SheetContainer-Y7ZMFBAP.mjs.map +0 -7
  220. package/dist/lib/node-esm/chunk-GNNVBNCX.mjs.map +0 -7
  221. package/dist/lib/node-esm/chunk-JRL5LGCE.mjs.map +0 -7
  222. package/dist/lib/node-esm/chunk-PGKZPKUD.mjs +0 -175
  223. package/dist/lib/node-esm/chunk-PGKZPKUD.mjs.map +0 -7
  224. package/dist/lib/node-esm/chunk-VBF7YENS.mjs +0 -8
  225. package/dist/lib/node-esm/chunk-VBF7YENS.mjs.map +0 -7
  226. package/dist/lib/node-esm/chunk-WUPTZUTX.mjs.map +0 -7
  227. package/dist/lib/node-esm/testing.mjs +0 -92
  228. package/dist/lib/node-esm/testing.mjs.map +0 -7
  229. package/dist/types/src/components/ComputeGraph/async-function.d.ts.map +0 -1
  230. package/dist/types/src/components/ComputeGraph/custom.d.ts.map +0 -1
  231. package/dist/types/src/components/ComputeGraph/edge-function.d.ts.map +0 -1
  232. package/dist/types/src/components/ComputeGraph/graph-context.d.ts +0 -12
  233. package/dist/types/src/components/ComputeGraph/graph-context.d.ts.map +0 -1
  234. package/dist/types/src/components/ComputeGraph/graph.browser.test.d.ts +0 -2
  235. package/dist/types/src/components/ComputeGraph/graph.browser.test.d.ts.map +0 -1
  236. package/dist/types/src/components/ComputeGraph/graph.d.ts +0 -26
  237. package/dist/types/src/components/ComputeGraph/graph.d.ts.map +0 -1
  238. package/dist/types/src/components/Sheet/formatting.d.ts +0 -14
  239. package/dist/types/src/components/Sheet/formatting.d.ts.map +0 -1
  240. package/dist/types/src/model/functions.d.ts.map +0 -1
  241. package/dist/types/src/model/model.browser.test.d.ts +0 -2
  242. package/dist/types/src/model/model.browser.test.d.ts.map +0 -1
  243. package/dist/types/src/model/model.d.ts.map +0 -1
  244. package/dist/types/src/model/types.d.ts.map +0 -1
  245. package/dist/types/src/model/types.test.d.ts.map +0 -1
  246. package/dist/types/src/model/util.d.ts.map +0 -1
  247. package/dist/types/src/testing.d.ts +0 -9
  248. package/dist/types/src/testing.d.ts.map +0 -1
  249. package/src/components/ComputeGraph/graph-context.tsx +0 -50
  250. package/src/components/ComputeGraph/graph.browser.test.ts +0 -49
  251. package/src/components/ComputeGraph/graph.ts +0 -62
  252. package/src/model/model.browser.test.ts +0 -99
  253. package/src/testing.ts +0 -50
  254. /package/dist/types/src/{model → defs}/types.test.d.ts +0 -0
  255. /package/dist/types/src/{components/ComputeGraph → graph}/edge-function.d.ts +0 -0
  256. /package/src/{model/functions.ts → graph/function-defs.ts} +0 -0
@@ -2,22 +2,16 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import React, { type PropsWithChildren, createContext, useContext, useState, useEffect, useMemo } from 'react';
5
+ import React, { type PropsWithChildren, createContext, useContext, useMemo, useState } from 'react';
6
6
 
7
7
  import { invariant } from '@dxos/invariant';
8
- import { type FunctionType } from '@dxos/plugin-script';
9
- import { fullyQualifiedId, type Space } from '@dxos/react-client/echo';
8
+ import { type Space } from '@dxos/react-client/echo';
10
9
 
11
10
  import { createDecorations } from './decorations';
12
- import { FormattingModel } from './formatting';
13
- import { type CellAddress, type CellRange, defaultFunctions, SheetModel } from '../../model';
11
+ import { type CellAddress, type CellRange } from '../../defs';
12
+ import { useSheetModel, useFormattingModel } from '../../hooks';
13
+ import { type FormattingModel, type SheetModel } from '../../model';
14
14
  import { type SheetType } from '../../types';
15
- import { type FunctionContextOptions } from '../ComputeGraph';
16
- // TODO(wittjosiah): Refactor. This is not exported from ./components due to depending on ECHO.
17
- import { useComputeGraph } from '../ComputeGraph/graph-context';
18
-
19
- // TODO(wittjosiah): Factor out.
20
- const OBJECT_ID_LENGTH = 60; // 33 (space id) + 26 (object id) + 1 (separator).
21
15
 
22
16
  export type SheetContextType = {
23
17
  model: SheetModel;
@@ -54,49 +48,7 @@ export type SheetContextProps = {
54
48
  sheet: SheetType;
55
49
  space: Space;
56
50
  readonly?: boolean;
57
- } & Pick<SheetContextType, 'onInfo'> &
58
- Partial<FunctionContextOptions>;
59
-
60
- /**
61
- * Map from binding to fully qualified ECHO ID.
62
- */
63
- const mapFormulaBindingToId =
64
- (functions: FunctionType[]) =>
65
- (formula: string): string => {
66
- return formula.replace(/([a-zA-Z0-9]+)\((.*)\)/g, (match, binding, args) => {
67
- if (defaultFunctions.find((fn) => fn.name === binding) || binding === 'EDGE') {
68
- return match;
69
- }
70
-
71
- const fn = functions.find((fn) => fn.binding === binding);
72
- if (fn) {
73
- return `${fullyQualifiedId(fn)}(${args})`;
74
- } else {
75
- return match;
76
- }
77
- });
78
- };
79
-
80
- /**
81
- * Map from fully qualified ECHO ID to binding.
82
- */
83
- const mapFormulaBindingFromId =
84
- (functions: FunctionType[]) =>
85
- (formula: string): string => {
86
- return formula.replace(/([a-zA-Z0-9]+):([a-zA-Z0-9]+)\((.*)\)/g, (match, spaceId, objectId, args) => {
87
- const id = `${spaceId}:${objectId}`;
88
- if (id.length !== OBJECT_ID_LENGTH) {
89
- return match;
90
- }
91
-
92
- const fn = functions.find((fn) => fullyQualifiedId(fn) === id);
93
- if (fn?.binding) {
94
- return `${fn.binding}(${args})`;
95
- } else {
96
- return match;
97
- }
98
- });
99
- };
51
+ } & Pick<SheetContextType, 'onInfo'>;
100
52
 
101
53
  export const SheetContextProvider = ({
102
54
  children,
@@ -104,39 +56,17 @@ export const SheetContextProvider = ({
104
56
  space,
105
57
  readonly,
106
58
  onInfo,
107
- ...options
108
59
  }: PropsWithChildren<SheetContextProps>) => {
109
- const graph = useComputeGraph(space, options);
60
+ const model = useSheetModel(space, sheet, { readonly });
61
+ const formatting = useFormattingModel(model);
110
62
 
111
- // TODO(Zan): We should offer a version of set range and set cursor that scrolls to
112
- // that cell or range if it is not visible.
63
+ // TODO(Zan): Impl. set range and set cursor that scrolls to that cell or range if it is not visible.
113
64
  const [cursor, setCursor] = useState<CellAddress>();
114
65
  const [range, setRange] = useState<CellRange>();
115
66
  const [editing, setEditing] = useState<boolean>(false);
116
67
  const decorations = useMemo(() => createDecorations(), []);
117
68
 
118
- const [[model, formatting] = [], setModels] = useState<[SheetModel, FormattingModel] | undefined>(undefined);
119
- useEffect(() => {
120
- let model: SheetModel | undefined;
121
- let formatting;
122
- const t = setTimeout(async () => {
123
- model = new SheetModel(graph, sheet, space, { readonly, mapFormulaBindingToId, mapFormulaBindingFromId });
124
- await model.initialize();
125
- formatting = new FormattingModel(model);
126
- setModels([model, formatting]);
127
- });
128
-
129
- return () => {
130
- clearTimeout(t);
131
- void model?.destroy();
132
- };
133
- }, [graph, readonly]);
134
-
135
- if (!model || !formatting) {
136
- return null;
137
- }
138
-
139
- return (
69
+ return !model || !formatting ? null : (
140
70
  <SheetContext.Provider
141
71
  value={{
142
72
  model,
@@ -3,18 +3,19 @@
3
3
  //
4
4
 
5
5
  import { effect } from '@preact/signals-core';
6
- import React, { useCallback, useEffect, useMemo } from 'react';
6
+ import React, { type PropsWithChildren, useCallback, useEffect, useMemo } from 'react';
7
7
 
8
8
  import { type IntentResolver, LayoutAction, useIntentDispatcher, useIntentResolver } from '@dxos/app-framework';
9
9
  import { debounce } from '@dxos/async';
10
10
  import { fullyQualifiedId } from '@dxos/react-client/echo';
11
11
  import { Icon, useTranslation } from '@dxos/react-ui';
12
- import { mx } from '@dxos/react-ui-theme';
13
12
 
14
13
  import { type Decoration } from './decorations';
15
14
  import { useSheetContext } from './sheet-context';
15
+ import { addressFromIndex, addressToIndex, type CellAddress, closest } from '../../defs';
16
16
  import { SHEET_PLUGIN } from '../../meta';
17
- import { addressFromIndex, addressToIndex, type CellAddress, closest } from '../../model';
17
+
18
+ // TODO(burdon): Move into folder; split hooks.
18
19
 
19
20
  const CommentIndicator = () => {
20
21
  return (
@@ -25,9 +26,9 @@ const CommentIndicator = () => {
25
26
  );
26
27
  };
27
28
 
28
- const ThreadedCellWrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => {
29
+ const ThreadedCellWrapper = ({ children }: PropsWithChildren) => {
29
30
  const dispatch = useIntentDispatcher();
30
- const [isHovered, setIsHovered] = React.useState(true);
31
+ const [isHovered, setIsHovered] = React.useState(false);
31
32
  const { t } = useTranslation(SHEET_PLUGIN);
32
33
 
33
34
  const handleClick = React.useCallback(
@@ -40,7 +41,7 @@ const ThreadedCellWrapper: React.FC<{ children: React.ReactNode }> = ({ children
40
41
  return (
41
42
  <div
42
43
  role='none'
43
- className={mx('relative h-full is-full')}
44
+ className='relative h-full is-full'
44
45
  onMouseEnter={() => {
45
46
  setIsHovered(true);
46
47
  }}
@@ -73,6 +74,8 @@ const createThreadDecoration = (cellIndex: string, threadId: string, sheetId: st
73
74
  };
74
75
  };
75
76
 
77
+ // TODO(burdon): Factor out hooks.
78
+
76
79
  const useUpdateCursorOnThreadSelection = () => {
77
80
  const { setCursor, model } = useSheetContext();
78
81
 
@@ -190,6 +193,7 @@ const useThreadDecorations = () => {
190
193
  }
191
194
  }
192
195
  });
196
+
193
197
  return () => unsubscribe();
194
198
  });
195
199
  };
@@ -22,7 +22,7 @@ const attentionFragment = mx(
22
22
  export const sectionToolbarLayout =
23
23
  'bs-[--rail-action] bg-[--sticky-bg] sticky block-start-0 __-block-start-px transition-opacity';
24
24
 
25
- const SheetContainer = ({ sheet, space, role, remoteFunctionUrl }: SheetRootProps & { role?: string }) => {
25
+ const SheetContainer = ({ sheet, space, role }: SheetRootProps & { role?: string }) => {
26
26
  const dispatch = useIntentDispatcher();
27
27
 
28
28
  const id = fullyQualifiedId(sheet);
@@ -50,7 +50,7 @@ const SheetContainer = ({ sheet, space, role, remoteFunctionUrl }: SheetRootProp
50
50
 
51
51
  return (
52
52
  <div role='none' className={role === 'article' ? 'row-span-2 grid grid-rows-subgrid' : undefined}>
53
- <Sheet.Root sheet={sheet} space={space} remoteFunctionUrl={remoteFunctionUrl}>
53
+ <Sheet.Root space={space} sheet={sheet}>
54
54
  <div role='none' className={mx('flex flex-0 justify-center overflow-x-auto')}>
55
55
  <Toolbar.Root
56
56
  onAction={handleAction}
@@ -26,8 +26,8 @@ import {
26
26
  import { nonNullable } from '@dxos/util';
27
27
 
28
28
  import { ToolbarButton, ToolbarSeparator, ToolbarToggleButton } from './common';
29
+ import { addressToIndex } from '../../defs';
29
30
  import { SHEET_PLUGIN } from '../../meta';
30
- import { addressToIndex } from '../../model';
31
31
  import { type Formatting } from '../../types';
32
32
  import { useSheetContext } from '../Sheet/sheet-context';
33
33
 
@@ -179,7 +179,6 @@ const Styles = () => {
179
179
  // Actions
180
180
  //
181
181
 
182
- // TODO(Zan): Instead of taking props, can we access the state from sheet context?
183
182
  const Actions = () => {
184
183
  const { onAction } = useToolbarContext('Actions');
185
184
  const { cursor, range, model } = useSheetContext();
@@ -5,6 +5,7 @@
5
5
  import React from 'react';
6
6
 
7
7
  export * from './ComputeGraph';
8
+ export * from './Sheet';
8
9
 
9
10
  // Lazily load components for content surfaces.
10
11
  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';
@@ -9,8 +9,8 @@ import { inRange, addressFromA1Notation, addressToA1Notation, rangeFromA1Notatio
9
9
 
10
10
  describe('cell', () => {
11
11
  test('posToA1Notation', () => {
12
- expect(addressToA1Notation({ column: 0, row: 0 })).to.eq('A1');
13
- 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 });
14
14
  });
15
15
 
16
16
  test('rangeToA1Notation', () => {
@@ -55,19 +55,19 @@ describe('cell', () => {
55
55
  // Values.
56
56
  const cells: Record<string, any> = {};
57
57
  const setCell = (cell: string, value: any) => {
58
- const { column, row } = addressFromA1Notation(cell);
58
+ const { col, row } = addressFromA1Notation(cell);
59
59
  // Reallocate if > current bounds.
60
- if (column >= columns.length) {
61
- insertIndex(columns, column);
60
+ if (col >= columns.length) {
61
+ insertIndex(columns, col);
62
62
  }
63
63
  if (row >= rows.length) {
64
64
  insertIndex(rows, row);
65
65
  }
66
- const index = `${columns[column]}@${rows[row]}`;
66
+ const index = `${columns[col]}@${rows[row]}`;
67
67
  cells[index] = value;
68
68
  };
69
69
 
70
- expect(addressFromA1Notation('A1')).to.deep.eq({ column: 0, row: 0 });
70
+ expect(addressFromA1Notation('A1')).to.deep.eq({ col: 0, row: 0 });
71
71
 
72
72
  expect(columns).to.deep.eq(['a1', 'a2', 'a3', 'a4', 'a5']);
73
73
  insertIndex(columns, 7);
@@ -4,25 +4,34 @@
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
 
28
37
  export const addressFromA1Notation = (ref: string): CellAddress => {
@@ -30,7 +39,7 @@ export const addressFromA1Notation = (ref: string): CellAddress => {
30
39
  invariant(match, `Invalid notation: ${ref}`);
31
40
  return {
32
41
  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,
42
+ col: match[1].split('').reduce((acc, c) => acc * 26 + c.charCodeAt(0) - 'A'.charCodeAt(0) + 1, 0) - 1,
34
43
  };
35
44
  };
36
45
 
@@ -59,13 +68,13 @@ export const inRange = (range: CellRange | undefined, cell: CellAddress): boolea
59
68
  return false;
60
69
  }
61
70
 
62
- const { column: c1, row: r1 } = from;
63
- const { column: c2, row: r2 } = to;
71
+ const { col: c1, row: r1 } = from;
72
+ const { col: c2, row: r2 } = to;
64
73
  const cMin = Math.min(c1, c2);
65
74
  const cMax = Math.max(c1, c2);
66
75
  const rMin = Math.min(r1, r2);
67
76
  const rMax = Math.max(r1, r2);
68
77
 
69
- const { column, row } = cell;
70
- return column >= cMin && column <= cMax && row >= rMin && row <= rMax;
78
+ const { col, row } = cell;
79
+ return col >= cMin && col <= cMax && row >= rMin && row <= rMax;
71
80
  };
@@ -3,13 +3,16 @@
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 { type CellAddress, type CellRange, DEFAULT_COLUMNS, DEFAULT_ROWS, MAX_COLUMNS, MAX_ROWS } from './types';
9
+ import { type CreateSheetOptions, type SheetSize, SheetType } from '../types';
9
10
 
10
11
  // TODO(burdon): Factor out from dxos/protocols to new common package.
11
12
  export class ApiError extends Error {}
13
+
12
14
  export class ReadonlyException extends ApiError {}
15
+
13
16
  export class RangeException extends ApiError {
14
17
  constructor(n: number) {
15
18
  super();
@@ -28,11 +31,47 @@ export const createIndex = (length = 8): string => {
28
31
 
29
32
  export const createIndices = (length: number): string[] => Array.from({ length }).map(() => createIndex());
30
33
 
34
+ export const insertIndices = (indices: string[], i: number, n: number, max: number) => {
35
+ if (i + n > max) {
36
+ throw new RangeException(i + n);
37
+ }
38
+
39
+ const idx = createIndices(n);
40
+ indices.splice(i, 0, ...idx);
41
+ };
42
+
43
+ export const initialize = (
44
+ sheet: SheetType,
45
+ { rows = DEFAULT_ROWS, columns = DEFAULT_COLUMNS }: Partial<SheetSize> = {},
46
+ ) => {
47
+ if (!sheet.rows.length) {
48
+ insertIndices(sheet.rows, 0, rows, MAX_ROWS);
49
+ }
50
+ if (!sheet.columns.length) {
51
+ insertIndices(sheet.columns, 0, columns, MAX_COLUMNS);
52
+ }
53
+ };
54
+
55
+ export const createSheet = ({ title, ...size }: CreateSheetOptions = {}): SheetType => {
56
+ const sheet = create(SheetType, {
57
+ title,
58
+ cells: {},
59
+ rows: [],
60
+ columns: [],
61
+ rowMeta: {},
62
+ columnMeta: {},
63
+ formatting: {},
64
+ });
65
+
66
+ initialize(sheet, size);
67
+ return sheet;
68
+ };
69
+
31
70
  /**
32
71
  * E.g., "A1" => "CA2@CB3".
33
72
  */
34
73
  export const addressToIndex = (sheet: SheetType, cell: CellAddress): string => {
35
- return `${sheet.columns[cell.column]}@${sheet.rows[cell.row]}`;
74
+ return `${sheet.columns[cell.col]}@${sheet.rows[cell.row]}`;
36
75
  };
37
76
 
38
77
  /**
@@ -41,7 +80,7 @@ export const addressToIndex = (sheet: SheetType, cell: CellAddress): string => {
41
80
  export const addressFromIndex = (sheet: SheetType, idx: string): CellAddress => {
42
81
  const [column, row] = idx.split('@');
43
82
  return {
44
- column: sheet.columns.indexOf(column),
83
+ col: sheet.columns.indexOf(column),
45
84
  row: sheet.rows.indexOf(row),
46
85
  };
47
86
  };
@@ -61,22 +100,15 @@ export const rangeFromIndex = (sheet: SheetType, idx: string): CellRange => {
61
100
  return { from, to };
62
101
  };
63
102
 
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
-
103
+ /**
104
+ * Find closest cell to cursor.
105
+ */
74
106
  export const closest = (cursor: CellAddress, cells: CellAddress[]): CellAddress | undefined => {
75
107
  let closestCell: CellAddress | undefined;
76
108
  let closestDistance = Number.MAX_SAFE_INTEGER;
77
109
 
78
110
  for (const cell of cells) {
79
- const distance = Math.abs(cell.row - cursor.row) + Math.abs(cell.column - cursor.column);
111
+ const distance = Math.abs(cell.row - cursor.row) + Math.abs(cell.col - cursor.col);
80
112
  if (distance < closestDistance) {
81
113
  closestCell = cell;
82
114
  closestDistance = distance;
@@ -91,8 +123,8 @@ export const closest = (cursor: CellAddress, cells: CellAddress[]): CellAddress
91
123
  * Sorts primarily by row, then by column if rows are equal.
92
124
  */
93
125
  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);
126
+ const { row: rowA, col: columnA } = addressFromIndex(sheet, indexA);
127
+ const { row: rowB, col: columnB } = addressFromIndex(sheet, indexB);
96
128
 
97
129
  // Sort by row first, then by column.
98
130
  if (rowA !== rowB) {
@@ -0,0 +1,151 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import '@dxos-theme';
6
+ import React, { useEffect, useState } from 'react';
7
+
8
+ import { useSpace } from '@dxos/react-client/echo';
9
+ import { withClientProvider } from '@dxos/react-client/testing';
10
+ import { useThemeContext } from '@dxos/react-ui';
11
+ import {
12
+ createBasicExtensions,
13
+ createMarkdownExtensions,
14
+ createThemeExtensions,
15
+ decorateMarkdown,
16
+ useTextEditor,
17
+ } from '@dxos/react-ui-editor';
18
+ import { withTheme, withLayout } from '@dxos/storybook-utils';
19
+ import { nonNullable } from '@dxos/util';
20
+
21
+ import { compute } from './compute';
22
+ import { Sheet } from '../components';
23
+ import { type ComputeNode } from '../graph';
24
+ import { useComputeGraph, useSheetModel } from '../hooks';
25
+ import { useTestSheet, withGraphDecorator } from '../testing';
26
+ import { SheetType } from '../types';
27
+
28
+ const str = (...lines: string[]) => lines.join('\n');
29
+
30
+ type EditorProps = {
31
+ text?: string;
32
+ };
33
+
34
+ // TODO(burdon): Implement named expressions.
35
+ // https://hyperformula.handsontable.com/guide/cell-references.html
36
+
37
+ const DOC_NAME = 'Test Doc';
38
+ const SHEET_NAME = 'Test Sheet';
39
+
40
+ const Editor = ({ text }: EditorProps) => {
41
+ const { themeMode } = useThemeContext();
42
+ const space = useSpace();
43
+ const graph = useComputeGraph(space);
44
+ const [node, setNode] = useState<ComputeNode>();
45
+ // TODO(burdon): Virtualize SheetModel.
46
+ useEffect(() => {
47
+ if (graph) {
48
+ setNode(graph.getOrCreateNode(DOC_NAME));
49
+ }
50
+ }, [graph]);
51
+ const { parentRef, focusAttributes } = useTextEditor(
52
+ () => ({
53
+ initialValue: text,
54
+ extensions: [
55
+ createBasicExtensions(),
56
+ createMarkdownExtensions({ themeMode }),
57
+ createThemeExtensions({ themeMode, syntaxHighlighting: true }),
58
+ node && compute(node),
59
+ decorateMarkdown(),
60
+ ].filter(nonNullable),
61
+ }),
62
+ [node, themeMode],
63
+ );
64
+
65
+ return <div className='w-[40rem] overflow-hidden' ref={parentRef} {...focusAttributes} />;
66
+ };
67
+
68
+ const Grid = () => {
69
+ const space = useSpace();
70
+ const graph = useComputeGraph(space);
71
+ const sheet = useTestSheet(space, graph, { title: SHEET_NAME });
72
+ const model = useSheetModel(space, sheet);
73
+ useEffect(() => {
74
+ if (model) {
75
+ model.setValues({ A1: { value: 100 }, A2: { value: 200 }, A3: { value: 300 }, A5: { value: '=SUM(A1:A3)' } });
76
+ }
77
+ }, [model]);
78
+
79
+ if (!space || !sheet) {
80
+ return null;
81
+ }
82
+
83
+ return (
84
+ <div className='flex w-[40rem] overflow-hidden'>
85
+ <Sheet.Root space={space} sheet={sheet}>
86
+ <Sheet.Main classNames='border border-separator' />
87
+ </Sheet.Root>
88
+ </div>
89
+ );
90
+ };
91
+
92
+ const Story = (props: EditorProps) => {
93
+ return (
94
+ <div className='grid grid-rows-2'>
95
+ <Editor {...props} />
96
+ <Grid />
97
+ </div>
98
+ );
99
+ };
100
+
101
+ export default {
102
+ title: 'plugin-sheet/extensions',
103
+ decorators: [
104
+ withClientProvider({ types: [SheetType], createIdentity: true, createSpace: true }),
105
+ withGraphDecorator,
106
+ withTheme,
107
+ withLayout({ fullscreen: true, classNames: 'justify-center' }),
108
+ ],
109
+ parameters: { layout: 'fullscreen' },
110
+ };
111
+
112
+ export const Default = {
113
+ render: Editor,
114
+ args: {
115
+ text: str(
116
+ //
117
+ '# Compute Graph',
118
+ '',
119
+ 'This is a compute expression:',
120
+ '',
121
+ '```dx',
122
+ '=SUM(1, 2)',
123
+ '```',
124
+ '',
125
+ 'It should change in realtime.',
126
+ '',
127
+ '```dx',
128
+ '=SUM(3, 5)',
129
+ '```',
130
+ '',
131
+ '',
132
+ ),
133
+ },
134
+ };
135
+
136
+ export const Graph = {
137
+ render: Story,
138
+ args: {
139
+ text: str(
140
+ //
141
+ '# Compute Graph',
142
+ '',
143
+ 'The total projected cost is:',
144
+ '',
145
+ '```dx',
146
+ `="${SHEET_NAME}"!A5`,
147
+ '```',
148
+ '',
149
+ ),
150
+ },
151
+ };