@dxos/plugin-explorer 0.8.0 → 0.8.1-main.81238a8

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/{ExplorerContainer-GJTCBEM4.mjs → ExplorerContainer-3FC557MG.mjs} +2 -2
  2. package/dist/lib/browser/{chunk-S3QNIEBS.mjs → chunk-4OFGICWF.mjs} +241 -2
  3. package/dist/lib/{node-esm/chunk-BRJI3QC2.mjs.map → browser/chunk-4OFGICWF.mjs.map} +4 -4
  4. package/dist/lib/browser/{chunk-PMHCTMKT.mjs → chunk-B3EX52V3.mjs} +2 -2
  5. package/dist/lib/browser/{chunk-QOKAZK4V.mjs → chunk-KYB47PZA.mjs} +1 -1
  6. package/dist/lib/browser/chunk-KYB47PZA.mjs.map +7 -0
  7. package/dist/lib/browser/chunk-X5CI43J6.mjs +205 -0
  8. package/dist/lib/browser/chunk-X5CI43J6.mjs.map +7 -0
  9. package/dist/lib/browser/index.mjs +12 -12
  10. package/dist/lib/browser/index.mjs.map +2 -2
  11. package/dist/lib/browser/{intent-resolver-UJNDAIDZ.mjs → intent-resolver-5UXBTZAM.mjs} +3 -3
  12. package/dist/lib/browser/meta.json +1 -1
  13. package/dist/lib/browser/meta.mjs +1 -1
  14. package/dist/lib/browser/{react-surface-3X2V3VPN.mjs → react-surface-7HHUAS3J.mjs} +7 -6
  15. package/dist/lib/browser/react-surface-7HHUAS3J.mjs.map +7 -0
  16. package/dist/lib/browser/types/index.mjs +2 -2
  17. package/dist/lib/node/{ExplorerContainer-RJT54IOS.cjs → ExplorerContainer-2DQFUEG7.cjs} +6 -6
  18. package/dist/lib/node/{chunk-5MTMJYC4.cjs → chunk-6VLMSRD5.cjs} +4 -4
  19. package/dist/lib/node/chunk-6VLMSRD5.cjs.map +7 -0
  20. package/dist/lib/node/chunk-AABHIUUW.cjs +236 -0
  21. package/dist/lib/node/chunk-AABHIUUW.cjs.map +7 -0
  22. package/dist/lib/node/{chunk-YUY7P7R2.cjs → chunk-C4DXEIBU.cjs} +6 -6
  23. package/dist/lib/node/{chunk-VSACDC6F.cjs → chunk-ZJL53DLS.cjs} +234 -8
  24. package/dist/lib/node/chunk-ZJL53DLS.cjs.map +7 -0
  25. package/dist/lib/node/index.cjs +31 -31
  26. package/dist/lib/node/index.cjs.map +2 -2
  27. package/dist/lib/node/{intent-resolver-XQV24IAA.cjs → intent-resolver-WDMZJTJ5.cjs} +8 -8
  28. package/dist/lib/node/meta.cjs +3 -3
  29. package/dist/lib/node/meta.cjs.map +1 -1
  30. package/dist/lib/node/meta.json +1 -1
  31. package/dist/lib/node/{react-surface-36YIY7NA.cjs → react-surface-UKU6NFBS.cjs} +12 -11
  32. package/dist/lib/node/react-surface-UKU6NFBS.cjs.map +7 -0
  33. package/dist/lib/node/types/index.cjs +4 -4
  34. package/dist/lib/node/types/index.cjs.map +1 -1
  35. package/dist/lib/node-esm/{ExplorerContainer-TM3VIXVK.mjs → ExplorerContainer-RBGUFI5X.mjs} +2 -2
  36. package/dist/lib/node-esm/{chunk-BRJI3QC2.mjs → chunk-PIOV7IOO.mjs} +240 -2
  37. package/dist/lib/{browser/chunk-S3QNIEBS.mjs.map → node-esm/chunk-PIOV7IOO.mjs.map} +4 -4
  38. package/dist/lib/node-esm/{chunk-UHJZUVRI.mjs → chunk-RKQR2GVZ.mjs} +1 -1
  39. package/dist/lib/node-esm/chunk-RKQR2GVZ.mjs.map +7 -0
  40. package/dist/lib/node-esm/chunk-TI3P4L2P.mjs +207 -0
  41. package/dist/lib/node-esm/chunk-TI3P4L2P.mjs.map +7 -0
  42. package/dist/lib/node-esm/{chunk-57K7ORAW.mjs → chunk-WJ6AML7W.mjs} +2 -2
  43. package/dist/lib/node-esm/index.mjs +12 -12
  44. package/dist/lib/node-esm/index.mjs.map +2 -2
  45. package/dist/lib/node-esm/{intent-resolver-RZQ3EEOE.mjs → intent-resolver-KBRYGW6I.mjs} +3 -3
  46. package/dist/lib/node-esm/meta.json +1 -1
  47. package/dist/lib/node-esm/meta.mjs +1 -1
  48. package/dist/lib/node-esm/{react-surface-YDY7IBMY.mjs → react-surface-UZYRBRXP.mjs} +7 -6
  49. package/dist/lib/node-esm/react-surface-UZYRBRXP.mjs.map +7 -0
  50. package/dist/lib/node-esm/types/index.mjs +2 -2
  51. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  52. package/dist/types/src/components/Chart/Chart.d.ts +2 -1
  53. package/dist/types/src/components/Chart/Chart.d.ts.map +1 -1
  54. package/dist/types/src/components/Chart/Chart.stories.d.ts +2 -1
  55. package/dist/types/src/components/Chart/Chart.stories.d.ts.map +1 -1
  56. package/dist/types/src/components/ExplorerContainer.d.ts +2 -1
  57. package/dist/types/src/components/ExplorerContainer.d.ts.map +1 -1
  58. package/dist/types/src/components/Globe/Globe.d.ts +2 -1
  59. package/dist/types/src/components/Globe/Globe.d.ts.map +1 -1
  60. package/dist/types/src/components/Globe/Globe.stories.d.ts +3 -2
  61. package/dist/types/src/components/Globe/Globe.stories.d.ts.map +1 -1
  62. package/dist/types/src/components/Graph/Graph.d.ts +0 -3
  63. package/dist/types/src/components/Graph/Graph.d.ts.map +1 -1
  64. package/dist/types/src/components/Graph/Graph.stories.d.ts +1 -1
  65. package/dist/types/src/components/Graph/Graph.stories.d.ts.map +1 -1
  66. package/dist/types/src/components/Graph/graph-model.d.ts.map +1 -1
  67. package/dist/types/src/components/Tree/Tree.d.ts +2 -1
  68. package/dist/types/src/components/Tree/Tree.d.ts.map +1 -1
  69. package/dist/types/src/components/Tree/Tree.stories.d.ts.map +1 -1
  70. package/dist/types/src/components/Tree/types.d.ts +1 -1
  71. package/dist/types/src/components/Tree/types.d.ts.map +1 -1
  72. package/dist/types/src/components/index.d.ts +1 -1
  73. package/dist/types/src/components/index.d.ts.map +1 -1
  74. package/dist/types/src/meta.d.ts +2 -9
  75. package/dist/types/src/meta.d.ts.map +1 -1
  76. package/dist/types/src/translations.d.ts +3 -3
  77. package/package.json +26 -26
  78. package/src/ExplorerPlugin.tsx +1 -1
  79. package/src/capabilities/react-surface.tsx +2 -1
  80. package/src/components/Graph/Graph.stories.tsx +2 -2
  81. package/src/components/Graph/Graph.tsx +16 -142
  82. package/src/components/Graph/graph-model.ts +2 -0
  83. package/src/components/Tree/Tree.stories.tsx +3 -36
  84. package/src/components/Tree/types.ts +2 -1
  85. package/src/meta.ts +2 -2
  86. package/src/translations.ts +1 -1
  87. package/dist/lib/browser/chunk-QOKAZK4V.mjs.map +0 -7
  88. package/dist/lib/browser/chunk-YQL7YE6N.mjs +0 -546
  89. package/dist/lib/browser/chunk-YQL7YE6N.mjs.map +0 -7
  90. package/dist/lib/browser/react-surface-3X2V3VPN.mjs.map +0 -7
  91. package/dist/lib/node/chunk-5MTMJYC4.cjs.map +0 -7
  92. package/dist/lib/node/chunk-VSACDC6F.cjs.map +0 -7
  93. package/dist/lib/node/chunk-YH4QYCZH.cjs +0 -567
  94. package/dist/lib/node/chunk-YH4QYCZH.cjs.map +0 -7
  95. package/dist/lib/node/react-surface-36YIY7NA.cjs.map +0 -7
  96. package/dist/lib/node-esm/chunk-3KRWHGBM.mjs +0 -548
  97. package/dist/lib/node-esm/chunk-3KRWHGBM.mjs.map +0 -7
  98. package/dist/lib/node-esm/chunk-UHJZUVRI.mjs.map +0 -7
  99. package/dist/lib/node-esm/react-surface-YDY7IBMY.mjs.map +0 -7
  100. /package/dist/lib/browser/{ExplorerContainer-GJTCBEM4.mjs.map → ExplorerContainer-3FC557MG.mjs.map} +0 -0
  101. /package/dist/lib/browser/{chunk-PMHCTMKT.mjs.map → chunk-B3EX52V3.mjs.map} +0 -0
  102. /package/dist/lib/browser/{intent-resolver-UJNDAIDZ.mjs.map → intent-resolver-5UXBTZAM.mjs.map} +0 -0
  103. /package/dist/lib/node/{ExplorerContainer-RJT54IOS.cjs.map → ExplorerContainer-2DQFUEG7.cjs.map} +0 -0
  104. /package/dist/lib/node/{chunk-YUY7P7R2.cjs.map → chunk-C4DXEIBU.cjs.map} +0 -0
  105. /package/dist/lib/node/{intent-resolver-XQV24IAA.cjs.map → intent-resolver-WDMZJTJ5.cjs.map} +0 -0
  106. /package/dist/lib/node-esm/{ExplorerContainer-TM3VIXVK.mjs.map → ExplorerContainer-RBGUFI5X.mjs.map} +0 -0
  107. /package/dist/lib/node-esm/{chunk-57K7ORAW.mjs.map → chunk-WJ6AML7W.mjs.map} +0 -0
  108. /package/dist/lib/node-esm/{intent-resolver-RZQ3EEOE.mjs.map → intent-resolver-KBRYGW6I.mjs.map} +0 -0
