Packages
pui
1.0.0-alpha.32
1.0.0-beta.18
1.0.0-beta.17
1.0.0-beta.16
1.0.0-beta.15
1.0.0-beta.14
1.0.0-beta.13
1.0.0-beta.12
1.0.0-beta.11
1.0.0-beta.10
1.0.0-beta.9
1.0.0-beta.8
1.0.0-beta.7
1.0.0-beta.6
1.0.0-beta.5
1.0.0-beta.4
1.0.0-beta.3
1.0.0-beta.1
1.0.0-alpha.32
1.0.0-alpha.31
1.0.0-alpha.30
1.0.0-alpha.29
1.0.0-alpha.28
1.0.0-alpha.27
1.0.0-alpha.26
1.0.0-alpha.25
1.0.0-alpha.24
1.0.0-alpha.23
1.0.0-alpha.22
1.0.0-alpha.21
1.0.0-alpha.19
1.0.0-alpha.18
1.0.0-alpha.17
1.0.0-alpha.16
1.0.0-alpha.15
1.0.0-alpha.14
1.0.0-alpha.13
1.0.0-alpha.12
1.0.0-alpha.11
A Phoenix LiveView UI toolkit
Current section
Files
Jump to
Current section
Files
lib/pui/components.ex
defmodule PUI.Components do
use Phoenix.Component
attr :min, :float, default: 0.0
attr :max, :float, default: 100.0
attr :value, :float, default: 0.0
attr :class, :string, default: ""
@doc """
"""
def progress(assigns) do
~H"""
<div
role="progressbar"
aria-valuenow={@value}
aria-valuemin={@min}
aria-valuemax={@max}
class={[
"bg-primary/20 relative h-2 w-full overflow-hidden rounded-full",
@class
]}
>
<div
style={"transform: translateX(-#{100 - (@value || 0)}%)"}
class={[
"bg-primary h-full w-full flex-1 transition-all"
]}
>
</div>
</div>
"""
end
attr :class, :string, default: ""
attr :variant, :string,
values: ["default", "secondary", "destructive", "outline"],
default: "default"
slot :inner_block
def badge(assigns) do
assigns =
case assigns[:variant] do
"default" ->
assigns
|> assign(
:variant_class,
"border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90"
)
"secondary" ->
assigns
|> assign(
:variant_class,
"border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90"
)
"destructive" ->
assigns
|> assign(
:variant_class,
"border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60"
)
"outline" ->
assigns
|> assign(
:variant_class,
"text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground"
)
end
~H"""
<span class={[
"inline-flex items-center justify-center rounded-full border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden",
@variant_class,
@class
]}>
{render_slot(@inner_block)}
</span>
"""
end
@doc """
Renders form field error messages.
Displays validation errors below form inputs. Renders nothing when `errors` is empty.
## Examples
<.field_error errors={["can't be blank"]} />
<.field_error errors={["must be at least 3 characters", "is invalid"]} />
<.field_error errors={[]} />
"""
attr :errors, :list, default: []
def field_error(assigns) do
~H"""
<p
:for={msg <- @errors}
class="mt-1.5 text-xs text-destructive"
>
{msg}
</p>
"""
end
@doc """
Translates a form error tuple into a human-readable string.
Error tuples from changesets have the form `{msg, opts}` where `msg` may contain
interpolation placeholders like `%{count}`.
## Examples
iex> PUI.Components.translate_error({"can't be blank", []})
"can't be blank"
iex> PUI.Components.translate_error({"should be at least %{count} character(s)", [count: 3]})
"should be at least 3 character(s)"
"""
def translate_error({msg, opts}) do
msg = translate_error_text(msg)
Enum.reduce(opts, msg, fn {key, value}, acc ->
String.replace(acc, "%{#{translate_error_text(key)}}", translate_error_text(value))
end)
end
defp translate_error_text(term) when is_binary(term), do: term
defp translate_error_text(term) when is_atom(term), do: Atom.to_string(term)
defp translate_error_text(term) when is_integer(term) or is_float(term), do: to_string(term)
defp translate_error_text(term) when is_list(term) do
if Enum.all?(term, &is_integer/1) do
List.to_string(term)
else
inspect(term)
end
end
defp translate_error_text(term), do: inspect(term)
end