@legendapp/list 3.7.0 → 3.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,50 +1,22 @@
1
+ ## 3.7.1
2
+
3
+ - Fix: Loading callbacks respond reliably to data changes and new scroll gestures.
4
+ - Fix: Lists preserve scroll positions as rows, insets, and viewport sizes change.
5
+ - Fix: iOS lists with `contentInset.top` now rest at and measure from the inset start.
6
+ - Fix: Keyboard dismissal and interrupted scrolling no longer cause jumps or doubled movement.
7
+ - Fix: Rows stay correctly positioned after items are inserted, removed, or reordered.
8
+ - Perf: Lists prepare more rows before the first scroll.
9
+
1
10
  ## 3.7.0
2
11
 
3
- - Fix: List ref methods `scrollToIndex`, `scrollToOffset`, `scrollToItem`, `scrollToKey`, `scrollToEnd`, `scrollIndexIntoView`, and `scrollItemIntoView` resolve their promises once the scroll lands, or when it is interrupted by user input, canceled or replaced, or cannot reach its target (including removed targets, dataset replacement, and unmounting), instead of resolving early or never.
4
-
5
- Suspense/Activity hide counts as unmounting for scroll requests. Requests made through a captured ref while hidden resolve without scrolling and are not replayed on reveal.
6
-
7
- `scrollToIndex` and `scrollToOffset` clamp out-of-range targets and resolve once landed. Index-based navigation and `scrollToEnd` on empty data resolve without scrolling, including when a header or footer is present.
8
-
9
- - Types: new required members on `LegendListRef` / state since 3.6.0. These stay required, and code that implements or mocks these types must add them:
10
-
11
- - `LegendListRef` (native and web): `cancelScroll`, `scrollToKey`, `anchorVisibleContent`.
12
- - `LegendListState`: `distanceFromEnd`, `isFollowingEnd`. `dataKey` is added as optional.
13
- - `SectionListRef`: `cancelScroll`, `scrollToKey`, `anchorVisibleContent` (inherited from `LegendListRef`). Key-based methods use the flattened keys `${sectionKey}:item:${itemKey}`, `${sectionKey}:header`, `${sectionKey}:footer`, `${sectionKey}:separator:${itemIndex}`, and `${sectionKey}:section-separator`, where `sectionKey` is the section's key or `section-${sectionIndex}`.
14
- - `LegendListMetrics`, the `onMetricsChange` payload: unchanged from 3.6.0, still `headerSize` and `footerSize`. Scroll position and end-distance fields added during the cycle were removed before release.
15
-
16
- `getState().listen` accepts the new `isFollowingEnd` key. `distanceFromEnd` is not a listen key; read `getState().distanceFromEnd`, which is computed on demand. 3.6.0-shaped `listen` implementations remain assignable.
17
-
18
- - Feat: Add ref methods `cancelScroll` to stop queued and active scrolling, `scrollToKey` to navigate by stable item key through prepends, and `anchorVisibleContent` to capture an item's key and viewport offset and hold it through layout changes (the first visible item by default). Pass `{ key }` to choose an item, or use `anchorVisibleContent({ hold: false })` for a snapshot without side effects. Returns `undefined` before initial placement, during dataset replacement, or if no item is found; at the end while following, it returns the anchor without interrupting end following.
19
- - Feat: Add `viewportMargin: { start, end }` to `scrollIndexIntoView` to keep space clear at the start and end of the viewport along the scroll axis.
20
- - Feat: Add `itemOffset` and `itemLength` to `scrollIndexIntoView` and `scrollItemIntoView` to reveal a region inside an item within `viewportMargin` on vertical and horizontal lists.
21
- - Feat: Expose `distanceFromEnd`, `isFollowingEnd`, and `dataKey` through `getState()`, and accept `isFollowingEnd` in `getState().listen`.
22
- - Feat: Add boolean `maintainScrollAtEnd.on.dataAppend` to follow only additions that preserve existing item keys in order; `on.dataChange` remains a boolean option for all data changes.
23
- - Feat: `onUserScroll` fires once per accepted real user gesture (native drag with its momentum, web touch/wheel gesture, scroll key press, scrollbar input, or iOS status-bar tap), never for library or list-ref scrolls, and remains `@experimental` with heuristic wheel grouping and gaps in native pointer/wheel-only and web overlay scrollbar detection.
24
- - Fix: With a native screen reader enabled, unowned accessibility scrolling toward the start releases end following and reports `onUserScroll` once per burst; assistive input during library animations or just after `cancelScroll()` can be missed, and scrolls bypassing the list (such as native-ref commands or Reanimated `scrollTo` worklets) cannot be distinguished from accessibility input, so call `cancelScroll()` on the JS thread before that navigation.
25
- - Fix: Leftover trackpad momentum no longer cancels scroll commands; a new wheel gesture can interrupt them, while upward wheel motion releases automatic end following as in 3.6.0 and downward motion never does.
26
- - Fix: iOS status-bar taps release end following and settle an interrupted list scroll.
27
- - Fix: Native scrolls outside list-owned commands release end following when they move beyond its threshold, and appends while reading earlier rows leave no pending end measurements.
28
- - Fix: Pausing `maintainScrollAtEnd` retains end intent for resuming; `isFollowingEnd` continues to report that intent while paused.
29
- - Fix: Item-layout end following responds to every nonzero size change when its trigger is enabled.
30
- - Fix: End thresholds (`isAtEnd`, `onEndReached`, and `maintainScrollAtEnd`) count trailing content and keyboard insets once. With a trailing inset, they now activate closer to the physical end instead of firing early by the inset amount.
31
- - Fix: Row measurements and header/footer size changes recheck `onStartReached` and `onEndReached` thresholds, so pagination callbacks can fire without a scroll when layout brings an edge within its threshold.
32
- - Fix: Animated end following stays aligned through short-list growth, footer and viewport changes, late row measurements, and native drag-to-momentum handoffs. #563 #568
33
- - Fix: Automatic native end following waits for a drag and its momentum to settle, then catches up near the end using the configured threshold.
34
- - Fix: Keyed scroll targets survive prepends and same-key item updates, cached dataset switches restart initial placement, and fixed-size updates and cache clearing preserve the reader's anchor.
35
- - Fix: `scrollToOffset` can reach `contentContainerStyle` minimum sizes, horizontal RTL web lists use the scroll owner's direction for offsets, and horizontal RTL scroll-offset conversion keeps numeric `minWidth` in the physical content extent.
36
- - Fix: When `getFixedItemSize` is set, changing `extraData` invalidates all fixed sizes and repositions the data.
37
- - Fix: Inline `onMetricsChange` callbacks no longer cause repeated metrics emissions.
38
- - Fix: End following rearms when a scroll or gesture settles within `maintainScrollAtEndThreshold`, so new content resumes following after `scrollToIndex`/`scrollToOffset` or a small nudge that stays near the end.
39
- - Fix: When `getFixedItemSize` starts returning sizes for rows that were already measured, their stale measurements are dropped and the fixed sizes are applied, including rows reordered in the same render.
40
- - Fix: Web lists follow the end in one painted frame when every row grows after a mount or `dataKey` switch, instead of clamping against the stale content extent and catching up a frame late.
41
- - Fix: On Fabric, the native content extent commits in the same render pass as row positions, so shrinking content cannot briefly leave rows mispositioned.
42
- - Fix: `scrollMessageToEnd({ closeKeyboard: true })` starts scrolling right away and eases to the closed end in one motion while the keyboard closes, dismissing it once, including back-to-back and mixed animated and non-animated sends.
43
- - Fix: `AnimatedLegendList` `itemLayoutAnimation` no longer animates rows while scrolling, during list scroll commands, or after layout adjustments, and skips the transition when a container switches items even without `recycleItems`.
44
- - Fix: Keyboard occlusion is excluded from viewability calculations, horizontal viewability uses the correct start padding including RTL, native content insets are counted only where applied, and `KeyboardAwareLegendList` keeps the static `contentInset` prop out of Android keyboard inset reports so it is not counted twice.
45
- - Fix: `scrollMessageToEnd({ closeKeyboard: true })` freezes keyboard tracking before the keyboard starts closing, so the list scrolls to the end in one motion instead of first moving back with the closing keyboard. A rejected scroll or a keyboard close that never settles no longer leaves `freeze` set. #557
46
- - Fix: Animated scrolls that start past the end of the content ease back into range instead of snapping.
47
- - Perf: With `recycleItems` enabled, reuse warm offscreen rows before empty containers, and skip key extraction for unchanged append prefixes.
12
+ - Feat: `LegendListRef` gains `cancelScroll`, `scrollToKey`, `anchorVisibleContent`; state gains `distanceFromEnd`, `isFollowingEnd`.
13
+ - Feat: Expose end-following state and allow following only newly appended items.
14
+ - Feat: `onUserScroll` reports user scroll gestures.
15
+ - Fix: Scroll promises resolve reliably when scrolling finishes or is interrupted.
16
+ - Fix: Lists follow new content smoothly and respect users scrolling away from the end. #563 #568
17
+ - Fix: Scrolling to the end while closing the keyboard moves smoothly in one motion. #557
18
+ - Fix: Row sizing and layout changes preserve visible content and improve viewability accuracy.
19
+ - Perf: Recycled lists reuse rows more efficiently and process appended data faster.
48
20
 
