Skip to content

Commit ae26e62

Browse files
committed
feat: nestedNode component
1 parent 11c9cc2 commit ae26e62

File tree

8 files changed

+227
-4
lines changed

8 files changed

+227
-4
lines changed

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@
6262
- [ ] JSONEditor
6363
- [ ] UploadButton
6464
- [ ] Atom:
65-
- [ ] Nested Nodes
65+
- [x] Nested Nodes
6666
- [ ] Item component - used in Flash - history
6767
- [x] Code Drops: Dropdown
6868
- [x] DOT:
@@ -96,4 +96,4 @@
9696
- [x] Text overflow class
9797
- [x] Move popover position
9898
- [x] Change dot loader colors
99-
- [ ] Create item component/card or move NodeEditor from Octon
99+
- [x] Create item component/card or move NodeEditor from Octon

package-lock.json

+6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+3-2
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@
3939
"eslint-plugin-react-hooks": "^4.2.0",
4040
"husky": "^7.0.4",
4141
"semantic-release-cli": "^5.4.4",
42-
"semantic-release": "^18.0.1"
42+
"semantic-release": "^18.0.1",
43+
"@codedrops/lib": "0.0.49"
4344
},
4445
"scripts": {
4546
"dev": "webpack-dev-server --config webpack.app.js",
@@ -67,4 +68,4 @@
6768
"@commitlint/config-conventional"
6869
]
6970
}
70-
}
71+
}

src/UIComponents/index.js

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import BlockerScreen from "./molecules/BlockerScreen";
2222
import CheckboxGroup from "./molecules/CheckboxGroup";
2323
import ProfileDropdown from "./molecules/ProfileDropdown";
2424
import ProfileAvatar from "./molecules/ProfileAvatar";
25+
import NestedNodes from "./molecules/NestedNodes";
2526

