Skip to content

Commit 8451882

Browse files
fix: Prevent jump on node selection (no auto scroll to center) (#408)
Co-authored-by: Hrusikesh Panda <[email protected]>
1 parent a850b78 commit 8451882

File tree

4 files changed

+28
-15
lines changed

4 files changed

+28
-15
lines changed

src/index.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,10 @@ class DropdownTreeSelect extends Component {
254254
this.onNodeToggle
255255
)
256256
if (newFocus !== currentFocus) {
257-
this.setState({ currentFocus: newFocus })
257+
this.setState({ currentFocus: newFocus }, () => {
258+
const ele = document && document.getElementById(`${newFocus}_li`)
259+
ele && ele.scrollIntoView()
260+
})
258261
}
259262
} else if (showDropdown && ['Escape', 'Tab'].indexOf(e.key) > -1) {
260263
if (mode === 'simpleSelect' && tree.has(currentFocus)) {

src/index.keyboardNav.test.js

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import test from 'ava'
22
import React from 'react'
3-
import { spy, stub } from 'sinon'
3+
import { spy, stub, assert } from 'sinon'
44
import { mount } from 'enzyme'
55
import DropdownTreeSelect from './index'
66

@@ -164,6 +164,7 @@ test('should set current focus as selected on tab out for simpleSelect', t => {
164164

165165
test('should scroll on keyboard navigation', t => {
166166
const largeTree = [...Array(150).keys()].map(i => node(`id${i}`, `label${i}`))
167+
const scrollIntoView = (Element.prototype.scrollIntoView = spy())
167168
const wrapper = mount(<DropdownTreeSelect data={largeTree} showDropdown="initial" />)
168169
const getElementById = stub(document, 'getElementById')
169170
const contentNode = wrapper.find('.dropdown-content').getDOMNode()
@@ -172,25 +173,26 @@ test('should scroll on keyboard navigation', t => {
172173

173174
triggerOnKeyboardKeyDown(wrapper, ['ArrowUp'])
174175
largeTree.forEach((n, index) => {
175-
getElementById.withArgs(`${n.id}_li`).returns({ offsetTop: index, clientHeight: 1 })
176+
getElementById.withArgs(`${n.id}_li`).returns({ offsetTop: index, clientHeight: 1, scrollIntoView })
176177
})
177178

178179
triggerOnKeyboardKeyDown(wrapper, ['ArrowUp'])
179180
t.deepEqual(wrapper.find('li.focused').text(), 'label148')
180-
t.notDeepEqual(contentNode.scrollTop, 0)
181+
assert.calledOnce(scrollIntoView)
181182

182183
getElementById.restore()
183184
})
184185

185186
test('should only scroll on keyboard navigation', t => {
186187
const largeTree = [...Array(150).keys()].map(i => node(`id${i}`, `label${i}`))
187-
const wrapper = mount(<DropdownTreeSelect data={largeTree} showDropdown="initial" />)
188188
const getElementById = stub(document, 'getElementById')
189+
const scrollIntoView = (Element.prototype.scrollIntoView = spy())
190+
const wrapper = mount(<DropdownTreeSelect data={largeTree} showDropdown="initial" />)
189191
const contentNode = wrapper.find('.dropdown-content').getDOMNode()
190192

191193
triggerOnKeyboardKeyDown(wrapper, ['ArrowUp'])
192194
largeTree.forEach((n, index) => {
193-
getElementById.withArgs(`${n.id}_li`).returns({ offsetTop: index, clientHeight: 1 })
195+
getElementById.withArgs(`${n.id}_li`).returns({ offsetTop: index, clientHeight: 1, scrollIntoView })
194196
})
195197

196198
triggerOnKeyboardKeyDown(wrapper, ['ArrowUp'])
@@ -207,7 +209,8 @@ test('should only scroll on keyboard navigation', t => {
207209

208210
// Verify scroll is restored to previous position after keyboard nav
209211
triggerOnKeyboardKeyDown(wrapper, ['ArrowUp', 'ArrowDown'])
210-
t.deepEqual(contentNode.scrollTop, scrollTop)
212+
// Called once for each input, 3 in this case.
213+
assert.calledThrice(scrollIntoView)
211214

212215
getElementById.restore()
213216
})

src/index.test.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,3 +366,17 @@ test('select correct focused node when using external state data container', t =
366366
})
367367
t.deepEqual(wrapper.state().currentFocus, nodeAllData._id)
368368
})
369+
370+
test('should not scroll on select', t => {
371+
const node = (id, label) => ({ id, label, value: label })
372+
const largeTree = [...Array(150).keys()].map(i => node(`id${i}`, `label${i}`))
373+
const wrapper = mount(<DropdownTreeSelect data={largeTree} showDropdown="initial" />)
374+
const { scrollTop } = wrapper.find('.dropdown-content').getDOMNode()
375+
376+
t.deepEqual(scrollTop, 0)
377+
378+
const checkboxes = wrapper.find('.checkbox-item')
379+
checkboxes.at(140).simulate('click')
380+
381+
t.deepEqual(scrollTop, 0)
382+
})

src/tree/index.js

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,7 @@ class Tree extends Component {
5151
const { activeDescendant } = nextProps
5252
const hasSameActiveDescendant = activeDescendant === this.props.activeDescendant
5353
this.computeInstanceProps(nextProps, !hasSameActiveDescendant)
54-
this.setState({ items: this.allVisibleNodes.slice(0, this.currentPage * this.props.pageSize) }, () => {
55-
if (hasSameActiveDescendant) return
56-
const { scrollableTarget } = this.state
57-
const activeLi = activeDescendant && document && document.getElementById(activeDescendant)
58-
if (activeLi && scrollableTarget) {
59-
scrollableTarget.scrollTop = activeLi.offsetTop - (scrollableTarget.clientHeight - activeLi.clientHeight) / 2
60-
}
61-
})
54+
this.setState({ items: this.allVisibleNodes.slice(0, this.currentPage * this.props.pageSize) })
6255
}
6356

6457
componentDidMount = () => {

0 commit comments

Comments
 (0)