Conversation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Greptile SummaryThis PR fixes a long-standing bug (#3061) where What changed:
Key considerations:
Confidence Score: 4/5
Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A["updateOrder called"] --> B{isReordering?}
B -- yes --> Z[return early]
B -- no --> C["checkReorder - order, item, offset, velocity"]
C --> D{newOrder !== order?}
D -- no change --> Z
D -- swap detected --> E["isReordering = true"]
E --> F["newValues = spread of full values prop"]
F --> G["Loop over newOrder positions"]
G --> H{Values differ at position i?}
H -- no --> G
H -- yes --> I["Find index a of old value in values\nFind index b of new value in values"]
I --> J["Swap newValues at a and b"]
J --> K[break]
K --> L["onReorder called with full newValues array"]
style L fill:#d4edda,stroke:#28a745
style Z fill:#f8d7da,stroke:#dc3545
Last reviewed commit: c3c3c7f |
| const a = values.indexOf(order[i].value) | ||
| const b = values.indexOf(newOrder[i].value) | ||
| newValues[a] = newOrder[i].value | ||
| newValues[b] = order[i].value | ||
| break |
There was a problem hiding this comment.
Silent no-op when a registered value is absent from values
If either order[i].value or newOrder[i].value is not present in values, indexOf returns -1 and newValues[-1] = … silently sets a non-indexed property on the array instead of throwing. The result is that onReorder is called with the array effectively unchanged — the intended swap never happens.
This scenario arises when a currently-rendered/registered item's value has already been removed from values (e.g. the user removed a row while it was being dragged). It was not easily observable with the old code either, but the new path makes it worth guarding explicitly:
const a = values.indexOf(order[i].value)
const b = values.indexOf(newOrder[i].value)
if (a !== -1 && b !== -1) {
newValues[a] = newOrder[i].value
newValues[b] = order[i].value
}
breakCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Summary
Reorder.Group'supdateOrdercallback only returned measured/rendered items toonReorder, dropping any items not currently in the DOM (e.g. offscreen items in a virtualized list)updateOrdermapped the internalorderarray (which only contains measured items) back to values and filtered against thevaluesprop, discarding unmeasured items entirelycheckReorderswapped and apply that same swap to the fullvaluesarray. This preserves all unmeasured items in their correct positionsFixes #3061
Test plan
onReorderreturns the full values array with the swap applied🤖 Generated with Claude Code