Packages
petal_components
3.1.0
4.6.2
4.6.1
4.6.0
4.5.0
4.4.0
4.3.0
4.2.1
4.2.0
4.1.2
4.1.1
4.1.0
4.0.12
4.0.11
4.0.10
4.0.6
4.0.5
4.0.4
4.0.3
4.0.1
3.2.2
3.2.1
3.2.0
3.1.0
3.0.2
3.0.1
3.0.0
2.9.3
2.9.2
retired
2.9.1
retired
2.9.0
retired
2.8.4
2.8.3
2.8.2
2.8.1
2.8.0
2.7.4
2.7.3
2.7.2
2.7.1
2.7.0
2.6.1
2.6.0
2.5.2
2.5.1
2.5.0
2.4.3
2.4.2
2.4.1
2.4.0
2.3.0
2.2.1
2.2.0
2.1.2
2.1.1
2.1.0
2.0.6
2.0.5
2.0.4
2.0.3
2.0.2
2.0.1
2.0.0
1.9.3
1.9.2
1.9.1
1.9.0
1.8.0
1.7.1
1.7.0
1.6.2
1.6.1
1.6.0
1.5.5
1.5.4
1.5.3
1.5.2
1.5.1
1.5.0
1.4.9
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.0
1.2.14
1.2.13
1.2.12
1.2.11
1.2.10
1.2.9
1.2.8
1.2.7
1.2.6
1.2.5
1.2.4
1.2.3
1.2.2
1.2.1
1.2.0
1.1.6
1.1.5
1.1.4
1.1.3
1.1.2
1.1.1
1.1.0
1.0.8
1.0.7
1.0.6
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
0.19.10
0.19.9
0.19.8
0.19.7
0.19.6
0.19.5
0.19.4
0.19.3
0.19.2
0.19.1
0.19.0
0.18.5
0.18.4
0.18.3
0.18.2
0.18.1
0.18.0
0.17.7
0.17.6
0.17.5
0.17.4
0.17.3
0.17.2
0.17.1
0.17.0
0.16.0
0.15.0
0.14.1
0.14.0
0.13.7
0.13.6
0.13.5
0.13.4
0.13.3
0.13.2
0.13.1
0.13.0
0.12.0
0.11.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.8
0.10.7
0.10.6
0.10.5
0.10.4
0.10.3
0.10.2
0.10.1
0.10.0
0.9.3
0.9.2
0.9.1
0.9.0
0.8.0
0.7.0
0.6.1
0.6.0
0.5.1
0.5.0
0.4.0
0.3.2
0.3.1
0.3.0
0.2.2
0.2.1
0.2.0
0.1.0
Shadcn-style Phoenix LiveView components that AI assistants can actually use. Pair with the MCP server so AI coding tools can inspect the real component API.
Current section
Files
Jump to
Current section
Files
lib/petal_components/button.ex
defmodule PetalComponents.Button do
use Phoenix.Component
alias PetalComponents.Loading
alias PetalComponents.Link
import PetalComponents.Icon
attr :size, :string, default: "md", values: ["xs", "sm", "md", "lg", "xl"], doc: "button sizes"
attr :radius, :string,
default: "md",
values: ["none", "sm", "md", "lg", "xl", "full"],
doc: "button border radius"
attr :variant, :string,
default: "solid",
values: ["solid", "light", "outline", "inverted", "shadow", "ghost"],
doc: "button variant"
attr :color, :string,
default: "primary",
values: [
"primary",
"secondary",
"info",
"success",
"warning",
"danger",
"gray",
"pure_white",
"white",
"light",
"dark"
],
doc: "button color"
attr :to, :string, default: nil, doc: "link path"
attr :loading, :boolean, default: false, doc: "indicates a loading state"
attr :disabled, :boolean, default: false, doc: "indicates a disabled state"
attr :icon, :any, default: nil, doc: "name of a Heroicon at the front of the button"
attr :with_icon, :boolean, default: false, doc: "adds some icon base classes"
attr :link_type, :string,
default: "button",
values: ["a", "live_patch", "live_redirect", "button"]
attr :class, :any, default: nil, doc: "CSS class"
attr :label, :string, default: nil, doc: "labels your button"
attr :rest, :global,
include: ~w(method download hreflang ping referrerpolicy rel target type value name form)
slot :inner_block, required: false
def button(assigns) do
assigns =
assigns
|> assign(:classes, button_classes(assigns))
~H"""
<Link.a to={@to} link_type={@link_type} class={@classes} disabled={@disabled} {@rest}>
<%= if @loading do %>
<Loading.spinner show={true} size_class={"pc-button__spinner-icon--#{@size}"} />
<% else %>
<%= if @icon do %>
<.icon name={@icon} class={"pc-button__spinner-icon--#{@size}"} />
<% end %>
<% end %>
{render_slot(@inner_block) || @label}
</Link.a>
"""
end
attr :size, :string, default: "sm", values: ["xs", "sm", "md", "lg", "xl"]
attr :color, :string,
default: "gray",
values: [
"primary",
"secondary",
"info",
"success",
"warning",
"danger",
"gray"
]
attr :radius, :string,
default: "full",
values: ["none", "sm", "md", "lg", "xl", "full"],
doc: "button radius"
attr :to, :string, default: nil, doc: "link path"
attr :loading, :boolean, default: false, doc: "indicates a loading state"
attr :disabled, :boolean, default: false, doc: "indicates a disabled state"
attr :with_icon, :boolean, default: false, doc: "adds some icon base classes"
attr :link_type, :string,
default: "button",
values: ["a", "live_patch", "live_redirect", "button"]
attr :class, :any, default: nil, doc: "CSS class"
attr :tooltip, :string, default: nil, doc: "tooltip text"
attr :rest, :global,
include: ~w(method download hreflang ping referrerpolicy rel target type value name form)
slot :inner_block, required: false
def icon_button(assigns) do
~H"""
<Link.a
to={@to}
link_type={@link_type}
class={[
"pc-icon-button",
"pc-icon-button--radius-#{@radius}",
@disabled && "pc-button--disabled",
"pc-icon-button-bg--#{@color}",
"pc-icon-button--#{@color}",
"pc-icon-button--#{@size}",
@class
]}
disabled={@disabled}
{@rest}
>
<span class={[
"pc-icon-button__inner",
@tooltip && "group/pc-icon-button pc-icon-button__inner--tooltip"
]}>
<%= if @loading do %>
<Loading.spinner show={true} size_class={"pc-icon-button-spinner--#{@size}"} />
<% else %>
{render_slot(@inner_block)}
<div :if={@tooltip} role="tooltip" class="pc-icon-button__tooltip">
<span class="pc-icon-button__tooltip__text">
{@tooltip}
</span>
<div class="pc-icon-button__tooltip__arrow"></div>
</div>
<% end %>
</span>
</Link.a>
"""
end
defp button_classes(assigns) do
size = assigns[:size] || "md"
radius = assigns[:radius] || "md"
variant = assigns[:variant] || "solid"
color = assigns[:color] || "primary"
loading = assigns[:loading] || false
disabled = assigns[:disabled] || false
with_icon = assigns[:with_icon] || assigns[:icon] || false
user_classes = assigns[:class] || ""
color_class = "pc-button--#{String.replace(color, "_", "-")}"
variant_suffix = if variant == "solid", do: "", else: "-#{variant}"
[
"pc-button",
"#{color_class}#{variant_suffix}",
"pc-button--#{size}",
"pc-button--radius-#{radius}",
user_classes,
loading && "pc-button--loading",
disabled && "pc-button--disabled",
with_icon && "pc-button--with-icon"
]
end
end