@dxos/plugin-sheet 0.8.2-main.f11618f → 0.8.2-staging.42af850

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 (188) hide show
  1. package/dist/lib/browser/SheetContainer-GXPG3ZDN.mjs +351 -0
  2. package/dist/lib/browser/SheetContainer-GXPG3ZDN.mjs.map +7 -0
  3. package/dist/lib/browser/anchor-sort-CUTFYIT4.mjs +24 -0
  4. package/dist/lib/browser/anchor-sort-CUTFYIT4.mjs.map +7 -0
  5. package/dist/lib/browser/{chunk-HRTIOTK7.mjs → chunk-5FLX3UGU.mjs} +53 -61
  6. package/dist/lib/browser/chunk-5FLX3UGU.mjs.map +7 -0
  7. package/dist/lib/browser/chunk-AYMJXZFS.mjs +847 -0
  8. package/dist/lib/browser/chunk-AYMJXZFS.mjs.map +7 -0
  9. package/dist/lib/browser/{chunk-AT5ZK6JD.mjs → chunk-FJRLDX7Z.mjs} +1 -1
  10. package/dist/lib/browser/chunk-FJRLDX7Z.mjs.map +7 -0
  11. package/dist/lib/browser/{chunk-EMSCNWEK.mjs → chunk-IR42IS3F.mjs} +2 -2
  12. package/dist/lib/{node-esm/chunk-76T5X4VP.mjs.map → browser/chunk-IR42IS3F.mjs.map} +1 -1
  13. package/dist/lib/browser/{compute-graph-registry-WEJLJJ6T.mjs → compute-graph-registry-IXGGJJBU.mjs} +3 -3
  14. package/dist/lib/browser/compute-graph-registry-IXGGJJBU.mjs.map +7 -0
  15. package/dist/lib/browser/index.mjs +15 -14
  16. package/dist/lib/browser/index.mjs.map +3 -3
  17. package/dist/lib/browser/{intent-resolver-OMXW6BDZ.mjs → intent-resolver-UI4DHURQ.mjs} +2 -2
  18. package/dist/lib/browser/{markdown-DR4RDEEY.mjs → markdown-T4TUP4BF.mjs} +4 -4
  19. package/dist/lib/browser/markdown-T4TUP4BF.mjs.map +7 -0
  20. package/dist/lib/browser/meta.json +1 -1
  21. package/dist/lib/browser/{react-surface-RTQDRQ4X.mjs → react-surface-KI6T5M2X.mjs} +5 -5
  22. package/dist/lib/browser/types/index.mjs +1 -1
  23. package/dist/lib/node/SheetContainer-UUDOHLZR.cjs +351 -0
  24. package/dist/lib/node/SheetContainer-UUDOHLZR.cjs.map +7 -0
  25. package/dist/lib/node/{thread-NVEWN3H2.cjs → anchor-sort-LTLYUTUP.cjs} +17 -10
  26. package/dist/lib/node/anchor-sort-LTLYUTUP.cjs.map +7 -0
  27. package/dist/lib/node/{chunk-C3Q4GSES.cjs → chunk-76NESQLB.cjs} +69 -77
  28. package/dist/lib/node/chunk-76NESQLB.cjs.map +7 -0
  29. package/dist/lib/node/chunk-BXBNSNDK.cjs +855 -0
  30. package/dist/lib/node/chunk-BXBNSNDK.cjs.map +7 -0
  31. package/dist/lib/node/{chunk-LEV7OSTK.cjs → chunk-FIM6EZ6M.cjs} +4 -4
  32. package/dist/lib/node/chunk-FIM6EZ6M.cjs.map +7 -0
  33. package/dist/lib/node/{chunk-O2FOEUYB.cjs → chunk-LJWWS53Z.cjs} +5 -5
  34. package/dist/lib/node/{chunk-O2FOEUYB.cjs.map → chunk-LJWWS53Z.cjs.map} +1 -1
  35. package/dist/lib/node/{compute-graph-registry-VVSRJUGS.cjs → compute-graph-registry-ARLDHPFW.cjs} +7 -7
  36. package/dist/lib/node/compute-graph-registry-ARLDHPFW.cjs.map +7 -0
  37. package/dist/lib/node/index.cjs +21 -20
  38. package/dist/lib/node/index.cjs.map +3 -3
  39. package/dist/lib/node/{intent-resolver-KI5DG7LR.cjs → intent-resolver-EVLGL7VZ.cjs} +9 -9
  40. package/dist/lib/node/{markdown-E7OUIMZO.cjs → markdown-DBPOAYI7.cjs} +8 -8
  41. package/dist/lib/node/markdown-DBPOAYI7.cjs.map +7 -0
  42. package/dist/lib/node/meta.json +1 -1
  43. package/dist/lib/node/{react-surface-ZDOTWZ4Q.cjs → react-surface-QHAPOAR2.cjs} +14 -14
  44. package/dist/lib/node/types/index.cjs +29 -29
  45. package/dist/lib/node/types/index.cjs.map +1 -1
  46. package/dist/lib/node-esm/SheetContainer-44KHKMPI.mjs +352 -0
  47. package/dist/lib/node-esm/SheetContainer-44KHKMPI.mjs.map +7 -0
  48. package/dist/lib/node-esm/anchor-sort-3E2VGLO6.mjs +25 -0
  49. package/dist/lib/node-esm/anchor-sort-3E2VGLO6.mjs.map +7 -0
  50. package/dist/lib/node-esm/{chunk-SWRUEW6J.mjs → chunk-DIF3IOAB.mjs} +53 -61
  51. package/dist/lib/node-esm/chunk-DIF3IOAB.mjs.map +7 -0
  52. package/dist/lib/node-esm/chunk-GCCM7R45.mjs +848 -0
  53. package/dist/lib/node-esm/chunk-GCCM7R45.mjs.map +7 -0
  54. package/dist/lib/node-esm/{chunk-76T5X4VP.mjs → chunk-IQ76YE6M.mjs} +2 -2
  55. package/dist/lib/{browser/chunk-EMSCNWEK.mjs.map → node-esm/chunk-IQ76YE6M.mjs.map} +1 -1
  56. package/dist/lib/node-esm/{chunk-HXBUY5ET.mjs → chunk-NMCVJWDT.mjs} +1 -1
  57. package/dist/lib/node-esm/chunk-NMCVJWDT.mjs.map +7 -0
  58. package/dist/lib/node-esm/{compute-graph-registry-PBQ52KH6.mjs → compute-graph-registry-7PDWXMHF.mjs} +3 -3
  59. package/dist/lib/node-esm/compute-graph-registry-7PDWXMHF.mjs.map +7 -0
  60. package/dist/lib/node-esm/index.mjs +15 -14
  61. package/dist/lib/node-esm/index.mjs.map +3 -3
  62. package/dist/lib/node-esm/{intent-resolver-3FVOBB3K.mjs → intent-resolver-TPOH5JM5.mjs} +2 -2
  63. package/dist/lib/node-esm/{markdown-BPKS2TNG.mjs → markdown-WWUJ3E5F.mjs} +4 -4
  64. package/dist/lib/node-esm/markdown-WWUJ3E5F.mjs.map +7 -0
  65. package/dist/lib/node-esm/meta.json +1 -1
  66. package/dist/lib/node-esm/{react-surface-T4OVUZY2.mjs → react-surface-XT2J3S67.mjs} +5 -5
  67. package/dist/lib/node-esm/types/index.mjs +1 -1
  68. package/dist/types/src/SheetPlugin.d.ts.map +1 -1
  69. package/dist/types/src/capabilities/anchor-sort.d.ts +6 -0
  70. package/dist/types/src/capabilities/anchor-sort.d.ts.map +1 -0
  71. package/dist/types/src/capabilities/compute-graph-registry.d.ts +2 -2
  72. package/dist/types/src/capabilities/compute-graph-registry.d.ts.map +1 -1
  73. package/dist/types/src/capabilities/index.d.ts +6 -6
  74. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  75. package/dist/types/src/capabilities/markdown.d.ts +2 -2
  76. package/dist/types/src/capabilities/markdown.d.ts.map +1 -1
  77. package/dist/types/src/components/ComputeGraph/ComputeGraphContextProvider.d.ts.map +1 -1
  78. package/dist/types/src/components/GridSheet/GridSheet.d.ts.map +1 -1
  79. package/dist/types/src/components/GridSheet/GridSheet.stories.d.ts.map +1 -1
  80. package/dist/types/src/components/GridSheet/util.d.ts.map +1 -1
  81. package/dist/types/src/components/RangeList/RangeList.d.ts.map +1 -1
  82. package/dist/types/src/components/SheetContainer/SheetContainer.d.ts +3 -2
  83. package/dist/types/src/components/SheetContainer/SheetContainer.d.ts.map +1 -1
  84. package/dist/types/src/components/SheetContainer/SheetContainer.stories.d.ts.map +1 -1
  85. package/dist/types/src/components/SheetContext/SheetContext.d.ts.map +1 -1
  86. package/dist/types/src/components/SheetToolbar/SheetToolbar.d.ts +2 -2
  87. package/dist/types/src/components/SheetToolbar/SheetToolbar.d.ts.map +1 -1
  88. package/dist/types/src/components/SheetToolbar/align.d.ts +4 -1
  89. package/dist/types/src/components/SheetToolbar/align.d.ts.map +1 -1
  90. package/dist/types/src/components/SheetToolbar/style.d.ts +3 -1
  91. package/dist/types/src/components/SheetToolbar/style.d.ts.map +1 -1
  92. package/dist/types/src/components/SheetToolbar/useToolbarState.d.ts +2 -3
  93. package/dist/types/src/components/SheetToolbar/useToolbarState.d.ts.map +1 -1
  94. package/dist/types/src/components/index.d.ts +1 -6
  95. package/dist/types/src/components/index.d.ts.map +1 -1
  96. package/dist/types/src/extensions/compute.d.ts.map +1 -1
  97. package/dist/types/src/extensions/editor/extension.d.ts.map +1 -1
  98. package/dist/types/src/integrations/thread-ranges.d.ts.map +1 -1
  99. package/dist/types/src/model/sheet-model.d.ts.map +1 -1
  100. package/dist/types/src/model/testing.d.ts.map +1 -1
  101. package/dist/types/src/model/useSheetModel.d.ts.map +1 -1
  102. package/dist/types/src/serializer.d.ts.map +1 -1
  103. package/dist/types/src/testing/data.d.ts.map +1 -1
  104. package/dist/types/src/testing/playwright/sheet-manager.d.ts.map +1 -1
  105. package/dist/types/src/testing/testing.d.ts.map +1 -1
  106. package/dist/types/src/translations.d.ts +2 -54
  107. package/dist/types/src/translations.d.ts.map +1 -1
  108. package/dist/types/src/types/schema.d.ts +38 -374
  109. package/dist/types/src/types/schema.d.ts.map +1 -1
  110. package/dist/types/src/types/sheet-range-types.d.ts.map +1 -1
  111. package/dist/types/src/types/types.d.ts +36 -36
  112. package/dist/types/src/types/types.d.ts.map +1 -1
  113. package/dist/types/src/types/util.d.ts.map +1 -1
  114. package/dist/types/tsconfig.tsbuildinfo +1 -1
  115. package/package.json +55 -48
  116. package/src/SheetPlugin.tsx +7 -5
  117. package/src/capabilities/anchor-sort.ts +22 -0
  118. package/src/capabilities/compute-graph-registry.ts +3 -3
  119. package/src/capabilities/index.ts +1 -1
  120. package/src/capabilities/markdown.ts +3 -3
  121. package/src/components/ComputeGraph/compute-graph.stories.tsx +2 -2
  122. package/src/components/FunctionEditor/FunctionEditor.tsx +1 -1
  123. package/src/components/GridSheet/GridSheet.stories.tsx +5 -2
  124. package/src/components/GridSheet/GridSheet.tsx +18 -12
  125. package/src/components/GridSheet/SheetCellEditor.stories.tsx +2 -2
  126. package/src/components/GridSheet/util.ts +17 -11
  127. package/src/components/RangeList/RangeList.tsx +2 -2
  128. package/src/components/SheetContainer/SheetContainer.stories.tsx +3 -6
  129. package/src/components/SheetContainer/SheetContainer.tsx +5 -8
  130. package/src/components/SheetToolbar/SheetToolbar.stories.tsx +2 -2
  131. package/src/components/SheetToolbar/SheetToolbar.tsx +56 -20
  132. package/src/components/SheetToolbar/align.ts +44 -14
  133. package/src/components/SheetToolbar/style.ts +48 -12
  134. package/src/components/SheetToolbar/useToolbarState.ts +1 -2
  135. package/src/extensions/compute.ts +1 -1
  136. package/src/integrations/thread-ranges.ts +14 -17
  137. package/src/model/sheet-model.test.ts +1 -1
  138. package/src/model/sheet-model.ts +17 -17
  139. package/src/sanity.test.ts +1 -1
  140. package/src/serializer.ts +1 -2
  141. package/src/testing/playwright/sheet-manager.ts +9 -9
  142. package/src/types/schema.ts +20 -22
  143. package/src/types/types.ts +25 -25
  144. package/src/types/util.ts +0 -1
  145. package/dist/lib/browser/SheetContainer-7DK3ZZUT.mjs +0 -370
  146. package/dist/lib/browser/SheetContainer-7DK3ZZUT.mjs.map +0 -7
  147. package/dist/lib/browser/chunk-AT5ZK6JD.mjs.map +0 -7
  148. package/dist/lib/browser/chunk-HRTIOTK7.mjs.map +0 -7
  149. package/dist/lib/browser/chunk-IE42HBFC.mjs +0 -815
  150. package/dist/lib/browser/chunk-IE42HBFC.mjs.map +0 -7
  151. package/dist/lib/browser/compute-graph-registry-WEJLJJ6T.mjs.map +0 -7
  152. package/dist/lib/browser/markdown-DR4RDEEY.mjs.map +0 -7
  153. package/dist/lib/browser/thread-HV32Z27A.mjs +0 -17
  154. package/dist/lib/browser/thread-HV32Z27A.mjs.map +0 -7
  155. package/dist/lib/node/SheetContainer-6RPY4P7E.cjs +0 -364
  156. package/dist/lib/node/SheetContainer-6RPY4P7E.cjs.map +0 -7
  157. package/dist/lib/node/chunk-C3Q4GSES.cjs.map +0 -7
  158. package/dist/lib/node/chunk-LEV7OSTK.cjs.map +0 -7
  159. package/dist/lib/node/chunk-UXSU6W7E.cjs +0 -822
  160. package/dist/lib/node/chunk-UXSU6W7E.cjs.map +0 -7
  161. package/dist/lib/node/compute-graph-registry-VVSRJUGS.cjs.map +0 -7
  162. package/dist/lib/node/markdown-E7OUIMZO.cjs.map +0 -7
  163. package/dist/lib/node/thread-NVEWN3H2.cjs.map +0 -7
  164. package/dist/lib/node-esm/SheetContainer-QQUB22WF.mjs +0 -371
  165. package/dist/lib/node-esm/SheetContainer-QQUB22WF.mjs.map +0 -7
  166. package/dist/lib/node-esm/chunk-HXBUY5ET.mjs.map +0 -7
  167. package/dist/lib/node-esm/chunk-JSVXC3QP.mjs +0 -816
  168. package/dist/lib/node-esm/chunk-JSVXC3QP.mjs.map +0 -7
  169. package/dist/lib/node-esm/chunk-SWRUEW6J.mjs.map +0 -7
  170. package/dist/lib/node-esm/compute-graph-registry-PBQ52KH6.mjs.map +0 -7
  171. package/dist/lib/node-esm/markdown-BPKS2TNG.mjs.map +0 -7
  172. package/dist/lib/node-esm/thread-DTWGGMW4.mjs +0 -18
  173. package/dist/lib/node-esm/thread-DTWGGMW4.mjs.map +0 -7
  174. package/dist/types/src/capabilities/thread.d.ts +0 -6
  175. package/dist/types/src/capabilities/thread.d.ts.map +0 -1
  176. package/dist/types/src/components/SheetToolbar/comment.d.ts +0 -23
  177. package/dist/types/src/components/SheetToolbar/comment.d.ts.map +0 -1
  178. package/dist/types/src/components/SheetToolbar/useToolbarAction.d.ts +0 -8
  179. package/dist/types/src/components/SheetToolbar/useToolbarAction.d.ts.map +0 -1
  180. package/src/capabilities/thread.ts +0 -14
  181. package/src/components/SheetToolbar/comment.ts +0 -56
  182. package/src/components/SheetToolbar/useToolbarAction.ts +0 -87
  183. /package/dist/lib/browser/{intent-resolver-OMXW6BDZ.mjs.map → intent-resolver-UI4DHURQ.mjs.map} +0 -0
  184. /package/dist/lib/browser/{react-surface-RTQDRQ4X.mjs.map → react-surface-KI6T5M2X.mjs.map} +0 -0
  185. /package/dist/lib/node/{intent-resolver-KI5DG7LR.cjs.map → intent-resolver-EVLGL7VZ.cjs.map} +0 -0
  186. /package/dist/lib/node/{react-surface-ZDOTWZ4Q.cjs.map → react-surface-QHAPOAR2.cjs.map} +0 -0
  187. /package/dist/lib/node-esm/{intent-resolver-3FVOBB3K.mjs.map → intent-resolver-TPOH5JM5.mjs.map} +0 -0
  188. /package/dist/lib/node-esm/{react-surface-T4OVUZY2.mjs.map → react-surface-XT2J3S67.mjs.map} +0 -0
