@dxos/plugin-explorer 0.8.4-main.3eb6e50203 → 0.8.4-main.422d1c7879

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 (99) hide show
  1. package/dist/lib/browser/{chunk-YNQF4CPY.mjs → chunk-LSUP47BZ.mjs} +2 -2
  2. package/dist/lib/browser/{chunk-YNQF4CPY.mjs.map → chunk-LSUP47BZ.mjs.map} +1 -1
  3. package/dist/lib/browser/index.mjs +11325 -52
  4. package/dist/lib/browser/index.mjs.map +4 -4
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/meta.mjs +1 -1
  7. package/dist/lib/browser/types/index.mjs +64 -4
  8. package/dist/lib/browser/types/index.mjs.map +4 -4
  9. package/dist/lib/node-esm/{chunk-DK77RB6M.mjs → chunk-EN3JZNEY.mjs} +2 -2
  10. package/dist/lib/node-esm/{chunk-DK77RB6M.mjs.map → chunk-EN3JZNEY.mjs.map} +1 -1
  11. package/dist/lib/node-esm/index.mjs +11325 -52
  12. package/dist/lib/node-esm/index.mjs.map +4 -4
  13. package/dist/lib/node-esm/meta.json +1 -1
  14. package/dist/lib/node-esm/meta.mjs +1 -1
  15. package/dist/lib/node-esm/types/index.mjs +64 -4
  16. package/dist/lib/node-esm/types/index.mjs.map +4 -4
  17. package/dist/types/src/ExplorerPlugin.d.ts.map +1 -1
  18. package/dist/types/src/capabilities/index.d.ts +2 -1
  19. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  20. package/dist/types/src/capabilities/react-surface.d.ts +5 -0
  21. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -0
  22. package/dist/types/src/components/Chart/Chart.stories.d.ts.map +1 -1
  23. package/dist/types/src/components/Globe/Globe.stories.d.ts.map +1 -1
  24. package/dist/types/src/components/Graph/D3ForceGraph.d.ts +6 -5
  25. package/dist/types/src/components/Graph/D3ForceGraph.d.ts.map +1 -1
  26. package/dist/types/src/components/Graph/D3ForceGraph.stories.d.ts +4 -2
  27. package/dist/types/src/components/Graph/D3ForceGraph.stories.d.ts.map +1 -1
  28. package/dist/types/src/components/Graph/ForceGraph.stories.d.ts +1 -1
  29. package/dist/types/src/components/Tree/Tree.stories.d.ts.map +1 -1
  30. package/dist/types/src/components/Tree/types/tree.d.ts +3 -3
  31. package/dist/types/src/components/Tree/types/tree.d.ts.map +1 -1
  32. package/dist/types/src/components/index.d.ts +0 -2
  33. package/dist/types/src/components/index.d.ts.map +1 -1
  34. package/dist/types/src/containers/ExplorerContainer/ExplorerContainer.d.ts +6 -0
  35. package/dist/types/src/containers/ExplorerContainer/ExplorerContainer.d.ts.map +1 -0
  36. package/dist/types/src/containers/ExplorerContainer/index.d.ts +2 -0
  37. package/dist/types/src/containers/ExplorerContainer/index.d.ts.map +1 -0
  38. package/dist/types/src/containers/index.d.ts +3 -0
  39. package/dist/types/src/containers/index.d.ts.map +1 -0
  40. package/dist/types/src/hooks/useGraphModel.d.ts.map +1 -1
  41. package/dist/types/src/translations.d.ts +28 -26
  42. package/dist/types/src/translations.d.ts.map +1 -1
  43. package/dist/types/src/types/ExplorerAction.d.ts.map +1 -1
  44. package/dist/types/src/types/Graph.d.ts +2 -9
  45. package/dist/types/src/types/Graph.d.ts.map +1 -1
  46. package/dist/types/tsconfig.tsbuildinfo +1 -1
  47. package/package.json +45 -47
  48. package/src/ExplorerPlugin.tsx +23 -11
  49. package/src/capabilities/index.ts +3 -1
  50. package/src/capabilities/{react-surface/react-surface.tsx → react-surface.tsx} +10 -9
  51. package/src/components/Chart/Chart.stories.tsx +1 -2
  52. package/src/components/Globe/Globe.stories.tsx +1 -2
  53. package/src/components/Graph/D3ForceGraph.stories.tsx +13 -13
  54. package/src/components/Graph/D3ForceGraph.tsx +82 -75
  55. package/src/components/Graph/ForceGraph.stories.tsx +13 -13
  56. package/src/components/Tree/Tree.stories.tsx +6 -4
  57. package/src/components/Tree/types/tree.test.ts +2 -3
  58. package/src/components/Tree/types/tree.ts +9 -9
  59. package/src/components/index.ts +0 -4
  60. package/src/{components → containers/ExplorerContainer}/ExplorerContainer.tsx +17 -16
  61. package/src/containers/ExplorerContainer/index.ts +5 -0
  62. package/src/containers/index.ts +7 -0
  63. package/src/hooks/useGraphModel.ts +14 -10
  64. package/src/meta.ts +1 -1
  65. package/src/translations.ts +13 -12
  66. package/src/types/ExplorerAction.ts +0 -1
  67. package/src/types/Graph.ts +10 -23
  68. package/src/typings.d.ts +8 -0
  69. package/dist/lib/browser/ExplorerContainer-46BHUF6R.mjs +0 -45
  70. package/dist/lib/browser/ExplorerContainer-46BHUF6R.mjs.map +0 -7
  71. package/dist/lib/browser/chunk-HIFLWHXR.mjs +0 -83
  72. package/dist/lib/browser/chunk-HIFLWHXR.mjs.map +0 -7
  73. package/dist/lib/browser/chunk-JZSBQYJQ.mjs +0 -11076
  74. package/dist/lib/browser/chunk-JZSBQYJQ.mjs.map +0 -7
  75. package/dist/lib/browser/chunk-KIXHZZ2C.mjs +0 -35
  76. package/dist/lib/browser/chunk-KIXHZZ2C.mjs.map +0 -7
  77. package/dist/lib/browser/chunk-MGBT2ZFU.mjs +0 -177
  78. package/dist/lib/browser/chunk-MGBT2ZFU.mjs.map +0 -7
  79. package/dist/lib/browser/react-surface-TPQAT5EI.mjs +0 -36
  80. package/dist/lib/browser/react-surface-TPQAT5EI.mjs.map +0 -7
  81. package/dist/lib/node-esm/ExplorerContainer-OZNG47QB.mjs +0 -46
  82. package/dist/lib/node-esm/ExplorerContainer-OZNG47QB.mjs.map +0 -7
  83. package/dist/lib/node-esm/chunk-3OE6TBJI.mjs +0 -84
  84. package/dist/lib/node-esm/chunk-3OE6TBJI.mjs.map +0 -7
  85. package/dist/lib/node-esm/chunk-ASRWO2N5.mjs +0 -37
  86. package/dist/lib/node-esm/chunk-ASRWO2N5.mjs.map +0 -7
  87. package/dist/lib/node-esm/chunk-K5BYG7BW.mjs +0 -11078
  88. package/dist/lib/node-esm/chunk-K5BYG7BW.mjs.map +0 -7
  89. package/dist/lib/node-esm/chunk-YWJBDETV.mjs +0 -179
  90. package/dist/lib/node-esm/chunk-YWJBDETV.mjs.map +0 -7
  91. package/dist/lib/node-esm/react-surface-CYHGJJDU.mjs +0 -37
  92. package/dist/lib/node-esm/react-surface-CYHGJJDU.mjs.map +0 -7
  93. package/dist/types/src/capabilities/react-surface/index.d.ts +0 -3
  94. package/dist/types/src/capabilities/react-surface/index.d.ts.map +0 -1
  95. package/dist/types/src/capabilities/react-surface/react-surface.d.ts +0 -5
  96. package/dist/types/src/capabilities/react-surface/react-surface.d.ts.map +0 -1
  97. package/dist/types/src/components/ExplorerContainer.d.ts +0 -7
  98. package/dist/types/src/components/ExplorerContainer.d.ts.map +0 -1
  99. package/src/capabilities/react-surface/index.ts +0 -7
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/plugin-explorer",
3
- "version": "0.8.4-main.3eb6e50203",
3
+ "version": "0.8.4-main.422d1c7879",
4
4
  "description": "Braneframe data visualization plugin",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -12,37 +12,35 @@
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
+ "#types": "./src/types/index.ts"
22
+ },
15
23
  "exports": {
16
24
  ".": {
25
+ "source": "./src/index.ts",
17
26
  "browser": "./dist/lib/browser/index.mjs",
18
27
  "node": "./dist/lib/node-esm/index.mjs",
19
- "source": "./src/index.ts",
20
28
  "types": "./dist/types/src/index.d.ts"
21
29
  },
22
30
  "./meta": {
31
+ "source": "./src/meta.ts",
23
32
  "browser": "./dist/lib/browser/meta.mjs",
24
33
  "node": "./dist/lib/node-esm/meta.mjs",
25
- "source": "./src/meta.ts",
26
34
  "types": "./dist/types/src/meta.d.ts"
27
35
  },
28
36
  "./types": {
37
+ "source": "./src/types/index.ts",
29
38
  "browser": "./dist/lib/browser/types/index.mjs",
30
39
  "node": "./dist/lib/node-esm/types/index.mjs",
31
- "source": "./src/types/index.ts",
32
40
  "types": "./dist/types/src/types/index.d.ts"
33
41
  }
34
42
  },
