Found while re-deriving the divergence table for #6793. Not fixed there — that card is test-only and touches no widget source.
What was measured
Chromium 141.0.7390.37 (Playwright 1.62.1) was driven key by key on a real input type="number", and the resulting .value sequence was then driven through each widget in happy-dom. Typing 1e into an empty box is the reachable "clear" route: the browser moves .value from '' to '1' to '', and the widget is told the box is now empty.
| widget | emission when the box goes empty |
|---|
CurrencyField | null |
PercentField | null |
NumberField | null |
GeolocationField | { latitude: undefined } |
Same for plain deletion — any route that leaves the box empty. Pinned as current product behaviour in packages/fields/src/__tests__/NumberInputWidgets.browserDeliverable.test.tsx (PR for #6793).
Why it is not cosmetic
GeolocationField builds an object instead of emitting a scalar:
onChange({ ...location, [fieldName]: fieldValue ? Number(fieldValue) : undefined });
undefined and null part company at the persistence boundary. JSON.stringifydrops an undefined key entirely, so a cleared latitude can reach the server as an ABSENT key rather than an explicit null. On a PATCH-shaped update an absent key conventionally means "leave it alone" — so the user clears a coordinate, sees an empty box, and the old coordinate survives the save. The other three widgets of this class send an explicit null and do not have that ambiguity.
Not measured here: whether any data adapter in this repo actually round-trips a geolocation clear that way. That is the first thing to check before choosing a fix — the emission asymmetry is measured, the downstream consequence is reasoned.
Context, not a second finding
The class also carries two different parsers — parseFloat in CurrencyField / PercentField, Number in NumberField / GeolocationField. On every string a real browser can deliver they were measured to agree on all rows, so this is latent rather than live; it is worth knowing only because it is the same "one class, two spellings" shape.
Related
#6793 (the test-oracle card this came out of) · #6780 / PR #6801 (the badInput announcement across the same four widgets) · #6765
Found while re-deriving the divergence table for #6793. Not fixed there — that card is test-only and touches no widget source.
What was measured
Chromium 141.0.7390.37 (Playwright 1.62.1) was driven key by key on a real
input type="number", and the resulting.valuesequence was then driven through each widget in happy-dom. Typing1einto an empty box is the reachable "clear" route: the browser moves.valuefrom''to'1'to'', and the widget is told the box is now empty.CurrencyFieldnullPercentFieldnullNumberFieldnullGeolocationField{ latitude: undefined }Same for plain deletion — any route that leaves the box empty. Pinned as current product behaviour in
packages/fields/src/__tests__/NumberInputWidgets.browserDeliverable.test.tsx(PR for #6793).Why it is not cosmetic
GeolocationFieldbuilds an object instead of emitting a scalar:undefinedandnullpart company at the persistence boundary.JSON.stringifydrops anundefinedkey entirely, so a cleared latitude can reach the server as an ABSENT key rather than an explicit null. On a PATCH-shaped update an absent key conventionally means "leave it alone" — so the user clears a coordinate, sees an empty box, and the old coordinate survives the save. The other three widgets of this class send an explicitnulland do not have that ambiguity.Not measured here: whether any data adapter in this repo actually round-trips a geolocation clear that way. That is the first thing to check before choosing a fix — the emission asymmetry is measured, the downstream consequence is reasoned.
Context, not a second finding
The class also carries two different parsers —
parseFloatinCurrencyField/PercentField,NumberinNumberField/GeolocationField. On every string a real browser can deliver they were measured to agree on all rows, so this is latent rather than live; it is worth knowing only because it is the same "one class, two spellings" shape.Related
#6793 (the test-oracle card this came out of) · #6780 / PR #6801 (the
badInputannouncement across the same four widgets) · #6765