{"version":3,"sources":["../../src/rating/Rating.tsx","../../src/rating/RatingStar.tsx","../../src/rating/RatingStar.styles.ts","../../src/rating/utils.ts"],"sourcesContent":["import { useCombinedState } from '@spark-ui/hooks/use-combined-state'\nimport { cx } from 'class-variance-authority'\nimport {\n  type ChangeEvent,\n  type ComponentPropsWithRef,\n  type MouseEvent,\n  type PropsWithChildren,\n  useCallback,\n  useRef,\n} from 'react'\n\nimport { RatingStar, type RatingStarProps } from './RatingStar'\nimport { getNearestHalfDecimal, getStarValue, splitAt } from './utils'\n\nexport interface RatingProps extends PropsWithChildren<ComponentPropsWithRef<'div'>> {\n  /**\n   * Use the `defaultValue` prop to set the default value of the input, on a from 0 to 5.\n   *\n   * Use this when you want to use it in an uncontrolled manner\n   */\n  defaultValue?: number\n  /**\n   * The value is the number of the rating selected, on a scale from 0 to 5.\n   *\n   * Use this when you want to use it in a controlled manner,\n   * in conjunction with the `onValueChange` prop\n   */\n  value?: number\n  /**\n   * Event handler called when the value changes.\n   */\n  onValueChange?: (value: number) => void\n  /**\n   * Sets the component as interactive or not.\n   * @default undefined\n   */\n  readOnly?: boolean\n  /**\n   * When `true`, prevents the user from interacting.\n   * @default false\n   */\n  disabled?: boolean\n  /**\n   * Sets the size of the stars.\n   * @default 'md'\n   */\n  size?: RatingStarProps['size']\n  /**\n   * Name of the underlying input.\n   * @default undefined\n   */\n  name?: string\n  /**\n   * id of the underlying input.\n   * @default undefined\n   */\n  id?: string\n  /**\n   * aria-label of the underlying input.\n   * @default undefined\n   */\n  'aria-label': string\n}\n\nexport const Rating = ({\n  defaultValue,\n  value: propValue,\n  onValueChange,\n  size = 'md',\n  disabled,\n  readOnly,\n  name,\n  id,\n  'aria-label': ariaLabel,\n  ref,\n  ...rest\n}: RatingProps) => {\n  const inputRef = useRef<HTMLInputElement>(null)\n  const starRefList = useRef<HTMLDivElement[]>([])\n\n  const [value, setRatingValue] = useCombinedState(propValue, defaultValue, onValueChange)\n\n  const valueRef = useRef(value)\n  const isInteractive = !(disabled || readOnly)\n\n  function onStarClick(index: number) {\n    if (!inputRef.current) return\n\n    setRatingValue(index + 1)\n    valueRef.current = index + 1\n\n    inputRef.current.focus()\n    inputRef.current.setAttribute('data-clicked', '')\n  }\n\n  function onInputChange(event: ChangeEvent<HTMLInputElement>) {\n    // 1. Avoiding unnecessary calls to onValueChange prop if value doesn't change\n    // 2. Preventing value to be resetted to 0\n    if (valueRef.current === Number(event.target.value) || Number(event.target.value) === 0) {\n      return\n    }\n    valueRef.current = Number(event.target.value)\n\n    setRatingValue(Number(event.target.value))\n  }\n\n  function onStarMouseEnter({ currentTarget }: MouseEvent<HTMLDivElement>) {\n    const currentStarIndex = starRefList.current.findIndex(star => star === currentTarget)\n\n    const [previousStars, followingStars] = splitAt(starRefList.current, currentStarIndex + 1)\n\n    previousStars.forEach(star => star.setAttribute('data-hovered', ''))\n    followingStars.forEach(star => star.removeAttribute('data-hovered'))\n  }\n\n  const handleStarRef = useCallback((elm: HTMLDivElement | null) => {\n    if (!elm) return\n    starRefList.current.push(elm)\n  }, [])\n\n  function resetDataPartInputAttr() {\n    inputRef.current?.removeAttribute('data-clicked')\n  }\n\n  function resetDataPartStarAttr() {\n    starRefList.current.forEach(star => star.removeAttribute('data-hovered'))\n  }\n\n  return (\n    <div\n      className=\"relative inline-flex\"\n      ref={ref}\n      data-spark-component=\"rating\"\n      {...rest}\n      onMouseLeave={resetDataPartStarAttr}\n    >\n      <input\n        name={name}\n        id={id}\n        aria-label={ariaLabel}\n        ref={inputRef}\n        data-part=\"input\"\n        className=\"peer absolute inset-0 opacity-0\"\n        type=\"range\"\n        min=\"0\"\n        max=\"5\"\n        step={readOnly ? 0.5 : 1}\n        disabled={disabled}\n        readOnly={readOnly}\n        value={getNearestHalfDecimal(value ?? 0)}\n        onChange={event => isInteractive && onInputChange(event)}\n        onBlur={resetDataPartInputAttr}\n      />\n      <div\n        className={cx(\n          size === 'lg' ? 'gap-x-md' : 'gap-x-sm',\n          'flex',\n          'peer-focus-visible:u-outline peer-[[data-part=input][data-clicked]]:shadow-none'\n        )}\n      >\n        {Array.from({ length: 5 }).map((_, index) => (\n          <RatingStar\n            disabled={disabled}\n            readOnly={readOnly}\n            size={size}\n            onClick={() => isInteractive && onStarClick(index)}\n            onMouseEnter={event => isInteractive && onStarMouseEnter(event)}\n            ref={handleStarRef}\n            key={index}\n            value={getStarValue({ index, value })}\n          />\n        ))}\n      </div>\n    </div>\n  )\n}\n","import { StarFill } from '@spark-ui/icons/StarFill'\nimport { StarOutline } from '@spark-ui/icons/StarOutline'\nimport { cx } from 'class-variance-authority'\nimport { type MouseEvent, Ref } from 'react'\n\nimport { Icon } from '../icon'\nimport {\n  ratingStarIconStyles,\n  type RatingStarIconStylesProps,\n  ratingStarStyles,\n  type RatingStarstylesProps,\n} from './RatingStar.styles'\nimport type { StarValue } from './types'\n\nexport interface RatingStarProps extends RatingStarstylesProps, RatingStarIconStylesProps {\n  value: StarValue\n  onClick?: (event: MouseEvent<HTMLDivElement>) => void\n  onMouseEnter?: (event: MouseEvent<HTMLDivElement>) => void\n  ref?: Ref<HTMLDivElement>\n}\n\nexport const RatingStar = ({\n  value,\n  size,\n  disabled,\n  readOnly,\n  onClick,\n  onMouseEnter,\n  ref: forwardedRef,\n}: RatingStarProps) => {\n  return (\n    <div\n      ref={forwardedRef}\n      onMouseEnter={onMouseEnter}\n      className={ratingStarStyles({\n        gap: size === 'lg' ? 'md' : 'sm',\n        disabled,\n        readOnly,\n      })}\n      data-part=\"star\"\n      onClick={onClick}\n    >\n      <div\n        className={cx(\n          'z-raised absolute overflow-hidden',\n          'group-[[data-part=star][data-hovered]]:overflow-visible'\n        )}\n        style={{ width: value * 100 + '%' }}\n      >\n        <Icon\n          className={ratingStarIconStyles({\n            size,\n            design: 'filled',\n          })}\n        >\n          <StarFill />\n        </Icon>\n      </div>\n\n      <Icon className={ratingStarIconStyles({ size, design: 'outlined' })}>\n        <StarOutline />\n      </Icon>\n    </div>\n  )\n}\n","import { cva, cx, VariantProps } from 'class-variance-authority'\n\nconst emptyRemainingStarsOnHoverClass = cx('[&_>_div]:peer-hover:w-0!')\n\nconst ratingStarStyles = cva(\n  ['peer', 'after:inset-0', 'group', 'relative', 'after:block after:absolute'],\n  {\n    variants: {\n      disabled: {\n        true: 'opacity-dim-3',\n        false: '',\n      },\n      readOnly: {\n        true: '',\n        false: '',\n      },\n      gap: {\n        sm: ['after:w-[calc(100%+(var(--spacing-sm)))]', 'last-of-type:after:content-none'],\n        md: ['after:w-[calc(100%+(var(--spacing-md)))]', 'last-of-type:after:content-none'],\n      },\n    },\n    compoundVariants: [\n      {\n        readOnly: false,\n        disabled: false,\n        className: cx(emptyRemainingStarsOnHoverClass, 'cursor-pointer'),\n      },\n    ],\n    defaultVariants: {\n      disabled: false,\n      readOnly: false,\n      gap: 'sm',\n    },\n  }\n)\n\nconst ratingStarIconStyles = cva('', {\n  variants: {\n    size: {\n      sm: 'text-caption-link',\n      md: 'text-body-1',\n      lg: 'text-display-1',\n    },\n    design: {\n      filled: [\n        'text-main-variant',\n        'group-[[data-part=star][data-hovered]]:text-main-variant-hovered',\n      ],\n      outlined: ['text-on-surface/dim-3'],\n    },\n  },\n})\n\ntype RatingStarstylesProps = Omit<VariantProps<typeof ratingStarStyles>, 'gap'>\ntype RatingStarIconStylesProps = Omit<VariantProps<typeof ratingStarIconStyles>, 'design'>\n\nexport { ratingStarStyles, ratingStarIconStyles }\nexport type { RatingStarstylesProps, RatingStarIconStylesProps }\n","import { type StarValue } from './types'\n\nfunction getNearestHalfDecimal(num: number): number {\n  return Math.round(num / 0.5) * 0.5\n}\n\nfunction getStarValue({ value, index }: { value?: number; index: number }): StarValue {\n  if (value === undefined) return 0\n\n  const starPosition = index + 1\n  const formattedValue = getNearestHalfDecimal(value)\n\n  if (Math.ceil(formattedValue) < starPosition) return 0\n\n  return formattedValue >= starPosition ? 1 : 0.5\n}\n\nfunction splitAt<T>(arr: T[], index: number): [T[], T[]] {\n  const prev = arr.slice(0, index)\n  const next = arr.slice(index)\n\n  return [prev, next]\n}\n\nexport { getNearestHalfDecimal, getStarValue, splitAt }\n"],"mappings":"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","names":["cx","cx","cx","jsx","jsxs","cx"]}