49
21
  ## 3.6.0
50
22
 
package/README.md CHANGED
@@ -113,6 +113,20 @@ export default LegendListExample
113
113
 
114
114
  ---
115
115
 
116
+ ### Paging at reached edges
117
+
118
+ Inside their thresholds, `onEndReached` and `onStartReached` fire again when the data length changes, or when a new data array arrives and the content size differs from the size at the last callback. A new array with the same length and content size does not re-arm an edge. An empty page that leaves both unchanged does not automatically request another page.
119
+
120
+ A new user gesture toward an edge can retry unchanged data inside its threshold. If the current array already received a callback for changed content, that delivery counts toward the next gesture; a later gesture can retry it. Keep the data reference stable between updates to preserve that duplicate-callback protection.
121
+
122
+ While the scroll offset stays unchanged, row measurements, loading footers and other layout changes do not re-arm an already reached edge, even if they temporarily move it outside its hysteresis band. Scroll-offset changes, including MVCP compensation and native clamping, retain the existing distance-based reset behavior. Empty data fires neither callback.
123
+
124
+ ### Native scroll offsets and top insets
125
+
126
+ `scrollToOffset({ offset })` and `initialScrollOffset` use raw native scroll offsets, like React Native's `ScrollView`. With a vertical iOS `contentInset.top` of `T`, the resting start is `-T`: use `scrollToOffset({ offset: -T })` or `initialScrollOffset={-T}` to request it. An explicit `0` still requests native offset `0`, subject to the reachable content bounds. Omitting the initial target starts at `-T`.
127
+
128
+ `scrollToEnd()` lands at `-T` when the content plus both insets fits within the viewport. Start thresholds and `distanceFromStart` measure from this resting start.
129
+
116
130
  ### Sharing a scrollbar on the web
