Hide selected items from autocomplete dropdown (https://github.com/woocommerce/woocommerce-admin/pull/932)

This commit is contained in:
Albert Juhé Lluveras 2018-11-28 16:55:11 -06:00 committed by GitHub
parent c65709f2db
commit d59e5803d3
3 changed files with 52 additions and 7 deletions

View File

@ -6,15 +6,19 @@ import { __, _n, sprintf } from '@wordpress/i18n';
import { Button, withFocusOutside, withSpokenMessages } from '@wordpress/components';
import classnames from 'classnames';
import { Component } from '@wordpress/element';
import { escapeRegExp, map, debounce } from 'lodash';
import { debounce, escapeRegExp } from 'lodash';
import { ENTER, ESCAPE, UP, DOWN, LEFT, TAB, RIGHT } from '@wordpress/keycodes';
import { withInstanceId, compose } from '@wordpress/compose';
function filterOptions( search, options = [], maxResults = 10 ) {
function filterOptions( search, options = [], exclude = [], maxResults = 10 ) {
const filtered = [];
for ( let i = 0; i < options.length; i++ ) {
const option = options[ i ];
if ( exclude.includes( option.value.id ) ) {
continue;
}
// Merge label into keywords
let { keywords = [] } = option;
if ( 'string' === typeof option.label ) {
@ -142,6 +146,7 @@ export class Autocomplete extends Component {
const promise = ( this.activePromise = Promise.resolve(
typeof options === 'function' ? options( query ) : options
).then( optionsData => {
const { selected } = this.props;
if ( promise !== this.activePromise ) {
// Another promise has become active since this one was asked to resolve, so do nothing,
// or else we might end triggering a race condition updating the state.
@ -155,7 +160,7 @@ export class Autocomplete extends Component {
isDisabled: completer.isOptionDisabled ? completer.isOptionDisabled( optionData ) : false,
} ) );
const filteredOptions = filterOptions( this.state.search, keyedOptions );
const filteredOptions = filterOptions( this.state.search, keyedOptions, selected );
const selectedIndex =
filteredOptions.length === this.state.filteredOptions.length ? this.state.selectedIndex : 0;
this.setState( {
@ -171,7 +176,7 @@ export class Autocomplete extends Component {
search( event ) {
const { query: wasQuery } = this.state;
const { completer = {} } = this.props;
const { completer = {}, selected } = this.props;
const container = event.target;
// look for the trigger prefix and search query just before the cursor location
@ -187,7 +192,7 @@ export class Autocomplete extends Component {
// create a regular expression to filter the options
const search = new RegExp( escapeRegExp( query ), 'i' );
// filter the options we already have
const filteredOptions = filterOptions( search, this.state.options );
const filteredOptions = filterOptions( search, this.state.options, selected );
// update the state
this.setState( { selectedIndex: 0, filteredOptions, search, query } );
// announce the count of filtered options but only if they have loaded
@ -276,8 +281,7 @@ export class Autocomplete extends Component {
{ children( { isExpanded, listBoxId, activeId, onChange: this.search } ) }
{ isExpanded && (
<div id={ listBoxId } role="listbox" className={ resultsClasses }>
{ isExpanded &&
map( filteredOptions, ( option, index ) => (
{ filteredOptions.map( ( option, index ) => (
<Button
key={ option.key }
id={ `woocommerce-search__autocomplete-${ instanceId }-${ option.key }` }

View File

@ -128,6 +128,7 @@ class Search extends Component {
<Autocomplete
completer={ autocompleter }
onSelect={ this.selectResult }
selected={ selected.map( s => s.id ) }
staticResults={ staticResults }
>
{ ( { listBoxId, activeId, onChange } ) =>

View File

@ -0,0 +1,40 @@
/** @format */
/**
* External dependencies
*/
import { mount } from 'enzyme';
/**
* Internal dependencies
*/
import { Autocomplete } from '../autocomplete';
describe( 'Autocomplete', () => {
it( 'doesn\'t return matching excluded elements', () => {
const suggestionClassname = 'autocomplete-result';
const search = 'lorem';
const options = [
{ key: '1', label: 'lorem 1', value: { id: '1' } },
{ key: '2', label: 'lorem 2', value: { id: '2' } },
];
const exclude = [ '2' ];
const autocomplete = mount(
<Autocomplete
children={ () => null }
className={ suggestionClassname }
completer={ {} }
selected={ exclude }
/>
);
autocomplete.setState( {
options,
query: {},
search,
} );
autocomplete.instance().search( { target: { value: search } } );
autocomplete.update();
expect( autocomplete.find( '.' + suggestionClassname ).length ).toBe( 1 );
} );
} );