UNPKG

@primer/components

Version:
121 lines (110 loc) 4.78 kB
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } import React, { useCallback, useContext, useEffect, useState } from 'react'; import { AutocompleteContext } from './AutocompleteContext'; import TextInput from '../TextInput'; import { useCombinedRefs } from '../hooks/useCombinedRefs'; const AutocompleteInput = /*#__PURE__*/React.forwardRef(({ as: Component = TextInput, onFocus, onBlur, onChange, onKeyDown, onKeyPress, value, ...props }, forwardedRef) => { const { activeDescendantRef, autocompleteSuggestion = '', id, inputRef, inputValue = '', isMenuDirectlyActivated, setInputValue, setShowMenu, showMenu } = useContext(AutocompleteContext); const combinedInputRef = useCombinedRefs(inputRef, forwardedRef); const [highlightRemainingText, setHighlightRemainingText] = useState(true); const handleInputFocus = useCallback(e => { onFocus && onFocus(e); setShowMenu && setShowMenu(true); }, [onFocus, setShowMenu]); const handleInputBlur = useCallback(e => { onBlur && onBlur(e); // HACK: wait a tick and check the focused element before hiding the autocomplete menu // this prevents the menu from hiding when the user is clicking an option in the Autoselect.Menu, // but still hides the menu when the user blurs the input by tabbing out or clicking somewhere else on the page setTimeout(() => { if (document.activeElement !== combinedInputRef.current) { setShowMenu && setShowMenu(false); } }, 0); }, [onBlur, setShowMenu]); const handleInputChange = useCallback(e => { onChange && onChange(e); setInputValue && setInputValue(e.currentTarget.value); if (!showMenu) { setShowMenu && setShowMenu(true); } }, [onChange, setInputValue, setShowMenu, showMenu]); const handleInputKeyDown = useCallback(e => { var _inputRef$current; if (e.key === 'Backspace') { setHighlightRemainingText(false); } if (e.key === 'Escape' && inputRef !== null && inputRef !== void 0 && (_inputRef$current = inputRef.current) !== null && _inputRef$current !== void 0 && _inputRef$current.value) { setInputValue && setInputValue(''); inputRef.current.value = ''; } }, [inputRef, setInputValue, setHighlightRemainingText]); const handleInputKeyUp = useCallback(e => { if (e.key === 'Backspace') { setHighlightRemainingText(true); } }, [setHighlightRemainingText]); const onInputKeyPress = useCallback(event => { if (activeDescendantRef && event.key === 'Enter' && activeDescendantRef.current) { event.preventDefault(); event.nativeEvent.stopImmediatePropagation(); // Forward Enter key press to active descendant so that item gets activated const activeDescendantEvent = new KeyboardEvent(event.type, event.nativeEvent); activeDescendantRef.current.dispatchEvent(activeDescendantEvent); } }, [activeDescendantRef]); useEffect(() => { if (!(inputRef !== null && inputRef !== void 0 && inputRef.current)) { return; } // resets input value to being empty after a selection has been made if (!autocompleteSuggestion) { inputRef.current.value = inputValue; } // TODO: fix bug where this function prevents `onChange` from being triggered if the highlighted item text // is the same as what I'm typing // e.g.: typing 'tw' highights 'two', but when I 'two', the text input change does not get triggered if (highlightRemainingText && autocompleteSuggestion && (inputValue || isMenuDirectlyActivated)) { inputRef.current.value = autocompleteSuggestion; if (autocompleteSuggestion.toLowerCase().indexOf(inputValue.toLowerCase()) === 0) { inputRef.current.setSelectionRange(inputValue.length, autocompleteSuggestion.length); } } }, [autocompleteSuggestion, inputValue]); useEffect(() => { if (value) { setInputValue && setInputValue(value.toString()); } }, [value]); return /*#__PURE__*/React.createElement(Component, _extends({ onFocus: handleInputFocus, onBlur: handleInputBlur, onChange: handleInputChange, onKeyDown: handleInputKeyDown, onKeyPress: onInputKeyPress, onKeyUp: handleInputKeyUp, ref: combinedInputRef, "aria-controls": `${id}-listbox`, "aria-autocomplete": "both", role: "combobox", "aria-expanded": showMenu, "aria-haspopup": "listbox", "aria-owns": `${id}-listbox` }, props)); }); export default AutocompleteInput;