@dxos/plugin-sheet 0.6.12-main.78ddbdf → 0.6.12-main.89e9959

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 (160) hide show
  1. package/dist/lib/browser/{SheetContainer-V4GCCZTX.mjs → SheetContainer-LG77O4RM.mjs} +14 -13
  2. package/dist/lib/browser/SheetContainer-LG77O4RM.mjs.map +7 -0
  3. package/dist/lib/browser/{chunk-U2JHW3L6.mjs → chunk-CHQAW4F4.mjs} +206 -53
  4. package/dist/lib/browser/chunk-CHQAW4F4.mjs.map +7 -0
  5. package/dist/lib/browser/{chunk-6ZMQVB4Z.mjs → chunk-GSV5QNLD.mjs} +220 -177
  6. package/dist/lib/browser/chunk-GSV5QNLD.mjs.map +7 -0
  7. package/dist/lib/browser/{chunk-T3NJFTD4.mjs → chunk-WZMOZKQZ.mjs} +2 -2
  8. package/dist/lib/browser/{chunk-T3NJFTD4.mjs.map → chunk-WZMOZKQZ.mjs.map} +3 -3
  9. package/dist/lib/browser/graph-M4IQ76QX.mjs +33 -0
  10. package/dist/lib/browser/index.mjs +45 -21
  11. package/dist/lib/browser/index.mjs.map +4 -4
  12. package/dist/lib/browser/meta.json +1 -1
  13. package/dist/lib/browser/types.mjs +1 -1
  14. package/dist/lib/node/{SheetContainer-3ZY7MPWJ.cjs → SheetContainer-OZ7DHH4L.cjs} +21 -20
  15. package/dist/lib/node/SheetContainer-OZ7DHH4L.cjs.map +7 -0
  16. package/dist/lib/node/{chunk-OTTD7FBK.cjs → chunk-5FTFZL5W.cjs} +224 -70
  17. package/dist/lib/node/chunk-5FTFZL5W.cjs.map +7 -0
  18. package/dist/lib/node/{chunk-DD6FIXWC.cjs → chunk-5XPK2V4A.cjs} +222 -175
  19. package/dist/lib/node/chunk-5XPK2V4A.cjs.map +7 -0
  20. package/dist/lib/node/{chunk-Q3HBHPRL.cjs → chunk-AOP42UAA.cjs} +5 -5
  21. package/dist/lib/node/{chunk-Q3HBHPRL.cjs.map → chunk-AOP42UAA.cjs.map} +3 -3
  22. package/dist/lib/node/graph-Q3N2X26H.cjs +55 -0
  23. package/dist/lib/node/graph-Q3N2X26H.cjs.map +7 -0
  24. package/dist/lib/node/index.cjs +51 -30
  25. package/dist/lib/node/index.cjs.map +4 -4
  26. package/dist/lib/node/meta.json +1 -1
  27. package/dist/lib/node/types.cjs +8 -8
  28. package/dist/lib/node/types.cjs.map +1 -1
  29. package/dist/lib/node-esm/{SheetContainer-PXSJX6XK.mjs → SheetContainer-4XS2G25Z.mjs} +14 -13
  30. package/dist/lib/node-esm/SheetContainer-4XS2G25Z.mjs.map +7 -0
  31. package/dist/lib/node-esm/{chunk-D6KU5MI7.mjs → chunk-5WPZCXNS.mjs} +220 -177
  32. package/dist/lib/node-esm/chunk-5WPZCXNS.mjs.map +7 -0
  33. package/dist/lib/node-esm/{chunk-7HVSOTGA.mjs → chunk-KK3XL37M.mjs} +206 -53
  34. package/dist/lib/node-esm/chunk-KK3XL37M.mjs.map +7 -0
  35. package/dist/lib/node-esm/{chunk-BMNA27EX.mjs → chunk-RR2AO4SM.mjs} +2 -2
  36. package/dist/lib/node-esm/{chunk-BMNA27EX.mjs.map → chunk-RR2AO4SM.mjs.map} +3 -3
  37. package/dist/lib/node-esm/graph-SMPUMOV2.mjs +34 -0
  38. package/dist/lib/node-esm/index.mjs +45 -21
  39. package/dist/lib/node-esm/index.mjs.map +4 -4
  40. package/dist/lib/node-esm/meta.json +1 -1
  41. package/dist/lib/node-esm/types.mjs +1 -1
  42. package/dist/types/src/SheetPlugin.d.ts.map +1 -1
  43. package/dist/types/src/components/CellEditor/CellEditor.stories.d.ts.map +1 -1
  44. package/dist/types/src/components/CellEditor/extension.d.ts.map +1 -1
  45. package/dist/types/src/components/GridSheet/GridSheet.d.ts +3 -3
  46. package/dist/types/src/components/GridSheet/GridSheet.d.ts.map +1 -1
  47. package/dist/types/src/components/GridSheet/GridSheet.stories.d.ts +1 -1
  48. package/dist/types/src/components/GridSheet/util.d.ts +9 -0
  49. package/dist/types/src/components/GridSheet/util.d.ts.map +1 -1
  50. package/dist/types/src/components/Sheet/Sheet.d.ts.map +1 -1
  51. package/dist/types/src/components/Sheet/Sheet.stories.d.ts.map +1 -1
  52. package/dist/types/src/components/Sheet/sheet-context.d.ts +3 -3
  53. package/dist/types/src/components/Sheet/sheet-context.d.ts.map +1 -1
  54. package/dist/types/src/components/SheetContainer.d.ts +1 -1
  55. package/dist/types/src/components/SheetContainer.d.ts.map +1 -1
  56. package/dist/types/src/components/index.d.ts +1 -1
  57. package/dist/types/src/components/index.d.ts.map +1 -1
  58. package/dist/types/src/defs/types.d.ts.map +1 -1
  59. package/dist/types/src/defs/util.d.ts +1 -1
  60. package/dist/types/src/defs/util.d.ts.map +1 -1
  61. package/dist/types/src/extensions/compute.d.ts +3 -2
  62. package/dist/types/src/extensions/compute.d.ts.map +1 -1
  63. package/dist/types/src/extensions/compute.stories.d.ts.map +1 -1
  64. package/dist/types/src/graph/compute-graph-registry.d.ts +34 -0
  65. package/dist/types/src/graph/compute-graph-registry.d.ts.map +1 -0
  66. package/dist/types/src/graph/compute-graph.d.ts +17 -34
  67. package/dist/types/src/graph/compute-graph.d.ts.map +1 -1
  68. package/dist/types/src/graph/compute-graph.stories.d.ts.map +1 -1
  69. package/dist/types/src/graph/compute-graph.test.d.ts +2 -0
  70. package/dist/types/src/graph/compute-graph.test.d.ts.map +1 -0
  71. package/dist/types/src/graph/compute-node.d.ts +9 -2
  72. package/dist/types/src/graph/compute-node.d.ts.map +1 -1
  73. package/dist/types/src/graph/{async-function.d.ts → functions/async-function.d.ts} +13 -4
  74. package/dist/types/src/graph/functions/async-function.d.ts.map +1 -0
  75. package/dist/types/src/graph/functions/edge-function.d.ts +21 -0
  76. package/dist/types/src/graph/functions/edge-function.d.ts.map +1 -0
  77. package/dist/types/src/graph/functions/function-defs.d.ts.map +1 -0
  78. package/dist/types/src/graph/functions/index.d.ts +4 -0
  79. package/dist/types/src/graph/functions/index.d.ts.map +1 -0
  80. package/dist/types/src/graph/index.d.ts +2 -1
  81. package/dist/types/src/graph/index.d.ts.map +1 -1
  82. package/dist/types/src/graph/testing/index.d.ts +3 -0
  83. package/dist/types/src/graph/testing/index.d.ts.map +1 -0
  84. package/dist/types/src/graph/testing/test-builder.d.ts +15 -0
  85. package/dist/types/src/graph/testing/test-builder.d.ts.map +1 -0
  86. package/dist/types/src/graph/testing/test-plugin.d.ts +36 -0
  87. package/dist/types/src/graph/testing/test-plugin.d.ts.map +1 -0
  88. package/dist/types/src/hooks/useComputeGraph.d.ts.map +1 -1
  89. package/dist/types/src/hooks/useSheetModel.d.ts +2 -2
  90. package/dist/types/src/hooks/useSheetModel.d.ts.map +1 -1
  91. package/dist/types/src/model/sheet-model.d.ts +3 -3
  92. package/dist/types/src/model/sheet-model.d.ts.map +1 -1
  93. package/dist/types/src/model/sheet-model.test.d.ts +2 -0
  94. package/dist/types/src/model/sheet-model.test.d.ts.map +1 -0
  95. package/dist/types/src/testing/testing.d.ts +4 -5
  96. package/dist/types/src/testing/testing.d.ts.map +1 -1
  97. package/dist/types/src/types.d.ts +4 -3
  98. package/dist/types/src/types.d.ts.map +1 -1
  99. package/package.json +40 -39
  100. package/src/SheetPlugin.tsx +19 -15
  101. package/src/components/CellEditor/CellEditor.stories.tsx +2 -3
  102. package/src/components/CellEditor/extension.test.ts +0 -1
  103. package/src/components/CellEditor/extension.ts +4 -3
  104. package/src/components/GridSheet/GridSheet.stories.tsx +3 -3
  105. package/src/components/GridSheet/GridSheet.tsx +26 -8
  106. package/src/components/GridSheet/util.ts +61 -21
  107. package/src/components/Sheet/Sheet.stories.tsx +21 -20
  108. package/src/components/Sheet/Sheet.tsx +30 -14
  109. package/src/components/Sheet/sheet-context.tsx +4 -4
  110. package/src/components/SheetContainer.tsx +13 -15
  111. package/src/defs/types.ts +1 -0
  112. package/src/defs/util.ts +19 -3
  113. package/src/extensions/compute.stories.tsx +20 -20
  114. package/src/extensions/compute.ts +91 -42
  115. package/src/graph/compute-graph-registry.ts +90 -0
  116. package/src/graph/compute-graph.stories.tsx +4 -3
  117. package/src/graph/compute-graph.test.ts +87 -0
  118. package/src/graph/compute-graph.ts +73 -121
  119. package/src/graph/compute-node.ts +17 -5
  120. package/src/graph/{async-function.ts → functions/async-function.ts} +23 -15
  121. package/src/graph/{edge-function.ts → functions/edge-function.ts} +14 -13
  122. package/src/graph/functions/index.ts +7 -0
  123. package/src/graph/hyperformula.test.ts +1 -2
  124. package/src/graph/index.ts +2 -1
  125. package/src/graph/testing/index.ts +6 -0
  126. package/src/graph/testing/test-builder.ts +54 -0
  127. package/src/graph/{custom-function.ts → testing/test-plugin.ts} +43 -9
  128. package/src/hooks/hooks.stories.tsx +3 -3
  129. package/src/hooks/useComputeGraph.ts +9 -1
  130. package/src/hooks/useSheetModel.ts +4 -7
  131. package/src/model/sheet-model.test.ts +59 -0
  132. package/src/model/sheet-model.ts +47 -30
  133. package/src/testing/testing.tsx +17 -15
  134. package/src/types.ts +3 -3
  135. package/dist/lib/browser/SheetContainer-V4GCCZTX.mjs.map +0 -7
  136. package/dist/lib/browser/chunk-6ZMQVB4Z.mjs.map +0 -7
  137. package/dist/lib/browser/chunk-U2JHW3L6.mjs.map +0 -7
  138. package/dist/lib/browser/graph-T27BOBOV.mjs +0 -21
  139. package/dist/lib/node/SheetContainer-3ZY7MPWJ.cjs.map +0 -7
  140. package/dist/lib/node/chunk-DD6FIXWC.cjs.map +0 -7
  141. package/dist/lib/node/chunk-OTTD7FBK.cjs.map +0 -7
  142. package/dist/lib/node/graph-SPKGX7W4.cjs +0 -43
  143. package/dist/lib/node/graph-SPKGX7W4.cjs.map +0 -7
  144. package/dist/lib/node-esm/SheetContainer-PXSJX6XK.mjs.map +0 -7
  145. package/dist/lib/node-esm/chunk-7HVSOTGA.mjs.map +0 -7
  146. package/dist/lib/node-esm/chunk-D6KU5MI7.mjs.map +0 -7
  147. package/dist/lib/node-esm/graph-U67IO4UC.mjs +0 -22
  148. package/dist/types/src/graph/async-function.d.ts.map +0 -1
  149. package/dist/types/src/graph/compute-graph.browser.test.d.ts +0 -2
  150. package/dist/types/src/graph/compute-graph.browser.test.d.ts.map +0 -1
  151. package/dist/types/src/graph/custom-function.d.ts +0 -21
  152. package/dist/types/src/graph/custom-function.d.ts.map +0 -1
  153. package/dist/types/src/graph/edge-function.d.ts +0 -20
  154. package/dist/types/src/graph/edge-function.d.ts.map +0 -1
  155. package/dist/types/src/graph/function-defs.d.ts.map +0 -1
  156. package/src/graph/compute-graph.browser.test.ts +0 -104
  157. /package/dist/lib/browser/{graph-T27BOBOV.mjs.map → graph-M4IQ76QX.mjs.map} +0 -0
  158. /package/dist/lib/node-esm/{graph-U67IO4UC.mjs.map → graph-SMPUMOV2.mjs.map} +0 -0
  159. /package/dist/types/src/graph/{function-defs.d.ts → functions/function-defs.d.ts} +0 -0
  160. /package/src/graph/{function-defs.ts → functions/function-defs.ts} +0 -0
