import type * as React from 'react'; import type { FormValidityHandle } from '../utils/formControl.js'; import type { PrimitivePropsWithRef } from '../utils/primitive.js'; /** * Payload passed to `onValueChange`: new value, previous value, and what drove the change. */ export interface RatingValueChangeDetail { /** The rating value the change settled on. */ value: number; /** The value held before the change, or `null` when it was `0` (unrated). */ previousValue: number | null; /** * What drove the change: `'keyboard'` for an arrow key, Home/End, or focus * landing on an item; `'pointer'` for a click; `'programmatic'` when the * application set it (a controlled-prop write, an imperative method, or a * form reset). */ reason: 'keyboard' | 'pointer' | 'programmatic'; } /** @internal Shared state distributed from {@link Rating} to its `RatingItem`s via context. */ export interface RatingContextValue { value: number; max: number; /** Whether re-picking the committed value clears the rating to 0. */ allowClear: boolean; allowHalf: boolean; disabled: boolean; readOnly: boolean; hoverValue: number | null; /** Resolved {@link RatingProps.itemLabel} — each item calls it with its own value and the group's `max`. */ itemLabel: (value: number, max: number) => string; onValueChange: (value: number, reason: RatingValueChangeDetail['reason']) => void; onHoverValueChange: (value: number | null) => void; } /** Props for the {@link Rating} root. */ export interface RatingProps extends Omit, 'onChange'> { /** * Current value for controlled usage; pair with `onValueChange`. * @default undefined — uncontrolled, tracks its own value internally. */ value?: number | undefined; /** * Initial value, for uncontrolled usage, seeding the first render. * @default 0 — no items filled until the user picks a rating. */ defaultValue?: number | undefined; /** * Fires when the selected value changes, carrying new value, previous value, and reason. * @default undefined — no-op if omitted. */ onValueChange?: ((detail: RatingValueChangeDetail) => void) | undefined; /** * Fires with the previewed value while hovering; a display-only signal that never touches committed value. * @default undefined — no-op if omitted. */ onHoverValueChange?: ((value: number | null) => void) | undefined; /** * Number of items to render, e.g. stars. * @default 5 * @min 1 */ max?: number | undefined; /** * Names each item as `aria-label`, since a bare icon announces nothing; an item's own `aria-label` overrides it. * @default (value, max) => `${value} of ${max} stars` */ itemLabel?: ((value: number, max: number) => string) | undefined; /** * Clears the committed value to `0` when picked again; with `allowHalf`, the exact half-value must match. * @default false */ allowClear?: boolean | undefined; /** * Allows half-item values, switching the root to `role="slider"` with items as non-focusable `role="presentation"`. * @default false */ allowHalf?: boolean | undefined; /** * Disables every `RatingItem`, blocking all interaction. * @default false */ disabled?: boolean | undefined; /** * Displays the current value but blocks interaction (still focusable, unlike `disabled`). * @default false */ readOnly?: boolean | undefined; /** * Form field name; with it, a hidden input submits the rating as `String(value)`, or empty when `0`. * @default undefined — submits nothing. */ name?: string | undefined; /** * Marks the rating required: with `name`, native `valueMissing` until an * item is chosen, reported through `checkValidity()`/`reportValidity()`. * @default false */ required?: boolean | undefined; /** * Form ID for this rating when rendered outside it, e.g. in a Dialog portal. * @default undefined — the rating belongs to its nearest ancestor `
`, if any. */ form?: string | undefined; /** * Content inside each derived `RatingItem`, replacing the default star glyph; ignored when `children` is given. * @default undefined — the default star glyph. */ icon?: React.ReactNode | undefined; /** * Size rung the skin scales the stars by, mirrored to `data-size`. * @default undefined — the skin's own default size. */ size?: 'md' | 'sm' | 'lg' | (string & {}) | undefined; } /** * Root `
` ref augmented with `FormValidityHandle` constraint-validation methods. */ export type RatingHandle = HTMLDivElement & FormValidityHandle; /** Props for a single {@link RatingItem}, e.g. one star. */ export interface RatingItemProps extends PrimitivePropsWithRef<'button'> { /** This item's 1-indexed position within the rating scale. */ value: number; /** * Disables this item, blocking selection and interaction. * @default false */ disabled?: boolean | undefined; }