117
131
 
118
132
  React DOM lists can use an ancestor element's scrollbar with `scrollElement`:
package/keyboard.js CHANGED
@@ -231,13 +231,13 @@ var KeyboardAwareLegendList = typedForwardRef(function KeyboardAwareLegendList2(
231
231
  const list = refLegendList.current;
232
232
  if ((endScrollFreeze == null ? void 0 : endScrollFreeze.value) === "animated") {
233
233
  (_i = list == null ? void 0 : list.reportContentInsetForScrollInternal) == null ? void 0 : _i.call(list, { ...insets, bottom: getEndInset() });
234
- } else if (keyboardTarget.value > 0 && (list == null ? void 0 : list.reportContentInsetForScrollInternal)) {
234
+ } else if ((keyboardTarget.value > 0 || keyboard.value.height > 0) && (list == null ? void 0 : list.reportContentInsetForScrollInternal)) {
235
235
  list.reportContentInsetForScrollInternal(insets);
236
236
  } else {
237
237
  list == null ? void 0 : list.reportContentInset(insets);
238
238
  }
239
239
  },
240
- [endScrollFreeze, getEndInset, keyboardTarget]
240
+ [endScrollFreeze, getEndInset, keyboard, keyboardTarget]
241
241
  );
242
242
  const reportClosingInset = React.useCallback((bottom) => {
243
243
  var _a2;
package/keyboard.mjs CHANGED
@@ -210,13 +210,13 @@ var KeyboardAwareLegendList = typedForwardRef(function KeyboardAwareLegendList2(
210
210
  const list = refLegendList.current;
211
211
  if ((endScrollFreeze == null ? void 0 : endScrollFreeze.value) === "animated") {
212
212
  (_i = list == null ? void 0 : list.reportContentInsetForScrollInternal) == null ? void 0 : _i.call(list, { ...insets, bottom: getEndInset() });
213
- } else if (keyboardTarget.value > 0 && (list == null ? void 0 : list.reportContentInsetForScrollInternal)) {
213
+ } else if ((keyboardTarget.value > 0 || keyboard.value.height > 0) && (list == null ? void 0 : list.reportContentInsetForScrollInternal)) {
214
214
  list.reportContentInsetForScrollInternal(insets);
215
215
  } else {
216
216
  list == null ? void 0 : list.reportContentInset(insets);
217
217
  }
218
218
  },
219
- [endScrollFreeze, getEndInset, keyboardTarget]
219
+ [endScrollFreeze, getEndInset, keyboard, keyboardTarget]
220
220
  );
221
221
  const reportClosingInset = useCallback((bottom) => {
222
222
  var _a2;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@legendapp/list",
3
- "version": "3.7.0",
3
+ "version": "3.7.1",
4
4
  "description": "Legend List is a drop-in replacement for FlatList with much better performance and supporting dynamically sized items.",
5
5
  "sideEffects": false,
6
6
  "private": false,