Skip to content

LayrzNumberInput

Kenny Mochizuki Escalona edited this page Aug 20, 2026 · 3 revisions

LayrzNumberInput

Numeric input field with configurable bounds, step controls, and decimal formatting.


Specification Status

DERIVED from layrz_theme. This specification is extracted from the current ThemedNumberInput API and awaits team confirmation. Details may change during the M3 inputs review.


Metadata

Field Value
Mirrors ThemedNumberInput from layrz_theme
Phase M3 (Core Inputs)
Domain Inputs
Composes LayrzTextInput (base chrome + keyboard)
SDK Primitive EditableText (via LayrzTextInput), number formatting from intl package

Conformance

LayrzNumberInput conforms to the shared input contract and composes LayrzTextInput internally to achieve consistent chrome and keyboard handling. Only input-specific deltas are documented here. For the baseline API (labelText, placeholder, prefix, suffix, help affordances, onChanged, onTap, readOnly, focusNode, controller, padding), refer to the contract.


Value Type and Interaction

  • Value type: num (compatible with both int and double)
  • Selection surface: None (inline entry via keyboard + optional step buttons)
  • Step buttons: Increment/decrement buttons in the prefix or suffix slots (subject to design confirmation)

Deltas from the Input Contract

LayrzNumberInput adds the following over LayrzTextInput:

Numeric Constraints

  • value (num?) — the current numeric value. Distinct from the text controller; kept in sync during user input.
  • minimum (num?) — lower bound for the numeric value. When set, input below this triggers validation error.
  • maximum (num?) — upper bound for the numeric value. When set, input above this triggers validation error.
  • step (num?) — the increment/decrement amount when step buttons are pressed. Default: 1 (or language-locale-specific).

Decimal Handling

  • format (NumberFormat?) — explicit number formatting from the intl package (e.g., NumberFormat.decimalPattern()). When supplied, input must also have inputRegExp to filter characters.
  • decimalSeparator (ThemedDecimalSeparator) — whether to use dot (.) or comma (,) as the decimal separator. Enum with values dot and comma. Default: dot.
  • inputRegExp (RegExp?) — regular expression to validate/filter input characters (e.g., only digits and decimal separators). Required if format is non-null. Example: RegExp(r'[-0-9\,.]').
  • maximumDecimalDigits (int) — maximum number of digits after the decimal point. Default: 4. Maximum: 15.

Keyboard and Display

  • keyboardType (TextInputType) — soft keyboard type. Default: TextInputType.number (numeric keypad on mobile).
  • inputFormatters (List<TextInputFormatter>) — inherited from LayrzTextInput; applied to raw input before validation.

Text Variants

  • prefixText (String?) — static prefix (e.g., "USD ", "$"). Distinct from step buttons.
  • suffixText (String?) — static suffix (e.g., " kg", " °C").
  • hidePrefixSuffixActions (bool) — whether to hide step increment/decrement buttons. Default: false. These buttons typically occupy the prefix or suffix slot.

Callbacks

  • onChanged (void Function(num?)?) — invoked when the numeric value changes. Receives the parsed number or null if input is invalid.
  • onSubmitted (VoidCallback?) — invoked when the user submits the input (e.g., presses Enter).

State

  • disabled (bool) — when true, step buttons are hidden and input is blocked.
  • focusNode (FocusNode?) — inherited from LayrzTextInput.

Reference: ThemedNumberInput API

For porting purposes, the current layrz_theme implementation exposes (extracted from source):

// Design sketch — parameter names from layrz_theme source
class ThemedNumberInput extends StatefulWidget {
  final String? labelText;
  final Widget? label;              // NOT supported (labelText only)
  final String? placeholder;
  final void Function(num?)? onChanged;
  final num? value;
  final bool disabled;
  final List<String> errors;
  final bool hideDetails;
  final EdgeInsets? padding;
  final bool isRequired;            // Markup only
  final VoidCallback? onSubmitted;
  final List<TextInputFormatter> inputFormatters;
  final double? borderRadius;       // Controlled by theme
  final num? minimum;
  final num? maximum;
  final num? step;
  final TextInputType keyboardType; // Default: TextInputType.number
  final NumberFormat? format;
  final ThemedDecimalSeparator decimalSeparator; // dot or comma
  final RegExp? inputRegExp;        // Required when format is non-null
  final int maximumDecimalDigits;   // Default: 4, max 15
  final String? suffixText;
  final String? prefixText;
  final bool hidePrefixSuffixActions; // Hides ±1 step buttons
  final FocusNode? focusNode;
}

Key structural notes:

  • The implementation internally constructs a TextEditingController for the field and a separate num value holder to track the parsed number.
  • Step buttons (if not hidden) occupy the suffix slot or are rendered as paired buttons flanking the text.
  • Decimal formatting is locale-aware when decimalSeparator is set to comma (applies NumberFormat.decimalPattern('pt') for Portuguese localization).

Dependencies and Blockers

Dependency: LayrzTextInput (M3)

LayrzNumberInput is fully composed on LayrzTextInput. LayrzTextInput must ship first.

Status: LayrzTextInput is blocked on Material-free TextSelectionControls (see LayrzTextInput).

Dependency: intl Package

Number formatting uses NumberFormat from the intl package (already a transitive dependency of layrz_theme). No additional dependency required.

Status: Available.

Design Reference

The step button UI (appearance, position, size, interaction) must be documented in the design reference that covers LayrzTextInput. Step buttons are a visual affordance of LayrzNumberInput and must integrate visually with the base LayrzTextInput chrome.


Open Questions

The following decisions are not yet made and must be resolved before implementation.

1. Step Button Placement and Styling

  • Do step +1/-1 buttons appear in the prefix slot, suffix slot, or outside both (flanking the field)?
  • What is the visual appearance (text buttons, icon buttons, spinner arrows)?
  • Are they visible when the field is disabled or readOnly?
  • Can the caller override the step button appearance or disable them individually?

2. Validation Behavior for Min/Max Bounds

  • When minimum or maximum is violated, does the field trigger a validation error immediately, on blur, or only on submission?
  • Does the field prevent out-of-bounds input (e.g., via inputFormatters), or does it allow entry and then validate?

3. Decimal Separator and Locale Coupling

  • Should the decimal separator choice be entirely manual (caller provides decimalSeparator enum), or should it derive from the app's locale (e.g., Localizations.localeOf(context))?
  • When format is provided by the caller, does it override the decimalSeparator choice?

4. Step Size and Locale

  • Is the step parameter a literal num value, or does it derive from locale/format settings?
  • For currency input, should step default to the currency's smallest unit (e.g., $0.01 for USD)?

5. Composition vs. Decoration

  • Does LayrzNumberInput compose LayrzTextInput directly (i.e., LayrzNumberInput's build tree includes an LayrzTextInput widget), or does it decorate the LayrzTextInput chrome with additional logic?
  • If composed directly, how is the value synced between the caller's value parameter and LayrzTextInput's controller?

6. Formatter and RegExp Relationship

  • The source requires inputRegExp when format is non-null. Is this requirement enforced with an assertion, or is it optional?
  • What is the default inputRegExp when format is null?

Last updated: 2026-08-13
Related documents: Input Contract, LayrzTextInput, Design Tokens

Clone this wiki locally