diff --git a/lib/combobox.js b/lib/combobox.js index df19cfe4..0bf0998c 100644 --- a/lib/combobox.js +++ b/lib/combobox.js @@ -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 @@ -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); }, @@ -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) @@ -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() {