// @flow import React, { useCallback, useContext, useEffect, useRef } from 'react'; import { SearchContext } from './SearchContext'; import ButtonIcon from './ButtonIcon'; import styles from './SearchInput.css'; type Props = {||}; export default function SearchInput(props: Props) { // We use the wrapper searchContext object rather than its individual parts– // (specifically for the useCallback input arrays below)– // because a change in any one value (e.g. ids array) impacts other values (e.g. currentIndex). // It's easier to avoid stale scope issues if we depend on the entire search state. const searchContext = useContext(SearchContext); const inputRef = useRef(); const handleTextChange = useCallback(({ currentTarget }) => { searchContext.updateText(currentTarget.value); }); const selectNext = useCallback(() => { const { currentIndex } = searchContext; if (currentIndex !== null) { searchContext.updateCurrentIndex(currentIndex + 1); } }, [searchContext]); const selectPrevious = useCallback(() => { const { currentIndex } = searchContext; if (currentIndex !== null) { searchContext.updateCurrentIndex(currentIndex - 1); } }, [searchContext]); const resetSearch = useCallback(() => { searchContext.updateText(''); }, [searchContext]); const handleInputKeyPress = useCallback( ({ key }) => { if (key === 'Enter') { const { currentIndex, ids } = searchContext; if (currentIndex !== null) { if (currentIndex + 1 < ids.length) { searchContext.updateCurrentIndex(currentIndex + 1); } else { searchContext.updateCurrentIndex(0); } } } }, [searchContext] ); // Auto-focus search input useEffect(() => { const handleWindowKeyDown = event => { const { key, metaKey } = event; if (key === 'f' && metaKey) { if (inputRef.current !== null) { inputRef.current.focus(); event.preventDefault(); } } }; window.addEventListener('keydown', handleWindowKeyDown); return () => window.removeEventListener('keydown', handleWindowKeyDown); }, [inputRef]); const { currentIndex, ids, text } = searchContext; return (