@dxos/plugin-sheet 0.8.4-main.ae835ea → 0.8.4-main.bcb3aa67d6

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 (287) hide show
  1. package/dist/lib/browser/chunk-CBNIKBPQ.mjs +278 -0
  2. package/dist/lib/browser/chunk-CBNIKBPQ.mjs.map +7 -0
  3. package/dist/lib/browser/chunk-GZ2EV64I.mjs +118 -0
  4. package/dist/lib/browser/chunk-GZ2EV64I.mjs.map +7 -0
  5. package/dist/lib/browser/chunk-J5LGTIGS.mjs +10 -0
  6. package/dist/lib/browser/chunk-J5LGTIGS.mjs.map +7 -0
  7. package/dist/lib/browser/drop-axis-PB7F3LBV.mjs +23 -0
  8. package/dist/lib/browser/drop-axis-PB7F3LBV.mjs.map +7 -0
  9. package/dist/lib/browser/index.mjs +122 -114
  10. package/dist/lib/browser/index.mjs.map +4 -4
  11. package/dist/lib/browser/insert-axis-DH5CO4AY.mjs +16 -0
  12. package/dist/lib/browser/insert-axis-DH5CO4AY.mjs.map +7 -0
  13. package/dist/lib/browser/meta.json +1 -1
  14. package/dist/lib/browser/operations/index.mjs +13 -0
  15. package/dist/lib/browser/operations/index.mjs.map +7 -0
  16. package/dist/lib/browser/restore-axis-Y5H5IOC6.mjs +16 -0
  17. package/dist/lib/browser/restore-axis-Y5H5IOC6.mjs.map +7 -0
  18. package/dist/lib/browser/scroll-to-anchor-MN36E3X7.mjs +65 -0
  19. package/dist/lib/browser/scroll-to-anchor-MN36E3X7.mjs.map +7 -0
  20. package/dist/lib/browser/types/index.mjs +4 -2
  21. package/dist/lib/node-esm/chunk-3ZYLQWHC.mjs +279 -0
  22. package/dist/lib/node-esm/chunk-3ZYLQWHC.mjs.map +7 -0
  23. package/dist/lib/node-esm/chunk-74MOADQ7.mjs +119 -0
  24. package/dist/lib/node-esm/chunk-74MOADQ7.mjs.map +7 -0
  25. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +11 -0
  26. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs.map +7 -0
  27. package/dist/lib/node-esm/drop-axis-UBBQCU6D.mjs +24 -0
  28. package/dist/lib/node-esm/drop-axis-UBBQCU6D.mjs.map +7 -0
  29. package/dist/lib/node-esm/index.mjs +122 -114
  30. package/dist/lib/node-esm/index.mjs.map +4 -4
  31. package/dist/lib/node-esm/insert-axis-S7BR2RSJ.mjs +17 -0
  32. package/dist/lib/node-esm/insert-axis-S7BR2RSJ.mjs.map +7 -0
  33. package/dist/lib/node-esm/meta.json +1 -1
  34. package/dist/lib/node-esm/operations/index.mjs +14 -0
  35. package/dist/lib/node-esm/operations/index.mjs.map +7 -0
  36. package/dist/lib/node-esm/restore-axis-6B25SOHX.mjs +17 -0
  37. package/dist/lib/node-esm/restore-axis-6B25SOHX.mjs.map +7 -0
  38. package/dist/lib/node-esm/scroll-to-anchor-YLB4MYGF.mjs +66 -0
  39. package/dist/lib/node-esm/scroll-to-anchor-YLB4MYGF.mjs.map +7 -0
  40. package/dist/lib/node-esm/types/index.mjs +4 -2
  41. package/dist/types/src/SheetPlugin.d.ts +2 -1
  42. package/dist/types/src/SheetPlugin.d.ts.map +1 -1
  43. package/dist/types/src/capabilities/anchor-sort.d.ts +4 -4
  44. package/dist/types/src/capabilities/anchor-sort.d.ts.map +1 -1
  45. package/dist/types/src/capabilities/compute-graph-registry.d.ts +3 -2
  46. package/dist/types/src/capabilities/compute-graph-registry.d.ts.map +1 -1
  47. package/dist/types/src/capabilities/index.d.ts +9 -9
  48. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  49. package/dist/types/src/capabilities/markdown.d.ts +3 -2
  50. package/dist/types/src/capabilities/markdown.d.ts.map +1 -1
  51. package/dist/types/src/capabilities/operation-handler.d.ts +6 -0
  52. package/dist/types/src/capabilities/operation-handler.d.ts.map +1 -0
  53. package/dist/types/src/capabilities/react-surface.d.ts +3 -2
  54. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  55. package/dist/types/src/capabilities/state.d.ts +6 -0
  56. package/dist/types/src/capabilities/state.d.ts.map +1 -0
  57. package/dist/types/src/capabilities/undo-mappings.d.ts +5 -0
  58. package/dist/types/src/capabilities/undo-mappings.d.ts.map +1 -0
  59. package/dist/types/src/components/ComputeGraph/compute-graph.stories.d.ts.map +1 -1
  60. package/dist/types/src/components/Sheet/Sheet.d.ts +29 -0
  61. package/dist/types/src/components/Sheet/Sheet.d.ts.map +1 -0
  62. package/dist/types/src/components/Sheet/index.d.ts +2 -0
  63. package/dist/types/src/components/Sheet/index.d.ts.map +1 -0
  64. package/dist/types/src/components/{GridSheet → SheetContent}/SheetCellEditor.stories.d.ts +1 -1
  65. package/dist/types/src/components/SheetContent/SheetCellEditor.stories.d.ts.map +1 -0
  66. package/dist/types/src/components/SheetContent/SheetContent.d.ts +10 -0
  67. package/dist/types/src/components/SheetContent/SheetContent.d.ts.map +1 -0
  68. package/dist/types/src/components/SheetContent/SheetContent.stories.d.ts +63 -0
  69. package/dist/types/src/components/SheetContent/SheetContent.stories.d.ts.map +1 -0
  70. package/dist/types/src/components/SheetContent/index.d.ts +2 -0
  71. package/dist/types/src/components/SheetContent/index.d.ts.map +1 -0
  72. package/dist/types/src/components/SheetContent/util.d.ts.map +1 -0
  73. package/dist/types/src/components/{SheetContext/SheetContext.d.ts → SheetRoot/SheetRoot.d.ts} +7 -5
  74. package/dist/types/src/components/SheetRoot/SheetRoot.d.ts.map +1 -0
  75. package/dist/types/src/components/SheetRoot/index.d.ts +2 -0
  76. package/dist/types/src/components/SheetRoot/index.d.ts.map +1 -0
  77. package/dist/types/src/components/SheetStatusbar/SheetStatusbar.d.ts +10 -0
  78. package/dist/types/src/components/SheetStatusbar/SheetStatusbar.d.ts.map +1 -0
  79. package/dist/types/src/components/SheetStatusbar/index.d.ts +2 -0
  80. package/dist/types/src/components/SheetStatusbar/index.d.ts.map +1 -0
  81. package/dist/types/src/components/SheetToolbar/SheetToolbar.d.ts +9 -5
  82. package/dist/types/src/components/SheetToolbar/SheetToolbar.d.ts.map +1 -1
  83. package/dist/types/src/components/SheetToolbar/SheetToolbar.stories.d.ts +72 -66
  84. package/dist/types/src/components/SheetToolbar/SheetToolbar.stories.d.ts.map +1 -1
  85. package/dist/types/src/components/SheetToolbar/align.d.ts +13 -20
  86. package/dist/types/src/components/SheetToolbar/align.d.ts.map +1 -1
  87. package/dist/types/src/components/SheetToolbar/style.d.ts +13 -19
  88. package/dist/types/src/components/SheetToolbar/style.d.ts.map +1 -1
  89. package/dist/types/src/components/SheetToolbar/useToolbarState.d.ts +14 -1
  90. package/dist/types/src/components/SheetToolbar/useToolbarState.d.ts.map +1 -1
  91. package/dist/types/src/components/index.d.ts +1 -4
  92. package/dist/types/src/components/index.d.ts.map +1 -1
  93. package/dist/types/src/{components → containers}/RangeList/RangeList.d.ts +1 -1
  94. package/dist/types/src/{components → containers}/RangeList/RangeList.d.ts.map +1 -1
  95. package/dist/types/src/containers/RangeList/index.d.ts +3 -0
  96. package/dist/types/src/containers/RangeList/index.d.ts.map +1 -0
  97. package/dist/types/src/containers/SheetContainer/SheetContainer.d.ts +12 -0
  98. package/dist/types/src/containers/SheetContainer/SheetContainer.d.ts.map +1 -0
  99. package/dist/types/src/containers/SheetContainer/SheetContainer.stories.d.ts +58 -0
  100. package/dist/types/src/containers/SheetContainer/SheetContainer.stories.d.ts.map +1 -0
  101. package/dist/types/src/{components → containers}/SheetContainer/index.d.ts.map +1 -1
  102. package/dist/types/src/containers/index.d.ts +4 -0
  103. package/dist/types/src/containers/index.d.ts.map +1 -0
  104. package/dist/types/src/extensions/compute.stories.d.ts.map +1 -1
  105. package/dist/types/src/extensions/editor/sheet-extension.d.ts.map +1 -1
  106. package/dist/types/src/index.d.ts +1 -1
  107. package/dist/types/src/index.d.ts.map +1 -1
  108. package/dist/types/src/integrations/thread-ranges.d.ts +0 -2
  109. package/dist/types/src/integrations/thread-ranges.d.ts.map +1 -1
  110. package/dist/types/src/meta.d.ts +2 -2
  111. package/dist/types/src/meta.d.ts.map +1 -1
  112. package/dist/types/src/model/sheet-model.d.ts +3 -3
  113. package/dist/types/src/model/sheet-model.d.ts.map +1 -1
  114. package/dist/types/src/model/testing.d.ts +1 -1
  115. package/dist/types/src/model/testing.d.ts.map +1 -1
  116. package/dist/types/src/model/useSheetModel.d.ts +1 -1
  117. package/dist/types/src/model/useSheetModel.d.ts.map +1 -1
  118. package/dist/types/src/operations/definitions.d.ts +45 -0
  119. package/dist/types/src/operations/definitions.d.ts.map +1 -0
  120. package/dist/types/src/operations/drop-axis.d.ts +5 -0
  121. package/dist/types/src/operations/drop-axis.d.ts.map +1 -0
  122. package/dist/types/src/operations/index.d.ts +4 -0
  123. package/dist/types/src/operations/index.d.ts.map +1 -0
  124. package/dist/types/src/operations/insert-axis.d.ts +5 -0
  125. package/dist/types/src/operations/insert-axis.d.ts.map +1 -0
  126. package/dist/types/src/operations/restore-axis.d.ts +5 -0
  127. package/dist/types/src/operations/restore-axis.d.ts.map +1 -0
  128. package/dist/types/src/operations/scroll-to-anchor.d.ts +5 -0
  129. package/dist/types/src/operations/scroll-to-anchor.d.ts.map +1 -0
  130. package/dist/types/src/serializer.d.ts +1 -1
  131. package/dist/types/src/serializer.d.ts.map +1 -1
  132. package/dist/types/src/testing/data.d.ts +1 -1
  133. package/dist/types/src/testing/data.d.ts.map +1 -1
  134. package/dist/types/src/testing/testing.d.ts +16 -16
  135. package/dist/types/src/testing/testing.d.ts.map +1 -1
  136. package/dist/types/src/translations.d.ts +38 -35
  137. package/dist/types/src/translations.d.ts.map +1 -1
  138. package/dist/types/src/types/Sheet.d.ts +41 -35
  139. package/dist/types/src/types/Sheet.d.ts.map +1 -1
  140. package/dist/types/src/types/capabilities.d.ts +18 -0
  141. package/dist/types/src/types/capabilities.d.ts.map +1 -0
  142. package/dist/types/src/types/index.d.ts +1 -0
  143. package/dist/types/src/types/index.d.ts.map +1 -1
  144. package/dist/types/src/types/types.d.ts +2 -68
  145. package/dist/types/src/types/types.d.ts.map +1 -1
  146. package/dist/types/src/types/util.d.ts +2 -1
  147. package/dist/types/src/types/util.d.ts.map +1 -1
  148. package/dist/types/tsconfig.tsbuildinfo +1 -1
  149. package/package.json +93 -68
  150. package/src/SheetPlugin.tsx +63 -67
  151. package/src/capabilities/anchor-sort.ts +20 -15
  152. package/src/capabilities/compute-graph-registry.ts +18 -14
  153. package/src/capabilities/index.ts +12 -8
  154. package/src/capabilities/markdown.ts +20 -13
  155. package/src/capabilities/operation-handler.ts +16 -0
  156. package/src/capabilities/react-surface.tsx +38 -29
  157. package/src/capabilities/state.ts +29 -0
  158. package/src/capabilities/undo-mappings.ts +30 -0
  159. package/src/components/ComputeGraph/compute-graph.stories.tsx +13 -8
  160. package/src/components/Sheet/Sheet.tsx +20 -0
  161. package/src/components/Sheet/index.ts +5 -0
  162. package/src/components/{GridSheet → SheetContent}/SheetCellEditor.stories.tsx +10 -7
  163. package/src/components/{GridSheet/GridSheet.stories.tsx → SheetContent/SheetContent.stories.tsx} +16 -15
  164. package/src/components/{GridSheet/GridSheet.tsx → SheetContent/SheetContent.tsx} +80 -50
  165. package/src/components/{RangeList → SheetContent}/index.ts +1 -1
  166. package/src/components/{GridSheet → SheetContent}/util.ts +15 -9
  167. package/src/components/{SheetContext/SheetContext.tsx → SheetRoot/SheetRoot.tsx} +48 -41
  168. package/src/components/{GridSheet → SheetRoot}/index.ts +1 -1
  169. package/src/components/{FunctionEditor/FunctionEditor.tsx → SheetStatusbar/SheetStatusbar.tsx} +18 -6
  170. package/src/components/{FunctionEditor → SheetStatusbar}/index.ts +1 -1
  171. package/src/components/SheetToolbar/SheetToolbar.stories.tsx +4 -4
  172. package/src/components/SheetToolbar/SheetToolbar.tsx +50 -39
  173. package/src/components/SheetToolbar/align.ts +48 -23
  174. package/src/components/SheetToolbar/style.ts +51 -21
  175. package/src/components/SheetToolbar/useToolbarState.ts +22 -5
  176. package/src/components/index.ts +1 -7
  177. package/src/{components → containers}/RangeList/RangeList.tsx +18 -14
  178. package/src/containers/RangeList/index.ts +7 -0
  179. package/src/containers/SheetContainer/SheetContainer.stories.tsx +109 -0
  180. package/src/containers/SheetContainer/SheetContainer.tsx +57 -0
  181. package/src/{components → containers}/SheetContainer/index.ts +1 -1
  182. package/src/containers/index.ts +8 -0
  183. package/src/extensions/compute.stories.tsx +25 -15
  184. package/src/extensions/compute.ts +1 -1
  185. package/src/extensions/editor/sheet-extension.ts +16 -13
  186. package/src/index.ts +1 -1
  187. package/src/integrations/thread-ranges.ts +17 -60
  188. package/src/meta.ts +3 -3
  189. package/src/model/sheet-model.test.ts +3 -3
  190. package/src/model/sheet-model.ts +79 -47
  191. package/src/model/testing.ts +1 -1
  192. package/src/model/useSheetModel.ts +1 -1
  193. package/src/operations/definitions.ts +73 -0
  194. package/src/operations/drop-axis.ts +26 -0
  195. package/src/operations/index.ts +14 -0
  196. package/src/operations/insert-axis.ts +19 -0
  197. package/src/operations/restore-axis.ts +19 -0
  198. package/src/operations/scroll-to-anchor.ts +31 -0
  199. package/src/playwright/playwright.config.ts +1 -1
  200. package/src/playwright/sheet.spec.ts +2 -1
  201. package/src/sanity.test.ts +6 -3
  202. package/src/serializer.ts +2 -2
  203. package/src/testing/data.ts +1 -1
  204. package/src/testing/testing.tsx +2 -2
  205. package/src/translations.ts +38 -35
  206. package/src/types/Sheet.ts +31 -31
  207. package/src/types/capabilities.ts +26 -0
  208. package/src/types/index.ts +1 -0
  209. package/src/types/sheet-range-types.ts +3 -3
  210. package/src/types/types.ts +4 -40
  211. package/src/types/util.ts +2 -1
  212. package/dist/lib/browser/SheetContainer-GTINUSNB.mjs +0 -349
  213. package/dist/lib/browser/SheetContainer-GTINUSNB.mjs.map +0 -7
  214. package/dist/lib/browser/anchor-sort-R5CB37J7.mjs +0 -24
  215. package/dist/lib/browser/anchor-sort-R5CB37J7.mjs.map +0 -7
  216. package/dist/lib/browser/chunk-73AV3NH6.mjs +0 -15
  217. package/dist/lib/browser/chunk-73AV3NH6.mjs.map +0 -7
  218. package/dist/lib/browser/chunk-7VEWYJJN.mjs +0 -234
  219. package/dist/lib/browser/chunk-7VEWYJJN.mjs.map +0 -7
  220. package/dist/lib/browser/chunk-DVJ3QW3F.mjs +0 -907
  221. package/dist/lib/browser/chunk-DVJ3QW3F.mjs.map +0 -7
  222. package/dist/lib/browser/chunk-FWFAAGXL.mjs +0 -28
  223. package/dist/lib/browser/chunk-FWFAAGXL.mjs.map +0 -7
  224. package/dist/lib/browser/chunk-LS6D4GG7.mjs +0 -850
  225. package/dist/lib/browser/chunk-LS6D4GG7.mjs.map +0 -7
  226. package/dist/lib/browser/compute-graph-registry-AP5RA7W3.mjs +0 -21
  227. package/dist/lib/browser/compute-graph-registry-AP5RA7W3.mjs.map +0 -7
  228. package/dist/lib/browser/intent-resolver-66OAYVQF.mjs +0 -56
  229. package/dist/lib/browser/intent-resolver-66OAYVQF.mjs.map +0 -7
  230. package/dist/lib/browser/markdown-B6VKYY2S.mjs +0 -26
  231. package/dist/lib/browser/markdown-B6VKYY2S.mjs.map +0 -7
  232. package/dist/lib/browser/react-surface-F3VQPGDV.mjs +0 -53
  233. package/dist/lib/browser/react-surface-F3VQPGDV.mjs.map +0 -7
  234. package/dist/lib/node-esm/SheetContainer-PW4KNZME.mjs +0 -350
  235. package/dist/lib/node-esm/SheetContainer-PW4KNZME.mjs.map +0 -7
  236. package/dist/lib/node-esm/anchor-sort-HEND452H.mjs +0 -25
  237. package/dist/lib/node-esm/anchor-sort-HEND452H.mjs.map +0 -7
  238. package/dist/lib/node-esm/chunk-44YTKTMP.mjs +0 -16
  239. package/dist/lib/node-esm/chunk-44YTKTMP.mjs.map +0 -7
  240. package/dist/lib/node-esm/chunk-4H2EHVWE.mjs +0 -908
  241. package/dist/lib/node-esm/chunk-4H2EHVWE.mjs.map +0 -7
  242. package/dist/lib/node-esm/chunk-4QV4AGWK.mjs +0 -236
  243. package/dist/lib/node-esm/chunk-4QV4AGWK.mjs.map +0 -7
  244. package/dist/lib/node-esm/chunk-HILDMVPL.mjs +0 -29
  245. package/dist/lib/node-esm/chunk-HILDMVPL.mjs.map +0 -7
  246. package/dist/lib/node-esm/chunk-LYUIM3QG.mjs +0 -851
  247. package/dist/lib/node-esm/chunk-LYUIM3QG.mjs.map +0 -7
  248. package/dist/lib/node-esm/compute-graph-registry-UMQ5UYCL.mjs +0 -22
  249. package/dist/lib/node-esm/compute-graph-registry-UMQ5UYCL.mjs.map +0 -7
  250. package/dist/lib/node-esm/intent-resolver-VNKIMQQT.mjs +0 -57
  251. package/dist/lib/node-esm/intent-resolver-VNKIMQQT.mjs.map +0 -7
  252. package/dist/lib/node-esm/markdown-VKY7HXU2.mjs +0 -27
  253. package/dist/lib/node-esm/markdown-VKY7HXU2.mjs.map +0 -7
  254. package/dist/lib/node-esm/react-surface-GGX76V2Y.mjs +0 -54
  255. package/dist/lib/node-esm/react-surface-GGX76V2Y.mjs.map +0 -7
  256. package/dist/types/src/capabilities/capabilities.d.ts +0 -5
  257. package/dist/types/src/capabilities/capabilities.d.ts.map +0 -1
  258. package/dist/types/src/capabilities/intent-resolver.d.ts +0 -4
  259. package/dist/types/src/capabilities/intent-resolver.d.ts.map +0 -1
  260. package/dist/types/src/components/FunctionEditor/FunctionEditor.d.ts +0 -3
  261. package/dist/types/src/components/FunctionEditor/FunctionEditor.d.ts.map +0 -1
  262. package/dist/types/src/components/FunctionEditor/index.d.ts +0 -2
  263. package/dist/types/src/components/FunctionEditor/index.d.ts.map +0 -1
  264. package/dist/types/src/components/GridSheet/GridSheet.d.ts +0 -3
  265. package/dist/types/src/components/GridSheet/GridSheet.d.ts.map +0 -1
  266. package/dist/types/src/components/GridSheet/GridSheet.stories.d.ts +0 -54
  267. package/dist/types/src/components/GridSheet/GridSheet.stories.d.ts.map +0 -1
  268. package/dist/types/src/components/GridSheet/SheetCellEditor.stories.d.ts.map +0 -1
  269. package/dist/types/src/components/GridSheet/index.d.ts +0 -2
  270. package/dist/types/src/components/GridSheet/index.d.ts.map +0 -1
  271. package/dist/types/src/components/GridSheet/util.d.ts.map +0 -1
  272. package/dist/types/src/components/RangeList/index.d.ts +0 -2
  273. package/dist/types/src/components/RangeList/index.d.ts.map +0 -1
  274. package/dist/types/src/components/SheetContainer/SheetContainer.d.ts +0 -11
  275. package/dist/types/src/components/SheetContainer/SheetContainer.d.ts.map +0 -1
  276. package/dist/types/src/components/SheetContainer/SheetContainer.stories.d.ts +0 -55
  277. package/dist/types/src/components/SheetContainer/SheetContainer.stories.d.ts.map +0 -1
  278. package/dist/types/src/components/SheetContext/SheetContext.d.ts.map +0 -1
  279. package/dist/types/src/components/SheetContext/index.d.ts +0 -2
  280. package/dist/types/src/components/SheetContext/index.d.ts.map +0 -1
  281. package/src/capabilities/capabilities.ts +0 -14
  282. package/src/capabilities/intent-resolver.ts +0 -38
  283. package/src/components/SheetContainer/SheetContainer.stories.tsx +0 -90
  284. package/src/components/SheetContainer/SheetContainer.tsx +0 -40
  285. package/src/components/SheetContext/index.ts +0 -5
  286. /package/dist/types/src/components/{GridSheet → SheetContent}/util.d.ts +0 -0
  287. /package/dist/types/src/{components → containers}/SheetContainer/index.d.ts +0 -0
