@dxos/plugin-sheet 0.8.4-main.72ec0f3 → 0.8.4-main.937b3ca

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 (208) hide show
  1. package/dist/lib/browser/SheetContainer-ESCXPI7Y.mjs +397 -0
  2. package/dist/lib/browser/SheetContainer-ESCXPI7Y.mjs.map +7 -0
  3. package/dist/lib/browser/{anchor-sort-FCQ5OZZK.mjs → anchor-sort-JBRMW6OY.mjs} +7 -7
  4. package/dist/lib/browser/anchor-sort-JBRMW6OY.mjs.map +7 -0
  5. package/dist/lib/browser/chunk-2SAGT3BB.mjs +397 -0
  6. package/dist/lib/browser/chunk-2SAGT3BB.mjs.map +7 -0
  7. package/dist/lib/browser/{chunk-7VEWYJJN.mjs → chunk-IFLWVS2V.mjs} +5 -5
  8. package/dist/lib/browser/chunk-IFLWVS2V.mjs.map +7 -0
  9. package/dist/lib/browser/chunk-W6N44ONZ.mjs +1470 -0
  10. package/dist/lib/browser/chunk-W6N44ONZ.mjs.map +7 -0
  11. package/dist/lib/browser/compute-graph-registry-DL2PX7TF.mjs +21 -0
  12. package/dist/lib/browser/compute-graph-registry-DL2PX7TF.mjs.map +7 -0
  13. package/dist/lib/browser/index.mjs +68 -78
  14. package/dist/lib/browser/index.mjs.map +4 -4
  15. package/dist/lib/browser/markdown-BC4KBDUO.mjs +29 -0
  16. package/dist/lib/browser/markdown-BC4KBDUO.mjs.map +7 -0
  17. package/dist/lib/browser/meta.json +1 -1
  18. package/dist/lib/browser/operation-resolver-FJ4UWZUM.mjs +79 -0
  19. package/dist/lib/browser/operation-resolver-FJ4UWZUM.mjs.map +7 -0
  20. package/dist/lib/browser/{react-surface-5GYLVSMR.mjs → react-surface-5BXM6TJ3.mjs} +16 -19
  21. package/dist/lib/browser/react-surface-5BXM6TJ3.mjs.map +7 -0
  22. package/dist/lib/browser/types/index.mjs +5 -2
  23. package/dist/lib/node-esm/SheetContainer-YVIDJKP4.mjs +398 -0
  24. package/dist/lib/node-esm/SheetContainer-YVIDJKP4.mjs.map +7 -0
  25. package/dist/lib/node-esm/{anchor-sort-ZE7IS7SH.mjs → anchor-sort-C3XFPI6S.mjs} +7 -7
  26. package/dist/lib/node-esm/anchor-sort-C3XFPI6S.mjs.map +7 -0
  27. package/dist/lib/node-esm/chunk-IMWGSIDG.mjs +398 -0
  28. package/dist/lib/node-esm/chunk-IMWGSIDG.mjs.map +7 -0
  29. package/dist/lib/node-esm/{chunk-4QV4AGWK.mjs → chunk-PPOYR7DK.mjs} +5 -5
  30. package/dist/lib/node-esm/chunk-PPOYR7DK.mjs.map +7 -0
  31. package/dist/lib/node-esm/chunk-S7RYX7DG.mjs +1471 -0
  32. package/dist/lib/node-esm/chunk-S7RYX7DG.mjs.map +7 -0
  33. package/dist/lib/node-esm/compute-graph-registry-VXH55GDI.mjs +22 -0
  34. package/dist/lib/node-esm/compute-graph-registry-VXH55GDI.mjs.map +7 -0
  35. package/dist/lib/node-esm/index.mjs +68 -78
  36. package/dist/lib/node-esm/index.mjs.map +4 -4
  37. package/dist/lib/node-esm/markdown-6DGZCJRM.mjs +30 -0
  38. package/dist/lib/node-esm/markdown-6DGZCJRM.mjs.map +7 -0
  39. package/dist/lib/node-esm/meta.json +1 -1
  40. package/dist/lib/node-esm/operation-resolver-OGXEUWHA.mjs +80 -0
  41. package/dist/lib/node-esm/operation-resolver-OGXEUWHA.mjs.map +7 -0
  42. package/dist/lib/node-esm/{react-surface-RK32YZWR.mjs → react-surface-RLHC6B77.mjs} +16 -19
  43. package/dist/lib/node-esm/react-surface-RLHC6B77.mjs.map +7 -0
  44. package/dist/lib/node-esm/types/index.mjs +5 -2
  45. package/dist/types/src/SheetPlugin.d.ts +2 -1
  46. package/dist/types/src/SheetPlugin.d.ts.map +1 -1
  47. package/dist/types/src/capabilities/anchor-sort/anchor-sort.d.ts +5 -0
  48. package/dist/types/src/capabilities/anchor-sort/anchor-sort.d.ts.map +1 -0
  49. package/dist/types/src/capabilities/anchor-sort/index.d.ts +3 -0
  50. package/dist/types/src/capabilities/anchor-sort/index.d.ts.map +1 -0
  51. package/dist/types/src/capabilities/compute-graph-registry/compute-graph-registry.d.ts +5 -0
  52. package/dist/types/src/capabilities/compute-graph-registry/compute-graph-registry.d.ts.map +1 -0
  53. package/dist/types/src/capabilities/compute-graph-registry/index.d.ts +3 -0
  54. package/dist/types/src/capabilities/compute-graph-registry/index.d.ts.map +1 -0
  55. package/dist/types/src/capabilities/index.d.ts +5 -6
  56. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  57. package/dist/types/src/capabilities/markdown/index.d.ts +3 -0
  58. package/dist/types/src/capabilities/markdown/index.d.ts.map +1 -0
  59. package/dist/types/src/capabilities/markdown/markdown.d.ts +5 -0
  60. package/dist/types/src/capabilities/markdown/markdown.d.ts.map +1 -0
  61. package/dist/types/src/capabilities/operation-resolver/index.d.ts +3 -0
  62. package/dist/types/src/capabilities/operation-resolver/index.d.ts.map +1 -0
  63. package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts +5 -0
  64. package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts.map +1 -0
  65. package/dist/types/src/capabilities/react-surface/index.d.ts +3 -0
  66. package/dist/types/src/capabilities/react-surface/index.d.ts.map +1 -0
  67. package/dist/types/src/capabilities/react-surface/react-surface.d.ts +5 -0
  68. package/dist/types/src/capabilities/react-surface/react-surface.d.ts.map +1 -0
  69. package/dist/types/src/components/GridSheet/GridSheet.d.ts.map +1 -1
  70. package/dist/types/src/components/GridSheet/GridSheet.stories.d.ts +1 -0
  71. package/dist/types/src/components/GridSheet/GridSheet.stories.d.ts.map +1 -1
  72. package/dist/types/src/components/GridSheet/SheetCellEditor.stories.d.ts +1 -1
  73. package/dist/types/src/components/GridSheet/SheetCellEditor.stories.d.ts.map +1 -1
  74. package/dist/types/src/components/RangeList/RangeList.d.ts.map +1 -1
  75. package/dist/types/src/components/SheetContainer/SheetContainer.d.ts +4 -5
  76. package/dist/types/src/components/SheetContainer/SheetContainer.d.ts.map +1 -1
  77. package/dist/types/src/components/SheetContainer/SheetContainer.stories.d.ts +3 -1
  78. package/dist/types/src/components/SheetContainer/SheetContainer.stories.d.ts.map +1 -1
  79. package/dist/types/src/components/SheetToolbar/SheetToolbar.d.ts.map +1 -1
  80. package/dist/types/src/components/SheetToolbar/SheetToolbar.stories.d.ts +2 -0
  81. package/dist/types/src/components/SheetToolbar/SheetToolbar.stories.d.ts.map +1 -1
  82. package/dist/types/src/components/SheetToolbar/align.d.ts +12 -19
  83. package/dist/types/src/components/SheetToolbar/align.d.ts.map +1 -1
  84. package/dist/types/src/components/SheetToolbar/style.d.ts +12 -18
  85. package/dist/types/src/components/SheetToolbar/style.d.ts.map +1 -1
  86. package/dist/types/src/components/SheetToolbar/useToolbarState.d.ts +14 -1
  87. package/dist/types/src/components/SheetToolbar/useToolbarState.d.ts.map +1 -1
  88. package/dist/types/src/components/index.d.ts +1 -1
  89. package/dist/types/src/components/index.d.ts.map +1 -1
  90. package/dist/types/src/extensions/compute.stories.d.ts.map +1 -1
  91. package/dist/types/src/extensions/editor/sheet-extension.d.ts.map +1 -1
  92. package/dist/types/src/index.d.ts +1 -1
  93. package/dist/types/src/index.d.ts.map +1 -1
  94. package/dist/types/src/integrations/thread-ranges.d.ts.map +1 -1
  95. package/dist/types/src/meta.d.ts +2 -2
  96. package/dist/types/src/meta.d.ts.map +1 -1
  97. package/dist/types/src/model/sheet-model.d.ts +2 -2
  98. package/dist/types/src/model/sheet-model.d.ts.map +1 -1
  99. package/dist/types/src/serializer.d.ts.map +1 -1
  100. package/dist/types/src/testing/testing.d.ts +8 -8
  101. package/dist/types/src/translations.d.ts +1 -0
  102. package/dist/types/src/translations.d.ts.map +1 -1
  103. package/dist/types/src/types/Sheet.d.ts +34 -28
  104. package/dist/types/src/types/Sheet.d.ts.map +1 -1
  105. package/dist/types/src/types/capabilities.d.ts +6 -0
  106. package/dist/types/src/types/capabilities.d.ts.map +1 -0
  107. package/dist/types/src/types/index.d.ts +1 -0
  108. package/dist/types/src/types/index.d.ts.map +1 -1
  109. package/dist/types/src/types/types.d.ts +91 -65
  110. package/dist/types/src/types/types.d.ts.map +1 -1
  111. package/dist/types/tsconfig.tsbuildinfo +1 -1
  112. package/package.json +75 -69
  113. package/src/SheetPlugin.tsx +40 -62
  114. package/src/capabilities/anchor-sort/anchor-sort.ts +26 -0
  115. package/src/capabilities/anchor-sort/index.ts +7 -0
  116. package/src/capabilities/compute-graph-registry/compute-graph-registry.ts +27 -0
  117. package/src/capabilities/compute-graph-registry/index.ts +7 -0
  118. package/src/capabilities/index.ts +5 -9
  119. package/src/capabilities/markdown/index.ts +7 -0
  120. package/src/capabilities/markdown/markdown.ts +30 -0
  121. package/src/capabilities/operation-resolver/index.ts +7 -0
  122. package/src/capabilities/operation-resolver/operation-resolver.ts +77 -0
  123. package/src/capabilities/react-surface/index.ts +7 -0
  124. package/src/capabilities/react-surface/react-surface.tsx +43 -0
  125. package/src/components/ComputeGraph/compute-graph.stories.tsx +1 -1
  126. package/src/components/GridSheet/GridSheet.stories.tsx +2 -2
  127. package/src/components/GridSheet/GridSheet.tsx +14 -19
  128. package/src/components/GridSheet/SheetCellEditor.stories.tsx +7 -4
  129. package/src/components/GridSheet/util.ts +2 -2
  130. package/src/components/RangeList/RangeList.tsx +5 -2
  131. package/src/components/SheetContainer/SheetContainer.stories.tsx +41 -21
  132. package/src/components/SheetContainer/SheetContainer.tsx +27 -20
  133. package/src/components/SheetContext/SheetContext.tsx +4 -4
  134. package/src/components/SheetToolbar/SheetToolbar.tsx +29 -18
  135. package/src/components/SheetToolbar/align.ts +41 -16
  136. package/src/components/SheetToolbar/style.ts +45 -15
  137. package/src/components/SheetToolbar/useToolbarState.ts +22 -5
  138. package/src/extensions/compute.stories.tsx +15 -6
  139. package/src/extensions/compute.ts +1 -1
  140. package/src/extensions/editor/sheet-extension.ts +7 -4
  141. package/src/index.ts +1 -1
  142. package/src/integrations/thread-ranges.ts +37 -41
  143. package/src/meta.ts +2 -2
  144. package/src/model/sheet-model.ts +75 -45
  145. package/src/playwright/playwright.config.ts +1 -1
  146. package/src/playwright/sheet.spec.ts +1 -0
  147. package/src/sanity.test.ts +1 -1
  148. package/src/serializer.ts +1 -1
  149. package/src/translations.ts +1 -0
  150. package/src/types/Sheet.ts +23 -20
  151. package/src/{capabilities → types}/capabilities.ts +2 -2
  152. package/src/types/index.ts +1 -0
  153. package/src/types/types.ts +81 -37
  154. package/dist/lib/browser/SheetContainer-66BNB3XG.mjs +0 -349
  155. package/dist/lib/browser/SheetContainer-66BNB3XG.mjs.map +0 -7
  156. package/dist/lib/browser/anchor-sort-FCQ5OZZK.mjs.map +0 -7
  157. package/dist/lib/browser/chunk-73AV3NH6.mjs +0 -15
  158. package/dist/lib/browser/chunk-73AV3NH6.mjs.map +0 -7
  159. package/dist/lib/browser/chunk-7VEWYJJN.mjs.map +0 -7
  160. package/dist/lib/browser/chunk-DVJ3QW3F.mjs +0 -907
  161. package/dist/lib/browser/chunk-DVJ3QW3F.mjs.map +0 -7
  162. package/dist/lib/browser/chunk-FWFAAGXL.mjs +0 -28
  163. package/dist/lib/browser/chunk-FWFAAGXL.mjs.map +0 -7
  164. package/dist/lib/browser/chunk-OU5KTWY3.mjs +0 -852
  165. package/dist/lib/browser/chunk-OU5KTWY3.mjs.map +0 -7
  166. package/dist/lib/browser/compute-graph-registry-AP5RA7W3.mjs +0 -21
  167. package/dist/lib/browser/compute-graph-registry-AP5RA7W3.mjs.map +0 -7
  168. package/dist/lib/browser/intent-resolver-66OAYVQF.mjs +0 -56
  169. package/dist/lib/browser/intent-resolver-66OAYVQF.mjs.map +0 -7
  170. package/dist/lib/browser/markdown-B6VKYY2S.mjs +0 -26
  171. package/dist/lib/browser/markdown-B6VKYY2S.mjs.map +0 -7
  172. package/dist/lib/browser/react-surface-5GYLVSMR.mjs.map +0 -7
  173. package/dist/lib/node-esm/SheetContainer-NWEQETAY.mjs +0 -350
  174. package/dist/lib/node-esm/SheetContainer-NWEQETAY.mjs.map +0 -7
  175. package/dist/lib/node-esm/anchor-sort-ZE7IS7SH.mjs.map +0 -7
  176. package/dist/lib/node-esm/chunk-44YTKTMP.mjs +0 -16
  177. package/dist/lib/node-esm/chunk-44YTKTMP.mjs.map +0 -7
  178. package/dist/lib/node-esm/chunk-4H2EHVWE.mjs +0 -908
  179. package/dist/lib/node-esm/chunk-4H2EHVWE.mjs.map +0 -7
  180. package/dist/lib/node-esm/chunk-4MT3JJU2.mjs +0 -853
  181. package/dist/lib/node-esm/chunk-4MT3JJU2.mjs.map +0 -7
  182. package/dist/lib/node-esm/chunk-4QV4AGWK.mjs.map +0 -7
  183. package/dist/lib/node-esm/chunk-HILDMVPL.mjs +0 -29
  184. package/dist/lib/node-esm/chunk-HILDMVPL.mjs.map +0 -7
  185. package/dist/lib/node-esm/compute-graph-registry-UMQ5UYCL.mjs +0 -22
  186. package/dist/lib/node-esm/compute-graph-registry-UMQ5UYCL.mjs.map +0 -7
  187. package/dist/lib/node-esm/intent-resolver-VNKIMQQT.mjs +0 -57
  188. package/dist/lib/node-esm/intent-resolver-VNKIMQQT.mjs.map +0 -7
  189. package/dist/lib/node-esm/markdown-VKY7HXU2.mjs +0 -27
  190. package/dist/lib/node-esm/markdown-VKY7HXU2.mjs.map +0 -7
  191. package/dist/lib/node-esm/react-surface-RK32YZWR.mjs.map +0 -7
  192. package/dist/types/src/capabilities/anchor-sort.d.ts +0 -4
  193. package/dist/types/src/capabilities/anchor-sort.d.ts.map +0 -1
  194. package/dist/types/src/capabilities/capabilities.d.ts +0 -5
  195. package/dist/types/src/capabilities/capabilities.d.ts.map +0 -1
  196. package/dist/types/src/capabilities/compute-graph-registry.d.ts +0 -4
  197. package/dist/types/src/capabilities/compute-graph-registry.d.ts.map +0 -1
  198. package/dist/types/src/capabilities/intent-resolver.d.ts +0 -4
  199. package/dist/types/src/capabilities/intent-resolver.d.ts.map +0 -1
  200. package/dist/types/src/capabilities/markdown.d.ts +0 -4
  201. package/dist/types/src/capabilities/markdown.d.ts.map +0 -1
  202. package/dist/types/src/capabilities/react-surface.d.ts +0 -4
  203. package/dist/types/src/capabilities/react-surface.d.ts.map +0 -1
  204. package/src/capabilities/anchor-sort.ts +0 -21
  205. package/src/capabilities/compute-graph-registry.ts +0 -23
  206. package/src/capabilities/intent-resolver.ts +0 -38
  207. package/src/capabilities/markdown.ts +0 -23
  208. package/src/capabilities/react-surface.tsx +0 -41
