diff --git a/src/react-sortable-tree.js b/src/react-sortable-tree.js
index 76df00de..a0295c82 100644
--- a/src/react-sortable-tree.js
+++ b/src/react-sortable-tree.js
@@ -116,10 +116,9 @@ class ReactSortableTree extends Component {
this.handleDndMonitorChange = this.handleDndMonitorChange.bind(this);
}
- componentWillMount() {
+ componentDidMount() {
this.loadLazyChildren();
- this.search(this.props, false, false);
- this.ignoreOneTreeUpdate = false;
+ this.search(this.props);
// Hook into react-dnd state changes to detect when the drag ends
// TODO: This is very brittle, so it needs to be replaced if react-dnd
@@ -130,14 +129,17 @@ class ReactSortableTree extends Component {
}
componentWillReceiveProps(nextProps) {
- this.setState({ searchFocusTreeIndex: null });
if (this.props.treeData !== nextProps.treeData) {
// Ignore updates caused by search, in order to avoid infinite looping
if (this.ignoreOneTreeUpdate) {
this.ignoreOneTreeUpdate = false;
} else {
- this.loadLazyChildren(nextProps);
+ // Reset the focused index if the tree has changed
+ this.setState({ searchFocusTreeIndex: null });
+
// Load any children defined by a function
+ this.loadLazyChildren(nextProps);
+
this.search(nextProps, false, false);
}
@@ -353,6 +355,9 @@ class ReactSortableTree extends Component {
newNode: ({ node }) => ({ ...node, expanded: true }),
getNodeKey: this.props.getNodeKey,
}),
+ // reset the scroll focus so it doesn't jump back
+ // to a search result while dragging
+ searchFocusTreeIndex: null,
});
}
diff --git a/src/react-sortable-tree.test.js b/src/react-sortable-tree.test.js
index cc65e911..2604b670 100644
--- a/src/react-sortable-tree.test.js
+++ b/src/react-sortable-tree.test.js
@@ -3,7 +3,9 @@ import PropTypes from 'prop-types';
import renderer from 'react-test-renderer';
import { mount } from 'enzyme';
import { List } from 'react-virtualized';
-import SortableTree from './react-sortable-tree';
+import SortableTree, {
+ SortableTreeWithoutDndContext,
+} from './react-sortable-tree';
import sortableTreeStyles from './react-sortable-tree.scss';
import TreeNode from './tree-node';
import treeNodeStyles from './tree-node.scss';
@@ -268,4 +270,53 @@ describe('', () => {
expect(wrapper.find(FakeNode).length).toEqual(1);
});
+
+ it('search should call searchFinishCallback', () => {
+ const searchFinishCallback = jest.fn();
+ mount(
+ {}}
+ />
+ );
+
+ expect(searchFinishCallback).toHaveBeenCalledWith([
+ // Node should be found expanded
+ { node: { title: 'b' }, path: [0, 1], treeIndex: 1 },
+ ]);
+ });
+
+ it('search should expand all matches and seek out the focus offset', () => {
+ const wrapper = mount(
+ {}}
+ />
+ );
+
+ const tree = wrapper.find(SortableTreeWithoutDndContext).instance();
+ expect(tree.state.searchMatches).toEqual([
+ { node: { title: 'b' }, path: [0, 1], treeIndex: 1 },
+ { node: { title: 'be' }, path: [2, 3], treeIndex: 3 },
+ ]);
+ expect(tree.state.searchFocusTreeIndex).toEqual(null);
+
+ wrapper.setProps({ searchFocusOffset: 0 });
+ expect(tree.state.searchFocusTreeIndex).toEqual(1);
+
+ wrapper.setProps({ searchFocusOffset: 1 });
+ // As the empty `onChange` we use here doesn't actually change
+ // the tree, the expansion of all nodes doesn't get preserved
+ // after the first mount, and this change in searchFocusOffset
+ // only triggers the opening of a single path.
+ // Therefore it's 2 instead of 3.
+ expect(tree.state.searchFocusTreeIndex).toEqual(2);
+ });
});