@@ -7,59 +7,26 @@ import '@dxos-theme';
7
7
  import { type Meta } from '@storybook/react';
8
8
  import React, { type FC, useEffect, useState } from 'react';
9
9
 
10
- import { create, makeRef } from '@dxos/live-object';
11
- import { TreeItemType, TreeType } from '@dxos/plugin-outliner/types';
10
+ import { TreeType, Tree as TreeModel } from '@dxos/plugin-outliner/types';
12
11
  import { faker } from '@dxos/random';
13
12
  import { useClient } from '@dxos/react-client';
14
13
  import { type ClientRepeatedComponentProps, ClientRepeater } from '@dxos/react-client/testing';
15
14
  import { withLayout, withTheme } from '@dxos/storybook-utils';
16
- import { range } from '@dxos/util';
17
15
 
18
16
  import { Tree, type TreeComponentProps } from './Tree';
19
17
 
20
18
  // TODO(burdon): Storybook for Graph/Tree/Plot (generics); incl. GraphModel.
21
19
  // TODO(burdon): Type for all Explorer components (Space, Object, Query, etc.) incl.
22
- // TODO(burdon): Factor out to gem?
23
20
 
24
21
  faker.seed(1);
25
22
 
26
- const makeTreeItems = <T extends number>(count: T, items: TreeItemType[] = []) => {
27
- return range(count, () => create(TreeItemType, { content: '', items: items.map((item) => makeRef(item)) }));
28
- };
29
-
30
23
  const Story: FC<ClientRepeatedComponentProps & { type?: TreeComponentProps<any>['variant'] }> = ({ type }) => {
31
24
  const client = useClient();
32
25
  const space = client.spaces.default;
33
26
  const [object, setObject] = useState<TreeType>();
34
27
  useEffect(() => {
35
28
  setTimeout(() => {
36
- const tree = create(TreeType, {
37
- root: makeRef(
38
- makeTreeItems(1, [
39
- ...makeTreeItems(7),
40
- ...makeTreeItems(1, [
41
- ...makeTreeItems(1),
42
- ...makeTreeItems(1, [
43
- ...makeTreeItems(3),
44
- ...makeTreeItems(1, makeTreeItems(2)),
45
- ...makeTreeItems(2),
46
- ...makeTreeItems(1, makeTreeItems(2)),
47
- ...makeTreeItems(2),
48
- ]),
49
- ...makeTreeItems(1),
50
- ]),
51
- ...makeTreeItems(2),
52
- ...makeTreeItems(1, [
53
- ...makeTreeItems(1),
54
- ...makeTreeItems(1, [...makeTreeItems(2), ...makeTreeItems(1, makeTreeItems(2))]),
55
- ...makeTreeItems(1),
56
- ]),
57
- ...makeTreeItems(2),
58
- ])[0],
59
- ),
60
- });
61
-
62
- space.db.add(tree);
29
+ const tree = space.db.add(TreeModel.create());
63
30
  setObject(tree);
64
31
  });
65
32
  }, []);
@@ -92,7 +59,7 @@ export const Edge = {
92
59
  const meta: Meta = {
93
60
  title: 'plugins/plugin-explorer/Tree',
94
61
  component: Tree,
95
- render: () => <ClientRepeater component={Story} types={[TreeType, TreeItemType]} createSpace />,
62
+ render: () => <ClientRepeater component={Story} types={[TreeType]} createSpace />,
96
63
  decorators: [withTheme, withLayout({ fullscreen: true })],
97
64
  parameters: {
98
65
  layout: 'fullscreen',
@@ -2,7 +2,8 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import type { GraphModel } from '@dxos/gem-spore';
5
+ // TODO(burdon): Convert to common/graph.
6
+ import { type GraphModel } from '@dxos/gem-spore';
6
7
 
7
8
  export type TreeNode = {
8
9
  id: string;
package/src/meta.ts CHANGED
@@ -6,7 +6,7 @@ import { type PluginMeta } from '@dxos/app-framework';
6
6
 
7
7
  export const EXPLORER_PLUGIN = 'dxos.org/plugin/explorer';
8
8
 
9
- export const meta = {
9
+ export const meta: PluginMeta = {
10
10
  id: EXPLORER_PLUGIN,
11
11
  name: 'Explorer',
12
12
  description: 'Install this plugin to view a hypergraph of all objects inside of your Space.',
@@ -14,4 +14,4 @@ export const meta = {
14
14
  source: 'https://github.com/dxos/dxos/tree/main/packages/plugins/experimental/plugin-explorer',
15
15
  tags: ['experimental'],
16
16
  screenshots: ['https://dxos.network/plugin-details-explorer-dark.png'],
17
- } satisfies PluginMeta;
17
+ };
@@ -14,7 +14,7 @@ export default [
14
14
  [EXPLORER_PLUGIN]: {
15
15
  'plugin name': 'Explorer',
16
16
  'object title label': 'Title',
17
- 'object title placeholder': 'New explorer',
17
+ 'object placeholder': 'New explorer',
18
18
  'create object label': 'Create explorer',
19
19
  },
20
20
  },
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/meta.ts"],
4
- "sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport { type PluginMeta } from '@dxos/app-framework';\n\nexport const EXPLORER_PLUGIN = 'dxos.org/plugin/explorer';\n\nexport const meta = {\n id: EXPLORER_PLUGIN,\n name: 'Explorer',\n description: 'Install this plugin to view a hypergraph of all objects inside of your Space.',\n icon: 'ph--graph--regular',\n source: 'https://github.com/dxos/dxos/tree/main/packages/plugins/experimental/plugin-explorer',\n tags: ['experimental'],\n screenshots: ['https://dxos.network/plugin-details-explorer-dark.png'],\n} satisfies PluginMeta;\n"],
5
- "mappings": ";AAMO,IAAMA,kBAAkB;AAExB,IAAMC,OAAO;EAClBC,IAAIF;EACJG,MAAM;EACNC,aAAa;EACbC,MAAM;EACNC,QAAQ;EACRC,MAAM;IAAC;;EACPC,aAAa;IAAC;;AAChB;",
6
- "names": ["EXPLORER_PLUGIN", "meta", "id", "name", "description", "icon", "source", "tags", "screenshots"]
7
- }
@@ -1,546 +0,0 @@
1
- // packages/plugins/experimental/plugin-explorer/src/components/Graph/graph-model.ts
2
- import { getSchema, getSchemaDXN, AST, ReferenceAnnotationId, SchemaValidator, StoredSchema } from "@dxos/echo-schema";
3
- import { GraphModel } from "@dxos/gem-spore";
4
- import { log } from "@dxos/log";
5
- import { CollectionType } from "@dxos/plugin-space/types";
6
- import { Filter } from "@dxos/react-client/echo";
7
- var __dxlog_file = "/home/runner/work/dxos/dxos/packages/plugins/experimental/plugin-explorer/src/components/Graph/graph-model.ts";
8
- var SpaceGraphModel = class extends GraphModel {
9
- constructor(_options = {}) {
10
- super();
11
- this._options = _options;
12
- this._graph = {
13
- nodes: [],
14
- links: []
15
- };
16
- }
17
- get graph() {
18
- return this._graph;
19
- }
20
- get objects() {
21
- return this._objects ?? [];
22
- }
23
- // TODO(burdon): Alternative diagram types:
24
- // - https://observablehq.com/@d3/radial-tree/2
25
- // - https://observablehq.com/@d3/disjoint-force-directed-graph/2
26
- // - https://observablehq.com/@mbostock/tadpoles
27
- // - https://observablehq.com/@d3/psr-b1919-21
28
- // - https://vasturiano.github.io/react-force-graph/example/basic (3D)
29
- async open(space, objectId) {
30
- if (!this._schemaSubscription) {
31
- const schemaaQuery = space.db.schemaRegistry.query({});
32
- const schemas = await schemaaQuery.run();
33
- const onSchemaUpdate = ({ results }) => this._schema = results;
34
- this._schemaSubscription = schemaaQuery.subscribe(onSchemaUpdate);
35
- onSchemaUpdate({
36
- results: schemas
37
- });
38
- this._objectsSubscription = space.db.query(Filter.not(Filter.or(Filter.schema(StoredSchema), Filter.schema(CollectionType)))).subscribe(({ objects }) => {
39
- this._objects = objects;
40
- const currentNodes = this._graph.nodes;
41
- this._graph.nodes = [];
42
- this._graph.links = [];
43
- const addSchema = (typename) => {
44
- const current = currentNodes.find((node) => node.id === typename);
45
- if (typename) {
46
- this._graph.nodes.push({
47
- ...current,
48
- id: typename,
49
- type: "schema",
50
- data: {
51
- typename
52
- }
53
- });
54
- }
55
- };
56
- space.db.graph.schemaRegistry.schemas.forEach((schema) => {
57
- const typename = getSchemaDXN(schema)?.toTypename();
58
- if (typename) {
59
- addSchema(typename);
60
- }
61
- });
62
- this._schema?.forEach((schema) => {
63
- const typename = getSchemaDXN(schema)?.toTypename();
64
- if (typename) {
65
- addSchema(typename);
66
- }
67
- });
68
- this._objects.forEach((object) => {
69
- const schema = getSchema(object);
70
- if (schema) {
71
- const typename = getSchemaDXN(schema)?.toTypename();
72
- if (typename) {
73
- const current = currentNodes.find((node) => node.id === object.id);
74
- this._graph.nodes.push({
75
- ...current,
76
- id: object.id,
77
- type: "object",
78
- data: {
79
- typename,
80
- object
81
- }
82
- });
83
- const schemaNode = this._graph.nodes.find((node) => node.type === "schema" && node.data.typename === typename);
84
- if (schemaNode) {
85
- this._graph.links.push({
86
- id: `${object.id}-${schemaNode.id}`,
87
- source: object.id,
88
- target: schemaNode.id
89
- });
90
- } else {
91
- log.info("schema node not found", {
92
- typename
93
- }, {
94
- F: __dxlog_file,
95
- L: 145,
96
- S: this,
97
- C: (f, a) => f(...a)
98
- });
99
- }
100
- AST.getPropertySignatures(schema.ast).forEach((prop) => {
101
- if (!SchemaValidator.hasTypeAnnotation(schema, prop.name.toString(), ReferenceAnnotationId)) {
102
- return;
103
- }
104
- const value = object[String(prop.name)];
105
- if (value) {
106
- const refs = Array.isArray(value) ? value : [
107
- value
108
- ];
109
- for (const ref of refs) {
110
- if (objects.findIndex((obj) => obj.id === ref.id) !== -1) {
111
- this._graph.links.push({
112
- id: `${object.id}-${String(prop.name)}-${ref.id}`,
113
- source: object.id,
114
- target: ref.id
115
- });
116
- }
117
- }
118
- }
119
- });
120
- }
121
- }
122
- });
123
- this.triggerUpdate();
124
- }, {
125
- fire: true
126
- });
127
- }
128
- this.setSelected(objectId);
129
- return this;
130
- }
131
- close() {
132
- this._schemaSubscription?.();
133
- this._schemaSubscription = void 0;
134
- this._objectsSubscription?.();
135
- this._objectsSubscription = void 0;
136
- return this;
137
- }
138
- };
139
-
140
- // packages/plugins/experimental/plugin-explorer/src/components/Tree/Tree.tsx
141
- import React2, { useEffect as useEffect2, useState as useState2 } from "react";
142
- import { useResizeDetector as useResizeDetector2 } from "react-resize-detector";
143
- import { createSvgContext as createSvgContext2, SVG as SVG2, SVGRoot as SVGRoot2 } from "@dxos/gem-core";
144
- import { useAsyncState as useAsyncState2 } from "@dxos/react-ui";
145
-
146
- // packages/plugins/experimental/plugin-explorer/src/components/Tree/layout/HierarchicalEdgeBundling.ts
147
- import * as d3 from "d3";
148
- var HierarchicalEdgeBundling = (s, data, options) => {
149
- const svg = d3.select(s);
150
- svg.selectAll("*").remove();
151
- const { radius = 600, padding = 100, slots: slots2 } = options;
152
- const root = d3.hierarchy(flatten(data));
153
- const tree3 = d3.cluster().size([
154
- 2 * Math.PI,
155
- radius - padding
156
- ]);
157
- const layout = tree3(addLinks(root));
158
- const node = svg.append("g").selectAll().data(layout.leaves()).join("g").attr("transform", (d) => `rotate(${d.x * (180 / Math.PI) - 90}) translate(${d.y},0)`).append("text").attr("class", slots2?.text ?? "").attr("dy", "0.31em").attr("x", (d) => d.x < Math.PI ? 6 : -6).attr("text-anchor", (d) => d.x < Math.PI ? "start" : "end").attr("transform", (d) => d.x >= Math.PI ? "rotate(180)" : null).call((text) => text.text((d) => d.data.id.slice(0, 8)));
159
- const line = d3.lineRadial().curve(d3.curveBundle.beta(0.85)).radius((d) => d.y).angle((d) => d.x);
160
- const links = svg.append("g").selectAll().data(layout.leaves().flatMap((leaf) => leaf.outgoing)).join("path").style("mix-blend-mode", "multiply").attr("class", slots2?.path ?? "").attr("d", ([i, o]) => {
161
- return line(i.path(o));
162
- }).each(function(d) {
163
- d.path = this;
164
- });
165
- };
166
- var addLinks = (root) => {
167
- const nodes = new Map(root.descendants().map((d) => [
168
- d.data.id,
169
- d
170
- ]));
171
- const parents = root.descendants().reduce((map, d) => {
172
- if (d.children?.length) {
173
- map.set(d.data.id, d);
174
- }
175
- return map;
176
- }, /* @__PURE__ */ new Map());
177
- for (const d of root.leaves()) {
178
- const parent = parents.get(d.data.id);
179
- if (parent) {
180
- d.outgoing = parent.data.children?.slice(1).map((child) => {
181
- return [
182
- d,
183
- nodes.get(child.id)
184
- ];
185
- }) ?? [];
186
- } else {
187
- d.outgoing = [];
188
- }
189
- }
190
- return root;
191
- };
192
- var flatten = (node) => {
193
- const clone = {
194
- id: node.id
195
- };
196
- if (node.children?.length) {
197
- const children = node.children.map((child) => flatten(child));
198
- clone.children = [
199
- {
200
- id: node.id
201
- },
202
- ...children
203
- ];
204
- }
205
- return clone;
206
- };
207
- var HierarchicalEdgeBundling_default = HierarchicalEdgeBundling;
208
-
209
- // packages/plugins/experimental/plugin-explorer/src/components/Tree/layout/RadialTree.ts
210
- import * as d32 from "d3";
211
- var RadialTree = (s, data, options) => {
212
- const svg = d32.select(s);
213
- svg.selectAll("*").remove();
214
- const { label, radius = 400, r = 4, slots: slots2 } = options;
215
- const arc = 2 * Math.PI;
216
- const root = d32.hierarchy(data);
217
- const descendants = root.descendants();
218
- const getLabel = label === null ? null : descendants.map((d) => label(d.data));
219
- const layout = d32.tree().size([
220
- arc,
221
- radius
222
- ]).separation((a, b) => (a.parent === b.parent ? 1 : 2) / a.depth);
223
- layout(root);
224
- svg.append("g").selectAll("path").data(root.links()).join("path").attr("class", slots2?.path ?? "").attr("d", d32.linkRadial().angle((d) => d.x + Math.PI / 2).radius((d) => d.y));
225
- const node = svg.append("g").selectAll("a").data(root.descendants()).join("a").attr("transform", (d) => `rotate(${d.x * 180 / Math.PI}) translate(${d.y},0)`);
226
- node.append("circle").attr("class", slots2?.node ?? "").attr("r", r);
227
- if (getLabel) {
228
- node.append("text").attr("transform", (d) => `rotate(${d.x >= Math.PI ? 180 : 0})`).attr("dy", "0.32em").attr("x", (d) => d.x < Math.PI === !d.children ? 6 : -6).attr("text-anchor", (d) => d.x < Math.PI === !d.children ? "start" : "end").attr("class", slots2?.text ?? "").text((d, i) => getLabel[i]);
229
- }
230
- return svg.node();
231
- };
232
- var RadialTree_default = RadialTree;
233
-
234
- // packages/plugins/experimental/plugin-explorer/src/components/Tree/layout/TidyTree.ts
235
- import * as d33 from "d3";
236
- var TidyTree = (s, data, options) => {
237
- const svg = d33.select(s);
238
- svg.selectAll("*").remove();
239
- const { label, width, height, r = 4, padding = 4, margin = 60, slots: slots2 } = options;
240
- const root = d33.hierarchy(data);
241
- const descendants = root.descendants();
242
- const getLabel = label == null ? null : descendants.map((d) => label(d.data));
243
- const dx = 16;
244
- const dy = width / (root.height + padding);
245
- const layout = d33.tree().nodeSize([
246
- dx,
247
- dy
248
- ]);
249
- layout(root);
250
- let x0 = Infinity;
251
- let x1 = -x0;
252
- let y0 = Infinity;
253
- let y1 = -y0;
254
- root.each((d) => {
255
- if (d.x > x1) {
256
- x1 = d.x;
257
- }
258
- if (d.x < x0) {
259
- x0 = d.x;
260
- }
261
- if (d.y > y1) {
262
- y1 = d.y;
263
- }
264
- if (d.y < y0) {
265
- y0 = d.y;
266
- }
267
- });
268
- const sx = Math.min(2, Math.max(1, (height - margin * 2) / (x1 - x0)));
269
- const oy = -(width - (y1 - y0)) / 2;
270
- svg.append("g").selectAll("path").data(root.links()).join("path").attr("class", slots2?.path ?? "").attr("d", d33.link(d33.curveBumpX).x((d) => d.y + oy).y((d) => d.x * sx));
271
- const node = svg.append("g").selectAll("a").data(root.descendants()).join("a").attr("transform", (d) => `translate(${d.y + oy},${d.x * sx})`);
272
- node.append("circle").attr("class", slots2?.node ?? "").attr("r", r);
273
- if (getLabel) {
274
- node.append("text").attr("dy", "0.32em").attr("x", (d) => d.children ? -6 : 6).attr("text-anchor", (d) => d.children ? "end" : "start").attr("class", slots2?.text ?? "").text((d, i) => getLabel[i]);
275
- }
276
- };
277
- var TidyTree_default = TidyTree;
278
-
279
- // packages/plugins/experimental/plugin-explorer/src/components/Tree/types.ts
280
- var mapGraphToTreeData = (model, maxDepth = 8) => {
281
- const mapNode = (node, depth = 0) => {
282
- const treeNode = {
283
- id: model.idAccessor(node),
284
- label: model.idAccessor(node).slice(0, 8)
285
- };
286
- const links = model.graph.links.filter((link2) => link2.source === treeNode.id);
287
- if (depth < maxDepth) {
288
- treeNode.children = links.map((link2) => mapNode(model.graph.nodes.find((node2) => model.idAccessor(node2) === link2.target), depth + 1));
289
- }
290
- return treeNode;
291
- };
292
- let data;
293
- if (model.selected) {
294
- const node = model.graph.nodes.find((node2) => model.idAccessor(node2) === model.selected);
295
- if (node) {
296
- data = mapNode(node);
297
- }
298
- }
299
- return data;
300
- };
301
-
302
- // packages/plugins/experimental/plugin-explorer/src/components/Graph/Graph.tsx
303
- import { forceLink, forceManyBody } from "d3";
304
- import ForceGraph from "force-graph";
305
- import React, { useEffect, useMemo, useRef, useState } from "react";
306
- import { useResizeDetector } from "react-resize-detector";
307
- import { getTypename } from "@dxos/client/echo";
308
- import { createSvgContext, defaultGridStyles, Grid, SVG, SVGRoot, Zoom } from "@dxos/gem-core";
309
- import { defaultStyles, Graph as GraphComponent, GraphForceProjector, Markers } from "@dxos/gem-spore";
310
- import { filterObjectsSync } from "@dxos/plugin-search";
311
- import { useAsyncState, useThemeContext } from "@dxos/react-ui";
312
- import { mx } from "@dxos/react-ui-theme";
313
- import "@dxos/gem-spore/styles";
314
- var slots = {};
315
- var colors = [
316
- "[&>circle]:!fill-black-300 [&>circle]:!stroke-black-600",
317
- "[&>circle]:!fill-slate-300 [&>circle]:!stroke-slate-600",
318
- "[&>circle]:!fill-green-300 [&>circle]:!stroke-green-600",
319
- "[&>circle]:!fill-sky-300 [&>circle]:!stroke-sky-600",
320
- "[&>circle]:!fill-cyan-300 [&>circle]:!stroke-cyan-600",
321
- "[&>circle]:!fill-rose-300 [&>circle]:!stroke-rose-600",
322
- "[&>circle]:!fill-purple-300 [&>circle]:!stroke-purple-600",
323
- "[&>circle]:!fill-orange-300 [&>circle]:!stroke-orange-600",
324
- "[&>circle]:!fill-teal-300 [&>circle]:!stroke-teal-600",
325
- "[&>circle]:!fill-indigo-300 [&>circle]:!stroke-indigo-600"
326
- ];
327
- var Graph = ({ space, match, grid, svg }) => {
328
- const { themeMode } = useThemeContext();
329
- const [selected, setSelected] = useState();
330
- const [model] = useAsyncState(async () => space ? new SpaceGraphModel({
331
- schema: true
332
- }).open(space) : void 0, [
333
- space
334
- ]);
335
- const context = createSvgContext();
336
- const projector = useMemo(() => new GraphForceProjector(context, {
337
- forces: {
338
- manyBody: {
339
- strength: -100
340
- },
341
- link: {
342
- distance: 100
343
- },
344
- radial: {
345
- radius: 150,
346
- strength: 0.05
347
- }
348
- },
349
- attributes: {
350
- radius: (node) => node.data?.type === "schema" ? 12 : 8
351
- }
352
- }), []);
353
- const filteredRef = useRef();
354
- filteredRef.current = filterObjectsSync(model?.objects ?? [], match);
355
- useEffect(() => {
356
- void projector.start();
357
- }, [
358
- match
359
- ]);
360
- const [colorMap] = useState(/* @__PURE__ */ new Map());
361
- const { ref, width, height } = useResizeDetector();
362
- const rootRef = useRef(null);
363
- const forceGraph = useRef();
364
- useEffect(() => {
365
- if (rootRef.current) {
366
- forceGraph.current = new ForceGraph(rootRef.current).nodeRelSize(6).nodeLabel((node) => {
367
- if (node.type === "schema") {
368
- return node.data.typename;
369
- }
370
- return node.id;
371
- }).nodeAutoColorBy((node) => node.type === "schema" ? "schema" : node.data.typename).linkColor(() => "rgba(255,255,255,0.25)");
372
- }
373
- return () => {
374
- forceGraph.current?.pauseAnimation().graphData({
375
- nodes: [],
376
- links: []
377
- });
378
- forceGraph.current = void 0;
379
- };
380
- }, []);
381
- useEffect(() => {
382
- if (forceGraph.current && width && height && model) {
383
- forceGraph.current.pauseAnimation().width(width).height(height).onEngineStop(() => {
384
- forceGraph.current?.zoomToFit(400, 40);
385
- }).d3Force("link", forceLink().distance(160).strength(0.5)).d3Force("charge", forceManyBody().strength(-30)).warmupTicks(100).graphData(model.graph).resumeAnimation();
386
- }
387
- }, [
388
- model,
389
- width,
390
- height
391
- ]);
392
- const handleZoomToFit = () => {
393
- forceGraph.current?.zoomToFit(400, 40);
394
- };
395
- if (!svg) {
396
- return /* @__PURE__ */ React.createElement("div", {
397
- ref,
398
- className: "relative grow",
399
- onClick: handleZoomToFit
400
- }, /* @__PURE__ */ React.createElement("div", {
401
- ref: rootRef,
402
- className: "absolute inset-0"
403
- }));
404
- }
405
- if (selected) {
406
- return /* @__PURE__ */ React.createElement(Tree, {
407
- space,
408
- selected,
409
- variant: "tidy",
410
- onNodeClick: () => setSelected(void 0)
411
- });
412
- }
413
- return /* @__PURE__ */ React.createElement(SVGRoot, {
414
- context
415
- }, /* @__PURE__ */ React.createElement(SVG, {
416
- className: mx(defaultStyles, slots?.root?.className)
417
- }, /* @__PURE__ */ React.createElement(Markers, {
418
- arrowSize: 6
419
- }), grid && /* @__PURE__ */ React.createElement(Grid, {
420
- className: slots?.grid?.className ?? defaultGridStyles(themeMode)
421
- }), /* @__PURE__ */ React.createElement(Zoom, {
422
- extent: [
423
- 1 / 2,
424
- 4
425
- ]
426
- }, /* @__PURE__ */ React.createElement(GraphComponent, {
427
- model,
428
- projector,
429
- drag: true,
430
- arrows: true,
431
- onSelect: (node) => setSelected(node?.data?.id),
432
- labels: {
433
- text: (node) => {
434
- if (filteredRef.current?.length && !filteredRef.current.some((object) => object.id === node.data?.id)) {
435
- return void 0;
436
- }
437
- return node.data?.label ?? node.data?.title ?? node.data?.name ?? node.data?.id.slice(0, 8);
438
- }
439
- },
440
- attributes: {
441
- node: (node) => {
442
- let className;
443
- if (node.data) {
444
- const { object } = node.data;
445
- if (object) {
446
- const typename = getTypename(object);
447
- if (typename) {
448
- className = colorMap.get(typename);
449
- if (!className) {
450
- className = colors[colorMap.size % colors.length];
451
- colorMap.set(typename, className);
452
- }
453
- }
454
- }
455
- }
456
- const selected2 = filteredRef.current?.some((object) => object.id === node.data?.id);
457
- const blur = !selected2 && !!filteredRef.current?.length;
458
- return {
459
- class: mx(className, blur && "opacity-70")
460
- };
461
- },
462
- link: () => ({
463
- class: "[&>path]:!stroke-neutral-300 dark:[&>path]:!stroke-neutral-700"
464
- })
465
- }
466
- }))));
467
- };
468
-
469
- // packages/plugins/experimental/plugin-explorer/src/components/Tree/Tree.tsx
470
- var defaultTreeLayoutSlots = {
471
- node: "fill-blue-600",
472
- path: "fill-none stroke-blue-400 stroke-[0.5px]",
473
- text: "stroke-[0.5px] stroke-neutral-700 text-xs"
474
- };
475
- var renderers = /* @__PURE__ */ new Map([
476
- [
477
- "tidy",
478
- TidyTree_default
479
- ],
480
- [
481
- "radial",
482
- RadialTree_default
483
- ],
484
- [
485
- "edge",
486
- HierarchicalEdgeBundling_default
487
- ]
488
- ]);
489
- var Tree = ({ space, selected, variant = "tidy", onNodeClick }) => {
490
- const [model] = useAsyncState2(async () => space ? new SpaceGraphModel().open(space, selected) : void 0, [
491
- space,
492
- selected
493
- ]);
494
- const [tree3, setTree] = useState2();
495
- useEffect2(() => {
496
- return model?.subscribe(() => {
497
- const tree4 = mapGraphToTreeData(model);
498
- setTree(tree4);
499
- }, true);
500
- }, [
501
- model
502
- ]);
503
- const context = createSvgContext2();
504
- const { ref, width = 0, height = 0 } = useResizeDetector2();
505
- useEffect2(() => {
506
- if (width && height) {
507
- const size = Math.min(width, height);
508
- const radius = size * 0.4;
509
- const options = {
510
- // TODO(burdon): Type.
511
- label: (d) => d.label ?? d.id,
512
- width,
513
- height,
514
- radius,
515
- marginLeft: (width - radius * 2) / 2,
516
- marginRight: (width - radius * 2) / 2,
517
- marginTop: (height - radius * 2) / 2,
518
- marginBottom: (height - radius * 2) / 2,
519
- slots: defaultTreeLayoutSlots
520
- };
521
- if (tree3) {
522
- const renderer = renderers.get(variant);
523
- renderer?.(context.ref.current, tree3, options);
524
- }
525
- }
526
- }, [
527
- tree3,
528
- width,
529
- height
530
- ]);
531
- return /* @__PURE__ */ React2.createElement("div", {
532
- ref,
533
- className: "flex grow overflow-hidden",
534
- onClick: () => onNodeClick?.()
535
- }, /* @__PURE__ */ React2.createElement(SVGRoot2, {
536
- context
537
- }, /* @__PURE__ */ React2.createElement(SVG2, null)));
538
- };
539
-
540
- export {
541
- SpaceGraphModel,
542
- defaultTreeLayoutSlots,
543
- Tree,
544
- Graph
545
- };
546
- //# sourceMappingURL=chunk-YQL7YE6N.mjs.map