From 7f3c0c07df1a3b4dc20f1ffe53204c1a756ad08c Mon Sep 17 00:00:00 2001 From: Mathias Polligkeit Date: Mon, 20 Nov 2023 23:10:36 +0900 Subject: [PATCH] add input component --- lib/doggo.ex | 277 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 277 insertions(+) diff --git a/lib/doggo.ex b/lib/doggo.ex index fd3ea974..793b9514 100644 --- a/lib/doggo.ex +++ b/lib/doggo.ex @@ -5,6 +5,7 @@ defmodule Doggo do use Phoenix.Component + alias Phoenix.HTML.Form alias Phoenix.LiveView.JS ## Components @@ -284,6 +285,282 @@ defmodule Doggo do """ end + @doc """ + Renders a form field including input, label, errors, and description. + + A `Phoenix.HTML.FormField` may be passed as argument, + which is used to retrieve the input name, id, and values. + Otherwise all attributes may be passed explicitly. + + ## Types + + In addition to all HTML input types, the following type values are also + supported: + + - `"select"` - For ` + + <%= @label %> + + <.field_errors for={@id} errors={@errors} /> + <.field_description for={@id} description={@description} /> + + """ + end + + def input(%{type: "select"} = assigns) do + ~H""" +
+ <.label for={@id} required={@validations[:required] || false}> + <%= @label %> + +
+ +
+ <.field_errors for={@id} errors={@errors} /> + <.field_description for={@id} description={@description} /> +
+ """ + end + + def input(%{type: "textarea"} = assigns) do + ~H""" +
+ <.label for={@id} required={@validations[:required] || false}> + <%= @label %> + + + <.field_errors for={@id} errors={@errors} /> + <.field_description for={@id} description={@description} /> +
+ """ + end + + def input(%{type: "hidden", value: values} = assigns) when is_list(values) do + ~H""" + "[]"} value={value} /> + """ + end + + def input(%{type: "hidden"} = assigns) do + ~H""" + + """ + end + + def input(assigns) do + ~H""" +
+ <.label for={@id} required={@validations[:required] || false}> + <%= @label %> + + + <.field_errors for={@id} errors={@errors} /> + <.field_description for={@id} description={@description} /> +
+ """ + end + + defp input_aria_describedby(_, [], []), do: nil + defp input_aria_describedby(id, _, []), do: field_errors_id(id) + defp input_aria_describedby(id, [], _), do: field_description_id(id) + + defp input_aria_describedby(id, _, _), + do: "#{field_errors_id(id)} #{field_description_id(id)}" + + defp field_error_class([]), do: nil + defp field_error_class(_), do: "has-errors" + + @doc """ + Renders the label for an input. + """ + + attr :for, :string, default: nil, doc: "The ID of the input." + + attr :required, :boolean, + default: false, + doc: "If set to `true`, a 'required' mark is rendered." + + attr :rest, :global + slot :inner_block, required: true + + def label(assigns) do + ~H""" + + """ + end + + defp required_mark(assigns) do + ~H""" + + """ + end + + @doc """ + Renders the errors for an input. + """ + attr :for, :string, required: true, doc: "The ID of the input." + attr :errors, :list, required: true, doc: "A list of errors as strings." + + def field_errors(assigns) do + ~H""" + + """ + end + + defp field_errors_id(id) when is_binary(id), do: "#{id}_errors" + + @doc """ + Renders the description of an input. + """ + attr :for, :string, required: true, doc: "The ID of the input." + attr :description, :any + + def field_description(assigns) do + ~H""" +
+
  • <%= render_slot(@description) %>
  • +
    + """ + end + + defp field_description_id(id) when is_binary(id), do: "#{id}_description" + + def translate_error({msg, opts}) do + Enum.reduce(opts, msg, fn {key, value}, acc -> + String.replace(acc, "%{#{key}}", fn _ -> to_string(value) end) + end) + end + + def translate_errors(errors, field) when is_list(errors) do + for {^field, {msg, opts}} <- errors, do: translate_error({msg, opts}) + end + @doc """ Renders a modal.