# `Localize.Inputs.Number.Components`
[🔗](https://github.com/elixir-localize/localize_number_inputs/blob/v0.1.1/lib/localize/inputs/number/components.ex#L3)

HEEx components for locale-aware form input.

Today: `number_input/1`. More inputs (percentage, ratio,
dimension, …) will land here over time under the same
namespace.

## Setup

Add the JS hook in your `assets/js/app.js`:

    import Hooks from "localize_inputs"
    let liveSocket = new LiveSocket("/live", Socket, {
      hooks: { NumberInput: Hooks.NumberInput }
    })

Install AutoNumeric as a peer dep:

    npm install autonumeric

## Tolerance of invalid input

These components sit on the render path and never raise on
bad input — the page always renders. Specifically:

* **Unknown `:locale`** — falls back to `:en` locale data;
  if `:en` itself is unavailable (broken Localize install)
  falls back to an empty `%Localize.Inputs.Number.Symbols{}`
  so attribute reads still resolve to safe defaults.

* **Unknown `:category`** on `unit_input/1` — falls back
  to an empty `%Localize.Inputs.Number.Unit{}`. The picker
  renders no rows rather than 500ing the page.

* **Blank or non-numeric `value`** — formatted as `""` in
  the visible input; the hidden ISO carrier stays empty.
  The submit-side parser (`Localize.Inputs.Number.Parser.parse_number/2`)
  returns `{:ok, nil}` for blanks and `{:error, _}` for
  garbage, never raises.

* **Malformed `:min` / `:max` / `:decimals` bounds** —
  `Localize.Inputs.Number.Validator.validate_number/2`
  uses `Decimal.parse/1` with a `Decimal.new(0)` fallback,
  so a typo in a bound silently passes the bound check
  rather than crashing the validation pipeline. Returns
  `{:error, %ValidationError{}}` for real out-of-range
  values.

# `number_input`

Locale-aware plain-number input.

Renders an `<input type="text" inputmode="decimal">` wrapped
in a `<div>` that carries `data-` attributes the JS hook
reads (locale, separators, minus sign, min/max, decimals).
With AutoNumeric loaded the input live-formats as the user
types; without it, the server-side parser
(`Localize.Inputs.Number.Parser.parse_number/2`) accepts whatever
the user typed on submit.

The form value submits in the user's *locale-formatted* shape
— exactly what AutoNumeric was displaying. Parse it on the
server with `Localize.Inputs.Number.Parser.parse_number/2` (or
`Localize.Inputs.Number.Changeset.validate_number/3` for an
Ecto-backed flow). One wire shape regardless of whether the
JS hook is loaded — no canonical-vs-locale ambiguity.

### Arguments

* `assigns` — see the per-attribute documentation below.

### Attributes

* `:form` — the `Phoenix.HTML.Form` the field belongs to.

* `:field` — the form field as an atom.

* `:locale` — display locale. Defaults to
  `Localize.get_locale/0`.

* `:integer` — when `true`, accept integers only and emit
  `inputmode="numeric"`.

* `:min`, `:max` — value bounds.

* `:decimals` — maximum fractional digits.

* `:align` — `:left` (default), `:right`, or `:center`.

* `:placeholder` — placeholder text.

* `:js` — set to `false` to skip the `phx-hook` attribute.

* `:class`, `:input_class` — extra classes for the wrapper
  and the input.

### Returns

* A `Phoenix.LiveView.Rendered` struct containing the input
  markup.

### Examples

    <.number_input form={@form} field={:quantity} integer={true} min={1} max={999} />
    <.number_input form={@form} field={:rating} min={0} max={5} decimals={1} />

## Attributes

* `form` (`Phoenix.HTML.Form`) (required)
* `field` (`:atom`) (required)
* `value` (`:any`) - Defaults to `nil`.
* `locale` (`:string`) - Defaults to `nil`.
* `integer` (`:boolean`) - Defaults to `false`.
* `min` (`:any`) - Defaults to `nil`.
* `max` (`:any`) - Defaults to `nil`.
* `decimals` (`:integer`) - Defaults to `nil`.
* `align` (`:atom`) - Defaults to `:left`. Must be one of `:left`, `:right`, or `:center`.
* `placeholder` (`:string`) - Defaults to `nil`.
* `js` (`:boolean`) - Defaults to `true`.
* `class` (`:string`) - Defaults to `nil`.
* `input_class` (`:string`) - Defaults to `nil`.
* Global attributes are accepted. Supports all globals plus: `["disabled", "readonly", "required", "autofocus"]`.

# `unit_input`

Locale-aware number + unit-of-measure input.

Renders a number input paired with a searchable
`unit_picker/1` for a given measurement category
(`"length"`, `"volume"`, `"mass"`, …). The picker is
grouped into **Preferred** (units in the locale's
measurement system — metric, US, or UK) and **All units**
(every known unit in the category). Unit display names are
localized via `Localize.Unit.display_name/2`.

Submits as a nested map:

    params[field] = %{"amount" => "1.5", "unit" => "meter"}

Parse on the server with the locale you already have.

### Attributes

* `:form` — the `Phoenix.HTML.Form` the field belongs to.

* `:field` — the form field as an atom. The amount and unit
  sub-fields submit under `params[field][amount]` and
  `params[field][unit]`.

* `:category` — the unit category as a string (e.g.
  `"length"`). **Required.** See
  `Localize.Inputs.Number.Unit.known_categories/0`.

* `:default_unit` — the unit selected by default. If `nil`,
  the first preferred unit for the locale is selected.

* `:locale` — display locale. Defaults to
  `Localize.get_locale/0`.

* `:integer`, `:min`, `:max`, `:decimals`, `:align`,
  `:placeholder`, `:js`, `:class`, `:input_class` — passed
  through to the underlying `number_input/1`.

* `:include_prefixed` — when `true`, the All-units section
  includes SI-prefixed variants (e.g. `decimeter`). The
  default is `false` to keep the list manageable.

### Examples

    <.unit_input form={@form} field={:height} category="length" />

    <.unit_input
      form={@form}
      field={:weight}
      category="mass"
      default_unit="kilogram"
      min={0}
    />

## Attributes

* `form` (`Phoenix.HTML.Form`) (required)
* `field` (`:atom`) (required)
* `category` (`:string`) (required)
* `default_unit` (`:string`) - Defaults to `nil`.
* `locale` (`:string`) - Defaults to `nil`.
* `value` (`:any`) - Defaults to `nil`.
* `integer` (`:boolean`) - Defaults to `false`.
* `min` (`:any`) - Defaults to `nil`.
* `max` (`:any`) - Defaults to `nil`.
* `decimals` (`:integer`) - Defaults to `nil`.
* `align` (`:atom`) - Defaults to `:left`. Must be one of `:left`, `:right`, or `:center`.
* `placeholder` (`:string`) - Defaults to `nil`.
* `include_prefixed` (`:boolean`) - Defaults to `false`.
* `js` (`:boolean`) - Defaults to `true`.
* `class` (`:string`) - Defaults to `nil`.
* `input_class` (`:string`) - Defaults to `nil`.
* `picker_class` (`:string`) - Defaults to `nil`.
* Global attributes are accepted. Supports all globals plus: `["disabled", "readonly", "required", "autofocus"]`.

# `unit_picker`

Standalone locale-aware unit picker.

Searchable picker grouped into a **Preferred** section
(units in the locale's measurement system) and an
**All units** section (every known unit in the category).
Selecting a row updates a hidden input that the picker
serialises on form submission and emits a
`localize-inputs:unit-change` `CustomEvent` so any enclosing
`unit_input/1` can react.

### Attributes

* `:current` — the currently-selected unit name (string).
  **Required.**

* `:category` — the unit category. **Required.**

* `:locale` — display locale. Defaults to
  `Localize.get_locale/0`.

* `:form` + `:field` — when given, the hidden value input
  is named `Phoenix.HTML.Form.input_name(form, field)`.

* `:name` — explicit hidden-input name. Overrides
  `:form`/`:field`. Used by `unit_input/1` to inject a
  nested name like `height[unit]`.

* `:input_id` — explicit id for the hidden value input.

* `:include_prefixed` — when `true`, the All-units section
  includes SI-prefixed variants.

* `:variant` — `:auto` (default), `:dropdown`, or `:sheet`.

* `:id`, `:class`, `:button_class`, `:overlay_class`,
  `:row_class` — customisation hooks.

## Attributes

* `form` (`Phoenix.HTML.Form`) - Defaults to `nil`.
* `field` (`:atom`) - Defaults to `nil`.
* `name` (`:string`) - Explicit hidden-input name. Overrides form+field. Used by `unit_input/1` to inject a nested name like `height[unit]`. Defaults to `nil`.
* `input_id` (`:string`) - Explicit id for the hidden value input. Defaults to `nil`.
* `current` (`:string`) (required)
* `category` (`:string`) (required)
* `locale` (`:any`) - Defaults to `nil`.
* `include_prefixed` (`:boolean`) - Defaults to `false`.
* `variant` (`:atom`) - Defaults to `:auto`. Must be one of `:auto`, `:dropdown`, or `:sheet`.
* `id` (`:string`) - Defaults to `nil`.
* `class` (`:string`) - Defaults to `nil`.
* `button_class` (`:string`) - Defaults to `nil`.
* `overlay_class` (`:string`) - Defaults to `nil`.
* `row_class` (`:string`) - Defaults to `nil`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
