/*! © 2026 Yahoo, Inc. UDS v0.0.0-development */
"use client";
import { cx, getStyles } from "../../../styles/styler.js";
import { Box } from "../../Box.js";
import { FormLabel } from "../../FormLabel.js";
import { SpringMotionConfig } from "../SpringMotionConfig.js";
import { useRadioGroup } from "./useRadioGroup.js";
import { forwardRef, useCallback, useId, useMemo, useRef, useState } from "react";
import { jsx, jsxs } from "react/jsx-runtime";
import { m, useReducedMotion } from "motion/react";
//#region src/components/client/Radio/Radio.tsx
const RADIO_VARIANTS = ["primary", "secondary"];
const RADIO_SIZES = ["sm", "md"];
const VARIANT_ERROR_MAP = {
	primary: "alert",
	secondary: "alert-secondary"
};
const MotionBox = m.create(Box);
const hoverTransition = {
	layoutVariant: "smooth",
	layoutSpeed: "3"
};
const pressTransition = {
	layoutVariant: "veryBouncy",
	layoutSpeed: "4"
};
/**
* **⚙️️ A Radio.
*
* @componentType Client component
*
* @description
* A radio component allows users to select one or multiple options from a set. Unlike checkbox, radio buttons cannot have multiple selected in a form, allowing only 1 selection in a group. It represents a binary state, typically as selected or unselected.
*
* @see
* Check out the {@link https://uds.build/docs/components/radio Radio Docs} for more info
*
* @usage
* - Forms: Radio
*
* @example
* ```tsx
* 'use client';
* import { Radio } from "@yahoo/uds";
*
* <Radio label="Name" />
*```
*
* @related [Radio](https://uds.build/docs/components/Radio).
**/
const Radio = forwardRef(function Radio({ id, name: nameProp, label, labelPosition = "start", variant: variantProp = "primary", size = "md", reduceMotion: forceReduceMotion, value: valueProp = "", checked: checkedProp, defaultChecked, disabled, hasError, onChange, onFocus, onBlur, className, style, slotProps, ...radioProps }, parentRef) {
	const generatedId = useId();
	const uid = id ?? `uds-radio-${generatedId}`;
	const rootSlotProps = slotProps?.root ?? {};
	const radioSlotProps = slotProps?.radio ?? {};
	const radioIconSlotProps = slotProps?.radioIcon ?? {};
	const labelSlotProps = slotProps?.label ?? {};
	const innerRef = useRef(null);
	/**
	* State
	*/
	const { name, isControlled, checked, setGroupValue } = useRadioGroup({
		name: nameProp,
		value: valueProp,
		checked: checkedProp,
		defaultChecked
	});
	const [isHovered, setIsHovered] = useState(false);
	const [isPressed, setIsPressed] = useState(false);
	/**
	* Derived values
	*/
	const variant = useMemo(() => hasError ? VARIANT_ERROR_MAP[variantProp] : variantProp, [hasError, variantProp]);
	const showHoverEffect = useMemo(() => !disabled && isHovered, [disabled, isHovered]);
	const showPressedEffect = useMemo(() => !disabled && !checked && isPressed, [
		checked,
		disabled,
		isPressed
	]);
	const scale = useMemo(() => showPressedEffect ? .9 : showHoverEffect ? 1.1 : 1, [showHoverEffect, showPressedEffect]);
	const checkOpacity = useMemo(() => checked ? showPressedEffect ? "opacity-55" : "opacity-100" : "opacity-0", [checked, showPressedEffect]);
	const showShadow = useMemo(() => {
		return !disabled && (showPressedEffect && !checked || showHoverEffect && checked);
	}, [
		checked,
		disabled,
		showHoverEffect,
		showPressedEffect
	]);
	const motionAnimate = useMemo(() => ({ scale }), [scale]);
	const motionTransition = useMemo(() => isPressed ? pressTransition : hoverTransition, [isPressed]);
	/**
	* Handlers
	*/
	const handleOnChange = useCallback((e) => {
		setGroupValue(e.target.value);
		onChange?.(e);
	}, [onChange, setGroupValue]);
	const handleFocus = useCallback((e) => {
		onFocus?.(e);
	}, [onFocus]);
	const handleBlur = useCallback((e) => {
		onBlur?.(e);
	}, [onBlur]);
	const handleHoverStart = useCallback(() => {
		setIsHovered(true);
	}, []);
	const handleHoverEnd = useCallback(() => {
		setIsHovered(false);
	}, []);
	const handleTapStart = useCallback(() => {
		setIsPressed(true);
	}, []);
	const handleTapEnd = useCallback(() => {
		setIsPressed(false);
	}, []);
	const prefersReducedMotion = useReducedMotion();
	const reduceMotion = forceReduceMotion ? "always" : "user";
	const cssAnimationDuration = prefersReducedMotion || forceReduceMotion ? "duration-0" : "duration-120";
	const classNames = {
		root: getStyles({
			radioSizeRoot: size,
			radioVariantValueRoot: checked ? "checked" : "unchecked",
			radioVariantRoot: variant,
			display: "flex",
			flexDirection: labelPosition === "start" ? "row" : "row-reverse",
			alignItems: "center",
			className: cx([{
				"cursor-pointer": !disabled,
				"cursor-default": disabled,
				"opacity-50": disabled
			}, className])
		}),
		radio: getStyles({
			radioSizeRadio: size,
			radioVariantRadio: variant,
			radioVariantValueRadio: checked ? "checked" : "unchecked",
			className: cx([
				"border",
				"uds-ring",
				"uds-ring-within",
				cssAnimationDuration,
				"transition-[background-color,border-color]",
				"transition-shadow"
			])
		}),
		radioCircle: getStyles({
			radioVariantRadioCircle: variant,
			radioVariantValueRadioCircle: checked ? "checked" : "unchecked",
			className: cx([
				"pointer-events-none",
				"w-[8px]",
				"h-[8px]",
				checkOpacity,
				cssAnimationDuration,
				"transition-opacity"
			])
		}),
		htmlRadio: cx("cursor-[inherit]", "absolute", "opacity-0", "top-1/2", "left-1/2", "w-[calc(100%+2px)]", "h-[calc(100%+2px)]", "transform", "translate-x-[-50%]", "translate-y-[-50%]"),
		label: cx(labelPosition === "start" ? "text-start" : "text-end")
	};
	const RootElement = label ? m.label : m.div;
	return /* @__PURE__ */ jsx(SpringMotionConfig, {
		reducedMotion: reduceMotion,
		...motionTransition,
		children: /* @__PURE__ */ jsxs(RootElement, {
			className: classNames.root,
			"data-testid": "container",
			style,
			onHoverStart: handleHoverStart,
			onHoverEnd: handleHoverEnd,
			onTapStart: handleTapStart,
			onTap: handleTapEnd,
			onTapCancel: handleTapEnd,
			tabIndex: -1,
			...rootSlotProps,
			children: [/* @__PURE__ */ jsxs(MotionBox, {
				position: "relative",
				borderRadius: "full",
				alignItems: "center",
				justifyContent: "center",
				flex: "none",
				className: classNames.radio,
				animate: motionAnimate,
				insetShadow: showShadow ? "lg-invert" : "none",
				...radioSlotProps,
				children: [/* @__PURE__ */ jsx("input", {
					type: "radio",
					tabIndex: 0,
					...radioProps,
					ref: (ref) => {
						innerRef.current = ref;
						if (typeof parentRef === "function") parentRef(ref);
						else if (parentRef !== null) parentRef.current = ref;
					},
					onFocus: handleFocus,
					onBlur: handleBlur,
					id: uid,
					name,
					value: valueProp,
					disabled,
					"aria-invalid": hasError,
					onChange: handleOnChange,
					...isControlled ? { checked } : { defaultChecked },
					className: classNames.htmlRadio
				}), /* @__PURE__ */ jsx(Box, {
					borderRadius: "full",
					className: classNames.radioCircle,
					...radioIconSlotProps
				})]
			}), label && /* @__PURE__ */ jsx(FormLabel, {
				as: "div",
				variant: "inherit",
				color: "inherit",
				label,
				className: classNames.label,
				...labelSlotProps
			})]
		})
	});
});
Radio.displayName = "Radio";
//#endregion
export { RADIO_SIZES, RADIO_VARIANTS, Radio };
