@dxos/plugin-explorer 0.8.4-main.4a85c3132b → 0.8.4-main.51f1e5ca51

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 (108) hide show
  1. package/dist/lib/browser/index.mjs +11306 -60
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/browser/meta.mjs +20 -3
  5. package/dist/lib/browser/meta.mjs.map +4 -4
  6. package/dist/lib/browser/translations.mjs +33 -0
  7. package/dist/lib/browser/translations.mjs.map +7 -0
  8. package/dist/lib/browser/types/index.mjs +66 -4
  9. package/dist/lib/browser/types/index.mjs.map +4 -4
  10. package/dist/lib/node-esm/index.mjs +11306 -60
  11. package/dist/lib/node-esm/index.mjs.map +4 -4
  12. package/dist/lib/node-esm/meta.json +1 -1
  13. package/dist/lib/node-esm/meta.mjs +20 -3
  14. package/dist/lib/node-esm/meta.mjs.map +4 -4
  15. package/dist/lib/node-esm/translations.mjs +34 -0
  16. package/dist/lib/node-esm/translations.mjs.map +7 -0
  17. package/dist/lib/node-esm/types/index.mjs +66 -4
  18. package/dist/lib/node-esm/types/index.mjs.map +4 -4
  19. package/dist/types/data/cities.d.ts +4 -4
  20. package/dist/types/data/cities.d.ts.map +1 -1
  21. package/dist/types/data/countries-110m.d.ts +19 -22
  22. package/dist/types/data/countries-110m.d.ts.map +1 -1
  23. package/dist/types/src/ExplorerPlugin.d.ts.map +1 -1
  24. package/dist/types/src/capabilities/index.d.ts +2 -1
  25. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  26. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -0
  27. package/dist/types/src/components/Chart/Chart.d.ts.map +1 -1
  28. package/dist/types/src/components/Chart/Chart.stories.d.ts.map +1 -1
  29. package/dist/types/src/components/Globe/Globe.d.ts.map +1 -1
  30. package/dist/types/src/components/Globe/Globe.stories.d.ts.map +1 -1
  31. package/dist/types/src/components/Graph/D3ForceGraph.d.ts +5 -4
  32. package/dist/types/src/components/Graph/D3ForceGraph.d.ts.map +1 -1
  33. package/dist/types/src/components/Graph/D3ForceGraph.stories.d.ts +4 -2
  34. package/dist/types/src/components/Graph/D3ForceGraph.stories.d.ts.map +1 -1
  35. package/dist/types/src/components/Graph/ForceGraph.stories.d.ts +1 -1
  36. package/dist/types/src/components/Graph/ForceGraph.stories.d.ts.map +1 -1
  37. package/dist/types/src/components/Graph/adapter.d.ts.map +1 -1
  38. package/dist/types/src/components/Graph/testing.d.ts.map +1 -1
  39. package/dist/types/src/components/Tree/Tree.d.ts.map +1 -1
  40. package/dist/types/src/components/Tree/Tree.stories.d.ts.map +1 -1
  41. package/dist/types/src/components/Tree/layout/HierarchicalEdgeBundling.d.ts.map +1 -1
  42. package/dist/types/src/components/Tree/layout/RadialTree.d.ts.map +1 -1
  43. package/dist/types/src/components/Tree/layout/TidyTree.d.ts.map +1 -1
  44. package/dist/types/src/components/Tree/testing/generator.d.ts.map +1 -1
  45. package/dist/types/src/components/Tree/types/tree.d.ts +6 -6
  46. package/dist/types/src/components/Tree/types/tree.d.ts.map +1 -1
  47. package/dist/types/src/components/Tree/types/types.d.ts.map +1 -1
  48. package/dist/types/src/components/plot.d.ts.map +1 -1
  49. package/dist/types/src/containers/ExplorerContainer/ExplorerContainer.d.ts +3 -3
  50. package/dist/types/src/containers/ExplorerContainer/ExplorerContainer.d.ts.map +1 -1
  51. package/dist/types/src/containers/ExplorerContainer/index.d.ts +1 -2
  52. package/dist/types/src/containers/ExplorerContainer/index.d.ts.map +1 -1
  53. package/dist/types/src/hooks/useGraphModel.d.ts.map +1 -1
  54. package/dist/types/src/index.d.ts +0 -1
  55. package/dist/types/src/index.d.ts.map +1 -1
  56. package/dist/types/src/translations.d.ts +28 -26
  57. package/dist/types/src/translations.d.ts.map +1 -1
  58. package/dist/types/src/types/ExplorerAction.d.ts.map +1 -1
  59. package/dist/types/src/types/Graph.d.ts +2 -9
  60. package/dist/types/src/types/Graph.d.ts.map +1 -1
  61. package/dist/types/tsconfig.tsbuildinfo +1 -1
  62. package/package.json +49 -44
  63. package/src/ExplorerPlugin.tsx +22 -11
  64. package/src/capabilities/index.ts +3 -1
  65. package/src/capabilities/{react-surface/react-surface.tsx → react-surface.tsx} +10 -9
  66. package/src/components/Chart/Chart.stories.tsx +0 -1
  67. package/src/components/Globe/Globe.stories.tsx +0 -1
  68. package/src/components/Graph/D3ForceGraph.stories.tsx +9 -10
  69. package/src/components/Graph/D3ForceGraph.tsx +81 -75
  70. package/src/components/Graph/ForceGraph.stories.tsx +9 -10
  71. package/src/components/Tree/Tree.stories.tsx +5 -3
  72. package/src/components/Tree/testing/generator.ts +1 -1
  73. package/src/components/Tree/types/tree.test.ts +3 -4
  74. package/src/components/Tree/types/tree.ts +13 -13
  75. package/src/containers/ExplorerContainer/ExplorerContainer.tsx +6 -6
  76. package/src/containers/ExplorerContainer/index.ts +1 -3
  77. package/src/hooks/useGraphModel.ts +14 -10
  78. package/src/index.ts +0 -1
  79. package/src/meta.ts +1 -1
  80. package/src/translations.ts +14 -13
  81. package/src/types/ExplorerAction.ts +0 -1
  82. package/src/types/Graph.ts +8 -22
  83. package/src/typings.d.ts +8 -0
  84. package/dist/lib/browser/ExplorerContainer-4RB2TY3G.mjs +0 -48
  85. package/dist/lib/browser/ExplorerContainer-4RB2TY3G.mjs.map +0 -7
  86. package/dist/lib/browser/chunk-4NFGHCGO.mjs +0 -84
  87. package/dist/lib/browser/chunk-4NFGHCGO.mjs.map +0 -7
  88. package/dist/lib/browser/chunk-6AZY4CDH.mjs +0 -11278
  89. package/dist/lib/browser/chunk-6AZY4CDH.mjs.map +0 -7
  90. package/dist/lib/browser/chunk-YNQF4CPY.mjs +0 -24
  91. package/dist/lib/browser/chunk-YNQF4CPY.mjs.map +0 -7
  92. package/dist/lib/browser/react-surface-KAHVDMFX.mjs +0 -38
  93. package/dist/lib/browser/react-surface-KAHVDMFX.mjs.map +0 -7
  94. package/dist/lib/node-esm/ExplorerContainer-LCG425I7.mjs +0 -49
  95. package/dist/lib/node-esm/ExplorerContainer-LCG425I7.mjs.map +0 -7
  96. package/dist/lib/node-esm/chunk-DK77RB6M.mjs +0 -26
  97. package/dist/lib/node-esm/chunk-DK77RB6M.mjs.map +0 -7
  98. package/dist/lib/node-esm/chunk-DOXAIJEC.mjs +0 -11280
  99. package/dist/lib/node-esm/chunk-DOXAIJEC.mjs.map +0 -7
  100. package/dist/lib/node-esm/chunk-V42OFY7B.mjs +0 -85
  101. package/dist/lib/node-esm/chunk-V42OFY7B.mjs.map +0 -7
  102. package/dist/lib/node-esm/react-surface-7XILIUI4.mjs +0 -39
  103. package/dist/lib/node-esm/react-surface-7XILIUI4.mjs.map +0 -7
  104. package/dist/types/src/capabilities/react-surface/index.d.ts +0 -3
  105. package/dist/types/src/capabilities/react-surface/index.d.ts.map +0 -1
  106. package/dist/types/src/capabilities/react-surface/react-surface.d.ts.map +0 -1
  107. package/src/capabilities/react-surface/index.ts +0 -7
  108. /package/dist/types/src/capabilities/{react-surface/react-surface.d.ts → react-surface.d.ts} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/plugin-explorer",
