sample-ui-component-library 0.0.0-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/.storybook/main.js +22 -0
- package/.storybook/manager.js +6 -0
- package/.storybook/preview.js +13 -0
- package/LICENSE +201 -0
- package/README.md +37 -0
- package/babel.config.js +6 -0
- package/dist/cjs/index.js +47 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/esm/index.js +47 -0
- package/dist/esm/index.js.map +1 -0
- package/package.json +72 -0
- package/rollup.config.mjs +37 -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 +59 -0
- package/src/components/FlowDiagram/index.js +1 -0
- package/src/components/StackList/StackList.jsx +92 -0
- package/src/components/StackList/StackList.scss +51 -0
- package/src/components/StackList/index.js +1 -0
- package/src/components/Viewer/MonacoInstance/MonacoInstance.jsx +46 -0
- package/src/components/Viewer/MonacoInstance/MonacoInstance.scss +0 -0
- package/src/components/Viewer/Tabs/Tab/Tab.jsx +51 -0
- package/src/components/Viewer/Tabs/Tab/Tab.scss +21 -0
- package/src/components/Viewer/Tabs/Tabs.jsx +159 -0
- package/src/components/Viewer/Tabs/Tabs.scss +50 -0
- package/src/components/Viewer/Viewer.jsx +84 -0
- package/src/components/Viewer/Viewer.scss +25 -0
- package/src/components/Viewer/index.js +1 -0
- package/src/index.js +3 -0
- package/src/stories/FlowDiagram.scss +7 -0
- package/src/stories/FlowDiagram.stories.js +29 -0
- package/src/stories/StackList.stories.js +89 -0
- package/src/stories/StackListStories.scss +13 -0
- package/src/stories/Viewer.stories.js +40 -0
- package/src/stories/ViewerStories.scss +7 -0
- package/src/stories/data/filetree.json +1 -0
- package/src/stories/data/flow/SampleTree.json +8 -0
package/package.json
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "sample-ui-component-library",
|
|
3
|
+
"version": "0.0.0-beta",
|
|
4
|
+
"description": "A library which contains sample UI elements that can be used for populating layouts.",
|
|
5
|
+
"main": "dist/cjs/index.js",
|
|
6
|
+
"module": "dist/esm/index.js",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
9
|
+
"storybook": "storybook dev -p 6007",
|
|
10
|
+
"build-storybook": "storybook build",
|
|
11
|
+
"build": "rollup -c",
|
|
12
|
+
"predeploy": "npm run build-storybook",
|
|
13
|
+
"deploy-storybook": "gh-pages -d storybook-static"
|
|
14
|
+
},
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/vishalpalaniappan/sample-ui-component-library.git"
|
|
18
|
+
},
|
|
19
|
+
"author": "Vishal Palaniappan",
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"bugs": {
|
|
22
|
+
"url": "https://github.com/vishalpalaniappan/sample-ui-component-library/issues"
|
|
23
|
+
},
|
|
24
|
+
"homepage": "https://github.com/vishalpalaniappan/sample-ui-component-library.git",
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@babel/core": "^7.26.10",
|
|
27
|
+
"@babel/preset-env": "^7.26.9",
|
|
28
|
+
"@babel/preset-react": "^7.26.3",
|
|
29
|
+
"@chromatic-com/storybook": "^3.2.6",
|
|
30
|
+
"@rollup/plugin-babel": "^6.0.4",
|
|
31
|
+
"@rollup/plugin-commonjs": "^28.0.3",
|
|
32
|
+
"@rollup/plugin-json": "^6.1.0",
|
|
33
|
+
"@rollup/plugin-node-resolve": "^16.0.1",
|
|
34
|
+
"@rollup/plugin-terser": "^0.4.4",
|
|
35
|
+
"@storybook/addon-actions": "^8.6.11",
|
|
36
|
+
"@storybook/addon-essentials": "^8.6.8",
|
|
37
|
+
"@storybook/addon-interactions": "^8.6.8",
|
|
38
|
+
"@storybook/addon-onboarding": "^8.6.8",
|
|
39
|
+
"@storybook/addon-webpack5-compiler-swc": "^3.0.0",
|
|
40
|
+
"@storybook/blocks": "^8.6.8",
|
|
41
|
+
"@storybook/manager-api": "^8.6.11",
|
|
42
|
+
"@storybook/preset-scss": "^1.0.3",
|
|
43
|
+
"@storybook/react": "^8.6.8",
|
|
44
|
+
"@storybook/react-webpack5": "^8.6.8",
|
|
45
|
+
"@storybook/test": "^8.6.11",
|
|
46
|
+
"@storybook/theming": "^8.6.11",
|
|
47
|
+
"css-loader": "^7.1.2",
|
|
48
|
+
"gh-pages": "^6.3.0",
|
|
49
|
+
"prop-types": "^15.8.1",
|
|
50
|
+
"react": "^18.2.0",
|
|
51
|
+
"react-dom": "^18.2.0",
|
|
52
|
+
"rollup": "^4.37.0",
|
|
53
|
+
"rollup-plugin-peer-deps-external": "^2.2.4",
|
|
54
|
+
"rollup-plugin-postcss": "^4.0.2",
|
|
55
|
+
"sass": "^1.86.0",
|
|
56
|
+
"sass-loader": "^16.0.5",
|
|
57
|
+
"storybook": "^8.6.8",
|
|
58
|
+
"style-loader": "^4.0.0"
|
|
59
|
+
},
|
|
60
|
+
"peerDependencies": {
|
|
61
|
+
"react": "^18.2.0",
|
|
62
|
+
"react-dom": "^18.2.0"
|
|
63
|
+
},
|
|
64
|
+
"dependencies": {
|
|
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"
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import resolve from '@rollup/plugin-node-resolve';
|
|
2
|
+
import commonjs from '@rollup/plugin-commonjs';
|
|
3
|
+
import terser from '@rollup/plugin-terser';
|
|
4
|
+
import external from 'rollup-plugin-peer-deps-external';
|
|
5
|
+
import postcss from 'rollup-plugin-postcss';
|
|
6
|
+
import json from '@rollup/plugin-json';
|
|
7
|
+
import { babel } from '@rollup/plugin-babel';
|
|
8
|
+
|
|
9
|
+
export default {
|
|
10
|
+
input: 'src/index.js',
|
|
11
|
+
output: [
|
|
12
|
+
{
|
|
13
|
+
file: 'dist/cjs/index.js',
|
|
14
|
+
format: 'cjs',
|
|
15
|
+
sourcemap: true
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
file: 'dist/esm/index.js',
|
|
19
|
+
format: 'esm',
|
|
20
|
+
sourcemap: true,
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
plugins: [
|
|
24
|
+
external(['react', 'react-dom']),
|
|
25
|
+
resolve({
|
|
26
|
+
extensions: ['.js', '.jsx'],
|
|
27
|
+
}),
|
|
28
|
+
postcss(),
|
|
29
|
+
terser(),
|
|
30
|
+
babel({
|
|
31
|
+
babelHelpers: 'bundled',
|
|
32
|
+
exclude: 'node_modules/**',
|
|
33
|
+
}),
|
|
34
|
+
commonjs(),
|
|
35
|
+
json()
|
|
36
|
+
]
|
|
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);
|
|
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,59 @@
|
|
|
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
|
|
18
|
+
* @returns {Array} An array co
|
|
19
|
+
*/
|
|
20
|
+
export const getLayoutInfoFromTree = (tree) => {
|
|
21
|
+
const edges = [];
|
|
22
|
+
const nodes = [];
|
|
23
|
+
Object.keys(tree).forEach((branchName, index1) => {
|
|
24
|
+
tree[branchName].forEach((node, index) => {
|
|
25
|
+
|
|
26
|
+
// Position doesn't matter, it will be set by layout algorithm
|
|
27
|
+
const flowNode = {
|
|
28
|
+
id: node,
|
|
29
|
+
flowId: node,
|
|
30
|
+
position: { x: 250, y: index * 200 },
|
|
31
|
+
data: { label: String(node) }
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (index == 0) {
|
|
35
|
+
flowNode.type = "input"
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (index > 0) {
|
|
39
|
+
const prevNode = nodes[nodes.length-1]
|
|
40
|
+
const edge = {
|
|
41
|
+
id: prevNode.flowId + "-" + branchName + "-" + index + "-" + flowNode.flowId,
|
|
42
|
+
source: prevNode.flowId,
|
|
43
|
+
target: flowNode.flowId,
|
|
44
|
+
animated: true,
|
|
45
|
+
markerEnd: marker,
|
|
46
|
+
style: arrowStyle
|
|
47
|
+
}
|
|
48
|
+
edges.push(edge);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
nodes.push(flowNode);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
nodes: nodes,
|
|
57
|
+
edges: edges
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./FlowDiagram.jsx"
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import "./StackList.scss";
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
|
|
4
|
+
const ROW_STYLE = {
|
|
5
|
+
SELECTED: "#184b2d",
|
|
6
|
+
EXCEPTION: "#420b0e",
|
|
7
|
+
SELECTED_TOP: "#4b4b18"
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Renders a row in the stack list component.
|
|
12
|
+
*
|
|
13
|
+
* @param {Number} index
|
|
14
|
+
* @param {String} functionName
|
|
15
|
+
* @param {String} fileName
|
|
16
|
+
* @param {Number} lineNumber
|
|
17
|
+
* @param {Boolean} selected
|
|
18
|
+
* @param {Function} selectTraceItem
|
|
19
|
+
* @param {Boolean} hasException
|
|
20
|
+
* @return {JSX}
|
|
21
|
+
*/
|
|
22
|
+
const StackRow = ({index, functionName, fileName, lineNumber, selected, selectTraceItem, hasException}) => {
|
|
23
|
+
|
|
24
|
+
let style = {};
|
|
25
|
+
if (selected && index === 0) {
|
|
26
|
+
// Style for top of stack
|
|
27
|
+
style = {backgroundColor: hasException ? ROW_STYLE.EXCEPTION : ROW_STYLE.SELECTED_TOP};
|
|
28
|
+
} else if (selected) {
|
|
29
|
+
// Style for rest of stack
|
|
30
|
+
style = {backgroundColor: hasException ? ROW_STYLE.EXCEPTION : ROW_STYLE.SELECTED};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<div className="stackRow" style={style} onClick={(e) => selectTraceItem(index)}>
|
|
35
|
+
<div className="left">
|
|
36
|
+
<span className="functionName">{functionName}</span>
|
|
37
|
+
</div>
|
|
38
|
+
<div className="right">
|
|
39
|
+
<span className="fileName">{fileName}</span>
|
|
40
|
+
<span className="lineNumber">{lineNumber}:1</span>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
StackRow.propTypes = {
|
|
47
|
+
index: PropTypes.number,
|
|
48
|
+
functionName: PropTypes.string,
|
|
49
|
+
fileName: PropTypes.string,
|
|
50
|
+
lineNumber: PropTypes.number,
|
|
51
|
+
selected: PropTypes.bool,
|
|
52
|
+
selectTraceItem: PropTypes.func,
|
|
53
|
+
hasException: PropTypes.bool,
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Renders the stack list component.
|
|
58
|
+
*
|
|
59
|
+
* @param {Array} traces
|
|
60
|
+
* @param {Function} selectTraceItem
|
|
61
|
+
* @return {JSX}
|
|
62
|
+
*/
|
|
63
|
+
export const StackList = ({traces, selectTraceItem}) => {
|
|
64
|
+
|
|
65
|
+
const generateStackList = () => {
|
|
66
|
+
const traceList = traces.map((trace, index) => {
|
|
67
|
+
return <StackRow
|
|
68
|
+
key={`${trace.fileName}-${trace.lineNumber}-${trace.functionName}-${index}`}
|
|
69
|
+
functionName={trace.functionName}
|
|
70
|
+
fileName={trace.fileName}
|
|
71
|
+
lineNumber={trace.lineNumber}
|
|
72
|
+
selected={trace.selected}
|
|
73
|
+
hasException={trace.hasException}
|
|
74
|
+
index={index}
|
|
75
|
+
selectTraceItem={selectTraceItem}
|
|
76
|
+
/>
|
|
77
|
+
}
|
|
78
|
+
);
|
|
79
|
+
return traceList;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return (
|
|
83
|
+
<div className="stackContainer">
|
|
84
|
+
{generateStackList()}
|
|
85
|
+
</div>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
StackList.propTypes = {
|
|
90
|
+
traces: PropTypes.array,
|
|
91
|
+
selectTraceItem: PropTypes.func,
|
|
92
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
.stackContainer {
|
|
4
|
+
width: 100%;
|
|
5
|
+
height: 100%;
|
|
6
|
+
overflow-y: auto;
|
|
7
|
+
scrollbar-gutter: stable;
|
|
8
|
+
scrollbar-color: rgba(71, 71, 71, .4) #252526;
|
|
9
|
+
scrollbar-width: thin;
|
|
10
|
+
font-size: 13px;
|
|
11
|
+
font-family:'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.stackRow {
|
|
15
|
+
display: flex;
|
|
16
|
+
justify-content: space-between;
|
|
17
|
+
height: 30px;
|
|
18
|
+
align-items: center;
|
|
19
|
+
color:white;
|
|
20
|
+
padding: 0 20px;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.stackRow:hover {
|
|
24
|
+
cursor: pointer;
|
|
25
|
+
background-color: #2a2d2e;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.stackRow > .left {
|
|
29
|
+
display: flex;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.stackRow > .right {
|
|
33
|
+
display: flex;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.functionName {
|
|
37
|
+
color: #fff;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.fileName {
|
|
41
|
+
color: #ccc;
|
|
42
|
+
font-size:11px;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.lineNumber {
|
|
46
|
+
background:#4d4d4d;
|
|
47
|
+
color:#b0ccc3;
|
|
48
|
+
border-radius:5px;
|
|
49
|
+
margin-left:10px;
|
|
50
|
+
padding:0px 5px;
|
|
51
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./StackList.jsx"
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import React, { useEffect, useRef, useState } from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
|
|
4
|
+
import Editor from '@monaco-editor/react';
|
|
5
|
+
|
|
6
|
+
import "./MonacoInstance.scss"
|
|
7
|
+
|
|
8
|
+
export const MonacoInstance = ({editorContent}) => {
|
|
9
|
+
const editorRef = useRef(null);
|
|
10
|
+
|
|
11
|
+
const content = useRef();
|
|
12
|
+
|
|
13
|
+
const handleEditorDidMount = (editor, monaco) => {
|
|
14
|
+
editorRef.current = editor;
|
|
15
|
+
if(content?.current) {
|
|
16
|
+
editorRef.current.setValue(content.current);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
content.current = editorContent;
|
|
22
|
+
if (editorRef?.current && content.current) {
|
|
23
|
+
editorRef.current.setValue(content.current);
|
|
24
|
+
}
|
|
25
|
+
}, [editorContent]);
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<Editor
|
|
29
|
+
defaultLanguage="python"
|
|
30
|
+
defaultValue=""
|
|
31
|
+
onMount={handleEditorDidMount}
|
|
32
|
+
theme="vs-dark"
|
|
33
|
+
options={{
|
|
34
|
+
scrollBeyondLastLine:false,
|
|
35
|
+
fontSize:"12px",
|
|
36
|
+
minimap: {
|
|
37
|
+
enabled: false
|
|
38
|
+
}
|
|
39
|
+
}}
|
|
40
|
+
/>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
MonacoInstance.propTypes = {
|
|
45
|
+
editorContent: PropTypes.string,
|
|
46
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import "./Tab.scss";
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
|
|
4
|
+
import { X } from "react-bootstrap-icons";
|
|
5
|
+
|
|
6
|
+
const tabColors = {
|
|
7
|
+
active: "#1e1e1e",
|
|
8
|
+
disabled: "#2d2d2d"
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Renders the tab component.
|
|
13
|
+
*
|
|
14
|
+
* The tab component displays the file name and an option
|
|
15
|
+
* to close a tab. It also sets the style for the active tab.
|
|
16
|
+
*
|
|
17
|
+
* @return {JSX}
|
|
18
|
+
*/
|
|
19
|
+
export const Tab = ({file, activeTab, selectTab, closeTab}) => {
|
|
20
|
+
|
|
21
|
+
const getTabStyle = () => {
|
|
22
|
+
return {
|
|
23
|
+
backgroundColor: (activeTab === file.key)?tabColors.active:tabColors.disabled
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<div onClick={(e) => selectTab(e, file)} className="tab" style={getTabStyle()}>
|
|
29
|
+
<div className="fileName">
|
|
30
|
+
{file.fileName}
|
|
31
|
+
</div>
|
|
32
|
+
<div className="close" onClick={(e) => {
|
|
33
|
+
e.stopPropagation();
|
|
34
|
+
closeTab(e, file);
|
|
35
|
+
}}>
|
|
36
|
+
<X style={{color:"white"}}/>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
Tab.propTypes = {
|
|
43
|
+
file: PropTypes.shape({
|
|
44
|
+
key: PropTypes.string.isRequired,
|
|
45
|
+
fileName: PropTypes.oneOfType([PropTypes.string, PropTypes.array]).isRequired,
|
|
46
|
+
path: PropTypes.string
|
|
47
|
+
}).isRequired,
|
|
48
|
+
activeTab: PropTypes.string.isRequired,
|
|
49
|
+
selectTab: PropTypes.func.isRequired,
|
|
50
|
+
closeTab: PropTypes.func.isRequired
|
|
51
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
.tab {
|
|
2
|
+
height: 100%;
|
|
3
|
+
display:flex;
|
|
4
|
+
justify-content: center;
|
|
5
|
+
align-items: center;
|
|
6
|
+
padding: 0 5px 0 10px;
|
|
7
|
+
margin-right:2px;
|
|
8
|
+
cursor: default;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.fileName {
|
|
12
|
+
font-family: sans-serif;
|
|
13
|
+
font-size: 12px;
|
|
14
|
+
padding-right: 5px;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.close {
|
|
18
|
+
display:flex;
|
|
19
|
+
float:right;
|
|
20
|
+
cursor:pointer;
|
|
21
|
+
}
|