diff --git a/.flowconfig b/.flowconfig index 363b337..b68c78d 100644 --- a/.flowconfig +++ b/.flowconfig @@ -7,3 +7,4 @@ [lints] [options] +suppress_comment= \\(.\\|\n\\)*\\$FlowFixMe \ No newline at end of file diff --git a/src/Typeahead.jsx b/src/Typeahead.jsx index 81ec75b..d124ba9 100644 --- a/src/Typeahead.jsx +++ b/src/Typeahead.jsx @@ -186,8 +186,9 @@ export default class Typeahead extends PureComponent { this.setState({ typedLabel: label }, () => { + const highlightedRowIndex = this._gethighlightedRowIndexByTypedLabel(); this.setState({ - highlightedRowIndex: this._gethighlightedRowIndexByTypedLabel() + highlightedRowIndex: highlightedRowIndex }); if (label === '' && this.props.isClearable) { @@ -256,9 +257,15 @@ export default class Typeahead extends PureComponent { }; _gethighlightedRowIndexByTypedLabel = (): number | typeof undefined => { - const optionIndex = this._getFilteredOptions().findIndex(this._byTypedLabel); - const typedLabelFoundInOptions = optionIndex !== -1; - return typedLabelFoundInOptions ? optionIndex : NOTHING_HIGHLIGHTED; + const rows = this._generateRows( + this._getFilteredOptions(), + this.props.groups, + this.props, + this._isUnknownValue() + ); + // $FlowFixMe Flow does not recognize that filter narrowed down the list to only OptionRows + const foundRow = rows.filter(_isOptionRow).find(this._rowByTypedLabel); + return foundRow ? foundRow.rowIndex : NOTHING_HIGHLIGHTED; }; _updateValue = (afterValueUpdated: Function): void => { @@ -378,6 +385,9 @@ export default class Typeahead extends PureComponent { _byTypedLabel = (option: Option | Group) => this._typedLabelHasText() && option.label.toLowerCase().includes(this.state.typedLabel.toLowerCase()); + _rowByTypedLabel = (row: OptionRow) => this._typedLabelHasText() && + row.option.label.toLowerCase().includes(this.state.typedLabel.toLowerCase()); + _byGroupAndTypedLabel = (option: Option) => { if (this.props.groups !== undefined) { const matchingGroupValues = this.props.groups.filter(this._byTypedLabel).map(group => group.value); @@ -636,8 +646,8 @@ export default class Typeahead extends PureComponent { return this.props.menuWidth ? this.props.menuWidth : this.props.estimateMenuWidth - ? this._estimateMenuWidth(this.props.estimateMenuWidth, rows) - : undefined; + ? this._estimateMenuWidth(this.props.estimateMenuWidth, rows) + : undefined; }; renderMenu(): Node { @@ -784,7 +794,7 @@ function _estimateMenuWidth(rows: Row[]): Optional { : undefined; } -function _isOptionRow(row) { +function _isOptionRow(row: Row): boolean { return row.hasOwnProperty('option'); } diff --git a/src/Typeahead.spec.jsx b/src/Typeahead.spec.jsx index ca72f35..c999aa9 100644 --- a/src/Typeahead.spec.jsx +++ b/src/Typeahead.spec.jsx @@ -849,6 +849,25 @@ describe('Typeahead should', () => { expect(group2.exists()).toBe(true); }); + it('select single option when exactly searching for an option in a grouped list', () => { + const singleGroup = [ + {label: 'Group 1', value: 'group1'} + ]; + const optionsWithGroups = [ + {label: 'label1', value: 'value1', group: 'group1'}, + {label: 'label2', value: 'value2', group: 'group1'} + ]; + const wrapper = mount(); + wrapper.find('input').simulate('focus'); + simulateKeys(wrapper.find('input'), 'label2'); + const value2Option = wrapper.find('.typeahead__option[data-value="value2"]'); + expect(value2Option.exists()).toBe(true); + expect(value2Option.prop('data-group')).toEqual('group1'); + expect(Boolean(value2Option.prop('data-highlighted'))).toEqual(true); + wrapper.find('input').simulate('blur'); + expect(wrapper.state('value')).toEqual('value2'); + }); + it('render options of a group when searching for a group label', () => { const wrapper = mount(); wrapper.find('input').simulate('focus'); @@ -1108,4 +1127,4 @@ describe('Typeahead should', () => { window.top = top; window.dispatchEvent(resizeEvent); } -}); +}); \ No newline at end of file