'use client'; import * as React from 'react'; import { getIntrinsicElementProps, isHTMLElement, mergeCallbacks, slot, useControllableState, useId } from '@fluentui/react-utilities'; import { RatingItem } from '../../RatingItem'; import { StarFilled, StarRegular } from '@fluentui/react-icons'; /** * Create the state required to render Rating. * * The returned state can be modified with hooks such as useRatingStyles_unstable, * before being passed to renderRating_unstable. * * @param props - props from this instance of Rating * @param ref - reference to root HTMLElement of Rating */ export const useRating_unstable = (props, ref)=>{ const { color = 'neutral', size = 'extra-large', iconFilled = StarFilled, iconOutline = StarRegular, ...baseProps } = props; const state = useRatingBase_unstable({ iconFilled, iconOutline, ...baseProps }, ref); return { ...state, color, size }; }; /** * Base hook for Rating component. Manages state related to controlled/uncontrolled * rating value, hover state, radiogroup ARIA role, and keyboard/mouse interaction — * without design props (color, size). * * @param props - props from this instance of Rating (without color, size) * @param ref - reference to root HTMLElement of Rating */ export const useRatingBase_unstable = (props, ref)=>{ const generatedName = useId('rating-'); const { iconFilled = 'span', iconOutline = 'span', max = 5, name = generatedName, onChange, step = 1, itemLabel } = props; const [value, setValue] = useControllableState({ state: props.value, defaultState: props.defaultValue, initialState: 0 }); const isRatingRadioItem = (target)=>isHTMLElement(target, { constructorName: 'HTMLInputElement' }) && target.type === 'radio' && target.name === name; const [hoveredValue, setHoveredValue] = React.useState(undefined); // Generate the child RatingItems and memoize them to prevent unnecessary re-rendering const rootChildren = React.useMemo(()=>{ return Array.from(Array(max), (_, i)=>/*#__PURE__*/ React.createElement(RatingItem, { value: i + 1, key: i + 1 })); }, [ max ]); const state = { iconFilled, iconOutline, name, step, itemLabel, value, hoveredValue, components: { root: 'div' }, root: slot.always(getIntrinsicElementProps('div', { ref, children: rootChildren, role: 'radiogroup', ...props }, [ 'onChange' ]), { elementType: 'div' }) }; state.root.onChange = (ev)=>{ if (isRatingRadioItem(ev.target)) { const newValue = parseFloat(ev.target.value); if (!isNaN(newValue)) { setValue(newValue); onChange === null || onChange === void 0 ? void 0 : onChange(ev, { type: 'change', event: ev, value: newValue }); } } }; state.root.onMouseOver = mergeCallbacks(props.onMouseOver, (ev)=>{ if (isRatingRadioItem(ev.target)) { const newValue = parseFloat(ev.target.value); if (!isNaN(newValue)) { setHoveredValue(newValue); } } }); state.root.onMouseLeave = mergeCallbacks(props.onMouseLeave, (ev)=>{ setHoveredValue(undefined); }); return state; };