Money input component
A currency-aware amount field — optional currency selector, per-currency decimal precision, locale-grouped formatting on blur, robust parsing of what the user types, and a minor-unit storage contract. Pairs the money display mask (data/masks.kmd) with input behavior. Modeled after Polaris (price fields). Used by Koder Exchange, Invest, Billing, marketplace, checkout.
Status: v0.1.0 — Draft. Promoted from the Shopify Polaris parity scan (metadocsstack #091). Source: https://polaris.shopify.com/components/selection-and-input/text-field (pricecurrency usage). Display mask: `specsdata/masks.kmd`.
R1 — Currency
- The field has an associated currency. Either fixed (shown as a
prefix/suffix affix, e.g.
R$) or selectable via an adjacent currency selector when the surface supports multiple currencies. - Changing the selected currency re-applies that currency's precision (R2)
and symbol; it never silently rescales the entered numeric amount.
R2 — Precision per currency
- Decimal places follow the currency, not the locale: BRLUSDEUR = 2,
JPYCLP = 0, BHDKWD = 3. Use the ISO-4217 minor-unit exponent, not a hardcoded 2.
- On blur, the value is rounded to that precision (half-up); the input
shows the formatted amount.
R3 — Formatting & parsing
- Display (on blur / read): grouped per the UI locale
(
specs/data/masks.kmdmoney mask) with the currency affix. - Parsing (what the user types): accept the locale's decimal +
grouping separators, an optional leading sign, and a pasted formatted string; reject letters/extra symbols. Be liberal in, strict out.
inputmode="decimal"; nevernumeric(decimals needed).
R4 — Storage contract
- Persist as an integer in the currency's minor units (cents) +
the currency code — never a float (no binary-float money), aligned with
specs/data/field-types.kmd. Display is derived from this pair.
R5 — Range & validation
- Optional min/max + non-negative constraints; violations show an inline
message (
specs/errors/user-facing-messages.kmd), never silent clamp. - Empty vs zero are distinct (empty = unset).
R6 — Accessibility & i18n
- Real
<label>; the currency affix/selector is part of the accessiblename ("Amount in Brazilian Real").
- Right-alignment is presentational only; the value reads correctly to AT.
- All formatting/parsing is locale + currency aware
(
specs/i18n/contract.kmd); the stored minor-unit value is locale-invariant.
Não-escopo
- FX conversion between currencies (a service concern).
- The money display mask mechanics (
specs/data/masks.kmd). - Accounting/rounding policy beyond per-currency precision (domain rules).