35
43
  "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
44
  "files": [
47
45
  "dist",
48
46
  "src"
@@ -52,35 +50,35 @@
52
50
  "@effect-atom/atom-react": "^0.5.0",
53
51
  "@observablehq/plot": "^0.6.11",
54
52
  "d3": "^7.9.0",
55
- "effect": "3.19.16",
53
+ "effect": "3.20.0",
56
54
  "force-graph": "^1.49.4",
57
55
  "lodash.defaultsdeep": "^4.6.1",
58
56
  "react-resize-detector": "^11.0.1",
59
57
  "three": "^0.178.0",
60
58
  "topojson-client": "^3.1.0",
61
- "@dxos/app-framework": "0.8.4-main.3eb6e50203",
62
- "@dxos/async": "0.8.4-main.3eb6e50203",
63
- "@dxos/client": "0.8.4-main.3eb6e50203",
64
- "@dxos/echo": "0.8.4-main.3eb6e50203",
65
- "@dxos/echo-query": "0.8.4-main.3eb6e50203",
66
- "@dxos/invariant": "0.8.4-main.3eb6e50203",
67
- "@dxos/graph": "0.8.4-main.3eb6e50203",
68
- "@dxos/log": "0.8.4-main.3eb6e50203",
69
- "@dxos/operation": "0.8.4-main.3eb6e50203",
70
- "@dxos/plugin-graph": "0.8.4-main.3eb6e50203",
71
- "@dxos/plugin-search": "0.8.4-main.3eb6e50203",
72
- "@dxos/plugin-client": "0.8.4-main.3eb6e50203",
73
- "@dxos/plugin-space": "0.8.4-main.3eb6e50203",
74
- "@dxos/react-ui-components": "0.8.4-main.3eb6e50203",
75
- "@dxos/react-ui-attention": "0.8.4-main.3eb6e50203",
76
- "@dxos/react-ui-graph": "0.8.4-main.3eb6e50203",
77
- "@dxos/react-ui-mosaic": "0.8.4-main.3eb6e50203",
78
- "@dxos/react-ui-stack": "0.8.4-main.3eb6e50203",
79
- "@dxos/react-client": "0.8.4-main.3eb6e50203",
80
- "@dxos/schema": "0.8.4-main.3eb6e50203",
81
- "@dxos/types": "0.8.4-main.3eb6e50203",
82
- "@dxos/app-toolkit": "0.8.4-main.3eb6e50203",
83
- "@dxos/util": "0.8.4-main.3eb6e50203"
59
+ "@dxos/app-framework": "0.8.4-main.422d1c7879",
60
+ "@dxos/app-toolkit": "0.8.4-main.422d1c7879",
61
+ "@dxos/client": "0.8.4-main.422d1c7879",
62
+ "@dxos/async": "0.8.4-main.422d1c7879",
63
+ "@dxos/echo": "0.8.4-main.422d1c7879",
64
+ "@dxos/echo-query": "0.8.4-main.422d1c7879",
65
+ "@dxos/graph": "0.8.4-main.422d1c7879",
66
+ "@dxos/operation": "0.8.4-main.422d1c7879",
67
+ "@dxos/plugin-client": "0.8.4-main.422d1c7879",
68
+ "@dxos/plugin-graph": "0.8.4-main.422d1c7879",
69
+ "@dxos/plugin-search": "0.8.4-main.422d1c7879",
70
+ "@dxos/invariant": "0.8.4-main.422d1c7879",
71
+ "@dxos/plugin-space": "0.8.4-main.422d1c7879",
72
+ "@dxos/react-client": "0.8.4-main.422d1c7879",
73
+ "@dxos/react-ui-attention": "0.8.4-main.422d1c7879",
74
+ "@dxos/react-ui-components": "0.8.4-main.422d1c7879",
75
+ "@dxos/react-ui-graph": "0.8.4-main.422d1c7879",
76
+ "@dxos/log": "0.8.4-main.422d1c7879",
77
+ "@dxos/schema": "0.8.4-main.422d1c7879",
78
+ "@dxos/react-ui-mosaic": "0.8.4-main.422d1c7879",
79
+ "@dxos/react-ui-stack": "0.8.4-main.422d1c7879",
80
+ "@dxos/types": "0.8.4-main.422d1c7879",
81
+ "@dxos/util": "0.8.4-main.422d1c7879"
84
82
  },
