sample-ui-component-library 0.0.17-dev → 0.0.23-dev

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,6 +1,6 @@
1
1
  {
2
2
  "name": "sample-ui-component-library",
3
- "version": "0.0.17-dev",
3
+ "version": "0.0.23-dev",
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",
@@ -68,8 +68,6 @@
68
68
  "@dagrejs/dagre": "^1.1.4",
69
69
  "@monaco-editor/react": "^4.7.0",
70
70
  "@xyflow/react": "^12.6.0",
71
- "bootstrap": "^5.3.4",
72
- "react-bootstrap": "^2.10.9",
73
71
  "react-bootstrap-icons": "^1.11.5"
74
72
  }
75
73
  }
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
3
3
 
4
4
  import { MonacoInstance } from "./MonacoInstance/MonacoInstance";
5
5
  import { Tabs } from "./Tabs/Tabs";
6
- import { TabPreview } from "./Tabs/Tab/Tab";
6
+
7
7
  import React, {
8
8
  forwardRef,
9
9
  useCallback,
@@ -42,19 +42,10 @@ export const Editor = forwardRef(({ }, ref) => {
42
42
  }, []);
43
43
 
44
44
  const setTabGroupId = useCallback((id) => {
45
+ dispatch({ type: "RESET_STATE"});
45
46
  dispatch({ type: "SET_PARENT_TAB_GROUP_ID", payload: id });
46
47
  }, []);
47
48
 
48
- const getPreviewElement = useCallback((tabId) => {
49
- // Get the preview element for a tab by its id for use in drag-and-drop operations.
50
- const tab = state.tabs.find(t => t.uid === tabId);
51
- if (!tab) {
52
- console.error(`getPreviewElement: tab with id ${tabId} not found.`);
53
- return null;
54
- }
55
- return <TabPreview info={{ label: tab.name }} />;
56
- }, [state]);
57
-
58
49
  const api = useMemo(() => {
59
50
  return {
60
51
  state,
@@ -62,10 +53,9 @@ export const Editor = forwardRef(({ }, ref) => {
62
53
  setTabGroupId,
63
54
  selectTab,
64
55
  closeTab,
65
- moveTab,
66
- getPreviewElement
56
+ moveTab
67
57
  };
68
- }, [state, addTab, selectTab, closeTab, moveTab, getPreviewElement, setTabGroupId]);
58
+ }, [state, addTab, selectTab, closeTab, moveTab, setTabGroupId]);
69
59
 
70
60
  useImperativeHandle(ref, () => api, [api]);
71
61
 
@@ -98,6 +98,10 @@ export const editorReducer = (state, action) => {
98
98
  tabs: prevTabs
99
99
  };
100
100
  }
101
+
102
+ case "RESET_STATE": {
103
+ return initialState;
104
+ }
101
105
 
