defmodule PUI.Input do
@moduledoc """
Form input components including text inputs, checkboxes, radio buttons, switches, and textareas.
## Basic Text Input
<.input type="text" name="username" placeholder="Enter username" />
## Input with Label
<.input type="email" label="Email" placeholder="you@example.com" />
## With Phoenix Form
<.form for={@form} phx-change="validate">
<.input field={@form[:email]} type="email" label="Email" />
<.input field={@form[:password]} type="password" label="Password" />
## Input Types
Supports various HTML input types:
<.input type="text" placeholder="Text input" />
<.input type="email" placeholder="Email input" />
<.input type="password" placeholder="Password" />
<.input type="number" placeholder="Number" />
<.input type="file" />
<.input type="date" />
## Checkbox
<.checkbox id="terms" label="I agree to the terms" />
Or with custom label:
## Radio Button
## Switch/Toggle
<.switch id="notifications" label="Enable notifications" />
## Textarea
<.textarea label="Description" placeholder="Enter description..." />
## Disabled State
<.input type="text" disabled placeholder="Disabled input" />
<.checkbox id="terms" disabled label="Disabled checkbox" />
## Attributes (input/1)
| Attribute | Type | Default | Description |
|-----------|------|---------|-------------|
| `type` | `string` | `"text"` | Input type (text, email, password, etc.) |
| `label` | `string` | `nil` | Label text (creates wrapped label + input) |
| `field` | `FormField` | `nil` | Phoenix form field struct |
| `class` | `string` | `""` | Additional CSS classes |
| `id` | `any` | `nil` | Input ID |
## Global Attributes
All standard HTML input attributes are supported: `accept`, `autocomplete`,
`disabled`, `max`, `min`, `pattern`, `placeholder`, `readonly`, `required`, etc.
"""
use Phoenix.Component
attr :id, :any, default: nil
attr :class, :string, default: ""
attr :type, :string, default: "text"
attr :label, :string, default: nil
attr :field, Phoenix.HTML.FormField,
default: nil,
doc: "a form field struct retrieved from the form, for example: @form[:email]"
attr :rest, :global,
include: ~w(accept autocomplete capture cols disabled form list max maxlength min minlength
multiple pattern placeholder readonly required rows size step name value)
def input(%{label: label} = assigns) when label not in ["", nil] do
assigns = map_field(assigns)
~H"""
<.label for={@id}>{@label}
<.input id={@id} class={@class} type={@type} field={@field} {@rest} />
"""
end
def input(assigns) do
assigns = map_field(assigns)
~H"""
"""
end
attr :class, :string, default: ""
attr :rest, :global, include: ~w(for)
slot :inner_block
def label(assigns) do
~H"""
"""
end
attr :id, :any, default: nil
attr :label, :string, default: nil
attr :class, :string, default: nil
attr :field, Phoenix.HTML.FormField,
default: nil,
doc: "a form field struct retrieved from the form, for example: @form[:email]"
attr :rest, :global,
include: ~w(accept autocomplete capture cols disabled form list max maxlength min minlength
multiple pattern placeholder readonly required rows size step checked name value)
slot :inner_block
def checkbox(%{label: label} = assigns) when label != nil do
~H"""
"""
end
def checkbox(assigns) do
assigns = map_field(assigns)
~H"""
"""
end
attr :id, :any, default: nil
attr :rest, :global, include: ~w(checked name value)
attr :class, :string, default: ""
attr :field, Phoenix.HTML.FormField,
default: nil,
doc: "a form field struct retrieved from the form, for example: @form[:email]"
def radio(assigns) do
assigns = map_field(assigns)
~H"""
"""
end
attr :id, :any, default: nil
attr :class, :string, default: ""
attr :label, :string, default: nil
attr :field, Phoenix.HTML.FormField,
default: nil,
doc: "a form field struct retrieved from the form, for example: @form[:email]"
attr :rest, :global,
include: ~w(accept capture cols disabled form list max maxlength min minlength
multiple pattern placeholder readonly required rows size step name value)
def switch(%{label: label} = assigns) when label != nil do
assigns = map_field(assigns)
~H"""
"""
end
def switch(assigns) do
assigns = map_field(assigns)
~H"""
"""
end
@doc """
"""
attr :id, :any, default: nil
attr :class, :string, default: ""
attr :label, :string, default: nil
attr :field, Phoenix.HTML.FormField,
default: nil,
doc: "a form field struct retrieved from the form, for example: @form[:email]"
attr :rest, :global,
include: ~w(accept capture cols disabled form list max maxlength min minlength
multiple pattern placeholder readonly required rows size step name value)
def textarea(%{label: label} = assigns) when label not in ["", nil] do
assigns = map_field(assigns)
~H"""
<.label for={@id}>{@label}
<.textarea id={@id} class={@class} field={@field} {@rest} />
"""
end
def textarea(assigns) do
assigns =
map_field(assigns)
~H"""
"""
end
def map_field(%{field: %Phoenix.HTML.FormField{} = field} = assigns) do
rest =
assigns
|> Map.get(:rest, %{})
|> Map.put(:name, field.name)
|> then(fn rest ->
type = Map.get(rest, :type, "text")
rest |> Map.put(:value, Phoenix.HTML.Form.normalize_value(type, field.value))
end)
assigns
|> assign(:id, assigns.id || field.id)
|> assign(:field, nil)
|> assign(:rest, rest)
end
def map_field(assigns) do
assigns
end
def generate_id(prefix \\ "input"), do: "#{prefix}_#{System.unique_integer([:positive])}"
end