Repository navigation
feat: BigNumberField onValueChange and value={null} (#97), DropdownSelect multiple selection (#106), react-aria-components 1.20.0; fix read-only steppers (related to #98), dropdown trigger overflow (#105), CustomRadio arrow keys (#109), stray CSS utilities (#110), Slider input names (#111) - #107
kemuru wants to merge 26 commits into
Conversation
…ead-only steppers (#98) BigNumberField (#97 points 1 and 3; 3.10.0 shipped points 2 and 4): - onValueChange gets the same number as onChange, or null when the input holds none ("", "-", ".", "-."). onChange is unchanged: 0 when emptied, NaN for "." and "-.". - value={null} empties a controlled field like value="". It threw a TypeError. - "." and "-." keep their text instead of showing NaN, so ".5" gives 0.5 when the value echoes back. An empty value counts as an echo only when it comes in the same commit as the edit. The check compares committed text, so React's effect timing can't break it. - "." over a selection that holds the decimal point replaces it. - A required field flags the empty text that blur leaves after "." or "-.". NumberField (#98): a read-only field no longer reveals its disabled steppers on hover. hideStepper is not added: the kleros-v2 review asked for a use case beyond ID and suffix fields, and none exists yet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
✅ Deploy Preview for kleros-v2-ui-storybook ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. ℹ️ Recent review info
WalkthroughThe changes update BigNumberField controlled values and callbacks, add multiple selection and trigger sizing to dropdowns, and adjust read-only NumberField and CustomRadio behavior. They also upgrade react-aria-components and update stylesheet source scanning and related interaction coverage. ChangesBigNumberField controlled input
Dropdown selection and layout
Form control behavior
React Aria compatibility
Stylesheet source scanning
Priority: Estimated code review effort: 4 (Complex) | ~60 minutes Change: Feature · Severity of issue fixed: Medium Sequence Diagram(s)sequenceDiagram
actor User
participant DropdownSelect
participant ReactAriaSelectState
participant ParentState
User->>DropdownSelect: Select or deselect options
DropdownSelect->>ReactAriaSelectState: Update selected keys
DropdownSelect->>ParentState: Report selected values and matching items
ParentState->>DropdownSelect: Send controlled selection
Possibly related issues
Possibly related PRs
Suggested reviewers: Merge Risk:
|
…et from outside The controlled-value effect writes the raw text of a value set from outside but kept `isFormatted`. After blur formatted the text, a reset to "" therefore left the field in formatted mode: - the next change was unformatted first, so a pasted "1,5" lost its comma as a group separator and gave 15, where a fresh field rejects it; - the idle formatter skipped every later value set from outside. Consumers that reset by remounting (kleros-v2 until its onValueChange migration) never hit it. Clear the flag whenever the effect applies a value. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
🔇 Additional comments: 3
src/lib/form/bignumber-field/useBigNumberField.tsx: 1
206-206: LGTM!Also applies to: 209-209, 214-214
src/lib/form/bignumber-field/useBigNumberField.test.tsx: 1
509-550: LGTM!CHANGELOG.md-23-23: 1
23-23: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
⚠️ Unverified finding
Verification ran but could not confirm this finding. It is shown for review, not as a verified issue.Use American English in the changelog.
Change “afterwards” to “afterward” on Line [23] to resolve the reported locale violation.
Source: Linters/SAST tools
ℹ️ Review info
⚙️ Run configuration
- Source mode: Auto
- Repository: Unavailable
- Branch: Unavailable
- File: No configuration file from this repository applied
- Commit: Unavailable
- Layers: Organization UI
- Review profile: CHILL
- Plan: Essentials
- Run ID:
1d868317-2825-4e67-8ac5-7444b8d108e1
📒 Files selected for processing: 3
CHANGELOG.mdsrc/lib/form/bignumber-field/useBigNumberField.test.tsxsrc/lib/form/bignumber-field/useBigNumberField.tsx
Included review availability: This review used your included allowance. 3 included reviews remain after this review. Your included PR review attempts over the past 7 days set your current allowance at 5 reviews per hour.
…t field CustomRadio's docs ask for fields (conditional content next to an option) to be rendered inside the group, and react-aria's RadioGroup handles the arrow keys of every keydown that reaches it. An arrow key typed in such a field moved the selection, which could unmount the field, and was cancelled, so the caret didn't move (kleros-v2's case ID and token address fields). The options now sit in a `display: contents` element whose keydown handler stops arrow keys from editable targets after their own handlers ran, so BigNumberField still steps on ArrowUp/Down. Arrow keys on the radios themselves still move the selection. Closes #109 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Tailwind's automatic source detection scanned the whole repository, so class-like words in
stories, tests and workflow files ended up in the published stylesheet as global utilities, such
as `.container` and `.collapse { visibility: collapse }`, styling any app element that had those
class names.
global.css now scans only src/lib. Storybook, the browser tests and the dev page load the new
stories.css, which imports it and adds the stories, native and test sources, so their stylesheet
keeps every class they used (only `.p-2` and `.text-red-500`, from a unit test of `cn`, drop out).
Closes #110
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Button uses it, so the stylesheet still ships it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The library bundles react-aria-components, and it was on 1.7.1. Select supports multiple selection from 1.13 on, which #106 needs, and apps already compile against 1.13 to 1.21 types, so the runtime lagged the types they see. 1.21.1 and 1.22.1 are skipped. In 1.21.1, preventFocus throws "Failed to execute 'contains' on 'Node'" when the window gets a focus event during a press, which shows up as unhandled errors in the story tests. In 1.22.1, opening a Modal or popover calls CSS.escape, which jsdom lacks, so apps' jsdom tests crash. 1.20.0 has neither. Adapting to it: - DropdownCascader commits validation after its Select button sets the key. setSelectedKey no longer does, so a required field kept its error. - Modal keeps isOpen and the other overlay props off the nested Modal, which react-aria now warns about on every render. - Stories expect the rest of the page to be inert under a modal, and click the Checkbox and Switch controls: react-aria reads the 0x0 pointer events of a synthetic label click as a screen reader's. A native test covers real clicks on the label and track. The behaviour apps may notice is listed in the changelog. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…#105) DropdownSelect's and DropdownCascader's trigger is a fixed w-60 button, and `className` styles the wrapper, so apps reached the button through descendant selectors. A long selected text wrapped onto a second line, and a long word ran past the border with the arrow squeezed to nothing. - `buttonClassName` merges over the trigger's classes. - The trigger is never wider than its field. Its value stays on one line and truncates; the arrow, icon and dot keep their size. - The select's list fills its popover, which is 240px wide but never narrower than the trigger. Long options wrap, breaking long words. The 240px default stays, since apps size skeletons and grid columns from it, and the DOM is unchanged, so their selector workarounds keep working. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…iple" (#106) DropdownSelect wraps react-aria's Select, which supports multiple selection from 1.13 on and is now bundled at 1.20.0. - `selectionMode="multiple"` keeps the list open while picking. `callback` gets the selected items, and react-aria's `value`, `defaultValue` and `onChange` take arrays of keys. react-aria calls only `onChange` in this mode, so the component maps its keys to items for `callback`. - With several items picked, the button shows their texts as react-aria's locale-aware list, truncated like any long value. One item shows as in single selection. - Two overloads type it, so `callback` takes an array only with `selectionMode="multiple"`. With a generic, `ComponentProps<typeof DropdownSelect>` would resolve to both modes, and kleros-v2 builds its LabeledDropdown props from that type. Selected rows keep the single-selection style, a left border rather than a check, as the design system describes. A single-selection story covers react-aria's `value` and `onChange`, which the upgrade enables. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
react-aria-components 1.20 declares Select's selectedKey, onSelectionChange, isOpen and other props in react-stately's types, which the docgen filter dropped. The new GlobalDOMEvents and GlobalDOMAttributes added about 70 DOM props to every table. Allow react-stately and leave the global DOM props out, so each component keeps the props it documented and gains only its new ones. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Since react-aria 1.15, a field that react-aria focuses after a clicked submit fails validation doesn't show its focus ring, because useFocusRing subscribes to the modality change too late (react-spectrum#10751). In this library only RadioGroup draws its ring from that state, as the RequiredOptions story's final screenshot shows. Submitting with the keyboard is unaffected. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- A key pressed on the closed trigger (an arrow or typeahead) that picked an item left a required field's error in place, and a second submit went through with the error still shown. react-aria commits validation for picks in the list but not for those keys. 3.10.0 committed for every change. Both dropdowns now commit from their onChange, reaching react-aria's state through a small bridge inside the Select. The cascader's Select button no longer needs its own commit. - The simple button stretches across its column, so the list's min-width followed it there. A 360px mobile column gave a 352px list. The list matches the trigger width only for the bordered button. - The multiple-selection overload omits selectedKey, defaultSelectedKey and onSelectionChange, which react-aria ignores in that mode. Adding selectionMode="multiple" to an existing select now flags its defaultSelectedKey instead of silently dropping it. - The overloads are ordered single, multiple, single. The docs read the first and ComponentProps the last, so both show single selection. The Select docs page had shown the multiple-selection types. - The changelog scopes the ellipsis to the bordered button, and notes the order callback receives items in. A story covers the keyboard pick, SimpleSelect checks its list stays 240px, and a type test locks the overloads. Each fails on 046a2ff. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The nested react-aria Modal got every prop the overlay got, apart from the open state. react-aria 1.20 passes DOM events on to the element, so a caller's onClick fired twice for a click inside the modal, and an id landed on two elements. The nested Modal needs none of these props. Kleros apps pass only className, isOpen, isDismissable and onOpenChange. The changelog lists the components that now call a caller's onClick, which react-aria 1.7.1 dropped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The library bundles 1.20.0, but its .d.ts files take their types from the app's react-aria-components, and ^1.20.0 resolves to 1.22.1 on a fresh install. Apps then compile against props the bundled code ignores, such as Modal's onEnter and onExit. ~1.20.0 gives them the types of the version they run. The changelog also scopes the label-click note. Only @testing-library/user-event before 14.6, which Storybook 8's @storybook/test bundles, sends the 0x0 pointer events react-aria ignores. Apps on 14.6 are unaffected. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The value label and the captions under the track were react-aria Labels with fixed ids, so
every input on a page was named after the first slider's value label and value ("400 $M 400"
for two sliders labelled "A" and "B"), and an aria-label had no effect.
- The value label and the captions are plain <label> elements that label nothing, so apps'
label styles still apply. The captions lose aria-label="min-label" and "max-label".
- With aria-labelledby, an empty hidden Label takes the group's place in react-aria's
labelling, and the thumb gets aria-labelledby and aria-label. Browsers read the group's text
rather than its aria-labelledby, so the input is otherwise named after the captions.
- The input announces the formatter's text as aria-valuetext, written after each commit since
react-aria has no prop for it. The value label is aria-hidden.
- Each part gets a data-slot named like its id. The ids stay: foresight and futarchy-ui style
through them.
Closes #111
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GitHub's ubuntu-latest image is now Ubuntu 26.04, and Playwright 1.56.1 can't install Chromium
there ("Playwright does not support chromium on ubuntu26.04-x64"), so the job failed before
any test ran. Ubuntu 26.04 support arrived in Playwright 1.61. Pin the job to the image of its
last green run until Playwright is upgraded.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… top react-aria 1.20 makes the page behind an open Modal or popover inert, including elements added while it is open, and ends a click outside a dismissable Modal on `click`, which it stops. A wallet modal opened from a library Modal, as the mobile menus of futarchy-ui, governor-v2 and foresight do, and toasts therefore ignored taps, in Chromium, Firefox and WebKit. A Yarn patch on the bundled react-aria 3.51.0 restores 1.7.1's behaviour: aria-hidden only, and the outside interaction ends on pointerup, so the click still reaches what it lands on. The Modal story checks aria-hidden again, as it did on main, and a browser test fails if the patch stops applying, for example after a react-aria bump. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Found by the audit of the whole PR, each reproduced against 3.10.0: - A required dropdown showed its error after a form reset that followed an awaited submit: the reset sets the value, and the dropdowns committed validation on every change. They skip that commit during a reset and leave validation to react-aria. - A single selection keeps ignoring defaultValue, as react-aria 1.7.1 did. curate-v2's chain field passes one and writes its form value only from callback, so it showed Ethereum Mainnet before any pick, and picking it again reported nothing: the step's Next button stayed disabled. - One long word widened the list's implicit grid column past the 240px list, clipping every option. The list has one column now, and the LongText story checks each option's right edge (its old check compared an option with itself). - An icon passed as an element shrank beside long text; every child but the text keeps its size. - The state bridge uses the isomorphic layout effect, so server rendering logs no warning. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
react-aria 1.20's Select lets ArrowDown and ArrowUp reach ancestors, so ArrowDown on a DropdownSelect nested in CustomRadio, as the docs recommend for conditional fields, moved the group's selection and unmounted the dropdown. A nested native select had the same problem on 3.10.0. The guard now stops arrow keys from any target that isn't one of the group's radios; radio-to-radio navigation and BigNumberField stepping are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The value-text bridge uses the library's isomorphic layout effect, like useElementSize, so React 18's server renderer logs no warning. A test renders the Slider and both dropdowns on the server. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The react-aria 1.20 entry now describes the patch, says Enter submits only from radios now, as Checkbox and Switch already did, and covers DOM events, scrollbar-gutter and defaultValue in a single selection. The BigNumberField entries and the value prop's JSDoc gain the caveats about late echoes and resetting a lone "-", "." or "-.", and #108's wording now says only the idle formatting skipped values. CustomRadio and the dropdown icons are updated, and a Deprecated section lists the Slider's fixed ids. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Review of f553238: a quick pass, a UI pass (Storybook in Chromium at 375 and 1280 px, light and dark, axe) and a standard code pass. Every item below was reproduced; the probe output is in each Proof line. What already checks out: unit (208), stories (314) and native (26) suites pass, the react-aria patch is bundled into 1. Introduced by this PRMediumClosing a library overlay clears an
The
Blur clears
Multi-select: keyboard focus is invisible among selected rows
Single-mode form reset never reaches
Single-mode
Low
|
|
Second part of the review of f553238: things that were already there, but in code this PR rewrote, so they're cheap to fix here. 2. Already there, but in code this PR rewrote (cheap to fix here)MediumRequired field accepts a lone
Cmd+A / C / V / X blocked on macOS
Slider thumb has no focus-visible style
Low
Older issues and out-of-scope items are filed separately and don't block this PR: #112, #113, #114, #115, #116, #117, #118, #119. |
The patch stopped react-aria from making the page behind an overlay inert, but its unhide path still set `inert = false`. Closing a library Modal or DropdownSelect therefore cleared an `inert` that the app had set itself, such as on its root while its own drawer is open. react-aria 1.7.1 never wrote `inert`. The line is gone from the three builds, and a native test checks both overlays. The comment above the pointerup listener now says that giving up upstream's Android Chrome fix is deliberate. Raised in the review of f553238. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ortcuts Raised in the review of f553238, each reproduced: - Blur empties a `-`, `.` or `-.` and reports it as an emptied input: onChange gets 0 and onValueChange null. Before, blur emptied `.` and `-.` while the parent's last onChange value was NaN, and a lone `-` stayed and passed a required field. The number a parent answers that report with, such as an echoed 0, is validated, since blur validated the empty text. - A `-`, `.` or `-.` survives a re-render of a parent that builds `value={new BigNumber(amount)}` while that value holds no number. Before, any re-render emptied it, so `.5` gave 5. A number given again still replaces the text, as on 3.10.0, since it can be a reset such as a Max button. - Only the parse is inside handleChange's `try`, and its two copies are merged. When onChange throws while the user types, the field keeps the number, still calls onValueChange and logs the error as an onChange error. It is still logged rather than thrown, as on 3.10.0: futarchy-ui's onChange runs viem's parseUnits, which throws for `.`. - Cmd+A, Cmd+C, Cmd+V and Cmd+X work on macOS; only their Ctrl versions did. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ton's arrow Raised in the review of f553238: - In a multiple selection, the row with keyboard focus looked like every other selected row. It gets DraggableList's focus outline; a single selection, with one selected row, is unchanged. - Beside long text, the simple button's arrow shrank to a few pixels. It keeps its size, and the text still wraps, since the simple button has no fixed width. - `defaultValue` is documented as ignored by a single selection, as it always has been, though its type accepts it. Removing it from the type would break curate-v2, which passes one. - A native test checks that `callback` gets the items in the order they were picked. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A read-only NumberField filled its background on hover, so it looked editable. As in BigNumberField, a field that can't be edited no longer reacts to hover. Raised in the review of f553238. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With two sliders on a page, nothing showed which one had keyboard focus. The thumb now glows like a focused input, in blue on themed sliders too, as the design system keeps focus blue. Raised in the review of f553238. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
"Breaking changes: None" now reads "None in the API", followed by each behaviour change that can affect an app on this minor release, including blur's new report and the Modal props, which had no entry. The fixes from the review of f553238 get their entries. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|



