defmodule PhiaUi.Components.IconButton do @moduledoc """ Icon-only button with a required accessible label and an optional CSS tooltip. Enforces `label` as a required attribute to ensure every icon-only button is accessible by default. The same string is used as `aria-label` on the button and as tooltip text shown on hover. ## Variants | Variant | Use case | |---------------|-----------------------------------| | `:ghost` | Default — toolbar / icon actions | | `:default` | Filled primary icon button | | `:destructive`| Dangerous icon action | | `:outline` | Bordered icon button | | `:secondary` | Lower-emphasis icon button | ## Sizes | Size | Dimensions | |------------|------------| | `:xs` | h-6 w-6 | | `:sm` | h-8 w-8 | | `:default` | h-9 w-9 | | `:lg` | h-11 w-11 | ## Example <.icon_button icon="trash-2" label="Delete" phx-click="delete" /> <.icon_button icon="settings" label="Settings" variant={:outline} size={:lg} /> <.icon_button icon="plus" label="Add item" shape={:circle} /> <.icon_button icon="x" label="Close" tooltip={false} /> """ use Phoenix.Component import PhiaUi.ClassMerger, only: [cn: 1] import PhiaUi.Components.Icon, only: [icon: 1] attr :icon, :string, required: true, doc: "Lucide icon name to render inside the button" attr :label, :string, required: true, doc: "Accessible label — used as aria-label and, when tooltip=true, as tooltip text" attr :variant, :atom, values: [:default, :destructive, :outline, :secondary, :ghost], default: :ghost, doc: "Visual style variant" attr :size, :atom, values: [:xs, :sm, :default, :lg], default: :default, doc: "Button and icon size" attr :shape, :atom, values: [:square, :circle], default: :square, doc: "Corner radius — :square uses rounded-md, :circle uses rounded-full" attr :tooltip, :boolean, default: true, doc: "Show a CSS-only tooltip on hover (uses group-hover, no JS hook required)" attr :disabled, :boolean, default: false attr :loading, :boolean, default: false attr :class, :string, default: nil attr :rest, :global @doc """ Renders an icon-only button with an accessible label. When `tooltip={true}` (the default), a CSS tooltip is shown above the button on hover using `group-hover:opacity-100`. No JS hook is required. When `loading={true}`, an animated spinner replaces the icon and `aria-busy="true"` is set on the button. """ def icon_button(assigns) do ~H"""