@@ -13,8 +13,7 @@ import React, {
13
13
  useState,
14
14
  } from 'react';
15
15
 
16
- import { createIntent } from '@dxos/app-framework';
17
- import { useIntentDispatcher } from '@dxos/app-framework/react';
16
+ import { useOperationInvoker } from '@dxos/app-framework/react';
18
17
  import { type CellRange, rangeToA1Notation } from '@dxos/compute';
19
18
  import { defaultColSize, defaultRowSize } from '@dxos/lit-grid';
20
19
  import { DropdownMenu, Icon, useTranslation } from '@dxos/react-ui';
@@ -36,7 +35,7 @@ import {
36
35
  import { type RangeController, rangeExtension, sheetExtension } from '../../extensions';
37
36
  import { useSelectThreadOnCellFocus, useUpdateFocusedCellOnThreadSelection } from '../../integrations';
38
37
  import { meta } from '../../meta';
39
- import { DEFAULT_COLS, DEFAULT_ROWS, SheetAction } from '../../types';
38
+ import { DEFAULT_COLS, DEFAULT_ROWS, SheetOperation } from '../../types';
40
39
  import { useSheetContext } from '../SheetContext';
41
40
 
42
41
  import { colLabelCell, rowLabelCell, useSheetModelDxGridProps } from './util';
@@ -77,7 +76,7 @@ export const GridSheet = () => {
77
76
  // a reliable dependency for `useEffect` whereas `useLayoutEffect` does not guarantee the element will be defined.
78
77
  const [dxGrid, setDxGrid] = useState<DxGridElement | null>(null);
79
78
  const [extraplanarFocus, setExtraplanarFocus] = useState<DxGridPosition | null>(null);
80
- const { dispatchPromise: dispatch } = useIntentDispatcher();
79
+ const { invokePromise } = useOperationInvoker();
81
80
  const rangeController = useRef<RangeController>(null);
82
81
  const { hasAttention } = useAttention(id);
83
82
 
@@ -266,24 +265,20 @@ export const GridSheet = () => {
266
265
  switch (operation) {
267
266
  case 'insert-before':
268
267
  case 'insert-after':
269
- return dispatch(
270
- createIntent(SheetAction.InsertAxis, {
271
- model,
272
- axis: contextMenuAxis,
273
- index: contextMenuOpen![contextMenuAxis] + (operation === 'insert-before' ? 0 : 1),
274
- }),
275
- );
268
+ return invokePromise(SheetOperation.InsertAxis, {
269
+ model,
270
+ axis: contextMenuAxis,
271
+ index: contextMenuOpen![contextMenuAxis] + (operation === 'insert-before' ? 0 : 1),
272
+ });
276
273
  case 'drop':
277
- return dispatch(
278
- createIntent(SheetAction.DropAxis, {
279
- model,
280
- axis: contextMenuAxis,
281
- axisIndex: model.sheet[contextMenuAxis === 'row' ? 'rows' : 'columns'][contextMenuOpen![contextMenuAxis]],
282
- }),
283
- );
274
+ return invokePromise(SheetOperation.DropAxis, {
275
+ model,
276
+ axis: contextMenuAxis,
277
+ axisIndex: model.sheet[contextMenuAxis === 'row' ? 'rows' : 'columns'][contextMenuOpen![contextMenuAxis]],
278
+ });
284
279
  }
285
280
  },
286
- [contextMenuAxis, contextMenuOpen, model, dispatch],
281
+ [contextMenuAxis, contextMenuOpen, model, invokePromise],
287
282
  );
288
283
 
289
284
  const { columns, rows } = useSheetModelDxGridProps(dxGrid, model);
@@ -6,13 +6,14 @@ import { type Meta, type StoryObj } from '@storybook/react-vite';
6
6
  import React, { useMemo, useState } from 'react';
7
7
 
8
8
  import { Client } from '@dxos/client';
9
- import { createDocAccessor } from '@dxos/client/echo';
10
9
  import { defaultFunctions } from '@dxos/compute';
11
10
  import { getRegisteredFunctionNames } from '@dxos/compute/testing';
11
+ import { Obj } from '@dxos/echo';
12
+ import { createDocAccessor } from '@dxos/echo-db';
12
13
  import { useAsyncEffect } from '@dxos/react-hooks';
13
14
  import { withTheme } from '@dxos/react-ui/testing';
14
- import { automerge } from '@dxos/react-ui-editor';
15
15
  import { CellEditor, type CellEditorProps } from '@dxos/react-ui-grid';
16
+ import { automerge } from '@dxos/ui-editor';
16
17
 
17
18
  import { sheetExtension } from '../../extensions';
18
19
  import { Sheet } from '../../types';
@@ -37,8 +38,10 @@ const AutomergeStory = ({ value, ...props }: CellEditorProps) => {
37
38
  const space = await client.spaces.create();
38
39
 
39
40
  const sheet = Sheet.make();
40
- sheet.name = 'Test';
41
- sheet.cells[cell] = { value };
41
+ Obj.change(sheet, (s) => {
42
+ s.name = 'Test';
43
+ s.cells[cell] = { value };
44
+ });
42
45
  space.db.add(sheet);
43
46
  setObject(sheet);
44
47
  }, [value]);
