defmodule RiverConnectWeb.Components.UI.ToggleGroup do
@moduledoc false
use RiverConnectWeb.Components.UI, :component
@doc """
A set of two-state buttons that can be toggled on or off.
## Example:
<.toggle_group name="style" type="single" value="bold">
<.toggle_group_item value="bold" builder={builder} aria-label="Toggle bold">
<.icon name="hero-bold" class="h-4 w-4" />
<.toggle_group_item value="italic" builder={builder} aria-label="Toggle italic">
<.icon name="hero-italic" class="h-4 w-4" />
<.toggle_group_item value="underline" builder={builder} aria-label="Toggle underline">
<.icon name="hero-underline" class="h-4 w-4" />
"""
attr :name, :string, default: nil
attr :multiple, :any, values: [true, false, "true", "false"], default: false
attr :field, Phoenix.HTML.FormField,
doc: "a form field struct retrieved from the form, for example: @form[:email]"
attr :"default-value", :any, values: [true, false, "true", "false"]
attr :value, :string,
default: nil,
doc:
"The value of the toggle group. It's a single value for single type and a list of values for multiple type."
attr :disabled, :boolean, default: false
attr :class, :string, default: nil
attr :variant, :string, default: "default"
attr :size, :string, default: "default"
attr :rest, :global
slot :inner_block
def toggle_group(assigns) do
assigns = prepare_assign(assigns)
assigns =
assign_new(assigns, :checked, fn ->
Phoenix.HTML.Form.normalize_value("checkbox", assigns.multiple)
end)
ensure_valid_value_type!(assigns)
~H"""
{render_slot(@inner_block, assigns)}
"""
end
defp ensure_valid_value_type!(%{value: value, multiple: multiple} = _assigns) do
cond do
multiple and not is_list(value) ->
raise ArgumentError, "The value of the toggle group must be a list for multiple type."
not multiple and not (is_nil(value) or is_binary(value)) ->
raise ArgumentError,
"The value of the toggle group must be a single value for single type."
true ->
nil
end
end
attr :class, :string, default: nil
attr :disabled, :boolean, default: false
attr :value, :string, default: nil
attr :builder, :map, required: true, doc: "The builder context of toggle group."
attr :rest, :global
slot :inner_block
def toggle_group_item(%{builder: %{multiple: true}} = assigns) do
assigns =
assigns
|> assign(:variant_class, variant(assigns.builder))
|> assign(:checked, assigns.value in assigns.builder.value)
~H"""
"""
end
# single type
def toggle_group_item(assigns) do
assigns =
assigns
|> assign(:variant_class, variant(assigns.builder))
|> assign(:checked, assigns.value == assigns.builder.value)
~H"""
"""
end
@variants %{
variant: %{
"default" => "bg-transparent",
"outline" =>
"border border-input bg-transparent hover:bg-accent hover:text-accent-foreground"
},
size: %{
"default" => "h-10 px-3",
"sm" => "h-9 px-2.5",
"lg" => "h-11 px-5"
}
}
@default_variants %{
variant: "default",
size: "default"
}
defp variant(props) do
variants = Map.take(props, ~w(variant size)a)
variants = Map.merge(@default_variants, variants)
Enum.map_join(variants, " ", fn {key, value} -> @variants[key][value] end)
end
end