text: import * as React from 'react';
  import { unstable_useControlled as useControlled } from '@mui/utils';
  import { ActionTypes } from './types';
  import areArraysEqual from '../utils/areArraysEqual';
  /**
   * Triggers change event handlers when reducer returns changed state.
   */
  
  function useReducerReturnValueHandler(state, value, options, optionComparer, setValueState, onValueChange, onHighlightChange) {
    const valueRef = React.useRef(value);
    valueRef.current = value;
    const onValueChangeRef = React.useRef(onValueChange);
    onValueChangeRef.current = onValueChange;
    const onHighlightChangeRef = React.useRef(onHighlightChange);
    onHighlightChangeRef.current = onHighlightChange;
    React.useEffect(() => {
      if (Array.isArray(state.selectedValue)) {
        if (areArraysEqual(state.selectedValue, valueRef.current)) {
          return;
        }
      } else if (state.selectedValue == null && valueRef.current == null || state.selectedValue != null && valueRef.current != null && optionComparer.current(state.selectedValue, valueRef.current)) {
        return;
      }
  
      setValueState(state.selectedValue);
  
      if (state.selectedValue != null) {
        var _onValueChangeRef$cur;
  
        // @ts-ignore We know that selectedValue has the correct type depending on `selectMultiple` prop.
        (_onValueChangeRef$cur = onValueChangeRef.current) == null ? void 0 : _onValueChangeRef$cur.call(onValueChangeRef, state.selectedValue);
      }
    }, [state.selectedValue, setValueState, optionComparer]);
    React.useEffect(() => {
      // Fire the highlightChange event when reducer returns changed `highlightedIndex`.
      if (state.highlightedIndex === -1) {
        var _onHighlightChangeRef;
  
        (_onHighlightChangeRef = onHighlightChangeRef.current) == null ? void 0 : _onHighlightChangeRef.call(onHighlightChangeRef, null);
      } else {
        var _onHighlightChangeRef2;
  
        (_onHighlightChangeRef2 = onHighlightChangeRef.current) == null ? void 0 : _onHighlightChangeRef2.call(onHighlightChangeRef, options[state.highlightedIndex]);
      }
    }, [state.highlightedIndex, options]);
  }
  
  export default function useControllableReducer(internalReducer, externalReducer, props) {
    const {
      value: controlledValue,
      defaultValue,
      onChange: onValueChange,
      onHighlightChange,
      options,
      optionComparer
    } = props;
    const propsRef = React.useRef(props);
    propsRef.current = props;
    const [value, setValueState] = useControlled({
      controlled: controlledValue,
      default: defaultValue,
      name: 'useListbox'
    });
    const previousValueRef = React.useRef(null);
    const [state, dispatch] = React.useReducer(externalReducer != null ? externalReducer : internalReducer, {
      highlightedIndex: -1,
      selectedValue: value
    });
    const optionComparerRef = React.useRef(optionComparer);
    optionComparerRef.current = optionComparer;
    React.useEffect(() => {
      // Detect external changes to the controlled `value` prop and update the state.
      if (controlledValue === undefined) {
        return;
      }
  
      if (Array.isArray(controlledValue) && Array.isArray(previousValueRef.current) && areArraysEqual(previousValueRef.current, controlledValue, optionComparerRef.current)) {
        // `value` is an array and it did not change.
        return;
      }
  
      if (!Array.isArray(controlledValue) && controlledValue != null && previousValueRef.current != null && optionComparerRef.current(controlledValue, previousValueRef.current)) {
        // `value` is a single option and it did not change.
        return;
      }
  
      previousValueRef.current = controlledValue;
      dispatch({
        type: ActionTypes.setControlledValue,
        value: controlledValue,
        props: propsRef.current
      });
    }, [controlledValue]);
    useReducerReturnValueHandler(state, value, options, optionComparerRef, setValueState, onValueChange, onHighlightChange);
    return [state, dispatch];
  }