React
by Michael Vashevko
HTML
<div id="app"></div>
CSS
body {
background: #20262e;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
li {
margin: 8px 0;
}
h2 {
font-weight: bold;
margin-bottom: 15px;
}
.done {
color: rgba(0, 0, 0, 0.3);
text-decoration: line-through;
}
input {
margin-right: 5px;
}
React
import React, { useState, useEffect } from "react";
// Sample Node class
class Node {
constructor(name, value, children = []) {
this.name = name;
this.value = value;
this.children = children;
this.isVisible = true;
this.isExpanded = false;
this.isEnabled = true;
this.parent = null;
}
}
// TreeVisitor Utility
class TreeVisitor {
static prepareData(root) {
root.parent = null; // Root has no parent
const queue = [root];
while (queue.length > 0) {
const node = queue.shift();
node.isVisible = true;
node.isExpanded = false;
node.isEnabled = true;
for (const child of node.children) {
child.parent = node; // Set parent reference
queue.push(child);
}
}
}
}
// TreeNode Component
const TreeNode = ({ node, onToggleExpand, onToggleEnable }) => {
return (
<div style={{ marginLeft: "20px" }}>
<span
style={{ cursor: "pointer", fontWeight: "bold" }}
onClick={() => onToggleExpand(node)}
>
{node.children.length > 0 ? (node.isExpanded ? "▼ " : "▶ ") : "• "}
{node.name}
</span>
<button
onClick={() => onToggleEnable(node)}
style={{
marginLeft: "10px",
cursor: "pointer",
background: "none",
border: "none",
color: node.isEnabled ? "green" : "red"
}}
>
{node.isEnabled ? "🟢 Disable" : "🔴 Enable"}
</button>
{node.isExpanded &&
node.children.map((child) => (
<TreeNode
key={child.name}
node={child}
onToggleExpand={onToggleExpand}
...