defmodule Shadix.Components.Slider do
@moduledoc """
Slider component adapted from shadcn/ui (new-york-v4) to a native
`<input type="range">`.
Field-aware: the current value is read from the bound `Phoenix.HTML.FormField`.
shadcn builds its slider from Radix markup (track + range + thumb); here the
same look is reconstructed on the native element with `appearance-none` plus
Tailwind arbitrary variants targeting the browser's slider track/thumb
pseudo-elements (`::-webkit-slider-runnable-track`, `::-webkit-slider-thumb`,
`::-moz-range-track`, `::-moz-range-thumb`). No JavaScript.
"""
use Phoenix.Component
import Shadix.Cn
import Shadix.Form
@base "w-full cursor-pointer appearance-none bg-transparent disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 focus-visible:outline-none " <>
"[&::-webkit-slider-runnable-track]:h-1.5 [&::-webkit-slider-runnable-track]:w-full [&::-webkit-slider-runnable-track]:rounded-full [&::-webkit-slider-runnable-track]:bg-muted " <>
"[&::-moz-range-track]:h-1.5 [&::-moz-range-track]:w-full [&::-moz-range-track]:rounded-full [&::-moz-range-track]:bg-muted " <>
"[&::-webkit-slider-thumb]:-mt-[5px] [&::-webkit-slider-thumb]:size-4 [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:border [&::-webkit-slider-thumb]:border-primary [&::-webkit-slider-thumb]:bg-background [&::-webkit-slider-thumb]:shadow-sm [&::-webkit-slider-thumb]:ring-ring/50 [&::-webkit-slider-thumb]:transition-[box-shadow] hover:[&::-webkit-slider-thumb]:ring-4 focus-visible:[&::-webkit-slider-thumb]:ring-4 " <>
"[&::-moz-range-thumb]:size-4 [&::-moz-range-thumb]:appearance-none [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border [&::-moz-range-thumb]:border-primary [&::-moz-range-thumb]:bg-background [&::-moz-range-thumb]:shadow-sm [&::-moz-range-thumb]:ring-ring/50 [&::-moz-range-thumb]:transition-[box-shadow] hover:[&::-moz-range-thumb]:ring-4 focus-visible:[&::-moz-range-thumb]:ring-4 " <>
"aria-invalid:[&::-webkit-slider-thumb]:border-destructive aria-invalid:[&::-moz-range-thumb]:border-destructive"
attr(:field, Phoenix.HTML.FormField, required: true)
attr(:min, :integer, default: 0)
attr(:max, :integer, default: 100)
attr(:step, :integer, default: 1)
attr(:class, :string, default: nil)
attr(:rest, :global, include: ~w(disabled required readonly autofocus))
def slider(assigns) do
%{id: id, name: name, value: value, errors: errors} = field_attrs(assigns.field)
assigns = assign(assigns, id: id, name: name, value: value, errors: errors)
assigns = assign(assigns, :computed_class, cn([@base, assigns.class]))
~H"""
<input
type="range"
data-slot="slider"
id={@id}
name={@name}
value={@value}
min={@min}
max={@max}
step={@step}
aria-invalid={@errors != [] && "true"}
aria-describedby={(@errors != [] && "#{@id}-error") || nil}
class={@computed_class}
{@rest}
/>
<p
:if={@errors != []}
id={"#{@id}-error"}
data-slot="form-message"
class="text-destructive text-sm mt-1"
>
{List.first(@errors)}
</p>
"""
end
end