lib/moon/design/form/radio/button.ex

defmodule Moon.Design.Form.Radio.Button do
  @moduledoc "Single component of the Radio, renders to a label"

  use Moon.StatelessComponent, slot: "option"

  alias Moon.Design.Form.Field.Label
  alias Moon.Design.Form.Radio.Indicator
  alias Surface.Components.Form.RadioButton

  import Phoenix.HTML.Form, only: [input_value: 2]

  @doc "Id to be given to the label tag"
  prop(id, :string)
  @doc "Data-testid attribute value"
  prop(testid, :string)
  @doc "Additional CSS classes for the label"
  prop(class, :css_class)
  @doc "Field name, surface-style"
  prop(field, :atom, from_context: {Surface.Components.Form.Field, :field})
  @doc "Form, surface-style"
  prop(form, :form, from_context: {Surface.Components.Form, :form})

  @doc "Making the radio selected, use it outside the form. In most cases is set by Radio component"
  prop(is_selected, :boolean, from_context: :is_selected)

  prop(on_click, :event, from_context: :on_click)
  prop(value, :string, from_context: :value)
  prop(disabled, :boolean, from_context: :disabled)

  @doc "Label to be shown when no default slot is given"
  prop(label, :string)
  @doc "Size of the label"
  prop(size, :string, values!: ~w(sm md lg), default: "md")
  @doc "Inner content - put label & <Indicator/> here"
  slot(default)

  def render(assigns) do
    ~F"""
    <Label
      {=@id}
      {=@testid}
      {=@value}
      {=@size}
      class={merge(["flex gap-2 p-0", ["opacity-60": @disabled], @class])}
      {=@on_click}
      attrs={role: "radio", "aria-checked": "#{is_selected(assigns)}"}
    >
      <RadioButton
        class="hidden"
        {=@value}
        opts={
          disabled: @disabled
        }
      />
      <#slot context_put={is_selected: @is_selected || is_selected(assigns)}>
        <Indicator is_selected={@is_selected || is_selected(assigns)} />
        {@label}
      </#slot>
    </Label>
    """
  end

  defp is_selected(%{value: value, form: form, field: field}) do
    "#{value}" == "#{input_value(form, field)}"
  end
end