defmodule BitstylesPhoenix.Component.Error do use BitstylesPhoenix.Component alias Phoenix.HTML.Form, as: PhxForm @moduledoc """ Component for showing UI errors. """ @doc """ Render errors from a Phoenix.HTML.Form. ## Attributes - `form` *(required)* - The form to render the input form. - `field` *(required)* - The name of the field for the input. - `class` - Extra classes to pass to the wrapping `ul` if there are mutliple errors. See `BitstylesPhoenix.Helper.classnames/1` for usage. - `error_class` - Extra classes to pass to the error component. See `BitstylesPhoenix.Helper.classnames/1` for usage. See also `BitstylesPhoenix.Component.Form`. Uses the `translate_errors` MFA from the config to translate field errors (e.g. with `gettext`). """ story( "A single error", """ iex> assigns = %{form: form_with_errors()} ...> render ~H\""" ...> <.ui_errors form={@form} field={:name} /> ...> \""" """, "6.0.0": """ \""" is too short \""" """, "5.0.1": """ \""" is too short \""" """, "4.3.0": """ \""" is too short \""" """, "3.0.0": """ \""" is too short \""" """ ) story( "Multiple errors", """ iex> assigns = %{form: form_with_errors()} ...> render ~H\""" ...> <.ui_errors form={@form} field={:email} /> ...> \""" """, """ \""" \""" """ ) def ui_errors(assigns) do assigns.form.errors |> Keyword.get_values(assigns.field) |> case do [] -> ~H"" [error] -> assigns = assign(assigns, error: error) ~H""" <.ui_error error={@error} phx-feedback-for={PhxForm.input_name(assigns.form, assigns.field)} class={assigns[:error_class]} /> """ errors -> class = classnames(["u-padding-l3-left", assigns[:class]]) assigns = assign(assigns, class: class, errors: errors) ~H""" """ end end @doc """ Generates tag for custom errors. ## Attributes - `error` *(required)* - The error to render (expected to be a tuple with `{message :: String.t(), opts :: keyword()}`). - All other attributes are passed to the outer `span` tag. Uses the `translate_errors` MFA from the config to translate field errors (e.g. with `gettext`). The error will be rendered with the warning color, as specified in [bitstyles colors](https://bitcrowd.github.io/bitstyles/?path=/docs/utilities-fg--warning). """ story( "An error tag", """ iex> assigns = %{} ...> render ~H\""" ...> <.ui_error error={{"Foo error", []}} /> ...> \""" """, "6.0.0": """ \""" Foo error \""" """, "5.0.1": """ \""" Foo error \""" """, "4.3.0": """ \""" Foo error \""" """, "3.0.0": """ \""" Foo error \""" """ ) story( "An error tag extra options and classes", """ iex> assigns = %{error: {"Foo error", []}} ...> render ~H\""" ...> <.ui_error error={@error} phx-feedback-for="foo" class="bar" /> ...> \""" """, """ \""" Foo error \""" """ ) def ui_error(assigns) do extra = assigns_to_attributes(assigns, [:class, :error, :field, :form]) class = classnames(["u-fg-warning", assigns[:class]]) assigns = assign(assigns, class: class, extra: extra) ~H""" <%= translate_error(@error) %> """ end defp translate_error(error) do {mod, translate_fn, args} = Application.get_env( :bitstyles_phoenix, :translate_errors, {__MODULE__, :no_translation, []} ) apply(mod, translate_fn, args ++ [error]) end @doc false def no_translation({error, _}) do error end def no_translation(error), do: error end