{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "radio-group",
  "title": "Radio Group",
  "description": "A controlled or uncontrolled radio group with horizontal and vertical layouts.",
  "registryDependencies": [
    "@neumorphism-ui/utils"
  ],
  "files": [
    {
      "path": "src/components/ui/radio-group.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\ntype RadioGroupContextValue = {\n  disabled?: boolean;\n  name: string;\n  onValueChange: (value: string) => void;\n  required?: boolean;\n  value?: string;\n};\n\nconst RadioGroupContext = React.createContext<RadioGroupContextValue | null>(null);\n\ninterface RadioGroupProps\n  extends Omit<React.ComponentProps<\"div\">, \"defaultValue\" | \"onChange\"> {\n  defaultValue?: string;\n  disabled?: boolean;\n  name?: string;\n  onValueChange?: (value: string) => void;\n  orientation?: \"horizontal\" | \"vertical\";\n  required?: boolean;\n  value?: string;\n}\n\nfunction RadioGroup({\n  children,\n  className,\n  defaultValue,\n  disabled,\n  name,\n  onValueChange,\n  orientation = \"vertical\",\n  required,\n  value,\n  ...props\n}: RadioGroupProps) {\n  const generatedName = React.useId();\n  const [uncontrolledValue, setUncontrolledValue] = React.useState(defaultValue);\n  const currentValue = value ?? uncontrolledValue;\n\n  const updateValue = React.useCallback(\n    (nextValue: string) => {\n      if (value === undefined) {\n        setUncontrolledValue(nextValue);\n      }\n\n      onValueChange?.(nextValue);\n    },\n    [onValueChange, value],\n  );\n\n  const context = React.useMemo(\n    () => ({\n      disabled,\n      name: name ?? generatedName,\n      onValueChange: updateValue,\n      required,\n      value: currentValue,\n    }),\n    [currentValue, disabled, generatedName, name, required, updateValue],\n  );\n\n  return (\n    <RadioGroupContext.Provider value={context}>\n      <div\n        role=\"radiogroup\"\n        aria-orientation={orientation}\n        data-slot=\"radio-group\"\n        data-orientation={orientation}\n        className={cn(\n          \"flex gap-3\",\n          orientation === \"horizontal\" ? \"flex-row items-center\" : \"flex-col items-start\",\n          className,\n        )}\n        {...props}\n      >\n        {children}\n      </div>\n    </RadioGroupContext.Provider>\n  );\n}\n\ninterface RadioGroupItemProps\n  extends Omit<\n    React.ComponentProps<\"input\">,\n    \"checked\" | \"defaultChecked\" | \"name\" | \"onChange\" | \"size\" | \"type\"\n  > {\n  onChange?: React.ChangeEventHandler<HTMLInputElement>;\n  value: string;\n}\n\nfunction RadioGroupItem({\n  className,\n  disabled,\n  onChange,\n  value,\n  ...props\n}: RadioGroupItemProps) {\n  const context = React.useContext(RadioGroupContext);\n\n  if (!context) {\n    throw new Error(\"RadioGroupItem must be used inside RadioGroup.\");\n  }\n\n  const isDisabled = disabled || context.disabled;\n  const isChecked = context.value === value;\n\n  return (\n    <span\n      data-slot=\"radio-group-item-root\"\n      className={cn(\"relative inline-flex size-5 shrink-0 align-middle\", className)}\n    >\n      <input\n        type=\"radio\"\n        data-slot=\"radio-group-item\"\n        className=\"peer absolute inset-0 z-10 m-0 size-full cursor-pointer appearance-none rounded-full opacity-0 disabled:cursor-not-allowed\"\n        name={context.name}\n        value={value}\n        checked={isChecked}\n        disabled={isDisabled}\n        required={context.required}\n        onChange={(event) => {\n          onChange?.(event);\n\n          if (event.currentTarget.checked) {\n            context.onValueChange(value);\n          }\n        }}\n        {...props}\n      />\n      <span\n        aria-hidden=\"true\"\n        className=\"flex size-5 items-center justify-center rounded-full border border-[color:var(--neu-edge)] bg-[var(--neu-surface)] [box-shadow:var(--neu-shadow-inset)] transition-[box-shadow] duration-[var(--neu-duration)] motion-reduce:transition-none peer-disabled:opacity-50 peer-disabled:shadow-none peer-disabled:border-[color:var(--muted-foreground)]/40 peer-focus-visible:ring-2 peer-focus-visible:ring-[var(--ring)] peer-focus-visible:ring-offset-2 peer-focus-visible:ring-offset-[var(--background)] peer-checked:[&>span]:opacity-100\"\n      >\n        <span className=\"size-2 rounded-full bg-[var(--neu-accent-ink)] opacity-0 transition-opacity duration-[var(--neu-duration)] motion-reduce:transition-none\" />\n      </span>\n    </span>\n  );\n}\n\nexport { RadioGroup, RadioGroupItem };\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}