fix(inverted): align ItemSeparatorComponent's trailingItem with visual flow#2301
Open
pranko17 wants to merge 1 commit into
Open
fix(inverted): align ItemSeparatorComponent's trailingItem with visual flow#2301pranko17 wants to merge 1 commit into
pranko17 wants to merge 1 commit into
Conversation
…l flow
`ItemSeparatorComponent` is passed `{ leadingItem: data[i], trailingItem:
data[i+1] }`, and in the default (non-inverted) layout `data[i+1]` is the
item visually below the separator — consumers can rely on `leadingItem`
being "above" and `trailingItem` being "below" the separator.
In `inverted` mode this breaks. Cells render in reverse visual order
(index 0 at the visual bottom), so each cell's separator visually
appears between `data[i]` (above) and `data[i - 1]` (below). The
existing code still passes `data[i + 1]` as `trailingItem`, which is
the item two cells away — not the visually-adjacent neighbor. A
consumer comparing `leadingItem` vs `trailingItem` (e.g. for
same-sender bubble grouping in a chat UI) ends up comparing the
wrong pair and renders wrong styling between bubbles.
Fix: in `inverted` mode pass `data[index - 1]` as `trailingItem`, and
skip the separator at `index === 0` (the visual-bottom cell has no
neighbor below it). Non-inverted behavior is unchanged.
Adds two tests covering the inverted case in
`src/__tests__/RecyclerView.test.tsx`.
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 free
to 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.
Summary
ItemSeparatorComponentis documented to receive{ leadingItem, trailingItem }so consumers can render context-aware separators (think: "small gap between same-sender chat bubbles, larger gap on sender switch"). In the default layout the prop names match the visual flow —leadingItemis the cell above the separator,trailingItemis the cell below.In
invertedmode this assumption breaks: cells are positioned in reverse visual order (array index 0 is at the visual bottom), so the separator owned by cellivisually appears betweendata[i](above) anddata[i - 1](below). The current code still passesdata[index + 1]astrailingItem, which is the cell two rows away — not the visually-adjacent neighbor below the separator. Anyone comparingleadingItemvstrailingItemin an inverted list ends up looking at the wrong pair.This is most painful in chat UIs (
invertedis the canonical layout for chronological chat lists). Imagine bubbles[user, user, expert]in chronological reading. With newest-first data +inverted, the array is[expert, user, user]. The separator inside the middle cell (leading=user,trailing=userviadata[i+1]) says "same sender → 4px gap". But the visually-adjacent items around that separator are the top user bubble and the expert bubble — different senders, should be 24px. The result is a 4px gap where the user expects 24px.Fix
In
ViewHolderCollection.tsx, branch oninverted:trailingItem = data[index - 1]so it stays semantically aligned with the visually-adjacent item below the separator.index === 0(visual-bottom cell has no neighbor below it). This mirrors the existing!isInLastRow(index)guard for the default case.Tests
Added two cases in
src/__tests__/RecyclerView.test.tsx → "Item separators in inverted mode":passes the visually-adjacent item as trailingItem in inverted mode— renders an inverted list withdata=[10, 20, 30]and asserts the separators carry{ leading: 20, trailing: 10 }and{ leading: 30, trailing: 20 }(the visually-adjacent pair below each separator). Without the fix this would assert wrong values.does not render a separator below the visual-bottom item (index 0)— rendersdata=[10, 20]and asserts only one separator is rendered (between data[1] above and data[0] below); no separator dangling at the visual bottom.All existing tests still pass (24 total in
RecyclerView.test.tsx).Notes
inverted: true), so existing non-inverted consumers see no difference.trailingItemvalues, this is a bug fix that may cause visible spacing changes in their separators. The new values match what most consumers actually intend by "between this cell and the next visible one."Test plan
yarn test --testPathPattern=RecyclerView— 24/24 passyarn lint— clean