UNPKG

jobiqo-cl

Version:

[![CircleCI](https://circleci.com/gh/jobiqo/jobiqo-cl.svg?style=svg&circle-token=5a24efa5b8bbc4879276123e77d0d3f35ca7144c)](https://circleci.com/gh/jobiqo/jobiqo-cl)

766 lines (651 loc) 28.4 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } var React = require('react'); var React__default = _interopDefault(React); var index = require('../../../prop-types/index.js'); var index$2 = require('../../utils/es/index.js'); var index$1 = require('../../../highlight-words-core/dist/index.js'); var index$3 = require('../../../escape-regexp/index.js'); var index$4 = require('../../auto-id/es/index.js'); var index$5 = require('../../popover/es/index.js'); var _on, _on2, _on3, _on4, _states; function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } 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); } // States // Nothing going on, waiting for the user to type or use the arrow keys var IDLE = "IDLE"; // The component is suggesting options as the user types var SUGGESTING = "SUGGESTING"; // The user is using the keyboard to navigate the list, not typing var NAVIGATING = "NAVIGATING"; // The user is interacting with arbitrary elements inside the popup that // are not ComboboxInputs var INTERACTING = "INTERACTING"; //////////////////////////////////////////////////////////////////////////////// // Actions // User cleared the value w/ backspace, but input still has focus var CLEAR = "CLEAR"; // User is typing var CHANGE = "CHANGE"; // User is navigating w/ the keyboard var NAVIGATE = "NAVIGATE"; // User can be navigating with keyboard and then click instead, we want the // value from the click, not the current nav item var SELECT_WITH_KEYBOARD = "SELECT_WITH_KEYBOARD"; var SELECT_WITH_CLICK = "SELECT_WITH_CLICK"; // Pretty self-explanatory, user can hit escape or blur to close the popover var ESCAPE = "ESCAPE"; var BLUR = "BLUR"; // The user left the input to interact with arbitrary elements inside the popup var INTERACT = "INTERACT"; var FOCUS = "FOCUS"; var OPEN_WITH_BUTTON = "OPEN_WITH_BUTTON"; var CLOSE_WITH_BUTTON = "CLOSE_WITH_BUTTON"; //////////////////////////////////////////////////////////////////////////////// var stateChart = { initial: IDLE, states: (_states = {}, _states[IDLE] = { on: (_on = {}, _on[BLUR] = IDLE, _on[CLEAR] = IDLE, _on[CHANGE] = SUGGESTING, _on[FOCUS] = SUGGESTING, _on[NAVIGATE] = NAVIGATING, _on[OPEN_WITH_BUTTON] = SUGGESTING, _on) }, _states[SUGGESTING] = { on: (_on2 = {}, _on2[CHANGE] = SUGGESTING, _on2[FOCUS] = SUGGESTING, _on2[NAVIGATE] = NAVIGATING, _on2[CLEAR] = IDLE, _on2[ESCAPE] = IDLE, _on2[BLUR] = IDLE, _on2[SELECT_WITH_CLICK] = IDLE, _on2[INTERACT] = INTERACTING, _on2[CLOSE_WITH_BUTTON] = IDLE, _on2) }, _states[NAVIGATING] = { on: (_on3 = {}, _on3[CHANGE] = SUGGESTING, _on3[FOCUS] = SUGGESTING, _on3[CLEAR] = IDLE, _on3[BLUR] = IDLE, _on3[ESCAPE] = IDLE, _on3[NAVIGATE] = NAVIGATING, _on3[SELECT_WITH_KEYBOARD] = IDLE, _on3[CLOSE_WITH_BUTTON] = IDLE, _on3[INTERACT] = INTERACTING, _on3) }, _states[INTERACTING] = { on: (_on4 = {}, _on4[CHANGE] = SUGGESTING, _on4[FOCUS] = SUGGESTING, _on4[BLUR] = IDLE, _on4[ESCAPE] = IDLE, _on4[NAVIGATE] = NAVIGATING, _on4[CLOSE_WITH_BUTTON] = IDLE, _on4[SELECT_WITH_CLICK] = IDLE, _on4) }, _states) }; function reducer(data, action) { var nextState = _extends({}, data, { lastActionType: action.type }); switch (action.type) { case CHANGE: return _extends({}, nextState, { navigationValue: null, value: action.value }); case NAVIGATE: case OPEN_WITH_BUTTON: return _extends({}, nextState, { navigationValue: findNavigationValue(nextState, action) }); case CLEAR: return _extends({}, nextState, { value: "", navigationValue: null }); case BLUR: case ESCAPE: return _extends({}, nextState, { navigationValue: null }); case SELECT_WITH_CLICK: return _extends({}, nextState, { value: action.value, navigationValue: null }); case SELECT_WITH_KEYBOARD: return _extends({}, nextState, { value: data.navigationValue, navigationValue: null }); case CLOSE_WITH_BUTTON: return _extends({}, nextState, { navigationValue: null }); case INTERACT: return nextState; case FOCUS: return _extends({}, nextState, { navigationValue: findNavigationValue(nextState, action) }); default: throw new Error("Unknown action " + action.type); } } var visibleStates = [SUGGESTING, NAVIGATING, INTERACTING]; var isVisible = function isVisible(state) { return visibleStates.includes(state); }; // When we open a list, set the navigation value to the value in the input, if // it's in the list, then it'll automatically be highlighted. var findNavigationValue = function findNavigationValue(state, action) { if (action.value) { return action.value; } else if (action.persistSelection) { return state.value; } else { return null; } }; var ComboboxContext = React.createContext(); // Allows us to put the option's value on context so that ComboboxOptionText // can work it's highlight text magic no matter what else is rendered around // it. var OptionContext = React.createContext(); //////////////////////////////////////////////////////////////////////////////// // Combobox var Combobox = React.forwardRef(function Combobox(_ref, forwardedRef) { var onSelect = _ref.onSelect, _ref$openOnFocus = _ref.openOnFocus, openOnFocus = _ref$openOnFocus === void 0 ? false : _ref$openOnFocus, children = _ref.children, _ref$as = _ref.as, Comp = _ref$as === void 0 ? "div" : _ref$as, rest = _objectWithoutPropertiesLoose(_ref, ["onSelect", "openOnFocus", "children", "as"]); // We store the values of all the ComboboxOptions on this ref. This makes it // possible to perform the keyboard navigation from the input on the list. We // manipulate this array through context so that we don't have to enforce a // parent/child relationship between ComboboxList and ComboboxOption with // cloneElement or fall back to DOM traversal. It's a new trick for me and // I'm pretty excited about it. var optionsRef = React.useRef(null); // Need this to focus it var inputRef = React.useRef(); var popoverRef = React.useRef(); var buttonRef = React.useRef(); // When <ComboboxInput autocomplete={false} /> we don't want cycle back to // the user's value while navigating (because it's always the user's value), // but we need to know this in useKeyDown which is far away from the prop // here, so we do something sneaky and write it to this ref on context so we // can use it anywhere else 😛. Another new trick for me and I'm excited // about this one too! var autocompletePropRef = React.useRef(); var persistSelectionRef = React.useRef(); var defaultData = { // the value the user has typed, we derived this also when the developer is // controlling the value of ComboboxInput value: "", // the value the user has navigated to with the keyboard navigationValue: null }; var _useReducerMachine = useReducerMachine(stateChart, reducer, defaultData), state = _useReducerMachine[0], data = _useReducerMachine[1], transition = _useReducerMachine[2]; useFocusManagement(data.lastActionType, inputRef); var id = index$4.useId(rest.id); var listboxId = index$2.makeId("listbox", id); var context = { data: data, inputRef: inputRef, popoverRef: popoverRef, buttonRef: buttonRef, onSelect: onSelect, optionsRef: optionsRef, state: state, transition: transition, listboxId: listboxId, autocompletePropRef: autocompletePropRef, persistSelectionRef: persistSelectionRef, isVisible: isVisible(state), openOnFocus: openOnFocus }; React.useEffect(function () { return index$2.checkStyles("combobox"); }); return React__default.createElement(ComboboxContext.Provider, { value: context }, React__default.createElement(Comp, _extends({}, rest, { "data-reach-combobox": "", ref: forwardedRef, role: "combobox", "aria-haspopup": "listbox", "aria-owns": listboxId, "aria-expanded": context.isVisible }), children)); }); Combobox.displayName = "Combobox"; if (process.env.NODE_ENV !== "production") { Combobox.propTypes = { onSelect: index.default.func }; } //////////////////////////////////////////////////////////////////////////////// // ComboboxInput var ComboboxInput = React.forwardRef(function ComboboxInput(_ref2, forwardedRef) { var _ref2$as = _ref2.as, Comp = _ref2$as === void 0 ? "input" : _ref2$as, _ref2$selectOnClick = _ref2.selectOnClick, selectOnClick = _ref2$selectOnClick === void 0 ? false : _ref2$selectOnClick, _ref2$autocomplete = _ref2.autocomplete, autocomplete = _ref2$autocomplete === void 0 ? true : _ref2$autocomplete, onClick = _ref2.onClick, onChange = _ref2.onChange, onKeyDown = _ref2.onKeyDown, onBlur = _ref2.onBlur, onFocus = _ref2.onFocus, controlledValue = _ref2.value, props = _objectWithoutPropertiesLoose(_ref2, ["as", "selectOnClick", "autocomplete", "onClick", "onChange", "onKeyDown", "onBlur", "onFocus", "value"]); var _useContext = React.useContext(ComboboxContext), _useContext$data = _useContext.data, navigationValue = _useContext$data.navigationValue, value = _useContext$data.value, lastActionType = _useContext$data.lastActionType, inputRef = _useContext.inputRef, state = _useContext.state, transition = _useContext.transition, listboxId = _useContext.listboxId, autocompletePropRef = _useContext.autocompletePropRef, openOnFocus = _useContext.openOnFocus; var ref = index$2.useForkedRef(inputRef, forwardedRef); // Because we close the List on blur, we need to track if the blur is // caused by clicking inside the list, and if so, don't close the List. var selectOnClickRef = React.useRef(false); var handleKeyDown = useKeyDown(); var handleBlur = useBlur(); var isControlled = controlledValue != null; React.useLayoutEffect(function () { autocompletePropRef.current = autocomplete; // eslint-disable-next-line react-hooks/exhaustive-deps }, [autocomplete]); var handleValueChange = function handleValueChange(value) { if (value.trim() === "") { transition(CLEAR); } else { transition(CHANGE, { value: value }); } }; // If they are controlling the value we still need to do our transitions, so // we have this derived state to emulate onChange of the input as we receive // new `value`s ...[*] if (isControlled && controlledValue !== value) { handleValueChange(controlledValue); } // [*]... and when controlled, we don't trigger handleValueChange as the user // types, instead the developer controls it with the normal input onChange // prop var handleChange = function handleChange(event) { if (!isControlled) { handleValueChange(event.target.value); } }; var handleFocus = function handleFocus() { if (selectOnClick) { selectOnClickRef.current = true; } // If we select an option with click, useFocusManagement will focus the // input, in those cases we don't want to cause the menu to open back up, // so we guard behind these states if (openOnFocus && lastActionType !== SELECT_WITH_CLICK) { transition(FOCUS); } }; var handleClick = function handleClick() { if (selectOnClickRef.current) { selectOnClickRef.current = false; inputRef.current.select(); } }; var inputValue = autocomplete && (state === NAVIGATING || state === INTERACTING) ? // When idle, we don't have a navigationValue on ArrowUp/Down navigationValue || controlledValue || value : controlledValue || value; return React__default.createElement(Comp, _extends({}, props, { "data-reach-combobox-input": "", ref: ref, value: inputValue, onClick: index$2.wrapEvent(onClick, handleClick), onBlur: index$2.wrapEvent(onBlur, handleBlur), onFocus: index$2.wrapEvent(onFocus, handleFocus), onChange: index$2.wrapEvent(onChange, handleChange), onKeyDown: index$2.wrapEvent(onKeyDown, handleKeyDown), id: listboxId, "aria-autocomplete": "both", "aria-activedescendant": navigationValue ? makeHash(navigationValue) : undefined })); }); ComboboxInput.displayName = "ComboboxInput"; //////////////////////////////////////////////////////////////////////////////// // ComboboxPopover var ComboboxPopover = React.forwardRef(function ComboboxPopover(_ref3, forwardedRef) { var _ref3$portal = _ref3.portal, portal = _ref3$portal === void 0 ? true : _ref3$portal, onKeyDown = _ref3.onKeyDown, onBlur = _ref3.onBlur, props = _objectWithoutPropertiesLoose(_ref3, ["portal", "onKeyDown", "onBlur"]); var _useContext2 = React.useContext(ComboboxContext), popoverRef = _useContext2.popoverRef, inputRef = _useContext2.inputRef, isVisible = _useContext2.isVisible; var ref = index$2.useForkedRef(popoverRef, forwardedRef); var handleKeyDown = useKeyDown(); var handleBlur = useBlur(); // Instead of conditionally rendering the popover we use the `hidden` prop // because we don't want to unmount on close (from escape or onSelect). If // we unmounted, then we'd lose the optionsRef and the user wouldn't be able // to use the arrow keys to pop the list back open. However, the developer // can conditionally render the ComboboxPopover if they do want to cause // mount/unmount based on the app's own data (like results.length or // whatever). var hidden = !isVisible; var Container = portal ? index$5.default : "div"; var popupProps = portal ? { targetRef: inputRef, position: index$5.positionMatchWidth } : null; return React__default.createElement(Container, _extends({}, props, { "data-reach-combobox-popover": "" }, popupProps, { ref: ref, onKeyDown: index$2.wrapEvent(onKeyDown, handleKeyDown), onBlur: index$2.wrapEvent(onBlur, handleBlur), hidden: hidden // Allow the user to click empty space inside the popover without causing // to close from useBlur , tabIndex: "-1" })); }); ComboboxPopover.displayName = "ComboboxPopover"; //////////////////////////////////////////////////////////////////////////////// // ComboboxList var ComboboxList = React.forwardRef(function ComboboxList(_ref4, forwardedRef) { var _ref4$persistSelectio = _ref4.persistSelection, persistSelection = _ref4$persistSelectio === void 0 ? false : _ref4$persistSelectio, _ref4$as = _ref4.as, Comp = _ref4$as === void 0 ? "ul" : _ref4$as, props = _objectWithoutPropertiesLoose(_ref4, ["persistSelection", "as"]); var _useContext3 = React.useContext(ComboboxContext), optionsRef = _useContext3.optionsRef, persistSelectionRef = _useContext3.persistSelectionRef; if (persistSelection) { persistSelectionRef.current = true; } // WEIRD? Reset the options ref every render so that they are always // accurate and ready for keyboard navigation handlers. Using layout // effect to schedule this effect before the ComboboxOptions push into // the array React.useLayoutEffect(function () { optionsRef.current = []; return function () { return optionsRef.current = []; }; }); return React__default.createElement(Comp, _extends({}, props, { ref: forwardedRef, "data-reach-combobox-list": "", role: "listbox" })); }); ComboboxList.displayName = "ComboboxList"; //////////////////////////////////////////////////////////////////////////////// // ComboboxOption var ComboboxOption = React.forwardRef(function ComboboxOption(_ref5, forwardedRef) { var children = _ref5.children, value = _ref5.value, onClick = _ref5.onClick, props = _objectWithoutPropertiesLoose(_ref5, ["children", "value", "onClick"]); var _useContext4 = React.useContext(ComboboxContext), onSelect = _useContext4.onSelect, navigationValue = _useContext4.data.navigationValue, transition = _useContext4.transition, optionsRef = _useContext4.optionsRef; React.useEffect(function () { optionsRef.current.push(value); }); var isActive = navigationValue === value; var handleClick = function handleClick() { onSelect && onSelect(value); transition(SELECT_WITH_CLICK, { value: value }); }; return React__default.createElement(OptionContext.Provider, { value: value }, React__default.createElement("li", _extends({}, props, { "data-reach-combobox-option": "", ref: forwardedRef, id: makeHash(value), role: "option", "aria-selected": isActive, "data-highlighted": isActive ? "" : undefined // without this the menu will close from `onBlur`, but with it the // element can be `document.activeElement` and then our focus checks in // onBlur will work as intended , tabIndex: "-1", onClick: index$2.wrapEvent(onClick, handleClick), children: children || React__default.createElement(ComboboxOptionText, null) }))); }); ComboboxOption.displayName = "ComboboxOption"; //////////////////////////////////////////////////////////////////////////////// // ComboboxOptionText // We don't forwardRef or spread props because we render multiple spans or null, // should be fine 🤙 function ComboboxOptionText() { var value = React.useContext(OptionContext); var _useContext5 = React.useContext(ComboboxContext), contextValue = _useContext5.data.value; var results = React.useMemo(function () { return index$1.findAll({ searchWords: index$3.default(contextValue).split(/\s+/), textToHighlight: value }); }, [contextValue, value]); return results.length ? results.map(function (result, index) { var str = value.slice(result.start, result.end); return React__default.createElement("span", { key: index, "data-user-value": result.highlight ? true : undefined, "data-suggested-value": result.highlight ? undefined : true }, str); }) : value; } ComboboxOptionText.displayName = "ComboboxOptionText"; //////////////////////////////////////////////////////////////////////////////// // ComboboxButton var ComboboxButton = React.forwardRef(function ComboboxButton(_ref6, forwardedRef) { var _ref6$as = _ref6.as, Comp = _ref6$as === void 0 ? "button" : _ref6$as, onClick = _ref6.onClick, onKeyDown = _ref6.onKeyDown, props = _objectWithoutPropertiesLoose(_ref6, ["as", "onClick", "onKeyDown"]); var _useContext6 = React.useContext(ComboboxContext), transition = _useContext6.transition, state = _useContext6.state, buttonRef = _useContext6.buttonRef, listboxId = _useContext6.listboxId, isVisible = _useContext6.isVisible; var ref = index$2.useForkedRef(buttonRef, forwardedRef); var handleKeyDown = useKeyDown(); var handleClick = function handleClick() { if (state === IDLE) { transition(OPEN_WITH_BUTTON); } else { transition(CLOSE_WITH_BUTTON); } }; return React__default.createElement(Comp, _extends({ "data-reach-combobox-button": "", "aria-controls": listboxId, "aria-haspopup": "listbox", "aria-expanded": isVisible, ref: ref, onClick: index$2.wrapEvent(onClick, handleClick), onKeyDown: index$2.wrapEvent(onKeyDown, handleKeyDown) }, props)); }); ComboboxButton.displayName = "ComboboxButton"; //////////////////////////////////////////////////////////////////////////////// // The rest is all implementation details // Move focus back to the input if we start navigating w/ the // keyboard after focus has moved to any focusable content in // the popup. function useFocusManagement(lastActionType, inputRef) { // useLayoutEffect so that the cursor goes to the end of the input instead // of awkwardly at the beginning, unclear to my why ... React.useLayoutEffect(function () { if (lastActionType === NAVIGATE || lastActionType === ESCAPE || lastActionType === SELECT_WITH_CLICK || lastActionType === OPEN_WITH_BUTTON) { inputRef.current.focus(); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [lastActionType]); } // We want the same events when the input or the popup have focus (HOW COOL ARE // HOOKS BTW?) This is probably the hairiest piece but it's not bad. function useKeyDown() { var _useContext7 = React.useContext(ComboboxContext), navigationValue = _useContext7.data.navigationValue, onSelect = _useContext7.onSelect, optionsRef = _useContext7.optionsRef, state = _useContext7.state, transition = _useContext7.transition, autocompletePropRef = _useContext7.autocompletePropRef, persistSelectionRef = _useContext7.persistSelectionRef; return function handleKeyDown(event) { var options = optionsRef.current; switch (event.key) { case "ArrowDown": { // Don't scroll the page event.preventDefault(); // If the developer didn't render any options, there's no point in // trying to navigate--but seriously what the heck? Give us some // options fam. if (!options || options.length === 0) { return; } if (state === IDLE) { // Opening a closed list transition(NAVIGATE, { persistSelection: persistSelectionRef.current }); } else { var index = options.indexOf(navigationValue); var atBottom = index === options.length - 1; if (atBottom) { if (autocompletePropRef.current) { // Go back to the value the user has typed because we are // autocompleting and they need to be able to get back to what // they had typed w/o having to backspace out. transition(NAVIGATE, { value: null }); } else { // cycle through var firstOption = options[0]; transition(NAVIGATE, { value: firstOption }); } } else { // Go to the next item in the list var nextValue = options[(index + 1) % options.length]; transition(NAVIGATE, { value: nextValue }); } } break; } // A lot of duplicate code with ArrowDown up next, I'm already over it. case "ArrowUp": { // Don't scroll the page event.preventDefault(); // If the developer didn't render any options, there's no point in // trying to navigate--but seriously what the heck? Give us some // options fam. if (!options || options.length === 0) { return; } if (state === IDLE) { transition(NAVIGATE); } else { var _index = options.indexOf(navigationValue); if (_index === 0) { if (autocompletePropRef.current) { // Go back to the value the user has typed because we are // autocompleting and they need to be able to get back to what // they had typed w/o having to backspace out. transition(NAVIGATE, { value: null }); } else { // cycle through var lastOption = options[options.length - 1]; transition(NAVIGATE, { value: lastOption }); } } else if (_index === -1) { // displaying the user's value, so go select the last one var value = options.length ? options[options.length - 1] : null; transition(NAVIGATE, { value: value }); } else { // normal case, select previous var _nextValue = options[(_index - 1 + options.length) % options.length]; transition(NAVIGATE, { value: _nextValue }); } } break; } case "Escape": { if (state !== IDLE) { transition(ESCAPE); } break; } case "Enter": { if (state === NAVIGATING && navigationValue !== null) { // don't want to submit forms event.preventDefault(); onSelect && onSelect(navigationValue); transition(SELECT_WITH_KEYBOARD); } break; } } }; } function useBlur() { var _useContext8 = React.useContext(ComboboxContext), state = _useContext8.state, transition = _useContext8.transition, popoverRef = _useContext8.popoverRef, inputRef = _useContext8.inputRef, buttonRef = _useContext8.buttonRef; return function handleBlur(event) { requestAnimationFrame(function () { // we on want to close only if focus rests outside the combobox if (document.activeElement !== inputRef.current && document.activeElement !== buttonRef.current && popoverRef.current) { if (popoverRef.current.contains(document.activeElement)) { // focus landed inside the combobox, keep it open if (state !== INTERACTING) { transition(INTERACT); } } else { // focus landed outside the combobox, close it. transition(BLUR); } } }); }; } // This manages transitions between states with a built in reducer to manage // the data that goes with those transitions. function useReducerMachine(chart, reducer, initialData) { var _useState = React.useState(chart.initial), state = _useState[0], setState = _useState[1]; var _useReducer = React.useReducer(reducer, initialData), data = _useReducer[0], dispatch = _useReducer[1]; var transition = function transition(action, payload) { if (payload === void 0) { payload = {}; } var currentState = chart.states[state]; var nextState = currentState.on[action]; if (!nextState) { throw new Error("Unknown action \"" + action + "\" for state \"" + state + "\""); } dispatch(_extends({ type: action, state: state, nextState: state }, payload)); setState(nextState); }; return [state, data, transition]; } // We don't want to track the active descendant with indexes because nothing is // more annoying in a combobox than having it change values RIGHT AS YOU HIT // ENTER. That only happens if you use the index as your data, rather than // *your data as your data*. We use this to generate a unique ID based on the // value of each item. This function is short, sweet, and good enough™ (I also // don't know how it works, tbqh) // https://stackoverflow.com/questions/6122571/simple-non-secure-hash-function-for-javascript var makeHash = function makeHash(str) { var hash = 0; if (str.length === 0) { return hash; } for (var i = 0; i < str.length; i++) { var _char = str.charCodeAt(i); hash = (hash << 5) - hash + _char; hash = hash & hash; } return hash; }; //////////////////////////////////////////////////////////////////////////////// // Well alright, you made it all the way here to like 700 lines of code (geez, // what the heck?). Have a great day :D exports.Combobox = Combobox; exports.ComboboxButton = ComboboxButton; exports.ComboboxInput = ComboboxInput; exports.ComboboxList = ComboboxList; exports.ComboboxOption = ComboboxOption; exports.ComboboxOptionText = ComboboxOptionText; exports.ComboboxPopover = ComboboxPopover;