Current section

Files

Jump to
moon lib moon components button.ex
Raw

lib/moon/components/button.ex

defmodule Moon.Components.Button do
@moduledoc false
use Moon.StatelessComponent
alias Moon.Icon
alias Moon.Components.Loader
prop(id, :string)
prop(href, :string)
# TODO, none variant was added so as not to break PreviewCodeButton component
# Deprecate Link and None (they are not in Figma)
prop(variant, :string,
values: ["primary", "secondary", "tertiary", "ghost", "none"],
default: "primary"
)
prop(size, :string, values: ["xs", "sm", "md", "lg", "xl"], default: "md")
prop(full_width, :boolean)
prop(progress, :boolean)
prop(oops, :boolean)
prop(success, :boolean)
prop(pulse, :boolean)
prop(disabled, :boolean)
prop(no_hover_bg, :boolean, default: false)
prop(type, :string, default: "button")
prop(to, :string)
prop(active_class_name, :string)
prop(active_style, :string)
prop(exact, :boolean)
prop(string, :boolean)
prop(is_active, :boolean)
prop(location, :string)
prop(style, :string)
prop(class, :css_class)
prop(form, :string)
prop(on_click, :event)
prop(value_name, :string)
prop(value, :any)
prop(values, :keyword, default: [])
prop(left_icon, :string)
prop(right_icon, :string)
prop(icon_only, :string)
prop(testid, :string)
prop(animation, :string, values: ~w(progress success error pulse))
slot(default)
slot(right_icon_slot)
slot(left_icon_slot)
slot(icon_only_slot)
prop(button_gap, :css_class, default: "gap-2")
def render(assigns) do
~F"""
<button
id={@id}
class={merge([
[
"flex justify-center items-center gap-2 relative overflow-hidden active:scale-90 transition-all font-semibold",
"text-goten bg-piccolo": @variant in ["primary"],
"border border-solid bg-transparent text-bulma border-trunks hover:border-bulma":
@variant in ["secondary"],
"bg-hit text-goten": @variant in ["tertiary"],
"bg-transparent text-trunks hover:text-bulma": @variant in ["ghost"],
"text-trunks hover:bg-hit-120 hover:text-piccolo": @variant in ["link"],
"text-moon-12 h-8 px-2": @size == "xs" && slot_assigned?(:default),
"text-moon-14 h-8 px-3": @size == "sm" && slot_assigned?(:default),
"text-moon-14 h-10 px-4": @size == "md" && slot_assigned?(:default),
"text-moon-16 h-12 px-5": @size == "lg" && slot_assigned?(:default),
"text-moon-16 h-14 px-6": @size == "xl" && slot_assigned?(:default),
"p-1": @size == "xs" && !slot_assigned?(:default),
"p-1": @size == "sm" && !slot_assigned?(:default),
"p-2": @size == "md" && !slot_assigned?(:default),
"p-3": @size == "lg" && !slot_assigned?(:default),
"p-4": @size == "xl" && !slot_assigned?(:default),
"rounded-moon-s-xs": @size == "xs",
"rounded-moon-s-sm": @size == "sm",
"rounded-moon-s-sm": @size == "md",
"rounded-moon-s-sm": @size == "lg",
"rounded-moon-s-md": @size == "xl",
"w-full bg-hit": @full_width && slot_assigned?(:right_icon_slot),
"opacity-60": @disabled,
"anim-pulse animate-[pulse2_1.5s_infinite]": @animation == "pulse",
"bg-chichi text-goten animate-[error_0.82s_cubic-bezier(0.36,0.07,0.19,0.97)_1_both] anim-error":
@animation == "error"
],
@class
])}
disabled={@disabled}
type={@type}
form={@form}
data-size={@size}
data-testid={@testid}
:on-click={@on_click}
:values={@values}
{...phx_val_tag(@value_name || (@value && "click_value") || nil, @value)}
>
<span
:if={@animation in ["success", "progress"]}
class="flex absolute top-1/2 left-1/2 translate-y-[-50%] translate-x-[-50%] content-center justify-center"
>
{#if @animation == "progress"}
<Loader color="currentColor" size="xs" />
{#elseif @animation == "success"}
<Icon name="generic_check_alternative" color="currentColor" class={icon_class(@size)} />
{/if}
</span>
<span class={
"flex justify-center items-center",
@button_gap,
"opacity-0": @animation in ["success", "progress"]
}>
{#if slot_assigned?(:icon_only_slot)}
<#slot {@icon_only_slot} />
{#elseif @icon_only != nil}
<Icon name={@icon_only} class={icon_class(@size)} :if={@icon_only} />
{#else}
{#if slot_assigned?(:left_icon_slot)}
<#slot {@left_icon_slot} />
{#else}
<Icon name={@left_icon} class={icon_class(@size)} :if={@left_icon} />
{/if}
<#slot />
{#if slot_assigned?(:right_icon_slot)}
<#slot {@right_icon_slot} />
{#else}
<Icon name={@right_icon} class={icon_class(@size)} :if={@right_icon} />
{/if}
{/if}
</span>
<span :if={!@no_hover_bg} class="block absolute inset-0 bg-transparent hover:bg-primary-hover" />
</button>
"""
end
defp phx_val_tag(nil, _), do: []
defp phx_val_tag(name, value) do
# credo:disable-for-next-line Credo.Check.Warning.UnsafeToAtom
key = String.to_atom("phx-value-#{name}")
[{key, value}]
end
defp icon_class("xs"), do: "h-4 w-4"
defp icon_class("sm"), do: "h-4 w-4"
defp icon_class("md"), do: "h-6 w-6"
defp icon_class("lg"), do: "h-6 w-6"
defp icon_class("xl"), do: "h-6 w-6"
end