@dxos/plugin-explorer 0.6.11 → 0.6.12-main.5cc132e

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.
@@ -0,0 +1,27 @@
1
+ import {
2
+ Graph
3
+ } from "./chunk-XKITKIPQ.mjs";
4
+
5
+ // packages/plugins/experimental/plugin-explorer/src/components/ExplorerArticle.tsx
6
+ import React from "react";
7
+ import { useGlobalSearch } from "@dxos/plugin-search";
8
+ import { getSpace } from "@dxos/react-client/echo";
9
+ var ExplorerArticle = ({ view }) => {
10
+ const space = getSpace(view);
11
+ const { match } = useGlobalSearch();
12
+ if (!space) {
13
+ return null;
14
+ }
15
+ return /* @__PURE__ */ React.createElement("div", {
16
+ role: "none",
17
+ className: "row-span-2 overflow-auto"
18
+ }, /* @__PURE__ */ React.createElement(Graph, {
19
+ space,
20
+ match
21
+ }));
22
+ };
23
+ var ExplorerArticle_default = ExplorerArticle;
24
+ export {
25
+ ExplorerArticle_default as default
26
+ };
27
+ //# sourceMappingURL=ExplorerArticle-2LF7QANN.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/components/ExplorerArticle.tsx"],
4
+ "sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport React from 'react';\n\nimport { useGlobalSearch } from '@dxos/plugin-search';\nimport { getSpace } from '@dxos/react-client/echo';\n\nimport { Graph } from './Graph';\nimport { type ViewType } from '../types';\n\nconst ExplorerArticle = ({ view }: { view: ViewType }) => {\n const space = getSpace(view);\n const { match } = useGlobalSearch();\n\n if (!space) {\n return null;\n }\n\n return (\n <div role='none' className='row-span-2 overflow-auto'>\n <Graph space={space} match={match} />\n </div>\n );\n};\n\nexport default ExplorerArticle;\n"],
5
+ "mappings": ";;;;;AAIA,OAAOA,WAAW;AAElB,SAASC,uBAAuB;AAChC,SAASC,gBAAgB;AAKzB,IAAMC,kBAAkB,CAAC,EAAEC,KAAI,MAAsB;AACnD,QAAMC,QAAQC,SAASF,IAAAA;AACvB,QAAM,EAAEG,MAAK,IAAKC,gBAAAA;AAElB,MAAI,CAACH,OAAO;AACV,WAAO;EACT;AAEA,SACE,sBAAA,cAACI,OAAAA;IAAIC,MAAK;IAAOC,WAAU;KACzB,sBAAA,cAACC,OAAAA;IAAMP;IAAcE;;AAG3B;AAEA,IAAA,0BAAeJ;",
6
+ "names": ["React", "useGlobalSearch", "getSpace", "ExplorerArticle", "view", "space", "getSpace", "match", "useGlobalSearch", "div", "role", "className", "Graph"]
7
+ }
@@ -0,0 +1,33 @@
1
+ import {
2
+ Graph
3
+ } from "./chunk-XKITKIPQ.mjs";
4
+
5
+ // packages/plugins/experimental/plugin-explorer/src/components/ExplorerMain.tsx
6
+ import React from "react";
7
+ import { useGlobalSearch } from "@dxos/plugin-search";
8
+ import { getSpace } from "@dxos/react-client/echo";
9
+ import { Main } from "@dxos/react-ui";
10
+ import { baseSurface, topbarBlockPaddingStart, fixedInsetFlexLayout, bottombarBlockPaddingEnd } from "@dxos/react-ui-theme";
11
+ var ExplorerMain = ({ view }) => {
12
+ const space = getSpace(view);
13
+ const { match } = useGlobalSearch();
14
+ if (!space) {
15
+ return null;
16
+ }
17
+ return /* @__PURE__ */ React.createElement(Main.Content, {
18
+ classNames: [
19
+ baseSurface,
20
+ fixedInsetFlexLayout,
21
+ topbarBlockPaddingStart,
22
+ bottombarBlockPaddingEnd
23
+ ]
24
+ }, /* @__PURE__ */ React.createElement(Graph, {
25
+ space,
26
+ match
27
+ }));
28
+ };
29
+ var ExplorerMain_default = ExplorerMain;
30
+ export {
31
+ ExplorerMain_default as default
32
+ };
33
+ //# sourceMappingURL=ExplorerMain-K6Z6UVZR.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/components/ExplorerMain.tsx"],
4
+ "sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport React from 'react';\n\nimport { useGlobalSearch } from '@dxos/plugin-search';\nimport { getSpace } from '@dxos/react-client/echo';\nimport { Main } from '@dxos/react-ui';\nimport {\n baseSurface,\n topbarBlockPaddingStart,\n fixedInsetFlexLayout,\n bottombarBlockPaddingEnd,\n} from '@dxos/react-ui-theme';\n\nimport { Graph } from './Graph';\nimport { type ViewType } from '../types';\n\nconst ExplorerMain = ({ view }: { view: ViewType }) => {\n const space = getSpace(view);\n const { match } = useGlobalSearch();\n if (!space) {\n return null;\n }\n\n return (\n <Main.Content classNames={[baseSurface, fixedInsetFlexLayout, topbarBlockPaddingStart, bottombarBlockPaddingEnd]}>\n <Graph space={space} match={match} />\n </Main.Content>\n );\n};\n\nexport default ExplorerMain;\n"],
5
+ "mappings": ";;;;;AAIA,OAAOA,WAAW;AAElB,SAASC,uBAAuB;AAChC,SAASC,gBAAgB;AACzB,SAASC,YAAY;AACrB,SACEC,aACAC,yBACAC,sBACAC,gCACK;AAKP,IAAMC,eAAe,CAAC,EAAEC,KAAI,MAAsB;AAChD,QAAMC,QAAQC,SAASF,IAAAA;AACvB,QAAM,EAAEG,MAAK,IAAKC,gBAAAA;AAClB,MAAI,CAACH,OAAO;AACV,WAAO;EACT;AAEA,SACE,sBAAA,cAACI,KAAKC,SAAO;IAACC,YAAY;MAACC;MAAaC;MAAsBC;MAAyBC;;KACrF,sBAAA,cAACC,OAAAA;IAAMX;IAAcE;;AAG3B;AAEA,IAAA,uBAAeJ;",
6
+ "names": ["React", "useGlobalSearch", "getSpace", "Main", "baseSurface", "topbarBlockPaddingStart", "fixedInsetFlexLayout", "bottombarBlockPaddingEnd", "ExplorerMain", "view", "space", "getSpace", "match", "useGlobalSearch", "Main", "Content", "classNames", "baseSurface", "fixedInsetFlexLayout", "topbarBlockPaddingStart", "bottombarBlockPaddingEnd", "Graph"]
7
+ }
@@ -0,0 +1,27 @@
1
+ import {
2
+ EXPLORER_PLUGIN
3
+ } from "./chunk-TL6ADY3P.mjs";
4
+
5
+ // packages/plugins/experimental/plugin-explorer/src/types/view.ts
6
+ import { S, TypedObject } from "@dxos/echo-schema";
7
+ var ViewType = class extends TypedObject({
8
+ typename: "dxos.org/type/View",
9
+ version: "0.1.0"
10
+ })({
11
+ name: S.optional(S.String),
12
+ type: S.String
13
+ }) {
14
+ };
15
+
16
+ // packages/plugins/experimental/plugin-explorer/src/types/types.ts
17
+ var EXPLORER_ACTION = `${EXPLORER_PLUGIN}/action`;
18
+ var ExplorerAction;
19
+ (function(ExplorerAction2) {
20
+ ExplorerAction2[ExplorerAction2["CREATE"] = `${EXPLORER_ACTION}/create`] = "CREATE";
21
+ })(ExplorerAction || (ExplorerAction = {}));
22
+
23
+ export {
24
+ ViewType,
25
+ ExplorerAction
26
+ };
27
+ //# sourceMappingURL=chunk-JIDPF2GF.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/types/view.ts", "../../../src/types/types.ts"],
4
+ "sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nimport { S, TypedObject } from '@dxos/echo-schema';\n\n// TODO(burdon): Standardize views?\nexport class ViewType extends TypedObject({ typename: 'dxos.org/type/View', version: '0.1.0' })({\n name: S.optional(S.String),\n type: S.String,\n}) {}\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport type {\n GraphBuilderProvides,\n IntentResolverProvides,\n MetadataRecordsProvides,\n SurfaceProvides,\n TranslationsProvides,\n} from '@dxos/app-framework';\nimport { type SchemaProvides } from '@dxos/plugin-client';\n\nimport { EXPLORER_PLUGIN } from '../meta';\n\nconst EXPLORER_ACTION = `${EXPLORER_PLUGIN}/action`;\n\nexport enum ExplorerAction {\n CREATE = `${EXPLORER_ACTION}/create`,\n}\n\nexport type ExplorerPluginProvides = SurfaceProvides &\n IntentResolverProvides &\n GraphBuilderProvides &\n MetadataRecordsProvides &\n TranslationsProvides &\n SchemaProvides;\n"],
5
+ "mappings": ";;;;;AAIA,SAASA,GAAGC,mBAAmB;AAGxB,IAAMC,WAAN,cAAuBC,YAAY;EAAEC,UAAU;EAAsBC,SAAS;AAAQ,CAAA,EAAG;EAC9FC,MAAMC,EAAEC,SAASD,EAAEE,MAAM;EACzBC,MAAMH,EAAEE;AACV,CAAA,EAAA;AAAI;;;ACKJ,IAAME,kBAAkB,GAAGC,eAAAA;;UAEfC,iBAAAA;8CACD,GAAGF,eAAAA,SAAwB,IAAA;GAD1BE,mBAAAA,iBAAAA,CAAAA,EAAAA;",
6
+ "names": ["S", "TypedObject", "ViewType", "TypedObject", "typename", "version", "name", "S", "optional", "String", "type", "EXPLORER_ACTION", "EXPLORER_PLUGIN", "ExplorerAction"]
7
+ }
@@ -0,0 +1,21 @@
1
+ // packages/plugins/experimental/plugin-explorer/src/meta.tsx
2
+ import { Graph } from "@phosphor-icons/react";
3
+ import React from "react";
4
+ import { pluginMeta } from "@dxos/app-framework";
5
+ var EXPLORER_PLUGIN = "dxos.org/plugin/explorer";
6
+ var meta_default = pluginMeta({
7
+ id: EXPLORER_PLUGIN,
8
+ name: "Explorer",
9
+ description: "Explore the ECHO hypergraph.",
10
+ tags: [
11
+ "experimental"
12
+ ],
13
+ iconComponent: (props) => /* @__PURE__ */ React.createElement(Graph, props),
14
+ iconSymbol: "ph--graph--regular"
15
+ });
16
+
17
+ export {
18
+ EXPLORER_PLUGIN,
19
+ meta_default
20
+ };
21
+ //# sourceMappingURL=chunk-TL6ADY3P.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/meta.tsx"],
4
+ "sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport { Graph, type IconProps } from '@phosphor-icons/react';\nimport React from 'react';\n\nimport { pluginMeta } from '@dxos/app-framework';\n\nexport const EXPLORER_PLUGIN = 'dxos.org/plugin/explorer';\n\nexport default pluginMeta({\n id: EXPLORER_PLUGIN,\n name: 'Explorer',\n description: 'Explore the ECHO hypergraph.',\n tags: ['experimental'],\n iconComponent: (props: IconProps) => <Graph {...props} />,\n iconSymbol: 'ph--graph--regular',\n});\n"],
5
+ "mappings": ";AAIA,SAASA,aAA6B;AACtC,OAAOC,WAAW;AAElB,SAASC,kBAAkB;AAEpB,IAAMC,kBAAkB;AAE/B,IAAA,eAAeC,WAAW;EACxBC,IAAIF;EACJG,MAAM;EACNC,aAAa;EACbC,MAAM;IAAC;;EACPC,eAAe,CAACC,UAAqB,sBAAA,cAACC,OAAUD,KAAAA;EAChDE,YAAY;AACd,CAAA;",
6
+ "names": ["Graph", "React", "pluginMeta", "EXPLORER_PLUGIN", "pluginMeta", "id", "name", "description", "tags", "iconComponent", "props", "Graph", "iconSymbol"]
7
+ }
@@ -0,0 +1,474 @@
1
+ // packages/plugins/experimental/plugin-explorer/src/components/Graph/graph-model.ts
2
+ import { AST, DynamicSchema, getSchema, getType, 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
+ var __dxlog_file = "/home/runner/work/dxos/dxos/packages/plugins/experimental/plugin-explorer/src/components/Graph/graph-model.ts";
7
+ var SpaceGraphModel = class extends GraphModel {
8
+ constructor(_options = {}) {
9
+ super();
10
+ this._options = _options;
11
+ this._graph = {
12
+ nodes: [],
13
+ links: []
14
+ };
15
+ }
16
+ get graph() {
17
+ return this._graph;
18
+ }
19
+ get objects() {
20
+ return this._objects ?? [];
21
+ }
22
+ open(space, objectId) {
23
+ if (!this._subscription) {
24
+ const query = space.db.query((object) => !(object instanceof CollectionType));
25
+ this._subscription = query.subscribe(({ objects }) => {
26
+ this._objects = objects;
27
+ this._graph.nodes = objects.map((object) => {
28
+ if (object instanceof StoredSchema) {
29
+ const effectSchema = space.db.schema.getSchemaById(object.id);
30
+ return {
31
+ type: "schema",
32
+ id: object.id,
33
+ schema: effectSchema.schema
34
+ };
35
+ }
36
+ return {
37
+ type: "echo-object",
38
+ id: object.id,
39
+ object
40
+ };
41
+ });
42
+ this._graph.links = objects.reduce((links, object) => {
43
+ const objectSchema = getSchema(object);
44
+ const typename = getType(object)?.objectId;
45
+ if (objectSchema == null || typename == null) {
46
+ log.info("no schema for object:", {
47
+ id: object.id.slice(0, 8)
48
+ }, {
49
+ F: __dxlog_file,
50
+ L: 81,
51
+ S: this,
52
+ C: (f, a) => f(...a)
53
+ });
54
+ return links;
55
+ }
56
+ if (!(objectSchema instanceof DynamicSchema)) {
57
+ const idx = objects.findIndex((obj) => obj.id === typename);
58
+ if (idx === -1) {
59
+ this._graph.nodes.push({
60
+ id: typename,
61
+ type: "schema",
62
+ schema: objectSchema
63
+ });
64
+ }
65
+ }
66
+ if (this._options.schema) {
67
+ links.push({
68
+ id: `${object.id}-${typename}`,
69
+ source: object.id,
70
+ target: typename
71
+ });
72
+ }
73
+ AST.getPropertySignatures(objectSchema.ast).forEach((prop) => {
74
+ if (!SchemaValidator.hasTypeAnnotation(objectSchema, prop.name.toString(), ReferenceAnnotationId)) {
75
+ return;
76
+ }
77
+ const value = object[String(prop.name)];
78
+ if (value) {
79
+ const refs = Array.isArray(value) ? value : [
80
+ value
81
+ ];
82
+ for (const ref of refs) {
83
+ if (objects.findIndex((obj) => obj.id === ref.id) !== -1) {
84
+ links.push({
85
+ id: `${object.id}-${String(prop.name)}-${ref.id}`,
86
+ source: object.id,
87
+ target: ref.id
88
+ });
89
+ }
90
+ }
91
+ }
92
+ });
93
+ return links;
94
+ }, []);
95
+ this.triggerUpdate();
96
+ }, {
97
+ fire: true
98
+ });
99
+ }
100
+ this.setSelected(objectId);
101
+ return this;
102
+ }
103
+ close() {
104
+ if (this._subscription) {
105
+ this._subscription();
106
+ this._subscription = void 0;
107
+ }
108
+ return this;
109
+ }
110
+ };
111
+
112
+ // packages/plugins/experimental/plugin-explorer/src/components/Tree/Tree.tsx
113
+ import React2, { useEffect as useEffect2, useMemo as useMemo2, useState as useState2 } from "react";
114
+ import { useResizeDetector } from "react-resize-detector";
115
+ import { createSvgContext as createSvgContext2, SVG as SVG2, SVGRoot as SVGRoot2 } from "@dxos/gem-core";
116
+
117
+ // packages/plugins/experimental/plugin-explorer/src/components/Tree/layout/HierarchicalEdgeBundling.ts
118
+ import * as d3 from "d3";
119
+ var HierarchicalEdgeBundling = (s, data, options) => {
120
+ const svg = d3.select(s);
121
+ svg.selectAll("*").remove();
122
+ const { radius = 600, padding = 100, slots: slots2 } = options;
123
+ const root = d3.hierarchy(flatten(data));
124
+ const tree3 = d3.cluster().size([
125
+ 2 * Math.PI,
126
+ radius - padding
127
+ ]);
128
+ const layout = tree3(addLinks(root));
129
+ 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)));
130
+ const line = d3.lineRadial().curve(d3.curveBundle.beta(0.85)).radius((d) => d.y).angle((d) => d.x);
131
+ 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]) => {
132
+ return line(i.path(o));
133
+ }).each(function(d) {
134
+ d.path = this;
135
+ });
136
+ };
137
+ var addLinks = (root) => {
138
+ const nodes = new Map(root.descendants().map((d) => [
139
+ d.data.id,
140
+ d
141
+ ]));
142
+ const parents = root.descendants().reduce((map, d) => {
143
+ if (d.children?.length) {
144
+ map.set(d.data.id, d);
145
+ }
146
+ return map;
147
+ }, /* @__PURE__ */ new Map());
148
+ for (const d of root.leaves()) {
149
+ const parent = parents.get(d.data.id);
150
+ if (parent) {
151
+ d.outgoing = parent.data.children?.slice(1).map((child) => {
152
+ return [
153
+ d,
154
+ nodes.get(child.id)
155
+ ];
156
+ }) ?? [];
157
+ } else {
158
+ d.outgoing = [];
159
+ }
160
+ }
161
+ return root;
162
+ };
163
+ var flatten = (node) => {
164
+ const clone = {
165
+ id: node.id
166
+ };
167
+ if (node.children?.length) {
168
+ const children = node.children.map((child) => flatten(child));
169
+ clone.children = [
170
+ {
171
+ id: node.id
172
+ },
173
+ ...children
174
+ ];
175
+ }
176
+ return clone;
177
+ };
178
+ var HierarchicalEdgeBundling_default = HierarchicalEdgeBundling;
179
+
180
+ // packages/plugins/experimental/plugin-explorer/src/components/Tree/layout/RadialTree.ts
181
+ import * as d32 from "d3";
182
+ var RadialTree = (s, data, options) => {
183
+ const svg = d32.select(s);
184
+ svg.selectAll("*").remove();
185
+ const { label, radius = 400, r = 4, slots: slots2 } = options;
186
+ const arc = 2 * Math.PI;
187
+ const root = d32.hierarchy(data);
188
+ const descendants = root.descendants();
189
+ const getLabel = label === null ? null : descendants.map((d) => label(d.data));
190
+ const layout = d32.tree().size([
191
+ arc,
192
+ radius
193
+ ]).separation((a, b) => (a.parent === b.parent ? 1 : 2) / a.depth);
194
+ layout(root);
195
+ 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));
196
+ 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)`);
197
+ node.append("circle").attr("class", slots2?.node ?? "").attr("r", r);
198
+ if (getLabel) {
199
+ 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]);
200
+ }
201
+ return svg.node();
202
+ };
203
+ var RadialTree_default = RadialTree;
204
+
205
+ // packages/plugins/experimental/plugin-explorer/src/components/Tree/layout/TidyTree.ts
206
+ import * as d33 from "d3";
207
+ var TidyTree = (s, data, options) => {
208
+ const svg = d33.select(s);
209
+ svg.selectAll("*").remove();
210
+ const { label, width, height, r = 4, padding = 4, margin = 60, slots: slots2 } = options;
211
+ const root = d33.hierarchy(data);
212
+ const descendants = root.descendants();
213
+ const getLabel = label == null ? null : descendants.map((d) => label(d.data));
214
+ const dx = 16;
215
+ const dy = width / (root.height + padding);
216
+ const layout = d33.tree().nodeSize([
217
+ dx,
218
+ dy
219
+ ]);
220
+ layout(root);
221
+ let x0 = Infinity;
222
+ let x1 = -x0;
223
+ let y0 = Infinity;
224
+ let y1 = -y0;
225
+ root.each((d) => {
226
+ if (d.x > x1) {
227
+ x1 = d.x;
228
+ }
229
+ if (d.x < x0) {
230
+ x0 = d.x;
231
+ }
232
+ if (d.y > y1) {
233
+ y1 = d.y;
234
+ }
235
+ if (d.y < y0) {
236
+ y0 = d.y;
237
+ }
238
+ });
239
+ const sx = Math.min(2, Math.max(1, (height - margin * 2) / (x1 - x0)));
240
+ const oy = -(width - (y1 - y0)) / 2;
241
+ 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));
242
+ const node = svg.append("g").selectAll("a").data(root.descendants()).join("a").attr("transform", (d) => `translate(${d.y + oy},${d.x * sx})`);
243
+ node.append("circle").attr("class", slots2?.node ?? "").attr("r", r);
244
+ if (getLabel) {
245
+ 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]);
246
+ }
247
+ };
248
+ var TidyTree_default = TidyTree;
249
+
250
+ // packages/plugins/experimental/plugin-explorer/src/components/Tree/types.ts
251
+ var mapGraphToTreeData = (model, maxDepth = 8) => {
252
+ const mapNode = (node, depth = 0) => {
253
+ const treeNode = {
254
+ id: model.idAccessor(node),
255
+ label: model.idAccessor(node).slice(0, 8)
256
+ };
257
+ const links = model.graph.links.filter((link2) => link2.source === treeNode.id);
258
+ if (depth < maxDepth) {
259
+ treeNode.children = links.map((link2) => mapNode(model.graph.nodes.find((node2) => model.idAccessor(node2) === link2.target), depth + 1));
260
+ }
261
+ return treeNode;
262
+ };
263
+ let data;
264
+ if (model.selected) {
265
+ const node = model.graph.nodes.find((node2) => model.idAccessor(node2) === model.selected);
266
+ if (node) {
267
+ data = mapNode(node);
268
+ }
269
+ }
270
+ return data;
271
+ };
272
+
273
+ // packages/plugins/experimental/plugin-explorer/src/components/Graph/Graph.tsx
274
+ import React, { useEffect, useMemo, useRef, useState } from "react";
275
+ import { getType as getType2 } from "@dxos/echo-schema";
276
+ import { createSvgContext, defaultGridStyles, Grid, SVG, SVGRoot, Zoom } from "@dxos/gem-core";
277
+ import { defaultStyles, Graph as GraphComponent, GraphForceProjector, Markers } from "@dxos/gem-spore";
278
+ import { filterObjectsSync } from "@dxos/plugin-search";
279
+ import { useThemeContext } from "@dxos/react-ui";
280
+ import { mx } from "@dxos/react-ui-theme";
281
+ import "@dxos/gem-spore/styles";
282
+ var slots = {};
283
+ var colors = [
284
+ "[&>circle]:!fill-black-300 [&>circle]:!stroke-black-600",
285
+ "[&>circle]:!fill-slate-300 [&>circle]:!stroke-slate-600",
286
+ "[&>circle]:!fill-green-300 [&>circle]:!stroke-green-600",
287
+ "[&>circle]:!fill-sky-300 [&>circle]:!stroke-sky-600",
288
+ "[&>circle]:!fill-cyan-300 [&>circle]:!stroke-cyan-600",
289
+ "[&>circle]:!fill-rose-300 [&>circle]:!stroke-rose-600",
290
+ "[&>circle]:!fill-purple-300 [&>circle]:!stroke-purple-600",
291
+ "[&>circle]:!fill-orange-300 [&>circle]:!stroke-orange-600",
292
+ "[&>circle]:!fill-teal-300 [&>circle]:!stroke-teal-600",
293
+ "[&>circle]:!fill-indigo-300 [&>circle]:!stroke-indigo-600"
294
+ ];
295
+ var Graph = ({ space, match }) => {
296
+ const model = useMemo(() => space ? new SpaceGraphModel({
297
+ schema: true
298
+ }).open(space) : void 0, [
299
+ space
300
+ ]);
301
+ const [selected, setSelected] = useState();
302
+ const { themeMode } = useThemeContext();
303
+ const context = createSvgContext();
304
+ const projector = useMemo(() => new GraphForceProjector(context, {
305
+ forces: {
306
+ manyBody: {
307
+ strength: -100
308
+ },
309
+ link: {
310
+ distance: 180
311
+ },
312
+ radial: {
313
+ radius: 200,
314
+ strength: 0.05
315
+ }
316
+ },
317
+ attributes: {
318
+ radius: (node) => node.data?.type === "schema" ? 24 : 12
319
+ }
320
+ }), []);
321
+ const filteredRef = useRef();
322
+ filteredRef.current = filterObjectsSync(model?.objects ?? [], match);
323
+ useEffect(() => {
324
+ void projector.start();
325
+ }, [
326
+ match
327
+ ]);
328
+ const [colorMap] = useState(/* @__PURE__ */ new Map());
329
+ if (!model) {
330
+ return null;
331
+ }
332
+ if (selected) {
333
+ return /* @__PURE__ */ React.createElement(Tree, {
334
+ space,
335
+ selected,
336
+ variant: "tidy",
337
+ onNodeClick: () => setSelected(void 0)
338
+ });
339
+ }
340
+ return /* @__PURE__ */ React.createElement(SVGRoot, {
341
+ context
342
+ }, /* @__PURE__ */ React.createElement(SVG, {
343
+ className: mx(defaultStyles, slots?.root?.className)
344
+ }, /* @__PURE__ */ React.createElement(Markers, {
345
+ arrowSize: 6
346
+ }), /* @__PURE__ */ React.createElement(Grid, {
347
+ className: slots?.grid?.className ?? defaultGridStyles(themeMode)
348
+ }), /* @__PURE__ */ React.createElement(Zoom, {
349
+ extent: [
350
+ 1 / 2,
351
+ 4
352
+ ]
353
+ }, /* @__PURE__ */ React.createElement(GraphComponent, {
354
+ model,
355
+ projector,
356
+ drag: true,
357
+ arrows: true,
358
+ onSelect: (node) => setSelected(node?.data?.id),
359
+ labels: {
360
+ text: (node) => {
361
+ if (filteredRef.current?.length && !filteredRef.current.some((object) => object.id === node.data?.id)) {
362
+ return void 0;
363
+ }
364
+ return node.data?.label ?? node.data?.title ?? node.data?.name ?? node.data?.id.slice(0, 8);
365
+ }
366
+ },
367
+ attributes: {
368
+ node: (node) => {
369
+ let className;
370
+ if (node.data) {
371
+ const typename = getType2(node.data)?.objectId;
372
+ if (typename) {
373
+ className = colorMap.get(typename);
374
+ if (!className) {
375
+ className = colors[colorMap.size % colors.length];
376
+ colorMap.set(typename, className);
377
+ }
378
+ }
379
+ }
380
+ const selected2 = filteredRef.current?.some((object) => object.id === node.data?.id);
381
+ return {
382
+ class: mx(filteredRef.current?.length ? selected2 ? [
383
+ className
384
+ ] : "[&>text]:!fill-neutral-300" : [
385
+ "[&>text]:!fill-neutral-700",
386
+ className
387
+ ])
388
+ };
389
+ },
390
+ link: () => ({
391
+ class: "[&>path]:!stroke-neutral-300"
392
+ })
393
+ }
394
+ }))));
395
+ };
396
+
397
+ // packages/plugins/experimental/plugin-explorer/src/components/Tree/Tree.tsx
398
+ var defaultTreeLayoutSlots = {
399
+ node: "fill-blue-600",
400
+ path: "fill-none stroke-blue-400 stroke-[0.5px]",
401
+ text: "stroke-[0.5px] stroke-neutral-700 text-xs"
402
+ };
403
+ var renderers = /* @__PURE__ */ new Map([
404
+ [
405
+ "tidy",
406
+ TidyTree_default
407
+ ],
408
+ [
409
+ "radial",
410
+ RadialTree_default
411
+ ],
412
+ [
413
+ "edge",
414
+ HierarchicalEdgeBundling_default
415
+ ]
416
+ ]);
417
+ var Tree = ({ space, selected, variant = "tidy", onNodeClick }) => {
418
+ const model = useMemo2(() => space ? new SpaceGraphModel().open(space, selected) : void 0, [
419
+ space,
420
+ selected
421
+ ]);
422
+ const [tree3, setTree] = useState2();
423
+ useEffect2(() => {
424
+ return model?.subscribe(() => {
425
+ const tree4 = mapGraphToTreeData(model);
426
+ setTree(tree4);
427
+ }, true);
428
+ }, [
429
+ model
430
+ ]);
431
+ const context = createSvgContext2();
432
+ const { ref, width = 0, height = 0 } = useResizeDetector();
433
+ useEffect2(() => {
434
+ if (width && height) {
435
+ const size = Math.min(width, height);
436
+ const radius = size * 0.4;
437
+ const options = {
438
+ // TODO(burdon): Type.
439
+ label: (d) => d.label ?? d.id,
440
+ width,
441
+ height,
442
+ radius,
443
+ marginLeft: (width - radius * 2) / 2,
444
+ marginRight: (width - radius * 2) / 2,
445
+ marginTop: (height - radius * 2) / 2,
446
+ marginBottom: (height - radius * 2) / 2,
447
+ slots: defaultTreeLayoutSlots
448
+ };
449
+ if (tree3) {
450
+ const renderer = renderers.get(variant);
451
+ renderer?.(context.ref.current, tree3, options);
452
+ }
453
+ }
454
+ }, [
455
+ tree3,
456
+ width,
457
+ height
458
+ ]);
459
+ return /* @__PURE__ */ React2.createElement("div", {
460
+ ref,
461
+ className: "flex grow overflow-hidden",
462
+ onClick: () => onNodeClick?.()
463
+ }, /* @__PURE__ */ React2.createElement(SVGRoot2, {
464
+ context
465
+ }, /* @__PURE__ */ React2.createElement(SVG2, null)));
466
+ };
467
+
468
+ export {
469
+ SpaceGraphModel,
470
+ defaultTreeLayoutSlots,
471
+ Tree,
472
+ Graph
473
+ };
474
+ //# sourceMappingURL=chunk-XKITKIPQ.mjs.map