import classNames from 'classnames'; import * as React from 'react'; import { isFunction } from '@aws-amplify/ui'; import { AutocompleteOption } from './AutocompleteOption'; import { AutocompleteMenu } from './AutocompleteMenu'; import { useAutocomplete } from './useAutocomplete'; import { HighlightMatch } from '../HighlightMatch/HighlightMatch'; import { SearchField } from '../SearchField'; import { View } from '../View'; import { ComponentClassNames } from '../shared/constants'; import type { AutocompleteComboboxProps, AutocompleteProps, BaseAutocompleteProps, ComboBoxOption, ForwardRefPrimitive, Primitive, } from '../types'; export const AutocompletePrimitive: Primitive = ( { className, defaultValue, value, isLoading = false, menuSlots = {}, options, optionFilter, onBlur, onChange, onClear, onClick, onSelect, onSubmit, renderOption, testId, ...rest }, ref ) => { const { activeOptionId, autocompleteId, composedValue, filteredOptions, handleOnBlur, handleOnClear, handleOnClick, handleOnChange, handleOnKeyDown, isControlled, isCustomFiltering, isMenuOpen, listboxId, menuId, optionBaseId, setActiveOption, setIsMenuOpen, setInternalValue, } = useAutocomplete({ defaultValue, value, options, optionFilter, onBlur, onChange, onClear, onClick, onSelect, onSubmit, }); const comboboxProps: AutocompleteComboboxProps = { role: 'combobox', 'aria-activedescendant': activeOptionId, 'aria-autocomplete': 'list', 'aria-controls': isMenuOpen ? menuId : undefined, 'aria-expanded': isMenuOpen, 'aria-haspopup': 'listbox', 'aria-owns': isMenuOpen ? menuId : undefined, }; const Options = filteredOptions.map((option: ComboBoxOption, idx) => { const { id, label, ...rest } = option; const handleOnClick: React.MouseEventHandler = () => { setIsMenuOpen(false); setActiveOption(null); if (!isControlled) { setInternalValue(label); } if (isFunction(onSelect)) { onSelect(option); } }; // This is required. Mousedown event will fire a blur event by default // and so the menu will close before the click event on an option gets a chance to fire const handleOnMouseDown: React.MouseEventHandler = ( event ) => { event.preventDefault(); }; const handleOnMouseMove: React.MouseEventHandler = () => { setActiveOption(option); }; const optionId = id ?? `${optionBaseId}-option-${idx}`; const isActive = optionId === activeOptionId; return ( {isFunction(renderOption) ? ( renderOption(option, composedValue) ) : isCustomFiltering ? ( label ) : ( {label} )} ); }); return ( {isMenuOpen ? ( {Options} ) : null} ); }; /** * [📖 Docs](https://ui.docs.amplify.aws/react/components/autocomplete) */ export const Autocomplete: ForwardRefPrimitive = React.forwardRef(AutocompletePrimitive); Autocomplete.displayName = 'Autocomplete';