UNPKG

@awsui/components-react

Version:

AWS UI is a collection of [React](https://reactjs.org/) components that help create intuitive, responsive, and accessible user experiences for web applications. It is developed by Amazon Web Services (AWS). This work is available under the terms of the [A

126 lines (125 loc) • 8.35 kB
import { __assign, __rest } from "tslib"; import clsx from 'clsx'; import React, { useCallback, useMemo, useRef, useState } from 'react'; import { useAutosuggestItems, useFilteredItems, useKeyboardHandler, useSelectOption, useSelectVisibleOption, useHighlightVisibleOption } from './controller'; import { useDropdownA11yProps } from './a11y'; import Announcer from './announcer'; import VirtualList from './virtual-list'; import PlainList from './plain-list'; import Dropdown from '../internal/components/dropdown'; import DropdownStatus from '../internal/components/dropdown-status'; import { useFormFieldContext } from '../internal/context/form-field-context'; import { getBaseProps } from '../internal/base-component'; import { useUniqueId } from '../internal/hooks/use-unique-id'; import useForwardFocus from '../internal/hooks/forward-focus'; import { fireNonCancelableEvent } from '../internal/events'; import { useHighlightedOption } from '../internal/components/options-list/utils/use-highlight-option'; import InternalInput from '../input/internal'; import { useTelemetry } from '../internal/hooks/use-telemetry'; import styles from './styles.css.js'; var withinRange = function (items, index) { return index >= -1 && index < items.length; }; var isInteractive = function (option) { return !!option && !option.disabled && option.type !== 'parent'; }; var handleMouseEvent = function (handler, usingMouse) { return function (e) { e.preventDefault(); usingMouse.current = true; var mouseTarget = e.detail.mouseTarget; if (mouseTarget !== undefined) { var index = parseInt(mouseTarget, 10); if (index === index) { handler(index); } } }; }; var useLoadMoreItems = function (onLoadItems) { var lastFilteringText = useRef(null); return useCallback(function (firstPage, samePage, filteringText) { if (samePage || !firstPage || filteringText === undefined || lastFilteringText.current !== filteringText) { if (filteringText !== undefined) { lastFilteringText.current = filteringText; } if (lastFilteringText.current !== null && onLoadItems) { fireNonCancelableEvent(onLoadItems, { filteringText: lastFilteringText.current, firstPage: firstPage, samePage: samePage }); } } }, [onLoadItems]); }; var Autosuggest = React.forwardRef(function (props, ref) { var _a; useTelemetry('Autosuggest'); var value = props.value, onChange = props.onChange, onBlur = props.onBlur, onFocus = props.onFocus, onKeyUp = props.onKeyUp, onLoadItems = props.onLoadItems, options = props.options, _b = props.filteringType, filteringType = _b === void 0 ? 'auto' : _b, _c = props.statusType, statusType = _c === void 0 ? 'finished' : _c, placeholder = props.placeholder, name = props.name, disabled = props.disabled, _d = props.disableBrowserAutocorrect, disableBrowserAutocorrect = _d === void 0 ? false : _d, autoFocus = props.autoFocus, readOnly = props.readOnly, ariaLabel = props.ariaLabel, ariaRequired = props.ariaRequired, enteredTextLabel = props.enteredTextLabel, onKeyDown = props.onKeyDown, virtualScroll = props.virtualScroll, rest = __rest(props, ["value", "onChange", "onBlur", "onFocus", "onKeyUp", "onLoadItems", "options", "filteringType", "statusType", "placeholder", "name", "disabled", "disableBrowserAutocorrect", "autoFocus", "readOnly", "ariaLabel", "ariaRequired", "enteredTextLabel", "onKeyDown", "virtualScroll"]); var usingMouse = useRef(true); var _e = useState(false), showAll = _e[0], setShowAll = _e[1]; var _f = useState(false), open = _f[0], setOpen = _f[1]; var autosuggestItems = useAutosuggestItems(options); var filteredItems = useFilteredItems(autosuggestItems, value, filteringType, showAll); var openDropdown = useCallback(function () { return !readOnly && setOpen(true); }, [readOnly]); var scrollToIndex = useRef(null); var _g = useHighlightedOption({ options: filteredItems, scrollToIndex: (_a = scrollToIndex.current) !== null && _a !== void 0 ? _a : undefined, withinRange: withinRange, isInteractive: isInteractive }), highlightedOption = _g.highlightedOption, moveHighlight = _g.moveHighlight, resetHighlight = _g.resetHighlight, setHighlightedIndex = _g.setHighlightedIndex; var closeDropdown = useCallback(function () { setOpen(false); resetHighlight(); }, [setOpen, resetHighlight]); var handleBlur = useCallback(function (e) { closeDropdown(); onBlur && onBlur(e); }, [closeDropdown, onBlur]); var selectOption = useSelectOption(onChange, closeDropdown); var selectHighlighted = useCallback(function () { if (highlightedOption) { selectOption(highlightedOption); } else { closeDropdown(); } }, [selectOption, highlightedOption, closeDropdown]); var fireLoadMore = useLoadMoreItems(onLoadItems); var handleDelayedInput = useCallback(function (_a) { var detail = _a.detail; fireLoadMore(true, false, detail.value); }, [fireLoadMore]); var handleInputChange = useCallback(function (e) { openDropdown(); setShowAll(false); resetHighlight(); onChange && onChange(e); }, [onChange, openDropdown, resetHighlight, setShowAll]); var highlightVisibleOption = useHighlightVisibleOption(filteredItems, setHighlightedIndex, isInteractive); var selectVisibleOption = useSelectVisibleOption(filteredItems, selectOption, isInteractive); var handleMouseDown = useMemo(function () { return handleMouseEvent(selectVisibleOption, usingMouse); }, [selectVisibleOption, usingMouse]); var handleMouseMove = useMemo(function () { return handleMouseEvent(highlightVisibleOption, usingMouse); }, [highlightVisibleOption, usingMouse]); var handleKeyDown = useKeyboardHandler(moveHighlight, openDropdown, selectHighlighted, usingMouse, onKeyDown); var handleLoadMore = useCallback(function () { options && options.length && statusType === 'pending' && fireLoadMore(false, false); }, [fireLoadMore, options, statusType]); var handleRecoveryClick = useCallback(function () { return fireLoadMore(false, true); }, [fireLoadMore]); var formFieldContext = useFormFieldContext(rest); var baseProps = getBaseProps(rest); var inputRef = useRef(null); useForwardFocus(ref, inputRef); var listId = useUniqueId('list'); var _h = useDropdownA11yProps(listId, open, highlightedOption), inputA11yProps = _h[0], highlightedA11yProps = _h[1]; var nativeAttributes = __assign({ name: name, placeholder: placeholder, autoFocus: autoFocus, 'aria-label': ariaLabel }, inputA11yProps); var handleFocus = useCallback(function (e) { setShowAll(true); openDropdown(); fireLoadMore(true, false, ''); onFocus && onFocus(e); }, [setShowAll, openDropdown, onFocus, fireLoadMore]); var dropdownStatus = (React.createElement(DropdownStatus, __assign({}, props, { onRecoveryClick: handleRecoveryClick, isEmpty: !value && !filteredItems.length }))); var ListComponent = virtualScroll ? VirtualList : PlainList; return (React.createElement(Dropdown, __assign({}, baseProps, { className: clsx(styles.root, baseProps.className), onMouseDown: handleMouseDown, onMouseMove: handleMouseMove, trigger: React.createElement(InternalInput, __assign({ type: "search", value: value, onChange: handleInputChange, onDelayedInput: handleDelayedInput, onFocus: handleFocus, onBlur: handleBlur, onKeyDown: handleKeyDown, onKeyUp: onKeyUp, disabled: disabled, disableBrowserAutocorrect: disableBrowserAutocorrect, readOnly: readOnly, ariaRequired: ariaRequired, ref: inputRef, nativeAttributes: nativeAttributes }, formFieldContext)), open: open, dropdownId: listId }), open && (React.createElement(ListComponent, { handleLoadMore: handleLoadMore, filteredItems: filteredItems, value: value, usingMouse: usingMouse, highlightedOption: highlightedOption, enteredTextLabel: enteredTextLabel, dropdownStatus: dropdownStatus, ref: scrollToIndex, highlightedA11yProps: highlightedA11yProps })), React.createElement(Announcer, { item: highlightedOption, usingMouse: usingMouse }))); }); export default Autosuggest;