Hide selected items from autocomplete dropdown (https://github.com/woocommerce/woocommerce-admin/pull/932)
This commit is contained in:
parent
c65709f2db
commit
d59e5803d3
|
@ -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 }` }
|
||||
|
|
|
@ -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 } ) =>
|
||||
|
|
|
@ -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 );
|
||||
} );
|
||||
} );
|
Loading…
Reference in New Issue