85
83
  "devDependencies": {
86
84
  "@types/d3": "^7.4.3",
@@ -92,19 +90,19 @@
92
90
  "@types/topojson-specification": "^1.0.5",
93
91
  "react": "~19.2.3",
94
92
  "react-dom": "~19.2.3",
95
- "vite": "7.1.9",
96
- "@dxos/react-ui": "0.8.4-main.3eb6e50203",
97
- "@dxos/random": "0.8.4-main.3eb6e50203",
98
- "@dxos/storybook-utils": "0.8.4-main.3eb6e50203",
99
- "@dxos/ui-theme": "0.8.4-main.3eb6e50203",
100
- "@dxos/echo-generator": "0.8.4-main.3eb6e50203"
93
+ "vite": "^7.1.11",
94
+ "@dxos/random": "0.8.4-main.422d1c7879",
95
+ "@dxos/echo-generator": "0.8.4-main.422d1c7879",
96
+ "@dxos/react-ui": "0.8.4-main.422d1c7879",
97
+ "@dxos/storybook-utils": "0.8.4-main.422d1c7879",
98
+ "@dxos/ui-theme": "0.8.4-main.422d1c7879"
101
99
  },
102
100
  "peerDependencies": {
103
- "effect": "3.19.16",
101
+ "effect": "3.20.0",
104
102
  "react": "~19.2.3",
105
103
  "react-dom": "~19.2.3",
106
- "@dxos/ui-theme": "0.8.4-main.3eb6e50203",
107
- "@dxos/react-ui": "0.8.4-main.3eb6e50203"
104
+ "@dxos/react-ui": "0.8.4-main.422d1c7879",
105
+ "@dxos/ui-theme": "0.8.4-main.422d1c7879"
108
106
  },
