[select] Remove redundant size check in SelectPositioner - #5469
Conversation
commit: |
| const prevSize = prevMapSizeRef.current; | ||
| prevMapSizeRef.current = map.size; | ||
|
|
||
| if (map.size === prevSize) { |
There was a problem hiding this comment.
flush in CompositeList already handles this check and calls onMapChange when 2 maps change, so this check again in onMapChange is redundant and can introduce more bugs.
|
@claude review |
PR reviewThe core change is sound: Bugs (2)1. 🟡 The aligned-popup layout reset now fires on pure reorders, with nothing to recompute itLocation: if (open && alignItemWithTriggerActive) {
store.update({
scrollUpArrowVisible: false,
scrollDownArrowVisible: false,
});
const stylesToClear: React.CSSProperties = { height: '' };
clearStyles(positionerElement, stylesToClear);
clearStyles(popupRef.current, stylesToClear);
}The removed guard protected all three blocks in Note this is browser-only: in jsdom all rects are Failure scenario: A default Fix: Keep a narrower guard for this block only — e.g. run the layout reset when the item set actually changed ( 2. ℹ️ Object values without
|
Bundle size
PerformanceTotal duration: 1,206.93 ms -62.14 ms(-4.9%) | Renders: 76 (+0) | Paint: 1,890.35 ms -94.40 ms(-4.8%)
13 tests within noise — details Check out the code infra dashboard for more information about this PR. |
✅ Deploy Preview for base-ui ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
There was a problem hiding this comment.
Pull request overview
This PR updates Select’s internal reconciliation behavior so that changes to the item set are handled even when the total item count stays the same, and adds regression tests to cover these scenarios.
Changes:
- Remove an early-return in
SelectPositionersoonMapChangeruns for same-size item replacements/reorders. - Add tests ensuring the value resets when the selected item is replaced (or all items are replaced) without changing the item count.
- Add a test ensuring reordering items does not reset the value.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| packages/react/src/select/positioner/SelectPositioner.tsx | Removes the map-size guard so list mutations with unchanged count still trigger reconciliation. |
| packages/react/src/select/root/SelectRoot.test.tsx | Adds regression tests for value reconciliation when items are replaced vs reordered with unchanged item count. |
Suppressed comments (1)
packages/react/src/select/positioner/SelectPositioner.tsx:163
- Now that the
map.size === prevSizeearly-return is removed,onMapChangewill run for replacements/reorders where the item count stays the same. In theopen && alignItemWithTriggerActivebranch later in this callback, the store is updated to setscrollUpArrowVisible/scrollDownArrowVisibletofalsebut nothing in this callback recomputes their correct visibility (it’s normally derived from scroll geometry). This can cause scroll arrows to disappear after swapping/reordering items while the popup is open, until the user scrolls and triggers a recalculation.
const prevSize = prevMapSizeRef.current;
prevMapSizeRef.current = map.size;
const eventDetails = createChangeEventDetails(REASONS.none);
if (prevSize !== 0 && !store.state.multiple && value !== null) {
const selectedValueIndex = findItemIndex(valuesRef.current, value, isItemEqualToValue);
if (selectedValueIndex === -1) {
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
atomiks
left a comment
There was a problem hiding this comment.
Verified the same-count reconciliation change on the current head, added multiple-select regression coverage, merged current master, and ran focused jsdom/Chromium plus formatting, lint, and type checks locally.
Remove redundant size check in SelectPositioner component as
flushinCompositeListalready handles this