Skip to content

Commit 64a984a

Browse files
committed
fix: expand tree for searches on initial mount. fixes #223
1 parent b214065 commit 64a984a

File tree

2 files changed

+62
-6
lines changed

2 files changed

+62
-6
lines changed

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

+10-5
Original file line numberDiff line numberDiff line change
@@ -116,10 +116,9 @@ class ReactSortableTree extends Component {
116116
this.handleDndMonitorChange = this.handleDndMonitorChange.bind(this);
117117
}
118118

119-
componentWillMount() {
119+
componentDidMount() {
120120
this.loadLazyChildren();
121-
this.search(this.props, false, false);
122-
this.ignoreOneTreeUpdate = false;
121+
this.search(this.props);
123122

124123
// Hook into react-dnd state changes to detect when the drag ends
125124
// TODO: This is very brittle, so it needs to be replaced if react-dnd
@@ -130,14 +129,17 @@ class ReactSortableTree extends Component {
130129
}
131130

132131
componentWillReceiveProps(nextProps) {
133-
this.setState({ searchFocusTreeIndex: null });
134132
if (this.props.treeData !== nextProps.treeData) {
135133
// Ignore updates caused by search, in order to avoid infinite looping
136134
if (this.ignoreOneTreeUpdate) {
137135
this.ignoreOneTreeUpdate = false;
138136
} else {
139-
this.loadLazyChildren(nextProps);
137+
// Reset the focused index if the tree has changed
138+
this.setState({ searchFocusTreeIndex: null });
139+
140140
// Load any children defined by a function
141+
this.loadLazyChildren(nextProps);
142+
141143
this.search(nextProps, false, false);
142144
}
143145

@@ -353,6 +355,9 @@ class ReactSortableTree extends Component {
353355
newNode: ({ node }) => ({ ...node, expanded: true }),
354356
getNodeKey: this.props.getNodeKey,
355357
}),
358+
// reset the scroll focus so it doesn't jump back
359+
// to a search result while dragging
360+
searchFocusTreeIndex: null,
356361
});
357362
}
358363

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

+52-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ import PropTypes from 'prop-types';
33
import renderer from 'react-test-renderer';
44
import { mount } from 'enzyme';
55
import { List } from 'react-virtualized';
6-
import SortableTree from './react-sortable-tree';
6+
import SortableTree, {
7+
SortableTreeWithoutDndContext,
8+
} from './react-sortable-tree';
79
import sortableTreeStyles from './react-sortable-tree.scss';
810
import TreeNode from './tree-node';
911
import treeNodeStyles from './tree-node.scss';
@@ -268,4 +270,53 @@ describe('<SortableTree />', () => {
268270

269271
expect(wrapper.find(FakeNode).length).toEqual(1);
270272
});
273+
274+
it('search should call searchFinishCallback', () => {
275+
const searchFinishCallback = jest.fn();
276+
mount(
277+
<SortableTree
278+
treeData={[{ title: 'a', children: [{ title: 'b' }] }]}
279+
searchQuery="b"
280+
searchFocusOffset={0}
281+
searchFinishCallback={searchFinishCallback}
282+
onChange={() => {}}
283+
/>
284+
);
285+
286+
expect(searchFinishCallback).toHaveBeenCalledWith([
287+
// Node should be found expanded
288+
{ node: { title: 'b' }, path: [0, 1], treeIndex: 1 },
289+
]);
290+
});
291+
292+
it('search should expand all matches and seek out the focus offset', () => {
293+
const wrapper = mount(
294+
<SortableTree
295+
treeData={[
296+
{ title: 'a', children: [{ title: 'b' }] },
297+
{ title: 'a', children: [{ title: 'be' }] },
298+
]}
299+
searchQuery="b"
300+
onChange={() => {}}
301+
/>
302+
);
303+
304+
const tree = wrapper.find(SortableTreeWithoutDndContext).instance();
305+
expect(tree.state.searchMatches).toEqual([
306+
{ node: { title: 'b' }, path: [0, 1], treeIndex: 1 },
307+
{ node: { title: 'be' }, path: [2, 3], treeIndex: 3 },
308+
]);
309+
expect(tree.state.searchFocusTreeIndex).toEqual(null);
310+
311+
wrapper.setProps({ searchFocusOffset: 0 });
312+
expect(tree.state.searchFocusTreeIndex).toEqual(1);
313+
314+
wrapper.setProps({ searchFocusOffset: 1 });
315+
// As the empty `onChange` we use here doesn't actually change
316+
// the tree, the expansion of all nodes doesn't get preserved
317+
// after the first mount, and this change in searchFocusOffset
318+
// only triggers the opening of a single path.
319+
// Therefore it's 2 instead of 3.
320+
expect(tree.state.searchFocusTreeIndex).toEqual(2);
321+
});
271322
});

0 commit comments

Comments
 (0)