{"version":3,"file":"Rating.cjs","names":["createVarsResolver","getSize","getThemeColor","factory","useProps","useStyles","useDirection","RatingItem","RatingProvider","Box","classes"],"sources":["../../../src/components/Rating/Rating.tsx"],"sourcesContent":["import { useRef, useState } from 'react';\nimport { clamp, useId, useMergedRef, useUncontrolled } from '@mantine/hooks';\nimport {\n  Box,\n  BoxProps,\n  createVarsResolver,\n  ElementProps,\n  factory,\n  Factory,\n  getSize,\n  getThemeColor,\n  MantineColor,\n  MantineSize,\n  StylesApiProps,\n  useDirection,\n  useProps,\n  useStyles,\n} from '../../core';\nimport { RatingProvider } from './Rating.context';\nimport { RatingItem } from './RatingItem/RatingItem';\nimport classes from './Rating.module.css';\n\nfunction roundValueTo(value: number, to: number) {\n  const rounded = Math.round(value / to) * to;\n  const precision = `${to}`.split('.')[1]?.length || 0;\n  return Number(rounded.toFixed(precision));\n}\n\nexport type RatingStylesNames =\n  | 'root'\n  | 'starSymbol'\n  | 'input'\n  | 'label'\n  | 'symbolBody'\n  | 'symbolGroup';\n\nexport type RatingCssVariables = {\n  root: '--rating-size' | '--rating-color';\n};\n\nexport interface RatingProps\n  extends BoxProps, StylesApiProps<RatingFactory>, ElementProps<'div', 'onChange'> {\n  /** Uncontrolled component default value */\n  defaultValue?: number;\n\n  /** Controlled component value */\n  value?: number;\n\n  /** Called when value changes */\n  onChange?: (value: number) => void;\n\n  /** Icon displayed for unselected rating items. Can be a function that receives the rating value. */\n  emptySymbol?: React.ReactNode | ((value: number) => React.ReactNode);\n\n  /** Icon displayed for selected rating items. Can be a function that receives the rating value. */\n  fullSymbol?: React.ReactNode | ((value: number) => React.ReactNode);\n\n  /** Number of fractions each item can be divided into, default is 1 */\n  fractions?: number;\n\n  /** Controls component size @default 'sm' */\n  size?: MantineSize | number | (string & {});\n\n  /** Number of rating items (stars), default is 5 */\n  count?: number;\n\n  /** Called when rating item is hovered. Receives -1 when hover ends. */\n  onHover?: (value: number) => void;\n\n  /** Function to generate aria-label for each rating value. Receives the rating value as argument, default is (value) => String(value) */\n  getSymbolLabel?: (index: number) => string;\n\n  /** Name attribute for form submission. If not provided, a unique id will be generated. */\n  name?: string;\n\n  /** When true, rating cannot be changed by user interaction, default is false */\n  readOnly?: boolean;\n\n  /** When true, clicking the same rating value clears the rating to 0, default is false */\n  allowClear?: boolean;\n\n  /** When true, only the clicked rating item is highlighted, not all items up to the selected value, default is false */\n  highlightSelectedOnly?: boolean;\n\n  /** Key of theme.colors or any CSS color value, default is 'yellow' */\n  color?: MantineColor;\n}\n\nexport type RatingFactory = Factory<{\n  props: RatingProps;\n  ref: HTMLDivElement;\n  stylesNames: RatingStylesNames;\n  vars: RatingCssVariables;\n}>;\n\nconst defaultProps = {\n  size: 'sm',\n  getSymbolLabel: (value) => `${value}`,\n  count: 5,\n  fractions: 1,\n  color: 'yellow',\n} satisfies Partial<RatingProps>;\n\nconst varsResolver = createVarsResolver<RatingFactory>((theme, { size, color }) => ({\n  root: {\n    '--rating-size': getSize(size, 'rating-size'),\n    '--rating-color': getThemeColor(color, theme),\n  },\n}));\n\nexport const Rating = factory<RatingFactory>((_props) => {\n  const props = useProps('Rating', defaultProps, _props);\n  const {\n    classNames,\n    className,\n    style,\n    styles,\n    unstyled,\n    vars,\n    name,\n    id,\n    value,\n    defaultValue,\n    onChange,\n    fractions,\n    count,\n    onMouseEnter,\n    readOnly,\n    allowClear,\n    onMouseMove,\n    onHover,\n    onMouseLeave,\n    onTouchStart,\n    onTouchEnd,\n    size,\n    variant,\n    getSymbolLabel,\n    color,\n    emptySymbol,\n    fullSymbol,\n    highlightSelectedOnly,\n    attributes,\n    ref,\n    ...others\n  } = props;\n\n  const getStyles = useStyles<RatingFactory>({\n    name: 'Rating',\n    classes,\n    props,\n    className,\n    style,\n    classNames,\n    styles,\n    unstyled,\n    attributes,\n    vars,\n    varsResolver,\n  });\n\n  const { dir } = useDirection();\n\n  const _name = useId(name);\n  const _id = useId(id);\n  const rootRef = useRef<HTMLDivElement>(null);\n\n  const [_value, setValue] = useUncontrolled({\n    value,\n    defaultValue,\n    finalValue: 0,\n    onChange,\n  });\n\n  const [hovered, setHovered] = useState(-1);\n  const [isOutside, setOutside] = useState(true);\n\n  const _fractions = Math.floor(fractions);\n  const _count = Math.floor(count);\n\n  const decimalUnit = 1 / _fractions;\n  const stableValueRounded = roundValueTo(_value, decimalUnit);\n  const finalValue = hovered !== -1 ? hovered : stableValueRounded;\n\n  const getRatingFromCoordinates = (x: number) => {\n    if (!rootRef.current) {\n      return 0;\n    }\n\n    const { left, right, width } = rootRef.current.getBoundingClientRect();\n    const symbolWidth = width / _count;\n\n    const hoverPosition = dir === 'rtl' ? right - x : x - left;\n    const hoverValue = hoverPosition / symbolWidth;\n\n    return clamp(roundValueTo(hoverValue + decimalUnit / 2, decimalUnit), decimalUnit, _count);\n  };\n\n  const handleMouseEnter = (event: React.MouseEvent<HTMLDivElement>) => {\n    onMouseEnter?.(event);\n    !readOnly && setOutside(false);\n  };\n\n  const handleMouseMove = (event: React.MouseEvent<HTMLDivElement>) => {\n    onMouseMove?.(event);\n\n    if (readOnly) {\n      return;\n    }\n\n    const rounded = getRatingFromCoordinates(event.clientX);\n\n    setHovered(rounded);\n    rounded !== hovered && onHover?.(rounded);\n  };\n\n  const handleMouseLeave = (event: React.MouseEvent<HTMLDivElement>) => {\n    onMouseLeave?.(event);\n\n    if (readOnly) {\n      return;\n    }\n\n    setHovered(-1);\n    setOutside(true);\n    hovered !== -1 && onHover?.(-1);\n  };\n\n  const handleTouchStart = (event: React.TouchEvent<HTMLDivElement>) => {\n    const { touches } = event;\n    if (touches.length !== 1) {\n      return;\n    }\n\n    if (!readOnly) {\n      const touch = touches[0];\n      setValue(getRatingFromCoordinates(touch.clientX));\n    }\n\n    onTouchStart?.(event);\n  };\n\n  const handleTouchEnd = (event: React.TouchEvent<HTMLDivElement>) => {\n    event.preventDefault();\n\n    onTouchEnd?.(event);\n  };\n\n  const handleItemBlur = () => isOutside && setHovered(-1);\n\n  const handleInputChange = (event: React.ChangeEvent<HTMLInputElement> | number) => {\n    if (!readOnly) {\n      if (typeof event === 'number') {\n        setHovered(event);\n      } else {\n        setHovered(parseFloat(event.target.value));\n      }\n    }\n  };\n\n  const handleChange = (event: React.ChangeEvent<HTMLInputElement> | number) => {\n    if (!readOnly) {\n      const newValue = typeof event === 'number' ? event : parseFloat(event.target.value);\n\n      // If allowClear is true and clicking the same value, reset to 0\n      if (allowClear && newValue === stableValueRounded) {\n        setValue(0);\n      } else {\n        setValue(newValue);\n      }\n    }\n  };\n\n  const items = Array(_count)\n    .fill(0)\n    .map((_, index) => {\n      const integerValue = index + 1;\n      const fractionItems = Array.from(new Array(index === 0 ? _fractions + 1 : _fractions));\n      const isGroupActive = !readOnly && Math.ceil(hovered) === integerValue;\n\n      return (\n        <div\n          key={integerValue}\n          data-active={isGroupActive || undefined}\n          {...getStyles('symbolGroup')}\n        >\n          {fractionItems.map((__, fractionIndex) => {\n            const fractionValue = decimalUnit * (index === 0 ? fractionIndex : fractionIndex + 1);\n            const symbolValue = roundValueTo(integerValue - 1 + fractionValue, decimalUnit);\n\n            return (\n              <RatingItem\n                key={`${integerValue}-${symbolValue}`}\n                getSymbolLabel={getSymbolLabel}\n                emptyIcon={emptySymbol}\n                fullIcon={fullSymbol}\n                full={\n                  highlightSelectedOnly ? symbolValue === finalValue : symbolValue <= finalValue\n                }\n                active={symbolValue === finalValue}\n                checked={symbolValue === stableValueRounded}\n                readOnly={readOnly}\n                fractionValue={fractionValue}\n                value={symbolValue}\n                name={_name}\n                onChange={handleChange}\n                onBlur={handleItemBlur}\n                onInputChange={handleInputChange}\n                id={`${_id}-${index}-${fractionIndex}`}\n              />\n            );\n          })}\n        </div>\n      );\n    });\n\n  return (\n    <RatingProvider value={{ getStyles }}>\n      <Box\n        ref={useMergedRef(rootRef, ref)}\n        {...getStyles('root')}\n        onMouseMove={handleMouseMove}\n        onMouseEnter={handleMouseEnter}\n        onMouseLeave={handleMouseLeave}\n        onTouchStart={handleTouchStart}\n        onTouchEnd={handleTouchEnd}\n        variant={variant}\n        size={size}\n        id={_id}\n        {...others}\n      >\n        {items}\n      </Box>\n    </RatingProvider>\n  );\n});\n\nRating.classes = classes;\nRating.varsResolver = varsResolver;\nRating.displayName = '@mantine/core/Rating';\n"],"mappings":"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"}