@ts-graphviz/react 0.9.1 → 0.10.1
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 +86 -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 +32 -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/src/render.ts
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { type ReactElement, createElement } from 'react';
|
|
2
|
+
import { type GraphBaseModel, type RootGraphModel, toDot } from 'ts-graphviz';
|
|
3
|
+
|
|
4
|
+
import { CurrentGraph } from './contexts/CurrentGraph.js';
|
|
5
|
+
import { GraphContainer } from './contexts/GraphContainer.js';
|
|
6
|
+
import { GraphMap } from './contexts/GraphMap.js';
|
|
7
|
+
import { type Context, GraphvizContext } from './contexts/GraphvizContext.js';
|
|
8
|
+
import { reconciler } from './reconciler.js';
|
|
9
|
+
|
|
10
|
+
const noop = (): void => undefined;
|
|
11
|
+
|
|
12
|
+
function clusterMap(
|
|
13
|
+
graph?: GraphBaseModel,
|
|
14
|
+
map: Map<string, GraphBaseModel> = new Map(),
|
|
15
|
+
): Map<string, GraphBaseModel> {
|
|
16
|
+
if (graph) {
|
|
17
|
+
if (graph.id) {
|
|
18
|
+
map.set(graph.id, graph);
|
|
19
|
+
}
|
|
20
|
+
for (const s of graph.subgraphs) {
|
|
21
|
+
clusterMap(s, map);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return map;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Convert the given element to Graphviz model.
|
|
29
|
+
*
|
|
30
|
+
* @example Example of giving a cluster as a container with the second argument.
|
|
31
|
+
*
|
|
32
|
+
* ```tsx
|
|
33
|
+
* import React, { FC } from 'react';
|
|
34
|
+
* import { digraph, toDot } from 'ts-graphviz';
|
|
35
|
+
* import { Node, Subgraph, render, Edge } from '@ts-graphviz/react';
|
|
36
|
+
*
|
|
37
|
+
* const Example: FC = () => (
|
|
38
|
+
* <>
|
|
39
|
+
* <Node id="a" />
|
|
40
|
+
*
|
|
41
|
+
* <Subgraph id="my_cluster">
|
|
42
|
+
* <Node id="b" />
|
|
43
|
+
* </Subgraph>
|
|
44
|
+
* <Edge targets={['b', 'a']} />
|
|
45
|
+
* </>
|
|
46
|
+
* );
|
|
47
|
+
*
|
|
48
|
+
* const G = digraph((g) => render(<Example />, g));
|
|
49
|
+
* console.log(toDot(G));
|
|
50
|
+
* // digraph {
|
|
51
|
+
* // "a";
|
|
52
|
+
* // subgraph "my_cluster" {
|
|
53
|
+
* // "b";
|
|
54
|
+
* // }
|
|
55
|
+
* // "b" -> "a";
|
|
56
|
+
* // }
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export function render<T extends GraphBaseModel>(
|
|
60
|
+
element: ReactElement,
|
|
61
|
+
container?: T,
|
|
62
|
+
): T {
|
|
63
|
+
const context: Context<T> = { container };
|
|
64
|
+
reconciler.updateContainer(
|
|
65
|
+
createElement(
|
|
66
|
+
GraphvizContext.Provider,
|
|
67
|
+
{ value: context },
|
|
68
|
+
createElement(
|
|
69
|
+
GraphMap.Provider,
|
|
70
|
+
{ value: clusterMap(container) },
|
|
71
|
+
createElement(
|
|
72
|
+
GraphContainer.Provider,
|
|
73
|
+
{ value: container ?? null },
|
|
74
|
+
container
|
|
75
|
+
? createElement(
|
|
76
|
+
CurrentGraph.Provider,
|
|
77
|
+
{ value: container },
|
|
78
|
+
element,
|
|
79
|
+
)
|
|
80
|
+
: element,
|
|
81
|
+
),
|
|
82
|
+
),
|
|
83
|
+
),
|
|
84
|
+
reconciler.createContainer(
|
|
85
|
+
{},
|
|
86
|
+
0,
|
|
87
|
+
null,
|
|
88
|
+
true,
|
|
89
|
+
null,
|
|
90
|
+
'@ts-graphviz/react',
|
|
91
|
+
noop,
|
|
92
|
+
null,
|
|
93
|
+
),
|
|
94
|
+
null,
|
|
95
|
+
noop,
|
|
96
|
+
);
|
|
97
|
+
if (!context.container) {
|
|
98
|
+
throw Error(
|
|
99
|
+
'There are no clusters of container(Subgraph, Digraph, Graph).',
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
return context.container;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Converts the given element to DOT language and returns it.
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
*
|
|
110
|
+
* ```tsx
|
|
111
|
+
* import React, { FC } from 'react';
|
|
112
|
+
* import { Digraph, Node, Subgraph, renderToDot, Edge } from '@ts-graphviz/react';
|
|
113
|
+
*
|
|
114
|
+
* const Example: FC = () => (
|
|
115
|
+
* <Digraph>
|
|
116
|
+
* <Node id="a" />
|
|
117
|
+
* <Subgraph id="my_cluster">
|
|
118
|
+
* <Node id="b" />
|
|
119
|
+
* </Subgraph>
|
|
120
|
+
* <Edge targets={['b', 'a']} />
|
|
121
|
+
* </Digraph>
|
|
122
|
+
* );
|
|
123
|
+
*
|
|
124
|
+
* const dot = renderToDot(<Example />);
|
|
125
|
+
* console.log(dot);
|
|
126
|
+
* // digraph {
|
|
127
|
+
* // "a";
|
|
128
|
+
* // subgraph "my_cluster" {
|
|
129
|
+
* // "b";
|
|
130
|
+
* // }
|
|
131
|
+
* // "b" -> "a";
|
|
132
|
+
* // }
|
|
133
|
+
* ```
|
|
134
|
+
*
|
|
135
|
+
* @returns Rendered dot string
|
|
136
|
+
*/
|
|
137
|
+
export function renderToDot(
|
|
138
|
+
element: ReactElement,
|
|
139
|
+
container?: RootGraphModel,
|
|
140
|
+
): string {
|
|
141
|
+
return toDot(render(element, container));
|
|
142
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ReactElement } from 'react';
|
|
2
|
+
import { renderToStaticMarkup } from 'react-dom/server';
|
|
3
|
+
|
|
4
|
+
export function renderHTMLLike(label?: ReactElement): string {
|
|
5
|
+
const htmlLike = renderToStaticMarkup(label)
|
|
6
|
+
.replace(/<dot:port>(.+?)<\/dot:port>/gi, '<$1>')
|
|
7
|
+
.replace(/<(\/?)dot:([a-z-]+)/gi, (_, $1, $2) => `<${$1}${$2}`);
|
|
8
|
+
return `<${htmlLike}>`;
|
|
9
|
+
}
|
package/src/renderId.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type ReactElement, isValidElement } from 'react';
|
|
2
|
+
import { renderHTMLLike } from './renderHTMLLike.js';
|
|
3
|
+
|
|
4
|
+
export function renderId<T>(id?: ReactElement<T> | string): string | undefined {
|
|
5
|
+
if (isValidElement(id)) {
|
|
6
|
+
return renderHTMLLike(id);
|
|
7
|
+
}
|
|
8
|
+
return id;
|
|
9
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
EdgeAttributesObject,
|
|
3
|
+
EdgeTargetLikeTuple,
|
|
4
|
+
GraphAttributesObject,
|
|
5
|
+
HTMLLikeLabel,
|
|
6
|
+
HasComment,
|
|
7
|
+
NodeAttributesObject,
|
|
8
|
+
SubgraphAttributesObject,
|
|
9
|
+
} from '@ts-graphviz/common';
|
|
10
|
+
import type { ReactElement, ReactNode } from 'react';
|
|
11
|
+
|
|
12
|
+
/** Common attribute values of objects under cluster */
|
|
13
|
+
export interface GraphBaseAttributesProps {
|
|
14
|
+
/** Attribute value for Edges */
|
|
15
|
+
edge?: EdgeAttributesObject;
|
|
16
|
+
/** Attribute value for Nodes */
|
|
17
|
+
node?: NodeAttributesObject;
|
|
18
|
+
/** Attribute value for Graphs */
|
|
19
|
+
graph?: SubgraphAttributesObject;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Options for RootGraph */
|
|
23
|
+
export interface RootGraphOptions
|
|
24
|
+
extends GraphAttributesObject,
|
|
25
|
+
GraphBaseAttributesProps {
|
|
26
|
+
/** Cluster id */
|
|
27
|
+
id?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Options for Subgraph */
|
|
31
|
+
export interface SubgraphOptions
|
|
32
|
+
extends SubgraphAttributesObject,
|
|
33
|
+
GraphBaseAttributesProps,
|
|
34
|
+
HasComment {
|
|
35
|
+
/** Cluster id */
|
|
36
|
+
id?: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Options for Edge */
|
|
40
|
+
export interface EdgeOptions extends EdgeAttributesObject {}
|
|
41
|
+
|
|
42
|
+
/** Options for Node */
|
|
43
|
+
export interface NodeOptions extends NodeAttributesObject {}
|
|
44
|
+
|
|
45
|
+
/** Props for RootGraph component */
|
|
46
|
+
export interface RootGraphProps extends Omit<RootGraphOptions, 'label'> {
|
|
47
|
+
label?: ReactElement | string;
|
|
48
|
+
children?: ReactNode;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Props for Edge component */
|
|
52
|
+
export interface EdgeProps extends Omit<EdgeOptions, 'label'> {
|
|
53
|
+
/** Edge targets */
|
|
54
|
+
targets: EdgeTargetLikeTuple;
|
|
55
|
+
/** Edge label */
|
|
56
|
+
label?: ReactElement | string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Props for Node component */
|
|
60
|
+
export interface NodeProps extends Omit<NodeOptions, 'label' | 'xlabel'> {
|
|
61
|
+
/** Node id */
|
|
62
|
+
id: string;
|
|
63
|
+
/** Node label */
|
|
64
|
+
label?: ReactElement | string;
|
|
65
|
+
/** Node xlabel */
|
|
66
|
+
xlabel?: ReactElement | string;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Props for Subgraph component */
|
|
70
|
+
export interface SubgraphProps extends Omit<SubgraphOptions, 'label'> {
|
|
71
|
+
/** Subgraph label */
|
|
72
|
+
label?: ReactElement | string;
|
|
73
|
+
children?: ReactNode;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Props for GraphPortal component */
|
|
77
|
+
export interface GraphPortalProps {
|
|
78
|
+
/**
|
|
79
|
+
* id of the cluster you want to target for the portal.
|
|
80
|
+
* If not specified, target the cluster that is the container to the portal.
|
|
81
|
+
*/
|
|
82
|
+
id?: string;
|
|
83
|
+
children?: ReactNode;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
declare global {
|
|
87
|
+
namespace JSX {
|
|
88
|
+
interface IntrinsicElements {
|
|
89
|
+
'dot:port': { children: string };
|
|
90
|
+
'dot:table': HTMLLikeLabel.TableAttributes & { children?: ReactNode };
|
|
91
|
+
'dot:tr': HTMLLikeLabel.TrAttributes & { children?: ReactNode };
|
|
92
|
+
'dot:td': HTMLLikeLabel.TdAttributes & { children?: ReactNode };
|
|
93
|
+
'dot:font': HTMLLikeLabel.FontAttributes & { children?: ReactNode };
|
|
94
|
+
'dot:br': HTMLLikeLabel.BrAttributes;
|
|
95
|
+
'dot:img': HTMLLikeLabel.ImgAttributes;
|
|
96
|
+
'dot:i': HTMLLikeLabel.IAttributes & { children?: ReactNode };
|
|
97
|
+
'dot:b': HTMLLikeLabel.BAttributes & { children?: ReactNode };
|
|
98
|
+
'dot:u': HTMLLikeLabel.UAttributes & { children?: ReactNode };
|
|
99
|
+
'dot:o': HTMLLikeLabel.OAttributes & { children?: ReactNode };
|
|
100
|
+
'dot:sub': HTMLLikeLabel.SubAttributes & { children?: ReactNode };
|
|
101
|
+
'dot:sup': HTMLLikeLabel.SupAttributes & { children?: ReactNode };
|
|
102
|
+
'dot:s': HTMLLikeLabel.SAttributes & { children?: ReactNode };
|
|
103
|
+
'dot:hr': HTMLLikeLabel.HrAttributes;
|
|
104
|
+
'dot:vr': HTMLLikeLabel.VrAttributes;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
package/tsconfig.json
ADDED
package/typedoc.json
ADDED
package/vite.config.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import dts from 'vite-plugin-dts';
|
|
2
|
+
import { defineConfig } from 'vitest/config';
|
|
3
|
+
|
|
4
|
+
export default defineConfig({
|
|
5
|
+
build: {
|
|
6
|
+
target: 'ES2022',
|
|
7
|
+
outDir: './lib',
|
|
8
|
+
minify: false,
|
|
9
|
+
lib: {
|
|
10
|
+
entry: {
|
|
11
|
+
react: './src/react.ts',
|
|
12
|
+
},
|
|
13
|
+
formats: ['es', 'cjs'],
|
|
14
|
+
},
|
|
15
|
+
rollupOptions: {
|
|
16
|
+
external: [
|
|
17
|
+
'react',
|
|
18
|
+
'react/jsx-runtime',
|
|
19
|
+
'react-dom',
|
|
20
|
+
'react-dom/server',
|
|
21
|
+
'react-reconciler',
|
|
22
|
+
'ts-graphviz',
|
|
23
|
+
],
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
plugins: [
|
|
27
|
+
// @ts-ignore
|
|
28
|
+
dts({
|
|
29
|
+
rollupTypes: true,
|
|
30
|
+
}),
|
|
31
|
+
],
|
|
32
|
+
});
|
package/.all-contributorsrc
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"files": [
|
|
3
|
-
"README.md"
|
|
4
|
-
],
|
|
5
|
-
"imageSize": 100,
|
|
6
|
-
"commit": false,
|
|
7
|
-
"contributors": [
|
|
8
|
-
{
|
|
9
|
-
"login": "kamiazya",
|
|
10
|
-
"name": "Yuki Yamazaki",
|
|
11
|
-
"avatar_url": "https://avatars0.githubusercontent.com/u/35218186?v=4",
|
|
12
|
-
"profile": "http://blog.kamiazya.tech/",
|
|
13
|
-
"contributions": [
|
|
14
|
-
"code",
|
|
15
|
-
"test",
|
|
16
|
-
"ideas",
|
|
17
|
-
"doc"
|
|
18
|
-
]
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
"login": "nagasawaryoya",
|
|
22
|
-
"name": "nagasawaryoya",
|
|
23
|
-
"avatar_url": "https://avatars.githubusercontent.com/u/53528726?v=4",
|
|
24
|
-
"profile": "https://github.com/nagasawaryoya",
|
|
25
|
-
"contributions": [
|
|
26
|
-
"code",
|
|
27
|
-
"test"
|
|
28
|
-
]
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
"login": "tokidrill",
|
|
32
|
-
"name": "YukiSasaki",
|
|
33
|
-
"avatar_url": "https://avatars.githubusercontent.com/u/42460318?v=4",
|
|
34
|
-
"profile": "https://github.com/tokidrill",
|
|
35
|
-
"contributions": [
|
|
36
|
-
"code",
|
|
37
|
-
"test"
|
|
38
|
-
]
|
|
39
|
-
}
|
|
40
|
-
],
|
|
41
|
-
"contributorsPerLine": 7,
|
|
42
|
-
"projectName": "react",
|
|
43
|
-
"projectOwner": "ts-graphviz",
|
|
44
|
-
"repoType": "github",
|
|
45
|
-
"repoHost": "https://github.com",
|
|
46
|
-
"skipCi": true
|
|
47
|
-
}
|
package/.devcontainer/Dockerfile
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.192.0/containers/typescript-node/.devcontainer/base.Dockerfile
|
|
2
|
-
|
|
3
|
-
# [Choice] Node.js version: 16, 14, 12
|
|
4
|
-
ARG VARIANT="16-buster"
|
|
5
|
-
FROM mcr.microsoft.com/vscode/devcontainers/typescript-node:0-${VARIANT}
|
|
6
|
-
|
|
7
|
-
# [Optional] Uncomment this section to install additional OS packages.
|
|
8
|
-
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
|
9
|
-
&& apt-get -y install --no-install-recommends graphviz
|
|
10
|
-
|
|
11
|
-
# [Optional] Uncomment if you want to install an additional version of node using nvm
|
|
12
|
-
# ARG EXTRA_NODE_VERSION=10
|
|
13
|
-
# RUN su node -c "source /usr/local/share/nvm/nvm.sh && nvm install ${EXTRA_NODE_VERSION}"
|
|
14
|
-
|
|
15
|
-
# [Optional] Uncomment if you want to install more global node packages
|
|
16
|
-
# RUN su node -c "npm install -g <your-package-list -here>"
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
|
|
2
|
-
// https://github.com/microsoft/vscode-dev-containers/tree/v0.192.0/containers/typescript-node
|
|
3
|
-
{
|
|
4
|
-
"name": "ts-graphviz",
|
|
5
|
-
"build": {
|
|
6
|
-
"dockerfile": "Dockerfile",
|
|
7
|
-
// Update 'VARIANT' to pick a Node version: 12, 14, 16
|
|
8
|
-
"args": {
|
|
9
|
-
"VARIANT": "16"
|
|
10
|
-
}
|
|
11
|
-
},
|
|
12
|
-
// Set *default* container specific settings.json values on container create.
|
|
13
|
-
"settings": {
|
|
14
|
-
"editor.formatOnSave": false,
|
|
15
|
-
"editor.formatOnPaste": false,
|
|
16
|
-
"editor.formatOnType": false,
|
|
17
|
-
"editor.codeActionsOnSave": {
|
|
18
|
-
"source.fixAll.eslint": true
|
|
19
|
-
},
|
|
20
|
-
"typescript.tsdk": "node_modules/typescript/lib"
|
|
21
|
-
},
|
|
22
|
-
// Add the IDs of extensions you want installed when the container is created.
|
|
23
|
-
"extensions": [
|
|
24
|
-
"EditorConfig.EditorConfig",
|
|
25
|
-
"esbenp.prettier-vscode",
|
|
26
|
-
"dbaeumer.vscode-eslint",
|
|
27
|
-
"Orta.vscode-jest"
|
|
28
|
-
],
|
|
29
|
-
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
|
30
|
-
// "forwardPorts": [],
|
|
31
|
-
// Use 'postCreateCommand' to run commands after the container is created.
|
|
32
|
-
"postCreateCommand": "yarn install",
|
|
33
|
-
// Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
|
|
34
|
-
"remoteUser": "node"
|
|
35
|
-
}
|
package/.eslintignore
DELETED