@@ -5,8 +5,7 @@
5
5
  import React, { type PropsWithChildren, createContext, useCallback, useContext, useState } from 'react';
6
6
 
7
7
  import { type CellAddress, type CellRange, type CompleteCellRange, type ComputeGraph } from '@dxos/compute';
8
- import { invariant } from '@dxos/invariant';
9
- import { fullyQualifiedId } from '@dxos/react-client/echo';
8
+ import { raise } from '@dxos/debug';
10
9
  import {
11
10
  Grid,
12
11
  type GridContentProps,
@@ -16,11 +15,11 @@ import {
16
15
  } from '@dxos/react-ui-grid';
17
16
 
18
17
  import { type SheetModel, useSheetModel } from '../../model';
19
- import { type Sheet } from '../../types';
18
+ import { type Sheet } from '#types';
20
19
 
21
20
  export type SheetContextValue = {
22
21
  id: string;
23
-
22
+ attendableId: string;
24
23
  model: SheetModel;
25
24
 
26
25
  // Cursor state.
@@ -39,29 +38,62 @@ export type SheetContextValue = {
39
38
  activeRefs: GridContentProps['activeRefs'];
40
39
  setActiveRefs: (activeRefs: GridContentProps['activeRefs']) => void;
41
40
 
41
+ // Flags
42
+ ignoreAttention?: boolean;
43
+
42
44
  // Events.
43
45
  // TODO(burdon): Generalize.
44
46
  onInfo?: () => void;
45
-
46
- // Flags
47
- ignoreAttention?: boolean;
48
47
  };
49
48
 
49
+ // TODO(burdon): Use radix context.
50
50
  const SheetContext = createContext<SheetContextValue | undefined>(undefined);
51
51
 
52
52
  export const useSheetContext = (): SheetContextValue => {
53
- const context = useContext(SheetContext);
54
- invariant(context);
55
- return context;
53
+ return useContext(SheetContext) ?? raise(new Error('Missing SheetContext'));
54
+ };
55
+
56
+ export type SheetRootProps = {
57
+ graph: ComputeGraph;
58
+ sheet: Sheet.Sheet;
59
+ attendableId: string;
60
+ readonly?: boolean;
61
+ ignoreAttention?: boolean;
62
+ } & Pick<SheetContextValue, 'onInfo'>;
63
+
64
+ export const SheetRoot = ({
65
+ children,
66
+ graph,
67
+ sheet,
68
+ attendableId,
69
+ readonly,
70
+ ignoreAttention,
71
+ onInfo,
72
+ }: PropsWithChildren<SheetRootProps>) => {
73
+ const model = useSheetModel(graph, sheet, { readonly });
74
+ if (!model) {
75
+ return null;
76
+ }
77
+
78
+ return (
79
+ <Grid.Root id={attendableId}>
80
+ <SheetProviderImpl model={model} attendableId={attendableId} onInfo={onInfo} ignoreAttention={ignoreAttention}>
81
+ {children}
82
+ </SheetProviderImpl>
83
+ </Grid.Root>
84
+ );
56
85
  };
57
86
 
58
87
  const SheetProviderImpl = ({
88
+ __gridScope,
89
+ children,
90
+ attendableId,
91
+ ignoreAttention,
59
92
  model,
60
93
  onInfo,
61
- ignoreAttention,
62
- children,
63
- __gridScope,
64
- }: GridScopedProps<PropsWithChildren<Pick<SheetContextValue, 'onInfo' | 'model' | 'ignoreAttention'>>>) => {
94
+ }: GridScopedProps<
95
+ PropsWithChildren<Pick<SheetContextValue, 'attendableId' | 'ignoreAttention' | 'model' | 'onInfo'>>
96
+ >) => {
65
97
  const { id, editing, setEditing } = useGridContext('SheetProvider', __gridScope);
66
98
 
67
99
  const [cursor, setCursorInternal] = useState<CellAddress>();
@@ -92,6 +124,7 @@ const SheetProviderImpl = ({
92
124
  <SheetContext.Provider
93
125
  value={{
94
126
  id,
127
+ attendableId,
95
128
  model,
96
129
  editing,
97
130
  setEditing,
@@ -102,38 +135,12 @@ const SheetProviderImpl = ({
102
135
  cursorFallbackRange,
103
136
  activeRefs,
104
137
  setActiveRefs,
138
+ ignoreAttention,
105
139
  // TODO(burdon): Change to event.
106
140
  onInfo,
107
- ignoreAttention,
108
141
  }}
109
142
  >
110
143
  {children}
111
144
  </SheetContext.Provider>
112
145
  );
113
146
  };
114
-
115
- export type SheetProviderProps = {
116
- graph: ComputeGraph;
117
- sheet: Sheet.Sheet;
118
- readonly?: boolean;
119
- ignoreAttention?: boolean;
120
- } & Pick<SheetContextValue, 'onInfo'>;
121
-
122
- export const SheetProvider = ({
123
- children,
124
- graph,
125
- sheet,
126
- readonly,
127
- ignoreAttention,
128
- onInfo,
129
- }: PropsWithChildren<SheetProviderProps>) => {
130
- const model = useSheetModel(graph, sheet, { readonly });
131
-
132
- return !model ? null : (
133
- <Grid.Root id={fullyQualifiedId(sheet)}>
134
- <SheetProviderImpl model={model} onInfo={onInfo} ignoreAttention={ignoreAttention}>
135
- {children}
136
- </SheetProviderImpl>
137
- </Grid.Root>
138
- );
139
- };
@@ -2,4 +2,4 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- export * from './GridSheet';
5
+ export * from './SheetRoot';
@@ -7,10 +7,15 @@ import React from 'react';
7
7
  import { addressToA1Notation, isFormula, rangeToA1Notation } from '@dxos/compute';
8
8
  import { Icon } from '@dxos/react-ui';
9
9
 
10
- import { mapFormulaIndicesToRefs } from '../../types';
11
- import { useSheetContext } from '../SheetContext';
10
+ import { composable, composableProps, mx } from '@dxos/ui-theme';
12
11
 
13
- export const FunctionEditor = () => {
12
+ import { mapFormulaIndicesToRefs } from '#types';
13
+ import { useSheetContext } from '../SheetRoot';
14
+
15
+ export type SheetStatusbarProps = {};
16
+
17
+ export const SheetStatusbar = composable<HTMLDivElement, SheetStatusbarProps>((props, forwardedRef) => {
18
+ const { className, ...rest } = composableProps(props);
14
19
  const { model, cursor, range } = useSheetContext();
15
20
 
16
21
  let value;
@@ -26,16 +31,23 @@ export const FunctionEditor = () => {
26
31
  }
27
32
 
28
33
  return (
29
- <div className='flex shrink-0 justify-between items-center px-4 py-1 text-sm bg-toolbarSurface border-bs !border-subduedSeparator'>
34
+ <div
35
+ ref={forwardedRef}
36
+ {...rest}
37
+ className={mx(
38
+ 'flex shrink-0 justify-between items-center px-4 py-1 text-sm bg-toolbar-surface border-y !border-subdued-separator',
39
+ className,
40
+ )}
41
+ >
30
42
  <div className='flex gap-4 items-center'>
31
43
  <div className='flex w-16 items-center font-mono'>
32
44
  {(range && rangeToA1Notation(range)) || (cursor && addressToA1Notation(cursor))}
33
45
  </div>
34
46
  <div className='flex gap-2 items-center'>
35
- <Icon icon='ph--function--regular' classNames={['text-greenText', formula ? 'visible' : 'invisible']} />
47
+ <Icon icon='ph--function--regular' classNames={['text-green-text', formula ? 'visible' : 'invisible']} />
36
48
  <span className='font-mono'>{value}</span>
37
49
  </div>
38
50
  </div>
39
51
  </div>
40
52
  );
41
- };
53
+ });
@@ -2,4 +2,4 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- export * from './FunctionEditor';
5
+ export * from './SheetStatusbar';
@@ -5,23 +5,23 @@
5
5
  import { type Meta, type StoryObj } from '@storybook/react-vite';
6
6
  import React from 'react';
7
7
 
8
- import { withTheme } from '@dxos/react-ui/testing';
8
+ import { withLayout, withTheme } from '@dxos/react-ui/testing';
9
9
 
10
10
  import { translations } from '../../translations';
11
11
 
12
12
  import { SheetToolbar } from './SheetToolbar';
13
13
 
14
14
  const DefaultStory = () => {
15
- // TODO(wittjosiah): Depends on SheetProvider.
15
+ // TODO(wittjosiah): Depends on SheetRoot.
16
16
  // return <SheetToolbar id='test' />;
17
17
  return <>TODO</>;
18
18
  };
19
19
 
20
20
  const meta = {
21
- title: 'plugins/plugin-sheet/Toolbar',
21
+ title: 'plugins/plugin-sheet/components/Toolbar',
22
22
  component: SheetToolbar as any,
23
23
  render: DefaultStory,
24
- decorators: [withTheme],
24
+ decorators: [withTheme(), withLayout({ layout: 'fullscreen' })],
25
25
  parameters: {
26
26
  layout: 'fullscreen',
27
27
  translations,
@@ -2,36 +2,41 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { Rx } from '@effect-rx/rx-react';
6
- import React, { type PropsWithChildren, useMemo } from 'react';
5
+ import { Atom, type Registry, RegistryContext } from '@effect-atom/atom-react';
6
+ import React, { useContext, useMemo } from 'react';
7
7
 
8
- import { useAppGraph } from '@dxos/app-framework';
8
+ import { useAppGraph } from '@dxos/app-toolkit/ui';
9
9
  import { type CompleteCellRange } from '@dxos/compute';
10
- import {
11
- type ActionGraphProps,
12
- MenuProvider,
13
- ToolbarMenu,
14
- createGapSeparator,
15
- rxFromSignal,
16
- useMenuActions,
17
- } from '@dxos/react-ui-menu';
10
+ import { type ActionGraphProps, Menu, createGapSeparator, useMenuActions } from '@dxos/react-ui-menu';
11
+ import { composable, composableProps } from '@dxos/ui-theme';
18
12
 
19
13
  import { type SheetModel } from '../../model';
20
- import { useSheetContext } from '../SheetContext';
14
+ import { useSheetContext } from '../SheetRoot';
21
15
 
22
16
  import { createAlign, useAlignState } from './align';
23
17
  import { createStyle, useStyleState } from './style';
24
- import { type ToolbarState, useToolbarState } from './useToolbarState';
18
+ import { type ToolbarStateAtom, useToolbarState } from './useToolbarState';
25
19
 
26
- const createToolbarActions = (
27
- model: SheetModel,
28
- state: ToolbarState,
29
- cursorFallbackRange?: CompleteCellRange,
30
- customActions?: Rx.Rx<ActionGraphProps>,
31
- ): Rx.Rx<ActionGraphProps> => {
32
- return Rx.make((get) => {
33
- const align = get(rxFromSignal(() => createAlign(model, state, cursorFallbackRange)));
34
- const style = get(rxFromSignal(() => createStyle(model, state, cursorFallbackRange)));
20
+ type ToolbarActionsContext = {
21
+ model: SheetModel;
22
+ stateAtom: ToolbarStateAtom;
23
+ registry: Registry.Registry;
24
+ cursorFallbackRange?: CompleteCellRange;
25
+ customActions?: Atom.Atom<ActionGraphProps>;
26
+ };
27
+
28
+ const createToolbarActions = ({
29
+ model,
30
+ stateAtom,
31
+ registry,
32
+ cursorFallbackRange,
33
+ customActions,
34
+ }: ToolbarActionsContext): Atom.Atom<ActionGraphProps> => {
35
+ return Atom.make((get) => {
36
+ const state = get(stateAtom);
37
+ const context = { model, state, stateAtom, registry, cursorFallbackRange };
38
+ const align = createAlign(context);
39
+ const style = createStyle(context);
35
40
  const gap = createGapSeparator();
36
41
 
37
42
  const graph: ActionGraphProps = {
@@ -49,32 +54,38 @@ const createToolbarActions = (
49
54
  });
50
55
  };
51
56
 
52
- export type SheetToolbarProps = PropsWithChildren<{ id: string }>;
57
+ export type SheetToolbarProps = {};
53
58
 
54
- export const SheetToolbar = ({ id }: SheetToolbarProps) => {
55
- const { model, cursorFallbackRange } = useSheetContext();
56
- const state = useToolbarState({});
57
- useAlignState(state);
58
- useStyleState(state);
59
+ export const SheetToolbar = composable<HTMLDivElement, SheetToolbarProps>((props, forwardedRef) => {
60
+ const { attendableId, model, cursorFallbackRange } = useSheetContext();
61
+ const stateAtom = useToolbarState({});
62
+ const registry = useContext(RegistryContext);
63
+ useAlignState(stateAtom);
64
+ useStyleState(stateAtom);
59
65
 
60
66
  const { graph } = useAppGraph();
61
67
  const customActions = useMemo(() => {
62
- return Rx.make((get) => {
63
- const actions = get(graph.actions(id));
68
+ return Atom.make((get) => {
69
+ const actions = get(graph.actions(attendableId));
64
70
  const nodes = actions.filter((action) => action.properties.disposition === 'toolbar');
65
- return { nodes, edges: nodes.map((node) => ({ source: 'root', target: node.id })) };
71
+ return {
72
+ nodes,
73
+ edges: nodes.map((node) => ({ source: 'root', target: node.id, relation: 'child' })),
74
+ };
66
75
  });
67
- }, [graph]);
76
+ }, [graph, attendableId]);
68
77
 
69
78
  const actionsCreator = useMemo(
70
- () => createToolbarActions(model, state, cursorFallbackRange, customActions),
71
- [model, state, cursorFallbackRange, customActions],
79
+ () => createToolbarActions({ model, stateAtom, registry, cursorFallbackRange, customActions }),
80
+ [model, stateAtom, registry, cursorFallbackRange, customActions],
72
81
  );
73
- const menu = useMenuActions(actionsCreator);
82
+ const menuActions = useMenuActions(actionsCreator);
74
83
 
75
84
  return (
76
- <MenuProvider {...menu} attendableId={id}>
77
- <ToolbarMenu />
78
- </MenuProvider>
85
+ <Menu.Root {...menuActions} attendableId={attendableId}>
86
+ <Menu.Toolbar {...composableProps(props)} ref={forwardedRef} />
87
+ </Menu.Root>
79
88
  );
80
- };
89
+ });
90
+
91
+ SheetToolbar.displayName = 'SheetToolbar';
@@ -2,17 +2,24 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { useEffect } from 'react';
5
+ import { type Registry, RegistryContext } from '@effect-atom/atom-react';
6
+ import { useContext, useEffect } from 'react';
6
7
 
7
8
  import { type CompleteCellRange, inRange } from '@dxos/compute';
8
- import { type ToolbarMenuActionGroupProperties, createMenuAction, createMenuItemGroup } from '@dxos/react-ui-menu';
9
+ import { Obj } from '@dxos/echo';
10
+ import {
11
+ type ActionGraphProps,
12
+ type ToolbarMenuActionGroupProperties,
13
+ createMenuAction,
14
+ createMenuItemGroup,
15
+ } from '@dxos/react-ui-menu';
9
16
 
10
- import { meta } from '../../meta';
17
+ import { meta } from '#meta';
11
18
  import { type SheetModel } from '../../model';
12
- import { type AlignKey, type AlignValue, alignKey, rangeFromIndex, rangeToIndex } from '../../types';
13
- import { useSheetContext } from '../SheetContext';
19
+ import { type AlignKey, type AlignValue, alignKey, rangeFromIndex, rangeToIndex } from '#types';
20
+ import { useSheetContext } from '../SheetRoot';
14
21
 
15
- import { type ToolbarState } from './useToolbarState';
22
+ import { type ToolbarState, type ToolbarStateAtom } from './useToolbarState';
16
23
 
17
24
  export type AlignAction = { key: AlignKey; value: AlignValue };
18
25
 
@@ -24,29 +31,40 @@ const aligns: Record<AlignValue, string> = {
24
31
  end: 'ph--text-align-right--regular',
25
32
  };
26
33
 
27
- export const useAlignState = (state: Partial<AlignState>) => {
34
+ export const useAlignState = (stateAtom: ToolbarStateAtom) => {
35
+ const registry = useContext(RegistryContext);
28
36
  const { cursor, model } = useSheetContext();
29
37
  useEffect(() => {
30
38
  // TODO(thure): Can this O(n) call be memoized?
31
- state[alignKey] = (
39
+ const alignValue = (
32
40
  cursor
33
41
  ? model.sheet.ranges?.findLast(
34
42
  ({ range, key }) => key === alignKey && inRange(rangeFromIndex(model.sheet, range), cursor),
35
43
  )?.value
36
44
  : undefined
37
45
  ) as AlignValue | undefined;
38
- }, [cursor, model.sheet]);
46
+ const prev = registry.get(stateAtom);
47
+ registry.set(stateAtom, { ...prev, [alignKey]: alignValue });
48
+ }, [cursor, model.sheet, registry, stateAtom]);
39
49
  };
40
50
 
41
51
  const createAlignGroupAction = (value?: AlignValue) =>
42
52
  createMenuItemGroup('align', {
43
- label: ['align label', { ns: meta.id }],
53
+ label: ['align.label', { ns: meta.id }],
44
54
  variant: 'toggleGroup',
45
55
  selectCardinality: 'single',
46
56
  value: `${alignKey}--${value}`,
47
57
  } as ToolbarMenuActionGroupProperties);
48
58
 
49
- const createAlignActions = (model: SheetModel, state: ToolbarState, cursorFallbackRange?: CompleteCellRange) =>
59
+ type AlignActionsContext = {
60
+ model: SheetModel;
61
+ state: ToolbarState;
62
+ stateAtom: ToolbarStateAtom;
63
+ registry: Registry.Registry;
64
+ cursorFallbackRange?: CompleteCellRange;
65
+ };
66
+
67
+ const createAlignActions = ({ model, state, stateAtom, registry, cursorFallbackRange }: AlignActionsContext) =>
50
68
  Object.entries(aligns).map(([alignValue, icon]) => {
51
69
  return createMenuAction<AlignAction>(
52
70
  `${alignKey}--${alignValue}`,
@@ -64,36 +82,43 @@ const createAlignActions = (model: SheetModel, state: ToolbarState, cursorFallba
64
82
  key: alignKey,
65
83
  value: alignValue as AlignValue,
66
84
  };
85
+ const currentState = registry.get(stateAtom);
67
86
  if (index < 0) {
68
- model.sheet.ranges?.push(nextRangeEntity);
69
- state[alignKey] = nextRangeEntity.value;
87
+ Obj.change(model.sheet, (obj) => {
88
+ obj.ranges?.push(nextRangeEntity);
89
+ });
90
+ registry.set(stateAtom, { ...currentState, [alignKey]: nextRangeEntity.value });
70
91
  } else if (model.sheet.ranges![index].value === nextRangeEntity.value) {
71
- model.sheet.ranges?.splice(index, 1);
72
- state[alignKey] = undefined;
92
+ Obj.change(model.sheet, (obj) => {
93
+ obj.ranges?.splice(index, 1);
94
+ });
95
+ registry.set(stateAtom, { ...currentState, [alignKey]: undefined });
73
96
  } else {
74
- model.sheet.ranges?.splice(index, 1, nextRangeEntity);
75
- state[alignKey] = nextRangeEntity.value;
97
+ Obj.change(model.sheet, (obj) => {
98
+ obj.ranges?.splice(index, 1, nextRangeEntity);
99
+ });
100
+ registry.set(stateAtom, { ...currentState, [alignKey]: nextRangeEntity.value });
76
101
  }
77
102
  },
78
103
  {
79
104
  key: alignKey,
80
105
  value: alignValue as AlignValue,
81
106
  checked: state[alignKey] === alignValue,
82
- label: [`range value ${alignValue} label`, { ns: meta.id }],
107
+ label: [`range-value-${alignValue}.label`, { ns: meta.id }],
83
108
  icon,
84
109
  testId: `grid.toolbar.${alignKey}.${alignValue}`,
85
110
  },
86
111
  );
87
112
  });
88
113
 
89
- export const createAlign = (model: SheetModel, state: ToolbarState, cursorFallbackRange?: CompleteCellRange) => {
90
- const alignGroup = createAlignGroupAction(state[alignKey]);
91
- const alignActions = createAlignActions(model, state, cursorFallbackRange);
114
+ export const createAlign = (context: AlignActionsContext): ActionGraphProps => {
115
+ const alignGroup = createAlignGroupAction(context.state[alignKey]);
116
+ const alignActions = createAlignActions(context);
92
117
  return {
93
118
  nodes: [alignGroup, ...alignActions],
94
119
  edges: [
95
- { source: 'root', target: 'align' },
96
- ...alignActions.map(({ id }) => ({ source: alignGroup.id, target: id })),
120
+ { source: 'root', target: 'align', relation: 'child' },
121
+ ...alignActions.map(({ id }) => ({ source: alignGroup.id, target: id, relation: 'child' })),
97
122
  ],
98
123
  };
99
124
  };
@@ -2,15 +2,24 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { useEffect } from 'react';
5
+ import { type Registry, RegistryContext } from '@effect-atom/atom-react';
6
+ import { useContext, useEffect } from 'react';
6
7
 
7
8
  import { type CompleteCellRange, inRange } from '@dxos/compute';
8
- import { type ToolbarMenuActionGroupProperties, createMenuAction, createMenuItemGroup } from '@dxos/react-ui-menu';
9
+ import { Obj } from '@dxos/echo';
10
+ import {
11
+ type ActionGraphProps,
12
+ type ToolbarMenuActionGroupProperties,
13
+ createMenuAction,
14
+ createMenuItemGroup,
15
+ } from '@dxos/react-ui-menu';
9
16
 
10
- import { meta } from '../../meta';
17
+ import { meta } from '#meta';
11
18
  import { type SheetModel } from '../../model';
12
- import { type StyleKey, type StyleValue, rangeFromIndex, rangeToIndex } from '../../types';
13
- import { useSheetContext } from '../SheetContext';
19
+ import { type StyleKey, type StyleValue, rangeFromIndex, rangeToIndex } from '#types';
20
+ import { useSheetContext } from '../SheetRoot';
21
+
22
+ import { type ToolbarState, type ToolbarStateAtom } from './useToolbarState';
14
23
 
15
24
  export type StyleState = Partial<Record<StyleValue, boolean>>;
16
25
 
@@ -21,22 +30,30 @@ const styles: Record<StyleValue, string> = {
21
30
  softwrap: 'ph--paragraph--regular',
22
31
  };
23
32
 
24
- export const useStyleState = (state: StyleState) => {
33
+ export const useStyleState = (stateAtom: ToolbarStateAtom) => {
34
+ const registry = useContext(RegistryContext);
25
35
  const { cursorFallbackRange, model } = useSheetContext();
26
36
 
27
37
  useEffect(() => {
28
- state.highlight = false;
29
- state.softwrap = false;
38
+ let highlight = false;
39
+ let softwrap = false;
30
40
  if (cursorFallbackRange && model.sheet.ranges) {
31
41
  model.sheet.ranges
32
42
  .filter(
33
43
  ({ range, key }) => key === 'style' && inRange(rangeFromIndex(model.sheet, range), cursorFallbackRange.from),
34
44
  )
35
45
  .forEach(({ value }) => {
36
- state[value as StyleValue] = true;
46
+ if (value === 'highlight') {
47
+ highlight = true;
48
+ }
49
+ if (value === 'softwrap') {
50
+ softwrap = true;
51
+ }
37
52
  });
38
53
  }
39
- }, [cursorFallbackRange, model.sheet]);
54
+ const prev = registry.get(stateAtom);
55
+ registry.set(stateAtom, { ...prev, highlight, softwrap });
56
+ }, [cursorFallbackRange, model.sheet, registry, stateAtom]);
40
57
  };
41
58
 
42
59
  const createStyleGroup = (state: StyleState) => {
@@ -49,7 +66,15 @@ const createStyleGroup = (state: StyleState) => {
49
66
  } as ToolbarMenuActionGroupProperties);
50
67
  };
51
68
 
52
- const createStyleActions = (model: SheetModel, state: StyleState, cursorFallbackRange?: CompleteCellRange) =>
69
+ type StyleActionsContext = {
70
+ model: SheetModel;
71
+ state: ToolbarState;
72
+ stateAtom: ToolbarStateAtom;
73
+ registry: Registry.Registry;
74
+ cursorFallbackRange?: CompleteCellRange;
75
+ };
76
+
77
+ const createStyleActions = ({ model, state, stateAtom, registry, cursorFallbackRange }: StyleActionsContext) =>
53
78
  Object.entries(styles).map(([styleValue, icon]) => {
54
79
  return createMenuAction<StyleAction>(
55
80
  `style--${styleValue}`,
@@ -67,6 +92,7 @@ const createStyleActions = (model: SheetModel, state: StyleState, cursorFallback
67
92
  key: 'style',
68
93
  value: styleValue as StyleValue,
69
94
  };
95
+ const currentState = registry.get(stateAtom);
70
96
  if (
71
97
  model.sheet.ranges
72
98
  .filter(
@@ -77,32 +103,36 @@ const createStyleActions = (model: SheetModel, state: StyleState, cursorFallback
77
103
  ) {
78
104
  // this value should be unset
79
105
  if (index >= 0) {
80
- model.sheet.ranges?.splice(index, 1);
106
+ Obj.change(model.sheet, (obj) => {
107
+ obj.ranges?.splice(index, 1);
108
+ });
81
109
  }
82
- state[nextRangeEntity.value] = false;
110
+ registry.set(stateAtom, { ...currentState, [nextRangeEntity.value]: false });
83
111
  } else {
84
- model.sheet.ranges?.push(nextRangeEntity);
85
- state[nextRangeEntity.value] = true;
112
+ Obj.change(model.sheet, (obj) => {
113
+ obj.ranges?.push(nextRangeEntity);
114
+ });
115
+ registry.set(stateAtom, { ...currentState, [nextRangeEntity.value]: true });
86
116
  }
87
117
  },
88
118
  {
89
119
  key: 'style',
90
120
  value: styleValue as StyleValue,
91
121
  icon,
92
- label: [`range value ${styleValue} label`, { ns: meta.id }],
122
+ label: [`range-value-${styleValue}.label`, { ns: meta.id }],
93
123
  checked: !!state[styleValue as StyleValue],
94
124
  },
95
125
  );
96
126
  });
97
127
 
98
- export const createStyle = (model: SheetModel, state: StyleState, cursorFallbackRange?: CompleteCellRange) => {
99
- const styleGroupAction = createStyleGroup(state);
100
- const styleActions = createStyleActions(model, state, cursorFallbackRange);
128
+ export const createStyle = (context: StyleActionsContext): ActionGraphProps => {
129
+ const styleGroupAction = createStyleGroup(context.state);
130
+ const styleActions = createStyleActions(context);
101
131
  return {
102
132
  nodes: [styleGroupAction, ...styleActions],
103
133
  edges: [
104
- { source: 'root', target: 'style' },
105
- ...styleActions.map(({ id }) => ({ source: styleGroupAction.id, target: id })),
134
+ { source: 'root', target: 'style', relation: 'child' },
135
+ ...styleActions.map(({ id }) => ({ source: styleGroupAction.id, target: id, relation: 'child' })),
106
136
  ],
107
137
  };
108
138
  };
@@ -2,15 +2,32 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { useMemo } from 'react';
6
-
7
- import { live } from '@dxos/live-object';
5
+ import { Atom, type Registry, RegistryContext, useAtomValue } from '@effect-atom/atom-react';
6
+ import { useContext, useMemo } from 'react';
8
7
 
9
8
  import { type AlignState } from './align';
10
9
  import { type StyleState } from './style';
11
10
 
12
11
  export type ToolbarState = Partial<StyleState & AlignState>;
12
+ export type ToolbarStateAtom = Atom.Writable<ToolbarState>;
13
+
14
+ /**
15
+ * Creates a reactive toolbar state Atom.
16
+ */
17
+ export const useToolbarState = (initialState: ToolbarState = {}): ToolbarStateAtom => {
18
+ return useMemo(() => Atom.make<ToolbarState>(initialState).pipe(Atom.keepAlive), []);
19
+ };
20
+
21
+ /**
22
+ * Hook to read the current toolbar state value.
23
+ */
24
+ export const useToolbarStateValue = (stateAtom: ToolbarStateAtom): ToolbarState => {
25
+ return useAtomValue(stateAtom);
26
+ };
13
27
 
14
- export const useToolbarState = (initialState: ToolbarState = {}) => {
15
- return useMemo(() => live<ToolbarState>(initialState), []);
28
+ /**
29
+ * Hook to get the registry for updating toolbar state.
30
+ */
31
+ export const useToolbarStateRegistry = (): Registry.Registry => {
32
+ return useContext(RegistryContext);
16
33
  };