sample-ui-component-library 0.0.0 → 0.0.2-beta
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/README.md +2 -2
- package/dist/cjs/index.js +31 -4
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/index.js +31 -4
- package/dist/esm/index.js.map +1 -1
- package/package.json +12 -6
- package/rollup.config.mjs +2 -0
- package/src/components/FlowDiagram/DagreLayout.js +33 -0
- package/src/components/FlowDiagram/FlowDiagram.jsx +64 -0
- package/src/components/FlowDiagram/FlowDiagram.scss +0 -0
- package/src/components/FlowDiagram/helper.js +60 -0
- package/src/components/FlowDiagram/index.js +1 -0
- package/src/components/Viewer/MonacoInstance/MonacoInstance.jsx +4 -1
- package/src/components/Viewer/Tabs/Tabs.jsx +6 -3
- package/src/components/Viewer/Viewer.jsx +3 -3
- package/src/components/Viewer/Viewer.scss +23 -3
- package/src/index.js +2 -1
- package/src/stories/FlowDiagram.scss +7 -0
- package/src/stories/FlowDiagram.stories.js +29 -0
- package/src/stories/data/flow/SampleTree.json +8 -0
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sample-ui-component-library",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2-beta",
|
|
4
4
|
"description": "A library which contains sample UI elements that can be used for populating layouts.",
|
|
5
5
|
"main": "dist/cjs/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
9
|
-
"storybook": "storybook dev -p
|
|
9
|
+
"storybook": "storybook dev -p 6007",
|
|
10
10
|
"build-storybook": "storybook build",
|
|
11
11
|
"build": "rollup -c",
|
|
12
12
|
"predeploy": "npm run build-storybook",
|
|
@@ -14,14 +14,14 @@
|
|
|
14
14
|
},
|
|
15
15
|
"repository": {
|
|
16
16
|
"type": "git",
|
|
17
|
-
"url": "git+https://github.com/vishalpalaniappan/sample-component-library.git"
|
|
17
|
+
"url": "git+https://github.com/vishalpalaniappan/sample-ui-component-library.git"
|
|
18
18
|
},
|
|
19
19
|
"author": "Vishal Palaniappan",
|
|
20
20
|
"license": "MIT",
|
|
21
21
|
"bugs": {
|
|
22
|
-
"url": "https://github.com/vishalpalaniappan/sample-component-library/issues"
|
|
22
|
+
"url": "https://github.com/vishalpalaniappan/sample-ui-component-library/issues"
|
|
23
23
|
},
|
|
24
|
-
"homepage": "https://github.com/vishalpalaniappan/sample-component-library.git",
|
|
24
|
+
"homepage": "https://github.com/vishalpalaniappan/sample-ui-component-library.git",
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"@babel/core": "^7.26.10",
|
|
27
27
|
"@babel/preset-env": "^7.26.9",
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"@chromatic-com/storybook": "^3.2.6",
|
|
30
30
|
"@rollup/plugin-babel": "^6.0.4",
|
|
31
31
|
"@rollup/plugin-commonjs": "^28.0.3",
|
|
32
|
+
"@rollup/plugin-json": "^6.1.0",
|
|
32
33
|
"@rollup/plugin-node-resolve": "^16.0.1",
|
|
33
34
|
"@rollup/plugin-terser": "^0.4.4",
|
|
34
35
|
"@storybook/addon-actions": "^8.6.11",
|
|
@@ -61,6 +62,11 @@
|
|
|
61
62
|
"react-dom": "^18.2.0"
|
|
62
63
|
},
|
|
63
64
|
"dependencies": {
|
|
64
|
-
"
|
|
65
|
+
"@dagrejs/dagre": "^1.1.4",
|
|
66
|
+
"@monaco-editor/react": "^4.7.0",
|
|
67
|
+
"@xyflow/react": "^12.6.0",
|
|
68
|
+
"bootstrap": "^5.3.4",
|
|
69
|
+
"react-bootstrap": "^2.10.9",
|
|
70
|
+
"react-bootstrap-icons": "^1.11.5"
|
|
65
71
|
}
|
|
66
72
|
}
|
package/rollup.config.mjs
CHANGED
|
@@ -3,6 +3,7 @@ import commonjs from '@rollup/plugin-commonjs';
|
|
|
3
3
|
import terser from '@rollup/plugin-terser';
|
|
4
4
|
import external from 'rollup-plugin-peer-deps-external';
|
|
5
5
|
import postcss from 'rollup-plugin-postcss';
|
|
6
|
+
import json from '@rollup/plugin-json';
|
|
6
7
|
import { babel } from '@rollup/plugin-babel';
|
|
7
8
|
|
|
8
9
|
export default {
|
|
@@ -31,5 +32,6 @@ export default {
|
|
|
31
32
|
exclude: 'node_modules/**',
|
|
32
33
|
}),
|
|
33
34
|
commonjs(),
|
|
35
|
+
json()
|
|
34
36
|
]
|
|
35
37
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
|
|
2
|
+
import Dagre from '@dagrejs/dagre';
|
|
3
|
+
|
|
4
|
+
export const getLayoutedElements = (nodes, edges, options) => {
|
|
5
|
+
// Reference: https://reactflow.dev/learn/layouting/layouting
|
|
6
|
+
|
|
7
|
+
const g = new Dagre.graphlib.Graph().setDefaultEdgeLabel(() => ({}));
|
|
8
|
+
g.setGraph({ rankdir: options.direction, ranksep: 100, nodesep: 170});
|
|
9
|
+
|
|
10
|
+
edges.forEach((edge) => g.setEdge(edge.source, edge.target));
|
|
11
|
+
nodes.forEach((node) =>
|
|
12
|
+
g.setNode(node.id, {
|
|
13
|
+
...node,
|
|
14
|
+
width: node.measured?.width ?? 0,
|
|
15
|
+
height: node.measured?.height ?? 0,
|
|
16
|
+
}),
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
Dagre.layout(g);
|
|
20
|
+
|
|
21
|
+
return {
|
|
22
|
+
nodes: nodes.map((node) => {
|
|
23
|
+
const position = g.node(node.id);
|
|
24
|
+
// We are shifting the dagre node position (anchor=center center) to the top left
|
|
25
|
+
// so it matches the React Flow node anchor point (top left).
|
|
26
|
+
const x = position.x - (node.measured?.width ?? 0) / 2;
|
|
27
|
+
const y = position.y - (node.measured?.height ?? 0) / 2;
|
|
28
|
+
|
|
29
|
+
return { ...node, position: { x, y } };
|
|
30
|
+
}),
|
|
31
|
+
edges,
|
|
32
|
+
};
|
|
33
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { useCallback, useEffect, useState } from "react";
|
|
2
|
+
import {
|
|
3
|
+
ReactFlow,
|
|
4
|
+
ReactFlowProvider,
|
|
5
|
+
useNodesState,
|
|
6
|
+
useEdgesState,
|
|
7
|
+
Controls,
|
|
8
|
+
useReactFlow
|
|
9
|
+
} from "@xyflow/react";
|
|
10
|
+
import "@xyflow/react/dist/style.css";
|
|
11
|
+
|
|
12
|
+
import { getLayoutedElements } from "./DagreLayout.js";
|
|
13
|
+
import { getLayoutInfoFromTree } from "./helper.js"
|
|
14
|
+
|
|
15
|
+
const Flow = ({tree}) => {
|
|
16
|
+
const { fitView } = useReactFlow();
|
|
17
|
+
const [nodes, setNodes, onNodesChange] = useNodesState([]);
|
|
18
|
+
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
|
|
19
|
+
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
if (tree) {
|
|
22
|
+
const flowInfo = getLayoutInfoFromTree(tree.data, tree.animated ?? false);
|
|
23
|
+
|
|
24
|
+
//direction: TB, BT, LR, or RL, where T = top, B = bottom, L = left, and R = right.
|
|
25
|
+
const layouted = getLayoutedElements(
|
|
26
|
+
flowInfo.nodes,
|
|
27
|
+
flowInfo.edges,
|
|
28
|
+
{direction:tree.orientation}
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
setNodes([...layouted.nodes]);
|
|
32
|
+
setEdges([...layouted.edges]);
|
|
33
|
+
|
|
34
|
+
fitView();
|
|
35
|
+
}
|
|
36
|
+
}, [tree]);
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<ReactFlow
|
|
40
|
+
nodes={nodes}
|
|
41
|
+
edges={edges}
|
|
42
|
+
onNodesChange={onNodesChange}
|
|
43
|
+
onEdgesChange={onEdgesChange}
|
|
44
|
+
colorMode={"dark"}
|
|
45
|
+
fitView
|
|
46
|
+
>
|
|
47
|
+
<Controls />
|
|
48
|
+
</ReactFlow>
|
|
49
|
+
);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export const FlowDiagram = ({treeInfo}) => {
|
|
53
|
+
const [tree, setTree] = useState();
|
|
54
|
+
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
setTree(treeInfo)
|
|
57
|
+
}, [treeInfo])
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<ReactFlowProvider>
|
|
61
|
+
<Flow tree={tree} />
|
|
62
|
+
</ReactFlowProvider>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { MarkerType } from "@xyflow/react";
|
|
2
|
+
|
|
3
|
+
const marker = {
|
|
4
|
+
type: MarkerType.ArrowClosed,
|
|
5
|
+
width: 20,
|
|
6
|
+
height: 20,
|
|
7
|
+
color: '#FF0072',
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const arrowStyle = {
|
|
11
|
+
strokeWidth: 2,
|
|
12
|
+
stroke: '#FF0072',
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Returns react flow nodes and edges from the given tree.
|
|
17
|
+
* @param {Object} tree Layout tree object.
|
|
18
|
+
* @param {boolean} animated Indicates if the edges should be animated.
|
|
19
|
+
* @returns {Array} An object containing nodes and edges arrays.
|
|
20
|
+
*/
|
|
21
|
+
export const getLayoutInfoFromTree = (tree, animated) => {
|
|
22
|
+
const edges = [];
|
|
23
|
+
const nodes = [];
|
|
24
|
+
Object.keys(tree).forEach((branchName, index1) => {
|
|
25
|
+
tree[branchName].forEach((node, index) => {
|
|
26
|
+
|
|
27
|
+
// Position doesn't matter, it will be set by layout algorithm
|
|
28
|
+
const flowNode = {
|
|
29
|
+
id: node,
|
|
30
|
+
flowId: node,
|
|
31
|
+
position: { x: 250, y: index * 200 },
|
|
32
|
+
data: { label: String(node) }
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (index == 0) {
|
|
36
|
+
flowNode.type = "input"
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (index > 0) {
|
|
40
|
+
const prevNode = nodes[nodes.length-1]
|
|
41
|
+
const edge = {
|
|
42
|
+
id: prevNode.flowId + "-" + branchName + "-" + index + "-" + flowNode.flowId,
|
|
43
|
+
source: prevNode.flowId,
|
|
44
|
+
target: flowNode.flowId,
|
|
45
|
+
animated: animated,
|
|
46
|
+
markerEnd: marker,
|
|
47
|
+
style: arrowStyle
|
|
48
|
+
}
|
|
49
|
+
edges.push(edge);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
nodes.push(flowNode);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
nodes: nodes,
|
|
58
|
+
edges: edges
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./FlowDiagram.jsx"
|
|
@@ -109,9 +109,12 @@ export const Tabs = ({files, selectFile, systemTree}) => {
|
|
|
109
109
|
|
|
110
110
|
useEffect(() => {
|
|
111
111
|
if (files && files.length > 0) {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
112
|
+
const numFiles = Math.floor(Math.random() * files.length) + 1;
|
|
113
|
+
const newFiles = files.slice(0, numFiles);
|
|
114
|
+
setTabsList(newFiles);
|
|
115
|
+
const randomFileIndex = Math.floor(Math.random() * newFiles.length);
|
|
116
|
+
setActiveTab(newFiles[randomFileIndex].key);
|
|
117
|
+
selectFile(newFiles[randomFileIndex].key);
|
|
115
118
|
}
|
|
116
119
|
}, [files]);
|
|
117
120
|
|
|
@@ -67,11 +67,11 @@ export const Viewer = ({systemTree, onFileSelect}) => {
|
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
return (
|
|
70
|
-
<div className="viewerContainer
|
|
71
|
-
<div>
|
|
70
|
+
<div className="viewerContainer">
|
|
71
|
+
<div className="tabContainer">
|
|
72
72
|
<Tabs files={files} selectFile={selectFile} systemTree={systemTree}/>
|
|
73
73
|
</div>
|
|
74
|
-
<div className="
|
|
74
|
+
<div className="monacoContainer">
|
|
75
75
|
<MonacoInstance editorContent={editorContent}/>
|
|
76
76
|
</div>
|
|
77
77
|
</div>
|
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
.viewerContainer {
|
|
2
|
-
position:
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
position: absolute;
|
|
3
|
+
top: 0;
|
|
4
|
+
left: 0;
|
|
5
|
+
bottom: 0;
|
|
6
|
+
right:0;
|
|
7
|
+
overflow:hidden;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.tabContainer{
|
|
11
|
+
position: absolute;
|
|
12
|
+
top: 0;
|
|
13
|
+
left: 0;
|
|
14
|
+
bottom: 40px;
|
|
15
|
+
right:0;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.monacoContainer{
|
|
19
|
+
position: absolute;
|
|
20
|
+
top: 40px;
|
|
21
|
+
left: 0;
|
|
22
|
+
bottom: 0;
|
|
23
|
+
right:0;
|
|
24
|
+
|
|
5
25
|
}
|
package/src/index.js
CHANGED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { FlowDiagram } from "../components/FlowDiagram";
|
|
2
|
+
import "./FlowDiagram.scss"
|
|
3
|
+
|
|
4
|
+
import sampleTree from "./data/flow/SampleTree.json";
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
title: 'FlowDiagram',
|
|
8
|
+
component: FlowDiagram,
|
|
9
|
+
argTypes: {
|
|
10
|
+
treeInfo: {
|
|
11
|
+
type: 'array'
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const Template = (args) => {
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<div className="rootTraceContainer">
|
|
20
|
+
<FlowDiagram {...args}/>
|
|
21
|
+
</div>
|
|
22
|
+
)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const Default = Template.bind({})
|
|
26
|
+
|
|
27
|
+
Default.args = {
|
|
28
|
+
treeInfo: sampleTree
|
|
29
|
+
}
|