3
- "version": "0.8.4-main.4a85c3132b",
3
+ "version": "0.8.4-main.51f1e5ca51",
4
4
  "description": "Braneframe data visualization plugin",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -12,6 +12,15 @@
12
12
  "author": "DXOS.org",
13
13
  "sideEffects": true,
14
14
  "type": "module",
15
+ "imports": {
16
+ "#capabilities": "./src/capabilities/index.ts",
17
+ "#components": "./src/components/index.ts",
18
+ "#containers": "./src/containers/index.ts",
19
+ "#hooks": "./src/hooks/index.ts",
20
+ "#meta": "./src/meta.ts",
21
+ "#translations": "./src/translations.ts",
22
+ "#types": "./src/types/index.ts"
23
+ },
15
24
  "exports": {
16
25
  ".": {
17
26
  "source": "./src/index.ts",
@@ -25,6 +34,12 @@
25
34
  "node": "./dist/lib/node-esm/meta.mjs",
26
35
  "types": "./dist/types/src/meta.d.ts"
27
36
  },
37
+ "./translations": {
38
+ "source": "./src/translations.ts",
39
+ "types": "./dist/types/src/translations.d.ts",
40
+ "browser": "./dist/lib/browser/translations.mjs",
41
+ "node": "./dist/lib/node-esm/translations.mjs"
42
+ },
28
43
  "./types": {
29
44
  "source": "./src/types/index.ts",
30
45
  "browser": "./dist/lib/browser/types/index.mjs",
@@ -33,16 +48,6 @@
33
48
  }
34
49
  },
