@shopify/polaris
Version:
Shopify’s admin product component library
117 lines (110 loc) • 4.09 kB
JavaScript
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 };