/** * External dependencies */ import { isEmpty, noop } from 'lodash'; import classNames from 'classnames'; // eslint-disable-next-line no-restricted-imports import type { ChangeEvent, FocusEvent, ReactNode, Ref } from 'react'; /** * GeChiUI dependencies */ import { useInstanceId } from '@gechiui/compose'; import { useState, forwardRef } from '@gechiui/element'; import { Icon, chevronDown } from '@gechiui/icons'; /** * Internal dependencies */ import BaseControl from '../base-control'; import InputBase from '../input-control/input-base'; import type { InputBaseProps, LabelPosition } from '../input-control/types'; import { Select, DownArrowWrapper } from './styles/select-control-styles'; import type { Size } from './types'; import type { GeChiUIComponentProps } from '../ui/context'; function useUniqueId( idProp?: string ) { const instanceId = useInstanceId( SelectControl ); const id = `inspector-select-control-${ instanceId }`; return idProp || id; } export interface SelectControlProps extends Omit< InputBaseProps, 'children' | 'isFocused' > { help?: string; hideLabelFromVision?: boolean; multiple?: boolean; onBlur?: ( event: FocusEvent< HTMLSelectElement > ) => void; onFocus?: ( event: FocusEvent< HTMLSelectElement > ) => void; onChange?: ( value: string | string[], extra?: { event?: ChangeEvent< HTMLSelectElement > } ) => void; options?: { label: string; value: string; id?: string; disabled?: boolean; }[]; size?: Size; value?: string | string[]; labelPosition?: LabelPosition; children?: ReactNode; } function SelectControl( { className, disabled = false, help, hideLabelFromVision, id: idProp, label, multiple = false, onBlur = noop, onChange = noop, onFocus = noop, options = [], size = 'default', value: valueProp, labelPosition = 'top', children, prefix, suffix, ...props }: GeChiUIComponentProps< SelectControlProps, 'select', false >, ref: Ref< HTMLSelectElement > ) { const [ isFocused, setIsFocused ] = useState( false ); const id = useUniqueId( idProp ); const helpId = help ? `${ id }__help` : undefined; // Disable reason: A select with an onchange throws a warning if ( isEmpty( options ) && ! children ) return null; const handleOnBlur = ( event: FocusEvent< HTMLSelectElement > ) => { onBlur( event ); setIsFocused( false ); }; const handleOnFocus = ( event: FocusEvent< HTMLSelectElement > ) => { onFocus( event ); setIsFocused( true ); }; const handleOnChange = ( event: ChangeEvent< HTMLSelectElement > ) => { if ( multiple ) { const selectedOptions = Array.from( event.target.options ).filter( ( { selected } ) => selected ); const newValues = selectedOptions.map( ( { value } ) => value ); onChange( newValues ); return; } onChange( event.target.value, { event } ); }; const classes = classNames( 'components-select-control', className ); /* eslint-disable jsx-a11y/no-onchange */ return ( ) } prefix={ prefix } labelPosition={ labelPosition } > ); /* eslint-enable jsx-a11y/no-onchange */ } const ForwardedComponent = forwardRef( SelectControl ); export default ForwardedComponent;