35
50
  "types": "dist/types/src/index.d.ts",
36
- "typesVersions": {
37
- "*": {
38
- "meta": [
39
- "dist/types/src/meta.d.ts"
40
- ],
41
- "types": [
42
- "dist/types/src/types/index.d.ts"
43
- ]
44
- }
45
- },
46
51
  "files": [
47
52
  "dist",
48
53
  "src"
@@ -52,35 +57,35 @@
52
57
  "@effect-atom/atom-react": "^0.5.0",
53
58
  "@observablehq/plot": "^0.6.11",
54
59
  "d3": "^7.9.0",
55
- "effect": "3.19.16",
60
+ "effect": "3.20.0",
56
61
  "force-graph": "^1.49.4",
57
62
  "lodash.defaultsdeep": "^4.6.1",
58
63
  "react-resize-detector": "^11.0.1",
59
64
  "three": "^0.178.0",
60
65
  "topojson-client": "^3.1.0",
61
- "@dxos/app-framework": "0.8.4-main.4a85c3132b",
62
- "@dxos/async": "0.8.4-main.4a85c3132b",
63
- "@dxos/client": "0.8.4-main.4a85c3132b",
64
- "@dxos/app-toolkit": "0.8.4-main.4a85c3132b",
65
- "@dxos/echo-query": "0.8.4-main.4a85c3132b",
66
- "@dxos/echo": "0.8.4-main.4a85c3132b",
67
- "@dxos/graph": "0.8.4-main.4a85c3132b",
68
- "@dxos/invariant": "0.8.4-main.4a85c3132b",
69
- "@dxos/operation": "0.8.4-main.4a85c3132b",
70
- "@dxos/log": "0.8.4-main.4a85c3132b",
71
- "@dxos/plugin-client": "0.8.4-main.4a85c3132b",
72
- "@dxos/plugin-search": "0.8.4-main.4a85c3132b",
73
- "@dxos/plugin-graph": "0.8.4-main.4a85c3132b",
74
- "@dxos/react-client": "0.8.4-main.4a85c3132b",
75
- "@dxos/plugin-space": "0.8.4-main.4a85c3132b",
76
- "@dxos/react-ui-attention": "0.8.4-main.4a85c3132b",
77
- "@dxos/react-ui-components": "0.8.4-main.4a85c3132b",
78
- "@dxos/react-ui-graph": "0.8.4-main.4a85c3132b",
79
- "@dxos/react-ui-mosaic": "0.8.4-main.4a85c3132b",
80
- "@dxos/schema": "0.8.4-main.4a85c3132b",
81
- "@dxos/react-ui-stack": "0.8.4-main.4a85c3132b",
82
- "@dxos/types": "0.8.4-main.4a85c3132b",
83
- "@dxos/util": "0.8.4-main.4a85c3132b"
66
+ "@dxos/app-toolkit": "0.8.4-main.51f1e5ca51",
67
+ "@dxos/app-framework": "0.8.4-main.51f1e5ca51",
68
+ "@dxos/async": "0.8.4-main.51f1e5ca51",
69
+ "@dxos/client": "0.8.4-main.51f1e5ca51",
70
+ "@dxos/echo": "0.8.4-main.51f1e5ca51",
71
+ "@dxos/compute": "0.8.4-main.51f1e5ca51",
72
+ "@dxos/echo-query": "0.8.4-main.51f1e5ca51",
73
+ "@dxos/graph": "0.8.4-main.51f1e5ca51",
74
+ "@dxos/invariant": "0.8.4-main.51f1e5ca51",
75
+ "@dxos/log": "0.8.4-main.51f1e5ca51",
76
+ "@dxos/plugin-graph": "0.8.4-main.51f1e5ca51",
77
+ "@dxos/plugin-client": "0.8.4-main.51f1e5ca51",
78
+ "@dxos/plugin-search": "0.8.4-main.51f1e5ca51",
79
+ "@dxos/plugin-space": "0.8.4-main.51f1e5ca51",
80
+ "@dxos/react-client": "0.8.4-main.51f1e5ca51",
81
+ "@dxos/react-ui-graph": "0.8.4-main.51f1e5ca51",
82
+ "@dxos/react-ui-mosaic": "0.8.4-main.51f1e5ca51",
83
+ "@dxos/react-ui-attention": "0.8.4-main.51f1e5ca51",
84
+ "@dxos/react-ui-stack": "0.8.4-main.51f1e5ca51",
85
+ "@dxos/schema": "0.8.4-main.51f1e5ca51",
86
+ "@dxos/util": "0.8.4-main.51f1e5ca51",
87
+ "@dxos/types": "0.8.4-main.51f1e5ca51",
88
+ "@dxos/react-ui-components": "0.8.4-main.51f1e5ca51"
84
89
  },