102
106
  default: {
103
107
  return state;
@@ -24,6 +24,7 @@ export const FileBrowser = forwardRef(({onSelectFile}, ref) => {
24
24
  const [state, dispatch] = useReducer(fileBrowserReducer, initialState);
25
25
 
26
26
  const addFileTree = useCallback((tree) => {
27
+ dispatch({ type: "RESET_STATE"});
27
28
  dispatch({ type: "ADD_FILE_TREE", payload: tree });
28
29
  }, []);
29
30
 
@@ -1,8 +1,4 @@
1
- import {
2
- setDefaultCollapsed,
3
- collapseTree,
4
- flattenTree,
5
- } from "./helper";
1
+ import { setDefaultCollapsed, collapseTree, flattenTree } from "./helper";
6
2
 
7
3
  //TODO: I should set a unique id for each reducer state and use it
8
4
  // for all the ids of the components to make them unique. I could
@@ -15,9 +11,7 @@ export const initialState = {
15
11
  };
16
12
 
17
13
  export const fileBrowserReducer = (state, action) => {
18
-
19
14
  switch (action.type) {
20
-
21
15
  case "ADD_FILE_TREE": {
22
16
  let flattenedTree = setDefaultCollapsed(flattenTree(action.payload));
23
17
  const collapsedTree = collapseTree(flattenedTree);
@@ -25,29 +19,34 @@ export const fileBrowserReducer = (state, action) => {
25
19
  ...state,
26
20
  tree: action.payload,
27
21
  flattenedTree: flattenedTree,
28
- collapsedTree: collapsedTree
29
- }
22
+ collapsedTree: collapsedTree,
23
+ };
30
24
  }
31
25
 
32
26
  case "SELECT_NODE": {
33
- const tree = [...state.flattenedTree];
34
- let selectedNode;
35
- tree.forEach((n) => {
36
- if (n.uid === action.payload) {
37
- selectedNode = n;
38
- n.selected = true;
39
- n.collapsed = !n.collapsed;
40
- } else {
41
- n.selected = false;
27
+ const tree = state.flattenedTree.map((n) => {
28
+ if (n.uid === action.payload.uid) {
29
+ return {
30
+ ...n,
31
+ selected: true,
32
+ collapsed: !n.collapsed,
33
+ };
42
34
  }
35
+ return {
36
+ ...n,
37
+ selected: false,
38
+ };
43
39
  });
44
- const collapsedTree = collapseTree(tree);
45
40
  return {
46
41
  ...state,
47
42
  flattenedTree: tree,
48
- collapsedTree: collapsedTree,
49
- selectedNode: selectedNode
50
- }
43
+ collapsedTree: collapseTree(tree),
44
+ selectedNode: action.payload,
45
+ };
46
+ }
47
+
48
+ case "RESET_STATE": {
49
+ return initialState;
51
50
  }
52
51
  }
53
- }
52
+ };
@@ -1,33 +0,0 @@
1
- .file-node-row{
2
- width:100%;
3
- min-width: 200px;
4
- display:flex;
5
- padding: 5px 0;
6
- font-size:13px;
7
- font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
8
- cursor: pointer;
9
- }
10
-
11
- .indent {
12
- height:100%;
13
- }
14
-
15
- .center {
16
- display:flex;
17
- align-self: center;
18
- }
19
-
20
-
21
- .folder-icon {
22
- display:flex;
23
- margin-right: 5px;
24
- }
25
-
26
- .file-icon {
27
- margin-right: 5px;
28
- font-size:16px;
29
- }
30
-
31
- .file-name {
32
- color: #CCC;
33
- }
@@ -10,6 +10,7 @@ const INDENT_WIDTH = 20;
10
10
  const SELECTED_FILE_COLOR = "#00426b";
11
11
 
12
12
  import "./TreeNode.scss";
13
+ import { useCallback } from "react";
13
14
 
14
15
  /**
15
16
  * Renders a single node in the file tree.
@@ -50,7 +51,6 @@ export const TreeNode = ({ id, node }) => {
50
51
  return style;
51
52
  }
52
53
 
53
-
54
54
  /**
55
55
  * Get the file icon based on the extension.
56
56
  *
@@ -72,14 +72,13 @@ export const TreeNode = ({ id, node }) => {
72
72
  }
73
73
  }
74
74
 
75
-
76
- const onSelectRow = () => {
77
- selectNode(node.uid);
78
- }
75
+ const onSelectRow = useCallback(() => {
76
+ selectNode(node);
77
+ }, [selectNode]);
79
78
 
80
79
  return (
81
80
  <div className="file-node-row" ref={setNodeRef} {...listeners} {...attributes}
82
- style={getRowStyle()} onClick={() => onSelectRow()}>
81
+ style={getRowStyle()} onClick={onSelectRow}>
83
82
  <div className="indent" style={{ width: node.level * INDENT_WIDTH + "px" }} />
84
83
  {
85
84
  node.type === "folder" ?
@@ -2,10 +2,10 @@
2
2
  width:100%;
3
3
  min-width: 200px;
4
4
  display:flex;
5
- font-size:13px;
5
+ font-size:14px;
6
6
  font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
7
7
  cursor: pointer;
8
- height:32px;
8
+ height:30px;
9
9
  }
10
10
 
11
11
  .indent {
package/src/index.js CHANGED
@@ -1,5 +1,4 @@
1
1
  export * from "./components/StackList";
2
- export * from "./components/Viewer";
3
2
  export * from "./components/FlowDiagram";
4
3
  export * from "./components/FileBrowser";
5
4
  export * from "./components/Editor";
@@ -1,46 +0,0 @@
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
- }
@@ -1,51 +0,0 @@
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
- }
@@ -1,21 +0,0 @@
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
- }
@@ -1,159 +0,0 @@
1
- import React, { useEffect, useState } from "react";
2
- import PropTypes from 'prop-types';
3
-
4
- import {ChevronDown} from "react-bootstrap-icons";
5
- import {Tab} from "./Tab/Tab"
6
-
7
- import Dropdown from 'react-bootstrap/Dropdown';
8
-
9
- import 'bootstrap/dist/css/bootstrap.css';
10
- import "./Tabs.scss";
11
-
12
- // Dropdown needs access to the DOM node in order to position the Menu
13
- const SelectFileToggle = React.forwardRef(({ children, onClick }, ref) => (
14
- <a ref={ref} onClick={(e) => { e.preventDefault(); onClick(e); }}>
15
- {children}
16
- </a>
17
- ));
18
-
19
- /**
20
- * Renders the tabs component.
21
- *
22
- * The tabs component accepts a list of files which have been flattened from
23
- * its system tree structure with a unique id.
24
- *
25
- * It allows you to add a tab, close a tab and select add new tabs using the
26
- * file drop down.
27
- *
28
- * @return {JSX}
29
- */
30
- export const Tabs = ({files, selectFile, systemTree}) => {
31
-
32
- const [activeTab, setActiveTab] = useState(null);
33
- const [tabsList, setTabsList] = useState([]);
34
-
35
- const selectTab = (e, file) => {
36
- setActiveTab(file.key);
37
- selectFile(file.key)
38
- }
39
-
40
- const addTab = (key) => {
41
- const currTabsList = [...tabsList];
42
-
43
- let hasKey = currTabsList.find((tab) => tab.key === key)
44
-
45
- if (hasKey) {
46
- // Set the active tab and select the file.
47
- setActiveTab(key);
48
- selectFile(key);
49
- } else {
50
- // Add tab to the tabs list.
51
- files.forEach((file, index) => {
52
- if (file.key === key) {
53
- currTabsList.push(file);
54
- setActiveTab(file.key);
55
- selectFile(file.key);
56
- setTabsList(currTabsList);
57
- }
58
- });
59
- }
60
- }
61
-
62
- const closeTab = (e, file) => {
63
- e.stopPropagation();
64
-
65
- // Get index of file in tabs list
66
- const index = tabsList.indexOf(file);
67
-
68
- // Remove the closed tab
69
- const currTabsList = [...tabsList];
70
- currTabsList.splice(index, 1);
71
- setTabsList(currTabsList);
72
-
73
- // Select new tab
74
- if (currTabsList.length === 0) {
75
- selectFile(null);
76
- setActiveTab(null);
77
- } else {
78
- // If its the last tab, use the last tab in the new tabs list.
79
- const newIndex = (index >= currTabsList.length)?currTabsList.length - 1:index;
80
- setActiveTab(currTabsList[newIndex].key);
81
- selectFile(currTabsList[newIndex].key);
82
- }
83
- }
84
-
85
- const generateDropdown = () => {
86
- const items = [];
87
-
88
- if (!systemTree) {
89
- return items;
90
- }
91
-
92
- // Build files list from system
93
- for (const program in systemTree) {
94
- items.push(<Dropdown.Header key={`header-${program}`}>{program}</Dropdown.Header>);
95
- for (const fileName in systemTree[program]) {
96
- const key = program + "_" + fileName;
97
- items.push(
98
- <Dropdown.Item key={key} onClick={() => addTab(key)}>{fileName}</Dropdown.Item>
99
- );
100
- }
101
- items.push(<Dropdown.Divider key={`divider-${program}`} />);
102
- }
103
-
104
- // Remove last divider
105
- items.pop();
106
-
107
- return items;
108
- }
109
-
110
- useEffect(() => {
111
- if (files && files.length > 0) {
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);
118
- }
119
- }, [files]);
120
-
121
- return (
122
-
123
- <div className="tabsGutter">
124
-
125
- <div className="tabsContainer">
126
- {tabsList.map(function(file) {
127
- return <Tab
128
- file={file}
129
- key={file.key}
130
- activeTab={activeTab}
131
- selectTab={selectTab}
132
- closeTab={closeTab}
133
- />
134
- })}
135
- </div>
136
-
137
- <div className="tabsDropdown">
138
- {
139
- (files && files.length > 0) &&
140
- <Dropdown data-bs-theme="dark">
141
- <Dropdown.Toggle as={SelectFileToggle}>
142
- <ChevronDown className="chevron" />
143
- </Dropdown.Toggle>
144
- <Dropdown.Menu>
145
- {generateDropdown()}
146
- </Dropdown.Menu>
147
- </Dropdown>
148
- }
149
- </div>
150
-
151
- </div>
152
- );
153
- }
154
-
155
- Tabs.propTypes = {
156
- files: PropTypes.array,
157
- selectFile: PropTypes.func,
158
- systemTree: PropTypes.object
159
- }
@@ -1,50 +0,0 @@
1
- .tabsGutter {
2
- display: flex;
3
- flex-direction: row;
4
- width:100%;
5
- height:40px;
6
- background-color: #252526;
7
- }
8
-
9
- .tabsContainer {
10
- display: flex;
11
- flex-direction: row;
12
- height: 100%;
13
- flex-grow: 1;
14
- overflow-x: auto;
15
- scrollbar-gutter: stable;
16
- scrollbar-color: #47474766 #1e1e1e;
17
- scrollbar-width: thin;
18
- }
19
-
20
- .tabsDropdown {
21
- float: right;
22
- display: flex;
23
- align-items: center;
24
- color:rgb(138, 138, 138);
25
- padding: 0 10px;
26
- cursor:pointer;
27
- height:100%;
28
- }
29
-
30
- .chevron {
31
- color:rgb(177, 177, 177);
32
- }
33
-
34
- .chevron:hover {
35
- color: rgb(255, 255, 255);
36
- }
37
-
38
- .dropdown-menu {
39
- border-radius: 0 !important;
40
- padding: 0 !important;
41
- }
42
-
43
- .dropdown-item {
44
- font-size:11px;
45
- }
46
-
47
- .dropdown-header {
48
- font-size:12px !important;
49
- padding-bottom:5px !important;
50
- }
@@ -1,84 +0,0 @@
1
- import "./Viewer.scss";
2
- import PropTypes from 'prop-types';
3
-
4
- import { MonacoInstance } from "./MonacoInstance/MonacoInstance";
5
- import { useEffect, useState } from "react";
6
- import { Tabs } from "./Tabs/Tabs";
7
-
8
- /**
9
- * Renders the viewer component with support for tabs.
10
- *
11
- * @return {JSX}
12
- */
13
- export const Viewer = ({systemTree, onFileSelect}) => {
14
-
15
- const [files, setFiles] = useState();
16
- const [fileContent, setFileContent] = useState();
17
- const [editorContent, setEditorContent] = useState();
18
-
19
- // Flatten system tree into list with necessary information for tabs component
20
- useEffect(() => {
21
-
22
- // Store the files meta and content separately
23
- const files = [];
24
- const content = {};
25
-
26
- // Flatten system tree and assign key to each file in the program.
27
- for (const program in systemTree) {
28
- for (const filePath in systemTree[program]) {
29
- const file = systemTree[program][filePath];
30
- const key = program + "_" + filePath;
31
- const info = {
32
- program: program,
33
- key: key,
34
- fileName: filePath.split("/").slice(-1)[0],
35
- path: filePath
36
- }
37
- content[key] = file.source
38
- files.push(info);
39
- }
40
- }
41
-
42
- if (files.length === 0) {
43
- // TODO: Replace monaco editor with prompt until a tab is added
44
- setEditorContent("Select file using file navigator or drop down on top right.");
45
- setFileContent({});
46
- setFiles([]);
47
- } else {
48
- setFileContent(content);
49
- setFiles(files);
50
- }
51
-
52
- }, [systemTree])
53
-
54
-
55
- const selectFile = (fileKey) => {
56
- if (fileKey) {
57
- if (files && fileContent) {
58
- let file = files.find((tab) => tab.key === fileKey)
59
- setEditorContent(fileContent[fileKey]);
60
- if (onFileSelect && file) {
61
- onFileSelect(file);
62
- }
63
- }
64
- } else {
65
- setEditorContent("Select file using drop down on top right.");
66
- }
67
- }
68
-
69
- return (
70
- <div className="viewerContainer">
71
- <div className="tabContainer">
72
- <Tabs files={files} selectFile={selectFile} systemTree={systemTree}/>
73
- </div>
74
- <div className="monacoContainer">
75
- <MonacoInstance editorContent={editorContent}/>
76
- </div>
77
- </div>
78
- );
79
- }
80
-
81
- Viewer.propTypes = {
82
- systemTree: PropTypes.object,
83
- onFileSelect: PropTypes.func
84
- }
@@ -1,25 +0,0 @@
1
- .viewerContainer {
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
-
25
- }
@@ -1 +0,0 @@
1
- export * from "./Viewer.jsx"