109
107
  "publishConfig": {
110
108
  "access": "public"
@@ -3,30 +3,42 @@
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 { Annotation, Type } from '@dxos/echo';
11
+ import { Operation } from '@dxos/operation';
12
+ import { SpaceOperation } from '@dxos/plugin-space/operations';
10
13
  import { type CreateObject } from '@dxos/plugin-space/types';
11
- import { View } from '@dxos/schema';
14
+ import { ViewModel } from '@dxos/schema';
15
+
16
+ import { ReactSurface } from '#capabilities';
17
+ import { meta } from '#meta';
18
+ import { ExplorerAction, Graph } from '#types';
12
19
 
13
- import { ReactSurface } from './capabilities';
14
- import { meta } from './meta';
15
20
  import { translations } from './translations';
16
- import { ExplorerAction, Graph } from './types';
17
21
 
18
22
  export const ExplorerPlugin = Plugin.define(meta).pipe(
19
23
  AppPlugin.addMetadataModule({
20
24
  metadata: {
21
25
  id: Type.getTypename(Graph.Graph),
22
26
  metadata: {
23
- icon: 'ph--graph--regular',
24
- iconHue: 'green',
27
+ icon: Annotation.IconAnnotation.get(Graph.Graph).pipe(Option.getOrThrow).icon,
28
+ iconHue: Annotation.IconAnnotation.get(Graph.Graph).pipe(Option.getOrThrow).hue ?? 'white',
25
29
  inputSchema: ExplorerAction.GraphProps,
26
- createObject: ((props, { db }) =>
27
- Effect.promise(async () => {
28
- const { view } = await View.makeFromDatabase({ db, typename: props.typename });
29
- return Graph.make({ name: props.name, view });
30
+ createObject: ((props, options) =>
31
+ Effect.gen(function* () {
32
+ const object = yield* Effect.promise(async () => {
33
+ const { view } = await ViewModel.makeFromDatabase({ db: options.db, typename: props.typename });
34
+ return Graph.make({ name: props.name, view });
35
+ });
36
+ return yield* Operation.invoke(SpaceOperation.AddObject, {
37
+ object,
38
+ target: options.target,
39
+ hidden: true,
40
+ targetNodeId: options.targetNodeId,
41
+ });
30
42
  })) satisfies CreateObject,
31
43
  },
32
44
  },
@@ -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/schema';
10
+ import { AppSurface } from '@dxos/app-toolkit/ui';
12
11
 
13
- import { ExplorerContainer } from '../../components';
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.
@@ -32,7 +31,7 @@ const Story = () => {
32
31
  export const Default = () => <ClientRepeater component={Story} />;
33
32
 
34
33
  const meta = {
35
- title: 'plugins/plugin-explorer/Chart',
34
+ title: 'plugins/plugin-explorer/components/Chart',
36
35
  component: Chart,
37
36
  decorators: [withTheme(), withLayout()],
38
37
  parameters: {
@@ -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.
@@ -80,7 +79,7 @@ const ExtendedStory = () => {
80
79
  };
81
80
 
82
81
  const meta = {
83
- title: 'plugins/plugin-explorer/Globe',
82
+ title: 'plugins/plugin-explorer/components/Globe',
84
83
  decorators: [withTheme(), withLayout()],
85
84
  parameters: {
86
85
  layout: 'fullscreen',
@@ -6,27 +6,27 @@ import { type Meta, type StoryObj } from '@storybook/react-vite';
6
6
  import React, { useState } from 'react';
7
7
 
8
8
  import { Type } from '@dxos/echo';
9
- import { faker } from '@dxos/random';
9
+ import { View } from '@dxos/echo';
10
+ import { random } from '@dxos/random';
10
11
  import { useClient } from '@dxos/react-client';
11
12
  import { type Space } from '@dxos/react-client/echo';
12
13
  import { withClientProvider } from '@dxos/react-client/testing';
13
14
  import { useAsyncEffect } from '@dxos/react-ui';
14
- import { withLayout, withTheme } from '@dxos/react-ui/testing';
15
- import { View } from '@dxos/schema';
15
+ import { Loading, withLayout, withTheme } from '@dxos/react-ui/testing';
16
+ import { ViewModel } from '@dxos/schema';
16
17
  import { type ValueGenerator } from '@dxos/schema/testing';
17
18
  import { withRegistry } from '@dxos/storybook-utils';
18
- import { render } from '@dxos/storybook-utils';
19
19
  import { HasRelationship, Organization, Person, Pipeline } from '@dxos/types';
20
20
 
21
- import { useGraphModel } from '../../hooks';
22
- import { Graph } from '../../types';
21
+ import { useGraphModel } from '#hooks';
22
+ import { Graph } from '#types';
23
23
 
24
24
  import { D3ForceGraph } from './D3ForceGraph';
25
25
  import { generate } from './testing';
26
26
 
27
- const generator = faker as any as ValueGenerator;
27
+ const generator = random as any as ValueGenerator;
28
28
 
29
- faker.seed(1);
29
+ random.seed(1);
30
30
 
31
31
  const DefaultStory = () => {
32
32
  const client = useClient();
@@ -34,9 +34,9 @@ const DefaultStory = () => {
34
34
  const [graph, setGraph] = useState<Graph.Graph>();
35
35
 
36
36
  useAsyncEffect(async () => {
37
- const space = client.spaces.default;
37
+ const space = client.spaces.get()[0];
38
38
  void generate(space, generator);
39
- const { view } = await View.makeFromDatabase({ db: space.db, typename: Type.getTypename(Graph.Graph) });
39
+ const { view } = await ViewModel.makeFromDatabase({ db: space.db, typename: Type.getTypename(Graph.Graph) });
40
40
  const graph = Graph.make({ name: 'Test', view });
41
41
  space.db.add(graph);
42
42
  setSpace(space);
@@ -45,16 +45,16 @@ const DefaultStory = () => {
45
45
 
46
46
  const model = useGraphModel(space);
47
47
  if (!model || !space || !graph) {
48
- return null;
48
+ return <Loading data={{ model: !!model, space: !!space, graph: !!graph }} />;
49
49
  }
50
50
 
51
51
  return <D3ForceGraph model={model} />;
52
52
  };
53
53
 
54
54
  const meta = {
55
- title: 'plugins/plugin-explorer/D3ForceGraph',
55
+ title: 'plugins/plugin-explorer/components/D3ForceGraph',
56
56
  component: D3ForceGraph,
57
- render: render(DefaultStory),
57
+ render: DefaultStory,
58
58
  decorators: [
59
59
  withRegistry,
60
60
  withTheme(),
@@ -2,11 +2,11 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import React, { useCallback, useEffect, useMemo, useRef } from 'react';
5
+ import { Atom, useAtomValue } from '@effect-atom/atom-react';
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,86 +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
- >;
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);
31
36
 
32
- export const D3ForceGraph = ({ classNames, model, selection: _selection, grid, ...props }: D3ForceGraphProps) => {
33
- const context = useRef<SVGContext>(null);
34
- const projector = useMemo<GraphForceProjector | undefined>(() => {
35
- if (context.current) {
36
- return new GraphForceProjector(context.current, {
37
- attributes: {
38
- linkForce: (edge) => {
39
- // TODO(burdon): Check type (currently assumes Employee property).
40
- // Edge shouldn't contribute to force if it's not active.
41
- 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
+ },
42
47
  },
43
- },
44
- forces: {
45
- point: {
46
- strength: 0.01,
48
+ forces: {
49
+ point: {
50
+ strength: 0.01,
51
+ },
47
52
  },
48
- },
49
- });
50
- }
51
- }, [context.current]);
53
+ });
54
+ }
55
+ }, []);
52
56
 
53
- const graph = useRef<GraphController>(null);
54
- const selection = useMemo(() => _selection ?? new SelectionModel(), [_selection]);
55
- 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]);
56
60
 
57
- const handleSelect = useCallback<NonNullable<GraphProps['onSelect']>>(
58
- (node) => {
59
- if (selection.contains(node.id)) {
60
- selection.remove(node.id);
61
- } else {
62
- selection.add(node.id);
63
- }
64
- },
65
- [selection],
66
- );
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
+ );
67
71
 
68
- return (
69
- <SVG.Root ref={context} classNames={classNames}>
70
- <SVG.Markers />
71
- {grid && <SVG.Grid axis />}
72
- <SVG.Zoom extent={[1 / 2, 2]}>
73
- <SVG.Graph<SpaceGraphNode, SpaceGraphEdge>
74
- {...props}
75
- ref={graph}
76
- model={model}
77
- projector={projector}
78
- labels={{
79
- text: (node) => {
80
- return node.data?.data.label ?? node.id;
81
- },
82
- }}
83
- attributes={{
84
- node: (node: GraphLayoutNode<SpaceGraphNode>) => {
85
- const obj = node.data?.data.object;
86
- return {
87
- data: {
88
- 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;
89
86
  },
90
- classes: {
91
- '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
+ };
92
99
  },
93
- };
94
- },
95
- }}
96
- onSelect={handleSelect}
97
- />
98
- </SVG.Zoom>
99
- </SVG.Root>
100
- );
101
- };
100
+ }}
101
+ onSelect={handleSelect}
102
+ />
103
+ </SVG.Zoom>
104
+ </SVG.Root>
105
+ </div>
106
+ );
107
+ },
108
+ );
@@ -6,27 +6,27 @@ import { type Meta, type StoryObj } from '@storybook/react-vite';
6
6
  import React, { useState } from 'react';
7
7
 
8
8
  import { Type } from '@dxos/echo';
9
- import { faker } from '@dxos/random';
9
+ import { View } from '@dxos/echo';
10
+ import { random } from '@dxos/random';
10
11
  import { useClient } from '@dxos/react-client';
11
12
  import { type Space } from '@dxos/react-client/echo';
12
13
  import { withClientProvider } from '@dxos/react-client/testing';
13
14
  import { useAsyncEffect } from '@dxos/react-ui';
14
- import { withLayout, withTheme } from '@dxos/react-ui/testing';
15
- import { View } from '@dxos/schema';
15
+ import { Loading, withLayout, withTheme } from '@dxos/react-ui/testing';
16
+ import { ViewModel } from '@dxos/schema';
16
17
  import { type ValueGenerator } from '@dxos/schema/testing';
17
18
  import { withRegistry } from '@dxos/storybook-utils';
18
- import { render } from '@dxos/storybook-utils';
19
19
  import { HasRelationship, Organization, Person, Pipeline } from '@dxos/types';
20
20
 
21
- import { useGraphModel } from '../../hooks';
22
- import { Graph } from '../../types';
21
+ import { useGraphModel } from '#hooks';
22
+ import { Graph } from '#types';
23
23
 
24
24
  import { ForceGraph } from './ForceGraph';
25
25
  import { generate } from './testing';
26
26
 
27
- const generator = faker as any as ValueGenerator;
27
+ const generator = random as any as ValueGenerator;
28
28
 
29
- faker.seed(1);
29
+ random.seed(1);
30
30
 
31
31
  const DefaultStory = () => {
32
32
  const client = useClient();
@@ -34,9 +34,9 @@ const DefaultStory = () => {
34
34
  const [graph, setGraph] = useState<Graph.Graph>();
35
35
 
36
36
  useAsyncEffect(async () => {
37
- const space = client.spaces.default;
37
+ const space = client.spaces.get()[0];
38
38
  void generate(space, generator);
39
- const { view } = await View.makeFromDatabase({ db: space.db, typename: Type.getTypename(Graph.Graph) });
39
+ const { view } = await ViewModel.makeFromDatabase({ db: space.db, typename: Type.getTypename(Graph.Graph) });
40
40
  const graph = Graph.make({ name: 'Test', view });
41
41
  space.db.add(graph);
42
42
  setSpace(space);
@@ -45,16 +45,16 @@ const DefaultStory = () => {
45
45
 
46
46
  const model = useGraphModel(space);
47
47
  if (!model || !space || !graph) {
48
- return null;
48
+ return <Loading data={{ model: !!model, space: !!space, graph: !!graph }} />;
49
49
  }
50
50
 
51
51
  return <ForceGraph model={model} />;
52
52
  };
53
53
 
54
54
  const meta = {
55
- title: 'plugins/plugin-explorer/ForceGraph',
55
+ title: 'plugins/plugin-explorer/components/ForceGraph',
56
56
  component: ForceGraph,
57
- render: render(DefaultStory),
57
+ render: DefaultStory,
58
58
  decorators: [
59
59
  withRegistry,
60
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(() => {
@@ -44,7 +46,7 @@ const DefaultStory = () => {
44
46
  };
45
47
 
46
48
  const meta = {
47
- title: 'plugins/plugin-explorer/Tree',
49
+ title: 'plugins/plugin-explorer/components/Tree',
48
50
  component: Tree as any,
49
51
  render: DefaultStory,
50
52
  decorators: [withRegistry, withTheme(), withLayout()],
@@ -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;