85
90
  "devDependencies": {
86
91
  "@types/d3": "^7.4.3",
@@ -92,19 +97,19 @@
92
97
  "@types/topojson-specification": "^1.0.5",
93
98
  "react": "~19.2.3",
94
99
  "react-dom": "~19.2.3",
95
- "vite": "^7.1.11",
96
- "@dxos/random": "0.8.4-main.4a85c3132b",
97
- "@dxos/react-ui": "0.8.4-main.4a85c3132b",
98
- "@dxos/storybook-utils": "0.8.4-main.4a85c3132b",
99
- "@dxos/ui-theme": "0.8.4-main.4a85c3132b",
100
- "@dxos/echo-generator": "0.8.4-main.4a85c3132b"
100
+ "vite": "^8.0.10",
101
+ "@dxos/echo-generator": "0.8.4-main.51f1e5ca51",
102
+ "@dxos/react-ui": "0.8.4-main.51f1e5ca51",
103
+ "@dxos/random": "0.8.4-main.51f1e5ca51",
104
+ "@dxos/storybook-utils": "0.8.4-main.51f1e5ca51",
105
+ "@dxos/ui-theme": "0.8.4-main.51f1e5ca51"
101
106
  },
102
107
  "peerDependencies": {
103
- "effect": "3.19.16",
108
+ "effect": "3.20.0",
104
109
  "react": "~19.2.3",
105
110
  "react-dom": "~19.2.3",
106
- "@dxos/ui-theme": "0.8.4-main.4a85c3132b",
107
- "@dxos/react-ui": "0.8.4-main.4a85c3132b"
111
+ "@dxos/ui-theme": "0.8.4-main.51f1e5ca51",
112
+ "@dxos/react-ui": "0.8.4-main.51f1e5ca51"
108
113
  },
