import { CheckIcon } from "lucide-react"; import { createContext, useContext, useEffect, useMemo, type ReactNode, type RefObject, } from "react"; import { DropdownMenuRadioGroup, DropdownMenuRadioItem } from "../../../ui/dropdown-menu"; import { MENU_BUTTON_CLASS, MENU_CHECK_CLASS, MENU_CHECK_SLOT_CLASS, MENU_META_CLASS, } from "../../../ui/menu-styles"; import { cn } from "../../lib/utils"; /** Dropdowns rove through menu items; dialogs use ordinary Tab stops. */ export type MenuBodyPresentation = "menu" | "dialog"; const RadioGroupContext = createContext<{ presentation: MenuBodyPresentation; value: string | null; }>({ presentation: "menu", value: null }); export function RadioGroup(props: { presentation: MenuBodyPresentation; label: string; value: string | null; className?: string | undefined; children: ReactNode; }) { const { presentation, value } = props; const context = useMemo(() => ({ presentation, value }), [presentation, value]); return ( {presentation === "menu" ? ( {props.children} ) : (
{props.children}
)}
); } export function RadioRow(props: { value: string; disabled?: boolean | undefined; icon?: ReactNode | undefined; label: string; meta?: string | undefined; className?: string | undefined; ref?: ((node: HTMLElement | null) => void) | undefined; onSelect: () => void; }) { const group = useContext(RadioGroupContext); const content = ( <> {props.icon} {props.label} {props.meta ? {props.meta} : null} ); if (group.presentation === "menu") { return ( { // Choices can reveal more choices, or report a pending mutation. event.preventDefault(); props.onSelect(); }} className={cn("cursor-pointer", props.className)} > {content} ); } const checked = group.value === props.value; return ( ); } /** A drill-in replaces its opener; start roving focus on the checked enabled row. */ export function useFocusCheckedRow( ref: RefObject, presentation: MenuBodyPresentation, ) { useEffect(() => { const body = ref.current; if (presentation !== "menu" || !body || body.contains(document.activeElement)) return; const enabled = '[role="menuitemradio"]:not([data-disabled])'; const row = body.querySelector(`${enabled}[aria-checked="true"]`) ?? body.querySelector(enabled); row?.focus({ preventScroll: true }); // Only on open: later choices keep focus where the user put it. }, [ref, presentation]); }