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/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "sample-ui-component-library",
3
- "version": "0.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 6006",
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
- "asp-react-component-library": "^0.0.9"
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"
@@ -32,7 +32,10 @@ export const MonacoInstance = ({editorContent}) => {
32
32
  theme="vs-dark"
33
33
  options={{
34
34
  scrollBeyondLastLine:false,
35
- fontSize:"12px"
35
+ fontSize:"12px",
36
+ minimap: {
37
+ enabled: false
38
+ }
36
39
  }}
37
40
  />
38
41
  );
@@ -109,9 +109,12 @@ export const Tabs = ({files, selectFile, systemTree}) => {
109
109
 
110
110
  useEffect(() => {
111
111
  if (files && files.length > 0) {
112
- setTabsList(files);
113
- setActiveTab(files[0].key);
114
- selectFile(files[0].key);
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 d-flex flex-column">
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="d-flex flex-grow-1">
74
+ <div className="monacoContainer">
75
75
  <MonacoInstance editorContent={editorContent}/>
76
76
  </div>
77
77
  </div>
@@ -1,5 +1,25 @@
1
1
  .viewerContainer {
2
- position: relative;
3
- width: 100%;
4
- height: 100%;
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
@@ -1,2 +1,3 @@
1
1
  export * from "./components/StackList";
2
- export * from "./components/Viewer";
2
+ export * from "./components/Viewer";
3
+ export * from "./components/FlowDiagram";
@@ -0,0 +1,7 @@
1
+ .rootTraceContainer {
2
+ position: absolute;
3
+ top:0;
4
+ bottom:0;
5
+ left:0;
6
+ right:0;
7
+ }
@@ -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
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "orientation":"TB",
3
+ "data":{
4
+ "branch1" : ["a","b","c","p"],
5
+ "branch2" : ["a","b","d","x"],
6
+ "branch3" : ["a","f","g","x"]
7
+ }
8
+ }