text: import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
  import _extends from "@babel/runtime/helpers/esm/extends";
  const _excluded = ["value"],
        _excluded2 = ["className", "defaultValue", "disabled", "emptyIcon", "emptyLabelText", "getLabelText", "highlightSelectedOnly", "icon", "IconContainerComponent", "max", "name", "onChange", "onChangeActive", "onMouseLeave", "onMouseMove", "precision", "readOnly", "size", "value"];
  import * as React from 'react';
  import PropTypes from 'prop-types';
  import clsx from 'clsx';
  import { chainPropTypes, visuallyHidden } from '@mui/utils';
  import { unstable_composeClasses as composeClasses } from '@mui/core';
  import useTheme from '../styles/useTheme';
  import { capitalize, useForkRef, useIsFocusVisible, useControlled, unstable_useId as useId } from '../utils';
  import Star from '../internal/svg-icons/Star';
  import StarBorder from '../internal/svg-icons/StarBorder';
  import useThemeProps from '../styles/useThemeProps';
  import styled, { slotShouldForwardProp } from '../styles/styled';
  import ratingClasses, { getRatingUtilityClass } from './ratingClasses';
  import { jsx as _jsx } from "react/jsx-runtime";
  import { jsxs as _jsxs } from "react/jsx-runtime";
  
  function clamp(value, min, max) {
    if (value < min) {
      return min;
    }
  
    if (value > max) {
      return max;
    }
  
    return value;
  }
  
  function getDecimalPrecision(num) {
    const decimalPart = num.toString().split('.')[1];
    return decimalPart ? decimalPart.length : 0;
  }
  
  function roundValueToPrecision(value, precision) {
    if (value == null) {
      return value;
    }
  
    const nearest = Math.round(value / precision) * precision;
    return Number(nearest.toFixed(getDecimalPrecision(precision)));
  }
  
  const useUtilityClasses = ownerState => {
    const {
      classes,
      size,
      readOnly,
      disabled,
      emptyValueFocused,
      focusVisible
    } = ownerState;
    const slots = {
      root: ['root', `size${capitalize(size)}`, disabled && 'disabled', focusVisible && 'focusVisible', readOnly && 'readyOnly'],
      label: ['label', 'pristine'],
      labelEmptyValue: [emptyValueFocused && 'labelEmptyValueActive'],
      icon: ['icon'],
      iconEmpty: ['iconEmpty'],
      iconFilled: ['iconFilled'],
      iconHover: ['iconHover'],
      iconFocus: ['iconFocus'],
      iconActive: ['iconActive'],
      decimal: ['decimal'],
      visuallyHidden: ['visuallyHidden']
    };
    return composeClasses(slots, getRatingUtilityClass, classes);
  };
  
  const RatingRoot = styled('span', {
    name: 'MuiRating',
    slot: 'Root',
    overridesResolver: (props, styles) => {
      const {
        ownerState
      } = props;
      return [{
        [`& .${ratingClasses.visuallyHidden}`]: styles.visuallyHidden
      }, styles.root, styles[`size${capitalize(ownerState.size)}`], ownerState.readOnly && styles.readOnly];
    }
  })(({
    theme,
    ownerState
  }) => _extends({
    display: 'inline-flex',
    // Required to position the pristine input absolutely
    position: 'relative',
    fontSize: theme.typography.pxToRem(24),
    color: '#faaf00',
    cursor: 'pointer',
    textAlign: 'left',
    WebkitTapHighlightColor: 'transparent',
    [`&.${ratingClasses.disabled}`]: {
      opacity: theme.palette.action.disabledOpacity,
      pointerEvents: 'none'
    },
    [`&.${ratingClasses.focusVisible} .${ratingClasses.iconActive}`]: {
      outline: '1px solid #999'
    },
    [`& .${ratingClasses.visuallyHidden}`]: visuallyHidden
  }, ownerState.size === 'small' && {
    fontSize: theme.typography.pxToRem(18)
  }, ownerState.size === 'large' && {
    fontSize: theme.typography.pxToRem(30)
  }, ownerState.readOnly && {
    pointerEvents: 'none'
  }));
  const RatingLabel = styled('label', {
    name: 'MuiRating',
    slot: 'Label',
    overridesResolver: (props, styles) => styles.label
  })(({
    ownerState
  }) => _extends({
    cursor: 'inherit'
  }, ownerState.emptyValueFocused && {
    top: 0,
    bottom: 0,
    position: 'absolute',
    outline: '1px solid #999',
    width: '100%'
  }));
  const RatingIcon = styled('span', {
    name: 'MuiRating',
    slot: 'Icon',
    overridesResolver: (props, styles) => {
      const {
        ownerState
      } = props;
      return [styles.icon, ownerState.iconEmpty && styles.iconEmpty, ownerState.iconFilled && styles.iconFilled, ownerState.iconHover && styles.iconHover, ownerState.iconFocus && styles.iconFocus, ownerState.iconActive && styles.iconActive];
    }
  })(({
    theme,
    ownerState
  }) => _extends({
    // Fit wrapper to actual icon size.
    display: 'flex',
    transition: theme.transitions.create('transform', {
      duration: theme.transitions.duration.shortest
    }),
    // Fix mouseLeave issue.
    // https://github.com/facebook/react/issues/4492
    pointerEvents: 'none'
  }, ownerState.iconActive && {
    transform: 'scale(1.2)'
  }, ownerState.iconEmpty && {
    color: theme.palette.action.disabled
  }));
  const RatingDecimal = styled('span', {
    name: 'MuiRating',
    slot: 'Decimal',
    shouldForwardProp: prop => slotShouldForwardProp(prop) && prop !== 'iconActive',
    overridesResolver: (props, styles) => {
      const {
        iconActive
      } = props;
      return [styles.decimal, iconActive && styles.iconActive];
    }
  })(({
    iconActive
  }) => _extends({
    position: 'relative'
  }, iconActive && {
    transform: 'scale(1.2)'
  }));
  
  function IconContainer(props) {
    const other = _objectWithoutPropertiesLoose(props, _excluded);
  
    return /*#__PURE__*/_jsx("span", _extends({}, other));
  }
  
  process.env.NODE_ENV !== "production" ? IconContainer.propTypes = {
    value: PropTypes.number.isRequired
  } : void 0;
  
  function RatingItem(props) {
    const {
      classes,
      disabled,
      emptyIcon,
      focus,
      getLabelText,
      highlightSelectedOnly,
      hover,
      icon,
      IconContainerComponent,
      isActive,
      itemValue,
      labelProps,
      name,
      onBlur,
      onChange,
      onClick,
      onFocus,
      readOnly,
      ownerState,
      ratingValue,
      ratingValueRounded
    } = props;
    const isFilled = highlightSelectedOnly ? itemValue === ratingValue : itemValue <= ratingValue;
    const isHovered = itemValue <= hover;
    const isFocused = itemValue <= focus;
    const isChecked = itemValue === ratingValueRounded;
    const id = useId();
  
    const container = /*#__PURE__*/_jsx(RatingIcon, {
      as: IconContainerComponent,
      value: itemValue,
      className: clsx(classes.icon, isFilled ? classes.iconFilled : classes.iconEmpty, isHovered && classes.iconHover, isFocused && classes.iconFocus, isActive && classes.iconActive),
      ownerState: _extends({}, ownerState, {
        iconEmpty: !isFilled,
        iconFilled: isFilled,
        iconHover: isHovered,
        iconFocus: isFocused,
        iconActive: isActive
      }),
      children: emptyIcon && !isFilled ? emptyIcon : icon
    });
  
    if (readOnly) {
      return /*#__PURE__*/_jsx("span", _extends({}, labelProps, {
        children: container
      }));
    }
  
    return /*#__PURE__*/_jsxs(React.Fragment, {
      children: [/*#__PURE__*/_jsxs(RatingLabel, _extends({
        ownerState: _extends({}, ownerState, {
          emptyValueFocused: undefined
        }),
        htmlFor: id
      }, labelProps, {
        children: [container, /*#__PURE__*/_jsx("span", {
          className: classes.visuallyHidden,
          children: getLabelText(itemValue)
        })]
      })), /*#__PURE__*/_jsx("input", {
        className: classes.visuallyHidden,
        onFocus: onFocus,
        onBlur: onBlur,
        onChange: onChange,
        onClick: onClick,
        disabled: disabled,
        value: itemValue,
        id: id,
        type: "radio",
        name: name,
        checked: isChecked
      })]
    });
  }
  
  process.env.NODE_ENV !== "production" ? RatingItem.propTypes = {
    classes: PropTypes.object.isRequired,
    disabled: PropTypes.bool.isRequired,
    emptyIcon: PropTypes.node,
    focus: PropTypes.number.isRequired,
    getLabelText: PropTypes.func.isRequired,
    highlightSelectedOnly: PropTypes.bool.isRequired,
    hover: PropTypes.number.isRequired,
    icon: PropTypes.node,
    IconContainerComponent: PropTypes.elementType.isRequired,
    isActive: PropTypes.bool.isRequired,
    itemValue: PropTypes.number.isRequired,
    labelProps: PropTypes.object,
    name: PropTypes.string,
    onBlur: PropTypes.func.isRequired,
    onChange: PropTypes.func.isRequired,
    onClick: PropTypes.func.isRequired,
    onFocus: PropTypes.func.isRequired,
    ownerState: PropTypes.object.isRequired,
    ratingValue: PropTypes.number,
    ratingValueRounded: PropTypes.number,
    readOnly: PropTypes.bool.isRequired
  } : void 0;
  
  const defaultIcon = /*#__PURE__*/_jsx(Star, {
    fontSize: "inherit"
  });
  
  const defaultEmptyIcon = /*#__PURE__*/_jsx(StarBorder, {
    fontSize: "inherit"
  });
  
  function defaultLabelText(value) {
    return `${value} Star${value !== 1 ? 's' : ''}`;
  }
  
  const Rating = /*#__PURE__*/React.forwardRef(function Rating(inProps, ref) {
    const props = useThemeProps({
      name: 'MuiRating',
      props: inProps
    });
  
    const {
      className,
      defaultValue = null,
      disabled = false,
      emptyIcon = defaultEmptyIcon,
      emptyLabelText = 'Empty',
      getLabelText = defaultLabelText,
      highlightSelectedOnly = false,
      icon = defaultIcon,
      IconContainerComponent = IconContainer,
      max = 5,
      name: nameProp,
      onChange,
      onChangeActive,
      onMouseLeave,
      onMouseMove,
      precision = 1,
      readOnly = false,
      size = 'medium',
      value: valueProp
    } = props,
          other = _objectWithoutPropertiesLoose(props, _excluded2);
  
    const name = useId(nameProp);
    const [valueDerived, setValueState] = useControlled({
      controlled: valueProp,
      default: defaultValue,
      name: 'Rating'
    });
    const valueRounded = roundValueToPrecision(valueDerived, precision);
    const theme = useTheme();
    const [{
      hover,
      focus
    }, setState] = React.useState({
      hover: -1,
      focus: -1
    });
    let value = valueRounded;
  
    if (hover !== -1) {
      value = hover;
    }
  
    if (focus !== -1) {
      value = focus;
    }
  
    const {
      isFocusVisibleRef,
      onBlur: handleBlurVisible,
      onFocus: handleFocusVisible,
      ref: focusVisibleRef
    } = useIsFocusVisible();
    const [focusVisible, setFocusVisible] = React.useState(false);
    const rootRef = React.useRef();
    const handleFocusRef = useForkRef(focusVisibleRef, rootRef);
    const handleRef = useForkRef(handleFocusRef, ref);
  
    const handleMouseMove = event => {
      if (onMouseMove) {
        onMouseMove(event);
      }
  
      const rootNode = rootRef.current;
      const {
        right,
        left
      } = rootNode.getBoundingClientRect();
      const {
        width
      } = rootNode.firstChild.getBoundingClientRect();
      let percent;
  
      if (theme.direction === 'rtl') {
        percent = (right - event.clientX) / (width * max);
      } else {
        percent = (event.clientX - left) / (width * max);
      }
  
      let newHover = roundValueToPrecision(max * percent + precision / 2, precision);
      newHover = clamp(newHover, precision, max);
      setState(prev => prev.hover === newHover && prev.focus === newHover ? prev : {
        hover: newHover,
        focus: newHover
      });
      setFocusVisible(false);
  
      if (onChangeActive && hover !== newHover) {
        onChangeActive(event, newHover);
      }
    };
  
    const handleMouseLeave = event => {
      if (onMouseLeave) {
        onMouseLeave(event);
      }
  
      const newHover = -1;
      setState({
        hover: newHover,
        focus: newHover
      });
  
      if (onChangeActive && hover !== newHover) {
        onChangeActive(event, newHover);
      }
    };
  
    const handleChange = event => {
      let newValue = event.target.value === '' ? null : parseFloat(event.target.value); // Give mouse priority over keyboard
      // Fix https://github.com/mui-org/material-ui/issues/22827
  
      if (hover !== -1) {
        newValue = hover;
      }
  
      setValueState(newValue);
  
      if (onChange) {
        onChange(event, newValue);
      }
    };
  
    const handleClear = event => {
      // Ignore keyboard events
      // https://github.com/facebook/react/issues/7407
      if (event.clientX === 0 && event.clientY === 0) {
        return;
      }
  
      setState({
        hover: -1,
        focus: -1
      });
      setValueState(null);
  
      if (onChange && parseFloat(event.target.value) === valueRounded) {
        onChange(event, null);
      }
    };
  
    const handleFocus = event => {
      handleFocusVisible(event);
  
      if (isFocusVisibleRef.current === true) {
        setFocusVisible(true);
      }
  
      const newFocus = parseFloat(event.target.value);
      setState(prev => ({
        hover: prev.hover,
        focus: newFocus
      }));
    };
  
    const handleBlur = event => {
      if (hover !== -1) {
        return;
      }
  
      handleBlurVisible(event);
  
      if (isFocusVisibleRef.current === false) {
        setFocusVisible(false);
      }
  
      const newFocus = -1;
      setState(prev => ({
        hover: prev.hover,
        focus: newFocus
      }));
    };
  
    const [emptyValueFocused, setEmptyValueFocused] = React.useState(false);
  
    const ownerState = _extends({}, props, {
      defaultValue,
      disabled,
      emptyIcon,
      emptyLabelText,
      emptyValueFocused,
      focusVisible,
      getLabelText,
      icon,
      IconContainerComponent,
      max,
      precision,
      readOnly,
      size
    });
  
    const classes = useUtilityClasses(ownerState);
    return /*#__PURE__*/_jsxs(RatingRoot, _extends({
      ref: handleRef,
      onMouseMove: handleMouseMove,
      onMouseLeave: handleMouseLeave,
      className: clsx(classes.root, className),
      ownerState: ownerState,
      role: readOnly ? 'img' : null,
      "aria-label": readOnly ? getLabelText(value) : null
    }, other, {
      children: [Array.from(new Array(max)).map((_, index) => {
        const itemValue = index + 1;
        const ratingItemProps = {
          classes,
          disabled,
          emptyIcon,
          focus,
          getLabelText,
          highlightSelectedOnly,
          hover,
          icon,
          IconContainerComponent,
          name,
          onBlur: handleBlur,
          onChange: handleChange,
          onClick: handleClear,
          onFocus: handleFocus,
          ratingValue: value,
          ratingValueRounded: valueRounded,
          readOnly,
          ownerState
        };
        const isActive = itemValue === Math.ceil(value) && (hover !== -1 || focus !== -1);
  
        if (precision < 1) {
          const items = Array.from(new Array(1 / precision));
          return /*#__PURE__*/_jsx(RatingDecimal, {
            className: clsx(classes.decimal, isActive && classes.iconActive),
            ownerState: ownerState,
            iconActive: isActive,
            children: items.map(($, indexDecimal) => {
              const itemDecimalValue = roundValueToPrecision(itemValue - 1 + (indexDecimal + 1) * precision, precision);
              return /*#__PURE__*/_jsx(RatingItem, _extends({}, ratingItemProps, {
                // The icon is already displayed as active
                isActive: false,
                itemValue: itemDecimalValue,
                labelProps: {
                  style: items.length - 1 === indexDecimal ? {} : {
                    width: itemDecimalValue === value ? `${(indexDecimal + 1) * precision * 100}%` : '0%',
                    overflow: 'hidden',
                    position: 'absolute'
                  }
                }
              }), itemDecimalValue);
            })
          }, itemValue);
        }
  
        return /*#__PURE__*/_jsx(RatingItem, _extends({}, ratingItemProps, {
          isActive: isActive,
          itemValue: itemValue
        }), itemValue);
      }), !readOnly && !disabled && /*#__PURE__*/_jsxs(RatingLabel, {
        className: clsx(classes.label, classes.labelEmptyValue),
        ownerState: ownerState,
        children: [/*#__PURE__*/_jsx("input", {
          className: classes.visuallyHidden,
          value: "",
          id: `${name}-empty`,
          type: "radio",
          name: name,
          checked: valueRounded == null,
          onFocus: () => setEmptyValueFocused(true),
          onBlur: () => setEmptyValueFocused(false),
          onChange: handleChange
        }), /*#__PURE__*/_jsx("span", {
          className: classes.visuallyHidden,
          children: emptyLabelText
        })]
      })]
    }));
  });
  process.env.NODE_ENV !== "production" ? Rating.propTypes
  /* remove-proptypes */
  = {
    // ----------------------------- Warning --------------------------------
    // | These PropTypes are generated from the TypeScript type definitions |
    // |     To update them edit the d.ts file and run "yarn proptypes"     |
    // ----------------------------------------------------------------------
  
    /**
     * Override or extend the styles applied to the component.
     */
    classes: PropTypes.object,
  
    /**
     * @ignore
     */
    className: PropTypes.string,
  
    /**
     * The default value. Use when the component is not controlled.
     * @default null
     */
    defaultValue: PropTypes.number,
  
    /**
     * If `true`, the component is disabled.
     * @default false
     */
    disabled: PropTypes.bool,
  
    /**
     * The icon to display when empty.
     * @default <StarBorder fontSize="inherit" />
     */
    emptyIcon: PropTypes.node,
  
    /**
     * The label read when the rating input is empty.
     * @default 'Empty'
     */
    emptyLabelText: PropTypes.node,
  
    /**
     * Accepts a function which returns a string value that provides a user-friendly name for the current value of the rating.
     * This is important for screen reader users.
     *
     * For localization purposes, you can use the provided [translations](/guides/localization/).
     * @param {number} value The rating label's value to format.
     * @returns {string}
     * @default function defaultLabelText(value) {
     *   return `${value} Star${value !== 1 ? 's' : ''}`;
     * }
     */
    getLabelText: PropTypes.func,
  
    /**
     * If `true`, only the selected icon will be highlighted.
     * @default false
     */
    highlightSelectedOnly: PropTypes.bool,
  
    /**
     * The icon to display.
     * @default <Star fontSize="inherit" />
     */
    icon: PropTypes.node,
  
    /**
     * The component containing the icon.
     * @default function IconContainer(props) {
     *   const { value, ...other } = props;
     *   return <span {...other} />;
     * }
     */
    IconContainerComponent: PropTypes.elementType,
  
    /**
     * Maximum rating.
     * @default 5
     */
    max: PropTypes.number,
  
    /**
     * The name attribute of the radio `input` elements.
     * This input `name` should be unique within the page.
     * Being unique within a form is insufficient since the `name` is used to generated IDs.
     */
    name: PropTypes.string,
  
    /**
     * Callback fired when the value changes.
     * @param {React.SyntheticEvent} event The event source of the callback.
     * @param {number|null} value The new value.
     */
    onChange: PropTypes.func,
  
    /**
     * Callback function that is fired when the hover state changes.
     * @param {React.SyntheticEvent} event The event source of the callback.
     * @param {number} value The new value.
     */
    onChangeActive: PropTypes.func,
  
    /**
     * @ignore
     */
    onMouseLeave: PropTypes.func,
  
    /**
     * @ignore
     */
    onMouseMove: PropTypes.func,
  
    /**
     * The minimum increment value change allowed.
     * @default 1
     */
    precision: chainPropTypes(PropTypes.number, props => {
      if (props.precision < 0.1) {
        return new Error(['MUI: The prop `precision` should be above 0.1.', 'A value below this limit has an imperceptible impact.'].join('\n'));
      }
  
      return null;
    }),
  
    /**
     * Removes all hover effects and pointer events.
     * @default false
     */
    readOnly: PropTypes.bool,
  
    /**
     * The size of the component.
     * @default 'medium'
     */
    size: PropTypes
    /* @typescript-to-proptypes-ignore */
    .oneOfType([PropTypes.oneOf(['small', 'medium', 'large']), PropTypes.string]),
  
    /**
     * The system prop that allows defining system overrides as well as additional CSS styles.
     */
    sx: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
  
    /**
     * The rating value.
     */
    value: PropTypes.number
  } : void 0;
  export default Rating;