UNPKG

@mui/base

Version:

A library of headless ('unstyled') React UI components and low-level hooks.

259 lines (256 loc) 10.3 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var React = _interopRequireWildcard(require("react")); var _utils = require("@mui/utils"); var _useButton = _interopRequireDefault(require("../useButton")); var _useSelect = require("./useSelect.types"); var _useList = _interopRequireDefault(require("../useList")); var _defaultOptionStringifier = _interopRequireDefault(require("./defaultOptionStringifier")); var _useCompound = require("../utils/useCompound"); var _selectReducer = _interopRequireDefault(require("./selectReducer")); var _combineHooksSlotProps = _interopRequireDefault(require("../utils/combineHooksSlotProps")); function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } function preventDefault(event) { event.preventDefault(); } /** * * Demos: * * - [Select](https://mui.com/base/react-select/#hooks) * * API: * * - [useSelect API](https://mui.com/base/react-select/hooks-api/#use-select) */ function useSelect(props) { const { buttonRef: buttonRefProp, defaultOpen = false, defaultValue: defaultValueProp, disabled = false, listboxId: listboxIdProp, listboxRef: listboxRefProp, multiple = false, onChange, onHighlightChange, onOpenChange, open: openProp, options: optionsParam, getOptionAsString = _defaultOptionStringifier.default, value: valueProp } = 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.default)({ disabled, rootRef: handleButtonRef }); const optionValues = React.useMemo(() => Array.from(options.keys()), [options]); const isItemDisabled = React.useCallback(valueToCheck => { var _option$disabled; const option = options.get(valueToCheck); return (_option$disabled = option == null ? void 0 : option.disabled) != null ? _option$disabled : false; }, [options]); const stringifyOption = React.useCallback(valueToCheck => { const option = options.get(valueToCheck); if (!option) { return ''; } return getOptionAsString(option); }, [options, 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 ? void 0 : onChange(event, newValues); } else { var _newValues$; onChange == null ? void 0 : onChange(event, (_newValues$ = newValues[0]) != null ? _newValues$ : null); } }, [multiple, onChange]); const handleHighlightChange = React.useCallback((event, newValue) => { onHighlightChange == null ? void 0 : onHighlightChange(event, newValue != null ? newValue : null); }, [onHighlightChange]); const handleStateChange = React.useCallback((event, field, fieldValue) => { if (field === 'open') { onOpenChange == null ? void 0 : onOpenChange(fieldValue); if (fieldValue === false && (event == null ? void 0 : event.type) !== 'blur') { var _buttonRef$current; (_buttonRef$current = buttonRef.current) == null ? void 0 : _buttonRef$current.focus(); } } }, [onOpenChange]); const useListParameters = { getInitialState: () => { var _defaultValue; return { highlightedValue: null, selectedValues: (_defaultValue = defaultValue) != null ? _defaultValue : [], open: defaultOpen }; }, getItemId, controlledProps: controlledState, isItemDisabled, rootRef: mergedButtonRef, onChange: handleSelectionChange, onHighlightChange: handleHighlightChange, onStateChange: handleStateChange, reducerActionContext: React.useMemo(() => ({ multiple }), [multiple]), items: optionValues, getItemAsString: stringifyOption, selectionMode: multiple ? 'multiple' : 'single', stateReducer: _selectReducer.default }; const { dispatch, getRootProps: getListboxRootProps, contextValue: listContextValue, state: { open, highlightedValue: highlightedOption, selectedValues: selectedOptions }, rootRef: mergedListRootRef } = (0, _useList.default)(useListParameters); const createHandleButtonClick = otherHandlers => event => { var _otherHandlers$onClic; otherHandlers == null ? void 0 : (_otherHandlers$onClic = otherHandlers.onClick) == null ? void 0 : _otherHandlers$onClic.call(otherHandlers, event); if (!event.defaultMuiPrevented) { const action = { type: _useSelect.SelectActionTypes.buttonClick, event }; dispatch(action); } }; (0, _utils.unstable_useEnhancedEffect)(() => { // Scroll to the currently highlighted option. if (highlightedOption != null) { var _options$get2; const optionRef = (_options$get2 = options.get(highlightedOption)) == null ? void 0 : _options$get2.ref; if (!listboxRef.current || !(optionRef != null && optionRef.current)) { return; } 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; } } }, [highlightedOption, options]); const getOptionMetadata = React.useCallback(optionValue => options.get(optionValue), [options]); const getSelectTriggerProps = (otherHandlers = {}) => { return (0, _extends2.default)({}, otherHandlers, { onClick: createHandleButtonClick(otherHandlers), ref: mergedListRootRef, role: 'combobox', 'aria-expanded': open, 'aria-controls': listboxId }); }; const getButtonProps = (otherHandlers = {}) => { const listboxAndButtonProps = (0, _combineHooksSlotProps.default)(getButtonRootProps, getListboxRootProps); const combinedProps = (0, _combineHooksSlotProps.default)(listboxAndButtonProps, getSelectTriggerProps); return combinedProps(otherHandlers); }; const getListboxProps = (otherHandlers = {}) => { return (0, _extends2.default)({}, otherHandlers, { id: listboxId, role: 'listbox', 'aria-multiselectable': multiple ? 'true' : undefined, ref: handleListboxRef, onMouseDown: preventDefault // to prevent the button from losing focus when interacting with the listbox }); }; 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; } return { buttonActive, buttonFocusVisible, buttonRef: mergedButtonRef, contextValue, disabled, dispatch, getButtonProps, getListboxProps, getOptionMetadata, listboxRef: mergedListRootRef, open, options: optionValues, value: selectValue, highlightedOption }; } var _default = useSelect; exports.default = _default;