diff --git a/README.md b/README.md index 9dad5daf..6456ee1d 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,7 @@ Play with the code on an [example on CodeSandbox](https://codesandbox.io/s/wkxvy | 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.
`({ node: object, path: number[] or string[], treeIndex: number, searchQuery: any }): bool`
| | 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`. | | searchFocusOffset | number | Outline the <`searchFocusOffset`>th node and scroll to it. | +| expandOnlySearchedNodes | boolean | Only expand the nodes that match searches. Collapses all other nodes. Defaults to `false`. | | searchFinishCallback | func | Get the nodes that match the search criteria. Used for counting total matches, etc.
`(matches: { node: object, path: number[] or string[], treeIndex: number }[]): void`
| | 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 | | 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`.
`({ node: object, prevPath: number[] or string[], prevTreeIndex: number, }): bool`
| diff --git a/src/react-sortable-tree.js b/src/react-sortable-tree.js index 81ed7909..6dac1382 100644 --- a/src/react-sortable-tree.js +++ b/src/react-sortable-tree.js @@ -17,6 +17,7 @@ import { removeNode, insertNode, find, + toggleExpandedForAll, } from './utils/tree-data-utils'; import { memoizedInsertNode, @@ -262,6 +263,7 @@ class ReactSortableTree extends Component { searchQuery, searchMethod, searchFocusOffset, + onlyExpandSearchedNodes, } = props; // Skip search if no conditions are specified @@ -282,9 +284,12 @@ class ReactSortableTree extends Component { return; } + // if onlyExpandSearchedNodes collapse the tree and search const { treeData: expandedTreeData, matches: searchMatches } = find({ getNodeKey: this.props.getNodeKey, - treeData, + treeData: onlyExpandSearchedNodes + ? toggleExpandedForAll({ treeData, expanded: false }) + : treeData, searchQuery, searchMethod: searchMethod || defaultSearchMethod, searchFocusOffset, @@ -826,6 +831,9 @@ ReactSortableTree.propTypes = { // Called to track between dropped and dragging onDragStateChanged: PropTypes.func, + + // Specify that nodes that do not match search will be collapsed + onlyExpandSearchedNodes: PropTypes.bool, }; ReactSortableTree.defaultProps = { @@ -855,6 +863,7 @@ ReactSortableTree.defaultProps = { style: {}, theme: {}, onDragStateChanged: () => {}, + onlyExpandSearchedNodes: false, }; ReactSortableTree.contextTypes = { diff --git a/src/react-sortable-tree.test.js b/src/react-sortable-tree.test.js index 33e51d44..87c51f0e 100644 --- a/src/react-sortable-tree.test.js +++ b/src/react-sortable-tree.test.js @@ -313,6 +313,80 @@ describe('', () => { expect(tree.state.searchFocusTreeIndex).toEqual(2); }); + it('search onlyExpandSearchedNodes should collapse all nodes except matches', () => { + const wrapper = mount( + wrapper.setProps({ treeData })} + onlyExpandSearchedNodes + /> + ); + wrapper.setProps({ searchQuery: 'be' }); + expect(wrapper.prop('treeData')).toEqual([ + { + title: 'a', + children: [ + { + title: 'b', + children: [ + { + title: 'c', + expanded: false, + }, + ], + expanded: false, + }, + ], + expanded: false, + }, + { + title: 'b', + children: [ + { + title: 'd', + children: [ + { + title: 'be', + expanded: false, + }, + ], + expanded: true, + }, + ], + expanded: true, + }, + { + title: 'c', + children: [ + { + title: 'f', + children: [ + { + title: 'dd', + expanded: false, + }, + ], + expanded: false, + }, + ], + expanded: false, + }, + ]); + }); + it('loads using SortableTreeWithoutDndContext', () => { const HTML5Wrapped = DragDropContext(HTML5Backend)( SortableTreeWithoutDndContext