@dxos/plugin-sheet 0.8.4-main.66e292d → 0.8.4-main.69d29f4

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 (202) hide show
  1. package/dist/lib/browser/SheetContainer-J72HS2FI.mjs +397 -0
  2. package/dist/lib/browser/SheetContainer-J72HS2FI.mjs.map +7 -0
  3. package/dist/lib/browser/{anchor-sort-OWOAGQM6.mjs → anchor-sort-LLO7PZKF.mjs} +7 -7
  4. package/dist/lib/browser/anchor-sort-LLO7PZKF.mjs.map +7 -0
  5. package/dist/lib/browser/{chunk-7VEWYJJN.mjs → chunk-IFLWVS2V.mjs} +5 -5
  6. package/dist/lib/browser/chunk-IFLWVS2V.mjs.map +7 -0
  7. package/dist/lib/browser/chunk-KE3AKN5W.mjs +397 -0
  8. package/dist/lib/browser/chunk-KE3AKN5W.mjs.map +7 -0
  9. package/dist/lib/browser/chunk-S27QJYTN.mjs +1473 -0
  10. package/dist/lib/browser/chunk-S27QJYTN.mjs.map +7 -0
  11. package/dist/lib/browser/compute-graph-registry-RC5L7RE4.mjs +21 -0
  12. package/dist/lib/browser/compute-graph-registry-RC5L7RE4.mjs.map +7 -0
  13. package/dist/lib/browser/index.mjs +66 -76
  14. package/dist/lib/browser/index.mjs.map +4 -4
  15. package/dist/lib/browser/markdown-D2T2DOVX.mjs +29 -0
  16. package/dist/lib/browser/markdown-D2T2DOVX.mjs.map +7 -0
  17. package/dist/lib/browser/meta.json +1 -1
  18. package/dist/lib/browser/operation-resolver-YDOW72CN.mjs +79 -0
  19. package/dist/lib/browser/operation-resolver-YDOW72CN.mjs.map +7 -0
  20. package/dist/lib/browser/{react-surface-VPLFBQSV.mjs → react-surface-JIYVFH42.mjs} +16 -19
  21. package/dist/lib/browser/react-surface-JIYVFH42.mjs.map +7 -0
  22. package/dist/lib/browser/types/index.mjs +5 -2
  23. package/dist/lib/node-esm/SheetContainer-OGSSDOZU.mjs +398 -0
  24. package/dist/lib/node-esm/SheetContainer-OGSSDOZU.mjs.map +7 -0
  25. package/dist/lib/node-esm/{anchor-sort-FG3DS4HM.mjs → anchor-sort-OX5I2YOW.mjs} +7 -7
  26. package/dist/lib/node-esm/anchor-sort-OX5I2YOW.mjs.map +7 -0
  27. package/dist/lib/node-esm/chunk-6J5L47IB.mjs +398 -0
  28. package/dist/lib/node-esm/chunk-6J5L47IB.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-Y4V6HVHO.mjs +1474 -0
  32. package/dist/lib/node-esm/chunk-Y4V6HVHO.mjs.map +7 -0
  33. package/dist/lib/node-esm/compute-graph-registry-ZGXVLVGD.mjs +22 -0
  34. package/dist/lib/node-esm/compute-graph-registry-ZGXVLVGD.mjs.map +7 -0
  35. package/dist/lib/node-esm/index.mjs +66 -76
  36. package/dist/lib/node-esm/index.mjs.map +4 -4
  37. package/dist/lib/node-esm/markdown-PTV72DLO.mjs +30 -0
  38. package/dist/lib/node-esm/markdown-PTV72DLO.mjs.map +7 -0
  39. package/dist/lib/node-esm/meta.json +1 -1
  40. package/dist/lib/node-esm/operation-resolver-Q63VQBVA.mjs +80 -0
  41. package/dist/lib/node-esm/operation-resolver-Q63VQBVA.mjs.map +7 -0
  42. package/dist/lib/node-esm/{react-surface-YLTZQVNL.mjs → react-surface-SWRZSZVR.mjs} +16 -19
  43. package/dist/lib/node-esm/react-surface-SWRZSZVR.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.map +1 -1
  71. package/dist/types/src/components/GridSheet/SheetCellEditor.stories.d.ts +1 -1
  72. package/dist/types/src/components/GridSheet/SheetCellEditor.stories.d.ts.map +1 -1
  73. package/dist/types/src/components/RangeList/RangeList.d.ts.map +1 -1
  74. package/dist/types/src/components/SheetContainer/SheetContainer.d.ts +4 -5
  75. package/dist/types/src/components/SheetContainer/SheetContainer.d.ts.map +1 -1
  76. package/dist/types/src/components/SheetContainer/SheetContainer.stories.d.ts +2 -1
  77. package/dist/types/src/components/SheetContainer/SheetContainer.stories.d.ts.map +1 -1
  78. package/dist/types/src/components/SheetToolbar/SheetToolbar.d.ts.map +1 -1
  79. package/dist/types/src/components/SheetToolbar/align.d.ts +12 -19
  80. package/dist/types/src/components/SheetToolbar/align.d.ts.map +1 -1
  81. package/dist/types/src/components/SheetToolbar/style.d.ts +12 -18
  82. package/dist/types/src/components/SheetToolbar/style.d.ts.map +1 -1
  83. package/dist/types/src/components/SheetToolbar/useToolbarState.d.ts +14 -1
  84. package/dist/types/src/components/SheetToolbar/useToolbarState.d.ts.map +1 -1
  85. package/dist/types/src/components/index.d.ts +1 -1
  86. package/dist/types/src/components/index.d.ts.map +1 -1
  87. package/dist/types/src/extensions/compute.stories.d.ts.map +1 -1
  88. package/dist/types/src/extensions/editor/sheet-extension.d.ts.map +1 -1
  89. package/dist/types/src/index.d.ts +1 -1
  90. package/dist/types/src/index.d.ts.map +1 -1
  91. package/dist/types/src/integrations/thread-ranges.d.ts.map +1 -1
  92. package/dist/types/src/meta.d.ts +2 -2
  93. package/dist/types/src/meta.d.ts.map +1 -1
  94. package/dist/types/src/model/sheet-model.d.ts.map +1 -1
  95. package/dist/types/src/testing/testing.d.ts +13 -13
  96. package/dist/types/src/types/Sheet.d.ts +38 -32
  97. package/dist/types/src/types/Sheet.d.ts.map +1 -1
  98. package/dist/types/src/types/capabilities.d.ts +6 -0
  99. package/dist/types/src/types/capabilities.d.ts.map +1 -0
  100. package/dist/types/src/types/index.d.ts +1 -0
  101. package/dist/types/src/types/index.d.ts.map +1 -1
  102. package/dist/types/src/types/types.d.ts +91 -65
  103. package/dist/types/src/types/types.d.ts.map +1 -1
  104. package/dist/types/src/types/util.d.ts +2 -1
  105. package/dist/types/src/types/util.d.ts.map +1 -1
  106. package/dist/types/tsconfig.tsbuildinfo +1 -1
  107. package/package.json +75 -70
  108. package/src/SheetPlugin.tsx +42 -58
  109. package/src/capabilities/anchor-sort/anchor-sort.ts +26 -0
  110. package/src/capabilities/anchor-sort/index.ts +7 -0
  111. package/src/capabilities/compute-graph-registry/compute-graph-registry.ts +27 -0
  112. package/src/capabilities/compute-graph-registry/index.ts +7 -0
  113. package/src/capabilities/index.ts +5 -9
  114. package/src/capabilities/markdown/index.ts +7 -0
  115. package/src/capabilities/markdown/markdown.ts +30 -0
  116. package/src/capabilities/operation-resolver/index.ts +7 -0
  117. package/src/capabilities/operation-resolver/operation-resolver.ts +77 -0
  118. package/src/capabilities/react-surface/index.ts +7 -0
  119. package/src/capabilities/react-surface/react-surface.tsx +43 -0
  120. package/src/components/ComputeGraph/compute-graph.stories.tsx +1 -1
  121. package/src/components/GridSheet/GridSheet.stories.tsx +2 -2
  122. package/src/components/GridSheet/GridSheet.tsx +26 -28
  123. package/src/components/GridSheet/SheetCellEditor.stories.tsx +6 -3
  124. package/src/components/GridSheet/util.ts +1 -1
  125. package/src/components/RangeList/RangeList.tsx +5 -2
  126. package/src/components/SheetContainer/SheetContainer.stories.tsx +41 -21
  127. package/src/components/SheetContainer/SheetContainer.tsx +27 -20
  128. package/src/components/SheetContext/SheetContext.tsx +4 -4
  129. package/src/components/SheetToolbar/SheetToolbar.tsx +29 -18
  130. package/src/components/SheetToolbar/align.ts +41 -16
  131. package/src/components/SheetToolbar/style.ts +45 -15
  132. package/src/components/SheetToolbar/useToolbarState.ts +22 -5
  133. package/src/extensions/compute.stories.tsx +15 -6
  134. package/src/extensions/compute.ts +1 -1
  135. package/src/extensions/editor/sheet-extension.ts +7 -4
  136. package/src/index.ts +1 -1
  137. package/src/integrations/thread-ranges.ts +36 -40
  138. package/src/meta.ts +2 -2
  139. package/src/model/sheet-model.ts +67 -37
  140. package/src/playwright/playwright.config.ts +1 -1
  141. package/src/playwright/sheet.spec.ts +1 -0
  142. package/src/sanity.test.ts +1 -1
  143. package/src/types/Sheet.ts +22 -28
  144. package/src/{capabilities → types}/capabilities.ts +2 -2
  145. package/src/types/index.ts +1 -0
  146. package/src/types/types.ts +81 -37
  147. package/src/types/util.ts +2 -1
  148. package/dist/lib/browser/SheetContainer-WDKJPYCB.mjs +0 -349
  149. package/dist/lib/browser/SheetContainer-WDKJPYCB.mjs.map +0 -7
  150. package/dist/lib/browser/anchor-sort-OWOAGQM6.mjs.map +0 -7
  151. package/dist/lib/browser/chunk-6ILNTWSF.mjs +0 -852
  152. package/dist/lib/browser/chunk-6ILNTWSF.mjs.map +0 -7
  153. package/dist/lib/browser/chunk-73AV3NH6.mjs +0 -15
  154. package/dist/lib/browser/chunk-73AV3NH6.mjs.map +0 -7
  155. package/dist/lib/browser/chunk-7VEWYJJN.mjs.map +0 -7
  156. package/dist/lib/browser/chunk-FWFAAGXL.mjs +0 -28
  157. package/dist/lib/browser/chunk-FWFAAGXL.mjs.map +0 -7
  158. package/dist/lib/browser/chunk-GBK6OLCY.mjs +0 -907
  159. package/dist/lib/browser/chunk-GBK6OLCY.mjs.map +0 -7
  160. package/dist/lib/browser/compute-graph-registry-AP5RA7W3.mjs +0 -21
  161. package/dist/lib/browser/compute-graph-registry-AP5RA7W3.mjs.map +0 -7
  162. package/dist/lib/browser/intent-resolver-OMHQGXFL.mjs +0 -56
  163. package/dist/lib/browser/intent-resolver-OMHQGXFL.mjs.map +0 -7
  164. package/dist/lib/browser/markdown-B6VKYY2S.mjs +0 -26
  165. package/dist/lib/browser/markdown-B6VKYY2S.mjs.map +0 -7
  166. package/dist/lib/browser/react-surface-VPLFBQSV.mjs.map +0 -7
  167. package/dist/lib/node-esm/SheetContainer-62MZAU6Q.mjs +0 -350
  168. package/dist/lib/node-esm/SheetContainer-62MZAU6Q.mjs.map +0 -7
  169. package/dist/lib/node-esm/anchor-sort-FG3DS4HM.mjs.map +0 -7
  170. package/dist/lib/node-esm/chunk-44YTKTMP.mjs +0 -16
  171. package/dist/lib/node-esm/chunk-44YTKTMP.mjs.map +0 -7
  172. package/dist/lib/node-esm/chunk-4QV4AGWK.mjs.map +0 -7
  173. package/dist/lib/node-esm/chunk-HILDMVPL.mjs +0 -29
  174. package/dist/lib/node-esm/chunk-HILDMVPL.mjs.map +0 -7
  175. package/dist/lib/node-esm/chunk-KSHCRK5J.mjs +0 -908
  176. package/dist/lib/node-esm/chunk-KSHCRK5J.mjs.map +0 -7
  177. package/dist/lib/node-esm/chunk-QI3PNRCD.mjs +0 -853
  178. package/dist/lib/node-esm/chunk-QI3PNRCD.mjs.map +0 -7
  179. package/dist/lib/node-esm/compute-graph-registry-UMQ5UYCL.mjs +0 -22
  180. package/dist/lib/node-esm/compute-graph-registry-UMQ5UYCL.mjs.map +0 -7
  181. package/dist/lib/node-esm/intent-resolver-DHEHYV3B.mjs +0 -57
  182. package/dist/lib/node-esm/intent-resolver-DHEHYV3B.mjs.map +0 -7
  183. package/dist/lib/node-esm/markdown-VKY7HXU2.mjs +0 -27
  184. package/dist/lib/node-esm/markdown-VKY7HXU2.mjs.map +0 -7
  185. package/dist/lib/node-esm/react-surface-YLTZQVNL.mjs.map +0 -7
  186. package/dist/types/src/capabilities/anchor-sort.d.ts +0 -4
  187. package/dist/types/src/capabilities/anchor-sort.d.ts.map +0 -1
  188. package/dist/types/src/capabilities/capabilities.d.ts +0 -5
  189. package/dist/types/src/capabilities/capabilities.d.ts.map +0 -1
  190. package/dist/types/src/capabilities/compute-graph-registry.d.ts +0 -4
  191. package/dist/types/src/capabilities/compute-graph-registry.d.ts.map +0 -1
  192. package/dist/types/src/capabilities/intent-resolver.d.ts +0 -4
  193. package/dist/types/src/capabilities/intent-resolver.d.ts.map +0 -1
  194. package/dist/types/src/capabilities/markdown.d.ts +0 -4
  195. package/dist/types/src/capabilities/markdown.d.ts.map +0 -1
  196. package/dist/types/src/capabilities/react-surface.d.ts +0 -4
  197. package/dist/types/src/capabilities/react-surface.d.ts.map +0 -1
  198. package/src/capabilities/anchor-sort.ts +0 -21
  199. package/src/capabilities/compute-graph-registry.ts +0 -23
  200. package/src/capabilities/intent-resolver.ts +0 -38
  201. package/src/capabilities/markdown.ts +0 -23
  202. package/src/capabilities/react-surface.tsx +0 -41
