Skip to content

feat(LIB-2649): unify FzCurrencyInput into FzInput via type="currency"#398

Open
Trebh wants to merge 4 commits into
mainfrom
refactor/LIB-2649-fzinput-currency-type
Open

feat(LIB-2649): unify FzCurrencyInput into FzInput via type="currency"#398
Trebh wants to merge 4 commits into
mainfrom
refactor/LIB-2649-fzinput-currency-type

Conversation

@Trebh

@Trebh Trebh commented Jun 10, 2026

Copy link
Copy Markdown
Collaborator

Summary

Unifies FzCurrencyInput into FzInput behind a new type="currency" prop, and brings the up/down arrow step controls to type="number" inputs. Maintaining the FzCurrencyInput wrapper had become more harmful than useful; the currency behavior now lives directly in FzInput.

  • FzInput type="currency" — locale-aware currency formatting (Italian separators), min/max clamping, step quantization, paste parsing and step controls, all ported verbatim from FzCurrencyInput into the new internal useCurrencyInput composable. The v-model is numeric (number | null | undefined).
  • Generic componentFzInput is now generic over its type prop: a literal type="currency" switches the v-model type to numbers while every other type (and dynamic :type bindings) keeps string, so existing call sites typecheck unchanged.
  • type="number" step controls — the same up/down arrows replace the native browser spinners; stepping uses the native stepUp()/stepDown() algorithm and respects min/max/step.
  • FzCurrencyInput stays alive (deprecated) — now a thin wrapper around <FzInput type="currency"> with identical API and behavior; it will be removed once the migration of all consumers is complete. Its full 1800-line spec runs unchanged against the wrapper as a behavior-parity regression suite.
  • New exported typesFzInputType, FzInputModelValue, FzInputInstance (replaces InstanceType<typeof FzInput>, which doesn't apply to generic components). Internal usages in select/typeahead/table adapted.

Release impact

@fiscozen/input 3.4.2 → 3.5.0 (minor), with patch bumps for select, typeahead, table and a cascade patch for datepicker (changeset included).

⚠️ Note for existing type="number" consumers: arrows now appear in place of the native spinners (intended).

Companion PR

The migration of frontoffice/backoffice consumers (fiscozen-app) to <FzInput type="currency"> is prepared in a companion draft PR in the app repository, blocked on this PR being merged and @fiscozen/input@3.5.0 published.

Test plan

  • packages/input unit tests: 200 passed (189 pre-existing, incl. the full FzCurrencyInput spec against the new wrapper, + 11 new for currency/number modes)
  • Unit tests for dependent packages (select, typeahead, datepicker, table) green; snapshots updated for the new stepper v-if placeholder comment
  • Full nx run-many -t build (48 projects) green
  • Storybook play-function suite: 738 tests green, incl. new Currency and NumberWithStepControls stories
  • Figma parity checked against the FzCurrencyInput / FzInput design files

🤖 Generated with Claude Code

FzInput becomes generic over its type prop: type="currency" switches the
v-model to number | null | undefined with locale-aware formatting, min/max
clamping and step quantization (logic extracted to useCurrencyInput).
type="number" gains the same up/down step controls, replacing the native
browser spinners. FzCurrencyInput stays as a deprecated thin wrapper around
FzInput type="currency" until all consumers have migrated; its full spec now
runs against the wrapper as a behavior-parity regression suite.

New exported types: FzInputType, FzInputModelValue, FzInputInstance (the
latter replaces InstanceType<typeof FzInput>, not applicable to generic
components); internal usages in select/typeahead/table adapted.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Ported from the FzCurrencyInput component, which is now a thin deprecated
* wrapper around `<FzInput type="currency">`.
*/
export default function useCurrencyInput(options: UseCurrencyInputOptions) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

useCurrencyInput is very large and handles many unrelated responsibilities (parsing, formatting, paste, keydown, stepping, model sync). Break it into smaller focused functions/modules to improve readability and testability.

Details

✨ AI Reasoning
​1. Identify the change: a new composable function exposing currency behavior was added. 2. What it tries to accomplish: manage display string, parse/format Italian locale, clamp/quantize values, handle focus/paste/keydown, stepping and sync with numeric v-model. 3. Does it harm maintainability? The function bundles many unrelated responsibilities (input normalization, model normalization, formatting, event handling, step logic, lifecycle syncing), increasing cognitive load. 4. Is it appropriate? For readability and testability, splitting into smaller helpers (normalization, formatting, model-sync, stepper, event adapters) would make intent clearer. 5. Fix scope: this file is new and introduced in this PR, so refactoring into smaller functions is reasonable within the change set.

🔧 How do I fix it?
Break down long functions into smaller helper functions. Aim for functions under 60 lines with fewer than 10 local variables.

Reply @AikidoSec feedback: [FEEDBACK] to get better review comments in the future.
Reply @AikidoSec ignore: [REASON] to ignore this issue.
More info

The previous loose typing allowed any native type string; the generic
FzInputType union must list them explicitly. search and file are in active
use by consumers and render via native passthrough.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Trebh Trebh marked this pull request as ready for review June 10, 2026 10:06
Trebh and others added 2 commits June 11, 2026 09:51
…ncyInput

The paste handler was ported verbatim from FzCurrencyInput but had no test
coverage in either component. Pin down the accepted clipboard formats
(Italian/comma/dot decimals, negatives, whitespace, parseFloat quirks),
ignored content, decimal truncation, blur-time clamping/formatting,
readonly/disabled guards, consumer @paste forwarding, and the known parse()
limitations on ambiguous grouping, plus a retrocompat smoke suite on the
deprecated FzCurrencyInput wrapper.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Pasting Italian-formatted numbers ("1.234,56") or padded spreadsheet copies
into a native number input is browser-dependent broken: Chrome rejects the
paste, Firefox/Safari blank the value. Reuse the currency paste kernel to
rescue these: clipboard text outside the HTML floating-point grammar is
normalized via the shared parse() and replaces the whole value, while
natively-valid text keeps default browser behavior (cursor insertion) and
unparseable text is ignored, preserving the previous value. No decimal
truncation or min/max clamping: validation semantics stay native.

The parse-and-validate kernel is extracted to parseClipboardNumber() in
utils, now used by both currency mode and the new number branch.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant