Skip to content

Commit d4778ca

Browse files
konardclaude
andcommitted
Enhanced react-deep-tree with features inspired by react-sortable-tree
- Added comprehensive TypeScript interfaces for better type safety - Implemented customizable node rendering via renderNode prop - Added search functionality with searchQuery and searchMethod props - Included expand/collapse functionality with visual indicators - Added utility functions for tree data manipulation (findNode, filterNodes, walkTree, etc.) - Created comprehensive examples demonstrating all new features - Maintained backward compatibility with existing API - Updated package version to 0.1.0 for next release 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 9d1e289 commit d4778ca

21 files changed

+1829
-262
lines changed

example/components/deep-tree.tsx

Lines changed: 210 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,223 @@
1-
import React from 'react';
1+
import React, { useState } from 'react';
2+
import DeepTree, { DataNode, treeUtils } from '../../index';
23

3-
interface DataNode {
4-
readonly content: any;
5-
readonly children: DataNode[];
6-
}
7-
export type { DataNode };
4+
// Demo data showcasing the enhanced features
5+
const demoData: DataNode[] = [
6+
{
7+
id: 'docs',
8+
content: 'Documentation',
9+
expanded: true,
10+
children: [
11+
{
12+
id: 'api-docs',
13+
content: 'API Documentation',
14+
children: [
15+
{
16+
id: 'auth-api',
17+
content: 'Authentication API',
18+
children: []
19+
},
20+
{
21+
id: 'user-api',
22+
content: 'User Management API',
23+
children: []
24+
}
25+
]
26+
},
27+
{
28+
id: 'guides',
29+
content: 'User Guides',
30+
children: [
31+
{
32+
id: 'quick-start',
33+
content: 'Quick Start Guide',
34+
children: []
35+
},
36+
{
37+
id: 'advanced',
38+
content: 'Advanced Configuration',
39+
children: []
40+
}
41+
]
42+
}
43+
]
44+
},
45+
{
46+
id: 'src',
47+
content: 'Source Code',
48+
expanded: false,
49+
children: [
50+
{
51+
id: 'components',
52+
content: 'React Components',
53+
children: [
54+
{
55+
id: 'tree-component',
56+
content: 'DeepTree Component',
57+
children: []
58+
},
59+
{
60+
id: 'search-component',
61+
content: 'SearchBox Component',
62+
children: []
63+
}
64+
]
65+
},
66+
{
67+
id: 'utils',
68+
content: 'Utility Functions',
69+
children: [
70+
{
71+
id: 'tree-utils',
72+
content: 'Tree Manipulation Utils',
73+
children: []
74+
}
75+
]
76+
}
77+
]
78+
}
79+
];
880