109
114
  "publishConfig": {
110
115
  "access": "public"
@@ -3,30 +3,41 @@
3
3
  //
4
4
 
5
5
  import * as Effect from 'effect/Effect';
6
+ import * as Option from 'effect/Option';
6
7
 
7
8
  import { Plugin } from '@dxos/app-framework';
8
9
  import { AppPlugin } from '@dxos/app-toolkit';
9
- import { Type } from '@dxos/echo';
10
+ import { Operation } from '@dxos/compute';
11
+ import { Annotation, Type } from '@dxos/echo';
12
+ import { SpaceOperation } from '@dxos/plugin-space/operations';
10
13
  import { type CreateObject } from '@dxos/plugin-space/types';
11
14
  import { ViewModel } from '@dxos/schema';
12
15
 
13
- import { ReactSurface } from './capabilities';
14
- import { meta } from './meta';
15
- import { translations } from './translations';
16
- import { ExplorerAction, Graph } from './types';
16
+ import { ReactSurface } from '#capabilities';
17
+ import { meta } from '#meta';
18
+ import { translations } from '#translations';
19
+ import { ExplorerAction, Graph } from '#types';
17
20
 
18
21
  export const ExplorerPlugin = Plugin.define(meta).pipe(
19
22
  AppPlugin.addMetadataModule({
20
23
  metadata: {
21
24
  id: Type.getTypename(Graph.Graph),
22
25
  metadata: {
23
- icon: 'ph--graph--regular',
24
- iconHue: 'green',
26
+ icon: Annotation.IconAnnotation.get(Graph.Graph).pipe(Option.getOrThrow).icon,
27
+ iconHue: Annotation.IconAnnotation.get(Graph.Graph).pipe(Option.getOrThrow).hue ?? 'white',
25
28
  inputSchema: ExplorerAction.GraphProps,
26
- createObject: ((props, { db }) =>
27
- Effect.promise(async () => {
28
- const { view } = await ViewModel.makeFromDatabase({ db, typename: props.typename });
29
- return Graph.make({ name: props.name, view });
29
+ createObject: ((props, options) =>
30
+ Effect.gen(function* () {
31
+ const object = yield* Effect.promise(async () => {
32
+ const { view } = await ViewModel.makeFromDatabase({ db: options.db, typename: props.typename });
33
+ return Graph.make({ name: props.name, view });
34
+ });
35
+ return yield* Operation.invoke(SpaceOperation.AddObject, {
36
+ object,
37
+ target: options.target,
38
+ hidden: true,
39
+ targetNodeId: options.targetNodeId,
40
+ });
30
41
  })) satisfies CreateObject,
31
42
  },
32
43
  },
@@ -2,4 +2,6 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- export * from './react-surface';
5
+ import { Capability } from '@dxos/app-framework';
6
+
7
+ export const ReactSurface = Capability.lazy('ReactSurface', () => import('./react-surface'));
@@ -7,23 +7,24 @@ import React from 'react';
7
7
 
8
8
  import { Capabilities, Capability } from '@dxos/app-framework';
9
9
  import { Surface } from '@dxos/app-framework/ui';
10
- import { Obj } from '@dxos/echo';
11
- import { type View } from '@dxos/echo';
10
+ import { AppSurface } from '@dxos/app-toolkit/ui';
12
11
 
13
- import { ExplorerContainer } from '../../containers';
14
- import { meta } from '../../meta';
15
- import { Graph } from '../../types';
12
+ import { ExplorerContainer } from '#containers';
13
+ import { Graph } from '#types';
16
14
 
17
15
  export default Capability.makeModule(() =>
18
16
  Effect.succeed(
19
17
  Capability.contributes(
20
18
  Capabilities.ReactSurface,
21
19
  Surface.create({
22
- id: `${meta.id}/article`,
23
- role: ['article', 'section'],
24
- filter: (data): data is { subject: View.View } => Obj.instanceOf(Graph.Graph, data.subject),
20
+ id: 'article',
21
+ // TODO(wittjosiah): Split into multiple surfaces if this filter proves too strict for non-article roles.
22
+ filter: AppSurface.oneOf(
23
+ AppSurface.object(AppSurface.Article, Graph.Graph),
24
+ AppSurface.object(AppSurface.Section, Graph.Graph),
25
+ ),
25
26
  component: ({ data, role }) => {
26
- return <ExplorerContainer role={role} subject={data.subject} />;
27
+ return <ExplorerContainer role={role} subject={data.subject} attendableId={data.attendableId} />;
27
28
  },
28
29
  }),
29
30
  ),
@@ -9,7 +9,6 @@ import { ClientRepeater } from '@dxos/react-client/testing';
9
9
  import { withLayout, withTheme } from '@dxos/react-ui/testing';
10
10
 
11
11
  import CitiesData from '../../../data/cities.js';
12
-
13
12
  import { Chart } from './Chart';
14
13
 
15
14
  // TODO(burdon): Generate data with geo lat/lng.
@@ -14,7 +14,6 @@ import { withLayout, withTheme } from '@dxos/react-ui/testing';
14
14
 
15
15
  import CitiesData from '../../../data/cities.js';
16
16
  import CountriesData from '../../../data/countries-110m.js';
17
-
18
17
  import { Globe } from './Globe';
19
18
 
20
19
  // TODO(burdon): Generate data with geo lat/lng.
@@ -7,27 +7,26 @@ import React, { useState } from 'react';
7
7
 
8
8
  import { Type } from '@dxos/echo';
9
9
  import { View } from '@dxos/echo';
10
- import { faker } from '@dxos/random';
10
+ import { random } from '@dxos/random';
11
11
  import { useClient } from '@dxos/react-client';
12
12
  import { type Space } from '@dxos/react-client/echo';
13
13
  import { withClientProvider } from '@dxos/react-client/testing';
14
14
  import { useAsyncEffect } from '@dxos/react-ui';
15
- import { withLayout, withTheme } from '@dxos/react-ui/testing';
15
+ import { Loading, withLayout, withTheme } from '@dxos/react-ui/testing';
16
16
  import { ViewModel } from '@dxos/schema';
17
17
  import { type ValueGenerator } from '@dxos/schema/testing';
18
18
  import { withRegistry } from '@dxos/storybook-utils';
19
- import { render } from '@dxos/storybook-utils';
20
19
  import { HasRelationship, Organization, Person, Pipeline } from '@dxos/types';
21
20
 
22
- import { useGraphModel } from '../../hooks';
23
- import { Graph } from '../../types';
21
+ import { useGraphModel } from '#hooks';
22
+ import { Graph } from '#types';
24
23
 
25
24
  import { D3ForceGraph } from './D3ForceGraph';
26
25
  import { generate } from './testing';
27
26
 
28
- const generator = faker as any as ValueGenerator;
27
+ const generator = random as any as ValueGenerator;
29
28
 
30
- faker.seed(1);
29
+ random.seed(1);
31
30
 
32
31
  const DefaultStory = () => {
33
32
  const client = useClient();
@@ -35,7 +34,7 @@ const DefaultStory = () => {
35
34
  const [graph, setGraph] = useState<Graph.Graph>();
36
35
 
37
36
  useAsyncEffect(async () => {
38
- const space = client.spaces.default;
37
+ const space = client.spaces.get()[0];
39
38
  void generate(space, generator);
40
39
  const { view } = await ViewModel.makeFromDatabase({ db: space.db, typename: Type.getTypename(Graph.Graph) });
41
40
  const graph = Graph.make({ name: 'Test', view });
@@ -46,7 +45,7 @@ const DefaultStory = () => {
46
45
 
47
46
  const model = useGraphModel(space);
48
47
  if (!model || !space || !graph) {
49
- return null;
48
+ return <Loading data={{ model: !!model, space: !!space, graph: !!graph }} />;
50
49
  }
51
50
 
52
51
  return <D3ForceGraph model={model} />;
@@ -55,7 +54,7 @@ const DefaultStory = () => {
55
54
  const meta = {
56
55
  title: 'plugins/plugin-explorer/components/D3ForceGraph',
57
56
  component: D3ForceGraph,
58
- render: render(DefaultStory),
57
+ render: DefaultStory,
59
58
  decorators: [
60
59
  withRegistry,
61
60
  withTheme(),
@@ -2,11 +2,11 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
+ import { Atom, useAtomValue } from '@effect-atom/atom-react';
5
6
  import React, { type ComponentPropsWithoutRef, useCallback, useEffect, useMemo, useRef } from 'react';
6
7
 
7
8
  import { Obj } from '@dxos/echo';
8
9
  import { SelectionModel } from '@dxos/graph';
9
- import { type ThemedClassName } from '@dxos/react-ui';
10
10
  import {
11
11
  type GraphController,
12
12
  GraphForceProjector,
@@ -16,87 +16,93 @@ import {
16
16
  type SVGContext,
17
17
  } from '@dxos/react-ui-graph';
18
18
  import { type SpaceGraphEdge, type SpaceGraphModel, type SpaceGraphNode } from '@dxos/schema';
19
- import { getHashStyles } from '@dxos/ui-theme';
20
-
19
+ import { composable, composableProps, getHashStyles } from '@dxos/ui-theme';
21
20
  import '@dxos/react-ui-graph/styles/graph.css';
22
21
 
23
- export type D3ForceGraphProps = ThemedClassName<
24
- {
25
- model?: SpaceGraphModel;
26
- match?: RegExp;
27
- selection?: SelectionModel;
28
- grid?: boolean;
29
- } & Pick<GraphProps, 'drag'> &
30
- ComponentPropsWithoutRef<'div'>
31
- >;
22
+ export type D3ForceGraphProps = {
23
+ model?: SpaceGraphModel;
24
+ match?: RegExp;
25
+ selection?: SelectionModel;
26
+ grid?: boolean;
27
+ } & Pick<GraphProps, 'drag'> &
28
+ ComponentPropsWithoutRef<'div'>;
29
+
30
+ const EMPTY_ATOM = Atom.make<{ nodes: SpaceGraphNode[]; edges: SpaceGraphEdge[] }>({ nodes: [], edges: [] });
31
+
32
+ export const D3ForceGraph = composable<HTMLDivElement, D3ForceGraphProps>(
33
+ ({ model, selection: _selection, grid, drag, ...props }, forwardedRef) => {
34
+ // TODO(wittjosiah): This should go into Graph.tsx but for some reason doesn't work.
35
+ useAtomValue(model?.graphAtom ?? EMPTY_ATOM);
32
36
 
33
- export const D3ForceGraph = ({ classNames, model, selection: _selection, grid, drag, ...props }: D3ForceGraphProps) => {
34
- const context = useRef<SVGContext>(null);
35
- const projector = useMemo<GraphForceProjector | undefined>(() => {
36
- if (context.current) {
37
- return new GraphForceProjector(context.current, {
38
- attributes: {
39
- linkForce: (edge) => {
40
- // TODO(burdon): Check type (currently assumes Employee property).
41
- // Edge shouldn't contribute to force if it's not active.
42
- return edge.data?.object?.active !== false;
37
+ const svgRef = useRef<SVGContext>(null);
38
+ const projector = useMemo<GraphForceProjector | undefined>(() => {
39
+ if (svgRef.current) {
40
+ return new GraphForceProjector(svgRef.current, {
41
+ attributes: {
42
+ linkForce: (edge) => {
43
+ // TODO(burdon): Check type (currently assumes Employee property).
44
+ // Edge shouldn't contribute to force if it's not active.
45
+ return edge.data?.object?.active !== false;
46
+ },
43
47
  },
44
- },
45
- forces: {
46
- point: {
47
- strength: 0.01,
48
+ forces: {
49
+ point: {
50
+ strength: 0.01,
51
+ },
48
52
  },
49
- },
50
- });
51
- }
52
- }, [context.current]);
53
+ });
54
+ }
55
+ }, []);
53
56
 
54
- const graph = useRef<GraphController>(null);
55
- const selection = useMemo(() => _selection ?? new SelectionModel(), [_selection]);
56
- useEffect(() => selection.subscribe(() => graph.current?.repaint()), [selection]);
57
+ const graph = useRef<GraphController>(null);
58
+ const selection = useMemo(() => _selection ?? new SelectionModel(), [_selection]);
59
+ useEffect(() => selection.subscribe(() => graph.current?.repaint()), [selection]);
57
60
 
58
- const handleSelect = useCallback<NonNullable<GraphProps['onSelect']>>(
59
- (node) => {
60
- if (selection.contains(node.id)) {
61
- selection.remove(node.id);
62
- } else {
63
- selection.add(node.id);
64
- }
65
- },
66
- [selection],
67
- );
61
+ const handleSelect = useCallback<NonNullable<GraphProps['onSelect']>>(
62
+ (node) => {
63
+ if (selection.contains(node.id)) {
64
+ selection.remove(node.id);
65
+ } else {
66
+ selection.add(node.id);
67
+ }
68
+ },
69
+ [selection],
70
+ );
68
71
 
69
- return (
70
- <SVG.Root ref={context} classNames={classNames} {...props}>
71
- <SVG.Markers />
72
- {grid && <SVG.Grid axis />}
73
- <SVG.Zoom extent={[1 / 2, 2]}>
74
- <SVG.Graph<SpaceGraphNode, SpaceGraphEdge>
75
- drag={drag}
76
- ref={graph}
77
- model={model}
78
- projector={projector}
79
- labels={{
80
- text: (node) => {
81
- return node.data?.data.label ?? node.id;
82
- },
83
- }}
84
- attributes={{
85
- node: (node: GraphLayoutNode<SpaceGraphNode>) => {
86
- const obj = node.data?.data.object;
87
- return {
88
- data: {
89
- color: getHashStyles(obj && Obj.getTypename(obj))?.hue,
72
+ return (
73
+ <div {...composableProps(props, { classNames: 'dx-container' })} ref={forwardedRef}>
74
+ <SVG.Root ref={svgRef}>
75
+ <SVG.Markers />
76
+ {grid && <SVG.Grid axis />}
77
+ <SVG.Zoom extent={[1 / 2, 2]}>
78
+ <SVG.Graph<SpaceGraphNode, SpaceGraphEdge>
79
+ drag={drag}
80
+ ref={graph}
81
+ model={model}
82
+ projector={projector}
83
+ labels={{
84
+ text: (node) => {
85
+ return node.data?.data.label ?? node.id;
90
86
  },
91
- classes: {
92
- 'dx-selected': selection.contains(node.id),
87
+ }}
88
+ attributes={{
89
+ node: (node: GraphLayoutNode<SpaceGraphNode>) => {
90
+ const obj = node.data?.data.object;
91
+ return {
92
+ data: {
93
+ color: getHashStyles(obj && Obj.getTypename(obj))?.hue,
94
+ },
95
+ classes: {
96
+ 'dx-selected': selection.contains(node.id),
97
+ },
98
+ };
93
99
  },
94
- };
95
- },
96
- }}
97
- onSelect={handleSelect}
98
- />
99
- </SVG.Zoom>
100
- </SVG.Root>
101
- );
102
- };
100
+ }}
101
+ onSelect={handleSelect}
102
+ />
103
+ </SVG.Zoom>
104
+ </SVG.Root>
105
+ </div>
106
+ );
107
+ },
108
+ );
@@ -7,27 +7,26 @@ import React, { useState } from 'react';
7
7
 
8
8
  import { Type } from '@dxos/echo';
9
9
  import { View } from '@dxos/echo';
10
- import { faker } from '@dxos/random';
10
+ import { random } from '@dxos/random';
11
11
  import { useClient } from '@dxos/react-client';
12
12
  import { type Space } from '@dxos/react-client/echo';
13
13
  import { withClientProvider } from '@dxos/react-client/testing';
14
14
  import { useAsyncEffect } from '@dxos/react-ui';
15
- import { withLayout, withTheme } from '@dxos/react-ui/testing';
15
+ import { Loading, withLayout, withTheme } from '@dxos/react-ui/testing';
16
16
  import { ViewModel } from '@dxos/schema';
17
17
  import { type ValueGenerator } from '@dxos/schema/testing';
18
18
  import { withRegistry } from '@dxos/storybook-utils';
19
- import { render } from '@dxos/storybook-utils';
20
19
  import { HasRelationship, Organization, Person, Pipeline } from '@dxos/types';
21
20
 
22
- import { useGraphModel } from '../../hooks';
23
- import { Graph } from '../../types';
21
+ import { useGraphModel } from '#hooks';
22
+ import { Graph } from '#types';
24
23
 
25
24
  import { ForceGraph } from './ForceGraph';
26
25
  import { generate } from './testing';
27
26
 
28
- const generator = faker as any as ValueGenerator;
27
+ const generator = random as any as ValueGenerator;
29
28
 
30
- faker.seed(1);
29
+ random.seed(1);
31
30
 
32
31
  const DefaultStory = () => {
33
32
  const client = useClient();
@@ -35,7 +34,7 @@ const DefaultStory = () => {
35
34
  const [graph, setGraph] = useState<Graph.Graph>();
36
35
 
37
36
  useAsyncEffect(async () => {
38
- const space = client.spaces.default;
37
+ const space = client.spaces.get()[0];
39
38
  void generate(space, generator);
40
39
  const { view } = await ViewModel.makeFromDatabase({ db: space.db, typename: Type.getTypename(Graph.Graph) });
41
40
  const graph = Graph.make({ name: 'Test', view });
@@ -46,7 +45,7 @@ const DefaultStory = () => {
46
45
 
47
46
  const model = useGraphModel(space);
48
47
  if (!model || !space || !graph) {
49
- return null;
48
+ return <Loading data={{ model: !!model, space: !!space, graph: !!graph }} />;
50
49
  }
51
50
 
52
51
  return <ForceGraph model={model} />;
@@ -55,7 +54,7 @@ const DefaultStory = () => {
55
54
  const meta = {
56
55
  title: 'plugins/plugin-explorer/components/ForceGraph',
57
56
  component: ForceGraph,
58
- render: render(DefaultStory),
57
+ render: DefaultStory,
59
58
  decorators: [
60
59
  withRegistry,
61
60
  withTheme(),
@@ -5,7 +5,8 @@
5
5
  import { type Meta, type StoryObj } from '@storybook/react-vite';
6
6
  import React, { useEffect, useState } from 'react';
7
7
 
8
- import { faker } from '@dxos/random';
8
+ import { invariant } from '@dxos/invariant';
9
+ import { random } from '@dxos/random';
9
10
  import { useClient } from '@dxos/react-client';
10
11
  import { type ClientRepeatedComponentProps, ClientRepeater } from '@dxos/react-client/testing';
11
12
  import { withLayout, withTheme } from '@dxos/react-ui/testing';
@@ -17,13 +18,14 @@ import { Tree as TreeModel, TreeType } from './types';
17
18
  // TODO(burdon): Storybook for Graph/Tree/Plot (generics); incl. GraphModel.
18
19
  // TODO(burdon): Type for all Explorer components (Space, Object, Query, etc.) incl.
19
20
 
20
- faker.seed(1);
21
+ random.seed(1);
21
22
 
22
23
  type ComponentProps = ClientRepeatedComponentProps & { type?: TreeComponentProps<any>['variant'] };
23
24
 
24
25
  const Component = ({ type }: ComponentProps) => {
25
26
  const client = useClient();
26
- const space = client.spaces.default;
27
+ const space = client.spaces.get()[0];
28
+ invariant(space, 'Tree story requires at least one space');
27
29
  const [object, setObject] = useState<TreeType>();
28
30
  useEffect(() => {
29
31
  setTimeout(() => {
@@ -16,7 +16,7 @@ const random = (min: number, max: number) => Math.floor(Math.random() * (max - m
16
16
  */
17
17
  export const createTree = (spec: NumberOrNumberArray[] = [], createText?: () => string): Tree => {
18
18
  const tree = new Tree();
19
- Obj.change(tree.tree, () => {
19
+ Obj.update(tree.tree, () => {
20
20
  tree.root.data = { text: 'root' };
21
21
  });
22
22
 
@@ -5,14 +5,13 @@
5
5
  import { describe, test } from 'vitest';
6
6
 
7
7
  import { Obj, Ref } from '@dxos/echo';
8
- import { faker } from '@dxos/random';
8
+ import { random } from '@dxos/random';
9
9
  import { Task } from '@dxos/types';
10
10
 
11
11
  import { createTree } from '../testing';
12
-
13
12
  import { type Tree } from './tree';
14
13
 
15
- faker.seed(0);
14
+ random.seed(0);
16
15
 
17
16
  const print = (tree: Tree) => {
18
17
  let count = 0;
@@ -129,7 +128,7 @@ describe('tree', () => {
129
128
 
130
129
  const tree = createTree();
131
130
  const node = tree.addNode(tree.root);
132
- Obj.change(tree.tree, () => {
131
+ Obj.update(tree.tree, () => {
133
132
  node.ref = Ref.make(task);
134
133
  });
135
134
  });