@rific/scroll-view 0.2.0 → 0.4.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.
Files changed (35) hide show
  1. package/README.md +2 -0
  2. package/dist/index.d.mts +23 -17
  3. package/dist/index.d.ts +23 -17
  4. package/dist/index.js +720 -1960
  5. package/dist/index.mjs +697 -1939
  6. package/package.json +10 -10
  7. package/src/CustomList.tsx +32 -8
  8. package/src/FlatList.tsx +102 -20
  9. package/src/PullSearch.tsx +4 -3
  10. package/src/ScrollView.tsx +28 -8
  11. package/src/ScrollViewContext.ts +17 -4
  12. package/src/ScrollViewHeader.tsx +34 -31
  13. package/src/ScrollViewProvider.tsx +22 -6
  14. package/src/SectionList.tsx +31 -10
  15. package/src/internal/useScrollHandler.ts +19 -21
  16. package/src/internal/useScrollHandlerJS.ts +141 -0
  17. package/src/internal/useScrollList.ts +16 -11
  18. package/src/redux/scrollViewSlice.ts +19 -11
  19. package/src/useScrollInit.ts +200 -19
  20. package/src/__mocks__/auto-paper.ts +0 -9
  21. package/src/__mocks__/flash-list.ts +0 -20
  22. package/src/__mocks__/react-native-gesture-handler.ts +0 -13
  23. package/src/__mocks__/react-native-keyboard-controller.ts +0 -11
  24. package/src/__mocks__/react-native-paper.ts +0 -22
  25. package/src/__mocks__/react-native-reanimated.ts +0 -30
  26. package/src/__mocks__/react-native-safe-area-context.ts +0 -2
  27. package/src/__mocks__/react-native.ts +0 -30
  28. package/src/__tests__/CustomList.test.tsx +0 -61
  29. package/src/__tests__/FlatList.test.tsx +0 -52
  30. package/src/__tests__/PullSearch.test.tsx +0 -38
  31. package/src/__tests__/ScrollView.test.tsx +0 -23
  32. package/src/__tests__/ScrollViewHeader.test.tsx +0 -28
  33. package/src/__tests__/ScrollViewProvider.test.tsx +0 -65
  34. package/src/__tests__/SectionList.test.tsx +0 -88
  35. package/src/out.txt +0 -61
package/dist/index.mjs CHANGED
@@ -1,11 +1,8 @@
1
- var __defProp = Object.defineProperty;
2
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
- var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
-
5
1
  // src/CustomList.tsx
6
- import { memo, useCallback as useCallback2, useMemo as useMemo2, useRef as useRef2 } from "react";
2
+ import { memo, useCallback as useCallback2, useContext as useContext4, useLayoutEffect as useLayoutEffect2, useMemo as useMemo2, useRef as useRef2 } from "react";
7
3
  import { Dimensions, View } from "react-native";
8
4
  import { Gesture, GestureDetector } from "react-native-gesture-handler";
5
+ import { runOnUI, useSharedValue as useSharedValue4 } from "react-native-reanimated";
9
6
 
10
7
  // src/internal/RefreshControl.tsx
11
8
  import { RefreshControl as RNRefreshControl } from "react-native";
@@ -31,8 +28,8 @@ var styles = StyleSheet.create({
31
28
  });
32
29
 
33
30
  // src/internal/useScrollHandler.ts
34
- import { useContext } from "react";
35
- import { runOnJS, useAnimatedScrollHandler, useSharedValue, withTiming } from "react-native-reanimated";
31
+ import { useContext as useContext2 } from "react";
32
+ import { runOnJS, useAnimatedScrollHandler, useSharedValue as useSharedValue2, withTiming } from "react-native-reanimated";
36
33
 
37
34
  // src/ScrollViewContext.ts
38
35
  import { createContext } from "react";
