UNPKG

@shopify/polaris

Version:

Shopify’s admin product component library

117 lines (110 loc) 4.09 kB
import React, { useState, Children, useRef, useCallback, useMemo } from 'react'; import styles from './Combobox.scss.js'; import { ComboboxTextFieldContext, ComboboxListboxContext, ComboboxListboxOptionContext } from '../../utilities/combobox/context.js'; import { TextField } from './components/TextField/TextField.js'; import { Popover } from '../Popover/Popover.js'; function Combobox({ activator, allowMultiple, children, preferredPosition = 'below', willLoadMoreOptions, height, onScrolledToBottom, onClose }) { const [popoverActive, setPopoverActive] = useState(false); const [activeOptionId, setActiveOptionId] = useState(); const [textFieldLabelId, setTextFieldLabelId] = useState(); const [listboxId, setListboxId] = useState(); const [textFieldFocused, setTextFieldFocused] = useState(false); const [disableCloseOnSelect, setDisableCloseOnSelect] = useState(false); const shouldOpen = Boolean(!popoverActive && Children.count(children) > 0); const ref = useRef(null); const handleClose = useCallback(() => { // only deactive popover if not creating a new option if (!disableCloseOnSelect) { setPopoverActive(false); onClose === null || onClose === void 0 ? void 0 : onClose(); } setActiveOptionId(undefined); }, [disableCloseOnSelect, onClose]); const handleOpen = useCallback(() => { setPopoverActive(true); setActiveOptionId(undefined); }, []); const onOptionSelected = useCallback(() => { var _ref$current; if (!allowMultiple) { handleClose(); setActiveOptionId(undefined); return; } else { setDisableCloseOnSelect(true); } (_ref$current = ref.current) === null || _ref$current === void 0 ? void 0 : _ref$current.forceUpdatePosition(); }, [allowMultiple, handleClose, setDisableCloseOnSelect]); const handleFocus = useCallback(() => { if (shouldOpen) { handleOpen(); } }, [shouldOpen, handleOpen]); const handleChange = useCallback(() => { if (shouldOpen) { handleOpen(); } }, [shouldOpen, handleOpen]); const handleBlur = useCallback(() => { setDisableCloseOnSelect(false); if (popoverActive) { handleClose(); } }, [popoverActive, handleClose, setDisableCloseOnSelect]); const textFieldContextValue = useMemo(() => ({ activeOptionId, expanded: popoverActive, listboxId, setTextFieldFocused, setTextFieldLabelId, onTextFieldFocus: handleFocus, onTextFieldChange: handleChange, onTextFieldBlur: handleBlur }), [activeOptionId, popoverActive, listboxId, setTextFieldFocused, setTextFieldLabelId, handleFocus, handleChange, handleBlur]); const listboxOptionContextValue = useMemo(() => ({ allowMultiple }), [allowMultiple]); const listboxContextValue = useMemo(() => ({ listboxId, textFieldLabelId, textFieldFocused, willLoadMoreOptions, onOptionSelected, setActiveOptionId, setListboxId, onKeyToBottom: onScrolledToBottom }), [listboxId, textFieldLabelId, textFieldFocused, willLoadMoreOptions, onOptionSelected, setActiveOptionId, setListboxId, onScrolledToBottom]); return /*#__PURE__*/React.createElement(Popover, { ref: ref, active: popoverActive, activator: /*#__PURE__*/React.createElement(ComboboxTextFieldContext.Provider, { value: textFieldContextValue }, activator), autofocusTarget: "none", preventFocusOnClose: true, fullWidth: true, preferInputActivator: false, preferredPosition: preferredPosition, onClose: handleClose }, Children.count(children) > 0 ? /*#__PURE__*/React.createElement(Popover.Pane, { onScrolledToBottom: onScrolledToBottom, height: height }, /*#__PURE__*/React.createElement(ComboboxListboxContext.Provider, { value: listboxContextValue }, /*#__PURE__*/React.createElement(ComboboxListboxOptionContext.Provider, { value: listboxOptionContextValue }, /*#__PURE__*/React.createElement("div", { className: styles.Listbox }, children)))) : null); } Combobox.TextField = TextField; export { Combobox };