@@ -5,7 +5,7 @@
5
5
  import { useEffect, useState } from 'react';
6
6
 
7
7
  import { inRange } from '@dxos/compute';
8
- import { createDocAccessor, fullyQualifiedId } from '@dxos/react-client/echo';
8
+ import { createDocAccessor } from '@dxos/react-client/echo';
9
9
  import { parseValue, cellClassesForFieldType } from '@dxos/react-ui-form';
10
10
  import {
11
11
  type GridContentProps,
@@ -21,7 +21,6 @@ import {
21
21
  } from '@dxos/react-ui-grid';
22
22
  import { mx } from '@dxos/react-ui-theme';
23
23
 
24
- import { parseThreadAnchorAsCellRange } from '../../integrations';
25
24
  import { type SheetModel } from '../../model';
26
25
  import { cellClassNameForRange, rangeFromIndex } from '../../types';
27
26
 
@@ -53,13 +52,15 @@ const projectCellProps = (model: SheetModel, col: number, row: number): DxGridCe
53
52
  const address = { col, row };
54
53
  const rawValue = model.getValue(address);
55
54
  const ranges = model.sheet.ranges?.filter(({ range }) => inRange(rangeFromIndex(model.sheet, range), address));
56
- const threadRefs = model.sheet.threads
57
- ?.filter((thread) => {
58
- const range = thread.target?.anchor && parseThreadAnchorAsCellRange(thread.target!.anchor);
59
- return thread && range ? inRange(range, address) : false;
60
- })
61
- .map((thread) => fullyQualifiedId(thread!))
62
- .join(' ');
55
+ const threadRefs = undefined;
56
+ // TODO(wittjosiah): Update this to get threads via relations.
57
+ // model.sheet.threads
58
+ // ?.filter((thread) => {
59
+ // const range = thread.target?.anchor && parseThreadAnchorAsCellRange(thread.target!.anchor);
60
+ // return thread && range ? inRange(range, address) : false;
61
+ // })
62
+ // .map((thread) => fullyQualifiedId(thread!))
63
+ // .join(' ');
63
64
 
64
65
  const description = model.getValueDescription(address);
65
66
  const type = description?.type;
@@ -89,13 +90,13 @@ const gridCellGetter = (model: SheetModel) => {
89
90
 
90
91
  export const rowLabelCell = (row: number) => ({
91
92
  value: rowToA1Notation(row),
92
- className: 'text-end pie-1 text-subdued',
93
+ className: '!bg-toolbarSurface text-subdued text-end pie-1',
93
94
  resizeHandle: 'row',
94
95
  });
95
96
 
96
97
  export const colLabelCell = (col: number) => ({
97
98
  value: colToA1Notation(col),
98
- className: 'text-subdued',
99
+ className: '!bg-toolbarSurface text-subdued',
99
100
  resizeHandle: 'col',
100
101
  });
101
102
 
@@ -105,6 +106,11 @@ const cellGetter = (model: SheetModel) => {
105
106
  switch (plane) {
106
107
  case 'grid':
107
108
  return getGridCells(nextBounds);
109
+ case 'fixedStartStart': {
110
+ return {
111
+ '0,0': { className: '!bg-toolbarSurface' },
112
+ };
113
+ }
108
114
  case 'frozenColsStart':
109
115
  return [...Array(nextBounds.end.row - nextBounds.start.row)].reduce((acc, _, r0) => {
110
116
  const r = nextBounds.start.row + r0;
@@ -2,10 +2,10 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
+ import { Schema } from 'effect';
5
6
  import React, { useCallback } from 'react';
6
7
 
7
8
  import { rangeToA1Notation } from '@dxos/compute';
8
- import { S } from '@dxos/echo-schema';
9
9
  import { useTranslation } from '@dxos/react-ui';
10
10
  import { List } from '@dxos/react-ui-list';
11
11
  import { ghostHover } from '@dxos/react-ui-theme';
@@ -32,7 +32,7 @@ export const RangeList = ({ sheet }: RangeListProps) => {
32
32
  return (
33
33
  <>
34
34
  <h2 className='p-2 text-sm font-semibold'>{t('range list heading')}</h2>
35
- <List.Root<Range> items={sheet.ranges} isItem={S.is(Range)}>
35
+ <List.Root<Range> items={sheet.ranges} isItem={Schema.is(Range)}>
36
36
  {({ items: ranges }) =>
37
37
  ranges.map((range, i) => (
38
38
  <List.Item key={i} item={range} classNames={['p-2', ghostHover]}>
@@ -9,6 +9,7 @@ import React from 'react';
9
9
 
10
10
  import { Capabilities, contributes, createResolver, IntentPlugin } from '@dxos/app-framework';
11
11
  import { withPluginManager } from '@dxos/app-framework/testing';
12
+ import { GraphPlugin } from '@dxos/plugin-graph';
12
13
  import { fullyQualifiedId, useSpace } from '@dxos/react-client/echo';
13
14
  import { withClientProvider } from '@dxos/react-client/testing';
14
15
  import { AttendableContainer } from '@dxos/react-ui-attention';
@@ -64,15 +65,11 @@ const meta: Meta = {
64
65
  withClientProvider({ types: [SheetType], createSpace: true }),
65
66
  withComputeGraphDecorator(),
66
67
  withTheme,
67
- withLayout({
68
- fullscreen: true,
69
- tooltips: true,
70
- classNames: 'grid',
71
- }),
68
+ withLayout({ fullscreen: true, classNames: 'grid' }),
72
69
  withAttention,
73
70
  // TODO(wittjosiah): Consider whether we should refactor component so story doesn't need to depend on intents.
74
71
  withPluginManager({
75
- plugins: [IntentPlugin()],
72
+ plugins: [IntentPlugin(), GraphPlugin()],
76
73
  capabilities: [
77
74
  contributes(
78
75
  Capabilities.IntentResolver,
@@ -14,23 +14,20 @@ import { GridSheet } from '../GridSheet';
14
14
  import { SheetProvider } from '../SheetContext';
15
15
  import { SheetToolbar } from '../SheetToolbar';
16
16
 
17
- export const SheetContainer = ({
18
- space,
19
- sheet,
20
- role,
21
- ignoreAttention,
22
- }: {
17
+ export type SheetContainerProps = {
23
18
  space: Space;
24
19
  sheet: SheetType;
25
20
  role?: string;
26
21
  ignoreAttention?: boolean;
27
- }) => {
22
+ };
23
+
24
+ export const SheetContainer = ({ space, sheet, role, ignoreAttention }: SheetContainerProps) => {
28
25
  const graph = useComputeGraph(space);
29
26
 
30
27
  return graph ? (
31
28
  <SheetProvider sheet={sheet} graph={graph} ignoreAttention={ignoreAttention}>
32
29
  <StackItem.Content toolbar statusbar {...(role === 'section' && { classNames: 'aspect-video' })}>
33
- <SheetToolbar attendableId={fullyQualifiedId(sheet)} />
30
+ <SheetToolbar id={fullyQualifiedId(sheet)} />
34
31
  <GridSheet />
35
32
  <FunctionEditor />
36
33
  </StackItem.Content>
@@ -14,7 +14,7 @@ import { SheetToolbar } from './SheetToolbar';
14
14
  import translations from '../../translations';
15
15
 
16
16
  const DefaultStory = () => {
17
- return <SheetToolbar classNames={textBlockWidth} />;
17
+ return <SheetToolbar id='test' classNames={textBlockWidth} />;
18
18
  };
19
19
 
20
20
  export const Default = {};
@@ -23,7 +23,7 @@ const meta: Meta = {
23
23
  title: 'plugins/plugin-sheet/Toolbar',
24
24
  component: SheetToolbar,
25
25
  render: DefaultStory,
26
- decorators: [withTheme, withLayout({ tooltips: true })],
26
+ decorators: [withTheme, withLayout()],
27
27
  parameters: { translations, layout: 'fullscreen' },
28
28
  };
29
29
 
@@ -2,46 +2,82 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import React, { type PropsWithChildren, useCallback } from 'react';
5
+ import { Rx } from '@effect-rx/rx-react';
6
+ import React, { type PropsWithChildren, useMemo } from 'react';
6
7
 
8
+ import { useAppGraph } from '@dxos/app-framework';
9
+ import { type CompleteCellRange } from '@dxos/compute';
7
10
  import { type ThemedClassName } from '@dxos/react-ui';
8
- import { createGapSeparator, MenuProvider, ToolbarMenu, useMenuActions } from '@dxos/react-ui-menu';
11
+ import {
12
+ type ActionGraphEdges,
13
+ type ActionGraphNodes,
14
+ type ActionGraphProps,
15
+ createGapSeparator,
16
+ MenuProvider,
17
+ rxFromSignal,
18
+ ToolbarMenu,
19
+ useMenuActions,
20
+ } from '@dxos/react-ui-menu';
9
21
 
10
22
  import { createAlign, useAlignState } from './align';
11
- import { createComment, useCommentState } from './comment';
12
23
  import { createStyle, useStyleState } from './style';
13
- import { useToolbarAction } from './useToolbarAction';
14
24
  import { type ToolbarState, useToolbarState } from './useToolbarState';
25
+ import { type SheetModel } from '../../model';
26
+ import { useSheetContext } from '../SheetContext';
15
27
 
16
28
  //
17
29
  // Root
18
30
  //
19
31
 
20
- export type SheetToolbarProps = ThemedClassName<PropsWithChildren<{ attendableId?: string }>>;
21
-
22
- const createToolbarActions = (state: ToolbarState) => {
23
- const align = createAlign(state);
24
- const style = createStyle(state);
25
- const gap = createGapSeparator();
26
- const comment = createComment(state);
27
- return {
28
- nodes: [...align.nodes, ...style.nodes, ...gap.nodes, ...comment.nodes],
29
- edges: [...align.edges, ...style.edges, ...gap.edges, ...comment.edges],
30
- };
32
+ export type SheetToolbarProps = ThemedClassName<PropsWithChildren<{ id: string }>>;
33
+
34
+ const createToolbarActions = (
35
+ model: SheetModel,
36
+ state: ToolbarState,
37
+ cursorFallbackRange?: CompleteCellRange,
38
+ customActions?: Rx.Rx<ActionGraphProps>,
39
+ ) => {
40
+ return Rx.make((get) => {
41
+ const align = get(rxFromSignal(() => createAlign(model, state, cursorFallbackRange)));
42
+ const style = get(rxFromSignal(() => createStyle(model, state, cursorFallbackRange)));
43
+ const gap = createGapSeparator();
44
+ const nodes: ActionGraphNodes = [...align.nodes, ...style.nodes, ...gap.nodes];
45
+ const edges: ActionGraphEdges = [...align.edges, ...style.edges, ...gap.edges];
46
+ if (customActions) {
47
+ const custom = get(customActions);
48
+ nodes.push(...custom.nodes);
49
+ edges.push(...custom.edges);
50
+ }
51
+ return {
52
+ nodes,
53
+ edges,
54
+ };
55
+ });
31
56
  };
32
57
 
33
- export const SheetToolbar = ({ attendableId, classNames }: SheetToolbarProps) => {
58
+ export const SheetToolbar = ({ id, classNames }: SheetToolbarProps) => {
59
+ const { model, cursorFallbackRange } = useSheetContext();
34
60
  const state = useToolbarState({});
35
61
  useAlignState(state);
36
62
  useStyleState(state);
37
- useCommentState(state);
38
63
 
39
- const actionsCreator = useCallback(() => createToolbarActions(state), [state]);
64
+ const { graph } = useAppGraph();
65
+ const customActions = useMemo(() => {
66
+ return Rx.make((get) => {
67
+ const actions = get(graph.actions(id));
68
+ const nodes = actions.filter((action) => action.properties.disposition === 'toolbar');
69
+ return { nodes, edges: nodes.map((node) => ({ source: 'root', target: node.id })) };
70
+ });
71
+ }, [graph]);
72
+
73
+ const actionsCreator = useMemo(
74
+ () => createToolbarActions(model, state, cursorFallbackRange, customActions),
75
+ [model, state, cursorFallbackRange, customActions],
76
+ );
40
77
  const menu = useMenuActions(actionsCreator);
41
- const handleAction = useToolbarAction(state);
42
78
 
43
79
  return (
44
- <MenuProvider {...menu} attendableId={attendableId} onAction={handleAction}>
80
+ <MenuProvider {...menu} attendableId={id}>
45
81
  <ToolbarMenu classNames={classNames} />
46
82
  </MenuProvider>
47
83
  );
@@ -4,11 +4,13 @@
4
4
 
5
5
  import { useEffect } from 'react';
6
6
 
7
- import { inRange } from '@dxos/compute';
7
+ import { type CompleteCellRange, inRange } from '@dxos/compute';
8
8
  import { createMenuAction, createMenuItemGroup, type ToolbarMenuActionGroupProperties } from '@dxos/react-ui-menu';
9
9
 
10
+ import { type ToolbarState } from './useToolbarState';
10
11
  import { SHEET_PLUGIN } from '../../meta';
11
- import { type AlignKey, alignKey, type AlignValue, rangeFromIndex } from '../../types';
12
+ import { type SheetModel } from '../../model';
13
+ import { type AlignKey, alignKey, type AlignValue, rangeFromIndex, rangeToIndex } from '../../types';
12
14
  import { useSheetContext } from '../SheetContext';
13
15
 
14
16
  export type AlignAction = { key: AlignKey; value: AlignValue };
@@ -43,21 +45,49 @@ const createAlignGroupAction = (value?: AlignValue) =>
43
45
  value: `${alignKey}--${value}`,
44
46
  } as ToolbarMenuActionGroupProperties);
45
47
 
46
- const createAlignActions = (value?: AlignValue) =>
48
+ const createAlignActions = (model: SheetModel, state: ToolbarState, cursorFallbackRange?: CompleteCellRange) =>
47
49
  Object.entries(aligns).map(([alignValue, icon]) => {
48
- return createMenuAction<AlignAction>(`${alignKey}--${alignValue}`, {
49
- key: alignKey,
50
- value: alignValue as AlignValue,
51
- checked: value === alignValue,
52
- label: [`range value ${alignValue} label`, { ns: SHEET_PLUGIN }],
53
- icon,
54
- testId: `grid.toolbar.${alignKey}.${alignValue}`,
55
- });
50
+ return createMenuAction<AlignAction>(
51
+ `${alignKey}--${alignValue}`,
52
+ () => {
53
+ if (!cursorFallbackRange) {
54
+ return;
55
+ }
56
+ const index =
57
+ model.sheet.ranges?.findIndex(
58
+ (range) =>
59
+ range.key === alignKey && inRange(rangeFromIndex(model.sheet, range.range), cursorFallbackRange.from),
60
+ ) ?? -1;
61
+ const nextRangeEntity = {
62
+ range: rangeToIndex(model.sheet, cursorFallbackRange),
63
+ key: alignKey,
64
+ value: alignValue as AlignValue,
65
+ };
66
+ if (index < 0) {
67
+ model.sheet.ranges?.push(nextRangeEntity);
68
+ state[alignKey] = nextRangeEntity.value;
69
+ } else if (model.sheet.ranges![index].value === nextRangeEntity.value) {
70
+ model.sheet.ranges?.splice(index, 1);
71
+ state[alignKey] = undefined;
72
+ } else {
73
+ model.sheet.ranges?.splice(index, 1, nextRangeEntity);
74
+ state[alignKey] = nextRangeEntity.value;
75
+ }
76
+ },
77
+ {
78
+ key: alignKey,
79
+ value: alignValue as AlignValue,
80
+ checked: state[alignKey] === alignValue,
81
+ label: [`range value ${alignValue} label`, { ns: SHEET_PLUGIN }],
82
+ icon,
83
+ testId: `grid.toolbar.${alignKey}.${alignValue}`,
84
+ },
85
+ );
56
86
  });
57
87
 
58
- export const createAlign = ({ [alignKey]: alignValue }: Partial<AlignState>) => {
59
- const alignGroup = createAlignGroupAction(alignValue);
60
- const alignActions = createAlignActions(alignValue);
88
+ export const createAlign = (model: SheetModel, state: ToolbarState, cursorFallbackRange?: CompleteCellRange) => {
89
+ const alignGroup = createAlignGroupAction(state[alignKey]);
90
+ const alignActions = createAlignActions(model, state, cursorFallbackRange);
61
91
  return {
62
92
  nodes: [alignGroup, ...alignActions],
63
93
  edges: [
@@ -4,11 +4,12 @@
4
4
 
5
5
  import { useEffect } from 'react';
6
6
 
7
- import { inRange } from '@dxos/compute';
7
+ import { type CompleteCellRange, inRange } from '@dxos/compute';
8
8
  import { createMenuAction, createMenuItemGroup, type ToolbarMenuActionGroupProperties } from '@dxos/react-ui-menu';
9
9
 
10
10
  import { SHEET_PLUGIN } from '../../meta';
11
- import { rangeFromIndex, type StyleKey, type StyleValue } from '../../types';
11
+ import { type SheetModel } from '../../model';
12
+ import { rangeFromIndex, rangeToIndex, type StyleKey, type StyleValue } from '../../types';
12
13
  import { useSheetContext } from '../SheetContext';
13
14
 
14
15
  export type StyleState = Partial<Record<StyleValue, boolean>>;
@@ -48,20 +49,55 @@ const createStyleGroup = (state: StyleState) => {
48
49
  } as ToolbarMenuActionGroupProperties);
49
50
  };
50
51
 
51
- const createStyleActions = (state: StyleState) =>
52
+ const createStyleActions = (model: SheetModel, state: StyleState, cursorFallbackRange?: CompleteCellRange) =>
52
53
  Object.entries(styles).map(([styleValue, icon]) => {
53
- return createMenuAction<StyleAction>(`style--${styleValue}`, {
54
- key: 'style',
55
- value: styleValue as StyleValue,
56
- icon,
57
- label: [`range value ${styleValue} label`, { ns: SHEET_PLUGIN }],
58
- checked: !!state[styleValue as StyleValue],
59
- });
54
+ return createMenuAction<StyleAction>(
55
+ `style--${styleValue}`,
56
+ () => {
57
+ if (!cursorFallbackRange) {
58
+ return;
59
+ }
60
+ const index =
61
+ model.sheet.ranges?.findIndex(
62
+ (range) =>
63
+ range.key === 'style' && inRange(rangeFromIndex(model.sheet, range.range), cursorFallbackRange.from),
64
+ ) ?? -1;
65
+ const nextRangeEntity = {
66
+ range: rangeToIndex(model.sheet, cursorFallbackRange),
67
+ key: 'style',
68
+ value: styleValue as StyleValue,
69
+ };
70
+ if (
71
+ model.sheet.ranges
72
+ .filter(
73
+ ({ range, key: rangeKey }) =>
74
+ rangeKey === 'style' && inRange(rangeFromIndex(model.sheet, range), cursorFallbackRange.from),
75
+ )
76
+ .some(({ value: rangeValue }) => rangeValue === styleValue)
77
+ ) {
78
+ // this value should be unset
79
+ if (index >= 0) {
80
+ model.sheet.ranges?.splice(index, 1);
81
+ }
82
+ state[nextRangeEntity.value] = false;
83
+ } else {
84
+ model.sheet.ranges?.push(nextRangeEntity);
85
+ state[nextRangeEntity.value] = true;
86
+ }
87
+ },
88
+ {
89
+ key: 'style',
90
+ value: styleValue as StyleValue,
91
+ icon,
92
+ label: [`range value ${styleValue} label`, { ns: SHEET_PLUGIN }],
93
+ checked: !!state[styleValue as StyleValue],
94
+ },
95
+ );
60
96
  });
61
97
 
62
- export const createStyle = (state: StyleState) => {
98
+ export const createStyle = (model: SheetModel, state: StyleState, cursorFallbackRange?: CompleteCellRange) => {
63
99
  const styleGroupAction = createStyleGroup(state);
64
- const styleActions = createStyleActions(state);
100
+ const styleActions = createStyleActions(model, state, cursorFallbackRange);
65
101
  return {
66
102
  nodes: [styleGroupAction, ...styleActions],
67
103
  edges: [
@@ -7,10 +7,9 @@ import { useMemo } from 'react';
7
7
  import { live } from '@dxos/live-object';
8
8
 
9
9
  import { type AlignState } from './align';
10
- import { type CommentState } from './comment';
11
10
  import { type StyleState } from './style';
12
11
 
13
- export type ToolbarState = Partial<StyleState & AlignState & CommentState>;
12
+ export type ToolbarState = Partial<StyleState & AlignState>;
14
13
 
15
14
  export const useToolbarState = (initialState: ToolbarState = {}) => {
16
15
  return useMemo(() => live<ToolbarState>(initialState), []);
@@ -141,7 +141,7 @@ class ComputeWidget extends WidgetType {
141
141
  super();
142
142
  }
143
143
 
144
- override toDOM(_view: EditorView) {
144
+ override toDOM(_view: EditorView): HTMLDivElement {
145
145
  const div = document.createElement('div');
146
146
  div.setAttribute('title', this.formula);
147
147
  div.innerText = String(this.value);
@@ -2,7 +2,7 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { pipe } from 'effect';
5
+ import { Schema, pipe } from 'effect';
6
6
  import { useCallback, useEffect, useMemo } from 'react';
7
7
 
8
8
  import {
@@ -15,11 +15,12 @@ import {
15
15
  } from '@dxos/app-framework';
16
16
  import { debounce } from '@dxos/async';
17
17
  import { type CellAddress, type CompleteCellRange, inRange } from '@dxos/compute';
18
- import { S } from '@dxos/echo-schema';
18
+ import { isInstanceOf, RelationSourceId } from '@dxos/echo-schema';
19
19
  import { ATTENDABLE_PATH_SEPARATOR, DeckAction } from '@dxos/plugin-deck/types';
20
- import { ThreadAction } from '@dxos/plugin-thread/types';
21
- import { fullyQualifiedId } from '@dxos/react-client/echo';
20
+ import { ThreadAction, ThreadType } from '@dxos/plugin-thread/types';
21
+ import { Filter, fullyQualifiedId, getSpace, Query, useQuery } from '@dxos/react-client/echo';
22
22
  import { type DxGridElement, type DxGridPosition, type GridContentProps } from '@dxos/react-ui-grid';
23
+ import { AnchoredTo } from '@dxos/schema';
23
24
 
24
25
  import { useSheetContext } from '../components';
25
26
  import { SHEET_PLUGIN } from '../meta';
@@ -55,7 +56,7 @@ export const useUpdateFocusedCellOnThreadSelection = (grid: DxGridElement | null
55
56
  subject: string;
56
57
  options: { cursor: string; ref: GridContentProps['activeRefs'] };
57
58
  } => {
58
- if (!S.is(LayoutAction.ScrollIntoView.fields.input)(data)) {
59
+ if (!Schema.is(LayoutAction.ScrollIntoView.fields.input)(data)) {
59
60
  return false;
60
61
  }
61
62
 
@@ -78,23 +79,19 @@ export const useSelectThreadOnCellFocus = () => {
78
79
  const { model, cursor } = useSheetContext();
79
80
  const { dispatchPromise: dispatch } = useIntentDispatcher();
80
81
 
81
- const threads = useMemo(
82
- () => model.sheet.threads?.filter((thread): thread is NonNullable<typeof thread> => !!thread) ?? [],
83
- [
84
- // TODO(thure): Surely we can find a better dependency for this…
85
- JSON.stringify(model.sheet.threads),
86
- ],
87
- );
82
+ const space = getSpace(model.sheet);
83
+ const anchors = useQuery(space, Query.select(Filter.ids(model.sheet.id)).targetOf(AnchoredTo));
88
84
 
89
85
  const selectClosestThread = useCallback(
90
86
  (cellAddress: CellAddress) => {
91
- if (!cellAddress || !threads) {
87
+ if (!cellAddress) {
92
88
  return;
93
89
  }
94
90
 
95
- const closestThread = threads?.find((ref) => {
96
- if (ref.target?.anchor) {
97
- const range = parseThreadAnchorAsCellRange(ref.target!.anchor);
91
+ const closestThread = anchors.find((anchor) => {
92
+ const source = anchor[RelationSourceId];
93
+ if (anchor.anchor && isInstanceOf(ThreadType, source)) {
94
+ const range = parseThreadAnchorAsCellRange(anchor.anchor);
98
95
  return range ? inRange(range, cellAddress) : false;
99
96
  } else {
100
97
  return false;
@@ -110,7 +107,7 @@ export const useSelectThreadOnCellFocus = () => {
110
107
  void dispatch(intent);
111
108
  }
112
109
  },
113
- [dispatch, threads],
110
+ [dispatch, anchors],
114
111
  );
115
112
 
116
113
  const debounced = useMemo(() => {
@@ -7,7 +7,7 @@ import { afterEach, beforeEach, describe, expect, onTestFinished, test } from 'v
7
7
  import { Trigger } from '@dxos/async';
8
8
  import { type CellScalarValue, addressFromA1Notation, isFormula } from '@dxos/compute';
9
9
  import { TestBuilder, testFunctionPlugins } from '@dxos/compute/testing';
10
- import { FunctionType } from '@dxos/functions/types';
10
+ import { FunctionType } from '@dxos/functions';
11
11
  import { log } from '@dxos/log';
12
12
 
13
13
  import { SheetModel } from './sheet-model';