defmodule Shino.UI.Input do
@moduledoc """
Provides input related components.
## About main attrs
All components in this module accept four main attrs:
* `:field` - a `Phoenix.HTML.FormField` struct
* `:id`
* `:name`
* `:value`
When a `:field` attr is passed, `:id`, `:name` and `:value` can be retrieved
from it. So, it's not necessary to specify them:
```heex
```
Otherwise `:name`, `:value` should be passed explicitly:
```heex
```
## About file uploads
For live file uploads, see `Phoenix.Component.live_file_input/1`.
## More information of inputs
See for more
information. Unsupported inputs are best written directly in your templates.
## Notes
Differents from other components, input components are using `focus:`, instead of
`focus-visible:`.
## References
* [shadcn/ui - Input](https://ui.shadcn.com/docs/components/input)
"""
use Shino.UI, :component
alias Shino.UI.Label
@doc """
Renders an input.
## Examples
```heex
<.input field={@form[:email]} type="email" placeholder="Enter your email" />
```
"""
attr :field, Phoenix.HTML.FormField
attr :id, :any, default: nil
attr :name, :any
attr :value, :any
attr :type, :string,
default: "text",
values:
~w(text email url password number range tel search color date time datetime-local month week file hidden)
attr :class, :string, default: nil
attr :rest, :global,
# credo:disable-for-next-line
# TODO: cleanup this list
include: ~w(accept autocomplete capture cols disabled form list max maxlength min minlength
multiple pattern placeholder readonly required rows size step)
def input(%{type: "hidden"} = assigns) do
~H"""
"""
end
def input(assigns) do
assigns = prepare_assigns(assigns)
~H"""
"""
end
@doc """
Renders a textarea.
## Examples
```heex
<.textarea field={@form[:body]} class="resize-none" rows="6" />
```
"""
attr :field, Phoenix.HTML.FormField
attr :id, :any, default: nil
attr :name, :string
attr :value, :string
attr :class, :string, default: nil
attr :rest, :global, include: ~w(rows)
def textarea(assigns) do
assigns = prepare_assigns(assigns)
~H"""
"""
end
@doc """
Renders a checkbox.
> In theory, this is this component should be implemented within the input
> component, but to avoid complicating the attrs of input component, an
> additional component was created.
## Notes
To make this component pretty by default, extra style is added. If you find
If you find that this component does not meet your needs, feel free to submit
a PR.
## Examples
```heex
<.checkbox field={@form[:remember_me]} label="Remember me" />
```
"""
attr :field, Phoenix.HTML.FormField
attr :id, :any, default: nil
attr :name, :any
attr :value, :any
attr :label, :string, default: nil
attr :checked, :boolean
attr :class, :string, default: nil
attr :rest, :global
def checkbox(assigns) do
assigns =
assigns
|> prepare_assigns()
|> assign_new(:checked, fn assigns ->
Phoenix.HTML.Form.normalize_value("checkbox", assigns[:value])
end)
~H"""
<%= @label %>
"""
end
@doc """
Renders a switch.
> This is a actually a checkbox with fancy style.
> Some people also call it toggle.
## Examples
```heex
<.switch field={@form[:force_update]} />
```
"""
attr :field, Phoenix.HTML.FormField
attr :id, :any, default: nil
attr :name, :any
attr :value, :any
attr :checked, :boolean
attr :class, :string, default: nil
attr :disabled, :boolean, default: false
attr :rest, :global
def switch(assigns) do
assigns =
assigns
|> prepare_assigns()
|> assign_new(:checked, fn assigns ->
Phoenix.HTML.Form.normalize_value("checkbox", assigns[:value])
end)
~H"""
"""
end
@doc """
Renders a select.
## Examples
```heex
```
For the detail of `:options` attr, read the doc of `Phoenix.HTML.Form.options_for_select/2`.
"""
attr :field, Phoenix.HTML.FormField
attr :id, :any, default: nil
attr :name, :string
attr :value, :string
attr :prompt, :string, default: nil
attr :options, :list, doc: "the options to pass to Phoenix.HTML.Form.options_for_select/2"
attr :multiple, :boolean, default: false
attr :class, :string, default: nil
attr :rest, :global
def select(assigns) do
assigns = prepare_assigns(assigns)
~H"""
"""
end
defp prepare_assigns(%{field: %Phoenix.HTML.FormField{} = field} = assigns) do
assigns
|> assign(field: nil, id: assigns.id || field.id)
|> assign_new(:name, fn assigns ->
if assigns[:multiple], do: field.name <> "[]", else: field.name
end)
|> assign_new(:value, fn -> field.value end)
end
defp prepare_assigns(assigns) do
assigns
end
end