import React from 'react'; import { TextInputGroup, TextInputGroupMain, TextInputGroupUtilities, Button, Menu, MenuContent, MenuList, MenuItem, Popper, Chip, ChipGroup, Divider } from '@patternfly/react-core'; import SearchIcon from '@patternfly/react-icons/dist/esm/icons/search-icon'; import TimesIcon from '@patternfly/react-icons/dist/esm/icons/times-icon'; export const AutoCompleteSearch: React.FunctionComponent = () => { const [inputValue, setInputValue] = React.useState(''); const [menuIsOpen, setMenuIsOpen] = React.useState(false); const [currentChips, setCurrentChips] = React.useState([]); const [hint, setHint] = React.useState(''); /** auto-completing suggestion text items to be shown in the menu */ const suggestionItems = ['Cluster', 'Kind', 'Label', 'Name', 'Namespace', 'Status']; const [menuItems, setMenuItems] = React.useState([]); /** refs used to detect when clicks occur inside vs outside of the textInputGroup and menu popper */ const menuRef = React.useRef(); const textInputGroupRef = React.useRef(); /** callback for updating the inputValue state in this component so that the input can be controlled */ const handleInputChange = (_event: React.FormEvent, value: string) => { setInputValue(value); }; /** callback for removing a chip from the chip selections */ const deleteChip = (chipToDelete: string) => { const newChips = currentChips.filter((chip) => !Object.is(chip, chipToDelete)); setCurrentChips(newChips); }; /** callback for clearing all selected chips and the text input */ const clearChipsAndInput = () => { setCurrentChips([]); setInputValue(''); }; React.useEffect(() => { /** in the menu only show items that include the text in the input */ const filteredMenuItems = suggestionItems .filter((item) => !inputValue || item.toLowerCase().includes(inputValue.toString().toLowerCase())) .map((currentValue, index) => ( {currentValue} )); /** in the menu show a disabled "no result" when all menu items are filtered out */ if (filteredMenuItems.length === 0) { const noResultItem = ( No results found ); setMenuItems([noResultItem]); setHint(''); return; } /** The hint is set whenever there is only one autocomplete option left. */ if (filteredMenuItems.length === 1) { const hint = filteredMenuItems[0].props.children; if (hint.toLowerCase().indexOf(inputValue.toLowerCase())) { // the match was found in a place other than the start, so typeahead wouldn't work right setHint(''); } else { // use the input for the first part, otherwise case difference could make things look wrong setHint(inputValue + hint.substr(inputValue.length)); } } else { setHint(''); } /** add a heading to the menu */ const headingItem = ( Suggestions ); const divider = ; setMenuItems([headingItem, divider, ...filteredMenuItems]); }, [inputValue]); /** add the given string as a chip in the chip group and clear the input */ const addChip = (newChipText: string) => { setCurrentChips([...currentChips, `${newChipText}`]); setInputValue(''); }; /** add the current input value as a chip */ const handleEnter = () => { if (inputValue.length) { addChip(inputValue); } }; const handleTab = () => { if (menuItems.length === 3) { setInputValue(menuItems[2].props.children); } setMenuIsOpen(false); }; /** close the menu when escape is hit */ const handleEscape = () => { setMenuIsOpen(false); }; /** allow the user to focus on the menu and navigate using the arrow keys */ const handleArrowKey = () => {