Uh oh!
There was an error while loading. Please reload this page.
fix(fields): NumberField reads the published error slot - #7002
Merged
Conversation
`NumberField` destructured `{ value, onChange, field, readonly, ...props }`
with no `error`, so the published validation slot landed in `props` and
`toDomProps` (a whitelist) dropped it. The widget wrote `aria-invalid` only
while its own bad-input refusal was active, so handed an `error` and no host
to cover for it, the control carried no `aria-invalid` at all.
Wire `error` and collapse the conditional spread into the ordinary
`aria-invalid={!!error || !!refusal}` the sibling number widgets use. Both
halves land together: reading `error` is what makes an unconditional
attribute safe, and un-conditionalising is what makes reading `error` visible.
Pinned in `validation-feedback.test.tsx` (the consumer half, which goes red
without the wiring) and `number` added to the `WIDGETS` table of
`widget-aria-invalid-e2e.test.tsx`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yBCo-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB
Contributor
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
os-sam
marked this pull request as ready for review
August 31, 2026 09:01
This was referenced Aug 31, 2026
Uh oh!
There was an error while loading. Please reload this page.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes#6803
NumberFielddestructured{ value, onChange, field, readonly, ...props }withno
error, so the published validation slot landed in the open tail andtoDomProps— a whitelist — dropped it. The widget wrotearia-invalidonlywhile its own bad-input refusal was active.
This wires
errorand collapses that conditional spread into the ordinaryaria-invalid={!!error || !!refusal}thatCurrencyField,PercentField,LocationFieldandGeolocationFieldalready use, and addsnumberto theWIDGETStable (and theit.eachrow) ofwidget-aria-invalid-e2e.test.tsx.Premise correction — please read before reviewing the pins
The card says an invalid number field "is not announced to assistive tech". That
is true of the widget itself, but it is NOT what a user experiences on any
host in this repo today, and the difference decides which test can go red.
Measured on
1b1d772a5: inside the real form thearia-invalidthatFormControl's Radix Slot hands down arrives as a widget prop, andtoDomPropsforwards the whole
aria-*family by prefix. So the Slot's correct valuereached the input on its own. Adding
numberto the #3222 e2e table and runningit against unmodified
NumberFieldgives 14 passed — green before the fix aswell as after. A host was covering for the omission.
That also explains why the registry-wide sweep in
widget-aria-invalid-registry-e2e.test.tsxnever caught this with an emptyNOT_YET_DELIVEREDledger: it measures the rendered row, and the row was correct.So the e2e row alone would have been a pin that passes for the wrong reason. The
load-bearing pin is the consumer half in
validation-feedback.test.tsx— thewidget alone, no host, no Slot — which is the widget's own contract and which
does go red. I searched for a host that delivers
errorwithout a Slot-providedaria-invalid; there is none in-repo today (GridFieldrenders a rawInputfor numeric cells, and
FieldEditWidget's two callers pass noerror), so thedefect is a genuine contract gap that is currently latent rather than a live
screen-reader regression. Triage may want to re-grade the p1.
Red, green, ablation
numberadded to the e2e table,NumberFielduntouched: 14 passed — thegap is invisible there (above).
validation-feedback.test.tsxcases,NumberFielduntouched:2 failed —
Received:empty, i.e. noaria-invalidattribute at all.validation-feedback+ the 字段 widget 的错误提示键:spec 声明error,objectui 渲染errorMessage(declared ≠ enforced) #3222 e2e +badInputAnnounce+the registry sweep +
environmentDivergence= 5 files, 184 tests passed.errorwiring(
aria-invalid={!!error || !!refusal}becomesaria-invalid={!!refusal},the exact regression the card warns about): 2 failed, one of them the new
e2e
numberrow. Mutation confirmed on disk by anchored counts in bothdirections plus
git hash-object(
006c352a…HEAD blob vsfc1e6f35…mutated); restored undertrap ... EXIT INT TERMwith absolute paths and verified by hash equalityback to the HEAD blob plus an empty
git diff HEAD.Step 4 is the answer to "is the overwrite hazard closed": the e2e row is not
load-bearing against today's code, but it is load-bearing against the
un-conditionalised-without-
errorshape, which is the way this can regress.Verification
All at
8699b5634:pnpm exec vitest run packages/fields/— 125 files, 2105 tests passedpnpm exec vitest run packages/plugin-detail/ packages/plugin-kanban/(thetwo downstream
FieldEditWidgethosts) — 136 files, 1191 tests passedpnpm --filter @object-ui/fields type-check— exit 0 (covers the new testfiles: the script runs
tsc -p tsconfig.test.jsontoo)pnpm --filter @object-ui/fields lint—917 problems (0 errors, 917 warnings), all pre-existing; no narrowing for this package. Type-awarelinting is not configured, so this diff cannot move the verdict on any file it
does not touch.
check-changeset-presence— "3 source file(s) of 1 released package(s)changed, and this change declares 1 changeset(s)"
check-control-bytes"OK (scanned 5808 tracked text file(s))",check-changeset-fixed,check-changeset-no-major,check-changeset-overwrite— all exit 0check:readme-exportsis not measured here, not red: its 306 findings areall "type entry is not on disk -- run
pnpm buildfirst" for packages thisworktree has not built, plus a
packagesRead: found 11, floor is 25refusal.None names
@object-ui/fields, which IS built. It needs a full workspace build,which CI does.
Scope
Only the three files the card names, plus the changeset. No other widget is
touched and the e2e harness is not refactored. #6780 and #6801 are already
merged and are not affected by this branch.
Generated by Claude Code