defmodule PetalComponents.ButtonGroup do use Phoenix.Component alias PetalComponents.Helpers @doc """ Renders a button group. Group buttons are configured by defining multiple `:button` slots. Note: Phoenix LiveView >= 0.20.17 is required to prevent arbitrary attributes like phx-* given to `:button` slots emitting development warnings. ## Examples ### Buttons <.button_group aria_label="My actions" size="md"> <:button phx-click="beep" phx-value-boop="bop">Action 1 <:button phx-click="boop" phx-value-bop="beep">Action 2 <:button label="Action 3" phx-click="bop" phx-value-beep="boop" disabled={@action_disabled?} /> ### Links <.button_group aria_label="My links" size="md"> <:button kind="link" patch={~p"/path-one"}>Link 1 <:button kind="link" patch={~p"/path-two"}>Link 2 <:button label="Link 3" kind="link" navigate={~p"/other"} /> ### Custom Styles <.button_group aria_label="Custom styled buttons" button_bg_class="bg-blue-500 hover:bg-blue-600 dark:bg-blue-700 dark:hover:bg-blue-800 text-white" button_border_class="border border-blue-300 dark:border-blue-600" > <:button>Custom Button 1 <:button>Custom Button 2 """ attr :id, :string, default: nil attr :aria_label, :string, required: true, doc: "the ARIA label for the button group" attr :size, :string, default: "md", values: ["xs", "sm", "md", "lg", "xl"] attr :container_class, :string, default: "pc-button-group", doc: "class to apply to the group container" attr :font_weight_class, :string, default: "font-medium", doc: "the font weight class to apply to all buttons - defaults to font-medium" # New attributes for customizing button styles attr :button_bg_class, :string, default: nil, doc: "class to customize the button background colors" attr :button_border_class, :string, default: nil, doc: "class to customize the button border styles" # We mark validate_attrs false so passing phx-click etc. does not emit warnings slot :button, required: true, validate_attrs: false do attr :class, :string, doc: "classes in addition to those already configured" attr :label, :string, doc: "a button label, rendered if you don't provide an inner block" attr :kind, :string, values: ["button", "link"], doc: "determines whether we render a button or a <.link />" attr :disabled, :boolean, doc: "disables the button - will turn an into a """ end # Anchor tags can't be disabled - renders a disabled button defp group_button(%{kind: "link", disabled: true} = assigns) do assigns = update_in(assigns.rest, &Map.drop(&1, [:"phx-click"])) ~H""" """ end defp group_button(%{kind: "link"} = assigns) do ~H""" <.link class={[@class | group_btn_class(assigns)]} {@rest}> <%= render_slot(@inner_block) %> """ end defp group_btn_class(assigns) do base_classes = [ "pc-button-group__button", size_class(assigns.size), font_weight_class(assigns.font_weight_class), "pc-button-group__button--default-styles", background_class(nil), border_class(nil) ] custom_classes = [ background_class(assigns.button_bg_class), border_class(assigns.button_border_class) ] position_class = position_class(assigns.idx, assigns.last_idx) # Assemble classes in order: base, custom, position base_classes ++ custom_classes ++ [position_class] end defp position_class(idx, last_idx) do cond do idx == 0 and idx == last_idx -> "pc-button-group__button--rounded" idx == 0 -> "pc-button-group__button--rounded-r-none" idx == last_idx -> "pc-button-group__button--rounded-l-none" true -> "pc-button-group__button--rounded-none" end end defp size_class(size), do: "pc-button-group__button--#{size}" defp font_weight_class("font-normal"), do: "pc-button-group__button--font-normal" defp font_weight_class("font-medium"), do: "pc-button-group__button--font-medium" defp font_weight_class("font-semibold"), do: "pc-button-group__button--font-semibold" defp font_weight_class("font-bold"), do: "pc-button-group__button--font-bold" defp font_weight_class(custom_class), do: custom_class defp background_class(nil), do: "pc-button-group__button--bg-default" defp background_class(custom_class), do: custom_class defp border_class(nil), do: "pc-button-group__button--border-default" defp border_class(custom_class), do: custom_class end