defmodule Phoenix.UI.Components.Chip do
@moduledoc """
Provides chip component.
"""
import Phoenix.UI.Components.{Avatar, Heroicon}
use Phoenix.UI, :component
@default_avatar_size 2
@default_delete_icon_name "x-circle"
@default_icon_color "inherit"
attr(:avatar, :list)
attr(:color, :string, default: "slate", values: Theme.colors())
attr(:delete_icon, :list)
attr(:element, :string, default: "div")
attr(:extend_class, :string)
attr(:icon, :list)
attr(:label, :string)
attr(:rest, :global)
attr(:size, :string, default: "md", values: ["sm", "md"])
attr(:variant, :string, default: "filled", values: ["filled", "outlined"])
@doc """
Renders chip component.
## Examples
```
<.chip label="keto"/>
```
"""
@spec chip(Socket.assigns()) :: Rendered.t()
def chip(assigns) do
assigns =
assigns
|> assign_class(~w(
inline-flex items-center rounded-full text-sm
font-semibold transition-all ease-in-out duration-200
#{classes(:clickable, assigns)}
#{classes(:size, assigns)}
#{classes(:variant, assigns)}
))
|> build_avatar_attrs()
|> build_icon_attrs()
|> build_delete_icon_attrs()
~H"""
<.dynamic_tag class={@class} name={@element} {@rest}>
<%= if assigns[:avatar] do %>
<.avatar {@avatar_attrs} />
<% end %>
<%= if !assigns[:avatar] && assigns[:icon] do %>
<.heroicon {@icon_attrs} />
<% end %>
<%= @label %>
<%= if assigns[:delete_icon] do %>
<div class="ml-1 cursor-pointer text-slate-600 hover:text-slate-500">
<.heroicon {@delete_icon_attrs} />
</div>
<% end %>
</.dynamic_tag>
"""
end
### Avatar Attrs ##########################
defp build_avatar_attrs(%{avatar: avatar} = assigns) do
extend_class = build_class(~w(
mr-1
#{Map.get(assigns, :extend_class)}
))
attrs =
avatar
|> assigns_to_attributes()
|> Keyword.put(:extend_class, extend_class)
|> Keyword.put_new(:size, @default_avatar_size)
assign(assigns, :avatar_attrs, attrs)
end
defp build_avatar_attrs(assigns), do: assigns
### Icon Attrs ##########################
defp build_icon_attrs(%{icon: icon} = assigns) do
extend_class = build_class(~w(
mr-1
#{Map.get(assigns, :extend_class)}
))
attrs =
icon
|> assigns_to_attributes()
|> Keyword.put_new(:color, @default_icon_color)
|> Keyword.put(:extend_class, extend_class)
assign(assigns, :icon_attrs, attrs)
end
defp build_icon_attrs(assigns), do: assigns
### Delete Icon Attrs ##########################
defp build_delete_icon_attrs(%{delete_icon: icon} = assigns) do
attrs =
icon
|> assigns_to_attributes()
|> Keyword.put_new(:color, @default_icon_color)
|> Keyword.put_new(:name, @default_delete_icon_name)
assign(assigns, :delete_icon_attrs, attrs)
end
defp build_delete_icon_attrs(assigns), do: assigns
### CSS Classes ##########################
# Clickable
defp classes(:clickable, %{color: color, variant: "filled"} = assigns) do
classes = "hover:bg-#{color}-200 dark:hover:bg-#{color}-200 cursor-pointer"
case assigns do
%{element: el} when el in ["a", "link", "live_patch", "live_redirect"] -> classes
%{on_click: _} -> classes
_assigns -> nil
end
end
defp classes(:clickable, %{color: color, variant: "outlined"} = assigns) do
classes = "hover:bg-#{color}-200/50 dark:hover:bg-#{color}-200/25 cursor-pointer"
case assigns do
%{element: el} when el in ["a", "link", "live_patch", "live_redirect"] -> classes
%{on_click: _} -> classes
_assigns -> nil
end
end
# Size
defp classes(:size, %{size: "sm", avatar: _}), do: "pl-0 pr-1.5"
defp classes(:size, %{size: "sm", icon: _}), do: "py-0.5 pl-1.5 pr-1"
defp classes(:size, %{size: "sm"}), do: "py-0.5 px-1.5"
defp classes(:size, %{size: "md", avatar: _, delete_icon: _}), do: "pl-0 pr-1"
defp classes(:size, %{size: "md", avatar: _}), do: "pl-0 pr-3"
defp classes(:size, %{size: "md", icon: _, delete_icon: _}), do: "pl-1 py-1 pr-1"
defp classes(:size, %{size: "md", icon: _}), do: "pl-1 py-1 pr-3"
defp classes(:size, %{size: "md", delete_icon: _}), do: "py-1 pl-3 pr-1"
defp classes(:size, %{size: "md"}), do: "py-1 px-3"
# Variant
defp classes(:variant, %{color: color, variant: "filled"}) do
"bg-#{color}-300 text-#{color}-900 dark:bg-#{color}-400"
end
defp classes(:variant, %{color: color, variant: "outlined"}) do
"border border-#{color}-600 text-#{color}-600 dark:border-#{color}-300 dark:text-#{color}-300"
end
defp classes(_rule_group, _assigns), do: nil
end