"use strict"; 'use client'; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.useSelect = useSelect; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var React = _interopRequireWildcard(require("react")); var _utils = require("@mui/utils"); var _useButton = require("../useButton"); var _useSelect = require("./useSelect.types"); var _useList = require("../useList"); var _defaultOptionStringifier = require("./defaultOptionStringifier"); var _useCompound = require("../useCompound"); var _extractEventHandlers = require("../utils/extractEventHandlers"); var _selectReducer = require("./selectReducer"); var _combineHooksSlotProps = require("../utils/combineHooksSlotProps"); function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } function defaultFormValueProvider(selectedOption) { if (Array.isArray(selectedOption)) { if (selectedOption.length === 0) { return ''; } return JSON.stringify(selectedOption.map(o => o.value)); } if ((selectedOption == null ? void 0 : selectedOption.value) == null) { return ''; } if (typeof selectedOption.value === 'string' || typeof selectedOption.value === 'number') { return selectedOption.value; } return JSON.stringify(selectedOption.value); } /** * * Demos: * * - [Select](https://mui.com/base-ui/react-select/#hooks) * * API: * * - [useSelect API](https://mui.com/base-ui/react-select/hooks-api/#use-select) */ function useSelect(props) { const { areOptionsEqual, buttonRef: buttonRefProp, defaultOpen = false, defaultValue: defaultValueProp, disabled = false, listboxId: listboxIdProp, listboxRef: listboxRefProp, multiple = false, name, required, onChange, onHighlightChange, onOpenChange, open: openProp, options: optionsParam, getOptionAsString = _defaultOptionStringifier.defaultOptionStringifier, getSerializedValue = defaultFormValueProvider, value: valueProp, componentName = 'useSelect' } = props; const buttonRef = React.useRef(null); const handleButtonRef = (0, _utils.unstable_useForkRef)(buttonRefProp, buttonRef); const listboxRef = React.useRef(null); const listboxId = (0, _utils.unstable_useId)(listboxIdProp); let defaultValue; if (valueProp === undefined && defaultValueProp === undefined) { defaultValue = []; } else if (defaultValueProp !== undefined) { if (multiple) { defaultValue = defaultValueProp; } else { defaultValue = defaultValueProp == null ? [] : [defaultValueProp]; } } const value = React.useMemo(() => { if (valueProp !== undefined) { if (multiple) { return valueProp; } return valueProp == null ? [] : [valueProp]; } return undefined; }, [valueProp, multiple]); const { subitems, contextValue: compoundComponentContextValue } = (0, _useCompound.useCompoundParent)(); const options = React.useMemo(() => { if (optionsParam != null) { return new Map(optionsParam.map((option, index) => [option.value, { value: option.value, label: option.label, disabled: option.disabled, ref: /*#__PURE__*/React.createRef(), id: `${listboxId}_${index}` }])); } return subitems; }, [optionsParam, subitems, listboxId]); const handleListboxRef = (0, _utils.unstable_useForkRef)(listboxRefProp, listboxRef); const { getRootProps: getButtonRootProps, active: buttonActive, focusVisible: buttonFocusVisible, rootRef: mergedButtonRef } = (0, _useButton.useButton)({ disabled, rootRef: handleButtonRef }); const optionValues = React.useMemo(() => Array.from(options.keys()), [options]); const getOptionByValue = React.useCallback(valueToGet => { // This can't be simply `options.get(valueToGet)` because of the `areOptionsEqual` prop. // If it's provided, we assume that the user wants to compare the options by value. if (areOptionsEqual !== undefined) { const similarValue = optionValues.find(optionValue => areOptionsEqual(optionValue, valueToGet)); return options.get(similarValue); } return options.get(valueToGet); }, [options, areOptionsEqual, optionValues]); const isItemDisabled = React.useCallback(valueToCheck => { var _option$disabled; const option = getOptionByValue(valueToCheck); return (_option$disabled = option == null ? void 0 : option.disabled) != null ? _option$disabled : false; }, [getOptionByValue]); const stringifyOption = React.useCallback(valueToCheck => { const option = getOptionByValue(valueToCheck); if (!option) { return ''; } return getOptionAsString(option); }, [getOptionByValue, getOptionAsString]); const controlledState = React.useMemo(() => ({ selectedValues: value, open: openProp }), [value, openProp]); const getItemId = React.useCallback(itemValue => { var _options$get; return (_options$get = options.get(itemValue)) == null ? void 0 : _options$get.id; }, [options]); const handleSelectionChange = React.useCallback((event, newValues) => { if (multiple) { onChange == null || onChange(event, newValues); } else { var _newValues$; onChange == null || onChange(event, (_newValues$ = newValues[0]) != null ? _newValues$ : null); } }, [multiple, onChange]); const handleHighlightChange = React.useCallback((event, newValue) => { onHighlightChange == null || onHighlightChange(event, newValue != null ? newValue : null); }, [onHighlightChange]); const handleStateChange = React.useCallback((event, field, fieldValue) => { if (field === 'open') { onOpenChange == null || onOpenChange(fieldValue); if (fieldValue === false && (event == null ? void 0 : event.type) !== 'blur') { var _buttonRef$current; (_buttonRef$current = buttonRef.current) == null || _buttonRef$current.focus(); } } }, [onOpenChange]); const getItemDomElement = React.useCallback(itemId => { var _subitems$get$ref$cur, _subitems$get; if (itemId == null) { return null; } return (_subitems$get$ref$cur = (_subitems$get = subitems.get(itemId)) == null ? void 0 : _subitems$get.ref.current) != null ? _subitems$get$ref$cur : null; }, [subitems]); const useListParameters = { getInitialState: () => { var _defaultValue; return { highlightedValue: null, selectedValues: (_defaultValue = defaultValue) != null ? _defaultValue : [], open: defaultOpen }; }, getItemId, controlledProps: controlledState, focusManagement: 'DOM', getItemDomElement, itemComparer: areOptionsEqual, isItemDisabled, rootRef: handleListboxRef, onChange: handleSelectionChange, onHighlightChange: handleHighlightChange, onStateChange: handleStateChange, reducerActionContext: React.useMemo(() => ({ multiple }), [multiple]), items: optionValues, getItemAsString: stringifyOption, selectionMode: multiple ? 'multiple' : 'single', stateReducer: _selectReducer.selectReducer, componentName }; const { dispatch, getRootProps: getListboxRootProps, contextValue: listContextValue, state: { open, highlightedValue: highlightedOption, selectedValues: selectedOptions }, rootRef: mergedListRootRef } = (0, _useList.useList)(useListParameters); // store the initial open state to prevent focus stealing // (the first option gets focused only when the select is opened by the user) const isInitiallyOpen = React.useRef(open); (0, _utils.unstable_useEnhancedEffect)(() => { if (open && highlightedOption !== null) { var _getOptionByValue; const optionRef = (_getOptionByValue = getOptionByValue(highlightedOption)) == null ? void 0 : _getOptionByValue.ref; if (!listboxRef.current || !(optionRef != null && optionRef.current)) { return; } if (!isInitiallyOpen.current) { optionRef.current.focus({ preventScroll: true }); } const listboxClientRect = listboxRef.current.getBoundingClientRect(); const optionClientRect = optionRef.current.getBoundingClientRect(); if (optionClientRect.top < listboxClientRect.top) { listboxRef.current.scrollTop -= listboxClientRect.top - optionClientRect.top; } else if (optionClientRect.bottom > listboxClientRect.bottom) { listboxRef.current.scrollTop += optionClientRect.bottom - listboxClientRect.bottom; } } }, [open, highlightedOption, getOptionByValue]); const getOptionMetadata = React.useCallback(optionValue => getOptionByValue(optionValue), [getOptionByValue]); const createHandleButtonClick = externalEventHandlers => event => { var _externalEventHandler; externalEventHandlers == null || (_externalEventHandler = externalEventHandlers.onClick) == null || _externalEventHandler.call(externalEventHandlers, event); if (!event.defaultMuiPrevented) { const action = { type: _useSelect.SelectActionTypes.buttonClick, event }; dispatch(action); } }; const createHandleButtonKeyDown = otherHandlers => event => { var _otherHandlers$onKeyD; (_otherHandlers$onKeyD = otherHandlers.onKeyDown) == null || _otherHandlers$onKeyD.call(otherHandlers, event); if (event.defaultMuiPrevented) { return; } if (event.key === 'ArrowDown' || event.key === 'ArrowUp') { event.preventDefault(); dispatch({ type: _useList.ListActionTypes.keyDown, key: event.key, event }); } }; const getButtonOwnRootProps = (otherHandlers = {}) => ({ onClick: createHandleButtonClick(otherHandlers), onKeyDown: createHandleButtonKeyDown(otherHandlers) }); const getSelectTriggerProps = (otherHandlers = {}) => { return (0, _extends2.default)({}, otherHandlers, getButtonOwnRootProps(otherHandlers), { role: 'combobox', 'aria-expanded': open, 'aria-controls': listboxId }); }; const getButtonProps = (externalProps = {}) => { const externalEventHandlers = (0, _extractEventHandlers.extractEventHandlers)(externalProps); const combinedProps = (0, _combineHooksSlotProps.combineHooksSlotProps)(getSelectTriggerProps, getButtonRootProps); return (0, _extends2.default)({}, externalProps, combinedProps(externalEventHandlers)); }; const createListboxHandleBlur = otherHandlers => event => { var _otherHandlers$onBlur, _listboxRef$current; (_otherHandlers$onBlur = otherHandlers.onBlur) == null || _otherHandlers$onBlur.call(otherHandlers, event); if (event.defaultMuiPrevented) { return; } if ((_listboxRef$current = listboxRef.current) != null && _listboxRef$current.contains(event.relatedTarget) || event.relatedTarget === buttonRef.current) { event.defaultMuiPrevented = true; } }; const getOwnListboxHandlers = (otherHandlers = {}) => ({ onBlur: createListboxHandleBlur(otherHandlers) }); const getListboxProps = (externalProps = {}) => { const externalEventHandlers = (0, _extractEventHandlers.extractEventHandlers)(externalProps); const getCombinedRootProps = (0, _combineHooksSlotProps.combineHooksSlotProps)(getOwnListboxHandlers, getListboxRootProps); return (0, _extends2.default)({ id: listboxId, role: 'listbox', 'aria-multiselectable': multiple ? 'true' : undefined }, externalProps, getCombinedRootProps(externalEventHandlers)); }; React.useDebugValue({ selectedOptions, highlightedOption, open }); const contextValue = React.useMemo(() => (0, _extends2.default)({}, listContextValue, compoundComponentContextValue), [listContextValue, compoundComponentContextValue]); let selectValue; if (props.multiple) { selectValue = selectedOptions; } else { selectValue = selectedOptions.length > 0 ? selectedOptions[0] : null; } let selectedOptionsMetadata; if (multiple) { selectedOptionsMetadata = selectValue.map(v => getOptionMetadata(v)).filter(o => o !== undefined); } else { var _getOptionMetadata; selectedOptionsMetadata = (_getOptionMetadata = getOptionMetadata(selectValue)) != null ? _getOptionMetadata : null; } const createHandleHiddenInputChange = externalEventHandlers => event => { var _externalEventHandler2; externalEventHandlers == null || (_externalEventHandler2 = externalEventHandlers.onChange) == null || _externalEventHandler2.call(externalEventHandlers, event); if (event.defaultMuiPrevented) { return; } const option = options.get(event.target.value); // support autofill if (event.target.value === '') { dispatch({ type: _useList.ListActionTypes.clearSelection }); } else if (option !== undefined) { dispatch({ type: _useSelect.SelectActionTypes.browserAutoFill, item: option.value, event }); } }; const getHiddenInputProps = (externalProps = {}) => { const externalEventHandlers = (0, _extractEventHandlers.extractEventHandlers)(externalProps); return (0, _extends2.default)({ name, tabIndex: -1, 'aria-hidden': true, required: required ? true : undefined, value: getSerializedValue(selectedOptionsMetadata), style: _utils.visuallyHidden }, externalProps, { onChange: createHandleHiddenInputChange(externalEventHandlers) }); }; return { buttonActive, buttonFocusVisible, buttonRef: mergedButtonRef, contextValue, disabled, dispatch, getButtonProps, getHiddenInputProps, getListboxProps, getOptionMetadata, listboxRef: mergedListRootRef, open, options: optionValues, value: selectValue, highlightedOption }; }