Description
I'm facing a couple of issues while using react-sortable-tree in my Next js project: using "react-sortable-tree": "^2.7.1", version
Search query not working: The search functionality is not returning expected results. When I search for a node, no matching nodes are highlighted or returned.
Expand/Collapse issue after dragging nodes: After dragging nodes from one place to another, the expand/collapse functionality doesn't work on the node level. The nodes remain expanded or collapsed, and I cannot toggle them properly after moving. at node level expand and collapse and buttons as well.
I created a new node configuration and moved to under contact:
please find below my code can any one help to resolve this.
import React, { useEffect, useState } from 'react';
import dynamic from 'next/dynamic';
import { FaPlus, FaChevronDown, FaChevronUp, FaSearch } from 'react-icons/fa';
const SortableTree = dynamic(() => import('react-sortable-tree'), { ssr: false });
import 'react-sortable-tree/style.css';
interface TreeNode {
title: string;
expanded?: boolean;
children?: TreeNode[];
}
const Tree = () => {
const [treeData, setTreeData] = useState<TreeNode[]>([]);
const [newNodeTitle, setNewNodeTitle] = useState('');
const [searchText, setSearchText] = useState('');
const [matchedNodeIds, setMatchedNodeIds] = useState<string[]>([]);
useEffect(() => {
setTreeData([
{
title: 'Profile',
expanded: true,
children: [
{ title: 'Official' },
{ title: 'Contact' },
{ title: 'License/Passport' },
{ title: 'Education' },
{ title: 'Family' },
],
},
{
title: 'Time Tracking',
expanded: false,
children: [{ title: 'Timesheet Entry' }],
},
]);
}, []);
/*** Expand All Nodes ***/
const expandAll = () => {
const updatedTree = treeData.map((node) => ({
...node,
expanded: true,
children: node.children ? node.children.map((child) => ({ ...child, expanded: true })) : [],
}));
setTreeData(updatedTree);
};
/*** Collapse All Nodes ***/
const collapseAll = () => {
const updatedTree = treeData.map((node) => ({
...node,
expanded: false,
children: node.children ? node.children.map((child) => ({ ...child, expanded: false })) : [],
}));
setTreeData(updatedTree);
};
/*** Add a new node to the main tree ***/
const addNode = () => {
if (newNodeTitle.trim() === '') return;
setTreeData([...treeData, { title: newNodeTitle, expanded: false }]);
setNewNodeTitle('');
};
/*** Search Node in the Tree ***/
const handleSearch = (e: React.ChangeEvent) => {
const query = e.target.value;
setSearchText(query);
};
return (
<div style={{ height: 1000, padding: '10px', fontFamily: 'Arial, sans-serif' }}>
{/* Top Controls /}
<div style={{ display: 'flex', alignItems: 'center', gap: '10px', marginBottom: '10px' }}>
{/ Create Node Input */}
<input
type="text"
value={newNodeTitle}
onChange={(e) => setNewNodeTitle(e.target.value)}
placeholder="Enter node title"
style={{ padding: '5px', width: '180px', borderRadius: '5px', border: '1px solid #ccc' }}
/>
<button
onClick={addNode}
style={{
padding: '5px 10px',
cursor: 'pointer',
borderRadius: '50%',
background: '#4CAF50',
color: 'white',
border: 'none',
}}
title="Add Node"
>
{/* Search Box */}
<input
type="text"
value={searchText}
onChange={handleSearch}
placeholder="Search node..."
style={{ padding: '5px', width: '180px', borderRadius: '5px', border: '1px solid #ccc' }}
/>
<FaSearch style={{ color: '#666' }} />
{/* Expand and Collapse Buttons */}
<div style={{ display: 'flex', alignItems: 'center', gap: '10px', marginBottom: '10px' }}>
<button
onClick={expandAll}
style={{
marginRight: '10px',
padding: '10px 20px',
backgroundColor: '#FFFFFF',
color: 'black',
border: '1 px solid black',
borderRadius: '5px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
<span style={{ fontSize: '18px', marginRight: '8px' }}>+</span>
<span>Expand All Nodes</span>
</button>
<button
onClick={collapseAll}
style={{
marginRight: '10px',
padding: '10px 20px',
backgroundColor: '#FFFFFF',
color: 'black',
border: '1 px solid black',
borderRadius: '5px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
<span style={{ fontSize: '18px', marginRight: '8px' }}>-</span>
<span>Collapse All Nodes</span>
</button>
</div>
</div>
{/* Tree View */}
<div style={{ height: 400 }}>
<SortableTree
treeData={treeData}
isVirtualized={true}
searchQuery={searchText}
onChange={(newTreeData: TreeNode[]) => {
setTreeData(newTreeData);
console.log('Updated Tree Data:', newTreeData);
}}
canNodeHaveChildren={() => true}
generateNodeProps={({ node, path }) => ({
title: (
<span
style={{
fontWeight: matchedNodeIds.includes(path.join('-')) ? 'bold' : 'normal',
backgroundColor: matchedNodeIds.includes(path.join('-')) ? '#ffff99' : 'transparent',
padding: '2px 5px',
borderRadius: '4px',
}}
>
{node.title}
</span>
),
onClick: () => {
node.expanded = !node.expanded;
setTreeData([...treeData]);
},
})}
/>
</div>
</div>
);
};
export default Tree;