import React, { useRef } from 'react' import type PopperJs from 'popper.js' import { Search16 } from '@toptal/picasso-icons' import { OutlinedInput } from '@toptal/picasso-outlined-input' import { Popper } from '@toptal/picasso-popper' import { MenuItem } from '@toptal/picasso-menu' import { documentable, forwardRef, noop, useCombinedRefs, } from '@toptal/picasso-utils' import { InputAdornment } from '@toptal/picasso-input-adornment' import { useFieldsLayoutContext } from '@toptal/picasso-form' import { twMerge, twJoin } from '@toptal/picasso-tailwind-merge' import { SelectCaret } from '../SelectCaret' import { NonNativeSelectLoader } from '../NonNativeSelectLoader' import type { ValueType, SelectProps } from '../SelectBase' import { useAdornments, useSelectState, useSelectProps, renderOption as defaultRenderOption, getOptionText, DEFAULT_LIMIT, DEFAULT_SEARCH_THRESHOLD, countOptions, filterFlatOptions as defaultFilterOptions, } from '../SelectBase' import { NonNativeSelectOptions } from '../NonNativeSelectOptions' import { NonNativeSelectLimitFooter } from '../NonNativeSelectLimitFooter' const DEFAULT_EMPTY_ARRAY_VALUE: ValueType[] = [] const classesByWidth: Record< Exclude, string > = { auto: '', full: 'w-full', shrink: 'w-auto', } export const NonNativeSelect = documentable( forwardRef( // eslint-disable-next-line max-lines-per-function, complexity ( props: SelectProps, ref: React.Ref | null ) => { const { className, style, width = 'full', menuWidth, loading = false, id, icon, iconPosition = 'start', name, noOptionsText = 'No matches found', renderOption = defaultRenderOption, placeholder, disabled = false, disablePortal, status = 'default', multiple, value = multiple ? DEFAULT_EMPTY_ARRAY_VALUE : '', size = 'medium', enableReset, popperContainer, enableAutofill = false, enableResetSearch, autoComplete, searchPlaceholder = 'Search', searchThreshold = DEFAULT_SEARCH_THRESHOLD, limit = DEFAULT_LIMIT, getDisplayValue = getOptionText, options, onChange = noop, filterOptions = defaultFilterOptions, // eslint-disable-next-line @typescript-eslint/no-unused-vars native, testIds, highlight, ...rest } = props const selectRef = useCombinedRefs( ref, useRef(null) ) const searchInputRef = useRef(null) const popperRef = useRef(null) const inputWrapperRef = useRef(null) const selectState = useSelectState({ getDisplayValue, filterFlatOptions: filterOptions, options, disabled, multiple, value, searchThreshold, limit, }) const { highlightedIndex, isOpen, showSearch, filterOptionsValue, displayValue, selection, filteredOptions, } = selectState const { getItemProps, getRootProps, getInputProps, getSearchInputProps } = useSelectProps({ selectRef, popperRef, searchInputRef, selectProps: props, selectState, }) const { layout } = useFieldsLayoutContext() const searchInput = showSearch ? ( } placeholder={searchPlaceholder} enableReset={enableResetSearch} size={size} value={filterOptionsValue} testIds={testIds} aria-autocomplete='list' data-testid={testIds?.searchInput} /* eslint-disable-next-line react/jsx-props-no-spreading */ {...getSearchInputProps()} /> ) : null const rootProps = getRootProps() const [startAdornment, endAdornment] = useAdornments({ position: iconPosition, icon, disabled, }) const selectComponent = ( <>
{!enableAutofill && name && ( )}
{!disabled && isOpen && ( {loading ? ( ) : ( ) : null } testIds={{ noOptions: testIds?.noOptions, }} /> )} )} ) return (
{selectComponent}
) } ) ) NonNativeSelect.displayName = 'NonNativeSelect' export default NonNativeSelect