@ts-graphviz/react 0.9.1 → 0.10.0
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.
- package/CHANGELOG.md +76 -0
- package/LICENSE +1 -1
- package/README.md +25 -63
- package/example/example.tsx +14 -12
- package/lib/react.cjs +457 -0
- package/lib/react.d.ts +230 -0
- package/lib/react.js +457 -0
- package/package.json +55 -65
- package/src/components/Digraph.spec.tsx +18 -0
- package/src/components/Digraph.tsx +41 -0
- package/src/components/Edge.tsx +17 -0
- package/src/components/Graph.spec.tsx +18 -0
- package/src/components/Graph.tsx +36 -0
- package/src/components/GraphPortal.tsx +22 -0
- package/src/components/Node.spec.tsx +101 -0
- package/src/components/Node.tsx +21 -0
- package/src/components/Subgraph.tsx +30 -0
- package/src/contexts/CurrentGraph.ts +5 -0
- package/src/contexts/GraphContainer.ts +5 -0
- package/src/contexts/GraphMap.ts +5 -0
- package/src/contexts/GraphvizContext.ts +11 -0
- package/src/hooks/__tests__/wrapper.tsx +58 -0
- package/src/hooks/useCurrentGraph.spec.ts +56 -0
- package/src/hooks/useCurrentGraph.ts +18 -0
- package/src/hooks/useDigraph.spec.ts +15 -0
- package/src/hooks/useDigraph.ts +33 -0
- package/src/hooks/useEdge.spec.ts +46 -0
- package/src/hooks/useEdge.ts +35 -0
- package/src/hooks/useGraph.spec.ts +15 -0
- package/src/hooks/useGraph.ts +33 -0
- package/src/hooks/useGraphAttributes.ts +32 -0
- package/src/hooks/useGraphContainer.spec.ts +45 -0
- package/src/hooks/useGraphContainer.ts +10 -0
- package/src/hooks/useGraphMap.ts +7 -0
- package/src/hooks/useGraphvizContext.spec.ts +26 -0
- package/src/hooks/useGraphvizContext.ts +16 -0
- package/src/hooks/useHasAttributes.ts +16 -0
- package/src/hooks/useHasComment.ts +8 -0
- package/src/hooks/useNode.spec.ts +16 -0
- package/src/hooks/useNode.ts +29 -0
- package/src/hooks/useRenderedID.spec.tsx +28 -0
- package/src/hooks/useRenderedID.ts +6 -0
- package/src/hooks/useSubgraph.spec.ts +41 -0
- package/src/hooks/useSubgraph.ts +39 -0
- package/src/react.ts +16 -0
- package/src/reconciler.ts +272 -0
- package/src/render.test.tsx +71 -0
- package/src/render.ts +142 -0
- package/src/renderHTMLLike.ts +9 -0
- package/src/renderId.ts +9 -0
- package/src/types.ts +107 -0
- package/tsconfig.json +8 -0
- package/typedoc.json +5 -0
- package/vite.config.ts +31 -0
- package/.all-contributorsrc +0 -47
- package/.devcontainer/Dockerfile +0 -16
- package/.devcontainer/devcontainer.json +0 -35
- package/.eslintignore +0 -2
- package/lib/index.d.ts +0 -368
- package/lib/index.js +0 -1
- package/lib/index.mjs +0 -1
- package/rollup.config.js +0 -55
package/lib/react.cjs
ADDED
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const react = require("react");
|
|
4
|
+
const tsGraphviz = require("ts-graphviz");
|
|
5
|
+
const jsxRuntime = require("react/jsx-runtime");
|
|
6
|
+
const server = require("react-dom/server");
|
|
7
|
+
const ReactReconciler = require("react-reconciler");
|
|
8
|
+
const GraphContainer = react.createContext(null);
|
|
9
|
+
GraphContainer.displayName = "GraphContainer";
|
|
10
|
+
function useGraphContainer() {
|
|
11
|
+
return react.useContext(GraphContainer);
|
|
12
|
+
}
|
|
13
|
+
const CurrentGraph = react.createContext(null);
|
|
14
|
+
CurrentGraph.displayName = "CurrentGraph";
|
|
15
|
+
function useCurrentGraph() {
|
|
16
|
+
const cluster = react.useContext(CurrentGraph);
|
|
17
|
+
if (cluster === null) {
|
|
18
|
+
throw Error(
|
|
19
|
+
"useCurrentGraph must be called within a cluster such as Digraph, Graph, Subgraph."
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
return cluster;
|
|
23
|
+
}
|
|
24
|
+
function useGraphAttributes(cluster, attributes, { edge, node, graph }) {
|
|
25
|
+
react.useEffect(() => {
|
|
26
|
+
cluster.clear();
|
|
27
|
+
cluster.apply(attributes);
|
|
28
|
+
}, [cluster, attributes]);
|
|
29
|
+
react.useEffect(() => {
|
|
30
|
+
cluster.attributes.node.clear();
|
|
31
|
+
cluster.attributes.node.apply(node ?? {});
|
|
32
|
+
}, [cluster, node]);
|
|
33
|
+
react.useEffect(() => {
|
|
34
|
+
cluster.attributes.edge.clear();
|
|
35
|
+
cluster.attributes.edge.apply(edge ?? {});
|
|
36
|
+
}, [cluster, edge]);
|
|
37
|
+
react.useEffect(() => {
|
|
38
|
+
cluster.attributes.graph.clear();
|
|
39
|
+
cluster.attributes.graph.apply(graph ?? {});
|
|
40
|
+
}, [cluster, graph]);
|
|
41
|
+
}
|
|
42
|
+
const GraphvizContext = react.createContext(
|
|
43
|
+
null
|
|
44
|
+
);
|
|
45
|
+
GraphvizContext.displayName = "GraphvizContext";
|
|
46
|
+
function useGraphvizContext() {
|
|
47
|
+
const context = react.useContext(
|
|
48
|
+
GraphvizContext
|
|
49
|
+
);
|
|
50
|
+
if (context === null) {
|
|
51
|
+
throw Error(
|
|
52
|
+
"Cannot call useGraphvizContext outside GraphvizContext.\nBasically, you need to use the render function provided by @ts-graphviz/react."
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
return context;
|
|
56
|
+
}
|
|
57
|
+
function useHasComment(target, comment) {
|
|
58
|
+
react.useEffect(() => {
|
|
59
|
+
target.comment = comment;
|
|
60
|
+
}, [target, comment]);
|
|
61
|
+
}
|
|
62
|
+
function useDigraph(options = {}) {
|
|
63
|
+
const { id, comment, edge, node, graph, ...attributes } = options;
|
|
64
|
+
const context = useGraphvizContext();
|
|
65
|
+
const digraph = react.useMemo(() => {
|
|
66
|
+
const g = new tsGraphviz.Digraph(id);
|
|
67
|
+
context.container = g;
|
|
68
|
+
g.comment = comment;
|
|
69
|
+
g.apply(attributes);
|
|
70
|
+
g.attributes.node.apply(node ?? {});
|
|
71
|
+
g.attributes.edge.apply(edge ?? {});
|
|
72
|
+
g.attributes.graph.apply(graph ?? {});
|
|
73
|
+
return g;
|
|
74
|
+
}, [context, id, comment, edge, node, graph, attributes]);
|
|
75
|
+
useHasComment(digraph, comment);
|
|
76
|
+
useGraphAttributes(digraph, attributes, { edge, node, graph });
|
|
77
|
+
react.useEffect(() => {
|
|
78
|
+
return () => {
|
|
79
|
+
context.container = void 0;
|
|
80
|
+
};
|
|
81
|
+
}, [context]);
|
|
82
|
+
return digraph;
|
|
83
|
+
}
|
|
84
|
+
function useGraph(options = {}) {
|
|
85
|
+
const { id, comment, edge, node, graph, ...attributes } = options;
|
|
86
|
+
const context = useGraphvizContext();
|
|
87
|
+
const memoGraph = react.useMemo(() => {
|
|
88
|
+
const g = new tsGraphviz.Graph(id);
|
|
89
|
+
context.container = g;
|
|
90
|
+
g.comment = comment;
|
|
91
|
+
g.apply(attributes);
|
|
92
|
+
g.attributes.node.apply(node ?? {});
|
|
93
|
+
g.attributes.edge.apply(edge ?? {});
|
|
94
|
+
g.attributes.graph.apply(graph ?? {});
|
|
95
|
+
return g;
|
|
96
|
+
}, [context, id, comment, edge, node, graph, attributes]);
|
|
97
|
+
useHasComment(memoGraph, comment);
|
|
98
|
+
useGraphAttributes(memoGraph, attributes, { edge, node, graph });
|
|
99
|
+
react.useEffect(() => {
|
|
100
|
+
return () => {
|
|
101
|
+
context.container = void 0;
|
|
102
|
+
};
|
|
103
|
+
}, [context]);
|
|
104
|
+
return memoGraph;
|
|
105
|
+
}
|
|
106
|
+
function useSubgraph(props = {}) {
|
|
107
|
+
const { id, comment, edge, node, graph, ...attributes } = props;
|
|
108
|
+
const context = useGraphvizContext();
|
|
109
|
+
const cluster = useCurrentGraph();
|
|
110
|
+
const subgraph = react.useMemo(() => {
|
|
111
|
+
const g = new tsGraphviz.Subgraph(id);
|
|
112
|
+
if (cluster !== null) {
|
|
113
|
+
cluster.addSubgraph(g);
|
|
114
|
+
} else if (!context.container) {
|
|
115
|
+
context.container = g;
|
|
116
|
+
}
|
|
117
|
+
g.comment = comment;
|
|
118
|
+
g.apply(attributes);
|
|
119
|
+
g.attributes.node.apply(node ?? {});
|
|
120
|
+
g.attributes.edge.apply(edge ?? {});
|
|
121
|
+
g.attributes.graph.apply(graph ?? {});
|
|
122
|
+
return g;
|
|
123
|
+
}, [context, cluster, id, comment, edge, node, graph, attributes]);
|
|
124
|
+
useHasComment(subgraph, comment);
|
|
125
|
+
useGraphAttributes(subgraph, attributes, { edge, node, graph });
|
|
126
|
+
react.useEffect(() => {
|
|
127
|
+
return () => {
|
|
128
|
+
cluster.removeSubgraph(subgraph);
|
|
129
|
+
};
|
|
130
|
+
}, [cluster, subgraph]);
|
|
131
|
+
return subgraph;
|
|
132
|
+
}
|
|
133
|
+
function useHasAttributes(target, attributes) {
|
|
134
|
+
react.useEffect(() => {
|
|
135
|
+
target.attributes.clear();
|
|
136
|
+
target.attributes.apply(attributes);
|
|
137
|
+
}, [target, attributes]);
|
|
138
|
+
}
|
|
139
|
+
function useEdge(targets, props = {}) {
|
|
140
|
+
const { comment, ...attributes } = props;
|
|
141
|
+
const cluster = useCurrentGraph();
|
|
142
|
+
if (targets.length < 2) {
|
|
143
|
+
throw Error("Edges must have at least 2 targets.");
|
|
144
|
+
}
|
|
145
|
+
const edge = react.useMemo(() => {
|
|
146
|
+
const e = cluster.createEdge(targets);
|
|
147
|
+
e.comment = comment;
|
|
148
|
+
e.attributes.apply(attributes);
|
|
149
|
+
return e;
|
|
150
|
+
}, [cluster, targets, comment, attributes]);
|
|
151
|
+
useHasComment(edge, comment);
|
|
152
|
+
useHasAttributes(edge, attributes);
|
|
153
|
+
react.useEffect(() => {
|
|
154
|
+
return () => {
|
|
155
|
+
cluster.removeEdge(edge);
|
|
156
|
+
};
|
|
157
|
+
}, [cluster, edge]);
|
|
158
|
+
return edge;
|
|
159
|
+
}
|
|
160
|
+
function useNode(id, options = {}) {
|
|
161
|
+
const { comment, ...attributes } = options;
|
|
162
|
+
const cluster = useCurrentGraph();
|
|
163
|
+
const node = react.useMemo(() => {
|
|
164
|
+
const n = cluster.createNode(id);
|
|
165
|
+
n.attributes.apply(attributes);
|
|
166
|
+
n.comment = comment;
|
|
167
|
+
return n;
|
|
168
|
+
}, [cluster, id, attributes, comment]);
|
|
169
|
+
useHasComment(node, comment);
|
|
170
|
+
useHasAttributes(node, attributes);
|
|
171
|
+
react.useEffect(() => {
|
|
172
|
+
return () => {
|
|
173
|
+
cluster.removeNode(node);
|
|
174
|
+
};
|
|
175
|
+
}, [cluster, node]);
|
|
176
|
+
return node;
|
|
177
|
+
}
|
|
178
|
+
const GraphMap = react.createContext(/* @__PURE__ */ new Map());
|
|
179
|
+
GraphMap.displayName = "GraphMap";
|
|
180
|
+
function useGraphMap() {
|
|
181
|
+
return react.useContext(GraphMap);
|
|
182
|
+
}
|
|
183
|
+
function renderHTMLLike(label) {
|
|
184
|
+
const htmlLike = server.renderToStaticMarkup(label).replace(/<dot:port>(.+?)<\/dot:port>/gi, "<$1>").replace(/<(\/?)dot:([a-z-]+)/gi, (_, $1, $2) => `<${$1}${$2}`);
|
|
185
|
+
return `<${htmlLike}>`;
|
|
186
|
+
}
|
|
187
|
+
function renderId(id) {
|
|
188
|
+
if (react.isValidElement(id)) {
|
|
189
|
+
return renderHTMLLike(id);
|
|
190
|
+
}
|
|
191
|
+
return id;
|
|
192
|
+
}
|
|
193
|
+
function useRenderedID(id) {
|
|
194
|
+
return react.useMemo(() => renderId(id), [id]);
|
|
195
|
+
}
|
|
196
|
+
const Graph = ({ children, label, ...options }) => {
|
|
197
|
+
const container = useGraphContainer();
|
|
198
|
+
if (container !== null) {
|
|
199
|
+
throw Error(
|
|
200
|
+
"RootCluster is duplicated.\nUse only one of Digraph and Graph."
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
const renderedLabel = useRenderedID(label);
|
|
204
|
+
if (renderedLabel !== void 0)
|
|
205
|
+
Object.assign(options, { label: renderedLabel });
|
|
206
|
+
const graph = useGraph(options);
|
|
207
|
+
const clusters = useGraphMap();
|
|
208
|
+
react.useEffect(() => {
|
|
209
|
+
if (graph.id !== void 0) {
|
|
210
|
+
clusters.set(graph.id, graph);
|
|
211
|
+
}
|
|
212
|
+
}, [clusters, graph]);
|
|
213
|
+
return /* @__PURE__ */ jsxRuntime.jsx(GraphContainer.Provider, { value: graph, children: /* @__PURE__ */ jsxRuntime.jsx(CurrentGraph.Provider, { value: graph, children }) });
|
|
214
|
+
};
|
|
215
|
+
Graph.displayName = "Graph";
|
|
216
|
+
const Digraph = ({
|
|
217
|
+
children,
|
|
218
|
+
label,
|
|
219
|
+
...options
|
|
220
|
+
}) => {
|
|
221
|
+
const container = useGraphContainer();
|
|
222
|
+
if (container !== null) {
|
|
223
|
+
throw Error(
|
|
224
|
+
"RootCluster is duplicated.\nUse only one of Digraph and Graph."
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
const renderedLabel = useRenderedID(label);
|
|
228
|
+
if (renderedLabel !== void 0)
|
|
229
|
+
Object.assign(options, { label: renderedLabel });
|
|
230
|
+
const digraph = useDigraph(options);
|
|
231
|
+
const clusters = useGraphMap();
|
|
232
|
+
react.useEffect(() => {
|
|
233
|
+
if (digraph.id !== void 0) {
|
|
234
|
+
clusters.set(digraph.id, digraph);
|
|
235
|
+
}
|
|
236
|
+
}, [clusters, digraph]);
|
|
237
|
+
return /* @__PURE__ */ jsxRuntime.jsx(GraphContainer.Provider, { value: digraph, children: /* @__PURE__ */ jsxRuntime.jsx(CurrentGraph.Provider, { value: digraph, children }) });
|
|
238
|
+
};
|
|
239
|
+
Digraph.displayName = "Digraph";
|
|
240
|
+
const Subgraph = ({
|
|
241
|
+
children,
|
|
242
|
+
label,
|
|
243
|
+
...options
|
|
244
|
+
}) => {
|
|
245
|
+
const renderedLabel = useRenderedID(label);
|
|
246
|
+
if (renderedLabel !== void 0)
|
|
247
|
+
Object.assign(options, { label: renderedLabel });
|
|
248
|
+
const subgraph = useSubgraph(options);
|
|
249
|
+
const clusters = useGraphMap();
|
|
250
|
+
react.useEffect(() => {
|
|
251
|
+
if (subgraph.id !== void 0) {
|
|
252
|
+
clusters.set(subgraph.id, subgraph);
|
|
253
|
+
}
|
|
254
|
+
}, [subgraph, clusters]);
|
|
255
|
+
return /* @__PURE__ */ jsxRuntime.jsx(CurrentGraph.Provider, { value: subgraph, children });
|
|
256
|
+
};
|
|
257
|
+
Subgraph.displayName = "Subgraph";
|
|
258
|
+
const Node = ({ id, label, xlabel, ...options }) => {
|
|
259
|
+
const renderedLabel = useRenderedID(label);
|
|
260
|
+
const renderedXlabel = useRenderedID(xlabel);
|
|
261
|
+
if (renderedLabel !== void 0)
|
|
262
|
+
Object.assign(options, { label: renderedLabel });
|
|
263
|
+
if (renderedXlabel !== void 0)
|
|
264
|
+
Object.assign(options, { xlabel: renderedXlabel });
|
|
265
|
+
useNode(id, options);
|
|
266
|
+
return null;
|
|
267
|
+
};
|
|
268
|
+
Node.displayName = "Node";
|
|
269
|
+
const Edge = ({ targets, label, ...options }) => {
|
|
270
|
+
const renderedLabel = useRenderedID(label);
|
|
271
|
+
if (renderedLabel !== void 0)
|
|
272
|
+
Object.assign(options, { label: renderedLabel });
|
|
273
|
+
useEdge(targets, options);
|
|
274
|
+
return null;
|
|
275
|
+
};
|
|
276
|
+
Edge.displayName = "Edge";
|
|
277
|
+
const GraphPortal = ({ children, id }) => {
|
|
278
|
+
const container = useGraphContainer();
|
|
279
|
+
const map = react.useContext(GraphMap);
|
|
280
|
+
const cluster = react.useMemo(
|
|
281
|
+
() => id ? map.get(id) ?? container : container,
|
|
282
|
+
[container, map, id]
|
|
283
|
+
);
|
|
284
|
+
return /* @__PURE__ */ jsxRuntime.jsx(CurrentGraph.Provider, { value: cluster, children });
|
|
285
|
+
};
|
|
286
|
+
GraphPortal.displayName = "GraphPortal";
|
|
287
|
+
class HostConfig {
|
|
288
|
+
preparePortalMount(containerInfo) {
|
|
289
|
+
}
|
|
290
|
+
scheduleTimeout(fn, delay) {
|
|
291
|
+
}
|
|
292
|
+
cancelTimeout(id) {
|
|
293
|
+
}
|
|
294
|
+
queueMicrotask(fn) {
|
|
295
|
+
}
|
|
296
|
+
cloneInstance;
|
|
297
|
+
cloneFundamentalInstance;
|
|
298
|
+
createContainerChildSet;
|
|
299
|
+
appendChildToContainerChildSet;
|
|
300
|
+
finalizeContainerChildren;
|
|
301
|
+
replaceContainerChildren;
|
|
302
|
+
cloneHiddenInstance;
|
|
303
|
+
cloneHiddenTextInstance;
|
|
304
|
+
now = Date.now;
|
|
305
|
+
setTimeout = setTimeout;
|
|
306
|
+
clearTimeout = clearTimeout;
|
|
307
|
+
noTimeout = -1;
|
|
308
|
+
// TODO
|
|
309
|
+
// Temporary workaround for scenario where multiple renderers concurrently
|
|
310
|
+
// render using the same context objects. E.g. React DOM and React ART on the
|
|
311
|
+
// same page. DOM is the primary renderer; ART is the secondary renderer.
|
|
312
|
+
isPrimaryRenderer = false;
|
|
313
|
+
supportsMutation = false;
|
|
314
|
+
supportsPersistence = false;
|
|
315
|
+
supportsHydration = false;
|
|
316
|
+
getPublicInstance(instance) {
|
|
317
|
+
return instance;
|
|
318
|
+
}
|
|
319
|
+
getRootHostContext(rootContainerInstance) {
|
|
320
|
+
return {};
|
|
321
|
+
}
|
|
322
|
+
getChildHostContext(parentHostContext, type, rootContainerInstance) {
|
|
323
|
+
return parentHostContext;
|
|
324
|
+
}
|
|
325
|
+
prepareForCommit(containerInfo) {
|
|
326
|
+
return null;
|
|
327
|
+
}
|
|
328
|
+
resetAfterCommit(containerInfo) {
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Create component instance
|
|
332
|
+
*/
|
|
333
|
+
createInstance(type, props, rootContainerInstance, hostContext, internalInstanceHandle) {
|
|
334
|
+
return type(props);
|
|
335
|
+
}
|
|
336
|
+
appendInitialChild(parentInstance, child) {
|
|
337
|
+
parentInstance.appendChild(child);
|
|
338
|
+
}
|
|
339
|
+
finalizeInitialChildren(parentInstance, type, props, rootContainerInstance, hostContext) {
|
|
340
|
+
return false;
|
|
341
|
+
}
|
|
342
|
+
prepareUpdate(instance, type, oldProps, newProps, rootContainerInstance, hostContext) {
|
|
343
|
+
return {};
|
|
344
|
+
}
|
|
345
|
+
shouldSetTextContent(type, props) {
|
|
346
|
+
return false;
|
|
347
|
+
}
|
|
348
|
+
shouldDeprioritizeSubtree(type, props) {
|
|
349
|
+
return false;
|
|
350
|
+
}
|
|
351
|
+
createTextInstance(text, rootContainerInstance, hostContext, internalInstanceHandle) {
|
|
352
|
+
return text;
|
|
353
|
+
}
|
|
354
|
+
scheduleDeferredCallback(callback, options) {
|
|
355
|
+
}
|
|
356
|
+
cancelDeferredCallback(callbackID) {
|
|
357
|
+
}
|
|
358
|
+
// -------------------
|
|
359
|
+
// Mutation
|
|
360
|
+
// (optional)
|
|
361
|
+
// -------------------
|
|
362
|
+
appendChild(parentInstance, child) {
|
|
363
|
+
if (parentInstance.appendChild) {
|
|
364
|
+
parentInstance.appendChild(child);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
appendChildToContainer(container, child) {
|
|
368
|
+
}
|
|
369
|
+
commitTextUpdate(textInstance, oldText, newText) {
|
|
370
|
+
}
|
|
371
|
+
commitMount(instance, type, newProps, internalInstanceHandle) {
|
|
372
|
+
}
|
|
373
|
+
commitUpdate(instance, updatePayload, type, oldProps, newProps, internalInstanceHandle) {
|
|
374
|
+
}
|
|
375
|
+
insertBefore(parentInstance, child, beforeChild) {
|
|
376
|
+
}
|
|
377
|
+
insertInContainerBefore(container, child, beforeChild) {
|
|
378
|
+
}
|
|
379
|
+
removeChild(parentInstance, child) {
|
|
380
|
+
}
|
|
381
|
+
removeChildFromContainer(container, child) {
|
|
382
|
+
}
|
|
383
|
+
resetTextContent(instance) {
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
const reconciler = ReactReconciler(new HostConfig());
|
|
387
|
+
const noop = () => void 0;
|
|
388
|
+
function clusterMap(graph, map = /* @__PURE__ */ new Map()) {
|
|
389
|
+
if (graph) {
|
|
390
|
+
if (graph.id) {
|
|
391
|
+
map.set(graph.id, graph);
|
|
392
|
+
}
|
|
393
|
+
for (const s of graph.subgraphs) {
|
|
394
|
+
clusterMap(s, map);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
return map;
|
|
398
|
+
}
|
|
399
|
+
function render(element, container) {
|
|
400
|
+
const context = { container };
|
|
401
|
+
reconciler.updateContainer(
|
|
402
|
+
react.createElement(
|
|
403
|
+
GraphvizContext.Provider,
|
|
404
|
+
{ value: context },
|
|
405
|
+
react.createElement(
|
|
406
|
+
GraphMap.Provider,
|
|
407
|
+
{ value: clusterMap(container) },
|
|
408
|
+
react.createElement(
|
|
409
|
+
GraphContainer.Provider,
|
|
410
|
+
{ value: container ?? null },
|
|
411
|
+
container ? react.createElement(
|
|
412
|
+
CurrentGraph.Provider,
|
|
413
|
+
{ value: container },
|
|
414
|
+
element
|
|
415
|
+
) : element
|
|
416
|
+
)
|
|
417
|
+
)
|
|
418
|
+
),
|
|
419
|
+
reconciler.createContainer(
|
|
420
|
+
{},
|
|
421
|
+
0,
|
|
422
|
+
null,
|
|
423
|
+
true,
|
|
424
|
+
null,
|
|
425
|
+
"@ts-graphviz/react",
|
|
426
|
+
noop,
|
|
427
|
+
null
|
|
428
|
+
),
|
|
429
|
+
null,
|
|
430
|
+
noop
|
|
431
|
+
);
|
|
432
|
+
if (!context.container) {
|
|
433
|
+
throw Error(
|
|
434
|
+
"There are no clusters of container(Subgraph, Digraph, Graph)."
|
|
435
|
+
);
|
|
436
|
+
}
|
|
437
|
+
return context.container;
|
|
438
|
+
}
|
|
439
|
+
function renderToDot(element, container) {
|
|
440
|
+
return tsGraphviz.toDot(render(element, container));
|
|
441
|
+
}
|
|
442
|
+
exports.Digraph = Digraph;
|
|
443
|
+
exports.Edge = Edge;
|
|
444
|
+
exports.Graph = Graph;
|
|
445
|
+
exports.GraphPortal = GraphPortal;
|
|
446
|
+
exports.Node = Node;
|
|
447
|
+
exports.Subgraph = Subgraph;
|
|
448
|
+
exports.render = render;
|
|
449
|
+
exports.renderHTMLLike = renderHTMLLike;
|
|
450
|
+
exports.renderToDot = renderToDot;
|
|
451
|
+
exports.useCurrentGraph = useCurrentGraph;
|
|
452
|
+
exports.useDigraph = useDigraph;
|
|
453
|
+
exports.useEdge = useEdge;
|
|
454
|
+
exports.useGraph = useGraph;
|
|
455
|
+
exports.useGraphContainer = useGraphContainer;
|
|
456
|
+
exports.useNode = useNode;
|
|
457
|
+
exports.useSubgraph = useSubgraph;
|
package/lib/react.d.ts
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import type { EdgeAttributesObject } from '@ts-graphviz/common';
|
|
2
|
+
import type { EdgeModel } from 'ts-graphviz';
|
|
3
|
+
import type { EdgeTargetLikeTuple } from '@ts-graphviz/common';
|
|
4
|
+
import type { EdgeTargetLikeTuple as EdgeTargetLikeTuple_2 } from 'ts-graphviz';
|
|
5
|
+
import { FC } from 'react';
|
|
6
|
+
import type { GraphAttributesObject } from '@ts-graphviz/common';
|
|
7
|
+
import { GraphBaseModel } from 'ts-graphviz';
|
|
8
|
+
import type { HasComment } from '@ts-graphviz/common';
|
|
9
|
+
import type { NodeAttributesObject } from '@ts-graphviz/common';
|
|
10
|
+
import type { NodeModel } from 'ts-graphviz';
|
|
11
|
+
import { ReactElement } from 'react';
|
|
12
|
+
import type { ReactNode } from 'react';
|
|
13
|
+
import { RootGraphModel } from 'ts-graphviz';
|
|
14
|
+
import type { SubgraphAttributesObject } from '@ts-graphviz/common';
|
|
15
|
+
import { SubgraphModel } from 'ts-graphviz';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* `Digraph` component.
|
|
19
|
+
*/
|
|
20
|
+
export declare const Digraph: FC<RootGraphProps>;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* `Edge` component.
|
|
24
|
+
*/
|
|
25
|
+
export declare const Edge: FC<EdgeProps>;
|
|
26
|
+
|
|
27
|
+
/** Options for Edge */
|
|
28
|
+
export declare interface EdgeOptions extends EdgeAttributesObject {
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Props for Edge component */
|
|
32
|
+
export declare interface EdgeProps extends Omit<EdgeOptions, 'label'> {
|
|
33
|
+
/** Edge targets */
|
|
34
|
+
targets: EdgeTargetLikeTuple;
|
|
35
|
+
/** Edge label */
|
|
36
|
+
label?: ReactElement | string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* `Graph` component.
|
|
41
|
+
*/
|
|
42
|
+
export declare const Graph: FC<RootGraphProps>;
|
|
43
|
+
|
|
44
|
+
/** Common attribute values of objects under cluster */
|
|
45
|
+
export declare interface GraphBaseAttributesProps {
|
|
46
|
+
/** Attribute value for Edges */
|
|
47
|
+
edge?: EdgeAttributesObject;
|
|
48
|
+
/** Attribute value for Nodes */
|
|
49
|
+
node?: NodeAttributesObject;
|
|
50
|
+
/** Attribute value for Graphs */
|
|
51
|
+
graph?: SubgraphAttributesObject;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* GraphPortal component.
|
|
56
|
+
*/
|
|
57
|
+
export declare const GraphPortal: FC<GraphPortalProps>;
|
|
58
|
+
|
|
59
|
+
/** Props for GraphPortal component */
|
|
60
|
+
export declare interface GraphPortalProps {
|
|
61
|
+
/**
|
|
62
|
+
* id of the cluster you want to target for the portal.
|
|
63
|
+
* If not specified, target the cluster that is the container to the portal.
|
|
64
|
+
*/
|
|
65
|
+
id?: string;
|
|
66
|
+
children?: ReactNode;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* `Node` component.
|
|
71
|
+
*/
|
|
72
|
+
export declare const Node: FC<NodeProps>;
|
|
73
|
+
|
|
74
|
+
/** Options for Node */
|
|
75
|
+
export declare interface NodeOptions extends NodeAttributesObject {
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Props for Node component */
|
|
79
|
+
export declare interface NodeProps extends Omit<NodeOptions, 'label' | 'xlabel'> {
|
|
80
|
+
/** Node id */
|
|
81
|
+
id: string;
|
|
82
|
+
/** Node label */
|
|
83
|
+
label?: ReactElement | string;
|
|
84
|
+
/** Node xlabel */
|
|
85
|
+
xlabel?: ReactElement | string;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Convert the given element to Graphviz model.
|
|
90
|
+
*
|
|
91
|
+
* @example Example of giving a cluster as a container with the second argument.
|
|
92
|
+
*
|
|
93
|
+
* ```tsx
|
|
94
|
+
* import React, { FC } from 'react';
|
|
95
|
+
* import { digraph, toDot } from 'ts-graphviz';
|
|
96
|
+
* import { Node, Subgraph, render, Edge } from '@ts-graphviz/react';
|
|
97
|
+
*
|
|
98
|
+
* const Example: FC = () => (
|
|
99
|
+
* <>
|
|
100
|
+
* <Node id="a" />
|
|
101
|
+
*
|
|
102
|
+
* <Subgraph id="my_cluster">
|
|
103
|
+
* <Node id="b" />
|
|
104
|
+
* </Subgraph>
|
|
105
|
+
* <Edge targets={['b', 'a']} />
|
|
106
|
+
* </>
|
|
107
|
+
* );
|
|
108
|
+
*
|
|
109
|
+
* const G = digraph((g) => render(<Example />, g));
|
|
110
|
+
* console.log(toDot(G));
|
|
111
|
+
* // digraph {
|
|
112
|
+
* // "a";
|
|
113
|
+
* // subgraph "my_cluster" {
|
|
114
|
+
* // "b";
|
|
115
|
+
* // }
|
|
116
|
+
* // "b" -> "a";
|
|
117
|
+
* // }
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
export declare function render<T extends GraphBaseModel>(element: ReactElement, container?: T): T;
|
|
121
|
+
|
|
122
|
+
export declare function renderHTMLLike(label?: ReactElement): string;
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Converts the given element to DOT language and returns it.
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
*
|
|
129
|
+
* ```tsx
|
|
130
|
+
* import React, { FC } from 'react';
|
|
131
|
+
* import { Digraph, Node, Subgraph, renderToDot, Edge } from '@ts-graphviz/react';
|
|
132
|
+
*
|
|
133
|
+
* const Example: FC = () => (
|
|
134
|
+
* <Digraph>
|
|
135
|
+
* <Node id="a" />
|
|
136
|
+
* <Subgraph id="my_cluster">
|
|
137
|
+
* <Node id="b" />
|
|
138
|
+
* </Subgraph>
|
|
139
|
+
* <Edge targets={['b', 'a']} />
|
|
140
|
+
* </Digraph>
|
|
141
|
+
* );
|
|
142
|
+
*
|
|
143
|
+
* const dot = renderToDot(<Example />);
|
|
144
|
+
* console.log(dot);
|
|
145
|
+
* // digraph {
|
|
146
|
+
* // "a";
|
|
147
|
+
* // subgraph "my_cluster" {
|
|
148
|
+
* // "b";
|
|
149
|
+
* // }
|
|
150
|
+
* // "b" -> "a";
|
|
151
|
+
* // }
|
|
152
|
+
* ```
|
|
153
|
+
*
|
|
154
|
+
* @returns Rendered dot string
|
|
155
|
+
*/
|
|
156
|
+
export declare function renderToDot(element: ReactElement, container?: RootGraphModel): string;
|
|
157
|
+
|
|
158
|
+
/** Options for RootGraph */
|
|
159
|
+
export declare interface RootGraphOptions extends GraphAttributesObject, GraphBaseAttributesProps {
|
|
160
|
+
/** Cluster id */
|
|
161
|
+
id?: string;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/** Props for RootGraph component */
|
|
165
|
+
export declare interface RootGraphProps extends Omit<RootGraphOptions, 'label'> {
|
|
166
|
+
label?: ReactElement | string;
|
|
167
|
+
children?: ReactNode;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* `Subgraph` component.
|
|
172
|
+
*/
|
|
173
|
+
export declare const Subgraph: FC<SubgraphProps>;
|
|
174
|
+
|
|
175
|
+
/** Options for Subgraph */
|
|
176
|
+
export declare interface SubgraphOptions extends SubgraphAttributesObject, GraphBaseAttributesProps, HasComment {
|
|
177
|
+
/** Cluster id */
|
|
178
|
+
id?: string;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/** Props for Subgraph component */
|
|
182
|
+
export declare interface SubgraphProps extends Omit<SubgraphOptions, 'label'> {
|
|
183
|
+
/** Subgraph label */
|
|
184
|
+
label?: ReactElement | string;
|
|
185
|
+
children?: ReactNode;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Hook to get the current cluster(Digraph, Graph or Subgraph).
|
|
190
|
+
*
|
|
191
|
+
* @throws If it is out of the context of Cluster, it throws an exception.
|
|
192
|
+
*/
|
|
193
|
+
export declare function useCurrentGraph(): GraphBaseModel;
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* `useDigraph` is a hook that creates an instance of Digraph
|
|
197
|
+
* according to the object given by props.
|
|
198
|
+
*/
|
|
199
|
+
export declare function useDigraph(options?: RootGraphOptions): RootGraphModel;
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* `useEdge` is a hook that creates an instance of Edge
|
|
203
|
+
* according to the object given by props.
|
|
204
|
+
*/
|
|
205
|
+
export declare function useEdge(targets: EdgeTargetLikeTuple_2, props?: EdgeOptions): EdgeModel;
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* `useGraph` is a hook that creates an instance of Graph
|
|
209
|
+
* according to the object given by props.
|
|
210
|
+
*/
|
|
211
|
+
export declare function useGraph(options?: RootGraphOptions): RootGraphModel;
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Return the cluster of container.
|
|
215
|
+
*/
|
|
216
|
+
export declare function useGraphContainer(): GraphBaseModel | null;
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* `useNode` is a hook that creates an instance of Node
|
|
220
|
+
* according to the object given by props.
|
|
221
|
+
*/
|
|
222
|
+
export declare function useNode(id: string, options?: NodeOptions): NodeModel;
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* `useSubgraph` is a hook that creates an instance of Subgraph
|
|
226
|
+
* according to the object given by props.
|
|
227
|
+
*/
|
|
228
|
+
export declare function useSubgraph(props?: SubgraphOptions): SubgraphModel;
|
|
229
|
+
|
|
230
|
+
export { }
|