Closes #97, closes #105, closes #106, closes #109, closes #110, closes #111. Refs #98, which can be closed as not planned (see below).
#103 (released in 3.10.0) fixed #97 points 2 and 4. This PR covers points 1 and 3 without changing
onChange.BigNumberField (#97)
onValueChange?: (value: BigNumber | null) => voidgets the same number asonChange, ornullwhen the input holds none: emptied, or only-,.or-.. A field controlled through it tells a cleared input from a typed 0 and stays empty when cleared.value={null}empties a controlled field, likevalue="". It threw a TypeError before..or-.keeps that text instead of showingNaN, so.5gives 0.5 when the value echoes back. 3.10.0 gave 5.onChangestill gets NaN for that text..over a selection that holds the decimal point replaces it. Before, selecting2.7and typing.5gave 5.-,.or-.and reports it as an emptied input:onChangegets 0 andonValueChangegetsnull, and a required field shows its error. Before, a lone-survived blur and passed the required check..or-.survives a re-render of a parent that buildsvalue={new BigNumber(amount)}and so passes the NaNonChangereported again, so.5gives 0.5 there too. A number given again still replaces the text, as on 3.10.0, since it can be a deliberate reset.onChangethrows while the user types, the field keeps the number and still callsonValueChange. The error is logged asError in BigNumberField onChange, and still not thrown: 3.10.0 caught it too, and futarchy-ui'sonChangerunsparseUnits, which throws for.."", leaves the field unformatted. Before, the field kept treating its text as formatted: a pasted1,5lost its comma as a group separator and gave 15 where a fresh field rejects it, and the idle formatting skipped later values set from outside. kleros-v2 hits this once it resets throughvalue=""instead of remounting (fix(frontend): read BigNumberField values through onValueChange, validate gated token IDs, drop library workarounds (#2617, #2319, #2353) kleros-v2#2613): after a transaction popup resets the appeal field, a pasted0,5funded 5 ETH. Merged here from fix(bignumber-field): leave the field unformatted when its value is set from outside #108.NumberField (#98)
A read-only NumberField no longer reveals its disabled stepper buttons on hover; BigNumberField already hid them. A read-only or disabled NumberField no longer fills its background on hover either.
hideStepperis not added: the kleros-v2#2281 review asked for a validated use case beyond ID and suffix fields, and none turned up in the Kleros repos.CustomRadio (#109)
Arrow keys pressed in a control inside the group now stay with that control. That covers a field such as a TextField or BigNumberField next to the options, as the docs recommend, a DropdownSelect, and a native select: the keys move the field's caret or value, or open the dropdown's list. Before, react-aria's RadioGroup took them. It moved the selection, which could unmount the control, and cancelled the key. react-aria 1.20 made nested dropdowns hit this too, since its Select lets ArrowDown and ArrowUp reach the group. In kleros-v2 that hit the case ID field and the gated token address and ID fields. Arrow keys on the radios themselves still move the selection. The options now sit in a
display: contentselement with the keydown handler.Stylesheet (#110)
Tailwind scanned the whole repository, so class-like words in stories, tests and workflow files ended up in the published stylesheet as global utilities, such as
.container(a max-width per breakpoint) and.collapse(visibility: collapse).global.cssnow scans onlysrc/lib. Storybook, the browser tests and the dev page load the newstories.css, which adds the stories, native and test sources.Slider (#111)
aria-labeloraria-labelledby.aria-labelpassed had no effect. In Chrome, Firefox and Safari, two sliders labelled "A" and "B" were both named "400 $M 400". This was the same on 3.10.0 and on this branch's react-aria 1.20.0.<label>elements, now plain ones that label nothing. curate-v2's globallabelrule still styles them.aria-labelledby. Witharia-labelledby, an empty hidden label takes the group's place, and the thumb gets thearia-labelledbyand thearia-label. Every combination of the two props now names the input like its group in Chrome, Firefox and Safari, including both props together and an id that matches nothing.aria-labelledby,aria-labelreaches the input through the group. Forwarding it to the thumb as well, as the issue suggests, doubled the name ("A A").0.005 ETHwhere curate-v2's Deposit sliders read5,000,000,000,000,000.aria-valuetextafter each commit, like the dropdowns'SelectStateBridge.""still announces react-aria's number.aria-hidden, since the input announces the same text.aria-label="min-label"and"max-label".data-slotnamed like its id, such as[data-slot=slider-label].#slider-label,#slider-trackand#slider-fill. Removing them would silently change those sliders.#slider-thumbnever reached the DOM, on 3.10.0 too: react-aria drops a thumb'sid.shadow-input) while it has keyboard focus, as it already did while dragged. Nothing showed which slider had focus.react-aria-components 1.20.0
The library bundles react-aria-components, and it was on 1.7.1 (March 2025). #106 needs multiple selection in
Select, which arrived in 1.13. Apps already compile against 1.13 to 1.21 types, so the runtime lagged what their types allowed.~1.20.0replaces^1.7.1, so the types apps compile against are those of the version they run.^1.20.0would resolve to 1.22.1 types, which allow props that the bundled 1.20.0 ignores.preventFocusthrowsFailed to execute 'contains' on 'Node'when the window gets a focus event during a press. The story tests report it as unhandled errors in 4 files.CSS.escape, which jsdom lacks, so apps' jsdom tests that open one crash. It also has two open overlay issues (Popover opens up to ~600 ms late on touch-capable desktops (1.22: runAfterKeyboard waits for an on-screen keyboard that never appears) adobe/react-spectrum#10798 and #10772), though neither reproduced with these components.onChange. react-aria'ssetSelectedKeyno longer does, so a required field kept its error after a valid pick. That happened with the cascader's Select button and with an arrow key or typeahead on the closed trigger, and a second submit then went through with the error still shown. A form reset sets the value too, so they skip the commit then and leave validation to react-aria; otherwise a reset after an awaited submit showed the required error..yarn/patches/react-aria-npm-3.51.0-*.patch) changes two things in the bundled copy:inert, including elements added while it is open. The patch makes it usearia-hiddenonly, as 1.7.1 did, and closing the overlay leaves alone aninertthe app set itself.pointerup, as 1.7.1 did, so the click still reaches what it lands on.defaultValue, as 1.7.1 did. curate-v2's chain field passes one and writes its form value only fromcallback. Honouring it showed Ethereum Mainnet before any pick, and picking it again reported nothing, so the step's Next button stayed disabled.onClickfired twice.selectedKeyandisOpennow live, and leaves out the ~70 global DOM props every component gained. Every component keeps the props its table documented.DropdownSelect and DropdownCascader trigger (#105)
buttonClassNamestyles the trigger, for examplebuttonClassName="w-full";classNamestill styles the wrapper.[&_button]:w-fullin curate-v2,> button { width: 100% }in kleros-v2, atlas-dashboard's truncation set. The DOM is unchanged, so those keep working.w-fittriggers keep their 238px list: the token pickers in futarchy, foresight and governor.DropdownSelect multiple selection (#106)
selectionMode="multiple"keeps the list open while picking.callbackgets the selected items, andvalue,defaultValueandonChangetake arrays of keys; react-aria calls onlyonChangein this mode.isRequiredasks for at least one item andnamesubmits every selected key.ComponentProps<typeof DropdownSelect>reads the last overload, so it keeps resolving to the single-selection props, which kleros-v2's LabeledDropdown and foresight's wrapper build on. The docs read the first. A dynamicselectionMode(a union) has no overload.callbackgets the items in the order they were picked.selectedKey,defaultSelectedKeyandonSelectionChangedon't apply in multiple mode, and the types reject them.IItemdoesn't have.CI
The component tests job now runs on
ubuntu-24.04. GitHub'subuntu-latestimage became Ubuntu 26.04, where the repo's Playwright 1.56.1 can't install Chromium, so the job failed before any test ran. Playwright supports Ubuntu 26.04 from 1.61, so the pin can go when Playwright is upgraded.For consumers
onChangesends exactly what 3.10.0 sent for the same typed text, and blur now also reports a-,.or-.it empties.value's type gainsnull, which only affects code that reads the type back throughComponentProps<typeof BigNumberField>. The Slider keeps its props, types, ids, elements and behaviour; besides what screen readers get, only its keyboard focus glow is new.callback.value,defaultValueandonChangenow work.@testing-library/user-eventbefore 14.6, which Storybook 8's@storybook/testbundles. 14.6 and later, which kleros-v2, foresight and atlas-dashboard use, are unaffected.onClickalso fires on keyboard presses. Checkbox, Switch, TextField, NumberField and Modal now call a caller'sonClick, and other DOM event handlers and attributes such asdirorlangnow reach the element.scrollbar-gutter. In Chromium, a page with a custom::-webkit-scrollbar(escrow-ui, veashi-scanner) shifts by the scrollbar's width while it is open.null, and a disabled NumberField is left out of FormData.CSS.escapepolyfill.defaultValue, which a single selection keeps ignoring, so its chain field works as before.buttonClassNamereplaces the descendant selectors apps use to size the trigger, though those still work.selectionModemust be a literal, since a union has no overload.value={amount}withonValueChange={(v) => setAmount(v?.toString() ?? "")}. In kleros-v2 this retiresuseBigNumberFieldReset, theisZero()mappings and CreationCard's DOM read. It also stops the crash in Fund and InputDisplay when.reachesparseUnitsas"NaN". Code that stays ononChangeworks as before, crash included.display: contentselement. The group still lays them out, but a child selector such as[role="radiogroup"] > labelno longer matches them. kleros-v2 has none.aria-labeloraria-labelledby. curate-v2's two Deposit sliders have neither. Without one, an input has no name of its own: Chrome and Firefox read its captions, Safari reads nothing, and react-aria warns on every render in development.[data-slot=slider-label]to#slider-labelin new styles..or-.-,.or-., setting the value to empty again keeps that text: withonValueChangewiring, or asnew BigNumber("")afteronChange's NaN. Remount with akeywhere that matters.onChangenullable and drop the duplicate callback. Drop the Slider's fixed ids in favour ofdata-slot.Verification
Added after the review of f553238, in 92c7b4a…0c0b3b9:
inertthe app set was cleared when a library overlay closed (the patch's unhide path); the BigNumberField items above, withhandleChange's two copies merged; the multiple-selection focus outline; the CHANGELOG's breaking-changes wording and the missing Modal entry; the Slider focus glow, the NumberField hover fill and the simple button's arrow.callback, as on 3.10.0:callbacktakes an item and can't getnullwithout breaking apps' types.onSelectionChangegets thenull.defaultValue, as on 3.10.0, though its type accepts it. curate-v2 passes one, so removing it from the type would fail their type-check, and honouring it is what broke their chain step. The CHANGELOG and the prop's JSDoc say so.validate, a number given again over a lone-was ignored, and anonChangeerror from blur's report skipped validation.useBigNumberField.test.tsx, and the pick order ofcallbackindropdown.native.test.tsx.inert. The bundled.d.tsis unchanged; the per-module ones gain an explicitdefaultValuewith the type it inherited.yarn test:unit:coverage232,yarn test:stories314,test:native36,yarn test:storybook-plays314 stories × 2 themes,tsc, eslint andyarn build.Added after a whole-PR audit:
^3.x, the library's own changes against those apps, and a fresh review of the full diff.inert, and swallowed the click that closes a dismissable Modal. A wallet modal opened from futarchy-ui's, governor-v2's or foresight's mobile menu, and toasts, ignored taps. It's now patched as described above. The failure reproduced in Chromium, Firefox and WebKit.defaultValue, as before.scrollbar-gutter; the BigNumberField caveats about echoes and resets; fix(bignumber-field): leave the field unformatted when its value is set from outside #108's wording; a Deprecated entry for the Slider ids.src/native/dropdown.native.test.tsxsrc/native/custom-radio.native.test.tsxsrc/native/modal.native.test.tsx, for the patchsrc/test/ssr.test.tsxselectedKeyis rejected in multiple selection.d.ts: the changes since 3.10.0 only add things, and compile against consumer code (including vea'sFC<DropdownSelectProps>assignment).reactandreact-dom.Added with #111:
yarn test:unit:coverage: 205 testsyarn test:stories: 314test:native: 14yarn test:storybook-plays: 314 stories × 2 themestsc, eslint andyarn buildaria-valuetextchecks in the existing stories.aria-labelledbyoraria-label, or always forwarding thearia-label; unhiding the value label or making it a react-aria Label again; dropping adata-slot; putting back a caption'saria-label.aria-labelnext toaria-labelledbywas lost on the input, which had no name at all when the id matched nothing;""left no announced value;usehooks-ts), so React 18's server renderer logs no warning for them. A test renders both on the server.aria-labelledbywith and without captions, futarchy's slider, foresight's disabled sliders, an empty formatter, StrictMode and RTL.aria-label,aria-labelledby, both, two ids, a missing id and none at runtime gives the same names as a fresh load..d.tsfiles, the CSS files and the export list are identical to this branch before the fix. The Slider chunk grows by 81 bytes gzipped.labelrule, futarchy-ui's#slider-*overrides, a custom theme and RTL. Eight of them were also compared with 3.10.0 in Chromium, and match.Added with #105, #106 and the react-aria upgrade (branch head c5c2050):
yarn test:unit:coverage: 198 testsyarn test:stories: 312test:native: 14yarn test:storybook-plays: 312 stories × 2 themestsc, eslint andyarn buildvalue.onClick.check-typesgives 0 errors, 184 tests pass and the vite build succeeds. 69 component scenarios are unchanged.devbranch still has LabeledDropdown, built onComponentProps<typeof DropdownSelect>. It gives 0 type errors and 172 tests pass..d.tswith react-aria-components 1.20.0 and 1.22.1 types:The
.d.tschanges only bybuttonClassName, DropdownSelect's overloads and the exportedSelectProps.Added with the fixes for #108, #109 and #110:
yarn test:unit:coveragenow runs 196 tests.yarn test:storiesstill runs 302 tests, andtest:nativeruns 10..p-2and.text-red-500, which only a unit test ofcnused.Earlier checks:
yarn test:unit:coverage: 194 tests. They include a test of the echo check under real React scheduling, withoutact(), which caught a timing bug in an earlier draft.yarn test:mutation: 100%.yarn test:stories: 302 tests.yarn test:storybook-plays: 302 stories × 2 themes. The new and extended stories fail on 3.10.0.tsc, eslint, prettier andyarn buildpass. The emitted.d.tschanges only byvalue | null,onValueChangeand NumberField's prop destructuring.onChangecalls..5now gives 0.5. Migrated toonValueChange, it passes every BigNumberField: controlled mode cannot represent an empty field #97 point, which 3.9.0 and 3.10.0 fail.🤖 Generated with Claude Code
PR-Codex overview
This PR focuses on updating styles and functionality across the codebase, particularly in the
srcandstoriesdirectories, enhancing accessibility, and improving the behavior of various components.Detailed summary
global.csstostories.css.react-aria-componentsversion to~1.20.0.SelectStateBridgefor managing select states.BigNumberFieldfor clearer value handling.Summary by CodeRabbit
New Features
nullfor empty values and provide a callback that distinguishes empty or incomplete input from numeric values.Bug Fixes