{
"files": [
{
"content": "defmodule Shadix.Components.RadioGroup do\n @moduledoc \"\"\"\n Radio group component translated from shadcn/ui (new-york-v4).\n\n Two function-components:\n\n * `radio_group/1` — a presentational container (`role=\"radiogroup\"`,\n `data-slot=\"radio-group\"`) that lays out the items in a grid. It is NOT\n field-aware; it just renders its `inner_block`.\n\n * `radio_group_item/1` — a field-aware native `<input type=\"radio\">`. Each\n item shares the field's `name` (so the browser groups them) but renders a\n unique `id`, and is `checked` when the field's current value matches the\n item's `value`. The selected dot is drawn with CSS only (a `before:`\n pseudo-element shown via the `checked:` variant), no JavaScript.\n\n Radios are grouped, so an individual item does not render its own error\n message; surface validation alongside the group/label as appropriate. Each\n item still reflects the field's invalid state via `aria-invalid` so screen\n readers and the destructive styling pick it up.\n \"\"\"\n use Phoenix.Component\n\n import Shadix.Cn\n import Shadix.Form\n\n @container_base \"grid gap-3\"\n\n @item_base \"peer relative flex aspect-square size-4 shrink-0 appearance-none items-center justify-center rounded-full border border-input bg-transparent text-primary shadow-xs transition-[color,box-shadow] outline-none before:size-2 before:rounded-full before:bg-primary before:opacity-0 before:transition-opacity before:content-[''] checked:before:opacity-100 focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:bg-input/30 dark:aria-invalid:ring-destructive/40\"\n\n attr(:class, :string, default: nil)\n attr(:rest, :global)\n slot(:inner_block, required: true)\n\n def radio_group(assigns) do\n assigns = assign(assigns, :computed_class, cn([@container_base, assigns.class]))\n\n ~H\"\"\"\n <div role=\"radiogroup\" data-slot=\"radio-group\" class={@computed_class} {@rest}>\n {render_slot(@inner_block)}\n </div>\n \"\"\"\n end\n\n attr(:field, Phoenix.HTML.FormField, required: true)\n attr(:value, :string, required: true)\n attr(:class, :string, default: nil)\n attr(:rest, :global, include: ~w(disabled required))\n\n def radio_group_item(assigns) do\n %{name: name, value: value, errors: errors} = field_attrs(assigns.field)\n\n assigns =\n assigns\n |> assign(name: name, field_value: value, errors: errors)\n |> assign(:computed_class, cn([@item_base, assigns.class]))\n\n ~H\"\"\"\n <input\n type=\"radio\"\n id={\"#{@name}_#{@value}\"}\n name={@name}\n value={@value}\n checked={to_string(@field_value) == @value}\n aria-invalid={(@errors != [] && \"true\") || nil}\n data-slot=\"radio-group-item\"\n class={@computed_class}\n {@rest}\n />\n \"\"\"\n end\nend\n",
"path": "radio_group.ex"
}
],
"hooks": [],
"name": "radio_group",
"npm_deps": [],
"registry_deps": [
"cn",
"form"
]
}