@@ -5,7 +5,7 @@
5
5
  import { useEffect, useState } from 'react';
6
6
 
7
7
  import { inRange } from '@dxos/compute';
8
- import { createDocAccessor } from '@dxos/react-client/echo';
8
+ import { createDocAccessor } from '@dxos/echo-db';
9
9
  import { cellClassesForFieldType, parseValue } from '@dxos/react-ui-form';
10
10
  import {
11
11
  type DxGridAxisMeta,
@@ -19,7 +19,7 @@ import {
19
19
  commentedClassName,
20
20
  rowToA1Notation,
21
21
  } from '@dxos/react-ui-grid';
22
- import { mx } from '@dxos/react-ui-theme';
22
+ import { mx } from '@dxos/ui-theme';
23
23
 
24
24
  import { type SheetModel } from '../../model';
25
25
  import { cellClassNameForRange, rangeFromIndex } from '../../types';
@@ -6,9 +6,10 @@ import * as Schema from 'effect/Schema';
6
6
  import React, { useCallback } from 'react';
7
7
 
8
8
  import { rangeToA1Notation } from '@dxos/compute';
9
+ import { Obj } from '@dxos/echo';
9
10
  import { Callout, useTranslation } from '@dxos/react-ui';
10
11
  import { List } from '@dxos/react-ui-list';
11
- import { ghostHover } from '@dxos/react-ui-theme';
12
+ import { ghostHover } from '@dxos/ui-theme';
12
13
 
13
14
  import { meta } from '../../meta';
14
15
  import { rangeFromIndex } from '../../types';
@@ -25,7 +26,9 @@ export const RangeList = ({ sheet }: RangeListProps) => {
25
26
  const handleDeleteRange = useCallback(
26
27
  (range: Sheet.Range) => {
27
28
  const index = sheet.ranges.findIndex((sheetRange) => sheetRange === range);
28
- sheet.ranges.splice(index, 1);
29
+ Obj.change(sheet, (s) => {
30
+ s.ranges.splice(index, 1);
31
+ });
29
32
  },
30
33
  [sheet],
31
34
  );
@@ -3,21 +3,22 @@
3
3
  //
4
4
 
5
5
  import { type Meta } from '@storybook/react-vite';
6
+ import * as Effect from 'effect/Effect';
6
7
  import React from 'react';
7
8
 
8
- import { Capabilities, IntentPlugin, contributes, createResolver } from '@dxos/app-framework';
9
+ import { Capability, Common } from '@dxos/app-framework';
9
10
  import { withPluginManager } from '@dxos/app-framework/testing';
10
11
  import { Obj } from '@dxos/echo';
11
- import { GraphPlugin } from '@dxos/plugin-graph';
12
+ import { OperationResolver } from '@dxos/operation';
13
+ import { corePlugins } from '@dxos/plugin-testing';
12
14
  import { useSpace } from '@dxos/react-client/echo';
13
15
  import { withClientProvider } from '@dxos/react-client/testing';
14
- import { withTheme } from '@dxos/react-ui/testing';
16
+ import { withLayout, withTheme } from '@dxos/react-ui/testing';
15
17
  import { AttendableContainer } from '@dxos/react-ui-attention';
16
- import { withAttention } from '@dxos/react-ui-attention/testing';
17
18
 
18
19
  import { createTestCells, useTestSheet, withComputeGraphDecorator } from '../../testing';
19
20
  import { translations } from '../../translations';
20
- import { Sheet, SheetAction } from '../../types';
21
+ import { Sheet, SheetOperation } from '../../types';
21
22
  import { useComputeGraph } from '../ComputeGraph';
22
23
  import { RangeList } from '../RangeList';
23
24
 
@@ -28,22 +29,24 @@ const meta = {
28
29
  component: SheetContainer,
29
30
  decorators: [
30
31
  withTheme,
32
+ withLayout({ layout: 'fullscreen' }),
31
33
  withClientProvider({ types: [Sheet.Sheet], createSpace: true }),
32
34
  withComputeGraphDecorator(),
33
- withAttention,
34
35
  // TODO(wittjosiah): Consider whether we should refactor component so story doesn't need to depend on intents.
35
36
  withPluginManager({
36
- plugins: [IntentPlugin(), GraphPlugin()],
37
+ plugins: [...corePlugins()],
37
38
  capabilities: [
38
- contributes(
39
- Capabilities.IntentResolver,
40
- createResolver({
41
- intent: SheetAction.DropAxis,
42
- resolve: ({ model, axis, axisIndex }) => {
43
- model[axis === 'col' ? 'dropColumn' : 'dropRow'](axisIndex);
44
- },
39
+ Capability.contributes(Common.Capability.OperationResolver, [
40
+ OperationResolver.make({
41
+ operation: SheetOperation.DropAxis,
42
+ handler: ({ model, axis, axisIndex }) =>
43
+ Effect.sync(() => {
44
+ model[axis === 'col' ? 'dropColumn' : 'dropRow'](axisIndex);
45
+ // Return stub output for story purposes.
46
+ return { axis, axisIndex, index: 0, axisMeta: null, values: [] };
47
+ }),
45
48
  }),
46
- ),
49
+ ]),
47
50
  ],
48
51
  }),
49
52
  ],
@@ -65,25 +68,42 @@ export const Default = () => {
65
68
 
66
69
  return (
67
70
  <AttendableContainer id={Obj.getDXN(sheet).toString()} classNames='contents'>
68
- <SheetContainer space={space} sheet={sheet} role='story' ignoreAttention />
71
+ <SheetContainer role='article' space={space} subject={sheet} ignoreAttention />
69
72
  </AttendableContainer>
70
73
  );
71
74
  };
72
75
 
76
+ export const Section = () => {
77
+ const space = useSpace();
78
+ const graph = useComputeGraph(space);
79
+ const sheet = useTestSheet(space, graph, { cells: createTestCells() });
80
+ if (!sheet || !space) {
81
+ return null;
82
+ }
83
+
84
+ return (
85
+ <div className='is-full flex justify-center'>
86
+ <div className='is-[40rem]'>
87
+ <AttendableContainer id={Obj.getDXN(sheet).toString()} classNames='contents'>
88
+ <SheetContainer role='section' space={space} subject={sheet} ignoreAttention />
89
+ </AttendableContainer>
90
+ </div>
91
+ </div>
92
+ );
93
+ };
94
+
73
95
  export const Spec = () => {
74
96
  const space = useSpace();
75
97
  const graph = useComputeGraph(space);
76
- const sheet = useTestSheet(space, graph, {
77
- cells: { A1: { value: 'Ready' } },
78
- });
98
+ const sheet = useTestSheet(space, graph, { cells: { A1: { value: 'Ready' } } });
79
99
  if (!sheet || !space) {
80
100
  return null;
81
101
  }
82
102
 
83
103
  return (
84
104
  <AttendableContainer id={Obj.getDXN(sheet).toString()} classNames='contents'>
85
- <div role='none' className='grid grid-rows-[66%_33%] bs-full grid-cols-1'>
86
- <SheetContainer space={space} sheet={sheet} role='story' ignoreAttention />
105
+ <div role='none' className='is-full grid grid-cols-[1fr_20rem]'>
106
+ <SheetContainer role='article' space={space} subject={sheet} ignoreAttention />
87
107
  <div role='none' data-testid='grid.range-list'>
88
108
  <RangeList sheet={sheet} />
89
109
  </div>
@@ -2,11 +2,12 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import React from 'react';
5
+ import React, { Fragment } from 'react';
6
6
 
7
+ import { type SurfaceComponentProps } from '@dxos/app-framework/react';
7
8
  import { Obj } from '@dxos/echo';
8
9
  import { type Space } from '@dxos/react-client/echo';
9
- import { StackItem } from '@dxos/react-ui-stack';
10
+ import { Layout, type LayoutFlexProps } from '@dxos/react-ui-mosaic';
10
11
 
11
12
  import { type Sheet } from '../../types';
12
13
  import { useComputeGraph } from '../ComputeGraph';
@@ -15,27 +16,33 @@ import { GridSheet } from '../GridSheet';
15
16
  import { SheetProvider } from '../SheetContext';
16
17
  import { SheetToolbar } from '../SheetToolbar';
17
18
 
18
- export type SheetContainerProps = {
19
- space: Space;
20
- sheet: Sheet.Sheet;
21
- role?: string;
22
- ignoreAttention?: boolean;
23
- };
19
+ export type SheetContainerProps = SurfaceComponentProps<
20
+ Sheet.Sheet,
21
+ {
22
+ space: Space;
23
+ ignoreAttention?: boolean;
24
+ }
25
+ >;
24
26
 
25
- export const SheetContainer = ({ space, sheet, role, ignoreAttention }: SheetContainerProps) => {
27
+ export const SheetContainer = ({ role, subject: sheet, space, ignoreAttention }: SheetContainerProps) => {
26
28
  const graph = useComputeGraph(space);
29
+ if (!graph) {
30
+ return null;
31
+ }
32
+
33
+ const Root = role === 'section' ? Container : Fragment;
27
34
 
28
- return graph ? (
35
+ return (
29
36
  <SheetProvider sheet={sheet} graph={graph} ignoreAttention={ignoreAttention}>
30
- <StackItem.Content
31
- toolbar
32
- statusbar
33
- classNames={[role === 'section' && 'aspect-video', role === 'story' && 'bs-full']}
34
- >
35
- <SheetToolbar id={Obj.getDXN(sheet).toString()} />
36
- <GridSheet />
37
- <FunctionEditor />
38
- </StackItem.Content>
37
+ <Root>
38
+ <Layout.Main toolbar statusbar>
39
+ <SheetToolbar id={Obj.getDXN(sheet).toString()} />
40
+ <GridSheet />
41
+ <FunctionEditor />
42
+ </Layout.Main>
43
+ </Root>
39
44
  </SheetProvider>
40
- ) : null;
45
+ );
41
46
  };
47
+
48
+ const Container = (props: LayoutFlexProps) => <Layout.Flex {...props} classNames='aspect-square' />;
@@ -56,12 +56,12 @@ export const useSheetContext = (): SheetContextValue => {
56
56
  };
57
57
 
58
58
  const SheetProviderImpl = ({
59
+ __gridScope,
60
+ children,
61
+ ignoreAttention,
59
62
  model,
60
63
  onInfo,
61
- ignoreAttention,
62
- children,
63
- __gridScope,
64
- }: GridScopedProps<PropsWithChildren<Pick<SheetContextValue, 'onInfo' | 'model' | 'ignoreAttention'>>>) => {
64
+ }: GridScopedProps<PropsWithChildren<Pick<SheetContextValue, 'ignoreAttention' | 'model' | 'onInfo'>>>) => {
65
65
  const { id, editing, setEditing } = useGridContext('SheetProvider', __gridScope);
66
66
 
67
67
  const [cursor, setCursorInternal] = useState<CellAddress>();
@@ -2,8 +2,8 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { Atom } from '@effect-atom/atom-react';
6
- import React, { type PropsWithChildren, useMemo } from 'react';
5
+ import { Atom, type Registry, RegistryContext } from '@effect-atom/atom-react';
6
+ import React, { type PropsWithChildren, useContext, useMemo } from 'react';
7
7
 
8
8
  import { useAppGraph } from '@dxos/app-framework/react';
9
9
  import { type CompleteCellRange } from '@dxos/compute';
@@ -11,7 +11,6 @@ import {
11
11
  type ActionGraphProps,
12
12
  MenuProvider,
13
13
  ToolbarMenu,
14
- atomFromSignal,
15
14
  createGapSeparator,
16
15
  useMenuActions,
17
16
  } from '@dxos/react-ui-menu';
@@ -21,17 +20,28 @@ import { useSheetContext } from '../SheetContext';
21
20
 
22
21
  import { createAlign, useAlignState } from './align';
23
22
  import { createStyle, useStyleState } from './style';
24
- import { type ToolbarState, useToolbarState } from './useToolbarState';
23
+ import { type ToolbarStateAtom, useToolbarState } from './useToolbarState';
25
24
 
26
- const createToolbarActions = (
27
- model: SheetModel,
28
- state: ToolbarState,
29
- cursorFallbackRange?: CompleteCellRange,
30
- customActions?: Atom.Atom<ActionGraphProps>,
31
- ): Atom.Atom<ActionGraphProps> => {
25
+ type ToolbarActionsContext = {
26
+ model: SheetModel;
27
+ stateAtom: ToolbarStateAtom;
28
+ registry: Registry.Registry;
29
+ cursorFallbackRange?: CompleteCellRange;
30
+ customActions?: Atom.Atom<ActionGraphProps>;
31
+ };
32
+
33
+ const createToolbarActions = ({
34
+ model,
35
+ stateAtom,
36
+ registry,
37
+ cursorFallbackRange,
38
+ customActions,
39
+ }: ToolbarActionsContext): Atom.Atom<ActionGraphProps> => {
32
40
  return Atom.make((get) => {
33
- const align = get(atomFromSignal(() => createAlign(model, state, cursorFallbackRange)));
34
- const style = get(atomFromSignal(() => createStyle(model, state, cursorFallbackRange)));
41
+ const state = get(stateAtom);
42
+ const context = { model, state, stateAtom, registry, cursorFallbackRange };
43
+ const align = createAlign(context);
44
+ const style = createStyle(context);
35
45
  const gap = createGapSeparator();
36
46
 
37
47
  const graph: ActionGraphProps = {
@@ -53,9 +63,10 @@ export type SheetToolbarProps = PropsWithChildren<{ id: string }>;
53
63
 
54
64
  export const SheetToolbar = ({ id }: SheetToolbarProps) => {
55
65
  const { model, cursorFallbackRange } = useSheetContext();
56
- const state = useToolbarState({});
57
- useAlignState(state);
58
- useStyleState(state);
66
+ const stateAtom = useToolbarState({});
67
+ const registry = useContext(RegistryContext);
68
+ useAlignState(stateAtom);
69
+ useStyleState(stateAtom);
59
70
 
60
71
  const { graph } = useAppGraph();
61
72
  const customActions = useMemo(() => {
@@ -67,11 +78,11 @@ export const SheetToolbar = ({ id }: SheetToolbarProps) => {
67
78
  edges: nodes.map((node) => ({ source: 'root', target: node.id })),
68
79
  };
69
80
  });
70
- }, [graph]);
81
+ }, [graph, id]);
71
82
 
72
83
  const actionsCreator = useMemo(
73
- () => createToolbarActions(model, state, cursorFallbackRange, customActions),
74
- [model, state, cursorFallbackRange, customActions],
84
+ () => createToolbarActions({ model, stateAtom, registry, cursorFallbackRange, customActions }),
85
+ [model, stateAtom, registry, cursorFallbackRange, customActions],
75
86
  );
76
87
  const menu = useMenuActions(actionsCreator);
77
88
 
@@ -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
17
  import { meta } from '../../meta';
11
18
  import { type SheetModel } from '../../model';
12
19
  import { type AlignKey, type AlignValue, alignKey, rangeFromIndex, rangeToIndex } from '../../types';
13
20
  import { useSheetContext } from '../SheetContext';
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,18 +31,21 @@ 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) =>
@@ -46,7 +56,15 @@ const createAlignGroupAction = (value?: AlignValue) =>
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,15 +82,22 @@ 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, (s) => {
88
+ s.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, (s) => {
93
+ s.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, (s) => {
98
+ s.ranges?.splice(index, 1, nextRangeEntity);
99
+ });
100
+ registry.set(stateAtom, { ...currentState, [alignKey]: nextRangeEntity.value });
76
101
  }
77
102
  },
78
103
  {
@@ -86,9 +111,9 @@ const createAlignActions = (model: SheetModel, state: ToolbarState, cursorFallba
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: [
@@ -2,16 +2,25 @@
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
17
  import { meta } from '../../meta';
11
18
  import { type SheetModel } from '../../model';
12
19
  import { type StyleKey, type StyleValue, rangeFromIndex, rangeToIndex } from '../../types';
13
20
  import { useSheetContext } from '../SheetContext';
14
21
 
22
+ import { type ToolbarState, type ToolbarStateAtom } from './useToolbarState';
23
+
15
24
  export type StyleState = Partial<Record<StyleValue, boolean>>;
16
25
 
17
26
  export type StyleAction = { key: StyleKey; value: StyleValue };
@@ -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,12 +103,16 @@ 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, (s) => {
107
+ s.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, (s) => {
113
+ s.ranges?.push(nextRangeEntity);
114
+ });
115
+ registry.set(stateAtom, { ...currentState, [nextRangeEntity.value]: true });
86
116
  }
87
117
  },
88
118
  {
@@ -95,9 +125,9 @@ const createStyleActions = (model: SheetModel, state: StyleState, cursorFallback
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: [