@@ -0,0 +1,54 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import { Client, type ClientOptions } from '@dxos/client';
6
+ import { type Context, Resource } from '@dxos/context';
7
+ import { invariant } from '@dxos/invariant';
8
+
9
+ import { type ComputeGraphOptions, ComputeGraphRegistry } from '../compute-graph-registry';
10
+
11
+ export type TestBuilderOptions = ClientOptions & ComputeGraphOptions;
12
+
13
+ // TODO(burdon): Reconcile with @dxos/client/testing.
14
+ export class TestBuilder extends Resource {
15
+ private _client?: Client;
16
+ private _registry?: ComputeGraphRegistry;
17
+
18
+ constructor(private readonly _options: TestBuilderOptions = {}) {
19
+ super();
20
+ }
21
+
22
+ get ctx(): Context {
23
+ return this._ctx;
24
+ }
25
+
26
+ get client(): Client {
27
+ invariant(this._client);
28
+ return this._client;
29
+ }
30
+
31
+ get registry(): ComputeGraphRegistry {
32
+ invariant(this._registry);
33
+ return this._registry;
34
+ }
35
+
36
+ override async _open() {
37
+ const client = new Client(this._options);
38
+ await client.initialize();
39
+ await client.halo.createIdentity();
40
+ this._client = client;
41
+ this._ctx.onDispose(async () => {
42
+ await client.destroy();
43
+ this._client = undefined;
44
+ });
45
+
46
+ const registry = new ComputeGraphRegistry(this._options);
47
+ await registry.open();
48
+ this._registry = registry;
49
+ this._ctx.onDispose(async () => {
50
+ await registry.close();
51
+ this._registry = undefined;
52
+ });
53
+ }
54
+ }
@@ -8,14 +8,30 @@ import { type ProcedureAst } from 'hyperformula/typings/parser';
8
8
  import { getDeep } from '@dxos/util';
