@rific/scroll-view 0.1.1 → 0.3.0

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/dist/index.js CHANGED
@@ -56,6 +56,7 @@ module.exports = __toCommonJS(index_exports);
56
56
  var import_react6 = require("react");
57
57
  var import_react_native4 = require("react-native");
58
58
  var import_react_native_gesture_handler = require("react-native-gesture-handler");
59
+ var import_react_native_reanimated6 = require("react-native-reanimated");
59
60
 
60
61
  // src/internal/RefreshControl.tsx
61
62
  var import_react_native = require("react-native");
@@ -63,19 +64,26 @@ var import_jsx_runtime = require("react/jsx-runtime");
63
64
  var RefreshControl = (props) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.RefreshControl, { refreshing: false, ...props });
64
65
 
65
66
  // src/internal/ScrollViewChip.tsx
67
+ var import_auto_paper = require("@rific/auto-paper");
66
68
  var import_react_native2 = require("react-native");
67
- var import_react_native_paper = require("react-native-paper");
68
69
  var import_react_native_reanimated = __toESM(require("react-native-reanimated"));
69
70
  var import_jsx_runtime2 = require("react/jsx-runtime");
70
- var ScrollViewChip = ({ isHorizontal, onPress, style }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_reanimated.default.View, { style: [styles.chip, style], children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_paper.Chip, { compact: true, icon: isHorizontal ? "chevron-left" : "chevron-up", onPress, style: styles.chipInner, children: isHorizontal ? "Start" : "Top" }) });
71
+ var ScrollViewChip = ({ chipProps, isHorizontal, onChipPress, onPress, style }) => {
72
+ const { label, style: chipStyle, ...restChipProps } = chipProps ?? {};
73
+ const handlePress = onChipPress ? () => {
74
+ onPress();
75
+ onChipPress();
76
+ } : onPress;
77
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_reanimated.default.View, { style: [styles.chip, style], children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_auto_paper.Chip, { compact: true, ...restChipProps, icon: isHorizontal ? "chevron-left" : "chevron-up", onPress: handlePress, style: [styles.chipInner, chipStyle], children: label ?? (isHorizontal ? "Start" : "Top") }) });
78
+ };
71
79
  var styles = import_react_native2.StyleSheet.create({
72
80
  chip: { alignItems: "center", left: 0, position: "absolute", right: 0, zIndex: 3 },
73
81
  chipInner: { elevation: 2, shadowColor: "#000", shadowOffset: { width: 0, height: 1 }, shadowOpacity: 0.15, shadowRadius: 2 }
74
82
  });
75
83
 
76
84
  // src/internal/useScrollHandler.ts
77
- var import_react2 = require("react");
78
- var import_react_native_reanimated2 = require("react-native-reanimated");
85
+ var import_react3 = require("react");
86
+ var import_react_native_reanimated3 = require("react-native-reanimated");
79
87
 
80
88
  // src/ScrollViewContext.ts
81
89
  var import_react = require("react");
