Skip to content
This repository was archived by the owner on Jul 19, 2019. It is now read-only.

only focus ComboboxOption elements #13

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 27 additions & 10 deletions lib/combobox.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,26 +96,30 @@ module.exports = React.createClass({
var activedescendant;
var isEmpty = true;
children = children || this.props.children;
optionIndexes = [];
React.Children.forEach(children, function(child, index) {
if (child.type !== ComboboxOption.type)
// allow random elements to live in this list
return;
isEmpty = false;
isEmpty = false;
// TODO: cloneWithProps and map instead of altering the children in-place
var props = child.props;
optionIndexes.push(index);
if (this.state.value === props.value) {
// need an ID for WAI-ARIA
props.id = props.id || 'rf-combobox-selected-'+(++guid);
props.isSelected = true
props.isSelected = true;
activedescendant = props.id;
}
props.onBlur = this.handleOptionBlur;
props.onClick = this.selectOption.bind(this, child);
props.onFocus = this.handleOptionFocus;
props.onKeyDown = this.handleOptionKeyDown.bind(this, child);
props.onMouseEnter = this.handleOptionMouseEnter.bind(this, index);
props.onMouseEnter = this.handleOptionMouseEnter.bind(
this, optionIndexes.length - 1);
}.bind(this));
return {
optionIndexes: optionIndexes,
children: children,
activedescendant: activedescendant,
isEmpty: isEmpty
Expand Down Expand Up @@ -308,21 +312,31 @@ module.exports = React.createClass({

focusPrevious: function() {
if (this.state.menu.isEmpty) return;
var last = this.props.children.length - 1;
var last = this.state.menu.optionIndexes.length - 1;
var index = this.state.focusedIndex == null ?
last : this.state.focusedIndex - 1;
this.focusOptionAtIndex(index);
},

focusSelectedOption: function() {
var selectedIndex;
// we have to do two hops to go from the DOM index to option index
var selectedDomIndex;

// hop 1: dom index
React.Children.forEach(this.props.children, function(child, index) {
if (child.props.value === this.state.value)
selectedIndex = index;
selectedDomIndex = index;
}.bind(this));

// hop 2: option index
var selectedOptionIndex;
this.state.menu.optionIndexes.forEach(function(domIndex, optIndex) {
if (domIndex === selectedDomIndex) selectedOptionIndex = optIndex;
});

this.showList();
this.setState({
focusedIndex: selectedIndex
focusedIndex: selectedOptionIndex
}, this.focusOption);
},

Expand All @@ -337,11 +351,13 @@ module.exports = React.createClass({
return inputValue || value;
},

// index is the index of the option among the list of only options,
// NOT among all elements in the DOM
focusOptionAtIndex: function(index) {
if (!this.state.isOpen && this.state.value)
return this.focusSelectedOption();
this.showList();
var length = this.props.children.length;
var length = this.state.menu.optionIndexes.length;
if (index === -1)
index = length - 1;
else if (index === length)
Expand All @@ -352,8 +368,9 @@ module.exports = React.createClass({
},

focusOption: function() {
var index = this.state.focusedIndex;
this.refs.list.getDOMNode().childNodes[index].focus();
var optIndex = this.state.focusedIndex;
var domIndex = this.state.menu.optionIndexes[optIndex];
this.refs.list.getDOMNode().childNodes[domIndex].focus();
},

render: function() {
Expand Down