9
9
 
10
10
  import { FunctionArgumentType } from '#hyperformula';
11
- import { type AsyncFunction, FunctionPluginAsync } from './async-function';
12
- import { parseNumberString } from './util';
11
+ import { type ComputeGraphPlugin } from '../compute-graph-registry';
12
+ import { type AsyncFunction, AsyncFunctionPlugin } from '../functions';
13
+ import { parseNumberString } from '../util';
13
14
 
14
15
  /**
16
+ * Testing functions run locally (not run via EDGE).
15
17
  * https://hyperformula.handsontable.com/guide/custom-functions.html#add-a-simple-custom-function
16
18
  */
17
- export class CustomPlugin extends FunctionPluginAsync {
19
+ export class TestPlugin extends AsyncFunctionPlugin {
20
+ /**
21
+ * Simple local function returns input value.
22
+ */
18
23
  test(ast: ProcedureAst, state: InterpreterState) {
24
+ const handler: AsyncFunction = async (_value) => {
25
+ return _value;
26
+ };
27
+
28
+ return this.runAsyncFunction(ast, state, handler);
29
+ }
30
+
31
+ /**
32
+ * Simple local function returns random number.
33
+ */
34
+ random(ast: ProcedureAst, state: InterpreterState) {
19
35
  const handler: AsyncFunction = async () => {
20
36
  return Math.random();
21
37
  };
@@ -23,6 +39,9 @@ export class CustomPlugin extends FunctionPluginAsync {
23
39
  return this.runAsyncFunction(ast, state, handler);
24
40
  }
25
41
 
42
+ /**
43
+ * Async HTTP function.
44
+ */
26
45
  crypto(ast: ProcedureAst, state: InterpreterState) {
27
46
  const handler: AsyncFunction = async (_currency) => {
28
47
  const currency = (_currency || 'USD').toUpperCase();
@@ -40,9 +59,15 @@ export class CustomPlugin extends FunctionPluginAsync {
40
59
  }
41
60
  }
42
61
 
43
- CustomPlugin.implementedFunctions = {
62
+ TestPlugin.implementedFunctions = {
44
63
  TEST: {
45
64
  method: 'test',
65
+ parameters: [{ argumentType: FunctionArgumentType.NUMBER, optionalArg: false }],
66
+ isVolatile: true,
67
+ },
68
+
69
+ RANDOM: {
70
+ method: 'random',
46
71
  parameters: [],
47
72
  isVolatile: true,
48
73
  },
@@ -54,13 +79,22 @@ CustomPlugin.implementedFunctions = {
54
79
  },
55
80
  };
56
81
 
57
- export const CustomPluginTranslations = {
82
+ export const TestPluginTranslations = {
58
83
  enGB: {
59
- TEST: 'TEST',
60
- CRYPTO: 'CRYPTO',
84
+ TEST: 'Returns input value',
85
+ RANDOM: 'Random number',
86
+ CRYPTO: 'Crypto token value',
61
87
  },
62
88
  enUS: {
63
- TEST: 'TEST',
64
- CRYPTO: 'CRYPTO',
89
+ TEST: 'Returns input value',
90
+ RANDOM: 'Random number',
91
+ CRYPTO: 'Crypto token value',
65
92
  },
66
93
  };
94
+
95
+ export const testFunctionPlugins: ComputeGraphPlugin[] = [
96
+ {
97
+ plugin: TestPlugin,
98
+ translations: TestPluginTranslations,
99
+ },
100
+ ];
@@ -14,14 +14,14 @@ import { withTheme } from '@dxos/storybook-utils';
14
14
  import { ComputeGraphContextProvider } from '../components';
15
15
  import { createSheet } from '../defs';
16
16
  import { useComputeGraph, useSheetModel } from '../hooks';
17
- import { withGraphDecorator } from '../testing';
17
+ import { withComputeGraphDecorator } from '../testing';
18
18
  import { SheetType } from '../types';
19
19
 
20
20
  const Story = () => {
21
21
  const space = useSpace();
22
22
  const graph = useComputeGraph(space);
23
23
  const [sheet, setSheet] = useState<SheetType>();
24
- const model = useSheetModel(space, sheet);
24
+ const model = useSheetModel(graph, sheet);
25
25
  useEffect(() => {
26
26
  if (space) {
27
27
  const sheet = space.db.add(createSheet());
@@ -41,7 +41,7 @@ export default {
41
41
  component: ComputeGraphContextProvider,
42
42
  decorators: [
43
43
  withClientProvider({ types: [SheetType], createIdentity: true, createSpace: true }),
44
- withGraphDecorator,
44
+ withComputeGraphDecorator(),
45
45
  withTheme,
46
46
  ],
47
47
  render: (args: any) => <Story {...args} />,
@@ -16,5 +16,13 @@ import { type ComputeGraph } from '../graph';
16
16
  */
17
17
  export const useComputeGraph = (space?: Space): ComputeGraph | undefined => {
18
18
  const { registry } = useContext(ComputeGraphContext) ?? raise(new Error('Missing ComputeGraphContext'));
19
- return useAsyncState(async () => space && registry.getOrCreateGraph(space), [space, registry]);
19
+ const [graph] = useAsyncState(async () => {
20
+ if (space) {
21
+ const graph = registry.getOrCreateGraph(space);
22
+ await graph.open();
23
+ return graph;
24
+ }
25
+ }, [space, registry]);
26
+
27
+ return graph;
20
28
  };
@@ -4,9 +4,7 @@
4
4
 
5
5
  import { useEffect, useState } from 'react';
6
6
 
7
- import { type Space } from '@dxos/react-client/echo';
8
-
9
- import { useComputeGraph } from './useComputeGraph';
7
+ import { type ComputeGraph } from '../graph';
10
8
  import { SheetModel } from '../model';
11
9
  import { type SheetType } from '../types';
12
10
 
@@ -15,14 +13,13 @@ export type UseSheetModelOptions = {
15
13
  };
16
14
 
17
15
  export const useSheetModel = (
18
- space?: Space,
16
+ graph?: ComputeGraph,
19
17
  sheet?: SheetType,
20
18
  { readonly }: UseSheetModelOptions = {},
21
19
  ): SheetModel | undefined => {
22
- const graph = useComputeGraph(space);
23
20
  const [model, setModel] = useState<SheetModel>();
24
21
  useEffect(() => {
25
- if (!space || !graph || !sheet) {
22
+ if (!graph || !sheet) {
26
23
  return;
27
24
  }
28
25
 
@@ -37,7 +34,7 @@ export const useSheetModel = (
37
34
  clearTimeout(t);
38
35
  void model?.close();
39
36
  };
40
- }, [space, sheet, graph, readonly]);
37
+ }, [graph, sheet, readonly]);
41
38
 
42
39
  return model;
43
40
  };
@@ -0,0 +1,59 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import { afterEach, beforeEach, describe, expect, test } from 'vitest';
6
+
7
+ import { Trigger } from '@dxos/async';
8
+ import { FunctionType } from '@dxos/plugin-script/types';
9
+
10
+ import { SheetModel } from './sheet-model';
11
+ import { createSheet, addressFromA1Notation } from '../defs';
12
+ import { TestBuilder, testFunctionPlugins } from '../graph/testing';
13
+ import { type CellScalarValue } from '../types';
14
+
15
+ // TODO(burdon): GPT("prompt", inputs); e.g., with large text cells.
16
+
17
+ describe('SheetModel', () => {
18
+ let testBuilder: TestBuilder;
19
+ beforeEach(async () => {
20
+ testBuilder = new TestBuilder({ types: [FunctionType], plugins: testFunctionPlugins });
21
+ await testBuilder.open();
22
+ });
23
+ afterEach(async () => {
24
+ await testBuilder.close();
25
+ });
26
+
27
+ test('async function', async () => {
28
+ const space = await testBuilder.client.spaces.create();
29
+ const graph = testBuilder.registry.createGraph(space);
30
+ await graph.open();
31
+
32
+ // TODO(burdon): Create via factory.
33
+ const sheet = createSheet({ rows: 5, columns: 5 });
34
+ const model = new SheetModel(graph, sheet);
35
+ await model.open();
36
+ testBuilder.ctx.onDispose(() => model.close());
37
+
38
+ // Trigger waits for function invocation.
39
+ const trigger = new Trigger<CellScalarValue>();
40
+ model.setValue(addressFromA1Notation('A1'), '=TEST(100)');
41
+ model.update.once((update) => {
42
+ const { type } = update;
43
+ if (type === 'valuesUpdated') {
44
+ const value = model.getValue(addressFromA1Notation('A1'));
45
+ trigger.wake(value);
46
+ }
47
+ });
48
+
49
+ // Initial value will be null.
50
+ const v1 = model.getValue(addressFromA1Notation('A1'));
51
+ expect(v1).to.be.null;
52
+ expect(graph.context.info.invocations.TEST).not.to.exist;
53
+
54
+ // Wait until async update triggered.
55
+ const v2 = await trigger.wait();
56
+ expect(v2).to.eq(100);
57
+ expect(graph.context.info.invocations.TEST).to.eq(1);
58
+ });
59
+ });
@@ -8,6 +8,7 @@ import { type SimpleDate, type SimpleDateTime } from 'hyperformula/typings/DateT
8
8
 
9
9
  import { Event } from '@dxos/async';
10
10
  import { Resource } from '@dxos/context';
11
+ import { getTypename } from '@dxos/echo-schema';
11
12
  import { invariant } from '@dxos/invariant';
12
13
  import { PublicKey } from '@dxos/keys';
13
14
  import { log } from '@dxos/log';
@@ -22,7 +23,7 @@ import {
22
23
  MAX_ROWS,
23
24
  } from '../defs';
24
25
  import { addressFromIndex, addressToIndex, initialize, insertIndices, ReadonlyException } from '../defs';
25
- import { type ComputeNode, type ComputeGraph, createSheetName } from '../graph';
26
+ import { type ComputeNode, type ComputeGraph, createSheetName, type ComputeNodeEvent } from '../graph';
26
27
  import { type CellScalarValue, type CellValue, type SheetType, ValueTypeEnum } from '../types';
27
28
 
28
29
  const typeMap: Record<string, ValueTypeEnum> = {
@@ -60,13 +61,14 @@ export type SheetModelOptions = {
60
61
  *
61
62
  * [ComputeGraphContext] > [SheetContext]:[SheetModel] > [Sheet.Root]
62
63
  */
63
- // TODO(burdon): Factor out commonality with ComputeNode.
64
+ // TODO(burdon): Factor out commonality with ComputeNode. Factor out HF.
64
65
  export class SheetModel extends Resource {
65
66
  public readonly id = `model-${PublicKey.random().truncate()}`;
66
67
 
67
- public readonly update = new Event();
68
+ // Wraps compute node.
69
+ public readonly update = new Event<ComputeNodeEvent>();
68
70
 
69
- private readonly _node: ComputeNode;
71
+ private _node?: ComputeNode;
70
72
 
71
73
  constructor(
72
74
  private readonly _graph: ComputeGraph,
@@ -74,9 +76,6 @@ export class SheetModel extends Resource {
74
76
  private readonly _options: SheetModelOptions = {},
75
77
  ) {
76
78
  super();
77
- // TODO(burdon): SheetModel should extend ComputeNode and be constructed via the graph.
78
- this._node = this._graph.getOrCreateNode(createSheetName(this._sheet.id));
79
- this.reset();
80
79
  }
81
80
 
82
81
  get graph() {
@@ -104,12 +103,16 @@ export class SheetModel extends Resource {
104
103
  protected override async _open() {
105
104
  log('initialize', { id: this.id });
106
105
  initialize(this._sheet);
107
- this.reset();
108
106
 
109
- // TODO(burdon): Event hierarchy?
107
+ // TODO(burdon): SheetModel should extend ComputeNode and be constructed via the graph.
108
+ this._node = this._graph.getOrCreateNode(createSheetName({ type: getTypename(this._sheet)!, id: this._sheet.id }));
109
+ await this._node.open();
110
+
110
111
  // Listen for model updates (e.g., async calculations).
111
- const unsubscribe = this._graph.update.on(() => this.update.emit());
112
+ const unsubscribe = this._node.update.on((event) => this.update.emit(event));
112
113
  this._ctx.onDispose(unsubscribe);
114
+
115
+ this.reset();
113
116
  }
114
117
 
115
118
  /**
@@ -118,8 +121,10 @@ export class SheetModel extends Resource {
118
121
  * @deprecated
119
122
  */
120
123
  reset() {
121
- this._node.hf.clearSheet(this._node.sheetId);
124
+ invariant(this._node);
125
+ this._node.graph.hf.clearSheet(this._node.sheetId);
122
126
  Object.entries(this._sheet.cells).forEach(([key, { value }]) => {
127
+ invariant(this._node);
123
128
  const { col, row } = addressFromIndex(this._sheet, key);
124
129
  if (typeof value === 'string' && value.charAt(0) === '=') {
125
130
  value = this._graph.mapFormulaToNative(
@@ -127,7 +132,7 @@ export class SheetModel extends Resource {
127
132
  );
128
133
  }
129
134
 
130
- this._node.hf.setCellContents({ sheet: this._node.sheetId, row, col }, value);
135
+ this._node.graph.hf.setCellContents({ sheet: this._node.sheetId, row, col }, value);
131
136
  });
132
137
  }
133
138
 
@@ -139,7 +144,7 @@ export class SheetModel extends Resource {
139
144
  */
140
145
  // TODO(burdon): Remove.
141
146
  recalculate() {
142
- this._node.hf.rebuildAndRecalculate();
147
+ this._node?.graph.hf.rebuildAndRecalculate();
143
148
  }
144
149
 
145
150
  insertRows(i: number, n = 1) {
@@ -161,9 +166,10 @@ export class SheetModel extends Resource {
161
166
  * Clear range of values.
162
167
  */
163
168
  clear(range: CellRange) {
169
+ invariant(this._node);
164
170
  const topLeft = getTopLeft(range);
165
171
  const values = this._iterRange(range, () => null);
166
- this._node.hf.setCellContents(toSimpleCellAddress(this._node.sheetId, topLeft), values);
172
+ this._node.graph.hf.setCellContents(toSimpleCellAddress(this._node.sheetId, topLeft), values);
167
173
  this._iterRange(range, (cell) => {
168
174
  const idx = addressToIndex(this._sheet, cell);
169
175
  delete this._sheet.cells[idx];
@@ -171,7 +177,8 @@ export class SheetModel extends Resource {
171
177
  }
172
178
 
173
179
  cut(range: CellRange) {
174
- this._node.hf.cut(toModelRange(this._node.sheetId, range));
180
+ invariant(this._node);
181
+ this._node.graph.hf.cut(toModelRange(this._node.sheetId, range));
175
182
  this._iterRange(range, (cell) => {
176
183
  const idx = addressToIndex(this._sheet, cell);
177
184
  delete this._sheet.cells[idx];
@@ -179,12 +186,14 @@ export class SheetModel extends Resource {
179
186
  }
180
187
 
181
188
  copy(range: CellRange) {
182
- this._node.hf.copy(toModelRange(this._node.sheetId, range));
189
+ invariant(this._node);
190
+ this._node.graph.hf.copy(toModelRange(this._node.sheetId, range));
183
191
  }
184
192
 
185
193
  paste(cell: CellAddress) {
186
- if (!this._node.hf.isClipboardEmpty()) {
187
- const changes = this._node.hf.paste(toSimpleCellAddress(this._node.sheetId, cell));
194
+ invariant(this._node);
195
+ if (!this._node.graph.hf.isClipboardEmpty()) {
196
+ const changes = this._node.graph.hf.paste(toSimpleCellAddress(this._node.sheetId, cell));
188
197
  for (const change of changes) {
189
198
  if (change instanceof ExportedCellChange) {
190
199
  const { address, newValue } = change;
@@ -197,16 +206,18 @@ export class SheetModel extends Resource {
197
206
 
198
207
  // TODO(burdon): Display undo/redo state.
199
208
  undo() {
200
- if (this._node.hf.isThereSomethingToUndo()) {
201
- this._node.hf.undo();
202
- this.update.emit();
209
+ invariant(this._node);
210
+ if (this._node.graph.hf.isThereSomethingToUndo()) {
211
+ this._node.graph.hf.undo();
212
+ // this.update.emit();
203
213
  }
204
214
  }
205
215
 
206
216
  redo() {
207
- if (this._node.hf.isThereSomethingToRedo()) {
208
- this._node.hf.redo();
209
- this.update.emit();
217
+ invariant(this._node);
218
+ if (this._node.graph.hf.isThereSomethingToRedo()) {
219
+ this._node.graph.hf.redo();
220
+ // this.update.emit();
210
221
  }
211
222
  }
212
223
 
@@ -246,7 +257,8 @@ export class SheetModel extends Resource {
246
257
  */
247
258
  getValue(cell: CellAddress): CellScalarValue {
248
259
  // Applies rounding and post-processing.
249
- const value = this._node.hf.getCellValue(toSimpleCellAddress(this._node.sheetId, cell));
260
+ invariant(this._node);
261
+ const value = this._node.graph.hf.getCellValue(toSimpleCellAddress(this._node.sheetId, cell));
250
262
  if (value instanceof DetailedCellError) {
251
263
  return value.toString();
252
264
  }
@@ -258,8 +270,9 @@ export class SheetModel extends Resource {
258
270
  * Get value type.
259
271
  */
260
272
  getValueType(cell: CellAddress): ValueTypeEnum {
273
+ invariant(this._node);
261
274
  const addr = toSimpleCellAddress(this._node.sheetId, cell);
262
- const type = this._node.hf.getCellValueDetailedType(addr);
275
+ const type = this._node.graph.hf.getCellValueDetailedType(addr);
263
276
  return typeMap[type];
264
277
  }
265
278
 
@@ -267,6 +280,7 @@ export class SheetModel extends Resource {
267
280
  * Sets the value, updating the sheet and engine.
268
281
  */
269
282
  setValue(cell: CellAddress, value: CellScalarValue) {
283
+ invariant(this._node);
270
284
  if (this._options.readonly) {
271
285
  throw new ReadonlyException();
272
286
  }
@@ -288,7 +302,7 @@ export class SheetModel extends Resource {
288
302
  }
289
303
 
290
304
  // Insert into engine.
291
- this._node.hf.setCellContents({ sheet: this._node.sheetId, row: cell.row, col: cell.col }, [
305
+ this._node.graph.hf.setCellContents({ sheet: this._node.sheetId, row: cell.row, col: cell.col }, [
292
306
  [typeof value === 'string' && value.charAt(0) === '=' ? this._graph.mapFormulaToNative(value) : value],
293
307
  ]);
294
308
 
@@ -386,14 +400,17 @@ export class SheetModel extends Resource {
386
400
  }
387
401
 
388
402
  toDateTime(num: number): SimpleDateTime {
389
- return this._node.hf.numberToDateTime(num) as SimpleDateTime;
403
+ invariant(this._node);
404
+ return this._node.graph.hf.numberToDateTime(num) as SimpleDateTime;
390
405
  }
391
406
 
392
407
  toDate(num: number): SimpleDate {
393
- return this._node.hf.numberToDate(num) as SimpleDate;
408
+ invariant(this._node);
409
+ return this._node.graph.hf.numberToDate(num) as SimpleDate;
394
410
  }
395
411
 
396
412
  toTime(num: number): SimpleDate {
397
- return this._node.hf.numberToTime(num) as SimpleDate;
413
+ invariant(this._node);
414
+ return this._node.graph.hf.numberToTime(num) as SimpleDate;
398
415
  }
399
416
  }
@@ -2,7 +2,7 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import type { Decorator } from '@storybook/react';
5
+ import { type Decorator } from '@storybook/react';
6
6
  import React, { useState } from 'react';
7
7
 
8
8
  import { type Space } from '@dxos/react-client/echo';
@@ -10,14 +10,13 @@ import { useAsyncState } from '@dxos/react-hooks';
10
10
 
11
11
  import { ComputeGraphContextProvider } from '../components';
12
12
  import { createSheet } from '../defs';
13
- import { type ComputeGraph, ComputeGraphRegistry } from '../graph';
13
+ import { type ComputeGraph, type ComputeGraphOptions, ComputeGraphRegistry } from '../graph';
14
14
  import { type CellValue, type CreateSheetOptions } from '../types';
15
15
 
16
- export const testSheetName = 'test';
16
+ const testSheetName = 'test';
17
17
 
18
- // TODO(thure): Remove this from the `/testing` entrypoint.
19
- export const createCells = (): Record<string, CellValue> => ({
20
- B1: { value: 'Qty' },
18
+ export const createTestCells = (): Record<string, CellValue> => ({
19
+ B1: { value: 'Qty2' },
21
20
  B3: { value: 1 },
22
21
  B4: { value: 2 },
23
22
  B5: { value: 3 },
@@ -45,7 +44,7 @@ export const createCells = (): Record<string, CellValue> => ({
45
44
  });
46
45
 
47
46
  export const useTestSheet = (space?: Space, graph?: ComputeGraph, options?: CreateSheetOptions) => {
48
- return useAsyncState(async () => {
47
+ const [sheet] = useAsyncState(async () => {
49
48
  if (!space || !graph) {
50
49
  return;
51
50
  }
@@ -54,13 +53,16 @@ export const useTestSheet = (space?: Space, graph?: ComputeGraph, options?: Crea
54
53
  space.db.add(sheet);
55
54
  return sheet;
56
55
  }, [space, graph]);
56
+ return sheet;
57
57
  };
58
58
 
59
- export const withGraphDecorator: Decorator = (Story) => {
60
- const [registry] = useState(new ComputeGraphRegistry());
61
- return (
62
- <ComputeGraphContextProvider registry={registry}>
63
- <Story />
64
- </ComputeGraphContextProvider>
65
- );
66
- };
59
+ export const withComputeGraphDecorator =
60
+ (options?: ComputeGraphOptions): Decorator =>
61
+ (Story) => {
62
+ const [registry] = useState(new ComputeGraphRegistry(options));
63
+ return (
64
+ <ComputeGraphContextProvider registry={registry}>
65
+ <Story />
66
+ </ComputeGraphContextProvider>
67
+ );
68
+ };
package/src/types.ts CHANGED
@@ -102,7 +102,7 @@ export const RowColumnMeta = S.Struct({
102
102
  // TODO(wittjosiah): Migrate typename to remove `Type` suffix.
103
103
  // TODO(wittjosiah): Rename title to name to align with other schemas.
104
104
  export class SheetType extends TypedObject({ typename: 'dxos.org/type/SheetType', version: '0.1.0' })({
105
- title: S.optional(S.String),
105
+ name: S.optional(S.String),
106
106
 
107
107
  // Sparse map of cells referenced by index.
108
108
  cells: S.mutable(S.Record(S.String, S.mutable(CellValue))),
@@ -132,6 +132,6 @@ export type SheetSize = {
132
132
  };
133
133
 
134
134
  export type CreateSheetOptions = {
135
- // TODO(burdon): Standardize as name.
136
- title?: string;
135
+ name?: string;
136
+ cells?: Record<string, CellValue>;
137
137
  } & Partial<SheetSize>;
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/components/SheetContainer.tsx", "../../../src/components/Toolbar/Toolbar.tsx", "../../../src/components/Toolbar/common.tsx"],
4
- "sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport React, { useCallback } from 'react';\n\nimport { useIntentDispatcher } from '@dxos/app-framework';\nimport { fullyQualifiedId } from '@dxos/react-client/echo';\nimport { useIsDirectlyAttended } from '@dxos/react-ui-attention';\nimport { focusRing, mx } from '@dxos/react-ui-theme';\n\nimport { Sheet, type SheetRootProps } from './Sheet';\nimport { Toolbar, type ToolbarAction } from './Toolbar';\n\n// TODO(Zan): Factor out, copied this from MarkdownPlugin.\nconst attentionFragment = mx(\n 'group-focus-within/editor:attention-surface group-[[aria-current]]/editor:attention-surface',\n 'group-focus-within/editor:border-separator',\n);\n\n// TODO(Zan): Factor out, copied this from MarkdownPlugin.\nexport const sectionToolbarLayout =\n 'bs-[--rail-action] bg-[--sticky-bg] sticky block-start-0 __-block-start-px transition-opacity';\n\nconst SheetContainer = ({ sheet, space, role }: SheetRootProps & { role?: string }) => {\n const dispatch = useIntentDispatcher();\n\n const id = fullyQualifiedId(sheet);\n const isDirectlyAttended = useIsDirectlyAttended(id);\n\n // TODO(Zan): Centralise the toolbar action handler. Current implementation in stories.\n const handleAction = useCallback(\n (action: ToolbarAction) => {\n switch (action.type) {\n case 'comment': {\n // TODO(Zan): We shouldn't hardcode the action ID.\n void dispatch({\n action: 'dxos.org/plugin/thread/action/create',\n data: {\n cursor: action.anchor,\n name: action.cellContent,\n subject: sheet,\n },\n });\n }\n }\n },\n [sheet, dispatch],\n );\n\n return (\n <div role='none' className={role === 'article' ? 'row-span-2 grid grid-rows-subgrid' : undefined}>\n <Sheet.Root space={space} sheet={sheet}>\n <div role='none' className={mx('flex flex-0 justify-center overflow-x-auto')}>\n <Toolbar.Root\n onAction={handleAction}\n classNames={mx(\n role === 'section'\n ? ['z-[2] group-focus-within/section:visible', !isDirectlyAttended && 'invisible', sectionToolbarLayout]\n : 'group-focus-within/editor:border-separator group-[[aria-current]]/editor:border-separator',\n )}\n >\n {/* TODO(Zan): Restore some of this functionality */}\n {/* <Toolbar.Styles /> */}\n {/* <Toolbar.Format /> */}\n {/* <Toolbar.Alignment /> */}\n <Toolbar.Separator />\n <Toolbar.Actions />\n </Toolbar.Root>\n </div>\n <div\n role='none'\n className={mx(\n role === 'section' && 'aspect-square border-is border-bs border-be border-separator',\n role === 'article' &&\n 'flex is-full overflow-hidden focus-visible:ring-inset row-span-1 data-[toolbar=disabled]:pbs-2 data-[toolbar=disabled]:row-span-2 border-bs border-separator',\n focusRing,\n attentionFragment,\n )}\n >\n <Sheet.Main />\n </div>\n </Sheet.Root>\n </div>\n );\n};\n\nexport default SheetContainer;\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport {\n type Icon,\n Calendar,\n ChatText,\n CurrencyDollar,\n Eraser,\n HighlighterCircle,\n TextAlignCenter,\n TextAlignLeft,\n TextAlignRight,\n} from '@phosphor-icons/react';\nimport { createContext } from '@radix-ui/react-context';\nimport React, { type PropsWithChildren } from 'react';\n\nimport {\n DensityProvider,\n ElevationProvider,\n Toolbar as NaturalToolbar,\n type ThemedClassName,\n useTranslation,\n} from '@dxos/react-ui';\nimport { nonNullable } from '@dxos/util';\n\nimport { ToolbarButton, ToolbarSeparator, ToolbarToggleButton } from './common';\nimport { addressToIndex } from '../../defs';\nimport { SHEET_PLUGIN } from '../../meta';\nimport { type Formatting } from '../../types';\nimport { useSheetContext } from '../Sheet/sheet-context';\n\n//\n// Root\n//\n\nexport type ToolbarAction =\n | { type: 'clear' }\n | { type: 'highlight' }\n | { type: 'left' }\n | { type: 'center' }\n | { type: 'right' }\n | { type: 'date' }\n | { type: 'currency' }\n | { type: 'comment'; anchor: string; cellContent?: string };\n\nexport type ToolbarActionType = ToolbarAction['type'];\n\nexport type ToolbarActionHandler = (action: ToolbarAction) => void;\n\nexport type ToolbarProps = ThemedClassName<\n PropsWithChildren<{\n onAction?: ToolbarActionHandler;\n }>\n>;\n\nconst [ToolbarContextProvider, useToolbarContext] = createContext<ToolbarProps>('Toolbar');\n\nconst ToolbarRoot = ({ children, onAction, classNames }: ToolbarProps) => {\n return (\n <ToolbarContextProvider onAction={onAction}>\n <DensityProvider density='fine'>\n <ElevationProvider elevation='chrome'>\n <NaturalToolbar.Root classNames={['is-full shrink-0 overflow-x-auto overflow-y-hidden p-1', classNames]}>\n {children}\n </NaturalToolbar.Root>\n </ElevationProvider>\n </DensityProvider>\n </ToolbarContextProvider>\n );\n};\n\n// TODO(burdon): Generalize.\n// TODO(burdon): Detect and display current state.\ntype ButtonProps = {\n type: ToolbarActionType;\n Icon: Icon;\n getState: (state: Formatting) => boolean;\n disabled?: (state: Formatting) => boolean;\n};\n\n//\n// Alignment\n//\n\nconst formatOptions: ButtonProps[] = [\n { type: 'date', Icon: Calendar, getState: (state) => false },\n { type: 'currency', Icon: CurrencyDollar, getState: (state) => false },\n];\n\nconst Format = () => {\n const { onAction } = useToolbarContext('Format');\n const { t } = useTranslation(SHEET_PLUGIN);\n\n return (\n <NaturalToolbar.ToggleGroup\n type='single'\n // value={cellStyles.filter(({ getState }) => state && getState(state)).map(({ type }) => type)}\n >\n {formatOptions.map(({ type, getState, Icon }) => (\n <ToolbarToggleButton\n key={type}\n value={type}\n Icon={Icon}\n // disabled={state?.blockType === 'codeblock'}\n // onClick={state ? () => onAction?.({ type, data: !getState(state) }) : undefined}\n onClick={() => onAction?.({ type: type as Exclude<typeof type, 'comment'> })}\n >\n {t(`toolbar ${type} label`)}\n </ToolbarToggleButton>\n ))}\n </NaturalToolbar.ToggleGroup>\n );\n};\n\nconst alignmentOptions: ButtonProps[] = [\n { type: 'left', Icon: TextAlignLeft, getState: (state) => false },\n { type: 'center', Icon: TextAlignCenter, getState: (state) => false },\n { type: 'right', Icon: TextAlignRight, getState: (state) => false },\n];\n\nconst Alignment = () => {\n const { onAction } = useToolbarContext('Alignment');\n const { t } = useTranslation(SHEET_PLUGIN);\n\n return (\n <NaturalToolbar.ToggleGroup\n type='single'\n // value={cellStyles.filter(({ getState }) => state && getState(state)).map(({ type }) => type)}\n >\n {alignmentOptions.map(({ type, getState, Icon }) => (\n <ToolbarToggleButton\n key={type}\n value={type}\n Icon={Icon}\n // disabled={state?.blockType === 'codeblock'}\n // onClick={state ? () => onAction?.({ type, data: !getState(state) }) : undefined}\n onClick={() => onAction?.({ type: type as Exclude<typeof type, 'comment'> })}\n >\n {t(`toolbar ${type} label`)}\n </ToolbarToggleButton>\n ))}\n </NaturalToolbar.ToggleGroup>\n );\n};\n\nconst styleOptions: ButtonProps[] = [\n { type: 'clear', Icon: Eraser, getState: (state) => false },\n { type: 'highlight', Icon: HighlighterCircle, getState: (state) => false },\n];\n\nconst Styles = () => {\n const { onAction } = useToolbarContext('Alignment');\n const { t } = useTranslation(SHEET_PLUGIN);\n\n return (\n <NaturalToolbar.ToggleGroup\n type='single'\n // value={cellStyles.filter(({ getState }) => state && getState(state)).map(({ type }) => type)}\n >\n {styleOptions.map(({ type, getState, Icon }) => (\n <ToolbarToggleButton\n key={type}\n value={type}\n Icon={Icon}\n // disabled={state?.blockType === 'codeblock'}\n // onClick={state ? () => onAction?.({ type, data: !getState(state) }) : undefined}\n onClick={() => onAction?.({ type: type as Exclude<typeof type, 'comment'> })}\n >\n {t(`toolbar ${type} label`)}\n </ToolbarToggleButton>\n ))}\n </NaturalToolbar.ToggleGroup>\n );\n};\n\n//\n// Actions\n//\n\nconst Actions = () => {\n const { onAction } = useToolbarContext('Actions');\n const { cursor, range, model } = useSheetContext();\n const { t } = useTranslation(SHEET_PLUGIN);\n\n const overlapsCommentAnchor = (model.sheet.threads ?? [])\n .filter(nonNullable)\n .filter((thread) => thread.status !== 'resolved')\n .some((thread) => {\n if (!cursor) {\n return false;\n }\n return addressToIndex(model.sheet, cursor) === thread.anchor;\n });\n\n const hasCursor = !!cursor;\n const cursorOnly = hasCursor && !range && !overlapsCommentAnchor;\n\n const tooltipLabelKey = !hasCursor\n ? 'no cursor label'\n : overlapsCommentAnchor\n ? 'selection overlaps existing comment label'\n : range\n ? 'comment ranges not supported label'\n : 'comment label';\n\n return (\n <ToolbarButton\n value='comment'\n Icon={ChatText}\n data-testid='editor.toolbar.comment'\n onClick={() => {\n if (!cursor) {\n return;\n }\n return onAction?.({\n type: 'comment',\n anchor: addressToIndex(model.sheet, cursor),\n cellContent: model.getCellText(cursor),\n });\n }}\n disabled={!cursorOnly || overlapsCommentAnchor}\n >\n {t(tooltipLabelKey)}\n </ToolbarButton>\n );\n};\n\nexport const Toolbar = {\n Root: ToolbarRoot,\n Separator: ToolbarSeparator,\n Alignment,\n Format,\n Styles,\n Actions,\n};\n\nexport { useToolbarContext };\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { type Icon } from '@phosphor-icons/react';\nimport React from 'react';\n\nimport {\n Toolbar as NaturalToolbar,\n Tooltip,\n type ToolbarButtonProps as NaturalToolbarButtonProps,\n type ToolbarToggleGroupItemProps as NaturalToolbarToggleGroupItemProps,\n} from '@dxos/react-ui';\nimport { getSize } from '@dxos/react-ui-theme';\n\n// TODO(burdon): Factor out in common with react-ui-editor.\n\nexport const iconStyles = getSize(5);\nexport const buttonStyles = 'min-bs-0 p-2';\nexport const tooltipProps = { side: 'top' as const, classNames: 'z-10' };\n\nexport const ToolbarSeparator = () => <div role='separator' className='grow' />;\n\n//\n// ToolbarButton\n//\n\ntype ToolbarButtonProps = NaturalToolbarButtonProps & { Icon: Icon };\n\nexport const ToolbarButton = ({ Icon, children, ...props }: ToolbarButtonProps) => {\n return (\n <Tooltip.Root>\n <Tooltip.Trigger asChild>\n <NaturalToolbar.Button variant='ghost' {...props} classNames={buttonStyles}>\n <Icon className={iconStyles} />\n <span className='sr-only'>{children}</span>\n </NaturalToolbar.Button>\n </Tooltip.Trigger>\n <Tooltip.Portal>\n <Tooltip.Content {...tooltipProps}>\n {children}\n <Tooltip.Arrow />\n </Tooltip.Content>\n </Tooltip.Portal>\n </Tooltip.Root>\n );\n};\n\n//\n// ToolbarToggleButton\n//\n\nexport type ToolbarToggleButtonProps = NaturalToolbarToggleGroupItemProps & { Icon: Icon };\n\nexport const ToolbarToggleButton = ({ Icon, children, ...props }: ToolbarToggleButtonProps) => {\n return (\n <Tooltip.Root>\n <Tooltip.Trigger asChild>\n <NaturalToolbar.ToggleGroupItem variant='ghost' {...props} classNames={buttonStyles}>\n <Icon className={iconStyles} />\n <span className='sr-only'>{children}</span>\n </NaturalToolbar.ToggleGroupItem>\n </Tooltip.Trigger>\n <Tooltip.Portal>\n <Tooltip.Content {...tooltipProps}>\n {children}\n <Tooltip.Arrow />\n </Tooltip.Content>\n </Tooltip.Portal>\n </Tooltip.Root>\n );\n};\n"],
5
- "mappings": "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",
6
- "names": ["React", "useCallback", "useIntentDispatcher", "fullyQualifiedId", "useIsDirectlyAttended", "focusRing", "mx", "Calendar", "ChatText", "CurrencyDollar", "Eraser", "HighlighterCircle", "TextAlignCenter", "TextAlignLeft", "TextAlignRight", "createContext", "React", "DensityProvider", "ElevationProvider", "Toolbar", "NaturalToolbar", "useTranslation", "nonNullable", "React", "Toolbar", "NaturalToolbar", "Tooltip", "getSize", "iconStyles", "getSize", "buttonStyles", "tooltipProps", "side", "classNames", "ToolbarSeparator", "div", "role", "className", "ToolbarButton", "Icon", "children", "props", "Tooltip", "Root", "Trigger", "asChild", "NaturalToolbar", "Button", "variant", "span", "Portal", "Content", "Arrow", "ToolbarToggleButton", "ToggleGroupItem", "ToolbarContextProvider", "useToolbarContext", "createContext", "ToolbarRoot", "children", "onAction", "classNames", "React", "DensityProvider", "density", "ElevationProvider", "elevation", "NaturalToolbar", "Root", "formatOptions", "type", "Icon", "Calendar", "getState", "state", "CurrencyDollar", "Format", "t", "useTranslation", "SHEET_PLUGIN", "ToggleGroup", "map", "ToolbarToggleButton", "key", "value", "onClick", "alignmentOptions", "TextAlignLeft", "TextAlignCenter", "TextAlignRight", "Alignment", "styleOptions", "Eraser", "HighlighterCircle", "Styles", "Actions", "cursor", "range", "model", "useSheetContext", "overlapsCommentAnchor", "sheet", "threads", "filter", "nonNullable", "thread", "status", "some", "addressToIndex", "anchor", "hasCursor", "cursorOnly", "tooltipLabelKey", "ToolbarButton", "ChatText", "data-testid", "cellContent", "getCellText", "disabled", "Toolbar", "Separator", "ToolbarSeparator", "attentionFragment", "mx", "sectionToolbarLayout", "SheetContainer", "sheet", "space", "role", "dispatch", "useIntentDispatcher", "id", "fullyQualifiedId", "isDirectlyAttended", "useIsDirectlyAttended", "handleAction", "useCallback", "action", "type", "data", "cursor", "anchor", "name", "cellContent", "subject", "React", "div", "className", "undefined", "Sheet", "Root", "Toolbar", "onAction", "classNames", "Separator", "Actions", "focusRing", "Main"]
7
- }