@@ -85,10 +93,16 @@ var ScrollViewContext = (0, import_react.createContext)({
85
93
  footerHeightShared: null,
86
94
  footerFixed: false,
87
95
  footerOffset: null,
88
- headerHeight: 0,
96
+ headerHeight: null,
89
97
  headerHeightShared: null,
90
98
  headerFixed: false,
91
99
  headerOffset: null,
100
+ jsListGeneration: { current: 0 },
101
+ listGeneration: null,
102
+ onJsListUnmount: () => {
103
+ },
104
+ onListUnmount: () => {
105
+ },
92
106
  progress: null,
93
107
  progressing: false,
94
108
  pullSearchHeightShared: null,
@@ -107,25 +121,215 @@ var ScrollViewContext = (0, import_react.createContext)({
107
121
  tabBarHeight: 60
108
122
  });
109
123
 
124
+ // src/useScrollInit.ts
125
+ var import_react2 = require("react");
126
+ var import_react_native_reanimated2 = require("react-native-reanimated");
127
+ var REMOUNT_SYNC_MAX_ATTEMPTS = 8;
128
+ var REMOUNT_SYNC_TOLERANCE = 1;
129
+ var REMOUNT_SYNC_FALLBACK_MS = 500;
130
+ var REMOUNT_PRIME_FRAMES = 40;
131
+ var SNAP_VERIFY_TOLERANCE = 1;
132
+ var SNAP_VERIFY_MAX_ATTEMPTS = 5;
133
+ var SNAP_VERIFY_INITIAL_DELAY_MS = 400;
134
+ var SNAP_VERIFY_RETRY_DELAY_MS = 150;
135
+ function useScrollInit({ listHeaderComponent, onMomentumScrollEnd: externalMomentumScrollEnd, onRefresh, onScrollBeginDrag: externalScrollBeginDrag, onScrollEndDrag: externalScrollEndDrag, pullSearchHeight, scrollTo }) {
136
+ const { headerHeight, scrollPosition, setProgressing } = (0, import_react2.useContext)(ScrollViewContext);
137
+ const hasPullSearch = pullSearchHeight !== void 0;
138
+ const [phase, setPhase] = (0, import_react2.useState)(hasPullSearch && !headerHeight ? "measuring" : "ready");
139
+ const [refreshing, setRefreshing] = (0, import_react2.useState)(false);
140
+ const refreshingRef = (0, import_react2.useRef)(refreshing);
141
+ (0, import_react2.useEffect)(() => {
142
+ refreshingRef.current = refreshing;
143
+ }, [refreshing]);
144
+ const dragStartY = (0, import_react2.useRef)(null);
145
+ const pendingSnapTarget = (0, import_react2.useRef)(null);
146
+ const snapVerifyTimeout = (0, import_react2.useRef)(null);
147
+ const snapVerifyAttempts = (0, import_react2.useRef)(0);
148
+ const scheduleSnapVerification = (0, import_react2.useCallback)(
149
+ (target, delay) => {
150
+ if (snapVerifyTimeout.current !== null) clearTimeout(snapVerifyTimeout.current);
151
+ pendingSnapTarget.current = target;
152
+ snapVerifyAttempts.current = 0;
153
+ const check = () => {
154
+ snapVerifyTimeout.current = null;
155
+ if (pendingSnapTarget.current !== target) return;
156
+ if (Math.abs(scrollPosition.value - target) <= SNAP_VERIFY_TOLERANCE) {
157
+ pendingSnapTarget.current = null;
158
+ return;
159
+ }
160
+ snapVerifyAttempts.current += 1;
161
+ if (snapVerifyAttempts.current > SNAP_VERIFY_MAX_ATTEMPTS || refreshingRef.current) {
162
+ pendingSnapTarget.current = null;
163
+ return;
164
+ }
165
+ scrollTo(target, false);
166
+ snapVerifyTimeout.current = setTimeout(check, SNAP_VERIFY_RETRY_DELAY_MS);
167
+ };
168
+ snapVerifyTimeout.current = setTimeout(check, delay);
169
+ },
170
+ [scrollPosition, scrollTo]
171
+ );
172
+ (0, import_react2.useEffect)(
173
+ () => () => {
174
+ if (snapVerifyTimeout.current !== null) clearTimeout(snapVerifyTimeout.current);
175
+ },
176
+ []
177
+ );
178
+ const [remountTarget] = (0, import_react2.useState)(() => headerHeight !== null ? -headerHeight + (pullSearchHeight ?? 0) : null);
179
+ const remountSyncTarget = (0, import_react_native_reanimated2.useSharedValue)(remountTarget);
180
+ const [scrollReady, setScrollReady] = (0, import_react2.useState)(remountTarget === null);
181
+ const remountAttempts = (0, import_react2.useRef)(0);
182
+ const onRemountSynced = (0, import_react2.useCallback)(
183
+ (y) => {
184
+ scrollPosition.value = y;
185
+ setScrollReady(true);
186
+ },
187
+ [scrollPosition]
188
+ );
189
+ const onRemountSyncRetry = (0, import_react2.useCallback)(
190
+ (currentY) => {
191
+ if (remountTarget === null) return;
192
+ remountAttempts.current += 1;
193
+ if (remountAttempts.current > REMOUNT_SYNC_MAX_ATTEMPTS) {
194
+ remountSyncTarget.value = null;
195
+ onRemountSynced(currentY);
196
+ return;
197
+ }
198
+ scrollTo(remountTarget, false);
199
+ },
200
+ [onRemountSynced, remountSyncTarget, remountTarget, scrollTo]
201
+ );
202
+ (0, import_react2.useEffect)(() => {
203
+ if (remountTarget === null) return;
204
+ scrollTo(remountTarget, false);
205
+ const fallback = setTimeout(() => {
206
+ if (remountSyncTarget.value === null) return;
207
+ remountSyncTarget.value = null;
208
+ onRemountSynced(remountTarget);
209
+ }, REMOUNT_SYNC_FALLBACK_MS);
210
+ return () => clearTimeout(fallback);
211
+ }, []);
212
+ (0, import_react2.useEffect)(() => {
213
+ if (phase === "ready" || !headerHeight || !pullSearchHeight) return;
214
+ scrollPosition.value = -headerHeight + pullSearchHeight;
215
+ setPhase("ready");
216
+ }, [phase, headerHeight, pullSearchHeight, scrollPosition]);
217
+ const headerInitialized = (0, import_react2.useRef)(false);
218
+ (0, import_react2.useLayoutEffect)(() => {
219
+ if (!headerHeight || headerInitialized.current) return;
220
+ headerInitialized.current = true;
221
+ const target = remountTarget ?? -headerHeight;
222
+ scrollPosition.value = target;
223
+ scrollTo(target, false);
224
+ if (remountTarget === null) return;
225
+ let framesLeft = REMOUNT_PRIME_FRAMES;
226
+ let handle = null;
227
+ const tick = () => {
228
+ const offset = framesLeft === 1 ? target : framesLeft % 2 === 0 ? target + 30 : target - 30;
229
+ scrollTo(offset, false);
230
+ framesLeft -= 1;
231
+ if (framesLeft > 0) handle = requestAnimationFrame(tick);
232
+ };
233
+ handle = requestAnimationFrame(tick);
234
+ return () => {
235
+ if (handle !== null) cancelAnimationFrame(handle);
236
+ };
237
+ }, [remountTarget, headerHeight, scrollPosition, scrollTo]);
238
+ const pullSearchInitialized = (0, import_react2.useRef)(false);
239
+ (0, import_react2.useLayoutEffect)(() => {
240
+ if (remountTarget !== null || !hasPullSearch || phase !== "ready" || pullSearchInitialized.current || !headerHeight || !pullSearchHeight || !scrollReady) return;
241
+ pullSearchInitialized.current = true;
242
+ scrollPosition.value = -headerHeight + pullSearchHeight;
243
+ scrollTo(-headerHeight + pullSearchHeight, false);
244
+ }, [remountTarget, hasPullSearch, phase, headerHeight, pullSearchHeight, scrollPosition, scrollReady, scrollTo]);
245
+ (0, import_react2.useEffect)(() => {
246
+ if (pullSearchHeight) setProgressing(refreshing);
247
+ }, [pullSearchHeight, refreshing, setProgressing]);
248
+ const handleScrollBeginDrag = (0, import_react2.useCallback)(
249
+ (e) => {
250
+ if (snapVerifyTimeout.current !== null) {
251
+ clearTimeout(snapVerifyTimeout.current);
252
+ snapVerifyTimeout.current = null;
253
+ }
254
+ pendingSnapTarget.current = null;
255
+ if (pullSearchHeight) dragStartY.current = e.nativeEvent.contentOffset.y;
256
+ externalScrollBeginDrag?.(e);
257
+ },
258
+ [externalScrollBeginDrag, pullSearchHeight]
259
+ );
260
+ const handleScrollEndDrag = (0, import_react2.useCallback)(
261
+ (e) => {
262
+ if (pullSearchHeight && headerHeight) {
263
+ const y = e.nativeEvent.contentOffset.y;
264
+ const showY = -headerHeight;
265
+ const hideY = -headerHeight + pullSearchHeight;
266
+ const startY = dragStartY.current;
267
+ dragStartY.current = null;
268
+ const pulledDown = (startY ?? hideY) <= hideY;
269
+ const dragDistance = startY !== null ? startY - y : 0;
270
+ if (pulledDown && dragDistance >= pullSearchHeight * 0.5) {
271
+ if (y <= showY && !refreshing && onRefresh) {
272
+ setRefreshing(true);
273
+ Promise.resolve(onRefresh()).finally(() => setRefreshing(false));
274
+ }
275
+ scrollTo(showY, true);
276
+ scheduleSnapVerification(showY, SNAP_VERIFY_INITIAL_DELAY_MS);
277
+ } else if (y < hideY) {
278
+ scrollTo(hideY, true);
279
+ scheduleSnapVerification(hideY, SNAP_VERIFY_INITIAL_DELAY_MS);
280
+ }
281
+ }
282
+ externalScrollEndDrag?.(e);
283
+ },
284
+ [externalScrollEndDrag, headerHeight, onRefresh, pullSearchHeight, refreshing, scheduleSnapVerification, scrollTo]
285
+ );
286
+ const handleMomentumScrollEnd = (0, import_react2.useCallback)(
287
+ (e) => {
288
+ if (pullSearchHeight && headerHeight && !refreshing && pendingSnapTarget.current === null) {
289
+ const y = e.nativeEvent.contentOffset.y;
290
+ const hideY = -headerHeight + pullSearchHeight;
291
+ if (y < hideY - 1) {
292
+ scrollTo(hideY, true);
293
+ scheduleSnapVerification(hideY, SNAP_VERIFY_INITIAL_DELAY_MS);
294
+ }
295
+ }
296
+ externalMomentumScrollEnd?.(e);
297
+ },
298
+ [externalMomentumScrollEnd, headerHeight, pullSearchHeight, refreshing, scheduleSnapVerification, scrollTo]
299
+ );
300
+ const activeListHeader = hasPullSearch && phase === "measuring" ? null : listHeaderComponent;
301
+ const hiddenHeader = phase === "measuring" && listHeaderComponent != null ? typeof listHeaderComponent === "function" ? (0, import_react2.createElement)(listHeaderComponent) : listHeaderComponent : null;
302
+ return { activeListHeader, handleMomentumScrollEnd, handleScrollBeginDrag, handleScrollEndDrag, hiddenHeader, onRemountSyncRetry, onRemountSynced, pullSearchMinHeight: pullSearchHeight ?? 0, remountSyncTarget, remountTarget, scrollReady };
303
+ }
304
+
110
305
  // src/internal/useScrollHandler.ts
111
- function useScrollHandler({ chipHidden, footerFixed, headerFixed, isHorizontal, onPullSearchZoneEnter }) {
112
- const { footerHeightShared, footerOffset, headerHeightShared, headerOffset, pullSearchHeightShared, scrollPosition, snapBackFooterShared, snapBackHeaderShared } = (0, import_react2.useContext)(ScrollViewContext);
113
- const snapUpAccum = (0, import_react_native_reanimated2.useSharedValue)(0);
114
- const fromBottomBounce = (0, import_react_native_reanimated2.useSharedValue)(false);
115
- const isMomentum = (0, import_react_native_reanimated2.useSharedValue)(false);
116
- const momentumPullSearchFired = (0, import_react_native_reanimated2.useSharedValue)(false);
117
- return (0, import_react_native_reanimated2.useAnimatedScrollHandler)(
306
+ function useScrollHandler({ capturedGeneration, chipHidden, chipThreshold = 100, footerFixed, headerFixed, isHorizontal, listGeneration, onRemountSyncRetry, onRemountSynced, remountSyncTarget }) {
307
+ const { footerHeightShared, footerOffset, headerHeightShared, headerOffset, pullSearchHeightShared, scrollPosition, snapBackFooterShared, snapBackHeaderShared } = (0, import_react3.useContext)(ScrollViewContext);
308
+ const snapUpAccum = (0, import_react_native_reanimated3.useSharedValue)(0);
309
+ const fromBottomBounce = (0, import_react_native_reanimated3.useSharedValue)(false);
310
+ return (0, import_react_native_reanimated3.useAnimatedScrollHandler)(
118
311
  {
119
312
  onScroll: ({ contentOffset: { x, y }, contentSize: { height: contentHeight }, layoutMeasurement: { height: layoutHeight } }) => {
120
313
  "worklet";
314
+ if (remountSyncTarget && remountSyncTarget.value !== null) {
315
+ const target = remountSyncTarget.value;
316
+ if (Math.abs(y - target) < REMOUNT_SYNC_TOLERANCE) {
317
+ remountSyncTarget.value = null;
318
+ if (onRemountSynced) (0, import_react_native_reanimated3.runOnJS)(onRemountSynced)(y);
319
+ } else if (onRemountSyncRetry) {
320
+ (0, import_react_native_reanimated3.runOnJS)(onRemountSyncRetry)(y);
321
+ }
322
+ return;
323
+ }
324
+ if (listGeneration.value !== capturedGeneration.value) return;
121
325
  if (isHorizontal) {
122
326
  scrollPosition.value = x;
123
- chipHidden.value = x < 100 ? 1 : 0;
327
+ chipHidden.value = x < chipThreshold ? 1 : 0;
124
328
  return;
125
329
  }
126
330
  const delta = y - scrollPosition.value;
127
331
  scrollPosition.value = y;
128
- chipHidden.value = y < 100 ? 1 : 0;
332
+ chipHidden.value = y < chipThreshold ? 1 : 0;
129
333
  const maxScroll = contentHeight - layoutHeight;
130
334
  if (maxScroll > 0 && y >= maxScroll) {
131
335
  fromBottomBounce.value = true;
@@ -133,13 +337,6 @@ function useScrollHandler({ chipHidden, footerFixed, headerFixed, isHorizontal,
133
337
  } else if (fromBottomBounce.value) {
134
338
  fromBottomBounce.value = false;
135
339
  }
136
- if (isMomentum.value && pullSearchHeightShared.value > 0 && !momentumPullSearchFired.value) {
137
- const hideY = -headerHeightShared.value + pullSearchHeightShared.value;
138
- if (y < hideY) {
139
- momentumPullSearchFired.value = true;
140
- if (onPullSearchZoneEnter) (0, import_react_native_reanimated2.runOnJS)(onPullSearchZoneEnter)();
141
- }
142
- }
143
340
  const snapHeader = snapBackHeaderShared.value && !headerFixed;
144
341
  const snapFooter = snapBackFooterShared.value && !footerFixed;
145
342
  if (snapHeader || snapFooter) {
@@ -157,24 +354,17 @@ function useScrollHandler({ chipHidden, footerFixed, headerFixed, isHorizontal,
157
354
  if (y >= -headerHeightShared.value + pullSearchHeightShared.value) snapUpAccum.value -= delta;
158
355
  if (snapUpAccum.value >= 10) {
159
356
  snapUpAccum.value = 999;
160
- if (snapHeader) headerOffset.value = (0, import_react_native_reanimated2.withTiming)(0, { duration: 200 });
161
- if (snapFooter) footerOffset.value = (0, import_react_native_reanimated2.withTiming)(0, { duration: 200 });
357
+ if (snapHeader) headerOffset.value = (0, import_react_native_reanimated3.withTiming)(0, { duration: 200 });
358
+ if (snapFooter) footerOffset.value = (0, import_react_native_reanimated3.withTiming)(0, { duration: 200 });
162
359
  }
163
360
  }
164
361
  }
165
362
  },
166
363
  onBeginDrag: () => {
167
364
  "worklet";
168
- isMomentum.value = false;
169
- momentumPullSearchFired.value = false;
170
365
  fromBottomBounce.value = false;
171
366
  snapUpAccum.value = 0;
172
367
  },
173
- onMomentumBegin: () => {
174
- "worklet";
175
- isMomentum.value = true;
176
- momentumPullSearchFired.value = false;
177
- },
178
368
  onEndDrag: ({ contentOffset: { y }, contentSize: { height: contentHeight }, layoutMeasurement: { height: layoutHeight } }) => {
179
369
  "worklet";
180
370
  if (isHorizontal) return;
@@ -185,37 +375,35 @@ function useScrollHandler({ chipHidden, footerFixed, headerFixed, isHorizontal,
185
375
  },
186
376
  onMomentumEnd: () => {
187
377
  "worklet";
188
- isMomentum.value = false;
189
- momentumPullSearchFired.value = false;
190
378
  fromBottomBounce.value = false;
191
379
  snapUpAccum.value = 0;
192
380
  }
193
381
  },
194
- [headerFixed, footerFixed, isHorizontal, onPullSearchZoneEnter]
382
+ [capturedGeneration, headerFixed, footerFixed, isHorizontal, chipThreshold, listGeneration, onRemountSyncRetry, onRemountSynced, remountSyncTarget]
195
383
  );
196
384
  }
197
385
 
198
386
  // src/internal/useScrollList.ts
199
- var import_react4 = require("react");
387
+ var import_react5 = require("react");
200
388
  var import_react_native3 = require("react-native");
201
- var import_react_native_reanimated4 = require("react-native-reanimated");
389
+ var import_react_native_reanimated5 = require("react-native-reanimated");
202
390
  var import_react_native_safe_area_context = require("react-native-safe-area-context");
203
391
 
204
392
  // src/useKeyboardInset.ts
205
- var import_react3 = require("react");
393
+ var import_react4 = require("react");
206
394
  var import_react_native_keyboard_controller = require("react-native-keyboard-controller");
207
- var import_react_native_reanimated3 = require("react-native-reanimated");
395
+ var import_react_native_reanimated4 = require("react-native-reanimated");
208
396
  var useKeyboardInset = () => {
209
- const [keyboardHeight, setKeyboardHeight] = (0, import_react3.useState)(0);
397
+ const [keyboardHeight, setKeyboardHeight] = (0, import_react4.useState)(0);
210
398
  (0, import_react_native_keyboard_controller.useKeyboardHandler)(
211
399
  {
212
400
  onMove: (e) => {
213
401
  "worklet";
214
- (0, import_react_native_reanimated3.runOnJS)(setKeyboardHeight)(e.height);
402
+ (0, import_react_native_reanimated4.runOnJS)(setKeyboardHeight)(e.height);
215
403
  },
216
404
  onEnd: (e) => {
217
405
  "worklet";
218
- (0, import_react_native_reanimated3.runOnJS)(setKeyboardHeight)(e.height);
406
+ (0, import_react_native_reanimated4.runOnJS)(setKeyboardHeight)(e.height);
219
407
  }
220
408
  },
221
409
  []
@@ -228,122 +416,55 @@ var CHIP_SLIDE = 48;
228
416
  function useScrollList({ footerFixed: footerFixedProp, headerFixed: headerFixedProp, isHorizontal, keyboardAware, pullSearchHeight, style } = {}) {
229
417
  const insets = (0, import_react_native_safe_area_context.useSafeAreaInsets)();
230
418
  const keyboardHeight = useKeyboardInset();
231
- const { footerHeight, footerFixed: contextFooterFixed, headerHeight, headerFixed: contextHeaderFixed, headerOffset, pullSearchHeightShared, scrollPosition, snapBackHeaderShared } = (0, import_react4.useContext)(ScrollViewContext);
419
+ const { footerHeight, footerFixed: contextFooterFixed, headerHeight, headerFixed: contextHeaderFixed, headerOffset, pullSearchHeightShared, scrollPosition, snapBackHeaderShared } = (0, import_react5.useContext)(ScrollViewContext);
232
420
  const headerFixed = isHorizontal ? true : headerFixedProp ?? contextHeaderFixed;
233
421
  const footerFixed = isHorizontal ? true : footerFixedProp ?? contextFooterFixed;
234
- (0, import_react4.useEffect)(() => {
422
+ (0, import_react5.useEffect)(() => {
235
423
  pullSearchHeightShared.value = pullSearchHeight ?? 0;
236
424
  }, [pullSearchHeight, pullSearchHeightShared]);
237
- const containerStyle = (0, import_react4.useMemo)(() => headerHeight === 0 ? [{ flex: 1 }, style] : [import_react_native3.StyleSheet.absoluteFill, style], [headerHeight, style]);
238
- const contentInset = (0, import_react4.useMemo)(() => ({ bottom: (footerFixed ? footerHeight || insets.bottom : insets.bottom) + (keyboardAware ? keyboardHeight : 0), top: headerHeight }), [footerFixed, footerHeight, insets.bottom, headerHeight, keyboardAware, keyboardHeight]);
239
- const contentOffset = (0, import_react4.useMemo)(() => ({ x: 0, y: -contentInset.top }), [contentInset.top]);
240
- const chipHidden = (0, import_react_native_reanimated4.useSharedValue)(1);
241
- const chipStyle = (0, import_react_native_reanimated4.useAnimatedStyle)(() => {
425
+ const containerStyle = (0, import_react5.useMemo)(() => headerHeight === null ? [{ flex: 1, opacity: 0 }, style] : [import_react_native3.StyleSheet.absoluteFill, style], [headerHeight, style]);
426
+ const contentInset = (0, import_react5.useMemo)(() => ({ bottom: (footerFixed ? footerHeight || insets.bottom : insets.bottom) + (keyboardAware ? keyboardHeight : 0), top: headerHeight ?? 0 }), [footerFixed, footerHeight, insets.bottom, headerHeight, keyboardAware, keyboardHeight]);
427
+ const [startedWithHeader] = (0, import_react5.useState)(headerHeight !== null);
428
+ const contentOffset = (0, import_react5.useMemo)(() => ({ x: 0, y: headerHeight !== null ? -headerHeight + (startedWithHeader && !isHorizontal && pullSearchHeight ? pullSearchHeight : 0) : 0 }), [headerHeight, isHorizontal, pullSearchHeight, startedWithHeader]);
429
+ const chipHidden = (0, import_react_native_reanimated5.useSharedValue)(1);
430
+ const chipStyle = (0, import_react_native_reanimated5.useAnimatedStyle)(() => {
242
431
  const pointerEvents = chipHidden.value ? "none" : "box-none";
243
432
  if (isHorizontal) {
244
433
  return {
245
- opacity: chipHidden.value ? (0, import_react_native_reanimated4.withTiming)(0) : (0, import_react_native_reanimated4.withTiming)(1),
434
+ opacity: chipHidden.value ? (0, import_react_native_reanimated5.withTiming)(0) : (0, import_react_native_reanimated5.withTiming)(1),
246
435
  pointerEvents,
247
- top: Math.max(headerHeight, insets.top) + 4,
248
- transform: [{ translateX: chipHidden.value ? (0, import_react_native_reanimated4.withTiming)(-CHIP_SLIDE) : (0, import_react_native_reanimated4.withTiming)(0) }]
436
+ top: Math.max(headerHeight ?? 0, insets.top) + 4,
437
+ transform: [{ translateX: chipHidden.value ? (0, import_react_native_reanimated5.withTiming)(-CHIP_SLIDE) : (0, import_react_native_reanimated5.withTiming)(0) }]
249
438
  };
250
439
  }
251
- const slide = headerFixed ? 0 : snapBackHeaderShared.value ? -headerOffset.value : Math.max(0, scrollPosition.value + headerHeight - pullSearchHeightShared.value);
252
- const top = Math.max(headerHeight - slide, insets.top) + 4;
440
+ const h = headerHeight ?? 0;
441
+ const slide = headerFixed ? 0 : snapBackHeaderShared.value ? -headerOffset.value : Math.max(0, scrollPosition.value + h - pullSearchHeightShared.value);
442
+ const top = Math.max(h - slide, insets.top) + 4;
253
443
  return {
254
- opacity: chipHidden.value ? (0, import_react_native_reanimated4.withTiming)(0) : (0, import_react_native_reanimated4.withTiming)(1),
444
+ opacity: chipHidden.value ? (0, import_react_native_reanimated5.withTiming)(0) : (0, import_react_native_reanimated5.withTiming)(1),
255
445
  pointerEvents,
256
446
  top,
257
- transform: [{ translateY: chipHidden.value ? (0, import_react_native_reanimated4.withTiming)(-CHIP_SLIDE) : (0, import_react_native_reanimated4.withTiming)(0) }]
447
+ transform: [{ translateY: chipHidden.value ? (0, import_react_native_reanimated5.withTiming)(-CHIP_SLIDE) : (0, import_react_native_reanimated5.withTiming)(0) }]
258
448
  };
259
449
  }, [isHorizontal, headerFixed, headerHeight, insets.top]);
260
450
  return { chipHidden, chipStyle, containerStyle, contentInset, contentOffset, footerFixed, headerFixed, headerHeight, insets, isHorizontal: isHorizontal ?? false };
261
451
  }
262
452
 
263
- // src/useScrollInit.ts
264
- var import_react5 = require("react");
265
- function useScrollInit({ listHeaderComponent, onMomentumScrollEnd: externalMomentumScrollEnd, onRefresh, onScrollBeginDrag: externalScrollBeginDrag, onScrollEndDrag: externalScrollEndDrag, pullSearchHeight, scrollTo }) {
266
- const { headerHeight, scrollPosition, setProgressing } = (0, import_react5.useContext)(ScrollViewContext);
267
- const hasPullSearch = pullSearchHeight !== void 0;
268
- const [phase, setPhase] = (0, import_react5.useState)(hasPullSearch ? "measuring" : "ready");
269
- const [refreshing, setRefreshing] = (0, import_react5.useState)(false);
270
- const dragStartY = (0, import_react5.useRef)(null);
271
- const deliberatelyOpened = (0, import_react5.useRef)(false);
272
- (0, import_react5.useEffect)(() => {
273
- if (phase === "ready" || !headerHeight || !pullSearchHeight) return;
274
- scrollPosition.value = -headerHeight + pullSearchHeight;
275
- setPhase("ready");
276
- }, [phase, headerHeight, pullSearchHeight, scrollPosition]);
277
- const headerInitialized = (0, import_react5.useRef)(false);
278
- (0, import_react5.useLayoutEffect)(() => {
279
- if (!headerHeight || headerInitialized.current) return;
280
- headerInitialized.current = true;
281
- scrollPosition.value = -headerHeight;
282
- scrollTo(-headerHeight, false);
283
- }, [headerHeight, scrollPosition, scrollTo]);
284
- const pullSearchInitialized = (0, import_react5.useRef)(false);
285
- (0, import_react5.useLayoutEffect)(() => {
286
- if (!hasPullSearch || phase !== "ready" || pullSearchInitialized.current || !headerHeight || !pullSearchHeight) return;
287
- pullSearchInitialized.current = true;
288
- scrollPosition.value = -headerHeight + pullSearchHeight;
289
- scrollTo(-headerHeight + pullSearchHeight, false);
290
- }, [hasPullSearch, phase, headerHeight, pullSearchHeight, scrollPosition, scrollTo]);
291
- (0, import_react5.useEffect)(() => {
292
- if (pullSearchHeight) setProgressing(refreshing);
293
- }, [pullSearchHeight, refreshing, setProgressing]);
294
- const handleScrollBeginDrag = (0, import_react5.useCallback)(
295
- (e) => {
296
- deliberatelyOpened.current = false;
297
- if (pullSearchHeight) dragStartY.current = e.nativeEvent.contentOffset.y;
298
- externalScrollBeginDrag?.(e);
299
- },
300
- [externalScrollBeginDrag, pullSearchHeight]
301
- );
302
- const handleScrollEndDrag = (0, import_react5.useCallback)(
303
- (e) => {
304
- if (pullSearchHeight && headerHeight) {
305
- const y = e.nativeEvent.contentOffset.y;
306
- const showY = -headerHeight;
307
- const hideY = -headerHeight + pullSearchHeight;
308
- const pulledDown = (dragStartY.current ?? hideY) <= hideY;
309
- dragStartY.current = null;
310
- if (pulledDown && y <= showY + pullSearchHeight * 0.5) {
311
- deliberatelyOpened.current = true;
312
- if (y <= showY && !refreshing && onRefresh) {
313
- setRefreshing(true);
314
- Promise.resolve(onRefresh()).finally(() => setRefreshing(false));
315
- }
316
- scrollTo(showY, true);
317
- } else if (y < hideY) {
318
- scrollTo(hideY, true);
319
- }
320
- }
321
- externalScrollEndDrag?.(e);
322
- },
323
- [externalScrollEndDrag, headerHeight, onRefresh, pullSearchHeight, refreshing, scrollTo]
324
- );
325
- const handleMomentumScrollEnd = (0, import_react5.useCallback)(
326
- (e) => {
327
- if (pullSearchHeight && headerHeight && !deliberatelyOpened.current && !refreshing) {
328
- const y = e.nativeEvent.contentOffset.y;
329
- const hideY = -headerHeight + pullSearchHeight;
330
- if (y < hideY - 1) scrollTo(hideY, true);
331
- }
332
- deliberatelyOpened.current = false;
333
- externalMomentumScrollEnd?.(e);
334
- },
335
- [externalMomentumScrollEnd, headerHeight, pullSearchHeight, refreshing, scrollTo]
336
- );
337
- const activeListHeader = hasPullSearch && phase === "measuring" ? null : listHeaderComponent;
338
- const hiddenHeader = phase === "measuring" && listHeaderComponent != null ? typeof listHeaderComponent === "function" ? (0, import_react5.createElement)(listHeaderComponent) : listHeaderComponent : null;
339
- return { activeListHeader, handleMomentumScrollEnd, handleScrollBeginDrag, handleScrollEndDrag, hiddenHeader, pullSearchMinHeight: pullSearchHeight ?? 0 };
340
- }
341
-
342
453
  // src/CustomList.tsx
343
454
  var import_jsx_runtime3 = require("react/jsx-runtime");
344
- var CustomListInner = ({ component: List, renderFilters, footerFixed: footerFixedProp, gesture, headerFixed: headerFixedProp, keyboardAware, onMomentumScrollEnd: externalMomentumScrollEnd, onRefresh, onScrollBeginDrag: externalScrollBeginDrag, onScrollEndDrag: externalScrollEndDrag, pullSearchHeight, scrollRef, style, ...props }) => {
455
+ var CustomListInner = ({ chipProps, chipThreshold, component: List, renderFilters, footerFixed: footerFixedProp, gesture, headerFixed: headerFixedProp, keyboardAware, onChipPress, onMomentumScrollEnd: externalMomentumScrollEnd, onRefresh, onScrollBeginDrag: externalScrollBeginDrag, onScrollEndDrag: externalScrollEndDrag, pullSearchHeight, scrollRef, style, ...props }) => {
345
456
  const { ListHeaderComponent: listHeaderComponent, contentContainerStyle: externalContentContainerStyle, ...restProps } = props;
346
457
  const { chipHidden, chipStyle, containerStyle, contentInset, contentOffset, footerFixed, headerFixed } = useScrollList({ footerFixed: footerFixedProp, headerFixed: headerFixedProp, keyboardAware, pullSearchHeight, style });
458
+ const { listGeneration, onListUnmount } = (0, import_react6.useContext)(ScrollViewContext);
459
+ const capturedGeneration = (0, import_react_native_reanimated6.useSharedValue)(-1);
460
+ (0, import_react6.useLayoutEffect)(() => {
461
+ const generation = listGeneration.value;
462
+ (0, import_react_native_reanimated6.runOnUI)((gen) => {
463
+ "worklet";
464
+ capturedGeneration.value = gen;
465
+ })(generation);
466
+ }, [capturedGeneration, listGeneration]);
467
+ (0, import_react6.useLayoutEffect)(() => () => onListUnmount(), [onListUnmount]);
347
468
  const scrollViewInternal = (0, import_react6.useRef)(null);
348
469
  const handleRef = (0, import_react6.useCallback)(
349
470
  (el) => {
@@ -361,7 +482,10 @@ var CustomListInner = ({ component: List, renderFilters, footerFixed: footerFixe
361
482
  handleScrollBeginDrag,
362
483
  handleScrollEndDrag,
363
484
  hiddenHeader,
364
- pullSearchMinHeight
485
+ onRemountSyncRetry,
486
+ onRemountSynced,
487
+ pullSearchMinHeight,
488
+ remountSyncTarget
365
489
  } = useScrollInit({
366
490
  listHeaderComponent,
367
491
  onMomentumScrollEnd: externalMomentumScrollEnd,
@@ -380,11 +504,7 @@ var CustomListInner = ({ component: List, renderFilters, footerFixed: footerFixe
380
504
  ] });
381
505
  }, [pullSearchHeader, renderFilters]);
382
506
  const contentContainerStyle = (0, import_react6.useMemo)(() => [{ minHeight: import_react_native4.Dimensions.get("window").height - contentInset.top - contentInset.bottom + pullSearchMinHeight }, externalContentContainerStyle], [contentInset.bottom, contentInset.top, externalContentContainerStyle, pullSearchMinHeight]);
383
- const onPullSearchZoneEnter = (0, import_react6.useCallback)(() => {
384
- if (!pullSearchHeight) return;
385
- scrollViewInternal.current?.scrollToOffset({ offset: -contentInset.top + pullSearchHeight, animated: true });
386
- }, [contentInset.top, pullSearchHeight]);
387
- const onScroll = useScrollHandler({ chipHidden, footerFixed, headerFixed, onPullSearchZoneEnter: pullSearchHeight ? onPullSearchZoneEnter : void 0 });
507
+ const onScroll = useScrollHandler({ capturedGeneration, chipHidden, chipThreshold, footerFixed, headerFixed, listGeneration, onRemountSyncRetry, onRemountSynced, remountSyncTarget });
388
508
  const handleScrollToTop = (0, import_react6.useCallback)(() => {
389
509
  const offset = pullSearchHeight ? -contentInset.top + pullSearchHeight : -contentInset.top;
390
510
  scrollViewInternal.current?.scrollToOffset({ offset, animated: true });
@@ -397,7 +517,7 @@ var CustomListInner = ({ component: List, renderFilters, footerFixed: footerFixe
397
517
  const content = /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native4.View, { style: containerStyle, children: [
398
518
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(TypedList, { ...restProps, contentContainerStyle, contentInset, contentOffset, ListHeaderComponent: activeListHeader, onMomentumScrollEnd: handleMomentumScrollEnd, onScroll, onScrollBeginDrag: handleScrollBeginDrag, onScrollEndDrag: handleScrollEndDrag, ref: handleRef, refreshControl, scrollEventThrottle: 16 }),
399
519
  hiddenHeader && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native4.View, { pointerEvents: "none", style: styles2.measureContainer, children: hiddenHeader }),
400
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ScrollViewChip, { onPress: handleScrollToTop, style: chipStyle })
520
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ScrollViewChip, { chipProps, onChipPress, onPress: handleScrollToTop, style: chipStyle })
401
521
  ] });
402
522
  return detectorGesture ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native_gesture_handler.GestureDetector, { gesture: detectorGesture, children: content }) : content;
403
523
  };
@@ -405,17 +525,16 @@ var styles2 = { measureContainer: { left: 0, opacity: 0, position: "absolute", r
405
525
  var CustomList = (0, import_react6.memo)(CustomListInner);
406
526
 
407
527
  // src/FlatList.tsx
408
- var import_react8 = require("react");
528
+ var import_react9 = require("react");
409
529
  var import_react_native6 = require("react-native");
410
530
  var import_react_native_gesture_handler2 = require("react-native-gesture-handler");
411
- var import_react_native_reanimated6 = __toESM(require("react-native-reanimated"));
412
531
 
413
532
  // src/internal/HorizontalDots.tsx
414
- var import_auto_paper = require("@rific/auto-paper");
533
+ var import_auto_paper2 = require("@rific/auto-paper");
415
534
  var import_react7 = require("react");
416
535
  var import_react_native5 = require("react-native");
417
- var import_react_native_paper2 = require("react-native-paper");
418
- var import_react_native_reanimated5 = __toESM(require("react-native-reanimated"));
536
+ var import_react_native_paper = require("react-native-paper");
537
+ var import_react_native_reanimated7 = __toESM(require("react-native-reanimated"));
419
538
  var import_react_native_safe_area_context2 = require("react-native-safe-area-context");
420
539
  var import_jsx_runtime4 = require("react/jsx-runtime");
421
540
  var DOT_FULL = 8;
@@ -430,36 +549,36 @@ var PILL_HEIGHT = DOT_FULL + PILL_PAD_V * 2;
430
549
  var PILL_RADIUS = PILL_HEIGHT / 2;
431
550
  var PILL_WIDTH = CLIP_WIDTH + PILL_PAD_H * 2;
432
551
  var Dot = ({ activeColor, index, inactiveColor, pageWidth, scrollPosition }) => {
433
- const circleStyle = (0, import_react_native_reanimated5.useAnimatedStyle)(() => {
552
+ const circleStyle = (0, import_react_native_reanimated7.useAnimatedStyle)(() => {
434
553
  const page = scrollPosition.value / pageWidth;
435
554
  const distance = Math.abs(index - page);
436
555
  const t = Math.max(0, Math.min((distance - 0.5) / 2, 1));
437
556
  const size = DOT_FULL + (DOT_SMALL - DOT_FULL) * t;
438
- const backgroundColor = (0, import_react_native_reanimated5.interpolateColor)(t, [0, 1], [activeColor, inactiveColor]);
557
+ const backgroundColor = (0, import_react_native_reanimated7.interpolateColor)(t, [0, 1], [activeColor, inactiveColor]);
439
558
  return { backgroundColor, borderRadius: size / 2, height: size, width: size };
440
559
  });
441
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native5.View, { style: styles3.dotContainer, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_reanimated5.default.View, { style: circleStyle }) });
560
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native5.View, { style: styles3.dotContainer, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_reanimated7.default.View, { style: circleStyle }) });
442
561
  };
443
562
  var HorizontalDots = ({ total }) => {
444
563
  const { blur, footerHeightShared, scrollPosition } = (0, import_react7.useContext)(ScrollViewContext);
445
564
  const { width } = (0, import_react_native5.useWindowDimensions)();
446
565
  const insets = (0, import_react_native_safe_area_context2.useSafeAreaInsets)();
447
- const theme = (0, import_react_native_paper2.useTheme)();
566
+ const theme = (0, import_react_native_paper.useTheme)();
448
567
  const insetsBottom = insets.bottom;
449
568
  const activeColor = theme.colors.primary;
450
569
  const inactiveColor = theme.colors.outlineVariant;
451
- const pillContainerStyle = (0, import_react_native_reanimated5.useAnimatedStyle)(() => ({
570
+ const pillContainerStyle = (0, import_react_native_reanimated7.useAnimatedStyle)(() => ({
452
571
  bottom: Math.max(footerHeightShared.value, insetsBottom) + 8
453
572
  }));
454
- const rowStyle = (0, import_react_native_reanimated5.useAnimatedStyle)(() => {
573
+ const rowStyle = (0, import_react_native_reanimated7.useAnimatedStyle)(() => {
455
574
  const page = scrollPosition.value / width;
456
575
  const maxOffset = Math.max(0, (total - CLIP_COUNT) * DOT_STEP);
457
576
  const offset = Math.max(0, Math.min((page - (CLIP_COUNT - 1) / 2) * DOT_STEP, maxOffset));
458
577
  return { transform: [{ translateX: -offset }] };
459
578
  });
460
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_reanimated5.default.View, { pointerEvents: "none", style: [styles3.pillContainer, pillContainerStyle], children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native5.View, { style: styles3.pill, children: [
461
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_auto_paper.BlurView, { blur, style: import_react_native5.StyleSheet.absoluteFill }),
462
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native5.View, { style: styles3.dotsClip, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_reanimated5.default.View, { style: [styles3.dotsRow, rowStyle], children: Array.from({ length: total }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Dot, { activeColor, index: i, inactiveColor, pageWidth: width, scrollPosition }, i)) }) })
579
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_reanimated7.default.View, { pointerEvents: "none", style: [styles3.pillContainer, pillContainerStyle], children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native5.View, { style: styles3.pill, children: [
580
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_auto_paper2.BlurView, { blur, style: import_react_native5.StyleSheet.absoluteFill }),
581
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native5.View, { style: styles3.dotsClip, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_reanimated7.default.View, { style: [styles3.dotsRow, rowStyle], children: Array.from({ length: total }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Dot, { activeColor, index: i, inactiveColor, pageWidth: width, scrollPosition }, i)) }) })
463
582
  ] }) });
464
583
  };
465
584
  var styles3 = import_react_native5.StyleSheet.create({
@@ -477,14 +596,144 @@ var styles3 = import_react_native5.StyleSheet.create({
477
596
  pillContainer: { alignItems: "center", left: 0, position: "absolute", right: 0, zIndex: 3 }
478
597
  });
479
598
 
599
+ // src/internal/useScrollHandlerJS.ts
600
+ var import_react8 = require("react");
601
+ var import_react_native_reanimated8 = require("react-native-reanimated");
602
+ var REMOUNT_RETRY_TOLERANCE = 1;
603
+ var REMOUNT_RETRY_MAX_ATTEMPTS = 8;
604
+ function useScrollHandlerJS({ capturedGeneration, chipHidden, chipThreshold = 100, footerFixed, headerFixed, isHorizontal, jsListGeneration, remountTarget = null, scrollTo }) {
605
+ const { footerHeightShared, footerOffset, headerHeightShared, headerOffset, pullSearchHeightShared, scrollPosition, snapBackFooterShared, snapBackHeaderShared } = (0, import_react8.useContext)(ScrollViewContext);
606
+ const snapUpAccum = (0, import_react8.useRef)(0);
607
+ const fromBottomBounce = (0, import_react8.useRef)(false);
608
+ const pendingRemountTarget = (0, import_react8.useRef)(remountTarget);
609
+ const remountAttempts = (0, import_react8.useRef)(0);
610
+ const onScroll = (0, import_react8.useCallback)(
611
+ (event) => {
612
+ if (jsListGeneration.current !== capturedGeneration.current) return;
613
+ const {
614
+ contentOffset: { x, y },
615
+ contentSize: { height: contentHeight },
616
+ layoutMeasurement: { height: layoutHeight }
617
+ } = event.nativeEvent;
618
+ if (pendingRemountTarget.current !== null) {
619
+ const target = pendingRemountTarget.current;
620
+ if (Math.abs(y - target) < REMOUNT_RETRY_TOLERANCE) {
621
+ pendingRemountTarget.current = null;
622
+ } else {
623
+ remountAttempts.current += 1;
624
+ if (remountAttempts.current > REMOUNT_RETRY_MAX_ATTEMPTS) {
625
+ pendingRemountTarget.current = null;
626
+ } else {
627
+ scrollTo?.(target, false);
628
+ return;
629
+ }
630
+ }
631
+ }
632
+ if (isHorizontal) {
633
+ scrollPosition.value = x;
634
+ chipHidden.value = x < chipThreshold ? 1 : 0;
635
+ return;
636
+ }
637
+ const delta = y - scrollPosition.value;
638
+ scrollPosition.value = y;
639
+ chipHidden.value = y < chipThreshold ? 1 : 0;
640
+ const maxScroll = contentHeight - layoutHeight;
641
+ if (maxScroll > 0 && y >= maxScroll) {
642
+ fromBottomBounce.current = true;
643
+ snapUpAccum.current = 0;
644
+ } else if (fromBottomBounce.current) {
645
+ fromBottomBounce.current = false;
646
+ }
647
+ const snapHeader = snapBackHeaderShared.value && !headerFixed;
648
+ const snapFooter = snapBackFooterShared.value && !footerFixed;
649
+ if (snapHeader || snapFooter) {
650
+ if (y <= -headerHeightShared.value) {
651
+ snapUpAccum.current = 0;
652
+ if (snapHeader) headerOffset.value = 0;
653
+ if (snapFooter) footerOffset.value = 0;
654
+ } else if (delta > 0) {
655
+ snapUpAccum.current = 0;
656
+ if (y >= -headerHeightShared.value + pullSearchHeightShared.value) {
657
+ if (snapHeader) headerOffset.value = Math.max(-headerHeightShared.value, Math.min(0, headerOffset.value - delta));
658
+ if (snapFooter) footerOffset.value = Math.max(0, Math.min(footerHeightShared.value, footerOffset.value + delta));
659
+ }
660
+ } else if (delta < 0 && !fromBottomBounce.current) {
661
+ if (y >= -headerHeightShared.value + pullSearchHeightShared.value) snapUpAccum.current -= delta;
662
+ if (snapUpAccum.current >= 10) {
663
+ snapUpAccum.current = 999;
664
+ if (snapHeader) headerOffset.value = (0, import_react_native_reanimated8.withTiming)(0, { duration: 200 });
665
+ if (snapFooter) footerOffset.value = (0, import_react_native_reanimated8.withTiming)(0, { duration: 200 });
666
+ }
667
+ }
668
+ }
669
+ },
670
+ [capturedGeneration, chipHidden, chipThreshold, footerFixed, footerHeightShared, footerOffset, headerFixed, headerHeightShared, headerOffset, isHorizontal, jsListGeneration, pullSearchHeightShared, scrollPosition, scrollTo, snapBackFooterShared, snapBackHeaderShared]
671
+ );
672
+ const onScrollBeginDrag = (0, import_react8.useCallback)(() => {
673
+ fromBottomBounce.current = false;
674
+ snapUpAccum.current = 0;
675
+ }, []);
676
+ const onMomentumScrollBegin = (0, import_react8.useCallback)(() => {
677
+ }, []);
678
+ const onScrollEndDrag = (0, import_react8.useCallback)(
679
+ (event) => {
680
+ if (isHorizontal) return;
681
+ const {
682
+ contentOffset: { y },
683
+ contentSize: { height: contentHeight },
684
+ layoutMeasurement: { height: layoutHeight }
685
+ } = event.nativeEvent;
686
+ if (y >= contentHeight - layoutHeight - 10) {
687
+ fromBottomBounce.current = true;
688
+ snapUpAccum.current = 0;
689
+ }
690
+ },
691
+ [isHorizontal]
692
+ );
693
+ const onMomentumScrollEnd = (0, import_react8.useCallback)(() => {
694
+ fromBottomBounce.current = false;
695
+ snapUpAccum.current = 0;
696
+ }, []);
697
+ return { onMomentumScrollBegin, onMomentumScrollEnd, onScroll, onScrollBeginDrag, onScrollEndDrag };
698
+ }
699
+
480
700
  // src/FlatList.tsx
481
701
  var import_jsx_runtime5 = require("react/jsx-runtime");
482
- var FlatListInner = ({ contentContainerStyle: externalContentContainerStyle, data, initialNumToRender = 20, maxToRenderPerBatch = 50, renderFilters, footerFixed: footerFixedProp, gesture, headerFixed: headerFixedProp, horizontal, keyboardAware, ListHeaderComponent: externalListHeaderComponent, onMomentumScrollEnd: externalMomentumScrollEnd, onRefresh, onScrollBeginDrag: externalScrollBeginDrag, onScrollEndDrag: externalScrollEndDrag, pagingEnabled, pullSearchHeight, removeClippedSubviews = false, showsHorizontalScrollIndicator, showsVerticalScrollIndicator, style, onContentSizeChange, ref: externalRef, windowSize = 100, ...props }) => {
483
- const scrollView = (0, import_react8.useRef)(null);
702
+ var FlatListInner = ({ chipProps, chipThreshold, columnWrapperStyle, contentContainerStyle: externalContentContainerStyle, data, initialNumToRender = 20, keyExtractor, maxToRenderPerBatch = 50, numColumns, renderFilters, renderItem, footerFixed: footerFixedProp, gesture, headerFixed: headerFixedProp, horizontal, keyboardAware, ListHeaderComponent: externalListHeaderComponent, onChipPress, onMomentumScrollEnd: externalMomentumScrollEnd, onRefresh, onScrollBeginDrag: externalScrollBeginDrag, onScrollEndDrag: externalScrollEndDrag, pagingEnabled, pullSearchHeight, removeClippedSubviews = false, showsHorizontalScrollIndicator, showsVerticalScrollIndicator, style, onContentSizeChange, ref: externalRef, windowSize = 100, ...props }) => {
703
+ const scrollView = (0, import_react9.useRef)(null);
484
704
  const isHorizontal = horizontal === true;
485
705
  const showDots = isHorizontal && pagingEnabled === true && (data?.length ?? 0) > 1;
706
+ const cols = numColumns && numColumns > 1 ? numColumns : 1;
707
+ const rowData = (0, import_react9.useMemo)(() => {
708
+ if (cols <= 1 || !data) return data;
709
+ const items = Array.from(data);
710
+ const rows = [];
711
+ for (let i = 0; i < items.length; i += cols) rows.push(items.slice(i, i + cols));
712
+ return rows;
713
+ }, [cols, data]);
714
+ const rowKeyExtractor = (0, import_react9.useCallback)(
715
+ (row, rowIndex) => {
716
+ if (cols <= 1) return keyExtractor ? keyExtractor(row, rowIndex) : defaultKeyExtractor(row, rowIndex);
717
+ return row.map((item, kk) => keyExtractor ? keyExtractor(item, rowIndex * cols + kk) : defaultKeyExtractor(item, rowIndex * cols + kk)).join(":");
718
+ },
719
+ [cols, keyExtractor]
720
+ );
721
+ const rowRenderItem = (0, import_react9.useCallback)(
722
+ (info) => {
723
+ if (cols <= 1) return renderItem ? renderItem(info) : null;
724
+ const row = info.item;
725
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native6.View, { style: [styles4.row, columnWrapperStyle], children: row.map((item, kk) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react9.Fragment, { children: renderItem ? renderItem({ index: info.index * cols + kk, item, separators: info.separators }) : null }, kk)) });
726
+ },
727
+ [cols, columnWrapperStyle, renderItem]
728
+ );
486
729
  const { chipHidden, chipStyle, containerStyle, contentInset, contentOffset, footerFixed, headerFixed } = useScrollList({ footerFixed: footerFixedProp, headerFixed: headerFixedProp, isHorizontal, keyboardAware, pullSearchHeight, style });
487
- const scrollTo = (0, import_react8.useCallback)((offset, animated) => {
730
+ const { jsListGeneration, onJsListUnmount } = (0, import_react9.useContext)(ScrollViewContext);
731
+ const capturedGeneration = (0, import_react9.useRef)(jsListGeneration.current);
732
+ (0, import_react9.useLayoutEffect)(() => {
733
+ capturedGeneration.current = jsListGeneration.current;
734
+ }, [jsListGeneration]);
735
+ (0, import_react9.useLayoutEffect)(() => () => onJsListUnmount(), [onJsListUnmount]);
736
+ const scrollTo = (0, import_react9.useCallback)((offset, animated) => {
488
737
  scrollView.current?.scrollToOffset({ offset, animated });
489
738
  }, []);
490
739
  const {
@@ -493,7 +742,8 @@ var FlatListInner = ({ contentContainerStyle: externalContentContainerStyle, dat
493
742
  handleScrollBeginDrag,
494
743
  handleScrollEndDrag,
495
744
  hiddenHeader,
496
- pullSearchMinHeight
745
+ pullSearchMinHeight,
746
+ remountTarget
497
747
  } = useScrollInit({
498
748
  listHeaderComponent: externalListHeaderComponent,
499
749
  onMomentumScrollEnd: externalMomentumScrollEnd,
@@ -503,7 +753,7 @@ var FlatListInner = ({ contentContainerStyle: externalContentContainerStyle, dat
503
753
  pullSearchHeight,
504
754
  scrollTo
505
755
  });
506
- const activeListHeader = (0, import_react8.useMemo)(() => {
756
+ const activeListHeader = (0, import_react9.useMemo)(() => {
507
757
  if (!renderFilters) return pullSearchHeader;
508
758
  const Inner = pullSearchHeader;
509
759
  return () => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
@@ -511,13 +761,30 @@ var FlatListInner = ({ contentContainerStyle: externalContentContainerStyle, dat
511
761
  renderFilters
512
762
  ] });
513
763
  }, [pullSearchHeader, renderFilters]);
514
- const contentContainerStyle = (0, import_react8.useMemo)(() => isHorizontal ? externalContentContainerStyle : [{ minHeight: import_react_native6.Dimensions.get("window").height - contentInset.top - contentInset.bottom + pullSearchMinHeight }, externalContentContainerStyle], [isHorizontal, contentInset.bottom, contentInset.top, externalContentContainerStyle, pullSearchMinHeight]);
515
- const onPullSearchZoneEnter = (0, import_react8.useCallback)(() => {
516
- if (!pullSearchHeight) return;
517
- scrollView.current?.scrollToOffset({ offset: -contentInset.top + pullSearchHeight, animated: true });
518
- }, [contentInset.top, pullSearchHeight]);
519
- const handleScroll = useScrollHandler({ chipHidden, footerFixed, headerFixed, isHorizontal, onPullSearchZoneEnter: pullSearchHeight ? onPullSearchZoneEnter : void 0 });
520
- const handleScrollToTop = (0, import_react8.useCallback)(() => {
764
+ const contentContainerStyle = (0, import_react9.useMemo)(() => isHorizontal ? externalContentContainerStyle : [{ minHeight: import_react_native6.Dimensions.get("window").height - contentInset.top - contentInset.bottom + pullSearchMinHeight }, externalContentContainerStyle], [isHorizontal, contentInset.bottom, contentInset.top, externalContentContainerStyle, pullSearchMinHeight]);
765
+ const scrollHandler = useScrollHandlerJS({ capturedGeneration, chipHidden, chipThreshold, footerFixed, headerFixed, isHorizontal, jsListGeneration, remountTarget, scrollTo });
766
+ const onScrollBeginDrag = (0, import_react9.useCallback)(
767
+ (e) => {
768
+ scrollHandler.onScrollBeginDrag(e);
769
+ handleScrollBeginDrag(e);
770
+ },
771
+ [scrollHandler, handleScrollBeginDrag]
772
+ );
773
+ const onScrollEndDrag = (0, import_react9.useCallback)(
774
+ (e) => {
775
+ scrollHandler.onScrollEndDrag(e);
776
+ handleScrollEndDrag(e);
777
+ },
778
+ [scrollHandler, handleScrollEndDrag]
779
+ );
780
+ const onMomentumScrollEnd = (0, import_react9.useCallback)(
781
+ (e) => {
782
+ scrollHandler.onMomentumScrollEnd(e);
783
+ handleMomentumScrollEnd(e);
784
+ },
785
+ [scrollHandler, handleMomentumScrollEnd]
786
+ );
787
+ const handleScrollToTop = (0, import_react9.useCallback)(() => {
521
788
  if (isHorizontal) {
522
789
  scrollView.current?.scrollToOffset({ offset: 0, animated: true });
523
790
  return;
@@ -525,35 +792,39 @@ var FlatListInner = ({ contentContainerStyle: externalContentContainerStyle, dat
525
792
  const offset = pullSearchHeight ? -contentInset.top + pullSearchHeight : -contentInset.top;
526
793
  scrollView.current?.scrollToOffset({ offset, animated: true });
527
794
  }, [isHorizontal, contentInset.top, pullSearchHeight]);
528
- const handleContentSizeChange = (0, import_react8.useCallback)(
795
+ const handleContentSizeChange = (0, import_react9.useCallback)(
529
796
  (w, h) => {
530
797
  if (onContentSizeChange) onContentSizeChange(w, h);
531
798
  },
532
799
  [onContentSizeChange]
533
800
  );
534
- const refreshControl = (0, import_react8.useMemo)(() => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(RefreshControl, {}), []);
535
- const nativeGesture = (0, import_react8.useMemo)(() => import_react_native_gesture_handler2.Gesture.Native(), []);
536
- const combinedGesture = (0, import_react8.useMemo)(() => gesture !== void 0 ? import_react_native_gesture_handler2.Gesture.Simultaneous(gesture, nativeGesture) : nativeGesture, [gesture, nativeGesture]);
801
+ const refreshControl = (0, import_react9.useMemo)(() => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(RefreshControl, {}), []);
802
+ const nativeGesture = (0, import_react9.useMemo)(() => import_react_native_gesture_handler2.Gesture.Native(), []);
803
+ const combinedGesture = (0, import_react9.useMemo)(() => gesture !== void 0 ? import_react_native_gesture_handler2.Gesture.Simultaneous(gesture, nativeGesture) : nativeGesture, [gesture, nativeGesture]);
537
804
  const detectorGesture = gesture !== void 0 ? combinedGesture : void 0;
538
805
  const content = /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native6.View, { style: containerStyle, children: [
539
806
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
540
- import_react_native_reanimated6.default.FlatList,
807
+ import_react_native6.FlatList,
541
808
  {
542
809
  ...props,
543
810
  contentContainerStyle,
544
811
  contentInset,
812
+ contentInsetAdjustmentBehavior: "never",
545
813
  contentOffset,
546
- data,
814
+ data: cols > 1 ? rowData : data,
547
815
  horizontal: isHorizontal,
548
816
  initialNumToRender,
817
+ keyExtractor: cols > 1 ? rowKeyExtractor : keyExtractor,
549
818
  ListHeaderComponent: activeListHeader,
550
819
  maxToRenderPerBatch,
551
820
  onContentSizeChange: handleContentSizeChange,
552
- onMomentumScrollEnd: handleMomentumScrollEnd,
553
- onScroll: handleScroll,
554
- onScrollBeginDrag: handleScrollBeginDrag,
555
- onScrollEndDrag: handleScrollEndDrag,
821
+ onMomentumScrollBegin: scrollHandler.onMomentumScrollBegin,
822
+ onMomentumScrollEnd,
823
+ onScroll: scrollHandler.onScroll,
824
+ onScrollBeginDrag,
825
+ onScrollEndDrag,
556
826
  pagingEnabled,
827
+ renderItem: cols > 1 ? rowRenderItem : renderItem,
557
828
  ref: (el) => {
558
829
  if (externalRef) externalRef.current = el;
559
830
  scrollView.current = el;
@@ -567,52 +838,56 @@ var FlatListInner = ({ contentContainerStyle: externalContentContainerStyle, dat
567
838
  }
568
839
  ),
569
840
  hiddenHeader && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native6.View, { pointerEvents: "none", style: styles4.measureContainer, children: hiddenHeader }),
570
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ScrollViewChip, { isHorizontal, onPress: handleScrollToTop, style: chipStyle }),
841
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ScrollViewChip, { chipProps, isHorizontal, onChipPress, onPress: handleScrollToTop, style: chipStyle }),
571
842
  showDots && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(HorizontalDots, { total: data?.length ?? 0 })
572
843
  ] });
573
844
  return detectorGesture ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native_gesture_handler2.GestureDetector, { gesture: detectorGesture, children: content }) : content;
574
845
  };
575
- var styles4 = { measureContainer: { left: 0, opacity: 0, position: "absolute", right: 0, top: -9999 } };
576
- var FlatList = (0, import_react8.memo)(FlatListInner);
846
+ var defaultKeyExtractor = (item, index) => {
847
+ const key = item?.key ?? item?.id;
848
+ return key != null ? String(key) : String(index);
849
+ };
850
+ var styles4 = { measureContainer: { left: 0, opacity: 0, position: "absolute", right: 0, top: -9999 }, row: { flexDirection: "row" } };
851
+ var FlatList = (0, import_react9.memo)(FlatListInner);
577
852
 
578
853
  // src/PullSearch.tsx
579
- var import_react9 = require("react");
854
+ var import_react10 = require("react");
580
855
  var import_react_native7 = require("react-native");
581
- var import_react_native_paper3 = require("react-native-paper");
582
- var import_react_native_reanimated7 = __toESM(require("react-native-reanimated"));
856
+ var import_react_native_paper2 = require("react-native-paper");
857
+ var import_react_native_reanimated9 = __toESM(require("react-native-reanimated"));
583
858
  var import_jsx_runtime6 = require("react/jsx-runtime");
584
- var PullSearch = (0, import_react9.forwardRef)(function PullSearch2({ debounce, onChangeText, onHeightChange, placeholder, value: propValue }, ref) {
585
- const { headerHeight, scrollPosition } = (0, import_react9.useContext)(ScrollViewContext);
586
- const theme = (0, import_react_native_paper3.useTheme)();
587
- const inputRef = (0, import_react9.useRef)(null);
588
- const [barHeight, setBarHeight] = (0, import_react9.useState)(0);
589
- const [value, setValue] = (0, import_react9.useState)(propValue ?? "");
590
- const prevPropValueRef = (0, import_react9.useRef)(propValue);
591
- (0, import_react9.useEffect)(() => {
859
+ var PullSearch = (0, import_react10.forwardRef)(function PullSearch2({ debounce, onChangeText, onHeightChange, placeholder, value: propValue }, ref) {
860
+ const { headerHeight, scrollPosition } = (0, import_react10.useContext)(ScrollViewContext);
861
+ const theme = (0, import_react_native_paper2.useTheme)();
862
+ const inputRef = (0, import_react10.useRef)(null);
863
+ const [barHeight, setBarHeight] = (0, import_react10.useState)(0);
864
+ const [value, setValue] = (0, import_react10.useState)(propValue ?? "");
865
+ const prevPropValueRef = (0, import_react10.useRef)(propValue);
866
+ (0, import_react10.useEffect)(() => {
592
867
  if (prevPropValueRef.current === propValue) return;
593
868
  prevPropValueRef.current = propValue;
594
869
  setValue(propValue ?? "");
595
870
  }, [propValue]);
596
- (0, import_react9.useImperativeHandle)(ref, () => ({
871
+ (0, import_react10.useImperativeHandle)(ref, () => ({
597
872
  blur: () => inputRef.current?.blur(),
598
873
  focus: () => inputRef.current?.focus()
599
874
  }));
600
- const blurInput = (0, import_react9.useCallback)(() => inputRef.current?.blur(), []);
601
- (0, import_react_native_reanimated7.useAnimatedReaction)(
875
+ const blurInput = (0, import_react10.useCallback)(() => inputRef.current?.blur(), []);
876
+ (0, import_react_native_reanimated9.useAnimatedReaction)(
602
877
  () => {
603
878
  if (barHeight === 0) return false;
604
- return scrollPosition.value >= -headerHeight + barHeight;
879
+ return scrollPosition.value >= -(headerHeight ?? 0) + barHeight;
605
880
  },
606
881
  (isHidden, wasHidden) => {
607
- if (isHidden && !wasHidden) (0, import_react_native_reanimated7.runOnJS)(blurInput)();
882
+ if (isHidden && !wasHidden) (0, import_react_native_reanimated9.runOnJS)(blurInput)();
608
883
  },
609
884
  [barHeight, headerHeight, blurInput]
610
885
  );
611
- const handleClear = (0, import_react9.useCallback)(() => {
886
+ const handleClear = (0, import_react10.useCallback)(() => {
612
887
  setValue("");
613
888
  onChangeText("");
614
889
  }, [onChangeText]);
615
- const handleLayout = (0, import_react9.useCallback)(
890
+ const handleLayout = (0, import_react10.useCallback)(
616
891
  ({
617
892
  nativeEvent: {
618
893
  layout: { height }
@@ -623,7 +898,7 @@ var PullSearch = (0, import_react9.forwardRef)(function PullSearch2({ debounce,
623
898
  },
624
899
  [onHeightChange]
625
900
  );
626
- (0, import_react9.useEffect)(() => {
901
+ (0, import_react10.useEffect)(() => {
627
902
  const normalizedValue = value.trim();
628
903
  if (debounce) {
629
904
  const timeout = setTimeout(() => onChangeText(normalizedValue), 500);
@@ -631,13 +906,14 @@ var PullSearch = (0, import_react9.forwardRef)(function PullSearch2({ debounce,
631
906
  }
632
907
  onChangeText(normalizedValue);
633
908
  }, [debounce, onChangeText, value]);
634
- const animatedStyle = (0, import_react_native_reanimated7.useAnimatedStyle)(() => {
909
+ const animatedStyle = (0, import_react_native_reanimated9.useAnimatedStyle)(() => {
635
910
  if (barHeight === 0) return { opacity: 0 };
636
- const showY = -headerHeight;
637
- const hideY = -headerHeight + barHeight;
638
- return { opacity: (0, import_react_native_reanimated7.interpolate)(scrollPosition.value, [showY, hideY], [1, 0], import_react_native_reanimated7.Extrapolation.CLAMP) };
911
+ const h = headerHeight ?? 0;
912
+ const showY = -h;
913
+ const hideY = -h + barHeight;
914
+ return { opacity: (0, import_react_native_reanimated9.interpolate)(scrollPosition.value, [showY, hideY], [1, 0], import_react_native_reanimated9.Extrapolation.CLAMP) };
639
915
  }, [barHeight, headerHeight]);
640
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native_reanimated7.default.View, { onLayout: handleLayout, style: [styles5.container, animatedStyle], children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native_paper3.Searchbar, { autoCorrect: false, onChangeText: (text) => setValue((text || "").trimStart()), onClearIconPress: handleClear, placeholder, placeholderTextColor: theme.colors.onSurfaceVariant, ref: inputRef, spellCheck: false, style: styles5.input, value }) });
916
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native_reanimated9.default.View, { onLayout: handleLayout, style: [styles5.container, animatedStyle], children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native_paper2.Searchbar, { autoCorrect: false, onChangeText: (text) => setValue((text || "").trimStart()), onClearIconPress: handleClear, placeholder, placeholderTextColor: theme.colors.onSurfaceVariant, ref: inputRef, spellCheck: false, style: styles5.input, value }) });
641
917
  });
642
918
  var styles5 = import_react_native7.StyleSheet.create({
643
919
  container: { paddingVertical: 8 },
@@ -1138,6 +1414,24 @@ var objectTraps = {
1138
1414
  get(state, prop) {
1139
1415
  if (prop === DRAFT_STATE)
1140
1416
  return state;
1417
+ if (prop === "constructor" || prop === "__proto__") {
1418
+ const source2 = latest(state);
1419
+ const value2 = source2[prop];
1420
+ return new Proxy(value2 || {}, {
1421
+ get: (target, key) => {
1422
+ if (key === "__proto__" || key === "prototype") {
1423
+ return Object.freeze(/* @__PURE__ */ Object.create(null));
1424
+ }
1425
+ return Reflect.get(target, key);
1426
+ },
1427
+ set: () => {
1428
+ return true;
1429
+ },
1430
+ apply: (target, thisArg, args) => {
1431
+ return Reflect.apply(target, thisArg, args);
1432
+ }
1433
+ });
1434
+ }
1141
1435
  let arrayPlugin = state.scope_.arrayMethodsPlugin_;
1142
1436
  const isArrayWithStringProp = state.type_ === 1 && typeof prop === "string";
1143
1437
  if (isArrayWithStringProp) {
@@ -1167,12 +1461,18 @@ var objectTraps = {
1167
1461
  return value;
1168
1462
  },
1169
1463
  has(state, prop) {
1464
+ if (prop === "constructor" || prop === "__proto__" || prop === "prototype") {
1465
+ return false;
1466
+ }
1170
1467
  return prop in latest(state);
1171
1468
  },
1172
1469
  ownKeys(state) {
1173
1470
  return Reflect.ownKeys(latest(state));
1174
1471
  },
1175
1472
  set(state, prop, value) {
1473
+ if (prop === "constructor" || prop === "__proto__" || prop === "prototype") {
1474
+ return true;
1475
+ }
1176
1476
  const desc = getDescriptorFromProto(latest(state), prop);
1177
1477
  if (desc?.set) {
1178
1478
  desc.set.call(state.draft_, value);
@@ -1192,7 +1492,7 @@ var objectTraps = {
1192
1492
  markChanged(state);
1193
1493
  }
1194
1494
  if (state.copy_[prop] === value && // special case: handle new props with value 'undefined'
1195
- (value !== void 0 || prop in state.copy_) || // special case: NaN
1495
+ (value !== void 0 || has(state.copy_, prop, state.type_)) || // special case: NaN
1196
1496
  Number.isNaN(value) && Number.isNaN(state.copy_[prop]))
1197
1497
  return true;
1198
1498
  state.copy_[prop] = value;
@@ -2183,14 +2483,14 @@ function formatProdErrorMessage(code) {
2183
2483
  }
2184
2484
 
2185
2485
  // src/ScrollViewSettingsContext.ts
2186
- var import_react10 = require("react");
2486
+ var import_react11 = require("react");
2187
2487
  var defaultScrollViewSettings = {
2188
2488
  backActionFixed: true,
2189
2489
  footerFixed: false,
2190
2490
  headerFixed: false,
2191
2491
  snapBack: false
2192
2492
  };
2193
- var ScrollViewSettingsContext = (0, import_react10.createContext)({
2493
+ var ScrollViewSettingsContext = (0, import_react11.createContext)({
2194
2494
  settings: defaultScrollViewSettings,
2195
2495
  set: () => {
2196
2496
  }
@@ -2208,16 +2508,26 @@ var scrollViewActions = slice.actions;
2208
2508
  var scrollViewReducer = slice.reducer;
2209
2509
 
2210
2510
  // src/ScrollView.tsx
2211
- var import_react11 = require("react");
2511
+ var import_react12 = require("react");
2212
2512
  var import_react_native8 = require("react-native");
2213
2513
  var import_react_native_gesture_handler3 = require("react-native-gesture-handler");
2214
- var import_react_native_reanimated8 = __toESM(require("react-native-reanimated"));
2514
+ var import_react_native_reanimated10 = __toESM(require("react-native-reanimated"));
2215
2515
  var import_jsx_runtime7 = require("react/jsx-runtime");
2216
- var ScrollViewInner = ({ children, footerFixed: footerFixedProp, gesture, headerFixed: headerFixedProp, horizontal, keyboardAware, onMomentumScrollEnd: externalMomentumScrollEnd, onRefresh, onScrollBeginDrag: externalScrollBeginDrag, onScrollEndDrag: externalScrollEndDrag, pullSearchHeight, refreshing, style, ...props }) => {
2217
- const scrollView = (0, import_react11.useRef)(null);
2516
+ var ScrollViewInner = ({ chipProps, chipThreshold, children, footerFixed: footerFixedProp, gesture, headerFixed: headerFixedProp, horizontal, keyboardAware, onChipPress, onMomentumScrollEnd: externalMomentumScrollEnd, onRefresh, onScrollBeginDrag: externalScrollBeginDrag, onScrollEndDrag: externalScrollEndDrag, pullSearchHeight, refreshing, style, ...props }) => {
2517
+ const scrollView = (0, import_react12.useRef)(null);
2218
2518
  const isHorizontal = horizontal === true;
2219
2519
  const { chipHidden, chipStyle, containerStyle, contentInset, contentOffset, footerFixed, headerFixed } = useScrollList({ footerFixed: footerFixedProp, headerFixed: headerFixedProp, isHorizontal, keyboardAware, pullSearchHeight, style });
2220
- const scrollTo = (0, import_react11.useCallback)((offset, animated) => {
2520
+ const { listGeneration, onListUnmount } = (0, import_react12.useContext)(ScrollViewContext);
2521
+ const capturedGeneration = (0, import_react_native_reanimated10.useSharedValue)(-1);
2522
+ (0, import_react12.useLayoutEffect)(() => {
2523
+ const generation = listGeneration.value;
2524
+ (0, import_react_native_reanimated10.runOnUI)((gen) => {
2525
+ "worklet";
2526
+ capturedGeneration.value = gen;
2527
+ })(generation);
2528
+ }, [capturedGeneration, listGeneration]);
2529
+ (0, import_react12.useLayoutEffect)(() => () => onListUnmount(), [onListUnmount]);
2530
+ const scrollTo = (0, import_react12.useCallback)((offset, animated) => {
2221
2531
  scrollView.current?.scrollTo({ y: offset, animated });
2222
2532
  }, []);
2223
2533
  const { handleMomentumScrollEnd, handleScrollBeginDrag, handleScrollEndDrag } = useScrollInit({
@@ -2227,12 +2537,8 @@ var ScrollViewInner = ({ children, footerFixed: footerFixedProp, gesture, header
2227
2537
  pullSearchHeight,
2228
2538
  scrollTo
2229
2539
  });
2230
- const onPullSearchZoneEnter = (0, import_react11.useCallback)(() => {
2231
- if (!pullSearchHeight) return;
2232
- scrollTo(-contentInset.top + pullSearchHeight, true);
2233
- }, [contentInset.top, pullSearchHeight, scrollTo]);
2234
- const handleScroll = useScrollHandler({ chipHidden, footerFixed, headerFixed, isHorizontal, onPullSearchZoneEnter: pullSearchHeight ? onPullSearchZoneEnter : void 0 });
2235
- const handleScrollToTop = (0, import_react11.useCallback)(() => {
2540
+ const handleScroll = useScrollHandler({ capturedGeneration, chipHidden, chipThreshold, footerFixed, headerFixed, isHorizontal, listGeneration });
2541
+ const handleScrollToTop = (0, import_react12.useCallback)(() => {
2236
2542
  if (isHorizontal) {
2237
2543
  scrollView.current?.scrollTo({ x: 0, animated: true });
2238
2544
  return;
@@ -2240,13 +2546,13 @@ var ScrollViewInner = ({ children, footerFixed: footerFixedProp, gesture, header
2240
2546
  const offset = pullSearchHeight ? -contentInset.top + pullSearchHeight : -contentInset.top;
2241
2547
  scrollView.current?.scrollTo({ y: offset, animated: true });
2242
2548
  }, [isHorizontal, contentInset.top, pullSearchHeight]);
2243
- const refreshControl = (0, import_react11.useMemo)(() => onRefresh ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(RefreshControl, { onRefresh, refreshing: refreshing ?? false }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(RefreshControl, {}), [onRefresh, refreshing]);
2244
- const nativeGesture = (0, import_react11.useMemo)(() => import_react_native_gesture_handler3.Gesture.Native(), []);
2245
- const combinedGesture = (0, import_react11.useMemo)(() => gesture !== void 0 ? import_react_native_gesture_handler3.Gesture.Simultaneous(gesture, nativeGesture) : nativeGesture, [gesture, nativeGesture]);
2549
+ const refreshControl = (0, import_react12.useMemo)(() => onRefresh ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(RefreshControl, { onRefresh, refreshing: refreshing ?? false }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(RefreshControl, {}), [onRefresh, refreshing]);
2550
+ const nativeGesture = (0, import_react12.useMemo)(() => import_react_native_gesture_handler3.Gesture.Native(), []);
2551
+ const combinedGesture = (0, import_react12.useMemo)(() => gesture !== void 0 ? import_react_native_gesture_handler3.Gesture.Simultaneous(gesture, nativeGesture) : nativeGesture, [gesture, nativeGesture]);
2246
2552
  const detectorGesture = gesture !== void 0 ? combinedGesture : void 0;
2247
2553
  const content = /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native8.View, { style: containerStyle, children: [
2248
2554
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2249
- import_react_native_reanimated8.default.ScrollView,
2555
+ import_react_native_reanimated10.default.ScrollView,
2250
2556
  {
2251
2557
  ...props,
2252
2558
  contentInset,
@@ -2264,23 +2570,23 @@ var ScrollViewInner = ({ children, footerFixed: footerFixedProp, gesture, header
2264
2570
  children
2265
2571
  }
2266
2572
  ),
2267
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ScrollViewChip, { isHorizontal, onPress: handleScrollToTop, style: chipStyle })
2573
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ScrollViewChip, { chipProps, isHorizontal, onChipPress, onPress: handleScrollToTop, style: chipStyle })
2268
2574
  ] });
2269
2575
  return detectorGesture ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_gesture_handler3.GestureDetector, { gesture: detectorGesture, children: content }) : content;
2270
2576
  };
2271
- var ScrollView = (0, import_react11.memo)(ScrollViewInner);
2577
+ var ScrollView = (0, import_react12.memo)(ScrollViewInner);
2272
2578
 
2273
2579
  // src/ScrollViewFooter.tsx
2274
- var import_auto_paper2 = require("@rific/auto-paper");
2275
- var import_react12 = require("react");
2580
+ var import_auto_paper3 = require("@rific/auto-paper");
2581
+ var import_react13 = require("react");
2276
2582
  var import_react_native9 = require("react-native");
2277
- var import_react_native_reanimated9 = __toESM(require("react-native-reanimated"));
2583
+ var import_react_native_reanimated11 = __toESM(require("react-native-reanimated"));
2278
2584
  var import_react_native_safe_area_context3 = require("react-native-safe-area-context");
2279
2585
  var import_jsx_runtime8 = require("react/jsx-runtime");
2280
2586
  var ScrollViewFooter = ({ children, style }) => {
2281
- const { blur, footerHeight, footerFixed, footerOffset, headerHeightShared, pullSearchHeightShared, scrollPosition, setFooterHeight, snapBackFooterShared } = (0, import_react12.useContext)(ScrollViewContext);
2587
+ const { blur, footerHeight, footerFixed, footerOffset, headerHeightShared, pullSearchHeightShared, scrollPosition, setFooterHeight, snapBackFooterShared } = (0, import_react13.useContext)(ScrollViewContext);
2282
2588
  const insets = (0, import_react_native_safe_area_context3.useSafeAreaInsets)();
2283
- (0, import_react12.useEffect)(
2589
+ (0, import_react13.useEffect)(
2284
2590
  () => () => {
2285
2591
  setFooterHeight(0);
2286
2592
  },
@@ -2293,15 +2599,15 @@ var ScrollViewFooter = ({ children, style }) => {
2293
2599
  }) => {
2294
2600
  if (footerHeight !== height) setFooterHeight(height);
2295
2601
  };
2296
- const footerStyle = (0, import_react_native_reanimated9.useAnimatedStyle)(() => {
2602
+ const footerStyle = (0, import_react_native_reanimated11.useAnimatedStyle)(() => {
2297
2603
  if (footerFixed) return { transform: [{ translateY: 0 }] };
2298
2604
  if (snapBackFooterShared.value) return { transform: [{ translateY: footerOffset.value }] };
2299
2605
  const effective = scrollPosition.value + headerHeightShared.value - pullSearchHeightShared.value;
2300
2606
  if (effective <= 0) return { transform: [{ translateY: 0 }] };
2301
2607
  return { transform: [{ translateY: Math.min(effective, footerHeight) }] };
2302
2608
  }, [footerHeight, footerFixed]);
2303
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native_reanimated9.default.View, { onLayout: handleLayout, pointerEvents: "box-none", style: [styles6.footer, footerStyle], children: [
2304
- footerHeight > 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_auto_paper2.BlurView, { blur, style: import_react_native9.StyleSheet.absoluteFill }),
2609
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native_reanimated11.default.View, { onLayout: handleLayout, pointerEvents: "box-none", style: [styles6.footer, footerStyle], children: [
2610
+ footerHeight > 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_auto_paper3.BlurView, { blur, style: import_react_native9.StyleSheet.absoluteFill }),
2305
2611
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native9.View, { style: [styles6.row, { paddingBottom: insets.bottom }, style], children })
2306
2612
  ] });
2307
2613
  };
@@ -2311,20 +2617,20 @@ var styles6 = import_react_native9.StyleSheet.create({
2311
2617
  });
2312
2618
 
2313
2619
  // src/ScrollViewHeader.tsx
2314
- var import_auto_paper3 = require("@rific/auto-paper");
2315
- var import_react13 = require("react");
2620
+ var import_auto_paper4 = require("@rific/auto-paper");
2621
+ var import_react14 = require("react");
2316
2622
  var import_react_native10 = require("react-native");
2317
- var import_react_native_paper4 = require("react-native-paper");
2318
- var import_react_native_reanimated10 = __toESM(require("react-native-reanimated"));
2623
+ var import_react_native_paper3 = require("react-native-paper");
2624
+ var import_react_native_reanimated12 = __toESM(require("react-native-reanimated"));
2319
2625
  var import_react_native_safe_area_context4 = require("react-native-safe-area-context");
2320
2626
  var import_jsx_runtime9 = require("react/jsx-runtime");
2321
- var ActionBg = ({ blur, style }) => blur ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native10.View, { style: [import_react_native10.StyleSheet.absoluteFill, styles7.actionBg, style], children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_auto_paper3.BlurView, { blur: true, style: import_react_native10.StyleSheet.absoluteFill }) }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native10.View, { style: [import_react_native10.StyleSheet.absoluteFill, styles7.actionBg, style], pointerEvents: "none", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper4.Surface, { style: import_react_native10.StyleSheet.absoluteFill, elevation: 1, children: null }) });
2627
+ var ActionBg = ({ blur, style }) => blur ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native10.View, { style: [import_react_native10.StyleSheet.absoluteFill, styles7.actionBg, style], children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_auto_paper4.BlurView, { blur: true, style: import_react_native10.StyleSheet.absoluteFill }) }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native10.View, { style: [import_react_native10.StyleSheet.absoluteFill, styles7.actionBg, style], pointerEvents: "none", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper3.Surface, { style: import_react_native10.StyleSheet.absoluteFill, elevation: 1, children: null }) });
2322
2628
  var ScrollViewHeader = ({ actionSize = 48, actionStyle, backAction, backActionFixed, caption, centerContent, children, iconSize, style, title, topInset = true, trailingAction, trailingActionFixed = true }) => {
2323
- const { blur, headerHeight, headerFixed, headerOffset, progress, progressing, pullSearchHeightShared, scrollPosition, setHeaderHeight, snapBackHeaderShared } = (0, import_react13.useContext)(ScrollViewContext);
2324
- const { settings } = (0, import_react13.useContext)(ScrollViewSettingsContext);
2629
+ const { blur, headerHeight, headerFixed, headerOffset, progress, progressing, pullSearchHeightShared, scrollPosition, setHeaderHeight, snapBackHeaderShared } = (0, import_react14.useContext)(ScrollViewContext);
2630
+ const { settings } = (0, import_react14.useContext)(ScrollViewSettingsContext);
2325
2631
  const effectiveBackActionFixed = backActionFixed ?? settings.backActionFixed;
2326
2632
  const insets = (0, import_react_native_safe_area_context4.useSafeAreaInsets)();
2327
- const theme = (0, import_react_native_paper4.useTheme)();
2633
+ const theme = (0, import_react_native_paper3.useTheme)();
2328
2634
  const top = topInset ? insets.top : 0;
2329
2635
  const handleLayout = ({
2330
2636
  nativeEvent: {
@@ -2333,23 +2639,25 @@ var ScrollViewHeader = ({ actionSize = 48, actionStyle, backAction, backActionFi
2333
2639
  }) => {
2334
2640
  if (headerHeight !== height) setHeaderHeight(height);
2335
2641
  };
2336
- const translateStyle = (0, import_react_native_reanimated10.useAnimatedStyle)(() => {
2642
+ const translateStyle = (0, import_react_native_reanimated12.useAnimatedStyle)(() => {
2337
2643
  if (headerFixed) return { transform: [{ translateY: 0 }] };
2338
2644
  if (snapBackHeaderShared.value) return { transform: [{ translateY: headerOffset.value }] };
2339
- const effective = scrollPosition.value + headerHeight - pullSearchHeightShared.value;
2645
+ const effective = scrollPosition.value + (headerHeight ?? 0) - pullSearchHeightShared.value;
2340
2646
  if (effective <= 0) return { transform: [{ translateY: 0 }] };
2341
2647
  return { transform: [{ translateY: -effective }] };
2342
2648
  }, [headerFixed, headerHeight]);
2343
- const blurStyle = (0, import_react_native_reanimated10.useAnimatedStyle)(() => {
2649
+ const blurStyle = (0, import_react_native_reanimated12.useAnimatedStyle)(() => {
2344
2650
  if (!headerHeight) return { height: 0 };
2345
2651
  if (headerFixed) return { height: headerHeight };
2346
- const translateY = snapBackHeaderShared.value ? headerOffset.value : -Math.max(0, scrollPosition.value + headerHeight - pullSearchHeightShared.value);
2347
- return { height: Math.max(headerHeight + translateY, top) };
2652
+ const h = headerHeight ?? 0;
2653
+ const translateY = snapBackHeaderShared.value ? headerOffset.value : -Math.max(0, scrollPosition.value + h - pullSearchHeightShared.value);
2654
+ return { height: Math.max(h + translateY, top) };
2348
2655
  }, [headerFixed, headerHeight, top]);
2349
- const progressStyle = (0, import_react_native_reanimated10.useAnimatedStyle)(() => {
2350
- if (headerFixed) return { top: headerHeight };
2351
- const slide = snapBackHeaderShared.value ? -headerOffset.value : Math.max(0, scrollPosition.value + headerHeight - pullSearchHeightShared.value);
2352
- return { top: Math.max(headerHeight - slide, top) };
2656
+ const progressStyle = (0, import_react_native_reanimated12.useAnimatedStyle)(() => {
2657
+ const h = headerHeight ?? 0;
2658
+ if (headerFixed) return { top: h };
2659
+ const slide = snapBackHeaderShared.value ? -headerOffset.value : Math.max(0, scrollPosition.value + h - pullSearchHeightShared.value);
2660
+ return { top: Math.max(h - slide, top) };
2353
2661
  }, [headerFixed, headerHeight, top]);
2354
2662
  const actionMargin = 4;
2355
2663
  const contentMinHeight = actionSize + 2 * actionMargin;
@@ -2359,12 +2667,11 @@ var ScrollViewHeader = ({ actionSize = 48, actionStyle, backAction, backActionFi
2359
2667
  const leadingStyle = { alignItems: "center", height: actionSize, justifyContent: "center", left: actionMargin, position: "absolute", top: actionTop, width: actionSize, zIndex: 3, ...actionShadow };
2360
2668
  const trailingStyle = { alignItems: "center", height: actionSize, justifyContent: "center", position: "absolute", right: actionMargin, top: actionTop, width: actionSize, zIndex: 3, ...actionShadow };
2361
2669
  return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
2362
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_reanimated10.default.View, { pointerEvents: "none", style: [styles7.blur, blurStyle], children: headerHeight > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_auto_paper3.BlurView, { blur, style: [styles7.blurInner, { height: headerHeight }] }) }),
2363
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native_reanimated10.default.View, { onLayout: handleLayout, pointerEvents: "box-none", style: [headerHeight === 0 ? styles7.headerInit : styles7.header, translateStyle], children: [
2364
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native10.View, { style: [{ paddingTop: top }, style], children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: [styles7.content, { minHeight: contentMinHeight }], children: [
2670
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_reanimated12.default.View, { pointerEvents: "none", style: [styles7.blur, blurStyle], children: headerHeight !== null && headerHeight > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_auto_paper4.BlurView, { blur, style: [styles7.blurInner, { height: headerHeight }] }) }),
2671
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native_reanimated12.default.View, { onLayout: handleLayout, pointerEvents: "box-none", style: [headerHeight === null ? styles7.headerInit : styles7.header, translateStyle], children: [
2672
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native10.View, { style: [{ paddingTop: top }, style], children: children ?? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: [styles7.content, { minHeight: contentMinHeight }], children: [
2365
2673
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native10.View, { style: styles7.side }),
2366
2674
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native10.View, { style: styles7.spacer }),
2367
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native10.View, { style: styles7.side, children }),
2368
2675
  (centerContent || title || caption) && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native10.View, { style: [import_react_native10.StyleSheet.absoluteFill, styles7.titleContainer], pointerEvents: centerContent ? "box-none" : "none", children: centerContent ?? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
2369
2676
  title && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native10.Text, { numberOfLines: 1, style: [styles7.title, { color: theme.colors.onSurface }], children: title }),
2370
2677
  caption && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native10.Text, { numberOfLines: 1, style: [styles7.caption, { color: theme.colors.onSurfaceVariant }], children: caption })
@@ -2372,18 +2679,18 @@ var ScrollViewHeader = ({ actionSize = 48, actionStyle, backAction, backActionFi
2372
2679
  ] }) }),
2373
2680
  !blur && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native10.View, { style: [styles7.divider, { backgroundColor: theme.colors.outlineVariant }] })
2374
2681
  ] }),
2375
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_reanimated10.default.View, { pointerEvents: "none", style: [styles7.progress, progressStyle], children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper4.ProgressBar, { indeterminate: progress === null, visible: progressing, progress: progress ?? void 0 }) }),
2376
- backAction && (effectiveBackActionFixed ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native_reanimated10.default.View, { style: leadingStyle, children: [
2682
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_reanimated12.default.View, { pointerEvents: "none", style: [styles7.progress, progressStyle], children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper3.ProgressBar, { indeterminate: progress === null, visible: progressing, progress: progress ?? void 0 }) }),
2683
+ backAction && (effectiveBackActionFixed ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native_reanimated12.default.View, { style: leadingStyle, children: [
2377
2684
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ActionBg, { blur, style: actionStyle }),
2378
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper4.Appbar.BackAction, { onPress: backAction, size: iconSize ?? actionSize / 2, style: buttonStyle })
2379
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native_reanimated10.default.View, { style: [leadingStyle, translateStyle], children: [
2685
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper3.Appbar.BackAction, { onPress: backAction, size: iconSize ?? actionSize / 2, style: buttonStyle })
2686
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native_reanimated12.default.View, { style: [leadingStyle, translateStyle], children: [
2380
2687
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ActionBg, { blur, style: actionStyle }),
2381
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper4.Appbar.BackAction, { onPress: backAction, size: iconSize ?? actionSize / 2, style: buttonStyle })
2688
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper3.Appbar.BackAction, { onPress: backAction, size: iconSize ?? actionSize / 2, style: buttonStyle })
2382
2689
  ] })),
2383
2690
  trailingAction && (trailingActionFixed ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: trailingStyle, children: [
2384
2691
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ActionBg, { blur, style: actionStyle }),
2385
2692
  trailingAction
2386
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native_reanimated10.default.View, { style: [trailingStyle, translateStyle], children: [
2693
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native_reanimated12.default.View, { style: [trailingStyle, translateStyle], children: [
2387
2694
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ActionBg, { blur, style: actionStyle }),
2388
2695
  trailingAction
2389
2696
  ] }))
@@ -2406,63 +2713,78 @@ var styles7 = import_react_native10.StyleSheet.create({
2406
2713
  });
2407
2714
 
2408
2715
  // src/ScrollViewProvider.tsx
2409
- var import_auto_paper4 = require("@rific/auto-paper");
2410
- var import_react14 = require("react");
2716
+ var import_auto_paper5 = require("@rific/auto-paper");
2717
+ var import_react15 = require("react");
2411
2718
  var import_react_native11 = require("react-native");
2412
- var import_react_native_reanimated11 = require("react-native-reanimated");
2719
+ var import_react_native_reanimated13 = require("react-native-reanimated");
2413
2720
  var import_jsx_runtime10 = require("react/jsx-runtime");
2414
2721
  var ScrollViewProvider = ({ blur, children, fixed = false, footerFixed, headerFixed, snapBack, snapBackFooter, snapBackHeader, tabBarHeight = 60 }) => {
2415
- const { settings } = (0, import_react14.useContext)(ScrollViewSettingsContext);
2416
- const effectiveBlur = (0, import_auto_paper4.useBlur)(blur);
2722
+ const { settings } = (0, import_react15.useContext)(ScrollViewSettingsContext);
2723
+ const effectiveBlur = (0, import_auto_paper5.useBlur)(blur);
2417
2724
  const effectiveSnapBack = snapBack ?? settings.snapBack;
2418
2725
  const effectiveSnapBackHeader = snapBackHeader ?? settings.snapBackHeader;
2419
2726
  const effectiveSnapBackFooter = snapBackFooter ?? settings.snapBackFooter;
2420
- const [headerHeight, setHeaderHeightState] = (0, import_react14.useState)(0);
2421
- const [footerHeight, setFooterHeightState] = (0, import_react14.useState)(0);
2422
- const [progress, setProgress] = (0, import_react14.useState)(null);
2423
- const [progressing, setProgressing] = (0, import_react14.useState)(false);
2424
- const scrollPosition = (0, import_react_native_reanimated11.useSharedValue)(0);
2425
- const headerHeightShared = (0, import_react_native_reanimated11.useSharedValue)(0);
2426
- const footerHeightShared = (0, import_react_native_reanimated11.useSharedValue)(0);
2427
- const headerOffset = (0, import_react_native_reanimated11.useSharedValue)(0);
2428
- const footerOffset = (0, import_react_native_reanimated11.useSharedValue)(0);
2429
- const pullSearchHeightShared = (0, import_react_native_reanimated11.useSharedValue)(0);
2430
- const snapBackHeaderShared = (0, import_react_native_reanimated11.useSharedValue)(false);
2431
- const snapBackFooterShared = (0, import_react_native_reanimated11.useSharedValue)(false);
2432
- (0, import_react14.useEffect)(() => {
2727
+ const [headerHeight, setHeaderHeightState] = (0, import_react15.useState)(null);
2728
+ const [footerHeight, setFooterHeightState] = (0, import_react15.useState)(0);
2729
+ const [progress, setProgress] = (0, import_react15.useState)(null);
2730
+ const [progressing, setProgressing] = (0, import_react15.useState)(false);
2731
+ const scrollPosition = (0, import_react_native_reanimated13.useSharedValue)(0);
2732
+ const listGeneration = (0, import_react_native_reanimated13.useSharedValue)(0);
2733
+ const jsListGeneration = (0, import_react15.useRef)(0);
2734
+ const headerHeightShared = (0, import_react_native_reanimated13.useSharedValue)(0);
2735
+ const footerHeightShared = (0, import_react_native_reanimated13.useSharedValue)(0);
2736
+ const headerOffset = (0, import_react_native_reanimated13.useSharedValue)(0);
2737
+ const footerOffset = (0, import_react_native_reanimated13.useSharedValue)(0);
2738
+ const pullSearchHeightShared = (0, import_react_native_reanimated13.useSharedValue)(0);
2739
+ const snapBackHeaderShared = (0, import_react_native_reanimated13.useSharedValue)(false);
2740
+ const snapBackFooterShared = (0, import_react_native_reanimated13.useSharedValue)(false);
2741
+ (0, import_react15.useEffect)(() => {
2433
2742
  snapBackHeaderShared.value = effectiveSnapBackHeader ?? effectiveSnapBack;
2434
2743
  snapBackFooterShared.value = effectiveSnapBackFooter ?? effectiveSnapBack;
2435
2744
  }, [effectiveSnapBack, effectiveSnapBackFooter, effectiveSnapBackHeader, snapBackFooterShared, snapBackHeaderShared]);
2436
- const setHeaderHeight = (0, import_react14.useCallback)(
2745
+ const setHeaderHeight = (0, import_react15.useCallback)(
2437
2746
  (h) => {
2438
2747
  setHeaderHeightState(h);
2439
- headerHeightShared.value = h;
2748
+ headerHeightShared.value = h ?? 0;
2440
2749
  },
2441
2750
  [headerHeightShared]
2442
2751
  );
2443
- const setFooterHeight = (0, import_react14.useCallback)(
2752
+ const onListUnmount = (0, import_react15.useCallback)(() => {
2753
+ listGeneration.value += 1;
2754
+ }, [listGeneration]);
2755
+ const onJsListUnmount = (0, import_react15.useCallback)(() => {
2756
+ jsListGeneration.current += 1;
2757
+ }, []);
2758
+ (0, import_react15.useEffect)(() => {
2759
+ if (!__DEV__ || headerHeight !== null) return;
2760
+ const timeout = setTimeout(() => {
2761
+ console.warn("[scroll-view] No ScrollViewHeader ever measured inside this ScrollViewProvider \u2014 scroll content stays hidden (opacity: 0) until one does. Render a <ScrollViewHeader> (it can be empty / zero height) inside this provider.");
2762
+ }, 3e3);
2763
+ return () => clearTimeout(timeout);
2764
+ }, [headerHeight]);
2765
+ const setFooterHeight = (0, import_react15.useCallback)(
2444
2766
  (h) => {
2445
2767
  setFooterHeightState(h);
2446
2768
  footerHeightShared.value = h;
2447
2769
  },
2448
2770
  [footerHeightShared]
2449
2771
  );
2450
- const scrollHeight = (0, import_react14.useMemo)(() => import_react_native11.Dimensions.get("window").height - headerHeight - footerHeight, [headerHeight, footerHeight]);
2772
+ const scrollHeight = (0, import_react15.useMemo)(() => import_react_native11.Dimensions.get("window").height - (headerHeight ?? 0) - footerHeight, [headerHeight, footerHeight]);
2451
2773
  const effectiveHeaderFixed = fixed || (headerFixed ?? settings.headerFixed);
2452
2774
  const effectiveFooterFixed = fixed || (footerFixed ?? settings.footerFixed);
2453
- const value = (0, import_react14.useMemo)(() => ({ blur: effectiveBlur, footerHeight, footerHeightShared, footerFixed: effectiveFooterFixed, footerOffset, headerHeight, headerHeightShared, headerFixed: effectiveHeaderFixed, headerOffset, progress, pullSearchHeightShared, progressing, scrollHeight, scrollPosition, setFooterHeight, setHeaderHeight, setProgress, setProgressing, snapBackFooterShared, snapBackHeaderShared, tabBarHeight }), [effectiveBlur, effectiveFooterFixed, effectiveHeaderFixed, footerHeight, footerHeightShared, footerOffset, headerHeight, headerHeightShared, headerOffset, progress, pullSearchHeightShared, progressing, scrollHeight, scrollPosition, setFooterHeight, setHeaderHeight, snapBackFooterShared, snapBackHeaderShared, tabBarHeight]);
2775
+ const value = (0, import_react15.useMemo)(() => ({ blur: effectiveBlur, footerHeight, footerHeightShared, footerFixed: effectiveFooterFixed, footerOffset, headerHeight, headerHeightShared, headerFixed: effectiveHeaderFixed, headerOffset, jsListGeneration, listGeneration, onJsListUnmount, onListUnmount, progress, pullSearchHeightShared, progressing, scrollHeight, scrollPosition, setFooterHeight, setHeaderHeight, setProgress, setProgressing, snapBackFooterShared, snapBackHeaderShared, tabBarHeight }), [effectiveBlur, effectiveFooterFixed, effectiveHeaderFixed, footerHeight, footerHeightShared, footerOffset, headerHeight, headerHeightShared, headerOffset, jsListGeneration, listGeneration, onJsListUnmount, onListUnmount, progress, pullSearchHeightShared, progressing, scrollHeight, scrollPosition, setFooterHeight, setHeaderHeight, snapBackFooterShared, snapBackHeaderShared, tabBarHeight]);
2454
2776
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ScrollViewContext.Provider, { value, children });
2455
2777
  };
2456
2778
 
2457
2779
  // src/ScrollViewSettingsProvider.tsx
2458
- var import_react15 = require("react");
2780
+ var import_react16 = require("react");
2459
2781
  var import_jsx_runtime11 = require("react/jsx-runtime");
2460
- var ScrollViewSettingsProvider = ({ children, onChange, value }) => {
2461
- const [settings, setSettings] = (0, import_react15.useState)(() => ({
2782
+ var ScrollViewSettingsProvider = ({ children, onChange, initialValue }) => {
2783
+ const [settings, setSettings] = (0, import_react16.useState)(() => ({
2462
2784
  ...defaultScrollViewSettings,
2463
- ...value
2785
+ ...initialValue
2464
2786
  }));
2465
- const set2 = (0, import_react15.useCallback)(
2787
+ const set2 = (0, import_react16.useCallback)(
2466
2788
  (patch) => {
2467
2789
  setSettings((prev) => {
2468
2790
  const next = { ...prev, ...patch };
@@ -2472,33 +2794,33 @@ var ScrollViewSettingsProvider = ({ children, onChange, value }) => {
2472
2794
  },
2473
2795
  [onChange]
2474
2796
  );
2475
- const ctx = (0, import_react15.useMemo)(() => ({ settings, set: set2 }), [settings, set2]);
2797
+ const ctx = (0, import_react16.useMemo)(() => ({ settings, set: set2 }), [settings, set2]);
2476
2798
  return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ScrollViewSettingsContext.Provider, { value: ctx, children });
2477
2799
  };
2478
2800
 
2479
2801
  // src/SectionList.tsx
2480
- var import_react17 = require("react");
2802
+ var import_react18 = require("react");
2481
2803
  var import_react_native12 = require("react-native");
2482
2804
  var import_react_native_gesture_handler4 = require("react-native-gesture-handler");
2483
- var import_react_native_reanimated13 = __toESM(require("react-native-reanimated"));
2805
+ var import_react_native_reanimated15 = __toESM(require("react-native-reanimated"));
2484
2806
 
2485
2807
  // src/internal/useStickyHeaders.ts
2486
- var import_react16 = require("react");
2487
- var import_react_native_reanimated12 = require("react-native-reanimated");
2808
+ var import_react17 = require("react");
2809
+ var import_react_native_reanimated14 = require("react-native-reanimated");
2488
2810
  var import_react_native_safe_area_context5 = require("react-native-safe-area-context");
2489
2811
  function useStickyHeaders(headerFixed, enabled) {
2490
- const { headerHeightShared, headerOffset, pullSearchHeightShared, scrollPosition, snapBackHeaderShared } = (0, import_react16.useContext)(ScrollViewContext);
2812
+ const { headerHeightShared, headerOffset, pullSearchHeightShared, scrollPosition, snapBackHeaderShared } = (0, import_react17.useContext)(ScrollViewContext);
2491
2813
  const insetsTop = (0, import_react_native_safe_area_context5.useSafeAreaInsets)().top;
2492
- const sectionYPositions = (0, import_react_native_reanimated12.useSharedValue)([]);
2493
- const sectionHeights = (0, import_react_native_reanimated12.useSharedValue)([]);
2494
- const [activeIndex, setActiveIndex] = (0, import_react16.useState)(-1);
2495
- const contentIndexShared = (0, import_react_native_reanimated12.useSharedValue)(-1);
2496
- (0, import_react16.useLayoutEffect)(() => {
2814
+ const sectionYPositions = (0, import_react_native_reanimated14.useSharedValue)([]);
2815
+ const sectionHeights = (0, import_react_native_reanimated14.useSharedValue)([]);
2816
+ const [activeIndex, setActiveIndex] = (0, import_react17.useState)(-1);
2817
+ const contentIndexShared = (0, import_react_native_reanimated14.useSharedValue)(-1);
2818
+ (0, import_react17.useLayoutEffect)(() => {
2497
2819
  contentIndexShared.value = activeIndex;
2498
2820
  }, [activeIndex, contentIndexShared]);
2499
- const positionsCache = (0, import_react16.useRef)([]);
2500
- const heightsCache = (0, import_react16.useRef)([]);
2501
- (0, import_react_native_reanimated12.useAnimatedReaction)(
2821
+ const positionsCache = (0, import_react17.useRef)([]);
2822
+ const heightsCache = (0, import_react17.useRef)([]);
2823
+ (0, import_react_native_reanimated14.useAnimatedReaction)(
2502
2824
  () => {
2503
2825
  if (!enabled) return -1;
2504
2826
  const positions = sectionYPositions.value;
@@ -2523,11 +2845,11 @@ function useStickyHeaders(headerFixed, enabled) {
2523
2845
  return active;
2524
2846
  },
2525
2847
  (curr, prev) => {
2526
- if (curr !== prev) (0, import_react_native_reanimated12.runOnJS)(setActiveIndex)(curr);
2848
+ if (curr !== prev) (0, import_react_native_reanimated14.runOnJS)(setActiveIndex)(curr);
2527
2849
  },
2528
2850
  [enabled, headerFixed, insetsTop]
2529
2851
  );
2530
- const clipStyle = (0, import_react_native_reanimated12.useAnimatedStyle)(() => {
2852
+ const clipStyle = (0, import_react_native_reanimated14.useAnimatedStyle)(() => {
2531
2853
  const hHeight = headerHeightShared.value;
2532
2854
  const scrollPos = scrollPosition.value;
2533
2855
  let stickyTop;
@@ -2541,7 +2863,7 @@ function useStickyHeaders(headerFixed, enabled) {
2541
2863
  }
2542
2864
  return { top: stickyTop };
2543
2865
  }, [enabled, headerFixed, insetsTop]);
2544
- const overlayStyle = (0, import_react_native_reanimated12.useAnimatedStyle)(() => {
2866
+ const overlayStyle = (0, import_react_native_reanimated14.useAnimatedStyle)(() => {
2545
2867
  const hidden = { opacity: 0, top: 0, transform: [{ translateY: 0 }] };
2546
2868
  if (!enabled) return hidden;
2547
2869
  const index = contentIndexShared.value;
@@ -2569,7 +2891,7 @@ function useStickyHeaders(headerFixed, enabled) {
2569
2891
  }
2570
2892
  return { opacity: 1, top: 0, transform: [{ translateY }] };
2571
2893
  }, [enabled, headerFixed, insetsTop]);
2572
- const measureHeader = (0, import_react16.useCallback)(
2894
+ const measureHeader = (0, import_react17.useCallback)(
2573
2895
  (index, pageY, height) => {
2574
2896
  const contentY = pageY + scrollPosition.value;
2575
2897
  positionsCache.current[index] = contentY;
@@ -2579,7 +2901,7 @@ function useStickyHeaders(headerFixed, enabled) {
2579
2901
  },
2580
2902
  [scrollPosition, sectionHeights, sectionYPositions]
2581
2903
  );
2582
- const resetPositions = (0, import_react16.useCallback)(
2904
+ const resetPositions = (0, import_react17.useCallback)(
2583
2905
  (count) => {
2584
2906
  positionsCache.current = Array.from({ length: count }, () => -1);
2585
2907
  sectionYPositions.value = positionsCache.current.slice();
@@ -2593,18 +2915,27 @@ function useStickyHeaders(headerFixed, enabled) {
2593
2915
 
2594
2916
  // src/SectionList.tsx
2595
2917
  var import_jsx_runtime12 = require("react/jsx-runtime");
2596
- var AnimatedSectionList = (0, import_react_native_reanimated13.createAnimatedComponent)(import_react_native12.SectionList);
2597
- var SectionListInner = ({ contentContainerStyle: externalContentContainerStyle, initialNumToRender = 20, maxToRenderPerBatch = 50, renderFilters, footerFixed: footerFixedProp, gesture, headerFixed: headerFixedProp, keyboardAware, ListHeaderComponent: externalListHeaderComponent, onMomentumScrollEnd: externalMomentumScrollEnd, onRefresh, onContentSizeChange, onScrollBeginDrag: externalScrollBeginDrag, onScrollEndDrag: externalScrollEndDrag, pullSearchHeight, refreshing, removeClippedSubviews = false, sections, showsVerticalScrollIndicator, style, ref: externalRef, windowSize = 100, ...props }) => {
2598
- const scrollView = (0, import_react17.useRef)(null);
2918
+ var AnimatedSectionList = import_react_native_reanimated15.default.createAnimatedComponent(import_react_native12.SectionList);
2919
+ var SectionListInner = ({ chipProps, chipThreshold, contentContainerStyle: externalContentContainerStyle, initialNumToRender = 20, maxToRenderPerBatch = 50, renderFilters, footerFixed: footerFixedProp, gesture, headerFixed: headerFixedProp, keyboardAware, ListHeaderComponent: externalListHeaderComponent, onChipPress, onMomentumScrollEnd: externalMomentumScrollEnd, onRefresh, onContentSizeChange, onScrollBeginDrag: externalScrollBeginDrag, onScrollEndDrag: externalScrollEndDrag, pullSearchHeight, refreshing, removeClippedSubviews = false, sections, showsVerticalScrollIndicator, style, ref: externalRef, windowSize = 100, ...props }) => {
2920
+ const scrollView = (0, import_react18.useRef)(null);
2599
2921
  const { stickySectionHeadersEnabled = true, renderSectionHeader, ...passThroughProps } = props;
2600
2922
  const { chipHidden, chipStyle, containerStyle, contentInset, contentOffset, footerFixed, headerFixed, headerHeight } = useScrollList({ footerFixed: footerFixedProp, headerFixed: headerFixedProp, keyboardAware, pullSearchHeight, style });
2923
+ const { listGeneration, onListUnmount } = (0, import_react18.useContext)(ScrollViewContext);
2924
+ const capturedGeneration = (0, import_react_native_reanimated15.useSharedValue)(-1);
2925
+ (0, import_react18.useLayoutEffect)(() => {
2926
+ const generation = listGeneration.value;
2927
+ (0, import_react_native_reanimated15.runOnUI)((gen) => {
2928
+ "worklet";
2929
+ capturedGeneration.value = gen;
2930
+ })(generation);
2931
+ }, [capturedGeneration, listGeneration]);
2601
2932
  const usesCustomSticky = stickySectionHeadersEnabled && renderSectionHeader != null;
2602
2933
  const { activeIndex, clipStyle, measureHeader, overlayStyle, resetPositions } = useStickyHeaders(headerFixed, usesCustomSticky);
2603
- (0, import_react17.useLayoutEffect)(() => {
2934
+ (0, import_react18.useLayoutEffect)(() => {
2604
2935
  if (usesCustomSticky) resetPositions(sections.length);
2605
2936
  }, [sections, usesCustomSticky, resetPositions, headerHeight]);
2606
- const sectionViewRefs = (0, import_react17.useRef)(/* @__PURE__ */ new Map());
2607
- const wrappedRenderSectionHeader = (0, import_react17.useMemo)(() => {
2937
+ const sectionViewRefs = (0, import_react18.useRef)(/* @__PURE__ */ new Map());
2938
+ const wrappedRenderSectionHeader = (0, import_react18.useMemo)(() => {
2608
2939
  if (!usesCustomSticky) return renderSectionHeader ?? void 0;
2609
2940
  return (info) => {
2610
2941
  const idx = sections.findIndex((s) => s === info.section);
@@ -2625,7 +2956,8 @@ var SectionListInner = ({ contentContainerStyle: externalContentContainerStyle,
2625
2956
  );
2626
2957
  };
2627
2958
  }, [usesCustomSticky, renderSectionHeader, sections, measureHeader]);
2628
- const scrollTo = (0, import_react17.useCallback)((offset, animated) => {
2959
+ (0, import_react18.useLayoutEffect)(() => () => onListUnmount(), [onListUnmount]);
2960
+ const scrollTo = (0, import_react18.useCallback)((offset, animated) => {
2629
2961
  scrollView.current?.getScrollResponder()?.scrollTo({ y: offset, animated });
2630
2962
  }, []);
2631
2963
  const {
@@ -2643,7 +2975,7 @@ var SectionListInner = ({ contentContainerStyle: externalContentContainerStyle,
2643
2975
  pullSearchHeight,
2644
2976
  scrollTo
2645
2977
  });
2646
- const activeListHeader = (0, import_react17.useMemo)(() => {
2978
+ const activeListHeader = (0, import_react18.useMemo)(() => {
2647
2979
  if (!renderFilters) return pullSearchHeader;
2648
2980
  const Inner = pullSearchHeader;
2649
2981
  return () => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
@@ -2651,8 +2983,8 @@ var SectionListInner = ({ contentContainerStyle: externalContentContainerStyle,
2651
2983
  renderFilters
2652
2984
  ] });
2653
2985
  }, [pullSearchHeader, renderFilters]);
2654
- const pullSearchSettled = (0, import_react17.useRef)(false);
2655
- (0, import_react17.useEffect)(() => {
2986
+ const pullSearchSettled = (0, import_react18.useRef)(false);
2987
+ (0, import_react18.useEffect)(() => {
2656
2988
  if (!usesCustomSticky || activeListHeader == null || pullSearchSettled.current) return;
2657
2989
  pullSearchSettled.current = true;
2658
2990
  const handle = requestAnimationFrame(() => {
@@ -2664,25 +2996,21 @@ var SectionListInner = ({ contentContainerStyle: externalContentContainerStyle,
2664
2996
  });
2665
2997
  return () => cancelAnimationFrame(handle);
2666
2998
  }, [activeListHeader, usesCustomSticky, measureHeader]);
2667
- const contentContainerStyle = (0, import_react17.useMemo)(() => [{ minHeight: import_react_native12.Dimensions.get("window").height - contentInset.top - contentInset.bottom + pullSearchMinHeight }, externalContentContainerStyle], [contentInset.bottom, contentInset.top, externalContentContainerStyle, pullSearchMinHeight]);
2668
- const onPullSearchZoneEnter = (0, import_react17.useCallback)(() => {
2669
- if (!pullSearchHeight) return;
2670
- scrollTo(-contentInset.top + pullSearchHeight, true);
2671
- }, [contentInset.top, pullSearchHeight, scrollTo]);
2672
- const handleScroll = useScrollHandler({ chipHidden, footerFixed, headerFixed, onPullSearchZoneEnter: pullSearchHeight ? onPullSearchZoneEnter : void 0 });
2673
- const handleScrollToTop = (0, import_react17.useCallback)(() => {
2999
+ const contentContainerStyle = (0, import_react18.useMemo)(() => [{ minHeight: import_react_native12.Dimensions.get("window").height - contentInset.top - contentInset.bottom + pullSearchMinHeight }, externalContentContainerStyle], [contentInset.bottom, contentInset.top, externalContentContainerStyle, pullSearchMinHeight]);
3000
+ const handleScroll = useScrollHandler({ capturedGeneration, chipHidden, chipThreshold, footerFixed, headerFixed, listGeneration });
3001
+ const handleScrollToTop = (0, import_react18.useCallback)(() => {
2674
3002
  const offset = pullSearchHeight ? -contentInset.top + pullSearchHeight : -contentInset.top;
2675
3003
  scrollView.current?.getScrollResponder()?.scrollTo({ y: offset, animated: true });
2676
3004
  }, [contentInset.top, pullSearchHeight]);
2677
- const handleContentSizeChange = (0, import_react17.useCallback)(
3005
+ const handleContentSizeChange = (0, import_react18.useCallback)(
2678
3006
  (w, h) => {
2679
3007
  if (onContentSizeChange) onContentSizeChange(w, h);
2680
3008
  },
2681
3009
  [onContentSizeChange]
2682
3010
  );
2683
- const refreshControl = (0, import_react17.useMemo)(() => onRefresh ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(RefreshControl, { onRefresh, refreshing: refreshing ?? false }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(RefreshControl, {}), [onRefresh, refreshing]);
2684
- const nativeGesture = (0, import_react17.useMemo)(() => import_react_native_gesture_handler4.Gesture.Native(), []);
2685
- const combinedGesture = (0, import_react17.useMemo)(() => gesture !== void 0 ? import_react_native_gesture_handler4.Gesture.Simultaneous(gesture, nativeGesture) : nativeGesture, [gesture, nativeGesture]);
3011
+ const refreshControl = (0, import_react18.useMemo)(() => onRefresh ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(RefreshControl, { onRefresh, refreshing: refreshing ?? false }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(RefreshControl, {}), [onRefresh, refreshing]);
3012
+ const nativeGesture = (0, import_react18.useMemo)(() => import_react_native_gesture_handler4.Gesture.Native(), []);
3013
+ const combinedGesture = (0, import_react18.useMemo)(() => gesture !== void 0 ? import_react_native_gesture_handler4.Gesture.Simultaneous(gesture, nativeGesture) : nativeGesture, [gesture, nativeGesture]);
2686
3014
  const detectorGesture = gesture !== void 0 ? combinedGesture : void 0;
2687
3015
  const content = /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_react_native12.View, { style: containerStyle, children: [
2688
3016
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
@@ -2713,11 +3041,11 @@ var SectionListInner = ({ contentContainerStyle: externalContentContainerStyle,
2713
3041
  stickySectionHeadersEnabled: false,
2714
3042
  windowSize
2715
3043
  },
2716
- headerHeight > 0 ? 1 : 0
3044
+ headerHeight !== null && headerHeight > 0 ? 1 : 0
2717
3045
  ),
2718
3046
  hiddenHeader && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native12.View, { pointerEvents: "none", style: styles8.measureContainer, children: hiddenHeader }),
2719
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ScrollViewChip, { onPress: handleScrollToTop, style: chipStyle }),
2720
- usesCustomSticky && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native_reanimated13.default.View, { pointerEvents: "none", style: [styles8.stickyClip, clipStyle], children: activeIndex >= 0 && activeIndex < sections.length && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native_reanimated13.default.View, { style: [styles8.stickyOverlay, overlayStyle], children: renderSectionHeader({ section: sections[activeIndex] }) }) })
3047
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ScrollViewChip, { chipProps, onChipPress, onPress: handleScrollToTop, style: chipStyle }),
3048
+ usesCustomSticky && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native_reanimated15.default.View, { pointerEvents: "none", style: [styles8.stickyClip, clipStyle], children: activeIndex >= 0 && activeIndex < sections.length && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native_reanimated15.default.View, { style: [styles8.stickyOverlay, overlayStyle], children: renderSectionHeader({ section: sections[activeIndex] }) }) })
2721
3049
  ] });
2722
3050
  return detectorGesture ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native_gesture_handler4.GestureDetector, { gesture: detectorGesture, children: content }) : content;
2723
3051
  };
@@ -2726,18 +3054,18 @@ var styles8 = {
2726
3054
  stickyClip: { bottom: 0, left: 0, overflow: "hidden", position: "absolute", right: 0, zIndex: 2 },
2727
3055
  stickyOverlay: { left: 0, position: "absolute", right: 0 }
2728
3056
  };
2729
- var SectionList = (0, import_react17.memo)(SectionListInner);
3057
+ var SectionList = (0, import_react18.memo)(SectionListInner);
2730
3058
 
2731
3059
  // src/useScrollView.ts
2732
- var import_react18 = require("react");
3060
+ var import_react19 = require("react");
2733
3061
  var useScrollView = () => {
2734
- const { progress, progressing, scrollHeight, scrollPosition, setProgress, setProgressing } = (0, import_react18.useContext)(ScrollViewContext);
3062
+ const { progress, progressing, scrollHeight, scrollPosition, setProgress, setProgressing } = (0, import_react19.useContext)(ScrollViewContext);
2735
3063
  return { progress, progressing, scrollHeight, scrollPosition, setProgress, setProgressing };
2736
3064
  };
2737
3065
 
2738
3066
  // src/useScrollViewSettings.ts
2739
- var import_react19 = require("react");
2740
- var useScrollViewSettings = () => (0, import_react19.useContext)(ScrollViewSettingsContext);
3067
+ var import_react20 = require("react");
3068
+ var useScrollViewSettings = () => (0, import_react20.useContext)(ScrollViewSettingsContext);
2741
3069
  // Annotate the CommonJS export names for ESM import in node:
2742
3070
  0 && (module.exports = {
2743
3071
  CustomList,