2627
export {
2728
Card,
@@ -45,6 +46,7 @@ export {
4546
ProfileDropdown,
4647
ProfileAvatar,
4748
Backdrop,
49+
NestedNodes,
4850
};
4951

5052
export default color;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
/* eslint-disable react-hooks/exhaustive-deps */
2+
import React, { useState, Fragment } from "react";
3+
import colors, { Icon, Card, Button, Input, Select } from "../../index";
4+
import { useObject } from "@codedrops/lib";
5+
import "./NestedNodes.scss";
6+
import { v4 as uuidv4 } from "uuid";
7+
import classnames from "classnames";
8+
9+
const NestedNodesContainer = ({ nodes = [], onChange }) => {
10+
const [showAddRow, setShowAddRow] = useState(false);
11+
const [editId, setEditId] = useState(null);
12+
const [addData, setAddData, resetAddData] = useObject({});
13+
14+
const setNodeToEdit = (node) => {
15+
setAddData(node);
16+
setEditId(node._id);
17+
setShowAddRow(true);
18+
};
19+
20+
const handleChange = () => {
21+
if (!addData.label) return;
22+
23+
if (editId) {
24+
onChange(
25+
addData,
26+
"UPDATE",
27+
nodes.map((node) =>
28+
node._id === editId ? { ...node, ...addData } : node
29+
)
30+
);
31+
setEditId(null);
32+
} else {
33+
const newItem = { ...addData, _id: uuidv4() };
34+
onChange(newItem, "CREATE", [...nodes, newItem]);
35+
}
36+
reset();
37+
};
38+
39+
const reset = () => {
40+
resetAddData({});
41+
setShowAddRow(false);
42+
setEditId(null);
43+
};
44+
45+
const deleteNode = (_id) => {
46+
onChange(
47+
{ _id },
48+
"DELETE",
49+
nodes.filter((node) => node._id !== _id)
50+
);
51+
};
52+
53+
const hideParentSelect = editId && addData.default; // hide select parent dropdown when a field is `default` & in edit mode
54+
55+
return (
56+
<div className="nested-container">
57+
<NestedNodes
58+
nodes={nodes}
59+
setNodeToEdit={setNodeToEdit}
60+
deleteNode={deleteNode}
61+
/>
62+
<div className="controller mt">
63+
{showAddRow ? (
64+
<>
65+
<div className="flex center gap-4">
66+
<Input
67+
value={addData.label}
68+
name="label"
69+
placeholder="Label"
70+
onChange={(e, value) => setAddData(value)}
71+
autoFocus={true}
72+
/>
73+
{hideParentSelect ? null : (
74+
<Select
75+
dropPosition={"top"}
76+
placeholder="Parent"
77+
value={addData.parentTagId}
78+
name="parentTagId"
79+
onChange={(e, value) => setAddData(value)}
80+
options={nodes
81+
.map((node) => ({
82+
label: node.label,
83+
value: node._id,
84+
}))
85+
.filter((node) => node.value !== editId)}
86+
/>
87+
)}
88+
</div>
89+
<div className="flex center gap-4 mt-4">
90+
<Button onClick={handleChange}>
91+
{editId ? "Update" : "Add"}
92+
</Button>
93+
<Button onClick={reset}>Cancel</Button>
94+
</div>
95+
</>
96+
) : (
97+
<Button onClick={() => setShowAddRow(true)}>Add</Button>
98+
)}
99+
</div>
100+
</div>
101+
);
102+
};
103+
104+
const NestedNodes = (props) => {
105+
const { nodes, depth = 0, parentTagId, setNodeToEdit, deleteNode } = props;
106+
107+
const filteredNodes = nodes.filter((node) =>
108+
depth > 0
109+
? node.parentTagId && node.parentTagId === parentTagId
110+
: !node.parentTagId
111+
);
112+
const isRootLevel = !depth || depth === 0;
113+
const showDivider = Boolean(filteredNodes.length && !isRootLevel);
114+
const nextDepth = Number(depth) + 1;
115+
116+
return (
117+
<Fragment>
118+
{showDivider && <div className="divider"></div>}
119+
<div className="wrapper">
120+
{filteredNodes.map((node, index) => {
121+
const { _id, label, canDelete } = node;
122+
const hasChildNodes = nodes.filter(
123+
(node) => node.parentTagId === _id
124+
).length;
125+
const nodeClasses = classnames(
126+
"node",
127+
// `level-${depth || 0}`,
128+
{
129+
expanded: hasChildNodes,
130+
}
131+
);
132+
return (
133+
<Card key={_id} className={nodeClasses}>
134+
<div className="title-wrapper">
135+
<div className="title">{`${index + 1}. ${label}`}</div>
136+
<div>
137+
<Icon
138+
type="edit"
139+
size={10}
140+
onClick={() => setNodeToEdit(node)}
141+
/>
142+
<Icon
143+
type="delete"
144+
size={10}
145+
fill={canDelete ? colors.iron : colors.strokeOne}
146+
onClick={() => (canDelete ? deleteNode(node._id) : null)}
147+
/>
148+
</div>
149+
</div>
150+
<NestedNodes {...props} depth={nextDepth} parentTagId={_id} />
151+
</Card>
152+
);
153+
})}
154+
</div>
155+
</Fragment>
156+
);
157+
};
158+
159+
export default NestedNodesContainer;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
@import "../../../magicdust/colors";
2+
3+
.nested-container {
4+
.wrapper {
5+
display: flex;
6+
flex-direction: column;
7+
gap: 2px;
8+
}
9+
.node {
10+
display: flex;
11+
flex-direction: column;
12+
background: $white;
13+
padding: 8px 12px;
14+
box-shadow: 4px 4px 4px $bg;
15+
border-color: $strokeOne;
16+
.divider {
17+
margin: 0;
18+
}
19+
.title-wrapper {
20+
display: flex;
21+
align-items: center;
22+
justify-content: space-between;
23+
}
24+
&.expanded {
25+
// contains child nodes
26+
padding: 0;
27+
& > .title-wrapper {
28+
padding: 8px 12px;
29+
}
30+
& > .wrapper {
31+
padding: 12px;
32+
}
33+
}
34+
&:not(.expanded) {
35+
transition: 0.2s;
36+
&:hover {
37+
background: $feather;
38+
}
39+
}
40+
}
41+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import comp from "./NestedNodes";
2+
export default comp;

src/components/Home.js

+12
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
Dropdown,
2121
ProfileDropdown,
2222
ProfileAvatar,
23+
NestedNodes,
2324
} from "../UIComponents";
2425
import "./Home.scss";
2526
import colors from "../magicdust/colors";
@@ -47,6 +48,7 @@ const uiList = [
4748
"EMPTYSTATE",
4849
"BLOCKERSCREEN",
4950
"ICON",
51+
"NESTED_NODES",
5052
];
5153

5254
const icons = [
@@ -138,12 +140,15 @@ const UIComponent = ({ type }) => {
138140
radio: "a",
139141
select: "a",
140142
checkbox: true,
143+
nodes: [],
141144
});
142145

143146
const [id, setId] = useState();
144147

145148
const setInputField = (update) => setData((prev) => ({ ...prev, ...update }));
146149

150+
console.log("data::-", data);
151+
147152
switch (type) {
148153
case "PROFILE_AVATAR":
149154
return (
@@ -387,6 +392,13 @@ const UIComponent = ({ type }) => {
387392
<BlockerScreen />
388393
</div>
389394
);
395+
case "NESTED_NODES":
396+
return (
397+
<NestedNodes
398+
nodes={data.nodes}
399+
onChange={(node) => setInputField({ nodes: [...data.nodes, node] })}
400+
/>
401+
);
390402
case "DROPDOWN":
391403
return (
392404
<Dropdown

0 commit comments

Comments
 (0)