// components/ui/RadioGroup.tsx 'use client'; import * as React from 'react'; import clsx from 'clsx'; export type RadioGroupOption = { value: string; label: React.ReactNode; description?: React.ReactNode; disabled?: boolean; className?: string; }; export type RadioGroupVariant = | 'simple' // Radio links, Label rechts | 'withDescription' // Label + Description untereinander | 'right' // Label links, Radio rechts | 'panel'; // Segment-Panel (Pricing/Privacy-Style) type RadioGroupProps = { name?: string; legend?: React.ReactNode; helpText?: React.ReactNode; options: RadioGroupOption[]; /** Kontrollierter Wert (oder null für nichts gewählt) */ value: string | null; onChange: (value: string) => void; orientation?: 'vertical' | 'horizontal'; // nur relevant für simple variant?: RadioGroupVariant; className?: string; optionClassName?: string; idPrefix?: string; }; const baseRadioClasses = 'relative size-4 appearance-none rounded-full border border-gray-300 bg-white ' + 'before:absolute before:inset-1 before:rounded-full before:bg-white ' + 'not-checked:before:hidden checked:border-indigo-600 checked:bg-indigo-600 ' + 'focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600 ' + 'disabled:border-gray-300 disabled:bg-gray-100 disabled:before:bg-gray-400 ' + 'dark:border-white/10 dark:bg-white/5 dark:checked:border-indigo-500 dark:checked:bg-indigo-500 ' + 'dark:focus-visible:outline-indigo-500 dark:disabled:border-white/5 dark:disabled:bg-white/10 ' + 'dark:disabled:before:bg-white/20 forced-colors:appearance-auto forced-colors:before:hidden'; export function RadioGroup({ name, legend, helpText, options, value, onChange, orientation = 'vertical', variant = 'simple', className, optionClassName, idPrefix = 'rg', }: RadioGroupProps) { const internalName = React.useId(); const groupName = name ?? internalName; const isHorizontal = orientation === 'horizontal'; const handleChange = (nextValue: string) => { if (nextValue !== value) { onChange(nextValue); } }; const renderSimple = () => (
{options.map((opt) => { const id = `${idPrefix}-${groupName}-${opt.value}`; return (
handleChange(opt.value)} className={baseRadioClasses} />
); })}
); const renderWithDescription = () => (
{options.map((opt) => { const id = `${idPrefix}-${groupName}-${opt.value}`; const descId = opt.description ? `${id}-description` : undefined; return (
handleChange(opt.value)} className={baseRadioClasses} />
{opt.description && (

{opt.description}

)}
); })}
); const renderRight = () => (
{options.map((opt, idx) => { const id = `${idPrefix}-${groupName}-${opt.value || idx}`; const descId = opt.description ? `${id}-description` : undefined; return (
{opt.description && (

{opt.description}

)}
handleChange(opt.value)} className={baseRadioClasses} />
); })}
); const renderPanel = () => (
{options.map((opt, index) => { const id = `${idPrefix}-${groupName}-${opt.value}`; return ( ); })}
); return (
{legend && ( {legend} )} {helpText && (

{helpText}

)} {variant === 'withDescription' && renderWithDescription()} {variant === 'right' && renderRight()} {variant === 'panel' && renderPanel()} {variant === 'simple' && renderSimple()}
); }