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