@@ -42,10 +39,16 @@ var ScrollViewContext = createContext({
42
39
  footerHeightShared: null,
43
40
  footerFixed: false,
44
41
  footerOffset: null,
45
- headerHeight: 0,
42
+ headerHeight: null,
46
43
  headerHeightShared: null,
47
44
  headerFixed: false,
48
45
  headerOffset: null,
46
+ jsListGeneration: { current: 0 },
47
+ listGeneration: null,
48
+ onJsListUnmount: () => {
49
+ },
50
+ onListUnmount: () => {
51
+ },
49
52
  progress: null,
50
53
  progressing: false,
51
54
  pullSearchHeightShared: null,
@@ -64,17 +67,207 @@ var ScrollViewContext = createContext({
64
67
  tabBarHeight: 60
65
68
  });
66
69
 
70
+ // src/useScrollInit.ts
71
+ import { createElement, useCallback, useContext, useEffect, useLayoutEffect, useRef, useState } from "react";
72
+ import { useSharedValue } from "react-native-reanimated";
73
+ var REMOUNT_SYNC_MAX_ATTEMPTS = 8;
74
+ var REMOUNT_SYNC_TOLERANCE = 1;
75
+ var REMOUNT_SYNC_FALLBACK_MS = 500;
76
+ var REMOUNT_PRIME_FRAMES = 40;
77
+ var SNAP_VERIFY_TOLERANCE = 1;
78
+ var SNAP_VERIFY_MAX_ATTEMPTS = 5;
79
+ var SNAP_VERIFY_INITIAL_DELAY_MS = 400;
80
+ var SNAP_VERIFY_RETRY_DELAY_MS = 150;
81
+ function useScrollInit({ listHeaderComponent, onMomentumScrollEnd: externalMomentumScrollEnd, onRefresh, onScrollBeginDrag: externalScrollBeginDrag, onScrollEndDrag: externalScrollEndDrag, pullSearchHeight, scrollTo }) {
82
+ const { headerHeight, scrollPosition, setProgressing } = useContext(ScrollViewContext);
83
+ const hasPullSearch = pullSearchHeight !== void 0;
84
+ const [phase, setPhase] = useState(hasPullSearch && !headerHeight ? "measuring" : "ready");
85
+ const [refreshing, setRefreshing] = useState(false);
86
+ const refreshingRef = useRef(refreshing);
87
+ useEffect(() => {
88
+ refreshingRef.current = refreshing;
89
+ }, [refreshing]);
90
+ const dragStartY = useRef(null);
91
+ const pendingSnapTarget = useRef(null);
92
+ const snapVerifyTimeout = useRef(null);
93
+ const snapVerifyAttempts = useRef(0);
94
+ const scheduleSnapVerification = useCallback(
95
+ (target, delay) => {
96
+ if (snapVerifyTimeout.current !== null) clearTimeout(snapVerifyTimeout.current);
97
+ pendingSnapTarget.current = target;
98
+ snapVerifyAttempts.current = 0;
99
+ const check = () => {
100
+ snapVerifyTimeout.current = null;
101
+ if (pendingSnapTarget.current !== target) return;
102
+ if (Math.abs(scrollPosition.value - target) <= SNAP_VERIFY_TOLERANCE) {
103
+ pendingSnapTarget.current = null;
104
+ return;
105
+ }
106
+ snapVerifyAttempts.current += 1;
107
+ if (snapVerifyAttempts.current > SNAP_VERIFY_MAX_ATTEMPTS || refreshingRef.current) {
108
+ pendingSnapTarget.current = null;
109
+ return;
110
+ }
111
+ scrollTo(target, false);
112
+ snapVerifyTimeout.current = setTimeout(check, SNAP_VERIFY_RETRY_DELAY_MS);
113
+ };
114
+ snapVerifyTimeout.current = setTimeout(check, delay);
115
+ },
116
+ [scrollPosition, scrollTo]
117
+ );
118
+ useEffect(
119
+ () => () => {
120
+ if (snapVerifyTimeout.current !== null) clearTimeout(snapVerifyTimeout.current);
121
+ },
122
+ []
123
+ );
124
+ const [remountTarget] = useState(() => headerHeight !== null ? -headerHeight + (pullSearchHeight ?? 0) : null);
125
+ const remountSyncTarget = useSharedValue(remountTarget);
126
+ const [scrollReady, setScrollReady] = useState(remountTarget === null);
127
+ const remountAttempts = useRef(0);
128
+ const onRemountSynced = useCallback(
129
+ (y) => {
130
+ scrollPosition.value = y;
131
+ setScrollReady(true);
132
+ },
133
+ [scrollPosition]
134
+ );
135
+ const onRemountSyncRetry = useCallback(
136
+ (currentY) => {
137
+ if (remountTarget === null) return;
138
+ remountAttempts.current += 1;
139
+ if (remountAttempts.current > REMOUNT_SYNC_MAX_ATTEMPTS) {
140
+ remountSyncTarget.value = null;
141
+ onRemountSynced(currentY);
142
+ return;
143
+ }
144
+ scrollTo(remountTarget, false);
145
+ },
146
+ [onRemountSynced, remountSyncTarget, remountTarget, scrollTo]
147
+ );
148
+ useEffect(() => {
149
+ if (remountTarget === null) return;
150
+ scrollTo(remountTarget, false);
151
+ const fallback = setTimeout(() => {
152
+ if (remountSyncTarget.value === null) return;
153
+ remountSyncTarget.value = null;
154
+ onRemountSynced(remountTarget);
155
+ }, REMOUNT_SYNC_FALLBACK_MS);
156
+ return () => clearTimeout(fallback);
157
+ }, []);
158
+ useEffect(() => {
159
+ if (phase === "ready" || !headerHeight || !pullSearchHeight) return;
160
+ scrollPosition.value = -headerHeight + pullSearchHeight;
161
+ setPhase("ready");
162
+ }, [phase, headerHeight, pullSearchHeight, scrollPosition]);
163
+ const headerInitialized = useRef(false);
164
+ useLayoutEffect(() => {
165
+ if (!headerHeight || headerInitialized.current) return;
166
+ headerInitialized.current = true;
167
+ const target = remountTarget ?? -headerHeight;
168
+ scrollPosition.value = target;
169
+ scrollTo(target, false);
170
+ if (remountTarget === null) return;
171
+ let framesLeft = REMOUNT_PRIME_FRAMES;
172
+ let handle = null;
173
+ const tick = () => {
174
+ const offset = framesLeft === 1 ? target : framesLeft % 2 === 0 ? target + 30 : target - 30;
175
+ scrollTo(offset, false);
176
+ framesLeft -= 1;
177
+ if (framesLeft > 0) handle = requestAnimationFrame(tick);
178
+ };
179
+ handle = requestAnimationFrame(tick);
180
+ return () => {
181
+ if (handle !== null) cancelAnimationFrame(handle);
182
+ };
183
+ }, [remountTarget, headerHeight, scrollPosition, scrollTo]);
184
+ const pullSearchInitialized = useRef(false);
185
+ useLayoutEffect(() => {
186
+ if (remountTarget !== null || !hasPullSearch || phase !== "ready" || pullSearchInitialized.current || !headerHeight || !pullSearchHeight || !scrollReady) return;
187
+ pullSearchInitialized.current = true;
188
+ scrollPosition.value = -headerHeight + pullSearchHeight;
189
+ scrollTo(-headerHeight + pullSearchHeight, false);
190
+ }, [remountTarget, hasPullSearch, phase, headerHeight, pullSearchHeight, scrollPosition, scrollReady, scrollTo]);
191
+ useEffect(() => {
192
+ if (pullSearchHeight) setProgressing(refreshing);
193
+ }, [pullSearchHeight, refreshing, setProgressing]);
194
+ const handleScrollBeginDrag = useCallback(
195
+ (e) => {
196
+ if (snapVerifyTimeout.current !== null) {
197
+ clearTimeout(snapVerifyTimeout.current);
198
+ snapVerifyTimeout.current = null;
199
+ }
200
+ pendingSnapTarget.current = null;
201
+ if (pullSearchHeight) dragStartY.current = e.nativeEvent.contentOffset.y;
202
+ externalScrollBeginDrag?.(e);
203
+ },
204
+ [externalScrollBeginDrag, pullSearchHeight]
205
+ );
206
+ const handleScrollEndDrag = useCallback(
207
+ (e) => {
208
+ if (pullSearchHeight && headerHeight) {
209
+ const y = e.nativeEvent.contentOffset.y;
210
+ const showY = -headerHeight;
211
+ const hideY = -headerHeight + pullSearchHeight;
212
+ const startY = dragStartY.current;
213
+ dragStartY.current = null;
214
+ const pulledDown = (startY ?? hideY) <= hideY;
215
+ const dragDistance = startY !== null ? startY - y : 0;
216
+ if (pulledDown && dragDistance >= pullSearchHeight * 0.5) {
217
+ if (y <= showY && !refreshing && onRefresh) {
218
+ setRefreshing(true);
219
+ Promise.resolve(onRefresh()).finally(() => setRefreshing(false));
220
+ }
221
+ scrollTo(showY, true);
222
+ scheduleSnapVerification(showY, SNAP_VERIFY_INITIAL_DELAY_MS);
223
+ } else if (y < hideY) {
224
+ scrollTo(hideY, true);
225
+ scheduleSnapVerification(hideY, SNAP_VERIFY_INITIAL_DELAY_MS);
226
+ }
227
+ }
228
+ externalScrollEndDrag?.(e);
229
+ },
230
+ [externalScrollEndDrag, headerHeight, onRefresh, pullSearchHeight, refreshing, scheduleSnapVerification, scrollTo]
231
+ );
232
+ const handleMomentumScrollEnd = useCallback(
233
+ (e) => {
234
+ if (pullSearchHeight && headerHeight && !refreshing && pendingSnapTarget.current === null) {
235
+ const y = e.nativeEvent.contentOffset.y;
236
+ const hideY = -headerHeight + pullSearchHeight;
237
+ if (y < hideY - 1) {
238
+ scrollTo(hideY, true);
239
+ scheduleSnapVerification(hideY, SNAP_VERIFY_INITIAL_DELAY_MS);
240
+ }
241
+ }
242
+ externalMomentumScrollEnd?.(e);
243
+ },
244
+ [externalMomentumScrollEnd, headerHeight, pullSearchHeight, refreshing, scheduleSnapVerification, scrollTo]
245
+ );
246
+ const activeListHeader = hasPullSearch && phase === "measuring" ? null : listHeaderComponent;
247
+ const hiddenHeader = phase === "measuring" && listHeaderComponent != null ? typeof listHeaderComponent === "function" ? createElement(listHeaderComponent) : listHeaderComponent : null;
248
+ return { activeListHeader, handleMomentumScrollEnd, handleScrollBeginDrag, handleScrollEndDrag, hiddenHeader, onRemountSyncRetry, onRemountSynced, pullSearchMinHeight: pullSearchHeight ?? 0, remountSyncTarget, remountTarget, scrollReady };
249
+ }
250
+
67
251
  // src/internal/useScrollHandler.ts
68
- function useScrollHandler({ chipHidden, chipThreshold = 100, footerFixed, headerFixed, isHorizontal, onPullSearchZoneEnter }) {
69
- const { footerHeightShared, footerOffset, headerHeightShared, headerOffset, pullSearchHeightShared, scrollPosition, snapBackFooterShared, snapBackHeaderShared } = useContext(ScrollViewContext);
70
- const snapUpAccum = useSharedValue(0);
71
- const fromBottomBounce = useSharedValue(false);
72
- const isMomentum = useSharedValue(false);
73
- const momentumPullSearchFired = useSharedValue(false);
252
+ function useScrollHandler({ capturedGeneration, chipHidden, chipThreshold = 100, footerFixed, headerFixed, isHorizontal, listGeneration, onRemountSyncRetry, onRemountSynced, remountSyncTarget }) {
253
+ const { footerHeightShared, footerOffset, headerHeightShared, headerOffset, pullSearchHeightShared, scrollPosition, snapBackFooterShared, snapBackHeaderShared } = useContext2(ScrollViewContext);
254
+ const snapUpAccum = useSharedValue2(0);
255
+ const fromBottomBounce = useSharedValue2(false);
74
256
  return useAnimatedScrollHandler(
75
257
  {
76
258
  onScroll: ({ contentOffset: { x, y }, contentSize: { height: contentHeight }, layoutMeasurement: { height: layoutHeight } }) => {
77
259
  "worklet";
260
+ if (remountSyncTarget && remountSyncTarget.value !== null) {
261
+ const target = remountSyncTarget.value;
262
+ if (Math.abs(y - target) < REMOUNT_SYNC_TOLERANCE) {
263
+ remountSyncTarget.value = null;
264
+ if (onRemountSynced) runOnJS(onRemountSynced)(y);
265
+ } else if (onRemountSyncRetry) {
266
+ runOnJS(onRemountSyncRetry)(y);
267
+ }
268
+ return;
269
+ }
270
+ if (listGeneration.value !== capturedGeneration.value) return;
78
271
  if (isHorizontal) {
79
272
  scrollPosition.value = x;
80
273
  chipHidden.value = x < chipThreshold ? 1 : 0;
@@ -90,13 +283,6 @@ function useScrollHandler({ chipHidden, chipThreshold = 100, footerFixed, header
90
283
  } else if (fromBottomBounce.value) {
91
284
  fromBottomBounce.value = false;
92
285
  }
93
- if (isMomentum.value && pullSearchHeightShared.value > 0 && !momentumPullSearchFired.value) {
94
- const hideY = -headerHeightShared.value + pullSearchHeightShared.value;
95
- if (y < hideY) {
96
- momentumPullSearchFired.value = true;
97
- if (onPullSearchZoneEnter) runOnJS(onPullSearchZoneEnter)();
98
- }
99
- }
100
286
  const snapHeader = snapBackHeaderShared.value && !headerFixed;
101
287
  const snapFooter = snapBackFooterShared.value && !footerFixed;
102
288
  if (snapHeader || snapFooter) {
@@ -122,16 +308,9 @@ function useScrollHandler({ chipHidden, chipThreshold = 100, footerFixed, header
122
308
  },
123
309
  onBeginDrag: () => {
124
310
  "worklet";
125
- isMomentum.value = false;
126
- momentumPullSearchFired.value = false;
127
311
  fromBottomBounce.value = false;
128
312
  snapUpAccum.value = 0;
129
313
  },
130
- onMomentumBegin: () => {
131
- "worklet";
132
- isMomentum.value = true;
133
- momentumPullSearchFired.value = false;
134
- },
135
314
  onEndDrag: ({ contentOffset: { y }, contentSize: { height: contentHeight }, layoutMeasurement: { height: layoutHeight } }) => {
136
315
  "worklet";
137
316
  if (isHorizontal) return;
@@ -142,28 +321,26 @@ function useScrollHandler({ chipHidden, chipThreshold = 100, footerFixed, header
142
321
  },
143
322
  onMomentumEnd: () => {
144
323
  "worklet";
145
- isMomentum.value = false;
146
- momentumPullSearchFired.value = false;
147
324
  fromBottomBounce.value = false;
148
325
  snapUpAccum.value = 0;
149
326
  }
150
327
  },
151
- [headerFixed, footerFixed, isHorizontal, chipThreshold, onPullSearchZoneEnter]
328
+ [capturedGeneration, headerFixed, footerFixed, isHorizontal, chipThreshold, listGeneration, onRemountSyncRetry, onRemountSynced, remountSyncTarget]
152
329
  );
153
330
  }
154
331
 
155
332
  // src/internal/useScrollList.ts
156
- import { useContext as useContext2, useEffect, useMemo } from "react";
333
+ import { useContext as useContext3, useEffect as useEffect2, useMemo, useState as useState3 } from "react";
157
334
  import { StyleSheet as StyleSheet2 } from "react-native";
158
- import { useAnimatedStyle, useSharedValue as useSharedValue2, withTiming as withTiming2 } from "react-native-reanimated";
335
+ import { useAnimatedStyle, useSharedValue as useSharedValue3, withTiming as withTiming2 } from "react-native-reanimated";
159
336
  import { useSafeAreaInsets } from "react-native-safe-area-context";
160
337
 
161
338
  // src/useKeyboardInset.ts
162
- import { useState } from "react";
339
+ import { useState as useState2 } from "react";
163
340
  import { useKeyboardHandler } from "react-native-keyboard-controller";
164
341
  import { runOnJS as runOnJS2 } from "react-native-reanimated";
165
342
  var useKeyboardInset = () => {
166
- const [keyboardHeight, setKeyboardHeight] = useState(0);
343
+ const [keyboardHeight, setKeyboardHeight] = useState2(0);
167
344
  useKeyboardHandler(
168
345
  {
169
346
  onMove: (e) => {
@@ -185,28 +362,30 @@ var CHIP_SLIDE = 48;
185
362
  function useScrollList({ footerFixed: footerFixedProp, headerFixed: headerFixedProp, isHorizontal, keyboardAware, pullSearchHeight, style } = {}) {
186
363
  const insets = useSafeAreaInsets();
187
364
  const keyboardHeight = useKeyboardInset();
188
- const { footerHeight, footerFixed: contextFooterFixed, headerHeight, headerFixed: contextHeaderFixed, headerOffset, pullSearchHeightShared, scrollPosition, snapBackHeaderShared } = useContext2(ScrollViewContext);
365
+ const { footerHeight, footerFixed: contextFooterFixed, headerHeight, headerFixed: contextHeaderFixed, headerOffset, pullSearchHeightShared, scrollPosition, snapBackHeaderShared } = useContext3(ScrollViewContext);
189
366
  const headerFixed = isHorizontal ? true : headerFixedProp ?? contextHeaderFixed;
190
367
  const footerFixed = isHorizontal ? true : footerFixedProp ?? contextFooterFixed;
191
- useEffect(() => {
368
+ useEffect2(() => {
192
369
  pullSearchHeightShared.value = pullSearchHeight ?? 0;
193
370
  }, [pullSearchHeight, pullSearchHeightShared]);
194
- const containerStyle = useMemo(() => headerHeight === 0 ? [{ flex: 1 }, style] : [StyleSheet2.absoluteFill, style], [headerHeight, style]);
195
- const contentInset = useMemo(() => ({ bottom: (footerFixed ? footerHeight || insets.bottom : insets.bottom) + (keyboardAware ? keyboardHeight : 0), top: headerHeight }), [footerFixed, footerHeight, insets.bottom, headerHeight, keyboardAware, keyboardHeight]);
196
- const contentOffset = useMemo(() => ({ x: 0, y: -contentInset.top }), [contentInset.top]);
197
- const chipHidden = useSharedValue2(1);
371
+ const containerStyle = useMemo(() => headerHeight === null ? [{ flex: 1, opacity: 0 }, style] : [StyleSheet2.absoluteFill, style], [headerHeight, style]);
372
+ const contentInset = useMemo(() => ({ bottom: (footerFixed ? footerHeight || insets.bottom : insets.bottom) + (keyboardAware ? keyboardHeight : 0), top: headerHeight ?? 0 }), [footerFixed, footerHeight, insets.bottom, headerHeight, keyboardAware, keyboardHeight]);
373
+ const [startedWithHeader] = useState3(headerHeight !== null);
374
+ const contentOffset = useMemo(() => ({ x: 0, y: headerHeight !== null ? -headerHeight + (startedWithHeader && !isHorizontal && pullSearchHeight ? pullSearchHeight : 0) : 0 }), [headerHeight, isHorizontal, pullSearchHeight, startedWithHeader]);
375
+ const chipHidden = useSharedValue3(1);
198
376
  const chipStyle = useAnimatedStyle(() => {
199
377
  const pointerEvents = chipHidden.value ? "none" : "box-none";
200
378
  if (isHorizontal) {
201
379
  return {
202
380
  opacity: chipHidden.value ? withTiming2(0) : withTiming2(1),
203
381
  pointerEvents,
204
- top: Math.max(headerHeight, insets.top) + 4,
382
+ top: Math.max(headerHeight ?? 0, insets.top) + 4,
205
383
  transform: [{ translateX: chipHidden.value ? withTiming2(-CHIP_SLIDE) : withTiming2(0) }]
206
384
  };
207
385
  }
208
- const slide = headerFixed ? 0 : snapBackHeaderShared.value ? -headerOffset.value : Math.max(0, scrollPosition.value + headerHeight - pullSearchHeightShared.value);
209
- const top = Math.max(headerHeight - slide, insets.top) + 4;
386
+ const h = headerHeight ?? 0;
387
+ const slide = headerFixed ? 0 : snapBackHeaderShared.value ? -headerOffset.value : Math.max(0, scrollPosition.value + h - pullSearchHeightShared.value);
388
+ const top = Math.max(h - slide, insets.top) + 4;
210
389
  return {
211
390
  opacity: chipHidden.value ? withTiming2(0) : withTiming2(1),
212
391
  pointerEvents,
@@ -217,90 +396,21 @@ function useScrollList({ footerFixed: footerFixedProp, headerFixed: headerFixedP
217
396
  return { chipHidden, chipStyle, containerStyle, contentInset, contentOffset, footerFixed, headerFixed, headerHeight, insets, isHorizontal: isHorizontal ?? false };
218
397
  }
219
398
 
220
- // src/useScrollInit.ts
221
- import { createElement, useCallback, useContext as useContext3, useEffect as useEffect2, useLayoutEffect, useRef, useState as useState2 } from "react";
222
- function useScrollInit({ listHeaderComponent, onMomentumScrollEnd: externalMomentumScrollEnd, onRefresh, onScrollBeginDrag: externalScrollBeginDrag, onScrollEndDrag: externalScrollEndDrag, pullSearchHeight, scrollTo }) {
223
- const { headerHeight, scrollPosition, setProgressing } = useContext3(ScrollViewContext);
224
- const hasPullSearch = pullSearchHeight !== void 0;
225
- const [phase, setPhase] = useState2(hasPullSearch ? "measuring" : "ready");
226
- const [refreshing, setRefreshing] = useState2(false);
227
- const dragStartY = useRef(null);
228
- const deliberatelyOpened = useRef(false);
229
- useEffect2(() => {
230
- if (phase === "ready" || !headerHeight || !pullSearchHeight) return;
231
- scrollPosition.value = -headerHeight + pullSearchHeight;
232
- setPhase("ready");
233
- }, [phase, headerHeight, pullSearchHeight, scrollPosition]);
234
- const headerInitialized = useRef(false);
235
- useLayoutEffect(() => {
236
- if (!headerHeight || headerInitialized.current) return;
237
- headerInitialized.current = true;
238
- scrollPosition.value = -headerHeight;
239
- scrollTo(-headerHeight, false);
240
- }, [headerHeight, scrollPosition, scrollTo]);
241
- const pullSearchInitialized = useRef(false);
242
- useLayoutEffect(() => {
243
- if (!hasPullSearch || phase !== "ready" || pullSearchInitialized.current || !headerHeight || !pullSearchHeight) return;
244
- pullSearchInitialized.current = true;
245
- scrollPosition.value = -headerHeight + pullSearchHeight;
246
- scrollTo(-headerHeight + pullSearchHeight, false);
247
- }, [hasPullSearch, phase, headerHeight, pullSearchHeight, scrollPosition, scrollTo]);
248
- useEffect2(() => {
249
- if (pullSearchHeight) setProgressing(refreshing);
250
- }, [pullSearchHeight, refreshing, setProgressing]);
251
- const handleScrollBeginDrag = useCallback(
252
- (e) => {
253
- deliberatelyOpened.current = false;
254
- if (pullSearchHeight) dragStartY.current = e.nativeEvent.contentOffset.y;
255
- externalScrollBeginDrag?.(e);
256
- },
257
- [externalScrollBeginDrag, pullSearchHeight]
258
- );
259
- const handleScrollEndDrag = useCallback(
260
- (e) => {
261
- if (pullSearchHeight && headerHeight) {
262
- const y = e.nativeEvent.contentOffset.y;
263
- const showY = -headerHeight;
264
- const hideY = -headerHeight + pullSearchHeight;
265
- const pulledDown = (dragStartY.current ?? hideY) <= hideY;
266
- dragStartY.current = null;
267
- if (pulledDown && y <= showY + pullSearchHeight * 0.5) {
268
- deliberatelyOpened.current = true;
269
- if (y <= showY && !refreshing && onRefresh) {
270
- setRefreshing(true);
271
- Promise.resolve(onRefresh()).finally(() => setRefreshing(false));
272
- }
273
- scrollTo(showY, true);
274
- } else if (y < hideY) {
275
- scrollTo(hideY, true);
276
- }
277
- }
278
- externalScrollEndDrag?.(e);
279
- },
280
- [externalScrollEndDrag, headerHeight, onRefresh, pullSearchHeight, refreshing, scrollTo]
281
- );
282
- const handleMomentumScrollEnd = useCallback(
283
- (e) => {
284
- if (pullSearchHeight && headerHeight && !deliberatelyOpened.current && !refreshing) {
285
- const y = e.nativeEvent.contentOffset.y;
286
- const hideY = -headerHeight + pullSearchHeight;
287
- if (y < hideY - 1) scrollTo(hideY, true);
288
- }
289
- deliberatelyOpened.current = false;
290
- externalMomentumScrollEnd?.(e);
291
- },
292
- [externalMomentumScrollEnd, headerHeight, pullSearchHeight, refreshing, scrollTo]
293
- );
294
- const activeListHeader = hasPullSearch && phase === "measuring" ? null : listHeaderComponent;
295
- const hiddenHeader = phase === "measuring" && listHeaderComponent != null ? typeof listHeaderComponent === "function" ? createElement(listHeaderComponent) : listHeaderComponent : null;
296
- return { activeListHeader, handleMomentumScrollEnd, handleScrollBeginDrag, handleScrollEndDrag, hiddenHeader, pullSearchMinHeight: pullSearchHeight ?? 0 };
297
- }
298
-
299
399
  // src/CustomList.tsx
300
400
  import { Fragment, jsx as jsx3, jsxs } from "react/jsx-runtime";
301
401
  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 }) => {
302
402
  const { ListHeaderComponent: listHeaderComponent, contentContainerStyle: externalContentContainerStyle, ...restProps } = props;
303
403
  const { chipHidden, chipStyle, containerStyle, contentInset, contentOffset, footerFixed, headerFixed } = useScrollList({ footerFixed: footerFixedProp, headerFixed: headerFixedProp, keyboardAware, pullSearchHeight, style });
404
+ const { listGeneration, onListUnmount } = useContext4(ScrollViewContext);
405
+ const capturedGeneration = useSharedValue4(-1);
406
+ useLayoutEffect2(() => {
407
+ const generation = listGeneration.value;
408
+ runOnUI((gen) => {
409
+ "worklet";
410
+ capturedGeneration.value = gen;
411
+ })(generation);
412
+ }, [capturedGeneration, listGeneration]);
413
+ useLayoutEffect2(() => () => onListUnmount(), [onListUnmount]);
304
414
  const scrollViewInternal = useRef2(null);
305
415
  const handleRef = useCallback2(
306
416
  (el) => {
@@ -318,7 +428,10 @@ var CustomListInner = ({ chipProps, chipThreshold, component: List, renderFilter
318
428
  handleScrollBeginDrag,
319
429
  handleScrollEndDrag,
320
430
  hiddenHeader,
321
- pullSearchMinHeight
431
+ onRemountSyncRetry,
432
+ onRemountSynced,
433
+ pullSearchMinHeight,
434
+ remountSyncTarget
322
435
  } = useScrollInit({
323
436
  listHeaderComponent,
324
437
  onMomentumScrollEnd: externalMomentumScrollEnd,
@@ -337,11 +450,7 @@ var CustomListInner = ({ chipProps, chipThreshold, component: List, renderFilter
337
450
  ] });
338
451
  }, [pullSearchHeader, renderFilters]);
339
452
  const contentContainerStyle = useMemo2(() => [{ minHeight: Dimensions.get("window").height - contentInset.top - contentInset.bottom + pullSearchMinHeight }, externalContentContainerStyle], [contentInset.bottom, contentInset.top, externalContentContainerStyle, pullSearchMinHeight]);
340
- const onPullSearchZoneEnter = useCallback2(() => {
341
- if (!pullSearchHeight) return;
342
- scrollViewInternal.current?.scrollToOffset({ offset: -contentInset.top + pullSearchHeight, animated: true });
343
- }, [contentInset.top, pullSearchHeight]);
344
- const onScroll = useScrollHandler({ chipHidden, chipThreshold, footerFixed, headerFixed, onPullSearchZoneEnter: pullSearchHeight ? onPullSearchZoneEnter : void 0 });
453
+ const onScroll = useScrollHandler({ capturedGeneration, chipHidden, chipThreshold, footerFixed, headerFixed, listGeneration, onRemountSyncRetry, onRemountSynced, remountSyncTarget });
345
454
  const handleScrollToTop = useCallback2(() => {
346
455
  const offset = pullSearchHeight ? -contentInset.top + pullSearchHeight : -contentInset.top;
347
456
  scrollViewInternal.current?.scrollToOffset({ offset, animated: true });
@@ -362,14 +471,13 @@ var styles2 = { measureContainer: { left: 0, opacity: 0, position: "absolute", r
362
471
  var CustomList = memo(CustomListInner);
363
472
 
364
473
  // src/FlatList.tsx
365
- import { memo as memo2, useCallback as useCallback3, useMemo as useMemo3, useRef as useRef3 } from "react";
366
- import { Dimensions as Dimensions2, View as View3 } from "react-native";
474
+ import { Fragment as Fragment2, memo as memo2, useCallback as useCallback4, useContext as useContext7, useLayoutEffect as useLayoutEffect3, useMemo as useMemo3, useRef as useRef4 } from "react";
475
+ import { Dimensions as Dimensions2, FlatList as RNFlatList, View as View3 } from "react-native";
367
476
  import { Gesture as Gesture2, GestureDetector as GestureDetector2 } from "react-native-gesture-handler";
368
- import Animated3 from "react-native-reanimated";
369
477
 
370
478
  // src/internal/HorizontalDots.tsx
371
479
  import { BlurView } from "@rific/auto-paper";
372
- import { useContext as useContext4 } from "react";
480
+ import { useContext as useContext5 } from "react";
373
481
  import { StyleSheet as StyleSheet3, useWindowDimensions, View as View2 } from "react-native";
374
482
  import { useTheme } from "react-native-paper";
375
483
  import Animated2, { interpolateColor, useAnimatedStyle as useAnimatedStyle2 } from "react-native-reanimated";
@@ -398,7 +506,7 @@ var Dot = ({ activeColor, index, inactiveColor, pageWidth, scrollPosition }) =>
398
506
  return /* @__PURE__ */ jsx4(View2, { style: styles3.dotContainer, children: /* @__PURE__ */ jsx4(Animated2.View, { style: circleStyle }) });
399
507
  };
400
508
  var HorizontalDots = ({ total }) => {
401
- const { blur, footerHeightShared, scrollPosition } = useContext4(ScrollViewContext);
509
+ const { blur, footerHeightShared, scrollPosition } = useContext5(ScrollViewContext);
402
510
  const { width } = useWindowDimensions();
403
511
  const insets = useSafeAreaInsets2();
404
512
  const theme = useTheme();
@@ -420,1724 +528,343 @@ var HorizontalDots = ({ total }) => {
420
528
  ] }) });
421
529
  };
422
530
  var styles3 = StyleSheet3.create({
423
- dotContainer: { alignItems: "center", height: DOT_FULL, justifyContent: "center", width: DOT_FULL },
424
- dotsClip: { overflow: "hidden", width: CLIP_WIDTH },
425
- dotsRow: { flexDirection: "row", gap: DOT_GAP },
426
- pill: {
427
- alignItems: "center",
428
- borderRadius: PILL_RADIUS,
429
- height: PILL_HEIGHT,
430
- justifyContent: "center",
431
- overflow: "hidden",
432
- width: PILL_WIDTH
433
- },
434
- pillContainer: { alignItems: "center", left: 0, position: "absolute", right: 0, zIndex: 3 }
435
- });
436
-
437
- // src/FlatList.tsx
438
- import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
439
- var FlatListInner = ({ chipProps, chipThreshold, contentContainerStyle: externalContentContainerStyle, data, initialNumToRender = 20, maxToRenderPerBatch = 50, renderFilters, 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 }) => {
440
- const scrollView = useRef3(null);
441
- const isHorizontal = horizontal === true;
442
- const showDots = isHorizontal && pagingEnabled === true && (data?.length ?? 0) > 1;
443
- const { chipHidden, chipStyle, containerStyle, contentInset, contentOffset, footerFixed, headerFixed } = useScrollList({ footerFixed: footerFixedProp, headerFixed: headerFixedProp, isHorizontal, keyboardAware, pullSearchHeight, style });
444
- const scrollTo = useCallback3((offset, animated) => {
445
- scrollView.current?.scrollToOffset({ offset, animated });
446
- }, []);
447
- const {
448
- activeListHeader: pullSearchHeader,
449
- handleMomentumScrollEnd,
450
- handleScrollBeginDrag,
451
- handleScrollEndDrag,
452
- hiddenHeader,
453
- pullSearchMinHeight
454
- } = useScrollInit({
455
- listHeaderComponent: externalListHeaderComponent,
456
- onMomentumScrollEnd: externalMomentumScrollEnd,
457
- onRefresh: pullSearchHeight ? onRefresh : void 0,
458
- onScrollBeginDrag: externalScrollBeginDrag,
459
- onScrollEndDrag: externalScrollEndDrag,
460
- pullSearchHeight,
461
- scrollTo
462
- });
463
- const activeListHeader = useMemo3(() => {
464
- if (!renderFilters) return pullSearchHeader;
465
- const Inner = pullSearchHeader;
466
- return () => /* @__PURE__ */ jsxs3(Fragment2, { children: [
467
- Inner ? typeof Inner === "function" ? /* @__PURE__ */ jsx5(Inner, {}) : Inner : null,
468
- renderFilters
469
- ] });
470
- }, [pullSearchHeader, renderFilters]);
471
- const contentContainerStyle = useMemo3(() => isHorizontal ? externalContentContainerStyle : [{ minHeight: Dimensions2.get("window").height - contentInset.top - contentInset.bottom + pullSearchMinHeight }, externalContentContainerStyle], [isHorizontal, contentInset.bottom, contentInset.top, externalContentContainerStyle, pullSearchMinHeight]);
472
- const onPullSearchZoneEnter = useCallback3(() => {
473
- if (!pullSearchHeight) return;
474
- scrollView.current?.scrollToOffset({ offset: -contentInset.top + pullSearchHeight, animated: true });
475
- }, [contentInset.top, pullSearchHeight]);
476
- const handleScroll = useScrollHandler({ chipHidden, chipThreshold, footerFixed, headerFixed, isHorizontal, onPullSearchZoneEnter: pullSearchHeight ? onPullSearchZoneEnter : void 0 });
477
- const handleScrollToTop = useCallback3(() => {
478
- if (isHorizontal) {
479
- scrollView.current?.scrollToOffset({ offset: 0, animated: true });
480
- return;
481
- }
482
- const offset = pullSearchHeight ? -contentInset.top + pullSearchHeight : -contentInset.top;
483
- scrollView.current?.scrollToOffset({ offset, animated: true });
484
- }, [isHorizontal, contentInset.top, pullSearchHeight]);
485
- const handleContentSizeChange = useCallback3(
486
- (w, h) => {
487
- if (onContentSizeChange) onContentSizeChange(w, h);
488
- },
489
- [onContentSizeChange]
490
- );
491
- const refreshControl = useMemo3(() => /* @__PURE__ */ jsx5(RefreshControl, {}), []);
492
- const nativeGesture = useMemo3(() => Gesture2.Native(), []);
493
- const combinedGesture = useMemo3(() => gesture !== void 0 ? Gesture2.Simultaneous(gesture, nativeGesture) : nativeGesture, [gesture, nativeGesture]);
494
- const detectorGesture = gesture !== void 0 ? combinedGesture : void 0;
495
- const content = /* @__PURE__ */ jsxs3(View3, { style: containerStyle, children: [
496
- /* @__PURE__ */ jsx5(
497
- Animated3.FlatList,
498
- {
499
- ...props,
500
- contentContainerStyle,
501
- contentInset,
502
- contentOffset,
503
- data,
504
- horizontal: isHorizontal,
505
- initialNumToRender,
506
- ListHeaderComponent: activeListHeader,
507
- maxToRenderPerBatch,
508
- onContentSizeChange: handleContentSizeChange,
509
- onMomentumScrollEnd: handleMomentumScrollEnd,
510
- onScroll: handleScroll,
511
- onScrollBeginDrag: handleScrollBeginDrag,
512
- onScrollEndDrag: handleScrollEndDrag,
513
- pagingEnabled,
514
- ref: (el) => {
515
- if (externalRef) externalRef.current = el;
516
- scrollView.current = el;
517
- },
518
- refreshControl,
519
- removeClippedSubviews,
520
- scrollEventThrottle: 16,
521
- showsHorizontalScrollIndicator: showsHorizontalScrollIndicator ?? isHorizontal,
522
- showsVerticalScrollIndicator: showsVerticalScrollIndicator ?? !isHorizontal,
523
- windowSize
524
- }
525
- ),
526
- hiddenHeader && /* @__PURE__ */ jsx5(View3, { pointerEvents: "none", style: styles4.measureContainer, children: hiddenHeader }),
527
- /* @__PURE__ */ jsx5(ScrollViewChip, { chipProps, isHorizontal, onChipPress, onPress: handleScrollToTop, style: chipStyle }),
528
- showDots && /* @__PURE__ */ jsx5(HorizontalDots, { total: data?.length ?? 0 })
529
- ] });
530
- return detectorGesture ? /* @__PURE__ */ jsx5(GestureDetector2, { gesture: detectorGesture, children: content }) : content;
531
- };
532
- var styles4 = { measureContainer: { left: 0, opacity: 0, position: "absolute", right: 0, top: -9999 } };
533
- var FlatList = memo2(FlatListInner);
534
-
535
- // src/PullSearch.tsx
536
- import { forwardRef, useCallback as useCallback4, useContext as useContext5, useEffect as useEffect3, useImperativeHandle, useRef as useRef4, useState as useState3 } from "react";
537
- import { StyleSheet as StyleSheet4 } from "react-native";
538
- import { Searchbar, useTheme as useTheme2 } from "react-native-paper";
539
- import Animated4, { Extrapolation, interpolate, runOnJS as runOnJS3, useAnimatedReaction, useAnimatedStyle as useAnimatedStyle3 } from "react-native-reanimated";
540
- import { jsx as jsx6 } from "react/jsx-runtime";
541
- var PullSearch = forwardRef(function PullSearch2({ debounce, onChangeText, onHeightChange, placeholder, value: propValue }, ref) {
542
- const { headerHeight, scrollPosition } = useContext5(ScrollViewContext);
543
- const theme = useTheme2();
544
- const inputRef = useRef4(null);
545
- const [barHeight, setBarHeight] = useState3(0);
546
- const [value, setValue] = useState3(propValue ?? "");
547
- const prevPropValueRef = useRef4(propValue);
548
- useEffect3(() => {
549
- if (prevPropValueRef.current === propValue) return;
550
- prevPropValueRef.current = propValue;
551
- setValue(propValue ?? "");
552
- }, [propValue]);
553
- useImperativeHandle(ref, () => ({
554
- blur: () => inputRef.current?.blur(),
555
- focus: () => inputRef.current?.focus()
556
- }));
557
- const blurInput = useCallback4(() => inputRef.current?.blur(), []);
558
- useAnimatedReaction(
559
- () => {
560
- if (barHeight === 0) return false;
561
- return scrollPosition.value >= -headerHeight + barHeight;
562
- },
563
- (isHidden, wasHidden) => {
564
- if (isHidden && !wasHidden) runOnJS3(blurInput)();
565
- },
566
- [barHeight, headerHeight, blurInput]
567
- );
568
- const handleClear = useCallback4(() => {
569
- setValue("");
570
- onChangeText("");
571
- }, [onChangeText]);
572
- const handleLayout = useCallback4(
573
- ({
574
- nativeEvent: {
575
- layout: { height }
576
- }
577
- }) => {
578
- setBarHeight(height);
579
- onHeightChange(height);
580
- },
581
- [onHeightChange]
582
- );
583
- useEffect3(() => {
584
- const normalizedValue = value.trim();
585
- if (debounce) {
586
- const timeout = setTimeout(() => onChangeText(normalizedValue), 500);
587
- return () => clearTimeout(timeout);
588
- }
589
- onChangeText(normalizedValue);
590
- }, [debounce, onChangeText, value]);
591
- const animatedStyle = useAnimatedStyle3(() => {
592
- if (barHeight === 0) return { opacity: 0 };
593
- const showY = -headerHeight;
594
- const hideY = -headerHeight + barHeight;
595
- return { opacity: interpolate(scrollPosition.value, [showY, hideY], [1, 0], Extrapolation.CLAMP) };
596
- }, [barHeight, headerHeight]);
597
- return /* @__PURE__ */ jsx6(Animated4.View, { onLayout: handleLayout, style: [styles5.container, animatedStyle], children: /* @__PURE__ */ jsx6(Searchbar, { autoCorrect: false, onChangeText: (text) => setValue((text || "").trimStart()), onClearIconPress: handleClear, placeholder, placeholderTextColor: theme.colors.onSurfaceVariant, ref: inputRef, spellCheck: false, style: styles5.input, value }) });
598
- });
599
- var styles5 = StyleSheet4.create({
600
- container: { paddingVertical: 8 },
601
- input: { margin: 0 }
602
- });
603
-
604
- // node_modules/redux/dist/redux.mjs
605
- var randomString = () => Math.random().toString(36).substring(7).split("").join(".");
606
- var ActionTypes = {
607
- INIT: `@@redux/INIT${/* @__PURE__ */ randomString()}`,
608
- REPLACE: `@@redux/REPLACE${/* @__PURE__ */ randomString()}`,
609
- PROBE_UNKNOWN_ACTION: () => `@@redux/PROBE_UNKNOWN_ACTION${randomString()}`
610
- };
611
- function isPlainObject(obj) {
612
- if (typeof obj !== "object" || obj === null)
613
- return false;
614
- let proto = obj;
615
- while (Object.getPrototypeOf(proto) !== null) {
616
- proto = Object.getPrototypeOf(proto);
617
- }
618
- return Object.getPrototypeOf(obj) === proto || Object.getPrototypeOf(obj) === null;
619
- }
620
- function compose(...funcs) {
621
- if (funcs.length === 0) {
622
- return (arg) => arg;
623
- }
624
- if (funcs.length === 1) {
625
- return funcs[0];
626
- }
627
- return funcs.reduce((a, b) => (...args) => a(b(...args)));
628
- }
629
- function isAction(action) {
630
- return isPlainObject(action) && "type" in action && typeof action.type === "string";
631
- }
632
-
633
- // node_modules/immer/dist/immer.mjs
634
- var NOTHING = /* @__PURE__ */ Symbol.for("immer-nothing");
635
- var DRAFTABLE = /* @__PURE__ */ Symbol.for("immer-draftable");
636
- var DRAFT_STATE = /* @__PURE__ */ Symbol.for("immer-state");
637
- var errors = process.env.NODE_ENV !== "production" ? [
638
- // All error codes, starting by 0:
639
- function(plugin) {
640
- return `The plugin for '${plugin}' has not been loaded into Immer. To enable the plugin, import and call \`enable${plugin}()\` when initializing your application.`;
641
- },
642
- function(thing) {
643
- return `produce can only be called on things that are draftable: plain objects, arrays, Map, Set or classes that are marked with '[immerable]: true'. Got '${thing}'`;
644
- },
645
- "This object has been frozen and should not be mutated",
646
- function(data) {
647
- return "Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? " + data;
648
- },
649
- "An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft.",
650
- "Immer forbids circular references",
651
- "The first or second argument to `produce` must be a function",
652
- "The third argument to `produce` must be a function or undefined",
653
- "First argument to `createDraft` must be a plain object, an array, or an immerable object",
654
- "First argument to `finishDraft` must be a draft returned by `createDraft`",
655
- function(thing) {
656
- return `'current' expects a draft, got: ${thing}`;
657
- },
658
- "Object.defineProperty() cannot be used on an Immer draft",
659
- "Object.setPrototypeOf() cannot be used on an Immer draft",
660
- "Immer only supports deleting array indices",
661
- "Immer only supports setting array indices and the 'length' property",
662
- function(thing) {
663
- return `'original' expects a draft, got: ${thing}`;
664
- }
665
- // Note: if more errors are added, the errorOffset in Patches.ts should be increased
666
- // See Patches.ts for additional errors
667
- ] : [];
668
- function die(error, ...args) {
669
- if (process.env.NODE_ENV !== "production") {
670
- const e = errors[error];
671
- const msg = isFunction(e) ? e.apply(null, args) : e;
672
- throw new Error(`[Immer] ${msg}`);
673
- }
674
- throw new Error(
675
- `[Immer] minified error nr: ${error}. Full error at: https://bit.ly/3cXEKWf`
676
- );
677
- }
678
- var O = Object;
679
- var getPrototypeOf = O.getPrototypeOf;
680
- var CONSTRUCTOR = "constructor";
681
- var PROTOTYPE = "prototype";
682
- var CONFIGURABLE = "configurable";
683
- var ENUMERABLE = "enumerable";
684
- var WRITABLE = "writable";
685
- var VALUE = "value";
686
- var isDraft = (value) => !!value && !!value[DRAFT_STATE];
687
- function isDraftable(value) {
688
- if (!value)
689
- return false;
690
- return isPlainObject2(value) || isArray(value) || !!value[DRAFTABLE] || !!value[CONSTRUCTOR]?.[DRAFTABLE] || isMap(value) || isSet(value);
691
- }
692
- var objectCtorString = O[PROTOTYPE][CONSTRUCTOR].toString();
693
- var cachedCtorStrings = /* @__PURE__ */ new WeakMap();
694
- function isPlainObject2(value) {
695
- if (!value || !isObjectish(value))
696
- return false;
697
- const proto = getPrototypeOf(value);
698
- if (proto === null || proto === O[PROTOTYPE])
699
- return true;
700
- const Ctor = O.hasOwnProperty.call(proto, CONSTRUCTOR) && proto[CONSTRUCTOR];
701
- if (Ctor === Object)
702
- return true;
703
- if (!isFunction(Ctor))
704
- return false;
705
- let ctorString = cachedCtorStrings.get(Ctor);
706
- if (ctorString === void 0) {
707
- ctorString = Function.toString.call(Ctor);
708
- cachedCtorStrings.set(Ctor, ctorString);
709
- }
710
- return ctorString === objectCtorString;
711
- }
712
- function each(obj, iter, strict = true) {
713
- if (getArchtype(obj) === 0) {
714
- const keys = strict ? Reflect.ownKeys(obj) : O.keys(obj);
715
- keys.forEach((key) => {
716
- iter(key, obj[key], obj);
717
- });
718
- } else {
719
- obj.forEach((entry, index) => iter(index, entry, obj));
720
- }
721
- }
722
- function getArchtype(thing) {
723
- const state = thing[DRAFT_STATE];
724
- return state ? state.type_ : isArray(thing) ? 1 : isMap(thing) ? 2 : isSet(thing) ? 3 : 0;
725
- }
726
- var has = (thing, prop, type = getArchtype(thing)) => type === 2 ? thing.has(prop) : O[PROTOTYPE].hasOwnProperty.call(thing, prop);
727
- var get = (thing, prop, type = getArchtype(thing)) => (
728
- // @ts-ignore
729
- type === 2 ? thing.get(prop) : thing[prop]
730
- );
731
- var set = (thing, propOrOldValue, value, type = getArchtype(thing)) => {
732
- if (type === 2)
733
- thing.set(propOrOldValue, value);
734
- else if (type === 3) {
735
- thing.add(value);
736
- } else
737
- thing[propOrOldValue] = value;
738
- };
739
- function is(x, y) {
740
- if (x === y) {
741
- return x !== 0 || 1 / x === 1 / y;
742
- } else {
743
- return x !== x && y !== y;
744
- }
745
- }
746
- var isArray = Array.isArray;
747
- var isMap = (target) => target instanceof Map;
748
- var isSet = (target) => target instanceof Set;
749
- var isObjectish = (target) => typeof target === "object";
750
- var isFunction = (target) => typeof target === "function";
751
- var isBoolean = (target) => typeof target === "boolean";
752
- function isArrayIndex(value) {
753
- const n = +value;
754
- return Number.isInteger(n) && String(n) === value;
755
- }
756
- var latest = (state) => state.copy_ || state.base_;
757
- var getFinalValue = (state) => state.modified_ ? state.copy_ : state.base_;
758
- function shallowCopy(base, strict) {
759
- if (isMap(base)) {
760
- return new Map(base);
761
- }
762
- if (isSet(base)) {
763
- return new Set(base);
764
- }
765
- if (isArray(base))
766
- return Array[PROTOTYPE].slice.call(base);
767
- const isPlain = isPlainObject2(base);
768
- if (strict === true || strict === "class_only" && !isPlain) {
769
- const descriptors = O.getOwnPropertyDescriptors(base);
770
- delete descriptors[DRAFT_STATE];
771
- let keys = Reflect.ownKeys(descriptors);
772
- for (let i = 0; i < keys.length; i++) {
773
- const key = keys[i];
774
- const desc = descriptors[key];
775
- if (desc[WRITABLE] === false) {
776
- desc[WRITABLE] = true;
777
- desc[CONFIGURABLE] = true;
778
- }
779
- if (desc.get || desc.set)
780
- descriptors[key] = {
781
- [CONFIGURABLE]: true,
782
- [WRITABLE]: true,
783
- // could live with !!desc.set as well here...
784
- [ENUMERABLE]: desc[ENUMERABLE],
785
- [VALUE]: base[key]
786
- };
787
- }
788
- return O.create(getPrototypeOf(base), descriptors);
789
- } else {
790
- const proto = getPrototypeOf(base);
791
- if (proto !== null && isPlain) {
792
- return { ...base };
793
- }
794
- const obj = O.create(proto);
795
- return O.assign(obj, base);
796
- }
797
- }
798
- function freeze(obj, deep = false) {
799
- if (isFrozen(obj) || isDraft(obj) || !isDraftable(obj))
800
- return obj;
801
- if (getArchtype(obj) > 1) {
802
- O.defineProperties(obj, {
803
- set: dontMutateMethodOverride,
804
- add: dontMutateMethodOverride,
805
- clear: dontMutateMethodOverride,
806
- delete: dontMutateMethodOverride
807
- });
808
- }
809
- O.freeze(obj);
810
- if (deep)
811
- each(
812
- obj,
813
- (_key, value) => {
814
- freeze(value, true);
815
- },
816
- false
817
- );
818
- return obj;
819
- }
820
- function dontMutateFrozenCollections() {
821
- die(2);
822
- }
823
- var dontMutateMethodOverride = {
824
- [VALUE]: dontMutateFrozenCollections
825
- };
826
- function isFrozen(obj) {
827
- if (obj === null || !isObjectish(obj))
828
- return true;
829
- return O.isFrozen(obj);
830
- }
831
- var PluginMapSet = "MapSet";
832
- var PluginPatches = "Patches";
833
- var PluginArrayMethods = "ArrayMethods";
834
- var plugins = {};
835
- function getPlugin(pluginKey) {
836
- const plugin = plugins[pluginKey];
837
- if (!plugin) {
838
- die(0, pluginKey);
839
- }
840
- return plugin;
841
- }
842
- var isPluginLoaded = (pluginKey) => !!plugins[pluginKey];
843
- var currentScope;
844
- var getCurrentScope = () => currentScope;
845
- var createScope = (parent_, immer_) => ({
846
- drafts_: [],
847
- parent_,
848
- immer_,
849
- // Whenever the modified draft contains a draft from another scope, we
850
- // need to prevent auto-freezing so the unowned draft can be finalized.
851
- canAutoFreeze_: true,
852
- unfinalizedDrafts_: 0,
853
- handledSet_: /* @__PURE__ */ new Set(),
854
- processedForPatches_: /* @__PURE__ */ new Set(),
855
- mapSetPlugin_: isPluginLoaded(PluginMapSet) ? getPlugin(PluginMapSet) : void 0,
856
- arrayMethodsPlugin_: isPluginLoaded(PluginArrayMethods) ? getPlugin(PluginArrayMethods) : void 0
857
- });
858
- function usePatchesInScope(scope, patchListener) {
859
- if (patchListener) {
860
- scope.patchPlugin_ = getPlugin(PluginPatches);
861
- scope.patches_ = [];
862
- scope.inversePatches_ = [];
863
- scope.patchListener_ = patchListener;
864
- }
865
- }
866
- function revokeScope(scope) {
867
- leaveScope(scope);
868
- scope.drafts_.forEach(revokeDraft);
869
- scope.drafts_ = null;
870
- }
871
- function leaveScope(scope) {
872
- if (scope === currentScope) {
873
- currentScope = scope.parent_;
874
- }
875
- }
876
- var enterScope = (immer2) => currentScope = createScope(currentScope, immer2);
877
- function revokeDraft(draft) {
878
- const state = draft[DRAFT_STATE];
879
- if (state.type_ === 0 || state.type_ === 1)
880
- state.revoke_();
881
- else
882
- state.revoked_ = true;
883
- }
884
- function processResult(result, scope) {
885
- scope.unfinalizedDrafts_ = scope.drafts_.length;
886
- const baseDraft = scope.drafts_[0];
887
- const isReplaced = result !== void 0 && result !== baseDraft;
888
- if (isReplaced) {
889
- if (baseDraft[DRAFT_STATE].modified_) {
890
- revokeScope(scope);
891
- die(4);
892
- }
893
- if (isDraftable(result)) {
894
- result = finalize(scope, result);
895
- }
896
- const { patchPlugin_ } = scope;
897
- if (patchPlugin_) {
898
- patchPlugin_.generateReplacementPatches_(
899
- baseDraft[DRAFT_STATE].base_,
900
- result,
901
- scope
902
- );
903
- }
904
- } else {
905
- result = finalize(scope, baseDraft);
906
- }
907
- maybeFreeze(scope, result, true);
908
- revokeScope(scope);
909
- if (scope.patches_) {
910
- scope.patchListener_(scope.patches_, scope.inversePatches_);
911
- }
912
- return result !== NOTHING ? result : void 0;
913
- }
914
- function finalize(rootScope, value) {
915
- if (isFrozen(value))
916
- return value;
917
- const state = value[DRAFT_STATE];
918
- if (!state) {
919
- const finalValue = handleValue(value, rootScope.handledSet_, rootScope);
920
- return finalValue;
921
- }
922
- if (!isSameScope(state, rootScope)) {
923
- return value;
924
- }
925
- if (!state.modified_) {
926
- return state.base_;
927
- }
928
- if (!state.finalized_) {
929
- const { callbacks_ } = state;
930
- if (callbacks_) {
931
- while (callbacks_.length > 0) {
932
- const callback = callbacks_.pop();
933
- callback(rootScope);
934
- }
935
- }
936
- generatePatchesAndFinalize(state, rootScope);
937
- }
938
- return state.copy_;
939
- }
940
- function maybeFreeze(scope, value, deep = false) {
941
- if (!scope.parent_ && scope.immer_.autoFreeze_ && scope.canAutoFreeze_) {
942
- freeze(value, deep);
943
- }
944
- }
945
- function markStateFinalized(state) {
946
- state.finalized_ = true;
947
- state.scope_.unfinalizedDrafts_--;
948
- }
949
- var isSameScope = (state, rootScope) => state.scope_ === rootScope;
950
- var EMPTY_LOCATIONS_RESULT = [];
951
- function updateDraftInParent(parent, draftValue, finalizedValue, originalKey) {
952
- const parentCopy = latest(parent);
953
- const parentType = parent.type_;
954
- if (originalKey !== void 0) {
955
- const currentValue = get(parentCopy, originalKey, parentType);
956
- if (currentValue === draftValue) {
957
- set(parentCopy, originalKey, finalizedValue, parentType);
958
- return;
959
- }
960
- }
961
- if (!parent.draftLocations_) {
962
- const draftLocations = parent.draftLocations_ = /* @__PURE__ */ new Map();
963
- each(parentCopy, (key, value) => {
964
- if (isDraft(value)) {
965
- const keys = draftLocations.get(value) || [];
966
- keys.push(key);
967
- draftLocations.set(value, keys);
968
- }
969
- });
970
- }
971
- const locations = parent.draftLocations_.get(draftValue) ?? EMPTY_LOCATIONS_RESULT;
972
- for (const location of locations) {
973
- set(parentCopy, location, finalizedValue, parentType);
974
- }
975
- }
976
- function registerChildFinalizationCallback(parent, child, key) {
977
- parent.callbacks_.push(function childCleanup(rootScope) {
978
- const state = child;
979
- if (!state || !isSameScope(state, rootScope)) {
980
- return;
981
- }
982
- rootScope.mapSetPlugin_?.fixSetContents(state);
983
- const finalizedValue = getFinalValue(state);
984
- updateDraftInParent(parent, state.draft_ ?? state, finalizedValue, key);
985
- generatePatchesAndFinalize(state, rootScope);
986
- });
987
- }
988
- function generatePatchesAndFinalize(state, rootScope) {
989
- const shouldFinalize = state.modified_ && !state.finalized_ && (state.type_ === 3 || state.type_ === 1 && state.allIndicesReassigned_ || (state.assigned_?.size ?? 0) > 0);
990
- if (shouldFinalize) {
991
- const { patchPlugin_ } = rootScope;
992
- if (patchPlugin_) {
993
- const basePath = patchPlugin_.getPath(state);
994
- if (basePath) {
995
- patchPlugin_.generatePatches_(state, basePath, rootScope);
996
- }
997
- }
998
- markStateFinalized(state);
999
- }
1000
- }
1001
- function handleCrossReference(target, key, value) {
1002
- const { scope_ } = target;
1003
- if (isDraft(value)) {
1004
- const state = value[DRAFT_STATE];
1005
- if (isSameScope(state, scope_)) {
1006
- state.callbacks_.push(function crossReferenceCleanup() {
1007
- prepareCopy(target);
1008
- const finalizedValue = getFinalValue(state);
1009
- updateDraftInParent(target, value, finalizedValue, key);
1010
- });
1011
- }
1012
- } else if (isDraftable(value)) {
1013
- target.callbacks_.push(function nestedDraftCleanup() {
1014
- const targetCopy = latest(target);
1015
- if (target.type_ === 3) {
1016
- if (targetCopy.has(value)) {
1017
- handleValue(value, scope_.handledSet_, scope_);
1018
- }
1019
- } else {
1020
- if (get(targetCopy, key, target.type_) === value) {
1021
- if (scope_.drafts_.length > 1 && (target.assigned_.get(key) ?? false) === true && target.copy_) {
1022
- handleValue(
1023
- get(target.copy_, key, target.type_),
1024
- scope_.handledSet_,
1025
- scope_
1026
- );
1027
- }
1028
- }
1029
- }
1030
- });
1031
- }
1032
- }
1033
- function handleValue(target, handledSet, rootScope) {
1034
- if (!rootScope.immer_.autoFreeze_ && rootScope.unfinalizedDrafts_ < 1) {
1035
- return target;
1036
- }
1037
- if (isDraft(target) || handledSet.has(target) || !isDraftable(target) || isFrozen(target)) {
1038
- return target;
1039
- }
1040
- handledSet.add(target);
1041
- each(target, (key, value) => {
1042
- if (isDraft(value)) {
1043
- const state = value[DRAFT_STATE];
1044
- if (isSameScope(state, rootScope)) {
1045
- const updatedValue = getFinalValue(state);
1046
- set(target, key, updatedValue, target.type_);
1047
- markStateFinalized(state);
1048
- }
1049
- } else if (isDraftable(value)) {
1050
- handleValue(value, handledSet, rootScope);
1051
- }
1052
- });
1053
- return target;
1054
- }
1055
- function createProxyProxy(base, parent) {
1056
- const baseIsArray = isArray(base);
1057
- const state = {
1058
- type_: baseIsArray ? 1 : 0,
1059
- // Track which produce call this is associated with.
1060
- scope_: parent ? parent.scope_ : getCurrentScope(),
1061
- // True for both shallow and deep changes.
1062
- modified_: false,
1063
- // Used during finalization.
1064
- finalized_: false,
1065
- // Track which properties have been assigned (true) or deleted (false).
1066
- // actually instantiated in `prepareCopy()`
1067
- assigned_: void 0,
1068
- // The parent draft state.
1069
- parent_: parent,
1070
- // The base state.
1071
- base_: base,
1072
- // The base proxy.
1073
- draft_: null,
1074
- // set below
1075
- // The base copy with any updated values.
1076
- copy_: null,
1077
- // Called by the `produce` function.
1078
- revoke_: null,
1079
- isManual_: false,
1080
- // `callbacks` actually gets assigned in `createProxy`
1081
- callbacks_: void 0
1082
- };
1083
- let target = state;
1084
- let traps = objectTraps;
1085
- if (baseIsArray) {
1086
- target = [state];
1087
- traps = arrayTraps;
1088
- }
1089
- const { revoke, proxy } = Proxy.revocable(target, traps);
1090
- state.draft_ = proxy;
1091
- state.revoke_ = revoke;
1092
- return [proxy, state];
1093
- }
1094
- var objectTraps = {
1095
- get(state, prop) {
1096
- if (prop === DRAFT_STATE)
1097
- return state;
1098
- let arrayPlugin = state.scope_.arrayMethodsPlugin_;
1099
- const isArrayWithStringProp = state.type_ === 1 && typeof prop === "string";
1100
- if (isArrayWithStringProp) {
1101
- if (arrayPlugin?.isArrayOperationMethod(prop)) {
1102
- return arrayPlugin.createMethodInterceptor(state, prop);
1103
- }
1104
- }
1105
- const source = latest(state);
1106
- if (!has(source, prop, state.type_)) {
1107
- return readPropFromProto(state, source, prop);
1108
- }
1109
- const value = source[prop];
1110
- if (state.finalized_ || !isDraftable(value)) {
1111
- return value;
1112
- }
1113
- if (isArrayWithStringProp && state.operationMethod && arrayPlugin?.isMutatingArrayMethod(
1114
- state.operationMethod
1115
- ) && isArrayIndex(prop)) {
1116
- return value;
1117
- }
1118
- if (value === peek(state.base_, prop)) {
1119
- prepareCopy(state);
1120
- const childKey = state.type_ === 1 ? +prop : prop;
1121
- const childDraft = createProxy(state.scope_, value, state, childKey);
1122
- return state.copy_[childKey] = childDraft;
1123
- }
1124
- return value;
1125
- },
1126
- has(state, prop) {
1127
- return prop in latest(state);
1128
- },
1129
- ownKeys(state) {
1130
- return Reflect.ownKeys(latest(state));
1131
- },
1132
- set(state, prop, value) {
1133
- const desc = getDescriptorFromProto(latest(state), prop);
1134
- if (desc?.set) {
1135
- desc.set.call(state.draft_, value);
1136
- return true;
1137
- }
1138
- if (!state.modified_) {
1139
- const current2 = peek(latest(state), prop);
1140
- const currentState = current2?.[DRAFT_STATE];
1141
- if (currentState && currentState.base_ === value) {
1142
- state.copy_[prop] = value;
1143
- state.assigned_.set(prop, false);
1144
- return true;
1145
- }
1146
- if (is(value, current2) && (value !== void 0 || has(state.base_, prop, state.type_)))
1147
- return true;
1148
- prepareCopy(state);
1149
- markChanged(state);
1150
- }
1151
- if (state.copy_[prop] === value && // special case: handle new props with value 'undefined'
1152
- (value !== void 0 || prop in state.copy_) || // special case: NaN
1153
- Number.isNaN(value) && Number.isNaN(state.copy_[prop]))
1154
- return true;
1155
- state.copy_[prop] = value;
1156
- state.assigned_.set(prop, true);
1157
- handleCrossReference(state, prop, value);
1158
- return true;
1159
- },
1160
- deleteProperty(state, prop) {
1161
- prepareCopy(state);
1162
- if (peek(state.base_, prop) !== void 0 || prop in state.base_) {
1163
- state.assigned_.set(prop, false);
1164
- markChanged(state);
1165
- } else {
1166
- state.assigned_.delete(prop);
1167
- }
1168
- if (state.copy_) {
1169
- delete state.copy_[prop];
1170
- }
1171
- return true;
1172
- },
1173
- // Note: We never coerce `desc.value` into an Immer draft, because we can't make
1174
- // the same guarantee in ES5 mode.
1175
- getOwnPropertyDescriptor(state, prop) {
1176
- const owner = latest(state);
1177
- const desc = Reflect.getOwnPropertyDescriptor(owner, prop);
1178
- if (!desc)
1179
- return desc;
1180
- return {
1181
- [WRITABLE]: true,
1182
- [CONFIGURABLE]: state.type_ !== 1 || prop !== "length",
1183
- [ENUMERABLE]: desc[ENUMERABLE],
1184
- [VALUE]: owner[prop]
1185
- };
1186
- },
1187
- defineProperty() {
1188
- die(11);
1189
- },
1190
- getPrototypeOf(state) {
1191
- return getPrototypeOf(state.base_);
1192
- },
1193
- setPrototypeOf() {
1194
- die(12);
1195
- }
1196
- };
1197
- var arrayTraps = {};
1198
- for (let key in objectTraps) {
1199
- let fn = objectTraps[key];
1200
- arrayTraps[key] = function() {
1201
- const args = arguments;
1202
- args[0] = args[0][0];
1203
- return fn.apply(this, args);
1204
- };
1205
- }
1206
- arrayTraps.deleteProperty = function(state, prop) {
1207
- if (process.env.NODE_ENV !== "production" && isNaN(parseInt(prop)))
1208
- die(13);
1209
- return arrayTraps.set.call(this, state, prop, void 0);
1210
- };
1211
- arrayTraps.set = function(state, prop, value) {
1212
- if (process.env.NODE_ENV !== "production" && prop !== "length" && isNaN(parseInt(prop)))
1213
- die(14);
1214
- return objectTraps.set.call(this, state[0], prop, value, state[0]);
1215
- };
1216
- function peek(draft, prop) {
1217
- const state = draft[DRAFT_STATE];
1218
- const source = state ? latest(state) : draft;
1219
- return source[prop];
1220
- }
1221
- function readPropFromProto(state, source, prop) {
1222
- const desc = getDescriptorFromProto(source, prop);
1223
- return desc ? VALUE in desc ? desc[VALUE] : (
1224
- // This is a very special case, if the prop is a getter defined by the
1225
- // prototype, we should invoke it with the draft as context!
1226
- desc.get?.call(state.draft_)
1227
- ) : void 0;
1228
- }
1229
- function getDescriptorFromProto(source, prop) {
1230
- if (!(prop in source))
1231
- return void 0;
1232
- let proto = getPrototypeOf(source);
1233
- while (proto) {
1234
- const desc = Object.getOwnPropertyDescriptor(proto, prop);
1235
- if (desc)
1236
- return desc;
1237
- proto = getPrototypeOf(proto);
1238
- }
1239
- return void 0;
1240
- }
1241
- function markChanged(state) {
1242
- if (!state.modified_) {
1243
- state.modified_ = true;
1244
- if (state.parent_) {
1245
- markChanged(state.parent_);
1246
- }
1247
- }
1248
- }
1249
- function prepareCopy(state) {
1250
- if (!state.copy_) {
1251
- state.assigned_ = /* @__PURE__ */ new Map();
1252
- state.copy_ = shallowCopy(
1253
- state.base_,
1254
- state.scope_.immer_.useStrictShallowCopy_
1255
- );
1256
- }
1257
- }
1258
- var Immer2 = class {
1259
- constructor(config) {
1260
- this.autoFreeze_ = true;
1261
- this.useStrictShallowCopy_ = false;
1262
- this.useStrictIteration_ = false;
1263
- this.produce = (base, recipe, patchListener) => {
1264
- if (isFunction(base) && !isFunction(recipe)) {
1265
- const defaultBase = recipe;
1266
- recipe = base;
1267
- const self = this;
1268
- return function curriedProduce(base2 = defaultBase, ...args) {
1269
- return self.produce(base2, (draft) => recipe.call(this, draft, ...args));
1270
- };
1271
- }
1272
- if (!isFunction(recipe))
1273
- die(6);
1274
- if (patchListener !== void 0 && !isFunction(patchListener))
1275
- die(7);
1276
- let result;
1277
- if (isDraftable(base)) {
1278
- const scope = enterScope(this);
1279
- const proxy = createProxy(scope, base, void 0);
1280
- let hasError = true;
1281
- try {
1282
- result = recipe(proxy);
1283
- hasError = false;
1284
- } finally {
1285
- if (hasError)
1286
- revokeScope(scope);
1287
- else
1288
- leaveScope(scope);
1289
- }
1290
- usePatchesInScope(scope, patchListener);
1291
- return processResult(result, scope);
1292
- } else if (!base || !isObjectish(base)) {
1293
- result = recipe(base);
1294
- if (result === void 0)
1295
- result = base;
1296
- if (result === NOTHING)
1297
- result = void 0;
1298
- if (this.autoFreeze_)
1299
- freeze(result, true);
1300
- if (patchListener) {
1301
- const p = [];
1302
- const ip = [];
1303
- getPlugin(PluginPatches).generateReplacementPatches_(base, result, {
1304
- patches_: p,
1305
- inversePatches_: ip
1306
- });
1307
- patchListener(p, ip);
1308
- }
1309
- return result;
1310
- } else
1311
- die(1, base);
1312
- };
1313
- this.produceWithPatches = (base, recipe) => {
1314
- if (isFunction(base)) {
1315
- return (state, ...args) => this.produceWithPatches(state, (draft) => base(draft, ...args));
1316
- }
1317
- let patches, inversePatches;
1318
- const result = this.produce(base, recipe, (p, ip) => {
1319
- patches = p;
1320
- inversePatches = ip;
1321
- });
1322
- return [result, patches, inversePatches];
1323
- };
1324
- if (isBoolean(config?.autoFreeze))
1325
- this.setAutoFreeze(config.autoFreeze);
1326
- if (isBoolean(config?.useStrictShallowCopy))
1327
- this.setUseStrictShallowCopy(config.useStrictShallowCopy);
1328
- if (isBoolean(config?.useStrictIteration))
1329
- this.setUseStrictIteration(config.useStrictIteration);
1330
- }
1331
- createDraft(base) {
1332
- if (!isDraftable(base))
1333
- die(8);
1334
- if (isDraft(base))
1335
- base = current(base);
1336
- const scope = enterScope(this);
1337
- const proxy = createProxy(scope, base, void 0);
1338
- proxy[DRAFT_STATE].isManual_ = true;
1339
- leaveScope(scope);
1340
- return proxy;
1341
- }
1342
- finishDraft(draft, patchListener) {
1343
- const state = draft && draft[DRAFT_STATE];
1344
- if (!state || !state.isManual_)
1345
- die(9);
1346
- const { scope_: scope } = state;
1347
- usePatchesInScope(scope, patchListener);
1348
- return processResult(void 0, scope);
1349
- }
1350
- /**
1351
- * Pass true to automatically freeze all copies created by Immer.
1352
- *
1353
- * By default, auto-freezing is enabled.
1354
- */
1355
- setAutoFreeze(value) {
1356
- this.autoFreeze_ = value;
1357
- }
1358
- /**
1359
- * Pass true to enable strict shallow copy.
1360
- *
1361
- * By default, immer does not copy the object descriptors such as getter, setter and non-enumrable properties.
1362
- */
1363
- setUseStrictShallowCopy(value) {
1364
- this.useStrictShallowCopy_ = value;
1365
- }
1366
- /**
1367
- * Pass false to use faster iteration that skips non-enumerable properties
1368
- * but still handles symbols for compatibility.
1369
- *
1370
- * By default, strict iteration is enabled (includes all own properties).
1371
- */
1372
- setUseStrictIteration(value) {
1373
- this.useStrictIteration_ = value;
1374
- }
1375
- shouldUseStrictIteration() {
1376
- return this.useStrictIteration_;
1377
- }
1378
- applyPatches(base, patches) {
1379
- let i;
1380
- for (i = patches.length - 1; i >= 0; i--) {
1381
- const patch = patches[i];
1382
- if (patch.path.length === 0 && patch.op === "replace") {
1383
- base = patch.value;
1384
- break;
1385
- }
1386
- }
1387
- if (i > -1) {
1388
- patches = patches.slice(i + 1);
1389
- }
1390
- const applyPatchesImpl = getPlugin(PluginPatches).applyPatches_;
1391
- if (isDraft(base)) {
1392
- return applyPatchesImpl(base, patches);
1393
- }
1394
- return this.produce(
1395
- base,
1396
- (draft) => applyPatchesImpl(draft, patches)
1397
- );
1398
- }
1399
- };
1400
- function createProxy(rootScope, value, parent, key) {
1401
- const [draft, state] = isMap(value) ? getPlugin(PluginMapSet).proxyMap_(value, parent) : isSet(value) ? getPlugin(PluginMapSet).proxySet_(value, parent) : createProxyProxy(value, parent);
1402
- const scope = parent?.scope_ ?? getCurrentScope();
1403
- scope.drafts_.push(draft);
1404
- state.callbacks_ = parent?.callbacks_ ?? [];
1405
- state.key_ = key;
1406
- if (parent && key !== void 0) {
1407
- registerChildFinalizationCallback(parent, state, key);
1408
- } else {
1409
- state.callbacks_.push(function rootDraftCleanup(rootScope2) {
1410
- rootScope2.mapSetPlugin_?.fixSetContents(state);
1411
- const { patchPlugin_ } = rootScope2;
1412
- if (state.modified_ && patchPlugin_) {
1413
- patchPlugin_.generatePatches_(state, [], rootScope2);
1414
- }
1415
- });
1416
- }
1417
- return draft;
1418
- }
1419
- function current(value) {
1420
- if (!isDraft(value))
1421
- die(10, value);
1422
- return currentImpl(value);
1423
- }
1424
- function currentImpl(value) {
1425
- if (!isDraftable(value) || isFrozen(value))
1426
- return value;
1427
- const state = value[DRAFT_STATE];
1428
- let copy;
1429
- let strict = true;
1430
- if (state) {
1431
- if (!state.modified_)
1432
- return state.base_;
1433
- state.finalized_ = true;
1434
- copy = shallowCopy(value, state.scope_.immer_.useStrictShallowCopy_);
1435
- strict = state.scope_.immer_.shouldUseStrictIteration();
1436
- } else {
1437
- copy = shallowCopy(value, true);
1438
- }
1439
- each(
1440
- copy,
1441
- (key, childValue) => {
1442
- set(copy, key, currentImpl(childValue));
1443
- },
1444
- strict
1445
- );
1446
- if (state) {
1447
- state.finalized_ = false;
1448
- }
1449
- return copy;
1450
- }
1451
- var immer = new Immer2();
1452
- var produce = immer.produce;
1453
-
1454
- // node_modules/@reduxjs/toolkit/dist/redux-toolkit.modern.mjs
1455
- var composeWithDevTools = typeof window !== "undefined" && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ : function() {
1456
- if (arguments.length === 0) return void 0;
1457
- if (typeof arguments[0] === "object") return compose;
1458
- return compose.apply(null, arguments);
1459
- };
1460
- var devToolsEnhancer = typeof window !== "undefined" && window.__REDUX_DEVTOOLS_EXTENSION__ ? window.__REDUX_DEVTOOLS_EXTENSION__ : function() {
1461
- return function(noop3) {
1462
- return noop3;
1463
- };
1464
- };
1465
- var hasMatchFunction = (v) => {
1466
- return v && typeof v.match === "function";
1467
- };
1468
- function createAction(type, prepareAction) {
1469
- function actionCreator(...args) {
1470
- if (prepareAction) {
1471
- let prepared = prepareAction(...args);
1472
- if (!prepared) {
1473
- throw new Error(process.env.NODE_ENV === "production" ? formatProdErrorMessage(0) : "prepareAction did not return an object");
1474
- }
1475
- return {
1476
- type,
1477
- payload: prepared.payload,
1478
- ..."meta" in prepared && {
1479
- meta: prepared.meta
1480
- },
1481
- ..."error" in prepared && {
1482
- error: prepared.error
1483
- }
1484
- };
1485
- }
1486
- return {
1487
- type,
1488
- payload: args[0]
1489
- };
1490
- }
1491
- actionCreator.toString = () => `${type}`;
1492
- actionCreator.type = type;
1493
- actionCreator.match = (action) => isAction(action) && action.type === type;
1494
- return actionCreator;
1495
- }
1496
- function freezeDraftable(val) {
1497
- return isDraftable(val) ? produce(val, () => {
1498
- }) : val;
1499
- }
1500
- function getOrInsertComputed(map, key, compute) {
1501
- if (map.has(key)) return map.get(key);
1502
- return map.set(key, compute(key)).get(key);
1503
- }
1504
- function executeReducerBuilderCallback(builderCallback) {
1505
- const actionsMap = {};
1506
- const actionMatchers = [];
1507
- let defaultCaseReducer;
1508
- const builder = {
1509
- addCase(typeOrActionCreator, reducer) {
1510
- if (process.env.NODE_ENV !== "production") {
1511
- if (actionMatchers.length > 0) {
1512
- throw new Error(process.env.NODE_ENV === "production" ? formatProdErrorMessage(26) : "`builder.addCase` should only be called before calling `builder.addMatcher`");
1513
- }
1514
- if (defaultCaseReducer) {
1515
- throw new Error(process.env.NODE_ENV === "production" ? formatProdErrorMessage(27) : "`builder.addCase` should only be called before calling `builder.addDefaultCase`");
1516
- }
1517
- }
1518
- const type = typeof typeOrActionCreator === "string" ? typeOrActionCreator : typeOrActionCreator.type;
1519
- if (!type) {
1520
- throw new Error(process.env.NODE_ENV === "production" ? formatProdErrorMessage(28) : "`builder.addCase` cannot be called with an empty action type");
1521
- }
1522
- if (type in actionsMap) {
1523
- throw new Error(process.env.NODE_ENV === "production" ? formatProdErrorMessage(29) : `\`builder.addCase\` cannot be called with two reducers for the same action type '${type}'`);
1524
- }
1525
- actionsMap[type] = reducer;
1526
- return builder;
1527
- },
1528
- addAsyncThunk(asyncThunk, reducers) {
1529
- if (process.env.NODE_ENV !== "production") {
1530
- if (defaultCaseReducer) {
1531
- throw new Error(process.env.NODE_ENV === "production" ? formatProdErrorMessage(43) : "`builder.addAsyncThunk` should only be called before calling `builder.addDefaultCase`");
1532
- }
1533
- }
1534
- if (reducers.pending) actionsMap[asyncThunk.pending.type] = reducers.pending;
1535
- if (reducers.rejected) actionsMap[asyncThunk.rejected.type] = reducers.rejected;
1536
- if (reducers.fulfilled) actionsMap[asyncThunk.fulfilled.type] = reducers.fulfilled;
1537
- if (reducers.settled) actionMatchers.push({
1538
- matcher: asyncThunk.settled,
1539
- reducer: reducers.settled
1540
- });
1541
- return builder;
1542
- },
1543
- addMatcher(matcher, reducer) {
1544
- if (process.env.NODE_ENV !== "production") {
1545
- if (defaultCaseReducer) {
1546
- throw new Error(process.env.NODE_ENV === "production" ? formatProdErrorMessage(30) : "`builder.addMatcher` should only be called before calling `builder.addDefaultCase`");
1547
- }
1548
- }
1549
- actionMatchers.push({
1550
- matcher,
1551
- reducer
1552
- });
1553
- return builder;
1554
- },
1555
- addDefaultCase(reducer) {
1556
- if (process.env.NODE_ENV !== "production") {
1557
- if (defaultCaseReducer) {
1558
- throw new Error(process.env.NODE_ENV === "production" ? formatProdErrorMessage(31) : "`builder.addDefaultCase` can only be called once");
1559
- }
1560
- }
1561
- defaultCaseReducer = reducer;
1562
- return builder;
1563
- }
1564
- };
1565
- builderCallback(builder);
1566
- return [actionsMap, actionMatchers, defaultCaseReducer];
1567
- }
1568
- function isStateFunction(x) {
1569
- return typeof x === "function";
1570
- }
1571
- function createReducer(initialState, mapOrBuilderCallback) {
1572
- if (process.env.NODE_ENV !== "production") {
1573
- if (typeof mapOrBuilderCallback === "object") {
1574
- throw new Error(process.env.NODE_ENV === "production" ? formatProdErrorMessage(8) : "The object notation for `createReducer` has been removed. Please use the 'builder callback' notation instead: https://redux-toolkit.js.org/api/createReducer");
1575
- }
1576
- }
1577
- let [actionsMap, finalActionMatchers, finalDefaultCaseReducer] = executeReducerBuilderCallback(mapOrBuilderCallback);
1578
- let getInitialState;
1579
- if (isStateFunction(initialState)) {
1580
- getInitialState = () => freezeDraftable(initialState());
1581
- } else {
1582
- const frozenInitialState = freezeDraftable(initialState);
1583
- getInitialState = () => frozenInitialState;
1584
- }
1585
- function reducer(state = getInitialState(), action) {
1586
- let caseReducers = [actionsMap[action.type], ...finalActionMatchers.filter(({
1587
- matcher
1588
- }) => matcher(action)).map(({
1589
- reducer: reducer2
1590
- }) => reducer2)];
1591
- if (caseReducers.filter((cr) => !!cr).length === 0) {
1592
- caseReducers = [finalDefaultCaseReducer];
1593
- }
1594
- return caseReducers.reduce((previousState, caseReducer) => {
1595
- if (caseReducer) {
1596
- if (isDraft(previousState)) {
1597
- const draft = previousState;
1598
- const result = caseReducer(draft, action);
1599
- if (result === void 0) {
1600
- return previousState;
1601
- }
1602
- return result;
1603
- } else if (!isDraftable(previousState)) {
1604
- const result = caseReducer(previousState, action);
1605
- if (result === void 0) {
1606
- if (previousState === null) {
1607
- return previousState;
1608
- }
1609
- throw Error("A case reducer on a non-draftable value must not return undefined");
1610
- }
1611
- return result;
1612
- } else {
1613
- return produce(previousState, (draft) => {
1614
- return caseReducer(draft, action);
1615
- });
1616
- }
1617
- }
1618
- return previousState;
1619
- }, state);
1620
- }
1621
- reducer.getInitialState = getInitialState;
1622
- return reducer;
1623
- }
1624
- var matches = (matcher, action) => {
1625
- if (hasMatchFunction(matcher)) {
1626
- return matcher.match(action);
1627
- } else {
1628
- return matcher(action);
1629
- }
1630
- };
1631
- function isAnyOf(...matchers) {
1632
- return (action) => {
1633
- return matchers.some((matcher) => matches(matcher, action));
1634
- };
1635
- }
1636
- var urlAlphabet = "ModuleSymbhasOwnPr-0123456789ABCDEFGHNRVfgctiUvz_KqYTJkLxpZXIjQW";
1637
- var nanoid = (size = 21) => {
1638
- let id = "";
1639
- let i = size;
1640
- while (i--) {
1641
- id += urlAlphabet[Math.random() * 64 | 0];
1642
- }
1643
- return id;
1644
- };
1645
- var commonProperties = ["name", "message", "stack", "code"];
1646
- var RejectWithValue = class {
1647
- constructor(payload, meta) {
1648
- __publicField(this, "payload");
1649
- __publicField(this, "meta");
1650
- /*
1651
- type-only property to distinguish between RejectWithValue and FulfillWithMeta
1652
- does not exist at runtime
1653
- */
1654
- __publicField(this, "_type");
1655
- this.payload = payload;
1656
- this.meta = meta;
1657
- }
1658
- };
1659
- var FulfillWithMeta = class {
1660
- constructor(payload, meta) {
1661
- __publicField(this, "payload");
1662
- __publicField(this, "meta");
1663
- /*
1664
- type-only property to distinguish between RejectWithValue and FulfillWithMeta
1665
- does not exist at runtime
1666
- */
1667
- __publicField(this, "_type");
1668
- this.payload = payload;
1669
- this.meta = meta;
1670
- }
1671
- };
1672
- var miniSerializeError = (value) => {
1673
- if (typeof value === "object" && value !== null) {
1674
- const simpleError = {};
1675
- for (const property of commonProperties) {
1676
- if (typeof value[property] === "string") {
1677
- simpleError[property] = value[property];
1678
- }
1679
- }
1680
- return simpleError;
1681
- }
1682
- return {
1683
- message: String(value)
1684
- };
1685
- };
1686
- var externalAbortMessage = "External signal was aborted";
1687
- var createAsyncThunk = /* @__PURE__ */ (() => {
1688
- function createAsyncThunk2(typePrefix, payloadCreator, options) {
1689
- const fulfilled = createAction(typePrefix + "/fulfilled", (payload, requestId, arg, meta) => ({
1690
- payload,
1691
- meta: {
1692
- ...meta || {},
1693
- arg,
1694
- requestId,
1695
- requestStatus: "fulfilled"
1696
- }
1697
- }));
1698
- const pending = createAction(typePrefix + "/pending", (requestId, arg, meta) => ({
1699
- payload: void 0,
1700
- meta: {
1701
- ...meta || {},
1702
- arg,
1703
- requestId,
1704
- requestStatus: "pending"
1705
- }
1706
- }));
1707
- const rejected = createAction(typePrefix + "/rejected", (error, requestId, arg, payload, meta) => ({
1708
- payload,
1709
- error: (options && options.serializeError || miniSerializeError)(error || "Rejected"),
1710
- meta: {
1711
- ...meta || {},
1712
- arg,
1713
- requestId,
1714
- rejectedWithValue: !!payload,
1715
- requestStatus: "rejected",
1716
- aborted: error?.name === "AbortError",
1717
- condition: error?.name === "ConditionError"
1718
- }
1719
- }));
1720
- function actionCreator(arg, {
1721
- signal
1722
- } = {}) {
1723
- return (dispatch, getState, extra) => {
1724
- const requestId = options?.idGenerator ? options.idGenerator(arg) : nanoid();
1725
- const abortController = new AbortController();
1726
- let abortHandler;
1727
- let abortReason;
1728
- function abort(reason) {
1729
- abortReason = reason;
1730
- abortController.abort();
1731
- }
1732
- if (signal) {
1733
- if (signal.aborted) {
1734
- abort(externalAbortMessage);
531
+ dotContainer: { alignItems: "center", height: DOT_FULL, justifyContent: "center", width: DOT_FULL },
532
+ dotsClip: { overflow: "hidden", width: CLIP_WIDTH },
533
+ dotsRow: { flexDirection: "row", gap: DOT_GAP },
534
+ pill: {
535
+ alignItems: "center",
536
+ borderRadius: PILL_RADIUS,
537
+ height: PILL_HEIGHT,
538
+ justifyContent: "center",
539
+ overflow: "hidden",
540
+ width: PILL_WIDTH
541
+ },
542
+ pillContainer: { alignItems: "center", left: 0, position: "absolute", right: 0, zIndex: 3 }
543
+ });
544
+
545
+ // src/internal/useScrollHandlerJS.ts
546
+ import { useCallback as useCallback3, useContext as useContext6, useRef as useRef3 } from "react";
547
+ import { withTiming as withTiming3 } from "react-native-reanimated";
548
+ var REMOUNT_RETRY_TOLERANCE = 1;
549
+ var REMOUNT_RETRY_MAX_ATTEMPTS = 8;
550
+ function useScrollHandlerJS({ capturedGeneration, chipHidden, chipThreshold = 100, footerFixed, headerFixed, isHorizontal, jsListGeneration, remountTarget = null, scrollTo }) {
551
+ const { footerHeightShared, footerOffset, headerHeightShared, headerOffset, pullSearchHeightShared, scrollPosition, snapBackFooterShared, snapBackHeaderShared } = useContext6(ScrollViewContext);
552
+ const snapUpAccum = useRef3(0);
553
+ const fromBottomBounce = useRef3(false);
554
+ const pendingRemountTarget = useRef3(remountTarget);
555
+ const remountAttempts = useRef3(0);
556
+ const onScroll = useCallback3(
557
+ (event) => {
558
+ if (jsListGeneration.current !== capturedGeneration.current) return;
559
+ const {
560
+ contentOffset: { x, y },
561
+ contentSize: { height: contentHeight },
562
+ layoutMeasurement: { height: layoutHeight }
563
+ } = event.nativeEvent;
564
+ if (pendingRemountTarget.current !== null) {
565
+ const target = pendingRemountTarget.current;
566
+ if (Math.abs(y - target) < REMOUNT_RETRY_TOLERANCE) {
567
+ pendingRemountTarget.current = null;
568
+ } else {
569
+ remountAttempts.current += 1;
570
+ if (remountAttempts.current > REMOUNT_RETRY_MAX_ATTEMPTS) {
571
+ pendingRemountTarget.current = null;
1735
572
  } else {
1736
- signal.addEventListener("abort", () => abort(externalAbortMessage), {
1737
- once: true
1738
- });
573
+ scrollTo?.(target, false);
574
+ return;
1739
575
  }
1740
576
  }
1741
- const promise = (async function() {
1742
- let finalAction;
1743
- try {
1744
- let conditionResult = options?.condition?.(arg, {
1745
- getState,
1746
- extra
1747
- });
1748
- if (isThenable(conditionResult)) {
1749
- conditionResult = await conditionResult;
1750
- }
1751
- if (conditionResult === false || abortController.signal.aborted) {
1752
- throw {
1753
- name: "ConditionError",
1754
- message: "Aborted due to condition callback returning false."
1755
- };
1756
- }
1757
- const abortedPromise = new Promise((_, reject) => {
1758
- abortHandler = () => {
1759
- reject({
1760
- name: "AbortError",
1761
- message: abortReason || "Aborted"
1762
- });
1763
- };
1764
- abortController.signal.addEventListener("abort", abortHandler, {
1765
- once: true
1766
- });
1767
- });
1768
- dispatch(pending(requestId, arg, options?.getPendingMeta?.({
1769
- requestId,
1770
- arg
1771
- }, {
1772
- getState,
1773
- extra
1774
- })));
1775
- finalAction = await Promise.race([abortedPromise, Promise.resolve(payloadCreator(arg, {
1776
- dispatch,
1777
- getState,
1778
- extra,
1779
- requestId,
1780
- signal: abortController.signal,
1781
- abort,
1782
- rejectWithValue: ((value, meta) => {
1783
- return new RejectWithValue(value, meta);
1784
- }),
1785
- fulfillWithValue: ((value, meta) => {
1786
- return new FulfillWithMeta(value, meta);
1787
- })
1788
- })).then((result) => {
1789
- if (result instanceof RejectWithValue) {
1790
- throw result;
1791
- }
1792
- if (result instanceof FulfillWithMeta) {
1793
- return fulfilled(result.payload, requestId, arg, result.meta);
1794
- }
1795
- return fulfilled(result, requestId, arg);
1796
- })]);
1797
- } catch (err) {
1798
- finalAction = err instanceof RejectWithValue ? rejected(null, requestId, arg, err.payload, err.meta) : rejected(err, requestId, arg);
1799
- } finally {
1800
- if (abortHandler) {
1801
- abortController.signal.removeEventListener("abort", abortHandler);
1802
- }
1803
- }
1804
- const skipDispatch = options && !options.dispatchConditionRejection && rejected.match(finalAction) && finalAction.meta.condition;
1805
- if (!skipDispatch) {
1806
- dispatch(finalAction);
1807
- }
1808
- return finalAction;
1809
- })();
1810
- return Object.assign(promise, {
1811
- abort,
1812
- requestId,
1813
- arg,
1814
- unwrap() {
1815
- return promise.then(unwrapResult);
1816
- }
1817
- });
1818
- };
1819
- }
1820
- return Object.assign(actionCreator, {
1821
- pending,
1822
- rejected,
1823
- fulfilled,
1824
- settled: isAnyOf(rejected, fulfilled),
1825
- typePrefix
1826
- });
1827
- }
1828
- createAsyncThunk2.withTypes = () => createAsyncThunk2;
1829
- return createAsyncThunk2;
1830
- })();
1831
- function unwrapResult(action) {
1832
- if (action.meta && action.meta.rejectedWithValue) {
1833
- throw action.payload;
1834
- }
1835
- if (action.error) {
1836
- throw action.error;
1837
- }
1838
- return action.payload;
1839
- }
1840
- function isThenable(value) {
1841
- return value !== null && typeof value === "object" && typeof value.then === "function";
1842
- }
1843
- var asyncThunkSymbol = /* @__PURE__ */ Symbol.for("rtk-slice-createasyncthunk");
1844
- var asyncThunkCreator = {
1845
- [asyncThunkSymbol]: createAsyncThunk
1846
- };
1847
- function getType(slice2, actionKey) {
1848
- return `${slice2}/${actionKey}`;
1849
- }
1850
- function buildCreateSlice({
1851
- creators
1852
- } = {}) {
1853
- const cAT = creators?.asyncThunk?.[asyncThunkSymbol];
1854
- return function createSlice2(options) {
1855
- const {
1856
- name,
1857
- reducerPath = name
1858
- } = options;
1859
- if (!name) {
1860
- throw new Error(process.env.NODE_ENV === "production" ? formatProdErrorMessage(11) : "`name` is a required option for createSlice");
1861
- }
1862
- if (typeof process !== "undefined" && process.env.NODE_ENV === "development") {
1863
- if (options.initialState === void 0) {
1864
- console.error("You must provide an `initialState` value that is not `undefined`. You may have misspelled `initialState`");
1865
- }
1866
- }
1867
- const reducers = (typeof options.reducers === "function" ? options.reducers(buildReducerCreators()) : options.reducers) || {};
1868
- const reducerNames = Object.keys(reducers);
1869
- const context = {
1870
- sliceCaseReducersByName: {},
1871
- sliceCaseReducersByType: {},
1872
- actionCreators: {},
1873
- sliceMatchers: []
1874
- };
1875
- const contextMethods = {
1876
- addCase(typeOrActionCreator, reducer2) {
1877
- const type = typeof typeOrActionCreator === "string" ? typeOrActionCreator : typeOrActionCreator.type;
1878
- if (!type) {
1879
- throw new Error(process.env.NODE_ENV === "production" ? formatProdErrorMessage(12) : "`context.addCase` cannot be called with an empty action type");
1880
- }
1881
- if (type in context.sliceCaseReducersByType) {
1882
- throw new Error(process.env.NODE_ENV === "production" ? formatProdErrorMessage(13) : "`context.addCase` cannot be called with two reducers for the same action type: " + type);
1883
- }
1884
- context.sliceCaseReducersByType[type] = reducer2;
1885
- return contextMethods;
1886
- },
1887
- addMatcher(matcher, reducer2) {
1888
- context.sliceMatchers.push({
1889
- matcher,
1890
- reducer: reducer2
1891
- });
1892
- return contextMethods;
1893
- },
1894
- exposeAction(name2, actionCreator) {
1895
- context.actionCreators[name2] = actionCreator;
1896
- return contextMethods;
1897
- },
1898
- exposeCaseReducer(name2, reducer2) {
1899
- context.sliceCaseReducersByName[name2] = reducer2;
1900
- return contextMethods;
1901
577
  }
1902
- };
1903
- reducerNames.forEach((reducerName) => {
1904
- const reducerDefinition = reducers[reducerName];
1905
- const reducerDetails = {
1906
- reducerName,
1907
- type: getType(name, reducerName),
1908
- createNotation: typeof options.reducers === "function"
1909
- };
1910
- if (isAsyncThunkSliceReducerDefinition(reducerDefinition)) {
1911
- handleThunkCaseReducerDefinition(reducerDetails, reducerDefinition, contextMethods, cAT);
1912
- } else {
1913
- handleNormalReducerDefinition(reducerDetails, reducerDefinition, contextMethods);
578
+ if (isHorizontal) {
579
+ scrollPosition.value = x;
580
+ chipHidden.value = x < chipThreshold ? 1 : 0;
581
+ return;
1914
582
  }
1915
- });
1916
- function buildReducer() {
1917
- if (process.env.NODE_ENV !== "production") {
1918
- if (typeof options.extraReducers === "object") {
1919
- throw new Error(process.env.NODE_ENV === "production" ? formatProdErrorMessage(14) : "The object notation for `createSlice.extraReducers` has been removed. Please use the 'builder callback' notation instead: https://redux-toolkit.js.org/api/createSlice");
1920
- }
583
+ const delta = y - scrollPosition.value;
584
+ scrollPosition.value = y;
585
+ chipHidden.value = y < chipThreshold ? 1 : 0;
586
+ const maxScroll = contentHeight - layoutHeight;
587
+ if (maxScroll > 0 && y >= maxScroll) {
588
+ fromBottomBounce.current = true;
589
+ snapUpAccum.current = 0;
590
+ } else if (fromBottomBounce.current) {
591
+ fromBottomBounce.current = false;
1921
592
  }
1922
- const [extraReducers = {}, actionMatchers = [], defaultCaseReducer = void 0] = typeof options.extraReducers === "function" ? executeReducerBuilderCallback(options.extraReducers) : [options.extraReducers];
1923
- const finalCaseReducers = {
1924
- ...extraReducers,
1925
- ...context.sliceCaseReducersByType
1926
- };
1927
- return createReducer(options.initialState, (builder) => {
1928
- for (let key in finalCaseReducers) {
1929
- builder.addCase(key, finalCaseReducers[key]);
1930
- }
1931
- for (let sM of context.sliceMatchers) {
1932
- builder.addMatcher(sM.matcher, sM.reducer);
1933
- }
1934
- for (let m of actionMatchers) {
1935
- builder.addMatcher(m.matcher, m.reducer);
1936
- }
1937
- if (defaultCaseReducer) {
1938
- builder.addDefaultCase(defaultCaseReducer);
1939
- }
1940
- });
1941
- }
1942
- const selectSelf = (state) => state;
1943
- const injectedSelectorCache = /* @__PURE__ */ new Map();
1944
- const injectedStateCache = /* @__PURE__ */ new WeakMap();
1945
- let _reducer;
1946
- function reducer(state, action) {
1947
- if (!_reducer) _reducer = buildReducer();
1948
- return _reducer(state, action);
1949
- }
1950
- function getInitialState() {
1951
- if (!_reducer) _reducer = buildReducer();
1952
- return _reducer.getInitialState();
1953
- }
1954
- function makeSelectorProps(reducerPath2, injected = false) {
1955
- function selectSlice(state) {
1956
- let sliceState = state[reducerPath2];
1957
- if (typeof sliceState === "undefined") {
1958
- if (injected) {
1959
- sliceState = getOrInsertComputed(injectedStateCache, selectSlice, getInitialState);
1960
- } else if (process.env.NODE_ENV !== "production") {
1961
- throw new Error(process.env.NODE_ENV === "production" ? formatProdErrorMessage(15) : "selectSlice returned undefined for an uninjected slice reducer");
593
+ const snapHeader = snapBackHeaderShared.value && !headerFixed;
594
+ const snapFooter = snapBackFooterShared.value && !footerFixed;
595
+ if (snapHeader || snapFooter) {
596
+ if (y <= -headerHeightShared.value) {
597
+ snapUpAccum.current = 0;
598
+ if (snapHeader) headerOffset.value = 0;
599
+ if (snapFooter) footerOffset.value = 0;
600
+ } else if (delta > 0) {
601
+ snapUpAccum.current = 0;
602
+ if (y >= -headerHeightShared.value + pullSearchHeightShared.value) {
603
+ if (snapHeader) headerOffset.value = Math.max(-headerHeightShared.value, Math.min(0, headerOffset.value - delta));
604
+ if (snapFooter) footerOffset.value = Math.max(0, Math.min(footerHeightShared.value, footerOffset.value + delta));
1962
605
  }
1963
- }
1964
- return sliceState;
1965
- }
1966
- function getSelectors(selectState = selectSelf) {
1967
- const selectorCache = getOrInsertComputed(injectedSelectorCache, injected, () => /* @__PURE__ */ new WeakMap());
1968
- return getOrInsertComputed(selectorCache, selectState, () => {
1969
- const map = {};
1970
- for (const [name2, selector] of Object.entries(options.selectors ?? {})) {
1971
- map[name2] = wrapSelector(selector, selectState, () => getOrInsertComputed(injectedStateCache, selectState, getInitialState), injected);
606
+ } else if (delta < 0 && !fromBottomBounce.current) {
607
+ if (y >= -headerHeightShared.value + pullSearchHeightShared.value) snapUpAccum.current -= delta;
608
+ if (snapUpAccum.current >= 10) {
609
+ snapUpAccum.current = 999;
610
+ if (snapHeader) headerOffset.value = withTiming3(0, { duration: 200 });
611
+ if (snapFooter) footerOffset.value = withTiming3(0, { duration: 200 });
1972
612
  }
1973
- return map;
1974
- });
1975
- }
1976
- return {
1977
- reducerPath: reducerPath2,
1978
- getSelectors,
1979
- get selectors() {
1980
- return getSelectors(selectSlice);
1981
- },
1982
- selectSlice
1983
- };
1984
- }
1985
- const slice2 = {
1986
- name,
1987
- reducer,
1988
- actions: context.actionCreators,
1989
- caseReducers: context.sliceCaseReducersByName,
1990
- getInitialState,
1991
- ...makeSelectorProps(reducerPath),
1992
- injectInto(injectable, {
1993
- reducerPath: pathOpt,
1994
- ...config
1995
- } = {}) {
1996
- const newReducerPath = pathOpt ?? reducerPath;
1997
- injectable.inject({
1998
- reducerPath: newReducerPath,
1999
- reducer
2000
- }, config);
2001
- return {
2002
- ...slice2,
2003
- ...makeSelectorProps(newReducerPath, true)
2004
- };
613
+ }
2005
614
  }
2006
- };
2007
- return slice2;
2008
- };
2009
- }
2010
- function wrapSelector(selector, selectState, getInitialState, injected) {
2011
- function wrapper(rootState, ...args) {
2012
- let sliceState = selectState(rootState);
2013
- if (typeof sliceState === "undefined") {
2014
- if (injected) {
2015
- sliceState = getInitialState();
2016
- } else if (process.env.NODE_ENV !== "production") {
2017
- throw new Error(process.env.NODE_ENV === "production" ? formatProdErrorMessage(16) : "selectState returned undefined for an uninjected slice reducer");
615
+ },
616
+ [capturedGeneration, chipHidden, chipThreshold, footerFixed, footerHeightShared, footerOffset, headerFixed, headerHeightShared, headerOffset, isHorizontal, jsListGeneration, pullSearchHeightShared, scrollPosition, scrollTo, snapBackFooterShared, snapBackHeaderShared]
617
+ );
618
+ const onScrollBeginDrag = useCallback3(() => {
619
+ fromBottomBounce.current = false;
620
+ snapUpAccum.current = 0;
621
+ }, []);
622
+ const onMomentumScrollBegin = useCallback3(() => {
623
+ }, []);
624
+ const onScrollEndDrag = useCallback3(
625
+ (event) => {
626
+ if (isHorizontal) return;
627
+ const {
628
+ contentOffset: { y },
629
+ contentSize: { height: contentHeight },
630
+ layoutMeasurement: { height: layoutHeight }
631
+ } = event.nativeEvent;
632
+ if (y >= contentHeight - layoutHeight - 10) {
633
+ fromBottomBounce.current = true;
634
+ snapUpAccum.current = 0;
2018
635
  }
2019
- }
2020
- return selector(sliceState, ...args);
2021
- }
2022
- wrapper.unwrapped = selector;
2023
- return wrapper;
636
+ },
637
+ [isHorizontal]
638
+ );
639
+ const onMomentumScrollEnd = useCallback3(() => {
640
+ fromBottomBounce.current = false;
641
+ snapUpAccum.current = 0;
642
+ }, []);
643
+ return { onMomentumScrollBegin, onMomentumScrollEnd, onScroll, onScrollBeginDrag, onScrollEndDrag };
2024
644
  }
2025
- var createSlice = /* @__PURE__ */ buildCreateSlice();
2026
- function buildReducerCreators() {
2027
- function asyncThunk(payloadCreator, config) {
2028
- return {
2029
- _reducerDefinitionType: "asyncThunk",
2030
- payloadCreator,
2031
- ...config
2032
- };
2033
- }
2034
- asyncThunk.withTypes = () => asyncThunk;
2035
- return {
2036
- reducer(caseReducer) {
2037
- return Object.assign({
2038
- // hack so the wrapping function has the same name as the original
2039
- // we need to create a wrapper so the `reducerDefinitionType` is not assigned to the original
2040
- [caseReducer.name](...args) {
2041
- return caseReducer(...args);
2042
- }
2043
- }[caseReducer.name], {
2044
- _reducerDefinitionType: "reducer"
2045
- /* reducer */
2046
- });
645
+
646
+ // src/FlatList.tsx
647
+ import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
648
+ 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 }) => {
649
+ const scrollView = useRef4(null);
650
+ const isHorizontal = horizontal === true;
651
+ const showDots = isHorizontal && pagingEnabled === true && (data?.length ?? 0) > 1;
652
+ const cols = numColumns && numColumns > 1 ? numColumns : 1;
653
+ const rowData = useMemo3(() => {
654
+ if (cols <= 1 || !data) return data;
655
+ const items = Array.from(data);
656
+ const rows = [];
657
+ for (let i = 0; i < items.length; i += cols) rows.push(items.slice(i, i + cols));
658
+ return rows;
659
+ }, [cols, data]);
660
+ const rowKeyExtractor = useCallback4(
661
+ (row, rowIndex) => {
662
+ if (cols <= 1) return keyExtractor ? keyExtractor(row, rowIndex) : defaultKeyExtractor(row, rowIndex);
663
+ return row.map((item, kk) => keyExtractor ? keyExtractor(item, rowIndex * cols + kk) : defaultKeyExtractor(item, rowIndex * cols + kk)).join(":");
2047
664
  },
2048
- preparedReducer(prepare, reducer) {
2049
- return {
2050
- _reducerDefinitionType: "reducerWithPrepare",
2051
- prepare,
2052
- reducer
2053
- };
665
+ [cols, keyExtractor]
666
+ );
667
+ const rowRenderItem = useCallback4(
668
+ (info) => {
669
+ if (cols <= 1) return renderItem ? renderItem(info) : null;
670
+ const row = info.item;
671
+ return /* @__PURE__ */ jsx5(View3, { style: [styles4.row, columnWrapperStyle], children: row.map((item, kk) => /* @__PURE__ */ jsx5(Fragment2, { children: renderItem ? renderItem({ index: info.index * cols + kk, item, separators: info.separators }) : null }, kk)) });
2054
672
  },
2055
- asyncThunk
2056
- };
2057
- }
2058
- function handleNormalReducerDefinition({
2059
- type,
2060
- reducerName,
2061
- createNotation
2062
- }, maybeReducerWithPrepare, context) {
2063
- let caseReducer;
2064
- let prepareCallback;
2065
- if ("reducer" in maybeReducerWithPrepare) {
2066
- if (createNotation && !isCaseReducerWithPrepareDefinition(maybeReducerWithPrepare)) {
2067
- throw new Error(process.env.NODE_ENV === "production" ? formatProdErrorMessage(17) : "Please use the `create.preparedReducer` notation for prepared action creators with the `create` notation.");
2068
- }
2069
- caseReducer = maybeReducerWithPrepare.reducer;
2070
- prepareCallback = maybeReducerWithPrepare.prepare;
2071
- } else {
2072
- caseReducer = maybeReducerWithPrepare;
2073
- }
2074
- context.addCase(type, caseReducer).exposeCaseReducer(reducerName, caseReducer).exposeAction(reducerName, prepareCallback ? createAction(type, prepareCallback) : createAction(type));
2075
- }
2076
- function isAsyncThunkSliceReducerDefinition(reducerDefinition) {
2077
- return reducerDefinition._reducerDefinitionType === "asyncThunk";
2078
- }
2079
- function isCaseReducerWithPrepareDefinition(reducerDefinition) {
2080
- return reducerDefinition._reducerDefinitionType === "reducerWithPrepare";
2081
- }
2082
- function handleThunkCaseReducerDefinition({
2083
- type,
2084
- reducerName
2085
- }, reducerDefinition, context, cAT) {
2086
- if (!cAT) {
2087
- throw new Error(process.env.NODE_ENV === "production" ? formatProdErrorMessage(18) : "Cannot use `create.asyncThunk` in the built-in `createSlice`. Use `buildCreateSlice({ creators: { asyncThunk: asyncThunkCreator } })` to create a customised version of `createSlice`.");
2088
- }
673
+ [cols, columnWrapperStyle, renderItem]
674
+ );
675
+ const { chipHidden, chipStyle, containerStyle, contentInset, contentOffset, footerFixed, headerFixed } = useScrollList({ footerFixed: footerFixedProp, headerFixed: headerFixedProp, isHorizontal, keyboardAware, pullSearchHeight, style });
676
+ const { jsListGeneration, onJsListUnmount } = useContext7(ScrollViewContext);
677
+ const capturedGeneration = useRef4(jsListGeneration.current);
678
+ useLayoutEffect3(() => {
679
+ capturedGeneration.current = jsListGeneration.current;
680
+ }, [jsListGeneration]);
681
+ useLayoutEffect3(() => () => onJsListUnmount(), [onJsListUnmount]);
682
+ const scrollTo = useCallback4((offset, animated) => {
683
+ scrollView.current?.scrollToOffset({ offset, animated });
684
+ }, []);
2089
685
  const {
2090
- payloadCreator,
2091
- fulfilled,
2092
- pending,
2093
- rejected,
2094
- settled,
2095
- options
2096
- } = reducerDefinition;
2097
- const thunk = cAT(type, payloadCreator, options);
2098
- context.exposeAction(reducerName, thunk);
2099
- if (fulfilled) {
2100
- context.addCase(thunk.fulfilled, fulfilled);
2101
- }
2102
- if (pending) {
2103
- context.addCase(thunk.pending, pending);
2104
- }
2105
- if (rejected) {
2106
- context.addCase(thunk.rejected, rejected);
2107
- }
2108
- if (settled) {
2109
- context.addMatcher(thunk.settled, settled);
2110
- }
2111
- context.exposeCaseReducer(reducerName, {
2112
- fulfilled: fulfilled || noop,
2113
- pending: pending || noop,
2114
- rejected: rejected || noop,
2115
- settled: settled || noop
686
+ activeListHeader: pullSearchHeader,
687
+ handleMomentumScrollEnd,
688
+ handleScrollBeginDrag,
689
+ handleScrollEndDrag,
690
+ hiddenHeader,
691
+ pullSearchMinHeight,
692
+ remountTarget
693
+ } = useScrollInit({
694
+ listHeaderComponent: externalListHeaderComponent,
695
+ onMomentumScrollEnd: externalMomentumScrollEnd,
696
+ onRefresh: pullSearchHeight ? onRefresh : void 0,
697
+ onScrollBeginDrag: externalScrollBeginDrag,
698
+ onScrollEndDrag: externalScrollEndDrag,
699
+ pullSearchHeight,
700
+ scrollTo
2116
701
  });
2117
- }
2118
- function noop() {
2119
- }
2120
- var listener = "listener";
2121
- var completed = "completed";
2122
- var cancelled = "cancelled";
2123
- var taskCancelled = `task-${cancelled}`;
2124
- var taskCompleted = `task-${completed}`;
2125
- var listenerCancelled = `${listener}-${cancelled}`;
2126
- var listenerCompleted = `${listener}-${completed}`;
2127
- var {
2128
- assign
2129
- } = Object;
2130
- var alm = "listenerMiddleware";
2131
- var addListener = /* @__PURE__ */ assign(/* @__PURE__ */ createAction(`${alm}/add`), {
2132
- withTypes: () => addListener
702
+ const activeListHeader = useMemo3(() => {
703
+ if (!renderFilters) return pullSearchHeader;
704
+ const Inner = pullSearchHeader;
705
+ return () => /* @__PURE__ */ jsxs3(Fragment3, { children: [
706
+ Inner ? typeof Inner === "function" ? /* @__PURE__ */ jsx5(Inner, {}) : Inner : null,
707
+ renderFilters
708
+ ] });
709
+ }, [pullSearchHeader, renderFilters]);
710
+ const contentContainerStyle = useMemo3(() => isHorizontal ? externalContentContainerStyle : [{ minHeight: Dimensions2.get("window").height - contentInset.top - contentInset.bottom + pullSearchMinHeight }, externalContentContainerStyle], [isHorizontal, contentInset.bottom, contentInset.top, externalContentContainerStyle, pullSearchMinHeight]);
711
+ const scrollHandler = useScrollHandlerJS({ capturedGeneration, chipHidden, chipThreshold, footerFixed, headerFixed, isHorizontal, jsListGeneration, remountTarget, scrollTo });
712
+ const onScrollBeginDrag = useCallback4(
713
+ (e) => {
714
+ scrollHandler.onScrollBeginDrag(e);
715
+ handleScrollBeginDrag(e);
716
+ },
717
+ [scrollHandler, handleScrollBeginDrag]
718
+ );
719
+ const onScrollEndDrag = useCallback4(
720
+ (e) => {
721
+ scrollHandler.onScrollEndDrag(e);
722
+ handleScrollEndDrag(e);
723
+ },
724
+ [scrollHandler, handleScrollEndDrag]
725
+ );
726
+ const onMomentumScrollEnd = useCallback4(
727
+ (e) => {
728
+ scrollHandler.onMomentumScrollEnd(e);
729
+ handleMomentumScrollEnd(e);
730
+ },
731
+ [scrollHandler, handleMomentumScrollEnd]
732
+ );
733
+ const handleScrollToTop = useCallback4(() => {
734
+ if (isHorizontal) {
735
+ scrollView.current?.scrollToOffset({ offset: 0, animated: true });
736
+ return;
737
+ }
738
+ const offset = pullSearchHeight ? -contentInset.top + pullSearchHeight : -contentInset.top;
739
+ scrollView.current?.scrollToOffset({ offset, animated: true });
740
+ }, [isHorizontal, contentInset.top, pullSearchHeight]);
741
+ const handleContentSizeChange = useCallback4(
742
+ (w, h) => {
743
+ if (onContentSizeChange) onContentSizeChange(w, h);
744
+ },
745
+ [onContentSizeChange]
746
+ );
747
+ const refreshControl = useMemo3(() => /* @__PURE__ */ jsx5(RefreshControl, {}), []);
748
+ const nativeGesture = useMemo3(() => Gesture2.Native(), []);
749
+ const combinedGesture = useMemo3(() => gesture !== void 0 ? Gesture2.Simultaneous(gesture, nativeGesture) : nativeGesture, [gesture, nativeGesture]);
750
+ const detectorGesture = gesture !== void 0 ? combinedGesture : void 0;
751
+ const content = /* @__PURE__ */ jsxs3(View3, { style: containerStyle, children: [
752
+ /* @__PURE__ */ jsx5(
753
+ RNFlatList,
754
+ {
755
+ ...props,
756
+ contentContainerStyle,
757
+ contentInset,
758
+ contentInsetAdjustmentBehavior: "never",
759
+ contentOffset,
760
+ data: cols > 1 ? rowData : data,
761
+ horizontal: isHorizontal,
762
+ initialNumToRender,
763
+ keyExtractor: cols > 1 ? rowKeyExtractor : keyExtractor,
764
+ ListHeaderComponent: activeListHeader,
765
+ maxToRenderPerBatch,
766
+ onContentSizeChange: handleContentSizeChange,
767
+ onMomentumScrollBegin: scrollHandler.onMomentumScrollBegin,
768
+ onMomentumScrollEnd,
769
+ onScroll: scrollHandler.onScroll,
770
+ onScrollBeginDrag,
771
+ onScrollEndDrag,
772
+ pagingEnabled,
773
+ renderItem: cols > 1 ? rowRenderItem : renderItem,
774
+ ref: (el) => {
775
+ if (externalRef) externalRef.current = el;
776
+ scrollView.current = el;
777
+ },
778
+ refreshControl,
779
+ removeClippedSubviews,
780
+ scrollEventThrottle: 16,
781
+ showsHorizontalScrollIndicator: showsHorizontalScrollIndicator ?? isHorizontal,
782
+ showsVerticalScrollIndicator: showsVerticalScrollIndicator ?? !isHorizontal,
783
+ windowSize
784
+ }
785
+ ),
786
+ hiddenHeader && /* @__PURE__ */ jsx5(View3, { pointerEvents: "none", style: styles4.measureContainer, children: hiddenHeader }),
787
+ /* @__PURE__ */ jsx5(ScrollViewChip, { chipProps, isHorizontal, onChipPress, onPress: handleScrollToTop, style: chipStyle }),
788
+ showDots && /* @__PURE__ */ jsx5(HorizontalDots, { total: data?.length ?? 0 })
789
+ ] });
790
+ return detectorGesture ? /* @__PURE__ */ jsx5(GestureDetector2, { gesture: detectorGesture, children: content }) : content;
791
+ };
792
+ var defaultKeyExtractor = (item, index) => {
793
+ const key = item?.key ?? item?.id;
794
+ return key != null ? String(key) : String(index);
795
+ };
796
+ var styles4 = { measureContainer: { left: 0, opacity: 0, position: "absolute", right: 0, top: -9999 }, row: { flexDirection: "row" } };
797
+ var FlatList = memo2(FlatListInner);
798
+
799
+ // src/PullSearch.tsx
800
+ import { forwardRef, useCallback as useCallback5, useContext as useContext8, useEffect as useEffect3, useImperativeHandle, useRef as useRef5, useState as useState4 } from "react";
801
+ import { StyleSheet as StyleSheet4 } from "react-native";
802
+ import { Searchbar, useTheme as useTheme2 } from "react-native-paper";
803
+ import Animated3, { Extrapolation, interpolate, runOnJS as runOnJS3, useAnimatedReaction, useAnimatedStyle as useAnimatedStyle3 } from "react-native-reanimated";
804
+ import { jsx as jsx6 } from "react/jsx-runtime";
805
+ var PullSearch = forwardRef(function PullSearch2({ debounce, onChangeText, onHeightChange, placeholder, value: propValue }, ref) {
806
+ const { headerHeight, scrollPosition } = useContext8(ScrollViewContext);
807
+ const theme = useTheme2();
808
+ const inputRef = useRef5(null);
809
+ const [barHeight, setBarHeight] = useState4(0);
810
+ const [value, setValue] = useState4(propValue ?? "");
811
+ const prevPropValueRef = useRef5(propValue);
812
+ useEffect3(() => {
813
+ if (prevPropValueRef.current === propValue) return;
814
+ prevPropValueRef.current = propValue;
815
+ setValue(propValue ?? "");
816
+ }, [propValue]);
817
+ useImperativeHandle(ref, () => ({
818
+ blur: () => inputRef.current?.blur(),
819
+ focus: () => inputRef.current?.focus()
820
+ }));
821
+ const blurInput = useCallback5(() => inputRef.current?.blur(), []);
822
+ useAnimatedReaction(
823
+ () => {
824
+ if (barHeight === 0) return false;
825
+ return scrollPosition.value >= -(headerHeight ?? 0) + barHeight;
826
+ },
827
+ (isHidden, wasHidden) => {
828
+ if (isHidden && !wasHidden) runOnJS3(blurInput)();
829
+ },
830
+ [barHeight, headerHeight, blurInput]
831
+ );
832
+ const handleClear = useCallback5(() => {
833
+ setValue("");
834
+ onChangeText("");
835
+ }, [onChangeText]);
836
+ const handleLayout = useCallback5(
837
+ ({
838
+ nativeEvent: {
839
+ layout: { height }
840
+ }
841
+ }) => {
842
+ setBarHeight(height);
843
+ onHeightChange(height);
844
+ },
845
+ [onHeightChange]
846
+ );
847
+ useEffect3(() => {
848
+ const normalizedValue = value.trim();
849
+ if (debounce) {
850
+ const timeout = setTimeout(() => onChangeText(normalizedValue), 500);
851
+ return () => clearTimeout(timeout);
852
+ }
853
+ onChangeText(normalizedValue);
854
+ }, [debounce, onChangeText, value]);
855
+ const animatedStyle = useAnimatedStyle3(() => {
856
+ if (barHeight === 0) return { opacity: 0 };
857
+ const h = headerHeight ?? 0;
858
+ const showY = -h;
859
+ const hideY = -h + barHeight;
860
+ return { opacity: interpolate(scrollPosition.value, [showY, hideY], [1, 0], Extrapolation.CLAMP) };
861
+ }, [barHeight, headerHeight]);
862
+ return /* @__PURE__ */ jsx6(Animated3.View, { onLayout: handleLayout, style: [styles5.container, animatedStyle], children: /* @__PURE__ */ jsx6(Searchbar, { autoCorrect: false, onChangeText: (text) => setValue((text || "").trimStart()), onClearIconPress: handleClear, placeholder, placeholderTextColor: theme.colors.onSurfaceVariant, ref: inputRef, spellCheck: false, style: styles5.input, value }) });
2133
863
  });
2134
- var clearAllListeners = /* @__PURE__ */ createAction(`${alm}/removeAll`);
2135
- var removeListener = /* @__PURE__ */ assign(/* @__PURE__ */ createAction(`${alm}/remove`), {
2136
- withTypes: () => removeListener
864
+ var styles5 = StyleSheet4.create({
865
+ container: { paddingVertical: 8 },
866
+ input: { margin: 0 }
2137
867
  });
2138
- function formatProdErrorMessage(code) {
2139
- return `Minified Redux Toolkit error #${code}; visit https://redux-toolkit.js.org/Errors?code=${code} for the full message or use the non-minified dev environment for full errors. `;
2140
- }
2141
868
 
2142
869
  // src/ScrollViewSettingsContext.ts
2143
870
  import { createContext as createContext2 } from "react";
@@ -2154,27 +881,40 @@ var ScrollViewSettingsContext = createContext2({
2154
881
  });
2155
882
 
2156
883
  // src/redux/scrollViewSlice.ts
2157
- var slice = createSlice({
2158
- name: "scrollView",
2159
- initialState: defaultScrollViewSettings,
2160
- reducers: {
2161
- initialize: (_state, action) => action.payload
2162
- }
2163
- });
2164
- var scrollViewActions = slice.actions;
2165
- var scrollViewReducer = slice.reducer;
884
+ var createAction = (type) => {
885
+ const actionCreator = (payload) => ({ payload, type });
886
+ actionCreator.type = type;
887
+ actionCreator.match = (action) => action.type === type;
888
+ return actionCreator;
889
+ };
890
+ var initialize = createAction("scrollView/initialize");
891
+ var scrollViewActions = { initialize };
892
+ var scrollViewReducer = (state = defaultScrollViewSettings, action) => {
893
+ if (initialize.match(action)) return action.payload;
894
+ return state;
895
+ };
2166
896
 
2167
897
  // src/ScrollView.tsx
2168
- import { memo as memo3, useCallback as useCallback5, useMemo as useMemo4, useRef as useRef5 } from "react";
898
+ import { memo as memo3, useCallback as useCallback6, useContext as useContext9, useLayoutEffect as useLayoutEffect4, useMemo as useMemo4, useRef as useRef6 } from "react";
2169
899
  import { View as View4 } from "react-native";
2170
900
  import { Gesture as Gesture3, GestureDetector as GestureDetector3 } from "react-native-gesture-handler";
2171
- import Animated5 from "react-native-reanimated";
901
+ import Animated4, { runOnUI as runOnUI2, useSharedValue as useSharedValue5 } from "react-native-reanimated";
2172
902
  import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
2173
903
  var ScrollViewInner = ({ chipProps, chipThreshold, children, footerFixed: footerFixedProp, gesture, headerFixed: headerFixedProp, horizontal, keyboardAware, onChipPress, onMomentumScrollEnd: externalMomentumScrollEnd, onRefresh, onScrollBeginDrag: externalScrollBeginDrag, onScrollEndDrag: externalScrollEndDrag, pullSearchHeight, refreshing, style, ...props }) => {
2174
- const scrollView = useRef5(null);
904
+ const scrollView = useRef6(null);
2175
905
  const isHorizontal = horizontal === true;
2176
906
  const { chipHidden, chipStyle, containerStyle, contentInset, contentOffset, footerFixed, headerFixed } = useScrollList({ footerFixed: footerFixedProp, headerFixed: headerFixedProp, isHorizontal, keyboardAware, pullSearchHeight, style });
2177
- const scrollTo = useCallback5((offset, animated) => {
907
+ const { listGeneration, onListUnmount } = useContext9(ScrollViewContext);
908
+ const capturedGeneration = useSharedValue5(-1);
909
+ useLayoutEffect4(() => {
910
+ const generation = listGeneration.value;
911
+ runOnUI2((gen) => {
912
+ "worklet";
913
+ capturedGeneration.value = gen;
914
+ })(generation);
915
+ }, [capturedGeneration, listGeneration]);
916
+ useLayoutEffect4(() => () => onListUnmount(), [onListUnmount]);
917
+ const scrollTo = useCallback6((offset, animated) => {
2178
918
  scrollView.current?.scrollTo({ y: offset, animated });
2179
919
  }, []);
2180
920
  const { handleMomentumScrollEnd, handleScrollBeginDrag, handleScrollEndDrag } = useScrollInit({
@@ -2184,12 +924,8 @@ var ScrollViewInner = ({ chipProps, chipThreshold, children, footerFixed: footer
2184
924
  pullSearchHeight,
2185
925
  scrollTo
2186
926
  });
2187
- const onPullSearchZoneEnter = useCallback5(() => {
2188
- if (!pullSearchHeight) return;
2189
- scrollTo(-contentInset.top + pullSearchHeight, true);
2190
- }, [contentInset.top, pullSearchHeight, scrollTo]);
2191
- const handleScroll = useScrollHandler({ chipHidden, chipThreshold, footerFixed, headerFixed, isHorizontal, onPullSearchZoneEnter: pullSearchHeight ? onPullSearchZoneEnter : void 0 });
2192
- const handleScrollToTop = useCallback5(() => {
927
+ const handleScroll = useScrollHandler({ capturedGeneration, chipHidden, chipThreshold, footerFixed, headerFixed, isHorizontal, listGeneration });
928
+ const handleScrollToTop = useCallback6(() => {
2193
929
  if (isHorizontal) {
2194
930
  scrollView.current?.scrollTo({ x: 0, animated: true });
2195
931
  return;
@@ -2203,7 +939,7 @@ var ScrollViewInner = ({ chipProps, chipThreshold, children, footerFixed: footer
2203
939
  const detectorGesture = gesture !== void 0 ? combinedGesture : void 0;
2204
940
  const content = /* @__PURE__ */ jsxs4(View4, { style: containerStyle, children: [
2205
941
  /* @__PURE__ */ jsx7(
2206
- Animated5.ScrollView,
942
+ Animated4.ScrollView,
2207
943
  {
2208
944
  ...props,
2209
945
  contentInset,
@@ -2229,13 +965,13 @@ var ScrollView = memo3(ScrollViewInner);
2229
965
 
2230
966
  // src/ScrollViewFooter.tsx
2231
967
  import { BlurView as BlurView2 } from "@rific/auto-paper";
2232
- import { useContext as useContext6, useEffect as useEffect4 } from "react";
968
+ import { useContext as useContext10, useEffect as useEffect4 } from "react";
2233
969
  import { StyleSheet as StyleSheet5, View as View5 } from "react-native";
2234
- import Animated6, { useAnimatedStyle as useAnimatedStyle4 } from "react-native-reanimated";
970
+ import Animated5, { useAnimatedStyle as useAnimatedStyle4 } from "react-native-reanimated";
2235
971
  import { useSafeAreaInsets as useSafeAreaInsets3 } from "react-native-safe-area-context";
2236
972
  import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
2237
973
  var ScrollViewFooter = ({ children, style }) => {
2238
- const { blur, footerHeight, footerFixed, footerOffset, headerHeightShared, pullSearchHeightShared, scrollPosition, setFooterHeight, snapBackFooterShared } = useContext6(ScrollViewContext);
974
+ const { blur, footerHeight, footerFixed, footerOffset, headerHeightShared, pullSearchHeightShared, scrollPosition, setFooterHeight, snapBackFooterShared } = useContext10(ScrollViewContext);
2239
975
  const insets = useSafeAreaInsets3();
2240
976
  useEffect4(
2241
977
  () => () => {
@@ -2257,7 +993,7 @@ var ScrollViewFooter = ({ children, style }) => {
2257
993
  if (effective <= 0) return { transform: [{ translateY: 0 }] };
2258
994
  return { transform: [{ translateY: Math.min(effective, footerHeight) }] };
2259
995
  }, [footerHeight, footerFixed]);
2260
- return /* @__PURE__ */ jsxs5(Animated6.View, { onLayout: handleLayout, pointerEvents: "box-none", style: [styles6.footer, footerStyle], children: [
996
+ return /* @__PURE__ */ jsxs5(Animated5.View, { onLayout: handleLayout, pointerEvents: "box-none", style: [styles6.footer, footerStyle], children: [
2261
997
  footerHeight > 0 && /* @__PURE__ */ jsx8(BlurView2, { blur, style: StyleSheet5.absoluteFill }),
2262
998
  /* @__PURE__ */ jsx8(View5, { style: [styles6.row, { paddingBottom: insets.bottom }, style], children })
2263
999
  ] });
@@ -2269,16 +1005,16 @@ var styles6 = StyleSheet5.create({
2269
1005
 
2270
1006
  // src/ScrollViewHeader.tsx
2271
1007
  import { BlurView as BlurView3 } from "@rific/auto-paper";
2272
- import { useContext as useContext7 } from "react";
1008
+ import { useContext as useContext11 } from "react";
2273
1009
  import { StyleSheet as StyleSheet6, Text, View as View6 } from "react-native";
2274
1010
  import { Appbar, ProgressBar, Surface, useTheme as useTheme3 } from "react-native-paper";
2275
- import Animated7, { useAnimatedStyle as useAnimatedStyle5 } from "react-native-reanimated";
1011
+ import Animated6, { useAnimatedStyle as useAnimatedStyle5 } from "react-native-reanimated";
2276
1012
  import { useSafeAreaInsets as useSafeAreaInsets4 } from "react-native-safe-area-context";
2277
- import { Fragment as Fragment3, jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
1013
+ import { Fragment as Fragment4, jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
2278
1014
  var ActionBg = ({ blur, style }) => blur ? /* @__PURE__ */ jsx9(View6, { style: [StyleSheet6.absoluteFill, styles7.actionBg, style], children: /* @__PURE__ */ jsx9(BlurView3, { blur: true, style: StyleSheet6.absoluteFill }) }) : /* @__PURE__ */ jsx9(View6, { style: [StyleSheet6.absoluteFill, styles7.actionBg, style], pointerEvents: "none", children: /* @__PURE__ */ jsx9(Surface, { style: StyleSheet6.absoluteFill, elevation: 1, children: null }) });
2279
1015
  var ScrollViewHeader = ({ actionSize = 48, actionStyle, backAction, backActionFixed, caption, centerContent, children, iconSize, style, title, topInset = true, trailingAction, trailingActionFixed = true }) => {
2280
- const { blur, headerHeight, headerFixed, headerOffset, progress, progressing, pullSearchHeightShared, scrollPosition, setHeaderHeight, snapBackHeaderShared } = useContext7(ScrollViewContext);
2281
- const { settings } = useContext7(ScrollViewSettingsContext);
1016
+ const { blur, headerHeight, headerFixed, headerOffset, progress, progressing, pullSearchHeightShared, scrollPosition, setHeaderHeight, snapBackHeaderShared } = useContext11(ScrollViewContext);
1017
+ const { settings } = useContext11(ScrollViewSettingsContext);
2282
1018
  const effectiveBackActionFixed = backActionFixed ?? settings.backActionFixed;
2283
1019
  const insets = useSafeAreaInsets4();
2284
1020
  const theme = useTheme3();
@@ -2293,20 +1029,22 @@ var ScrollViewHeader = ({ actionSize = 48, actionStyle, backAction, backActionFi
2293
1029
  const translateStyle = useAnimatedStyle5(() => {
2294
1030
  if (headerFixed) return { transform: [{ translateY: 0 }] };
2295
1031
  if (snapBackHeaderShared.value) return { transform: [{ translateY: headerOffset.value }] };
2296
- const effective = scrollPosition.value + headerHeight - pullSearchHeightShared.value;
1032
+ const effective = scrollPosition.value + (headerHeight ?? 0) - pullSearchHeightShared.value;
2297
1033
  if (effective <= 0) return { transform: [{ translateY: 0 }] };
2298
1034
  return { transform: [{ translateY: -effective }] };
2299
1035
  }, [headerFixed, headerHeight]);
2300
1036
  const blurStyle = useAnimatedStyle5(() => {
2301
1037
  if (!headerHeight) return { height: 0 };
2302
1038
  if (headerFixed) return { height: headerHeight };
2303
- const translateY = snapBackHeaderShared.value ? headerOffset.value : -Math.max(0, scrollPosition.value + headerHeight - pullSearchHeightShared.value);
2304
- return { height: Math.max(headerHeight + translateY, top) };
1039
+ const h = headerHeight ?? 0;
1040
+ const translateY = snapBackHeaderShared.value ? headerOffset.value : -Math.max(0, scrollPosition.value + h - pullSearchHeightShared.value);
1041
+ return { height: Math.max(h + translateY, top) };
2305
1042
  }, [headerFixed, headerHeight, top]);
2306
1043
  const progressStyle = useAnimatedStyle5(() => {
2307
- if (headerFixed) return { top: headerHeight };
2308
- const slide = snapBackHeaderShared.value ? -headerOffset.value : Math.max(0, scrollPosition.value + headerHeight - pullSearchHeightShared.value);
2309
- return { top: Math.max(headerHeight - slide, top) };
1044
+ const h = headerHeight ?? 0;
1045
+ if (headerFixed) return { top: h };
1046
+ const slide = snapBackHeaderShared.value ? -headerOffset.value : Math.max(0, scrollPosition.value + h - pullSearchHeightShared.value);
1047
+ return { top: Math.max(h - slide, top) };
2310
1048
  }, [headerFixed, headerHeight, top]);
2311
1049
  const actionMargin = 4;
2312
1050
  const contentMinHeight = actionSize + 2 * actionMargin;
@@ -2315,32 +1053,31 @@ var ScrollViewHeader = ({ actionSize = 48, actionStyle, backAction, backActionFi
2315
1053
  const actionShadow = { borderRadius: actionSize / 2, elevation: 2, shadowColor: "#000", shadowOffset: { width: 0, height: 1 }, shadowOpacity: 0.15, shadowRadius: 2 };
2316
1054
  const leadingStyle = { alignItems: "center", height: actionSize, justifyContent: "center", left: actionMargin, position: "absolute", top: actionTop, width: actionSize, zIndex: 3, ...actionShadow };
2317
1055
  const trailingStyle = { alignItems: "center", height: actionSize, justifyContent: "center", position: "absolute", right: actionMargin, top: actionTop, width: actionSize, zIndex: 3, ...actionShadow };
2318
- return /* @__PURE__ */ jsxs6(Fragment3, { children: [
2319
- /* @__PURE__ */ jsx9(Animated7.View, { pointerEvents: "none", style: [styles7.blur, blurStyle], children: headerHeight > 0 && /* @__PURE__ */ jsx9(BlurView3, { blur, style: [styles7.blurInner, { height: headerHeight }] }) }),
2320
- /* @__PURE__ */ jsxs6(Animated7.View, { onLayout: handleLayout, pointerEvents: "box-none", style: [headerHeight === 0 ? styles7.headerInit : styles7.header, translateStyle], children: [
2321
- /* @__PURE__ */ jsx9(View6, { style: [{ paddingTop: top }, style], children: /* @__PURE__ */ jsxs6(View6, { style: [styles7.content, { minHeight: contentMinHeight }], children: [
1056
+ return /* @__PURE__ */ jsxs6(Fragment4, { children: [
1057
+ /* @__PURE__ */ jsx9(Animated6.View, { pointerEvents: "none", style: [styles7.blur, blurStyle], children: headerHeight !== null && headerHeight > 0 && /* @__PURE__ */ jsx9(BlurView3, { blur, style: [styles7.blurInner, { height: headerHeight }] }) }),
1058
+ /* @__PURE__ */ jsxs6(Animated6.View, { onLayout: handleLayout, pointerEvents: "box-none", style: [headerHeight === null ? styles7.headerInit : styles7.header, translateStyle], children: [
1059
+ /* @__PURE__ */ jsx9(View6, { style: [{ paddingTop: top }, style], children: children ?? /* @__PURE__ */ jsxs6(View6, { style: [styles7.content, { minHeight: contentMinHeight }], children: [
2322
1060
  /* @__PURE__ */ jsx9(View6, { style: styles7.side }),
2323
1061
  /* @__PURE__ */ jsx9(View6, { style: styles7.spacer }),
2324
- /* @__PURE__ */ jsx9(View6, { style: styles7.side, children }),
2325
- (centerContent || title || caption) && /* @__PURE__ */ jsx9(View6, { style: [StyleSheet6.absoluteFill, styles7.titleContainer], pointerEvents: centerContent ? "box-none" : "none", children: centerContent ?? /* @__PURE__ */ jsxs6(Fragment3, { children: [
1062
+ (centerContent || title || caption) && /* @__PURE__ */ jsx9(View6, { style: [StyleSheet6.absoluteFill, styles7.titleContainer], pointerEvents: centerContent ? "box-none" : "none", children: centerContent ?? /* @__PURE__ */ jsxs6(Fragment4, { children: [
2326
1063
  title && /* @__PURE__ */ jsx9(Text, { numberOfLines: 1, style: [styles7.title, { color: theme.colors.onSurface }], children: title }),
2327
1064
  caption && /* @__PURE__ */ jsx9(Text, { numberOfLines: 1, style: [styles7.caption, { color: theme.colors.onSurfaceVariant }], children: caption })
2328
1065
  ] }) })
2329
1066
  ] }) }),
2330
1067
  !blur && /* @__PURE__ */ jsx9(View6, { style: [styles7.divider, { backgroundColor: theme.colors.outlineVariant }] })
2331
1068
  ] }),
2332
- /* @__PURE__ */ jsx9(Animated7.View, { pointerEvents: "none", style: [styles7.progress, progressStyle], children: /* @__PURE__ */ jsx9(ProgressBar, { indeterminate: progress === null, visible: progressing, progress: progress ?? void 0 }) }),
2333
- backAction && (effectiveBackActionFixed ? /* @__PURE__ */ jsxs6(Animated7.View, { style: leadingStyle, children: [
1069
+ /* @__PURE__ */ jsx9(Animated6.View, { pointerEvents: "none", style: [styles7.progress, progressStyle], children: /* @__PURE__ */ jsx9(ProgressBar, { indeterminate: progress === null, visible: progressing, progress: progress ?? void 0 }) }),
1070
+ backAction && (effectiveBackActionFixed ? /* @__PURE__ */ jsxs6(Animated6.View, { style: leadingStyle, children: [
2334
1071
  /* @__PURE__ */ jsx9(ActionBg, { blur, style: actionStyle }),
2335
1072
  /* @__PURE__ */ jsx9(Appbar.BackAction, { onPress: backAction, size: iconSize ?? actionSize / 2, style: buttonStyle })
2336
- ] }) : /* @__PURE__ */ jsxs6(Animated7.View, { style: [leadingStyle, translateStyle], children: [
1073
+ ] }) : /* @__PURE__ */ jsxs6(Animated6.View, { style: [leadingStyle, translateStyle], children: [
2337
1074
  /* @__PURE__ */ jsx9(ActionBg, { blur, style: actionStyle }),
2338
1075
  /* @__PURE__ */ jsx9(Appbar.BackAction, { onPress: backAction, size: iconSize ?? actionSize / 2, style: buttonStyle })
2339
1076
  ] })),
2340
1077
  trailingAction && (trailingActionFixed ? /* @__PURE__ */ jsxs6(View6, { style: trailingStyle, children: [
2341
1078
  /* @__PURE__ */ jsx9(ActionBg, { blur, style: actionStyle }),
2342
1079
  trailingAction
2343
- ] }) : /* @__PURE__ */ jsxs6(Animated7.View, { style: [trailingStyle, translateStyle], children: [
1080
+ ] }) : /* @__PURE__ */ jsxs6(Animated6.View, { style: [trailingStyle, translateStyle], children: [
2344
1081
  /* @__PURE__ */ jsx9(ActionBg, { blur, style: actionStyle }),
2345
1082
  trailingAction
2346
1083
  ] }))
@@ -2364,62 +1101,77 @@ var styles7 = StyleSheet6.create({
2364
1101
 
2365
1102
  // src/ScrollViewProvider.tsx
2366
1103
  import { useBlur } from "@rific/auto-paper";
2367
- import { useCallback as useCallback6, useContext as useContext8, useEffect as useEffect5, useMemo as useMemo5, useState as useState4 } from "react";
1104
+ import { useCallback as useCallback7, useContext as useContext12, useEffect as useEffect5, useMemo as useMemo5, useRef as useRef7, useState as useState5 } from "react";
2368
1105
  import { Dimensions as Dimensions3 } from "react-native";
2369
- import { useSharedValue as useSharedValue3 } from "react-native-reanimated";
1106
+ import { useSharedValue as useSharedValue6 } from "react-native-reanimated";
2370
1107
  import { jsx as jsx10 } from "react/jsx-runtime";
2371
1108
  var ScrollViewProvider = ({ blur, children, fixed = false, footerFixed, headerFixed, snapBack, snapBackFooter, snapBackHeader, tabBarHeight = 60 }) => {
2372
- const { settings } = useContext8(ScrollViewSettingsContext);
1109
+ const { settings } = useContext12(ScrollViewSettingsContext);
2373
1110
  const effectiveBlur = useBlur(blur);
2374
1111
  const effectiveSnapBack = snapBack ?? settings.snapBack;
2375
1112
  const effectiveSnapBackHeader = snapBackHeader ?? settings.snapBackHeader;
2376
1113
  const effectiveSnapBackFooter = snapBackFooter ?? settings.snapBackFooter;
2377
- const [headerHeight, setHeaderHeightState] = useState4(0);
2378
- const [footerHeight, setFooterHeightState] = useState4(0);
2379
- const [progress, setProgress] = useState4(null);
2380
- const [progressing, setProgressing] = useState4(false);
2381
- const scrollPosition = useSharedValue3(0);
2382
- const headerHeightShared = useSharedValue3(0);
2383
- const footerHeightShared = useSharedValue3(0);
2384
- const headerOffset = useSharedValue3(0);
2385
- const footerOffset = useSharedValue3(0);
2386
- const pullSearchHeightShared = useSharedValue3(0);
2387
- const snapBackHeaderShared = useSharedValue3(false);
2388
- const snapBackFooterShared = useSharedValue3(false);
1114
+ const [headerHeight, setHeaderHeightState] = useState5(null);
1115
+ const [footerHeight, setFooterHeightState] = useState5(0);
1116
+ const [progress, setProgress] = useState5(null);
1117
+ const [progressing, setProgressing] = useState5(false);
1118
+ const scrollPosition = useSharedValue6(0);
1119
+ const listGeneration = useSharedValue6(0);
1120
+ const jsListGeneration = useRef7(0);
1121
+ const headerHeightShared = useSharedValue6(0);
1122
+ const footerHeightShared = useSharedValue6(0);
1123
+ const headerOffset = useSharedValue6(0);
1124
+ const footerOffset = useSharedValue6(0);
1125
+ const pullSearchHeightShared = useSharedValue6(0);
1126
+ const snapBackHeaderShared = useSharedValue6(false);
1127
+ const snapBackFooterShared = useSharedValue6(false);
2389
1128
  useEffect5(() => {
2390
1129
  snapBackHeaderShared.value = effectiveSnapBackHeader ?? effectiveSnapBack;
2391
1130
  snapBackFooterShared.value = effectiveSnapBackFooter ?? effectiveSnapBack;
2392
1131
  }, [effectiveSnapBack, effectiveSnapBackFooter, effectiveSnapBackHeader, snapBackFooterShared, snapBackHeaderShared]);
2393
- const setHeaderHeight = useCallback6(
1132
+ const setHeaderHeight = useCallback7(
2394
1133
  (h) => {
2395
1134
  setHeaderHeightState(h);
2396
- headerHeightShared.value = h;
1135
+ headerHeightShared.value = h ?? 0;
2397
1136
  },
2398
1137
  [headerHeightShared]
2399
1138
  );
2400
- const setFooterHeight = useCallback6(
1139
+ const onListUnmount = useCallback7(() => {
1140
+ listGeneration.value += 1;
1141
+ }, [listGeneration]);
1142
+ const onJsListUnmount = useCallback7(() => {
1143
+ jsListGeneration.current += 1;
1144
+ }, []);
1145
+ useEffect5(() => {
1146
+ if (!__DEV__ || headerHeight !== null) return;
1147
+ const timeout = setTimeout(() => {
1148
+ 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.");
1149
+ }, 3e3);
1150
+ return () => clearTimeout(timeout);
1151
+ }, [headerHeight]);
1152
+ const setFooterHeight = useCallback7(
2401
1153
  (h) => {
2402
1154
  setFooterHeightState(h);
2403
1155
  footerHeightShared.value = h;
2404
1156
  },
2405
1157
  [footerHeightShared]
2406
1158
  );
2407
- const scrollHeight = useMemo5(() => Dimensions3.get("window").height - headerHeight - footerHeight, [headerHeight, footerHeight]);
1159
+ const scrollHeight = useMemo5(() => Dimensions3.get("window").height - (headerHeight ?? 0) - footerHeight, [headerHeight, footerHeight]);
2408
1160
  const effectiveHeaderFixed = fixed || (headerFixed ?? settings.headerFixed);
2409
1161
  const effectiveFooterFixed = fixed || (footerFixed ?? settings.footerFixed);
2410
- const value = useMemo5(() => ({ 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]);
1162
+ const value = useMemo5(() => ({ 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]);
2411
1163
  return /* @__PURE__ */ jsx10(ScrollViewContext.Provider, { value, children });
2412
1164
  };
2413
1165
 
2414
1166
  // src/ScrollViewSettingsProvider.tsx
2415
- import { useCallback as useCallback7, useMemo as useMemo6, useState as useState5 } from "react";
1167
+ import { useCallback as useCallback8, useMemo as useMemo6, useState as useState6 } from "react";
2416
1168
  import { jsx as jsx11 } from "react/jsx-runtime";
2417
1169
  var ScrollViewSettingsProvider = ({ children, onChange, initialValue }) => {
2418
- const [settings, setSettings] = useState5(() => ({
1170
+ const [settings, setSettings] = useState6(() => ({
2419
1171
  ...defaultScrollViewSettings,
2420
1172
  ...initialValue
2421
1173
  }));
2422
- const set2 = useCallback7(
1174
+ const set = useCallback8(
2423
1175
  (patch) => {
2424
1176
  setSettings((prev) => {
2425
1177
  const next = { ...prev, ...patch };
@@ -2429,32 +1181,32 @@ var ScrollViewSettingsProvider = ({ children, onChange, initialValue }) => {
2429
1181
  },
2430
1182
  [onChange]
2431
1183
  );
2432
- const ctx = useMemo6(() => ({ settings, set: set2 }), [settings, set2]);
1184
+ const ctx = useMemo6(() => ({ settings, set }), [settings, set]);
2433
1185
  return /* @__PURE__ */ jsx11(ScrollViewSettingsContext.Provider, { value: ctx, children });
2434
1186
  };
2435
1187
 
2436
1188
  // src/SectionList.tsx
2437
- import { memo as memo4, useCallback as useCallback9, useEffect as useEffect6, useLayoutEffect as useLayoutEffect3, useMemo as useMemo7, useRef as useRef7 } from "react";
1189
+ import { memo as memo4, useCallback as useCallback10, useContext as useContext14, useEffect as useEffect6, useLayoutEffect as useLayoutEffect6, useMemo as useMemo7, useRef as useRef9 } from "react";
2438
1190
  import { Dimensions as Dimensions4, SectionList as RNSectionList, View as View7 } from "react-native";
2439
1191
  import { Gesture as Gesture4, GestureDetector as GestureDetector4 } from "react-native-gesture-handler";
2440
- import Animated8, { createAnimatedComponent } from "react-native-reanimated";
1192
+ import Animated7, { runOnUI as runOnUI3, useSharedValue as useSharedValue8 } from "react-native-reanimated";
2441
1193
 
2442
1194
  // src/internal/useStickyHeaders.ts
2443
- import { useCallback as useCallback8, useContext as useContext9, useLayoutEffect as useLayoutEffect2, useRef as useRef6, useState as useState6 } from "react";
2444
- import { runOnJS as runOnJS4, useAnimatedReaction as useAnimatedReaction2, useAnimatedStyle as useAnimatedStyle6, useSharedValue as useSharedValue4 } from "react-native-reanimated";
1195
+ import { useCallback as useCallback9, useContext as useContext13, useLayoutEffect as useLayoutEffect5, useRef as useRef8, useState as useState7 } from "react";
1196
+ import { runOnJS as runOnJS4, useAnimatedReaction as useAnimatedReaction2, useAnimatedStyle as useAnimatedStyle6, useSharedValue as useSharedValue7 } from "react-native-reanimated";
2445
1197
  import { useSafeAreaInsets as useSafeAreaInsets5 } from "react-native-safe-area-context";
2446
1198
  function useStickyHeaders(headerFixed, enabled) {
2447
- const { headerHeightShared, headerOffset, pullSearchHeightShared, scrollPosition, snapBackHeaderShared } = useContext9(ScrollViewContext);
1199
+ const { headerHeightShared, headerOffset, pullSearchHeightShared, scrollPosition, snapBackHeaderShared } = useContext13(ScrollViewContext);
2448
1200
  const insetsTop = useSafeAreaInsets5().top;
2449
- const sectionYPositions = useSharedValue4([]);
2450
- const sectionHeights = useSharedValue4([]);
2451
- const [activeIndex, setActiveIndex] = useState6(-1);
2452
- const contentIndexShared = useSharedValue4(-1);
2453
- useLayoutEffect2(() => {
1201
+ const sectionYPositions = useSharedValue7([]);
1202
+ const sectionHeights = useSharedValue7([]);
1203
+ const [activeIndex, setActiveIndex] = useState7(-1);
1204
+ const contentIndexShared = useSharedValue7(-1);
1205
+ useLayoutEffect5(() => {
2454
1206
  contentIndexShared.value = activeIndex;
2455
1207
  }, [activeIndex, contentIndexShared]);
2456
- const positionsCache = useRef6([]);
2457
- const heightsCache = useRef6([]);
1208
+ const positionsCache = useRef8([]);
1209
+ const heightsCache = useRef8([]);
2458
1210
  useAnimatedReaction2(
2459
1211
  () => {
2460
1212
  if (!enabled) return -1;
@@ -2526,7 +1278,7 @@ function useStickyHeaders(headerFixed, enabled) {
2526
1278
  }
2527
1279
  return { opacity: 1, top: 0, transform: [{ translateY }] };
2528
1280
  }, [enabled, headerFixed, insetsTop]);
2529
- const measureHeader = useCallback8(
1281
+ const measureHeader = useCallback9(
2530
1282
  (index, pageY, height) => {
2531
1283
  const contentY = pageY + scrollPosition.value;
2532
1284
  positionsCache.current[index] = contentY;
@@ -2536,7 +1288,7 @@ function useStickyHeaders(headerFixed, enabled) {
2536
1288
  },
2537
1289
  [scrollPosition, sectionHeights, sectionYPositions]
2538
1290
  );
2539
- const resetPositions = useCallback8(
1291
+ const resetPositions = useCallback9(
2540
1292
  (count) => {
2541
1293
  positionsCache.current = Array.from({ length: count }, () => -1);
2542
1294
  sectionYPositions.value = positionsCache.current.slice();
@@ -2549,18 +1301,27 @@ function useStickyHeaders(headerFixed, enabled) {
2549
1301
  }
2550
1302
 
2551
1303
  // src/SectionList.tsx
2552
- import { Fragment as Fragment4, jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
2553
- var AnimatedSectionList = createAnimatedComponent(RNSectionList);
1304
+ import { Fragment as Fragment5, jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
1305
+ var AnimatedSectionList = Animated7.createAnimatedComponent(RNSectionList);
2554
1306
  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 }) => {
2555
- const scrollView = useRef7(null);
1307
+ const scrollView = useRef9(null);
2556
1308
  const { stickySectionHeadersEnabled = true, renderSectionHeader, ...passThroughProps } = props;
2557
1309
  const { chipHidden, chipStyle, containerStyle, contentInset, contentOffset, footerFixed, headerFixed, headerHeight } = useScrollList({ footerFixed: footerFixedProp, headerFixed: headerFixedProp, keyboardAware, pullSearchHeight, style });
1310
+ const { listGeneration, onListUnmount } = useContext14(ScrollViewContext);
1311
+ const capturedGeneration = useSharedValue8(-1);
1312
+ useLayoutEffect6(() => {
1313
+ const generation = listGeneration.value;
1314
+ runOnUI3((gen) => {
1315
+ "worklet";
1316
+ capturedGeneration.value = gen;
1317
+ })(generation);
1318
+ }, [capturedGeneration, listGeneration]);
2558
1319
  const usesCustomSticky = stickySectionHeadersEnabled && renderSectionHeader != null;
2559
1320
  const { activeIndex, clipStyle, measureHeader, overlayStyle, resetPositions } = useStickyHeaders(headerFixed, usesCustomSticky);
2560
- useLayoutEffect3(() => {
1321
+ useLayoutEffect6(() => {
2561
1322
  if (usesCustomSticky) resetPositions(sections.length);
2562
1323
  }, [sections, usesCustomSticky, resetPositions, headerHeight]);
2563
- const sectionViewRefs = useRef7(/* @__PURE__ */ new Map());
1324
+ const sectionViewRefs = useRef9(/* @__PURE__ */ new Map());
2564
1325
  const wrappedRenderSectionHeader = useMemo7(() => {
2565
1326
  if (!usesCustomSticky) return renderSectionHeader ?? void 0;
2566
1327
  return (info) => {
@@ -2582,7 +1343,8 @@ var SectionListInner = ({ chipProps, chipThreshold, contentContainerStyle: exter
2582
1343
  );
2583
1344
  };
2584
1345
  }, [usesCustomSticky, renderSectionHeader, sections, measureHeader]);
2585
- const scrollTo = useCallback9((offset, animated) => {
1346
+ useLayoutEffect6(() => () => onListUnmount(), [onListUnmount]);
1347
+ const scrollTo = useCallback10((offset, animated) => {
2586
1348
  scrollView.current?.getScrollResponder()?.scrollTo({ y: offset, animated });
2587
1349
  }, []);
2588
1350
  const {
@@ -2603,12 +1365,12 @@ var SectionListInner = ({ chipProps, chipThreshold, contentContainerStyle: exter
2603
1365
  const activeListHeader = useMemo7(() => {
2604
1366
  if (!renderFilters) return pullSearchHeader;
2605
1367
  const Inner = pullSearchHeader;
2606
- return () => /* @__PURE__ */ jsxs7(Fragment4, { children: [
1368
+ return () => /* @__PURE__ */ jsxs7(Fragment5, { children: [
2607
1369
  Inner ? typeof Inner === "function" ? /* @__PURE__ */ jsx12(Inner, {}) : Inner : null,
2608
1370
  renderFilters
2609
1371
  ] });
2610
1372
  }, [pullSearchHeader, renderFilters]);
2611
- const pullSearchSettled = useRef7(false);
1373
+ const pullSearchSettled = useRef9(false);
2612
1374
  useEffect6(() => {
2613
1375
  if (!usesCustomSticky || activeListHeader == null || pullSearchSettled.current) return;
2614
1376
  pullSearchSettled.current = true;
@@ -2622,16 +1384,12 @@ var SectionListInner = ({ chipProps, chipThreshold, contentContainerStyle: exter
2622
1384
  return () => cancelAnimationFrame(handle);
2623
1385
  }, [activeListHeader, usesCustomSticky, measureHeader]);
2624
1386
  const contentContainerStyle = useMemo7(() => [{ minHeight: Dimensions4.get("window").height - contentInset.top - contentInset.bottom + pullSearchMinHeight }, externalContentContainerStyle], [contentInset.bottom, contentInset.top, externalContentContainerStyle, pullSearchMinHeight]);
2625
- const onPullSearchZoneEnter = useCallback9(() => {
2626
- if (!pullSearchHeight) return;
2627
- scrollTo(-contentInset.top + pullSearchHeight, true);
2628
- }, [contentInset.top, pullSearchHeight, scrollTo]);
2629
- const handleScroll = useScrollHandler({ chipHidden, chipThreshold, footerFixed, headerFixed, onPullSearchZoneEnter: pullSearchHeight ? onPullSearchZoneEnter : void 0 });
2630
- const handleScrollToTop = useCallback9(() => {
1387
+ const handleScroll = useScrollHandler({ capturedGeneration, chipHidden, chipThreshold, footerFixed, headerFixed, listGeneration });
1388
+ const handleScrollToTop = useCallback10(() => {
2631
1389
  const offset = pullSearchHeight ? -contentInset.top + pullSearchHeight : -contentInset.top;
2632
1390
  scrollView.current?.getScrollResponder()?.scrollTo({ y: offset, animated: true });
2633
1391
  }, [contentInset.top, pullSearchHeight]);
2634
- const handleContentSizeChange = useCallback9(
1392
+ const handleContentSizeChange = useCallback10(
2635
1393
  (w, h) => {
2636
1394
  if (onContentSizeChange) onContentSizeChange(w, h);
2637
1395
  },
@@ -2670,11 +1428,11 @@ var SectionListInner = ({ chipProps, chipThreshold, contentContainerStyle: exter
2670
1428
  stickySectionHeadersEnabled: false,
2671
1429
  windowSize
2672
1430
  },
2673
- headerHeight > 0 ? 1 : 0
1431
+ headerHeight !== null && headerHeight > 0 ? 1 : 0
2674
1432
  ),
2675
1433
  hiddenHeader && /* @__PURE__ */ jsx12(View7, { pointerEvents: "none", style: styles8.measureContainer, children: hiddenHeader }),
2676
1434
  /* @__PURE__ */ jsx12(ScrollViewChip, { chipProps, onChipPress, onPress: handleScrollToTop, style: chipStyle }),
2677
- usesCustomSticky && /* @__PURE__ */ jsx12(Animated8.View, { pointerEvents: "none", style: [styles8.stickyClip, clipStyle], children: activeIndex >= 0 && activeIndex < sections.length && /* @__PURE__ */ jsx12(Animated8.View, { style: [styles8.stickyOverlay, overlayStyle], children: renderSectionHeader({ section: sections[activeIndex] }) }) })
1435
+ usesCustomSticky && /* @__PURE__ */ jsx12(Animated7.View, { pointerEvents: "none", style: [styles8.stickyClip, clipStyle], children: activeIndex >= 0 && activeIndex < sections.length && /* @__PURE__ */ jsx12(Animated7.View, { style: [styles8.stickyOverlay, overlayStyle], children: renderSectionHeader({ section: sections[activeIndex] }) }) })
2678
1436
  ] });
2679
1437
  return detectorGesture ? /* @__PURE__ */ jsx12(GestureDetector4, { gesture: detectorGesture, children: content }) : content;
2680
1438
  };
@@ -2686,15 +1444,15 @@ var styles8 = {
2686
1444
  var SectionList = memo4(SectionListInner);
2687
1445
 
2688
1446
  // src/useScrollView.ts
2689
- import { useContext as useContext10 } from "react";
1447
+ import { useContext as useContext15 } from "react";
2690
1448
  var useScrollView = () => {
2691
- const { progress, progressing, scrollHeight, scrollPosition, setProgress, setProgressing } = useContext10(ScrollViewContext);
1449
+ const { progress, progressing, scrollHeight, scrollPosition, setProgress, setProgressing } = useContext15(ScrollViewContext);
2692
1450
  return { progress, progressing, scrollHeight, scrollPosition, setProgress, setProgressing };
2693
1451
  };
2694
1452
 
2695
1453
  // src/useScrollViewSettings.ts
2696
- import { useContext as useContext11 } from "react";
2697
- var useScrollViewSettings = () => useContext11(ScrollViewSettingsContext);
1454
+ import { useContext as useContext16 } from "react";
1455
+ var useScrollViewSettings = () => useContext16(ScrollViewSettingsContext);
2698
1456
  export {
2699
1457
  CustomList,
2700
1458
  FlatList,