Skip to main content

priv/registry/radio_group.json

{
  "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"
  ]
}