9-
interface TreeNodeProps {
10-
data: DataNode;
11-
ListItem?: React.ElementType;
12-
List?: React.ElementType;
13-
ContentFrame?: React.ElementType;
14-
}
81+
export const EnhancedDeepTreeDemo: React.FC = () => {
82+
const [searchQuery, setSearchQuery] = useState('');
83+
const [selectedNode, setSelectedNode] = useState<DataNode | null>(null);
1584

16-
export function TreeNode({ data, ListItem = 'li', List = 'ul', ContentFrame = 'div' }: TreeNodeProps) {
17-
const { content, children } = data;
18-
let item;
19-
let treeNodesList;
85+
const handleNodeClick = (node: DataNode) => {
86+
setSelectedNode(node);
87+
};
88+
89+
const customRenderNode = (node: DataNode, isLeaf: boolean) => {
90+
const getIcon = () => {
91+
if (node.id === 'docs') return '📚';
92+
if (node.id === 'src') return '💻';
93+
if (node.content.includes('Component')) return '⚛️';
94+
if (node.content.includes('API')) return '🔗';
95+
if (node.content.includes('Guide')) return '📖';
96+
if (isLeaf) return '📄';
97+
return '📁';
98+
};
99+
100+
return (
101+
<div style={{
102+
display: 'flex',
103+
alignItems: 'center',
104+
padding: '2px 4px',
105+
borderRadius: '3px',
106+
background: selectedNode?.id === node.id ? '#e3f2fd' : 'transparent'
107+
}}>
108+
<span style={{ marginRight: '6px' }}>{getIcon()}</span>
109+
<span>{node.content}</span>
110+
</div>
111+
);
112+
};
20113

21-
if (content !== undefined) {
22-
item = <ContentFrame>{content}</ContentFrame>;
23-
}
24-
if (children && children.length > 0) {
25-
const treeNodes = children.map((element, index) => (
26-
<TreeNode data={element} key={index} ListItem={ListItem} List={List} ContentFrame={ContentFrame} />
27-
));
28-
treeNodesList = <List>{treeNodes}</List>;
29-
}
30114
return (
31-
<ListItem>
32-
{item}
33-
{treeNodesList}
34-
</ListItem>
115+
<div style={{ maxWidth: '800px', margin: '0 auto', padding: '20px' }}>
116+
<h2>Enhanced React Deep Tree Demo</h2>
117+
118+
<div style={{ marginBottom: '20px' }}>
119+
<input
120+
type="text"
121+
placeholder="Search in tree..."
122+
value={searchQuery}
123+
onChange={(e) => setSearchQuery(e.target.value)}
124+
style={{
125+
width: '100%',
126+
padding: '8px 12px',
127+
fontSize: '14px',
128+
border: '1px solid #ddd',
129+
borderRadius: '4px',
130+
boxSizing: 'border-box'
131+
}}
132+
/>
133+
</div>
134+
135+
<div style={{ display: 'flex', gap: '20px' }}>
136+
<div style={{ flex: 1 }}>
137+
<h3>Interactive Tree</h3>
138+
<div style={{
139+
border: '1px solid #ddd',
140+
borderRadius: '4px',
141+
padding: '10px',
142+
background: '#fafafa',
143+
minHeight: '300px'
144+
}}>
145+
<DeepTree
146+
data={demoData}
147+
renderNode={customRenderNode}
148+
searchQuery={searchQuery}
149+
searchMethod={treeUtils.defaultSearchMethod}
150+
onNodeClick={handleNodeClick}
151+
/>
152+
</div>
153+
</div>
154+
155+
<div style={{ width: '250px' }}>
156+
<h3>Tree Statistics</h3>
157+
<div style={{
158+
border: '1px solid #ddd',
159+
borderRadius: '4px',
160+
padding: '10px',
161+
background: '#f9f9f9'
162+
}}>
163+
<p><strong>Total nodes:</strong> {treeUtils.countNodes(demoData)}</p>
164+
<p><strong>Max depth:</strong> {treeUtils.getMaxDepth(demoData)}</p>
165+
{searchQuery && (
166+
<p><strong>Matching nodes:</strong> {
167+
treeUtils.filterNodes(demoData, node =>
168+
treeUtils.defaultSearchMethod(node, searchQuery)
169+
).length
170+
}</p>
171+
)}
172+
</div>
173+
174+
{selectedNode && (
175+
<div style={{ marginTop: '20px' }}>
176+
<h3>Selected Node</h3>
177+
<div style={{
178+
border: '1px solid #ddd',
179+
borderRadius: '4px',
180+
padding: '10px',
181+
background: '#f0f8ff',
182+
fontSize: '12px'
183+
}}>
184+
<p><strong>ID:</strong> {selectedNode.id}</p>
185+
<p><strong>Content:</strong> {selectedNode.content}</p>
186+
<p><strong>Children:</strong> {selectedNode.children.length}</p>
187+
<p><strong>Has Path:</strong> {
188+
treeUtils.findNodePath(demoData, selectedNode.id!)?.join(' → ') || 'N/A'
189+
}</p>
190+
</div>
191+
</div>
192+
)}
193+
</div>
194+
</div>
195+
</div>
35196
);
36-
}
197+
};
37198

38-
interface DeepTreeProps {
39-
data: DataNode[];
40-
ListItem?: React.ElementType;
41-
List?: React.ElementType;
42-
ContentFrame?: React.ElementType;
43-
TreeFrame?: React.ElementType;
199+
// Maintain backward compatibility
200+
export function TreeNode({ data, ListItem = 'li', List = 'ul', ContentFrame = 'div' }: any) {
201+
return (
202+
<DeepTree
203+
data={[data]}
204+
ListItem={ListItem}
205+
List={List}
206+
ContentFrame={ContentFrame}
207+
/>
208+
);
44209
}
45210

46-
export function DeepTree({ data, ListItem = 'li', List = 'ul', ContentFrame = 'div', TreeFrame='div' }: DeepTreeProps) {
211+
export function DeepTree_Legacy({ data, ListItem = 'li', List = 'ul', ContentFrame = 'div', TreeFrame = 'div' }: any) {
47212
return (
48-
<TreeFrame>
49-
<List>
50-
{data.map((object, index) => (
51-
<TreeNode key={index} data={object} ListItem={ListItem} List={List} ContentFrame={ContentFrame} />
52-
))}
53-
</List>
54-
</TreeFrame>
213+
<DeepTree
214+
data={data}
215+
ListItem={ListItem}
216+
List={List}
217+
ContentFrame={ContentFrame}
218+
TreeFrame={TreeFrame}
219+
/>
55220
);
56221
}
57222

58-
export default DeepTree;
223+
export default EnhancedDeepTreeDemo;

examples/basic-usage.js

Lines changed: 77 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/basic-usage.js.map

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)