Skip to content

Commit

Permalink
[fixed] SelectList focus logic
Browse files Browse the repository at this point in the history
  • Loading branch information
jquense committed Mar 15, 2016
1 parent 4dc1175 commit db5fc11
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 25 deletions.
73 changes: 50 additions & 23 deletions src/SelectList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ import ListOption from './ListOption';
import validateList from './util/validateListInterface';
import scrollTo from 'dom-helpers/util/scrollTo';

import { dataItem } from './util/dataHelpers';
import { dataItem, dataIndexOf } from './util/dataHelpers';
import { widgetEditable } from './util/interaction';

import { instanceId, notify } from './util/widgetHelpers';
import { isDisabled, isReadOnly, contains } from './util/interaction';

let { omit, pick } = _;
let { omit, pick, find } = _;

let propTypes = {

Expand Down Expand Up @@ -51,7 +51,16 @@ let propTypes = {
})
}

function getFirstValue(props) {
var { data, value, valueField } = props
value = _.splat(value);

if (value.length)
return find(data, d => dataIndexOf(value, d, valueField) !== -1)
|| null

return null
}

var SelectList = React.createClass({

Expand All @@ -65,6 +74,19 @@ var SelectList = React.createClass({
willHandle(focused) {
if (focused)
this.focus()
},
didHandle(focused) {
// the rigamarole here is to avoid flicker went clicking an item and
// gaining focus at the same time.
if (focused !== this.state.focused) {
if (!focused)
this.setState({ focusedItem: null })
else if (focused && !this._clicking)
this.setState({
focusedItem: getFirstValue(this.props)
})
this._clicking = false
}
}
})
],
Expand All @@ -81,19 +103,12 @@ var SelectList = React.createClass({
}
},

getDefaultState(props){
getDefaultState(props) {
var { data, value, valueField, multiple } = props
, isRadio = !multiple
, values = _.splat(value)
, first = isRadio && dataItem(data, values[0], valueField)

first = isRadio && first
? first
: ((this.state || {}).focusedItem || null)

return {
focusedItem: first,
dataItems: !isRadio && values.map(item => dataItem(data, item, valueField))
dataItems: multiple &&
_.splat(value).map(item => dataItem(data, item, valueField))
}
},

Expand All @@ -106,7 +121,9 @@ var SelectList = React.createClass({
},

componentWillReceiveProps(nextProps) {
return this.setState(this.getDefaultState(nextProps))
return this.setState(
this.getDefaultState(nextProps)
)
},

componentDidMount() {
Expand Down Expand Up @@ -201,31 +218,35 @@ var SelectList = React.createClass({

if (key === 'End') {
e.preventDefault()
focusedItem = list.last()

if (multiple) this.setState({ focusedItem: list.last() })
else change(list.last())
this.setState({ focusedItem })
if (!multiple) change(focusedItem)
}
else if (key === 'Home' ) {
e.preventDefault()
focusedItem = list.first()

if (multiple) this.setState({ focusedItem: list.first() })
else change(list.first())
this.setState({ focusedItem })
if (!multiple) change(focusedItem)
}
else if (key === 'Enter' || key === ' ' ) {
e.preventDefault()
change(focusedItem)
}
else if (key === 'ArrowDown' || key === 'ArrowRight' ) {
e.preventDefault()
focusedItem = list.next(focusedItem)

if (multiple) this.setState({ focusedItem: list.next(focusedItem) })
else change(list.next(focusedItem))
this.setState({ focusedItem })
if (!multiple) change(focusedItem)
}
else if (key === 'ArrowUp' || key === 'ArrowLeft' ) {
e.preventDefault()
focusedItem = list.prev(focusedItem)

if (multiple) this.setState({ focusedItem: list.prev(focusedItem) })
else change(list.prev(focusedItem))
this.setState({ focusedItem })
if (!multiple) change(focusedItem)
}
else if (multiple && e.keyCode === 65 && e.ctrlKey ) {
e.preventDefault()
Expand Down Expand Up @@ -267,12 +288,15 @@ var SelectList = React.createClass({
notify(this.props.onChange, [data])
},

_change(item, checked){
_change(item, checked) {
var { multiple } = this.props
, values = this.state.dataItems;

multiple = !!multiple

this.clearTimeout('focusedItem')
this.setState({ focusedItem: item })

if (!multiple)
return notify(this.props.onChange, checked ? item : null)

Expand Down Expand Up @@ -343,7 +367,7 @@ function getListItem(parent){
role={type}
aria-checked={!!checked}
>
<label>
<label onMouseDown={onMouseDown}>
<input
name={name}
tabIndex='-1'
Expand All @@ -357,6 +381,9 @@ function getListItem(parent){
</label>
</ListOption>
);
function onMouseDown(e) {
parent._clicking = true
}

function onChange(e){
if (!disabled && !readonly)
Expand Down
9 changes: 7 additions & 2 deletions src/mixins/TimeoutMixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@ module.exports = {
this._unmounted = true;

for (var k in timers) if ( has(timers, k) )
clearTimeout(timers[k])
this.clearTimeout(k)
},

clearTimeout(key) {
var timers = this._timers || {};
window.clearTimeout(timers[key]);
},

setTimeout(key, cb, duration){
Expand All @@ -19,7 +24,7 @@ module.exports = {
if (this._unmounted)
return

clearTimeout(timers[key])
this.clearTimeout(key)
timers[key] = window.setTimeout(() => {
if (!this._unmounted) cb()
}, duration)
Expand Down

0 comments on commit db5fc11

Please sign in to comment.