@@ -13,9 +13,9 @@ 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';
18
+ import { Obj } from '@dxos/echo';
19
19
  import { defaultColSize, defaultRowSize } from '@dxos/lit-grid';
20
20
  import { DropdownMenu, Icon, useTranslation } from '@dxos/react-ui';
21
21
  import { useAttention } from '@dxos/react-ui-attention';
@@ -36,7 +36,7 @@ import {
36
36
  import { type RangeController, rangeExtension, sheetExtension } from '../../extensions';
37
37
  import { useSelectThreadOnCellFocus, useUpdateFocusedCellOnThreadSelection } from '../../integrations';
38
38
  import { meta } from '../../meta';
39
- import { DEFAULT_COLS, DEFAULT_ROWS, SheetAction } from '../../types';
39
+ import { DEFAULT_COLS, DEFAULT_ROWS, SheetOperation } from '../../types';
40
40
  import { useSheetContext } from '../SheetContext';
41
41
 
42
42
  import { colLabelCell, rowLabelCell, useSheetModelDxGridProps } from './util';
@@ -77,7 +77,7 @@ export const GridSheet = () => {
77
77
  // a reliable dependency for `useEffect` whereas `useLayoutEffect` does not guarantee the element will be defined.
78
78
  const [dxGrid, setDxGrid] = useState<DxGridElement | null>(null);
79
79
  const [extraplanarFocus, setExtraplanarFocus] = useState<DxGridPosition | null>(null);
80
- const { dispatchPromise: dispatch } = useIntentDispatcher();
80
+ const { invokePromise } = useOperationInvoker();
81
81
  const rangeController = useRef<RangeController>(null);
82
82
  const { hasAttention } = useAttention(id);
83
83
 
@@ -128,15 +128,17 @@ export const GridSheet = () => {
128
128
 
129
129
  const handleAxisResize = useCallback<NonNullable<GridContentProps['onAxisResize']>>(
130
130
  ({ axis, size, index: numericIndex }) => {
131
- if (axis === 'row') {
132
- const rowId = model.sheet.rows[parseInt(numericIndex)];
133
- model.sheet.rowMeta[rowId] ??= {};
134
- model.sheet.rowMeta[rowId].size = size;
135
- } else {
136
- const columnId = model.sheet.columns[parseInt(numericIndex)];
137
- model.sheet.columnMeta[columnId] ??= {};
138
- model.sheet.columnMeta[columnId].size = size;
139
- }
131
+ Obj.change(model.sheet, (sheet) => {
132
+ if (axis === 'row') {
133
+ const rowId = sheet.rows[parseInt(numericIndex)];
134
+ sheet.rowMeta[rowId] ??= {};
135
+ sheet.rowMeta[rowId].size = size;
136
+ } else {
137
+ const columnId = sheet.columns[parseInt(numericIndex)];
138
+ sheet.columnMeta[columnId] ??= {};
139
+ sheet.columnMeta[columnId].size = size;
140
+ }
141
+ });
140
142
  },
141
143
  [model],
142
144
  );
@@ -266,24 +268,20 @@ export const GridSheet = () => {
266
268
  switch (operation) {
267
269
  case 'insert-before':
268
270
  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
- );
271
+ return invokePromise(SheetOperation.InsertAxis, {
272
+ model,
273
+ axis: contextMenuAxis,
274
+ index: contextMenuOpen![contextMenuAxis] + (operation === 'insert-before' ? 0 : 1),
275
+ });
276
276
  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
- );
277
+ return invokePromise(SheetOperation.DropAxis, {
278
+ model,
279
+ axis: contextMenuAxis,
280
+ axisIndex: model.sheet[contextMenuAxis === 'row' ? 'rows' : 'columns'][contextMenuOpen![contextMenuAxis]],
281
+ });
284
282
  }
285
283
  },
286
- [contextMenuAxis, contextMenuOpen, model, dispatch],
284
+ [contextMenuAxis, contextMenuOpen, model, invokePromise],
287
285
  );
288
286
 
289
287
  const { columns, rows } = useSheetModelDxGridProps(dxGrid, model);
@@ -8,11 +8,12 @@ import React, { useMemo, useState } from 'react';
8
8
  import { Client } from '@dxos/client';
9
9
  import { defaultFunctions } from '@dxos/compute';
10
10
  import { getRegisteredFunctionNames } from '@dxos/compute/testing';
11
+ import { Obj } from '@dxos/echo';
11
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]);
@@ -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: [