sample-ui-component-library 0.0.7-dev → 0.0.8-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/dist/cjs/index.js +6 -6
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/index.js +7 -7
- package/dist/esm/index.js.map +1 -1
- package/package.json +3 -1
- package/src/components/Editor/Editor.jsx +77 -42
- package/src/components/Editor/Editor.scss +1 -0
- package/src/components/Editor/EditorContext.js +2 -0
- package/src/components/Editor/EditorReducer.js +88 -0
- package/src/components/Editor/MonacoInstance/MonacoInstance.jsx +62 -40
- package/src/components/Editor/MonacoInstance/MonacoInstance.scss +8 -0
- package/src/components/Editor/Tabs/Gutter/Gutter.jsx +35 -0
- package/src/components/Editor/Tabs/Gutter/Gutter.scss +5 -0
- package/src/components/Editor/Tabs/Tab/Tab.jsx +89 -0
- package/src/components/Editor/Tabs/Tab/Tab.scss +28 -0
- package/src/components/Editor/Tabs/Tabs.jsx +47 -0
- package/src/components/Editor/Tabs/Tabs.scss +15 -0
- package/src/components/FileBrowser/FileBrowser.jsx +56 -119
- package/src/components/FileBrowser/FileBrowser.scss +0 -33
- package/src/components/FileBrowser/FileBrowserContext.js +2 -0
- package/src/components/FileBrowser/FileBrowserReducer.js +47 -0
- package/src/components/FileBrowser/Tree/Tree.jsx +55 -0
- package/src/components/FileBrowser/Tree/Tree.scss +33 -0
- package/src/components/FileBrowser/TreeNode/TreeNode.jsx +101 -0
- package/src/components/FileBrowser/TreeNode/TreeNode.scss +33 -0
- package/src/components/FileBrowser/helper.js +1 -0
- package/src/stories/Editor.stories.js +34 -50
- package/src/stories/FileBrowser.stories.js +21 -36
- package/src/stories/data/FileBrowser/workspace_sample.json +1 -0
- package/src/components/Editor/EditorTabs/EditorTabs.jsx +0 -93
- package/src/components/Editor/EditorTabs/EditorTabs.scss +0 -33
- package/src/stories/data/FileBrowser/Tree1.json +0 -57
- package/src/stories/data/FileBrowser/Tree2.json +0 -60
|
@@ -1,136 +1,73 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
forwardRef,
|
|
3
|
+
useReducer,
|
|
4
|
+
useMemo,
|
|
5
|
+
useCallback,
|
|
6
|
+
useContext,
|
|
7
|
+
useImperativeHandle,
|
|
8
|
+
} from "react";
|
|
2
9
|
import "./FileBrowser.scss";
|
|
3
10
|
|
|
4
|
-
import {
|
|
11
|
+
import { Tree } from "./Tree/Tree";
|
|
12
|
+
import { TreeNodePreview } from "./TreeNode/TreeNode";
|
|
5
13
|
|
|
6
|
-
import {
|
|
7
|
-
import PropTypes from 'prop-types';
|
|
8
|
-
import {
|
|
9
|
-
DndContext,
|
|
10
|
-
DragOverlay,
|
|
11
|
-
useDraggable,
|
|
12
|
-
useDroppable,
|
|
13
|
-
} from "@dnd-kit/core";
|
|
14
|
+
import { FileBrowserContext } from "./FileBrowserContext";
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
const SELECTED_FILE_COLOR = "#00426b";
|
|
16
|
+
import { fileBrowserReducer, initialState } from "./FileBrowserReducer";
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
|
-
*
|
|
19
|
+
* Renders a file browser.
|
|
20
|
+
*
|
|
21
|
+
* @return {JSX}
|
|
20
22
|
*/
|
|
21
|
-
|
|
22
|
-
const
|
|
23
|
+
export const FileBrowser = forwardRef(({ }, ref) => {
|
|
24
|
+
const [state, dispatch] = useReducer(fileBrowserReducer, initialState);
|
|
23
25
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
return useCallback((...args) => {
|
|
29
|
-
return fnRef.current(...args);
|
|
26
|
+
const addFileTree = useCallback((tree) => {
|
|
27
|
+
dispatch({ type: "ADD_FILE_TREE", payload: tree });
|
|
30
28
|
}, []);
|
|
31
|
-
}
|
|
32
29
|
|
|
33
|
-
/**
|
|
34
|
-
* Renders a single node in the file tree.
|
|
35
|
-
*/
|
|
36
|
-
const TreeNode = ({id, node, onRowClick}) => {
|
|
37
|
-
const { attributes, listeners, setNodeRef, transform } = useDraggable({id});
|
|
38
|
-
/**
|
|
39
|
-
* Gets the appropriate icon for the node based on its type and collapsed state.
|
|
40
|
-
* @returns <JSX>
|
|
41
|
-
*/
|
|
42
|
-
const getCollapsedIcon = () => {
|
|
43
|
-
if (node.collapsed) {
|
|
44
|
-
return <ChevronRight />;
|
|
45
|
-
} else {
|
|
46
|
-
return <ChevronDown />;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
30
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
31
|
+
const selectNode = useCallback((node) => {
|
|
32
|
+
dispatch({ type: "SELECT_NODE", payload: node });
|
|
33
|
+
}, []);
|
|
34
|
+
|
|
35
|
+
const getPreviewElement = useCallback((tabId) => {
|
|
36
|
+
// Get the preview element for a tab by its id for use in drag-and-drop operations.
|
|
37
|
+
const tab = state.flattenedTree.find(t => t.uid === tabId);
|
|
38
|
+
if (!tab) {
|
|
39
|
+
console.error(`getPreviewElement: tab with id ${tabId} not found.`);
|
|
40
|
+
return null;
|
|
57
41
|
}
|
|
58
|
-
return
|
|
59
|
-
}
|
|
42
|
+
return <TreeNodePreview node={tab} />;
|
|
43
|
+
}, [state]);
|
|
60
44
|
|
|
45
|
+
const api = useMemo(() => {
|
|
46
|
+
return {
|
|
47
|
+
state,
|
|
48
|
+
addFileTree,
|
|
49
|
+
selectNode,
|
|
50
|
+
getPreviewElement
|
|
51
|
+
};
|
|
52
|
+
}, [state, addFileTree, selectNode, getPreviewElement]);
|
|
61
53
|
|
|
62
|
-
|
|
63
|
-
* Get the file icon based on the extension.
|
|
64
|
-
*
|
|
65
|
-
* TODO: This can be improved by having a mapping of extensions to icons and color.
|
|
66
|
-
*/
|
|
67
|
-
const getFileIcon = () => {
|
|
68
|
-
const extension = node.name.split('.').pop();
|
|
69
|
-
switch (extension) {
|
|
70
|
-
case "js":
|
|
71
|
-
return <FiletypeJs color="#f1e05a" />;
|
|
72
|
-
case "json":
|
|
73
|
-
return <Braces color="#fffb00" />;
|
|
74
|
-
case "scss":
|
|
75
|
-
return <FiletypeScss color="#f12727" />;
|
|
76
|
-
case "py":
|
|
77
|
-
return <FiletypePy color="#686affbd" />;
|
|
78
|
-
default:
|
|
79
|
-
return <FileCode color="#ffffff" />;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
54
|
+
useImperativeHandle(ref, () => api, [api]);
|
|
82
55
|
|
|
83
56
|
return (
|
|
84
|
-
<
|
|
85
|
-
<div className="
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
*
|
|
99
|
-
* @return {JSX}
|
|
100
|
-
*/
|
|
101
|
-
export const FileBrowser = ({tree, onNodeSelect}) => {
|
|
102
|
-
|
|
103
|
-
const [nodes, setNodes] = useState([]);
|
|
104
|
-
const treeRef = useRef();
|
|
105
|
-
|
|
106
|
-
const handleFileClick = useEvent((node) => {
|
|
107
|
-
selectNode(treeRef.current, node);
|
|
108
|
-
drawTree();
|
|
109
|
-
if (onNodeSelect) {
|
|
110
|
-
onNodeSelect(node);
|
|
111
|
-
}
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
useEffect(() => {
|
|
115
|
-
treeRef.current = flattenTree(tree);
|
|
116
|
-
setDefaultCollapsed(treeRef.current);
|
|
117
|
-
drawTree();
|
|
118
|
-
}, []);
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Draws the tree given the nodes and the collapsed state of each node.
|
|
122
|
-
*/
|
|
123
|
-
const drawTree = () => {
|
|
124
|
-
const nodes = collapseTree(treeRef.current);
|
|
125
|
-
const rows = [];
|
|
126
|
-
nodes.forEach((node) => {
|
|
127
|
-
rows.push(<TreeNode key={node.id} node={node} id={node.name} onRowClick={handleFileClick}/>);
|
|
128
|
-
});
|
|
129
|
-
setNodes(rows);
|
|
57
|
+
<FileBrowserContext.Provider value={api}>
|
|
58
|
+
<div className="file-browser">
|
|
59
|
+
<Tree />
|
|
60
|
+
</div>
|
|
61
|
+
</FileBrowserContext.Provider>
|
|
62
|
+
);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
FileBrowser.displayName = "FileBrowser";
|
|
66
|
+
|
|
67
|
+
export function useFileBrowser() {
|
|
68
|
+
const ctx = useContext(FileBrowserContext);
|
|
69
|
+
if (!ctx) {
|
|
70
|
+
throw new Error("useFileBrowser must be used inside <FileBrowser>");
|
|
130
71
|
}
|
|
131
|
-
return
|
|
132
|
-
|
|
133
|
-
{nodes}
|
|
134
|
-
</div>
|
|
135
|
-
)
|
|
136
|
-
}
|
|
72
|
+
return ctx;
|
|
73
|
+
}
|
|
@@ -5,36 +5,3 @@
|
|
|
5
5
|
color:white;
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
-
.file-node-row{
|
|
9
|
-
width:100%;
|
|
10
|
-
min-width: 200px;
|
|
11
|
-
display:flex;
|
|
12
|
-
padding: 5px 0;
|
|
13
|
-
font-size:13px;
|
|
14
|
-
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
|
15
|
-
cursor: pointer;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
.indent {
|
|
19
|
-
height:100%;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
.center {
|
|
23
|
-
display:flex;
|
|
24
|
-
align-self: center;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
.folder-icon {
|
|
29
|
-
display:flex;
|
|
30
|
-
margin-right: 5px;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
.file-icon {
|
|
34
|
-
margin-right: 5px;
|
|
35
|
-
font-size:16px;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
.file-name {
|
|
39
|
-
color: #CCC;
|
|
40
|
-
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import {
|
|
2
|
+
setDefaultCollapsed,
|
|
3
|
+
collapseTree,
|
|
4
|
+
selectNode,
|
|
5
|
+
flattenTree,
|
|
6
|
+
} from "./helper";
|
|
7
|
+
|
|
8
|
+
export const initialState = {
|
|
9
|
+
tree: {},
|
|
10
|
+
flattenedTree: {},
|
|
11
|
+
collapsedTree: [],
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const fileBrowserReducer = (state, action) => {
|
|
15
|
+
|
|
16
|
+
switch (action.type) {
|
|
17
|
+
|
|
18
|
+
case "ADD_FILE_TREE": {
|
|
19
|
+
let flattenedTree = setDefaultCollapsed(flattenTree(action.payload));
|
|
20
|
+
const collapsedTree = collapseTree(flattenedTree);
|
|
21
|
+
return {
|
|
22
|
+
...state,
|
|
23
|
+
tree: action.payload,
|
|
24
|
+
flattenedTree: flattenedTree,
|
|
25
|
+
collapsedTree: collapsedTree
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
case "SELECT_NODE": {
|
|
30
|
+
const tree = [...state.flattenedTree];
|
|
31
|
+
tree.forEach((n) => {
|
|
32
|
+
if (n.uid === action.payload) {
|
|
33
|
+
n.selected = true;
|
|
34
|
+
n.collapsed = !n.collapsed;
|
|
35
|
+
} else {
|
|
36
|
+
n.selected = false;
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
const collapsedTree = collapseTree(tree);
|
|
40
|
+
return {
|
|
41
|
+
...state,
|
|
42
|
+
flattenedTree: tree,
|
|
43
|
+
collapsedTree: collapsedTree
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import {
|
|
2
|
+
useEffect,
|
|
3
|
+
useState,
|
|
4
|
+
useRef
|
|
5
|
+
} from "react";
|
|
6
|
+
|
|
7
|
+
import { TreeNode } from "../TreeNode/TreeNode";
|
|
8
|
+
|
|
9
|
+
import { useFileBrowser } from "../FileBrowser";
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
setDefaultCollapsed,
|
|
13
|
+
collapseTree,
|
|
14
|
+
selectNode,
|
|
15
|
+
flattenTree,
|
|
16
|
+
} from "../helper";
|
|
17
|
+
|
|
18
|
+
import "./Tree.scss";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Renders a file tree.
|
|
22
|
+
*/
|
|
23
|
+
export const Tree = ({}) => {
|
|
24
|
+
const [nodes, setNodes] = useState([]);
|
|
25
|
+
const {state} = useFileBrowser();
|
|
26
|
+
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
if(state.collapsedTree && state.collapsedTree.length > 0) {
|
|
29
|
+
drawTree(state.collapsedTree);
|
|
30
|
+
}
|
|
31
|
+
}, [state.collapsedTree]);
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Draws the tree given the nodes and the collapsed state of each node.
|
|
35
|
+
*/
|
|
36
|
+
const drawTree = (collapsedTree) => {
|
|
37
|
+
const rows = [];
|
|
38
|
+
collapsedTree.forEach((node) => {
|
|
39
|
+
rows.push(
|
|
40
|
+
<TreeNode
|
|
41
|
+
key={node.uid}
|
|
42
|
+
node={node}
|
|
43
|
+
id={node.name}
|
|
44
|
+
/>,
|
|
45
|
+
);
|
|
46
|
+
});
|
|
47
|
+
setNodes(rows);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<>
|
|
52
|
+
{nodes}
|
|
53
|
+
</>
|
|
54
|
+
)
|
|
55
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { FileCode, ChevronRight, ChevronDown, Braces, FiletypeScss, FiletypeJs, FiletypePy } from "react-bootstrap-icons";
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import {
|
|
4
|
+
DndContext,
|
|
5
|
+
DragOverlay,
|
|
6
|
+
useDraggable,
|
|
7
|
+
useDroppable,
|
|
8
|
+
} from "@dnd-kit/core";
|
|
9
|
+
|
|
10
|
+
import { useFileBrowser } from "../FileBrowser";
|
|
11
|
+
|
|
12
|
+
const INDENT_WIDTH = 20;
|
|
13
|
+
const SELECTED_FILE_COLOR = "#00426b";
|
|
14
|
+
|
|
15
|
+
import "./TreeNode.scss";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Renders a single node in the file tree.
|
|
19
|
+
*/
|
|
20
|
+
export const TreeNode = ({ id, node }) => {
|
|
21
|
+
const { attributes, listeners, setNodeRef, transform } = useDraggable(
|
|
22
|
+
{
|
|
23
|
+
id,
|
|
24
|
+
data: {
|
|
25
|
+
node: node
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
);
|
|
29
|
+
const { selectNode } = useFileBrowser();
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Gets the appropriate icon for the node based on its type and collapsed state.
|
|
33
|
+
* @returns <JSX>
|
|
34
|
+
*/
|
|
35
|
+
const getCollapsedIcon = () => {
|
|
36
|
+
if (node.collapsed) {
|
|
37
|
+
return <ChevronRight />;
|
|
38
|
+
} else {
|
|
39
|
+
return <ChevronDown />;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Sets the background color of the row if the node is selected.
|
|
45
|
+
*/
|
|
46
|
+
const getRowStyle = () => {
|
|
47
|
+
const style = {};
|
|
48
|
+
if (node.selected) {
|
|
49
|
+
style["backgroundColor"] = SELECTED_FILE_COLOR;
|
|
50
|
+
}
|
|
51
|
+
return style;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Get the file icon based on the extension.
|
|
57
|
+
*
|
|
58
|
+
* TODO: This can be improved by having a mapping of extensions to icons and color.
|
|
59
|
+
*/
|
|
60
|
+
const getFileIcon = () => {
|
|
61
|
+
const extension = node.name.split('.').pop();
|
|
62
|
+
switch (extension) {
|
|
63
|
+
case "js":
|
|
64
|
+
return <FiletypeJs color="#f1e05a" />;
|
|
65
|
+
case "json":
|
|
66
|
+
return <Braces color="#fffb00" />;
|
|
67
|
+
case "scss":
|
|
68
|
+
return <FiletypeScss color="#f12727" />;
|
|
69
|
+
case "py":
|
|
70
|
+
return <FiletypePy color="#686affbd" />;
|
|
71
|
+
default:
|
|
72
|
+
return <FileCode color="#ffffff" />;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
const onSelectRow = () => {
|
|
78
|
+
selectNode(node.uid);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<div className="file-node-row" ref={setNodeRef} {...listeners} {...attributes}
|
|
83
|
+
style={getRowStyle()} onClick={() => onSelectRow()}>
|
|
84
|
+
<div className="indent" style={{ width: node.level * INDENT_WIDTH + "px" }} />
|
|
85
|
+
{
|
|
86
|
+
node.type === "folder" ?
|
|
87
|
+
<span className="folder-icon">{getCollapsedIcon()}</span> :
|
|
88
|
+
<span className="file-icon">{getFileIcon()}</span>
|
|
89
|
+
}
|
|
90
|
+
<span className="file-name">{node.name}</span>
|
|
91
|
+
</div>
|
|
92
|
+
)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export const TreeNodePreview = ({node}) => {
|
|
96
|
+
return (
|
|
97
|
+
<div className="file-node-row">
|
|
98
|
+
<span className="file-name">{node.name}</span>
|
|
99
|
+
</div>
|
|
100
|
+
);
|
|
101
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
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
|
+
}
|
|
@@ -1,18 +1,16 @@
|
|
|
1
|
-
import { useEffect } from "react";
|
|
1
|
+
import { useEffect, useState, useRef, useLayoutEffect } from "react";
|
|
2
2
|
import { Editor } from "../components/Editor";
|
|
3
3
|
import { useArgs } from "@storybook/preview-api";
|
|
4
4
|
import { action } from "@storybook/addon-actions";
|
|
5
5
|
import {
|
|
6
6
|
DndContext,
|
|
7
7
|
DragOverlay,
|
|
8
|
-
useDraggable,
|
|
9
|
-
useDroppable,
|
|
10
8
|
PointerSensor,
|
|
11
9
|
useSensor,
|
|
12
10
|
useSensors
|
|
13
11
|
} from "@dnd-kit/core";
|
|
14
12
|
|
|
15
|
-
import
|
|
13
|
+
import WorkspaceSampleTree from "./data/FileBrowser/workspace_sample.json"
|
|
16
14
|
|
|
17
15
|
import "./EditorStories.scss"
|
|
18
16
|
|
|
@@ -21,27 +19,6 @@ export default {
|
|
|
21
19
|
component: Editor,
|
|
22
20
|
argTypes: {}
|
|
23
21
|
};
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Preview for the div being dragged.
|
|
27
|
-
* @returns
|
|
28
|
-
*/
|
|
29
|
-
function DragPreview({ label }) {
|
|
30
|
-
return (
|
|
31
|
-
<div
|
|
32
|
-
style={{
|
|
33
|
-
padding: "6px 12px",
|
|
34
|
-
background: "#2d2d2d",
|
|
35
|
-
color: "white",
|
|
36
|
-
boxShadow: "0 4px 12px rgba(0,0,0,0.3)",
|
|
37
|
-
opacity:0.3
|
|
38
|
-
}}
|
|
39
|
-
>
|
|
40
|
-
{label}
|
|
41
|
-
</div>
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
22
|
/**
|
|
46
23
|
* Offset for the drag overlay.
|
|
47
24
|
* @returns
|
|
@@ -54,40 +31,49 @@ const offsetOverlay = ({ transform }) => {
|
|
|
54
31
|
};
|
|
55
32
|
};
|
|
56
33
|
|
|
34
|
+
const flattenTree = (tree, level = 0) =>
|
|
35
|
+
tree.flatMap(node => [
|
|
36
|
+
{ ...node, level },
|
|
37
|
+
...(node.children ? flattenTree(node.children, level + 1) : [])
|
|
38
|
+
]);
|
|
39
|
+
|
|
57
40
|
const Template = (args) => {
|
|
58
41
|
const [, updateArgs] = useArgs();
|
|
59
42
|
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
43
|
+
const [dragPreviewLabel, setDragPreviewLabel] = useState(<></>);
|
|
44
|
+
|
|
45
|
+
const editorRef = useRef();
|
|
63
46
|
|
|
64
|
-
|
|
65
|
-
|
|
47
|
+
useLayoutEffect(() => {
|
|
48
|
+
editorRef.current.setTabGroupId("tab-group-1");
|
|
49
|
+
flattenTree(WorkspaceSampleTree.tree).forEach((node, index) => {
|
|
50
|
+
if (node.type === "file") {
|
|
51
|
+
editorRef.current.addTab(node);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
66
54
|
}, []);
|
|
67
55
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
56
|
+
const onDragStart = (event) => {
|
|
57
|
+
console.log("");
|
|
58
|
+
console.log("Drag Started");
|
|
59
|
+
const dragPreview = editorRef.current.getPreviewElement(event.active.data.current.node.uid);
|
|
60
|
+
setDragPreviewLabel(dragPreview);
|
|
61
|
+
}
|
|
62
|
+
|
|
71
63
|
const handleDragEnd = (event) =>{
|
|
72
64
|
const { active, over } = event;
|
|
73
|
-
console.log("Drag Ended");
|
|
74
|
-
const rect = event.activatorEvent;
|
|
75
|
-
|
|
76
|
-
console.log(over );
|
|
77
65
|
|
|
78
66
|
if (over) {
|
|
79
|
-
console.log("Dragged item:", active
|
|
80
|
-
console.log("Dropped on:", over
|
|
67
|
+
console.log("Dragged item:", active);
|
|
68
|
+
console.log("Dropped on:", over);
|
|
81
69
|
} else {
|
|
82
70
|
console.log("Dropped outside any droppable");
|
|
71
|
+
return;
|
|
83
72
|
}
|
|
84
|
-
}
|
|
85
73
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
const onDragStart = (event) => {
|
|
90
|
-
console.log("Drag Started");
|
|
74
|
+
if (active.data.current.type === "tab-draggable" && over.data.current.type === "tab-gutter") {
|
|
75
|
+
editorRef.current.moveTab(active.data.current.node.uid, over.data.current.index);
|
|
76
|
+
}
|
|
91
77
|
}
|
|
92
78
|
|
|
93
79
|
const sensors = useSensors(
|
|
@@ -101,10 +87,10 @@ const Template = (args) => {
|
|
|
101
87
|
return (
|
|
102
88
|
<DndContext sensors={sensors} onDragStart={onDragStart} onDragEnd={handleDragEnd}>
|
|
103
89
|
<div className="editorStoryWrapper">
|
|
104
|
-
<Editor {...args} />
|
|
90
|
+
<Editor ref={editorRef}{...args} />
|
|
105
91
|
</div>
|
|
106
92
|
<DragOverlay modifiers={[offsetOverlay]} dropAnimation={null}>
|
|
107
|
-
|
|
93
|
+
{dragPreviewLabel}
|
|
108
94
|
</DragOverlay>
|
|
109
95
|
</DndContext>
|
|
110
96
|
)
|
|
@@ -112,6 +98,4 @@ const Template = (args) => {
|
|
|
112
98
|
|
|
113
99
|
export const Default = Template.bind({});
|
|
114
100
|
|
|
115
|
-
Default.args = {
|
|
116
|
-
systemTree: fileTrees.fileTrees
|
|
117
|
-
}
|
|
101
|
+
Default.args = {}
|