text: /**
   * External dependencies
   */
  import PropTypes from 'prop-types';
  import { useCallback, useRef } from '@wordpress/element';
  import classNames from 'classnames';
  import Downshift from 'downshift';
  import { __, sprintf } from '@wordpress/i18n';
  
  /**
   * Internal dependencies
   */
  import DropdownSelectorInput from './input';
  import DropdownSelectorInputWrapper from './input-wrapper';
  import DropdownSelectorMenu from './menu';
  import DropdownSelectorSelectedChip from './selected-chip';
  import DropdownSelectorSelectedValue from './selected-value';
  import './style.scss';
  
  /**
   * Component used to show an input box with a dropdown with suggestions.
   */
  const DropdownSelector = ( {
  	attributeLabel = '',
  	className,
  	checked = [],
  	inputLabel = '',
  	isDisabled = false,
  	isLoading = false,
  	multiple = false,
  	onChange = () => {},
  	options = [],
  } ) => {
  	const inputRef = useRef( null );
  
  	const classes = classNames( className, 'wc-block-dropdown-selector', {
  		'is-disabled': isDisabled,
  		'is-loading': isLoading,
  	} );
  
  	/**
  	 * State reducer for the downshift component.
  	 * See: https://github.com/downshift-js/downshift#statereducer
  	 */
  	const stateReducer = useCallback(
  		( state, changes ) => {
  			switch ( changes.type ) {
  				case Downshift.stateChangeTypes.keyDownEnter:
  				case Downshift.stateChangeTypes.clickItem:
  					return {
  						...changes,
  						highlightedIndex: state.highlightedIndex,
  						isOpen: multiple,
  						inputValue: '',
  					};
  				case Downshift.stateChangeTypes.blurInput:
  				case Downshift.stateChangeTypes.mouseUp:
  					return {
  						...changes,
  						inputValue: state.inputValue,
  					};
  				default:
  					return changes;
  			}
  		},
  		[ multiple ]
  	);
  
  	return (
  		<Downshift
  			onChange={ onChange }
  			selectedItem={ null }
  			stateReducer={ stateReducer }
  		>
  			{ ( {
  				getInputProps,
  				getItemProps,
  				getLabelProps,
  				getMenuProps,
  				highlightedIndex,
  				inputValue,
  				isOpen,
  				openMenu,
  			} ) => (
  				<div
  					className={ classNames( classes, {
  						'is-multiple': multiple,
  						'is-single': ! multiple,
  					} ) }
  				>
  					{ /* eslint-disable-next-line jsx-a11y/label-has-for */ }
  					<label
  						{ ...getLabelProps( {
  							className: 'screen-reader-text',
  						} ) }
  					>
  						{ inputLabel }
  					</label>
  					<DropdownSelectorInputWrapper
  						isOpen={ isOpen }
  						onClick={ () => inputRef.current.focus() }
  					>
  						{ checked.map( ( value ) => {
  							const option = options.find(
  								( o ) => o.value === value
  							);
  							const onRemoveItem = ( val ) => {
  								onChange( val );
  								inputRef.current.focus();
  							};
  							return multiple ? (
  								<DropdownSelectorSelectedChip
  									key={ value }
  									onRemoveItem={ onRemoveItem }
  									option={ option }
  								/>
  							) : (
  								<DropdownSelectorSelectedValue
  									key={ value }
  									onClick={ () => inputRef.current.focus() }
  									onRemoveItem={ onRemoveItem }
  									option={ option }
  								/>
  							);
  						} ) }
  						<DropdownSelectorInput
  							checked={ checked }
  							getInputProps={ getInputProps }
  							inputRef={ inputRef }
  							isDisabled={ isDisabled }
  							onFocus={ openMenu }
  							onRemoveItem={ ( val ) => {
  								onChange( val );
  								inputRef.current.focus();
  							} }
  							placeholder={
  								checked.length > 0 && multiple
  									? null
  									: sprintf(
  											// Translators: %s attribute name.
  											__(
  												'Any %s',
  												'woocommerce'
  											),
  											attributeLabel
  									  )
  							}
  							tabIndex={
  								// When it's a single selector and there is one element selected,
  								// we make the input non-focusable with the keyboard because it's
  								// visually hidden. The input is still rendered, though, because it
  								// must be possible to focus it when pressing the select value chip.
  								! multiple && checked.length > 0 ? '-1' : '0'
  							}
  							value={ inputValue }
  						/>
  					</DropdownSelectorInputWrapper>
  					{ isOpen && ! isDisabled && (
  						<DropdownSelectorMenu
  							checked={ checked }
  							getItemProps={ getItemProps }
  							getMenuProps={ getMenuProps }
  							highlightedIndex={ highlightedIndex }
  							options={ options.filter(
  								( option ) =>
  									! inputValue ||
  									option.value.startsWith( inputValue )
  							) }
  						/>
  					) }
  				</div>
  			) }
  		</Downshift>
  	);
  };
  
  DropdownSelector.propTypes = {
  	attributeLabel: PropTypes.string,
  	checked: PropTypes.array,
  	className: PropTypes.string,
  	inputLabel: PropTypes.string,
  	isDisabled: PropTypes.bool,
  	isLoading: PropTypes.bool,
  	limit: PropTypes.number,
  	onChange: PropTypes.func,
  	options: PropTypes.arrayOf(
  		PropTypes.shape( {
  			label: PropTypes.node.isRequired,
  			value: PropTypes.string.isRequired,
  		} )
  	),
  };
  
  export default DropdownSelector;
  