Skip to content

Commit 2d57928

Browse files
authored
feat: Added onlyExpandSearchedNodes prop
expandOnlySearchedNodes props is used so the tree only expands search matches and collapses all other nodes. #245.
1 parent 32d1db7 commit 2d57928

File tree

3 files changed

+85
-1
lines changed

3 files changed

+85
-1
lines changed

Diff for: README.md

+1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ Play with the code on an [example on CodeSandbox](https://codesandbox.io/s/wkxvy
5959
| searchMethod | func | The method used to search nodes. Defaults to [`defaultSearchMethod`](https://github.com/fritz-c/react-sortable-tree/blob/master/src/utils/default-handlers.js), which uses the `searchQuery` string to search for nodes with matching `title` or `subtitle` values. NOTE: Changing `searchMethod` will not update the search, but changing the `searchQuery` will.<div>`({ node: object, path: number[] or string[], treeIndex: number, searchQuery: any }): bool`</div> |
6060
| searchQuery | string or any | Used by the `searchMethod` to highlight and scroll to matched nodes. Should be a string for the default `searchMethod`, but can be anything when using a custom search. Defaults to `null`. |
6161
| searchFocusOffset | number | Outline the <`searchFocusOffset`>th node and scroll to it. |
62+
| expandOnlySearchedNodes | boolean | Only expand the nodes that match searches. Collapses all other nodes. Defaults to `false`. |
6263
| searchFinishCallback | func | Get the nodes that match the search criteria. Used for counting total matches, etc.<div>`(matches: { node: object, path: number[] or string[], treeIndex: number }[]): void`</div> |
6364
| dndType | string | String value used by [react-dnd](http://react-dnd.github.io/react-dnd/docs-overview.html) (see overview at the link) for dropTargets and dragSources types. If not set explicitly, a default value is applied by react-sortable-tree for you for its internal use. **NOTE:** Must be explicitly set and the same value used in order for correct functioning of external nodes |
6465
| shouldCopyOnOutsideDrop | func or bool | Return true, or a callback returning true, and dropping nodes to react-dnd drop targets outside of the tree will not remove them from the tree. Defaults to `false`. <div>`({ node: object, prevPath: number[] or string[], prevTreeIndex: number, }): bool`</div> |

Diff for: src/react-sortable-tree.js

+10-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
removeNode,
1818
insertNode,
1919
find,
20+
toggleExpandedForAll,
2021
} from './utils/tree-data-utils';
2122
import {
2223
memoizedInsertNode,
@@ -262,6 +263,7 @@ class ReactSortableTree extends Component {
262263
searchQuery,
263264
searchMethod,
264265
searchFocusOffset,
266+
onlyExpandSearchedNodes,
265267
} = props;
266268

267269
// Skip search if no conditions are specified
@@ -282,9 +284,12 @@ class ReactSortableTree extends Component {
282284
return;
283285
}
284286

287+
// if onlyExpandSearchedNodes collapse the tree and search
285288
const { treeData: expandedTreeData, matches: searchMatches } = find({
286289
getNodeKey: this.props.getNodeKey,
287-
treeData,
290+
treeData: onlyExpandSearchedNodes
291+
? toggleExpandedForAll({ treeData, expanded: false })
292+
: treeData,
288293
searchQuery,
289294
searchMethod: searchMethod || defaultSearchMethod,
290295
searchFocusOffset,
@@ -826,6 +831,9 @@ ReactSortableTree.propTypes = {
826831

827832
// Called to track between dropped and dragging
828833
onDragStateChanged: PropTypes.func,
834+
835+
// Specify that nodes that do not match search will be collapsed
836+
onlyExpandSearchedNodes: PropTypes.bool,
829837
};
830838

831839
ReactSortableTree.defaultProps = {
@@ -855,6 +863,7 @@ ReactSortableTree.defaultProps = {
855863
style: {},
856864
theme: {},
857865
onDragStateChanged: () => {},
866+
onlyExpandSearchedNodes: false,
858867
};
859868

860869
ReactSortableTree.contextTypes = {

Diff for: src/react-sortable-tree.test.js

+74
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,80 @@ describe('<SortableTree />', () => {
313313
expect(tree.state.searchFocusTreeIndex).toEqual(2);
314314
});
315315

316+
it('search onlyExpandSearchedNodes should collapse all nodes except matches', () => {
317+
const wrapper = mount(
318+
<SortableTree
319+
treeData={[
320+
{
321+
title: 'a',
322+
children: [{ title: 'b', children: [{ title: 'c' }] }],
323+
},
324+
{
325+
title: 'b',
326+
children: [{ title: 'd', children: [{ title: 'be' }] }],
327+
},
328+
{
329+
title: 'c',
330+
children: [{ title: 'f', children: [{ title: 'dd' }] }],
331+
},
332+
]}
333+
onChange={treeData => wrapper.setProps({ treeData })}
334+
onlyExpandSearchedNodes
335+
/>
336+
);
337+
wrapper.setProps({ searchQuery: 'be' });
338+
expect(wrapper.prop('treeData')).toEqual([
339+
{
340+
title: 'a',
341+
children: [
342+
{
343+
title: 'b',
344+
children: [
345+
{
346+
title: 'c',
347+
expanded: false,
348+
},
349+
],
350+
expanded: false,
351+
},
352+
],
353+
expanded: false,
354+
},
355+
{
356+
title: 'b',
357+
children: [
358+
{
359+
title: 'd',
360+
children: [
361+
{
362+
title: 'be',
363+
expanded: false,
364+
},
365+
],
366+
expanded: true,
367+
},
368+
],
369+
expanded: true,
370+
},
371+
{
372+
title: 'c',
373+
children: [
374+
{
375+
title: 'f',
376+
children: [
377+
{
378+
title: 'dd',
379+
expanded: false,
380+
},
381+
],
382+
expanded: false,
383+
},
384+
],
385+
expanded: false,
386+
},
387+
]);
388+
});
389+
316390
it('loads using SortableTreeWithoutDndContext', () => {
317391
const HTML5Wrapped = DragDropContext(HTML5Backend)(
318392
SortableTreeWithoutDndContext

0 commit comments

Comments
 (0)