feat(opal): add `@opal/InputCurrency`

Merged
RA
2d ago
+1290-5

Description

Adds InputCurrency to Opal: a segmented amount field that reads $ [whole] . [fraction] on the shared segmented-input chrome.

  • currency (ISO 4217, default USD): the host locale sets the symbol, its side (3,00 €) and the decimal separator, through a new OpalStrings.inputCurrencyParts. getCurrencyParts(locale, currency) is exported for the app's OpalStringsBridge.
  • precision (default: the currency's usual decimals): the fraction accepts at most this many digits; typing more is blocked. 0 hides the fraction.
  • The whole segment always resolves: leading zeros trim as soon as focus leaves it (0000 → 0).
  • Keyboard: . / , jump to the fraction, pasting 12.50 fills both segments, arrows cross segment edges. Inside a form, Enter submits from either segment; outside a form, Enter steps to the fraction.
  • onChange fires on every edit (every draft is a valid amount); blur and Enter tidy the display (3.5 → 3.50).
  • New inputs/numbers/ group: InputCurrency lives there and InputNumber moves in beside it.
  • New Opal strings for the field and segment labels, in all nine locales.

Summary by cubic

Adds @opal/InputCurrency, a segmented currency amount field that reads $ [whole] . [fraction] on the shared segmented-input chrome, with the symbol, its side, and the decimal separator driven by the host locale.

New Features

  • Typing . or , jumps to the fraction and splits the amount at the caret: an empty whole part fills 0 first (so .5 reads 0.5), digits after the caret move to the front of the fraction clipped to the precision, dropping any padded zeros (1|234 on 1234.00 reads 1 . 234), and with no fraction segment the separator does nothing. Other non-digits, grouping keys included, do nothing. Pasting reads the text as an amount: it drops whitespace, direction marks, grouping, and the symbol or code, fills both segments (12.50) or inserts into the focused segment, and ignores anything that is not an amount.
  • precision caps the fraction digits (0 hides the fraction, "unlimited" and larger numbers clamp to 15, the most digits a JS number holds exactly) and currency is typed as an ISO 4217 CurrencyCode; either change rebuilds the segments. Display rounds half up from the shortest decimal form (0.075 shows 0.075, or 0.08 at precision 2); leading zeros trim as soon as the whole segment loses focus.
  • onChange fires on every edit; blur and Enter tidy the display; Enter submits a surrounding form from either segment.
  • getCurrencyParts(locale, currency) is exported for OpalStringsBridge, with new strings in all nine locales.
  • InputNumber moves into a new inputs/numbers/ group next to it.

Summary by CodeRabbit

  • New Features

    • Added a locale-aware currency input with segmented editing, configurable precision, validation states, keyboard navigation, RTL support, and form integration.
    • Added currency formatting utilities for regional symbols, separators, placement, and decimal precision.
    • Added public exports and Storybook examples for currency input components.
    • Added active currency-code and precision type support.
  • Localization

    • Added accessibility labels for currency input parts in English, Arabic, German, Spanish, French, Japanese, Korean, Portuguese, and Chinese.
  • Documentation

    • Added currency input usage, behavior, props, and localization guidance.
    • Updated number input documentation links and organization.