Skip to content

Commit

Permalink
feat: rework TreeView component
Browse files Browse the repository at this point in the history
  • Loading branch information
cheton committed Jul 27, 2023
1 parent 3fffe7a commit 258a51b
Show file tree
Hide file tree
Showing 13 changed files with 712 additions and 284 deletions.
70 changes: 70 additions & 0 deletions packages/react-docs/pages/components/treeview/basic.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import {
Scrollbar,
TreeView,
TreeNode,
Truncate,
useColorStyle,
} from '@tonic-ui/react';
import React from 'react';
import tree from './data/tree.json';

const findExpandableNodeIds = (tree) => {
const expandableNodeIds = [];

const traverse = (node) => {
if (Array.isArray(node.children) && node.children.length > 0) {
expandableNodeIds.push(node.id);
node.children.forEach(traverse);
}
};

traverse(tree);

return expandableNodeIds;
};

const renderTree = (node, depth = 0) => {
const childCount = Array.isArray(node.children) ? node.children.length : 0;

return (
<TreeNode
key={node.id}
nodeId={node.id}
render={() => (
<Truncate>{node.name}</Truncate>
)}
>
{(childCount > 0)
? node.children.map(node => renderTree(node, depth + 1))
: null
}
</TreeNode>
);
};

const expandableNodeIds = findExpandableNodeIds(tree);

const App = () => {
const [colorStyle] = useColorStyle();

return (
<Scrollbar
width={400}
height={240}
overflowY="visible"
sx={{
border: 1,
borderColor: colorStyle.divider,
}}
>
<TreeView
aria-label="basic tree view"
defaultExpandedNodes={expandableNodeIds}
>
{renderTree(tree)}
</TreeView>
</Scrollbar>
);
};

export default App;
163 changes: 163 additions & 0 deletions packages/react-docs/pages/components/treeview/controlled.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
import {
Button,
ButtonGroup,
Divider,
Scrollbar,
Stack,
Text,
TreeView,
TreeNode,
Truncate,
useColorStyle,
} from '@tonic-ui/react';
import React, { useState } from 'react';
import tree from './data/tree.json';

const renderTree = (node, depth = 0) => {
const childCount = Array.isArray(node.children) ? node.children.length : 0;

return (
<TreeNode
key={node.id}
nodeId={node.id}
render={() => (
<Truncate>{node.name}</Truncate>
)}
>
{(childCount > 0)
? node.children.map(node => renderTree(node, depth + 1))
: null
}
</TreeNode>
);
};

const findExpandableNodeIds = (tree) => {
const expandableNodeIds = [];

const traverse = (node) => {
if (Array.isArray(node.children) && node.children.length > 0) {
expandableNodeIds.push(node.id);
node.children.forEach(traverse);
}
};

traverse(tree);

return expandableNodeIds;
};

const getAllNodeIds = (tree) => {
const allNodeIds = [];

const traverse = (node) => {
allNodeIds.push(node.id);
if (Array.isArray(node.children) && node.children.length > 0) {
node.children.forEach(traverse);
}
};

traverse(tree);

return allNodeIds;
};

const allNodeIds = getAllNodeIds(tree);
const expandableNodeIds = findExpandableNodeIds(tree);

const App = () => {
const [colorStyle] = useColorStyle();
const [expandedNodes, setExpandedNodes] = useState(expandableNodeIds);
const [selectedNodes, setSelectedNodes] = useState([]);

const onToggleNodes = (nodeIds) => {
setExpandedNodes(nodeIds);
};

const onSelectNodes = (nodeIds) => {
setSelectedNodes(nodeIds);
};

const handleClickExpandAll = (event) => {
setExpandedNodes(expandableNodeIds);
};

const handleClickCollapseAll = (event) => {
setExpandedNodes([]);
};

const handleClickSelectAll = (event) => {
setSelectedNodes(allNodeIds);
};

const handleClickUnselectAll = (event) => {
setSelectedNodes([]);
};

return (
<>
<ButtonGroup
variant="secondary"
columnGap="2x"
mb="3x"
>
<Button
variant="secondary"
disabled={expandedNodes.length === expandableNodeIds.length}
onClick={handleClickExpandAll}
>
Expand all
</Button>
<Button
variant="secondary"
disabled={expandedNodes.length === 0}
onClick={handleClickCollapseAll}
>
Collapse all
</Button>
<Button
variant="secondary"
disabled={selectedNodes.length === allNodeIds.length}
onClick={handleClickSelectAll}
>
Select all
</Button>
<Button
variant="secondary"
disabled={selectedNodes.length === 0}
onClick={handleClickUnselectAll}
>
Unselect all
</Button>
</ButtonGroup>
<Stack spacing="2x">
<Text>Expanded nodes: {expandedNodes.join(', ')}</Text>
<Text>Selected nodes: {selectedNodes.join(', ')}</Text>
</Stack>
<Divider my="4x" />
<Scrollbar
width={400}
height={240}
overflowY="visible"
sx={{
border: 1,
borderColor: colorStyle.divider,
}}
>
<TreeView
aria-label="controlled"
isSelectable
isMultiSelectable
expandedNodes={expandedNodes}
selectedNodes={selectedNodes}
onToggleNodes={onToggleNodes}
onSelectNodes={onSelectNodes}
>
{renderTree(tree)}
</TreeView>
</Scrollbar>
</>
);
};

export default App;
68 changes: 68 additions & 0 deletions packages/react-docs/pages/components/treeview/data/tree.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
{
"id": "0",
"name": "Root",
"children": [
{
"id": "1",
"name": "Node 1",
"children": [
{
"id": "2",
"name": "Node 2",
"children": [
{
"id": "3",
"name": "Node 3",
"children": [
{
"id": "4",
"name": "Node 4"
}
]
},
{
"id": "5",
"name": "Node 5"
}
]
},
{
"id": "6",
"name": "Node 6",
"children": [
{
"id": "7",
"name": "Node 7",
"children": [
{
"id": "8",
"name": "Node 8"
},
{
"id": "9",
"name": "Node 9"
}
]
}
]
}
]
},
{
"id": "10",
"name": "Node 10",
"children": [
{
"id": "11",
"name": "Node 11",
"children": [
{
"id": "12",
"name": "Node 12"
}
]
}
]
}
]
}
30 changes: 29 additions & 1 deletion packages/react-docs/pages/components/treeview/index.mdx
Original file line number Diff line number Diff line change
@@ -1,3 +1,31 @@
# Tree View

{render('./render-tree')}
## Usage

### Basic tree view

{render('./basic')}

### Node icons

{render('./node-icons')}

### Multi-selection

{render('./multi-selection')}

### Controlled tree view

{render('./controlled')}

## Props

### TreeView

| Name | Type | Default | Description |
| :--- | :--- | :------ | :---------- |

### TreeNode

| Name | Type | Default | Description |
| :--- | :--- | :------ | :---------- |
Loading

0 comments on commit 258a51b

Please sign in to comment.