@rific/scroll-view 0.1.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -7
- package/dist/index.d.mts +31 -10
- package/dist/index.d.ts +31 -10
- package/dist/index.js +663 -335
- package/dist/index.mjs +600 -272
- package/package.json +3 -3
- package/src/CustomList.tsx +38 -11
- package/src/FlatList.tsx +107 -22
- package/src/PullSearch.tsx +4 -3
- package/src/ScrollView.tsx +34 -11
- package/src/ScrollViewContext.ts +17 -4
- package/src/ScrollViewHeader.tsx +34 -31
- package/src/ScrollViewProvider.tsx +22 -6
- package/src/ScrollViewSettingsProvider.tsx +3 -3
- package/src/SectionList.tsx +37 -13
- package/src/__mocks__/auto-paper.ts +1 -0
- package/src/__mocks__/react-native-reanimated.ts +32 -1
- package/src/__tests__/FlatList.test.tsx +83 -0
- package/src/__tests__/ScrollViewProvider.test.tsx +2 -2
- package/src/__tests__/useScrollHandlerJS.test.ts +119 -0
- package/src/__tests__/useScrollInit.test.ts +251 -0
- package/src/index.ts +1 -0
- package/src/internal/ScrollViewChip.tsx +24 -8
- package/src/internal/useScrollHandler.ts +22 -23
- package/src/internal/useScrollHandlerJS.ts +141 -0
- package/src/internal/useScrollList.ts +16 -11
- package/src/useScrollInit.ts +200 -19
- package/src/out.txt +0 -61
package/dist/index.mjs
CHANGED
|
@@ -3,9 +3,10 @@ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { en
|
|
|
3
3
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
4
|
|
|
5
5
|
// src/CustomList.tsx
|
|
6
|
-
import { memo, useCallback as useCallback2, useMemo as useMemo2, useRef as useRef2 } from "react";
|
|
6
|
+
import { memo, useCallback as useCallback2, useContext as useContext4, useLayoutEffect as useLayoutEffect2, useMemo as useMemo2, useRef as useRef2 } from "react";
|
|
7
7
|
import { Dimensions, View } from "react-native";
|
|
8
8
|
import { Gesture, GestureDetector } from "react-native-gesture-handler";
|
|
9
|
+
import { runOnUI, useSharedValue as useSharedValue4 } from "react-native-reanimated";
|
|
9
10
|
|
|
10
11
|
// src/internal/RefreshControl.tsx
|
|
11
12
|
import { RefreshControl as RNRefreshControl } from "react-native";
|
|
@@ -13,19 +14,26 @@ import { jsx } from "react/jsx-runtime";
|
|
|
13
14
|
var RefreshControl = (props) => /* @__PURE__ */ jsx(RNRefreshControl, { refreshing: false, ...props });
|
|
14
15
|
|
|
15
16
|
// src/internal/ScrollViewChip.tsx
|
|
17
|
+
import { Chip } from "@rific/auto-paper";
|
|
16
18
|
import { StyleSheet } from "react-native";
|
|
17
|
-
import { Chip } from "react-native-paper";
|
|
18
19
|
import Animated from "react-native-reanimated";
|
|
19
20
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
20
|
-
var ScrollViewChip = ({ isHorizontal, onPress, style }) =>
|
|
21
|
+
var ScrollViewChip = ({ chipProps, isHorizontal, onChipPress, onPress, style }) => {
|
|
22
|
+
const { label, style: chipStyle, ...restChipProps } = chipProps ?? {};
|
|
23
|
+
const handlePress = onChipPress ? () => {
|
|
24
|
+
onPress();
|
|
25
|
+
onChipPress();
|
|
26
|
+
} : onPress;
|
|
27
|
+
return /* @__PURE__ */ jsx2(Animated.View, { style: [styles.chip, style], children: /* @__PURE__ */ jsx2(Chip, { compact: true, ...restChipProps, icon: isHorizontal ? "chevron-left" : "chevron-up", onPress: handlePress, style: [styles.chipInner, chipStyle], children: label ?? (isHorizontal ? "Start" : "Top") }) });
|
|
28
|
+
};
|
|
21
29
|
var styles = StyleSheet.create({
|
|
22
30
|
chip: { alignItems: "center", left: 0, position: "absolute", right: 0, zIndex: 3 },
|
|
23
31
|
chipInner: { elevation: 2, shadowColor: "#000", shadowOffset: { width: 0, height: 1 }, shadowOpacity: 0.15, shadowRadius: 2 }
|
|
24
32
|
});
|
|
25
33
|
|
|
26
34
|
// src/internal/useScrollHandler.ts
|
|
27
|
-
import { useContext } from "react";
|
|
28
|
-
import { runOnJS, useAnimatedScrollHandler, useSharedValue, withTiming } from "react-native-reanimated";
|
|
35
|
+
import { useContext as useContext2 } from "react";
|
|
36
|
+
import { runOnJS, useAnimatedScrollHandler, useSharedValue as useSharedValue2, withTiming } from "react-native-reanimated";
|
|
29
37
|
|
|
30
38
|
// src/ScrollViewContext.ts
|
|
31
39
|
import { createContext } from "react";
|
|
@@ -35,10 +43,16 @@ var ScrollViewContext = createContext({
|
|
|
35
43
|
footerHeightShared: null,
|
|
36
44
|
footerFixed: false,
|
|
37
45
|
footerOffset: null,
|
|
38
|
-
headerHeight:
|
|
46
|
+
headerHeight: null,
|
|
39
47
|
headerHeightShared: null,
|
|
40
48
|
headerFixed: false,
|
|
41
49
|
headerOffset: null,
|
|
50
|
+
jsListGeneration: { current: 0 },
|
|
51
|
+
listGeneration: null,
|
|
52
|
+
onJsListUnmount: () => {
|
|
53
|
+
},
|
|
54
|
+
onListUnmount: () => {
|
|
55
|
+
},
|
|
42
56
|
progress: null,
|
|
43
57
|
progressing: false,
|
|
44
58
|
pullSearchHeightShared: null,
|
|
@@ -57,25 +71,215 @@ var ScrollViewContext = createContext({
|
|
|
57
71
|
tabBarHeight: 60
|
|
58
72
|
});
|
|
59
73
|
|
|
74
|
+
// src/useScrollInit.ts
|
|
75
|
+
import { createElement, useCallback, useContext, useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
76
|
+
import { useSharedValue } from "react-native-reanimated";
|
|
77
|
+
var REMOUNT_SYNC_MAX_ATTEMPTS = 8;
|
|
78
|
+
var REMOUNT_SYNC_TOLERANCE = 1;
|
|
79
|
+
var REMOUNT_SYNC_FALLBACK_MS = 500;
|
|
80
|
+
var REMOUNT_PRIME_FRAMES = 40;
|
|
81
|
+
var SNAP_VERIFY_TOLERANCE = 1;
|
|
82
|
+
var SNAP_VERIFY_MAX_ATTEMPTS = 5;
|
|
83
|
+
var SNAP_VERIFY_INITIAL_DELAY_MS = 400;
|
|
84
|
+
var SNAP_VERIFY_RETRY_DELAY_MS = 150;
|
|
85
|
+
function useScrollInit({ listHeaderComponent, onMomentumScrollEnd: externalMomentumScrollEnd, onRefresh, onScrollBeginDrag: externalScrollBeginDrag, onScrollEndDrag: externalScrollEndDrag, pullSearchHeight, scrollTo }) {
|
|
86
|
+
const { headerHeight, scrollPosition, setProgressing } = useContext(ScrollViewContext);
|
|
87
|
+
const hasPullSearch = pullSearchHeight !== void 0;
|
|
88
|
+
const [phase, setPhase] = useState(hasPullSearch && !headerHeight ? "measuring" : "ready");
|
|
89
|
+
const [refreshing, setRefreshing] = useState(false);
|
|
90
|
+
const refreshingRef = useRef(refreshing);
|
|
91
|
+
useEffect(() => {
|
|
92
|
+
refreshingRef.current = refreshing;
|
|
93
|
+
}, [refreshing]);
|
|
94
|
+
const dragStartY = useRef(null);
|
|
95
|
+
const pendingSnapTarget = useRef(null);
|
|
96
|
+
const snapVerifyTimeout = useRef(null);
|
|
97
|
+
const snapVerifyAttempts = useRef(0);
|
|
98
|
+
const scheduleSnapVerification = useCallback(
|
|
99
|
+
(target, delay) => {
|
|
100
|
+
if (snapVerifyTimeout.current !== null) clearTimeout(snapVerifyTimeout.current);
|
|
101
|
+
pendingSnapTarget.current = target;
|
|
102
|
+
snapVerifyAttempts.current = 0;
|
|
103
|
+
const check = () => {
|
|
104
|
+
snapVerifyTimeout.current = null;
|
|
105
|
+
if (pendingSnapTarget.current !== target) return;
|
|
106
|
+
if (Math.abs(scrollPosition.value - target) <= SNAP_VERIFY_TOLERANCE) {
|
|
107
|
+
pendingSnapTarget.current = null;
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
snapVerifyAttempts.current += 1;
|
|
111
|
+
if (snapVerifyAttempts.current > SNAP_VERIFY_MAX_ATTEMPTS || refreshingRef.current) {
|
|
112
|
+
pendingSnapTarget.current = null;
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
scrollTo(target, false);
|
|
116
|
+
snapVerifyTimeout.current = setTimeout(check, SNAP_VERIFY_RETRY_DELAY_MS);
|
|
117
|
+
};
|
|
118
|
+
snapVerifyTimeout.current = setTimeout(check, delay);
|
|
119
|
+
},
|
|
120
|
+
[scrollPosition, scrollTo]
|
|
121
|
+
);
|
|
122
|
+
useEffect(
|
|
123
|
+
() => () => {
|
|
124
|
+
if (snapVerifyTimeout.current !== null) clearTimeout(snapVerifyTimeout.current);
|
|
125
|
+
},
|
|
126
|
+
[]
|
|
127
|
+
);
|
|
128
|
+
const [remountTarget] = useState(() => headerHeight !== null ? -headerHeight + (pullSearchHeight ?? 0) : null);
|
|
129
|
+
const remountSyncTarget = useSharedValue(remountTarget);
|
|
130
|
+
const [scrollReady, setScrollReady] = useState(remountTarget === null);
|
|
131
|
+
const remountAttempts = useRef(0);
|
|
132
|
+
const onRemountSynced = useCallback(
|
|
133
|
+
(y) => {
|
|
134
|
+
scrollPosition.value = y;
|
|
135
|
+
setScrollReady(true);
|
|
136
|
+
},
|
|
137
|
+
[scrollPosition]
|
|
138
|
+
);
|
|
139
|
+
const onRemountSyncRetry = useCallback(
|
|
140
|
+
(currentY) => {
|
|
141
|
+
if (remountTarget === null) return;
|
|
142
|
+
remountAttempts.current += 1;
|
|
143
|
+
if (remountAttempts.current > REMOUNT_SYNC_MAX_ATTEMPTS) {
|
|
144
|
+
remountSyncTarget.value = null;
|
|
145
|
+
onRemountSynced(currentY);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
scrollTo(remountTarget, false);
|
|
149
|
+
},
|
|
150
|
+
[onRemountSynced, remountSyncTarget, remountTarget, scrollTo]
|
|
151
|
+
);
|
|
152
|
+
useEffect(() => {
|
|
153
|
+
if (remountTarget === null) return;
|
|
154
|
+
scrollTo(remountTarget, false);
|
|
155
|
+
const fallback = setTimeout(() => {
|
|
156
|
+
if (remountSyncTarget.value === null) return;
|
|
157
|
+
remountSyncTarget.value = null;
|
|
158
|
+
onRemountSynced(remountTarget);
|
|
159
|
+
}, REMOUNT_SYNC_FALLBACK_MS);
|
|
160
|
+
return () => clearTimeout(fallback);
|
|
161
|
+
}, []);
|
|
162
|
+
useEffect(() => {
|
|
163
|
+
if (phase === "ready" || !headerHeight || !pullSearchHeight) return;
|
|
164
|
+
scrollPosition.value = -headerHeight + pullSearchHeight;
|
|
165
|
+
setPhase("ready");
|
|
166
|
+
}, [phase, headerHeight, pullSearchHeight, scrollPosition]);
|
|
167
|
+
const headerInitialized = useRef(false);
|
|
168
|
+
useLayoutEffect(() => {
|
|
169
|
+
if (!headerHeight || headerInitialized.current) return;
|
|
170
|
+
headerInitialized.current = true;
|
|
171
|
+
const target = remountTarget ?? -headerHeight;
|
|
172
|
+
scrollPosition.value = target;
|
|
173
|
+
scrollTo(target, false);
|
|
174
|
+
if (remountTarget === null) return;
|
|
175
|
+
let framesLeft = REMOUNT_PRIME_FRAMES;
|
|
176
|
+
let handle = null;
|
|
177
|
+
const tick = () => {
|
|
178
|
+
const offset = framesLeft === 1 ? target : framesLeft % 2 === 0 ? target + 30 : target - 30;
|
|
179
|
+
scrollTo(offset, false);
|
|
180
|
+
framesLeft -= 1;
|
|
181
|
+
if (framesLeft > 0) handle = requestAnimationFrame(tick);
|
|
182
|
+
};
|
|
183
|
+
handle = requestAnimationFrame(tick);
|
|
184
|
+
return () => {
|
|
185
|
+
if (handle !== null) cancelAnimationFrame(handle);
|
|
186
|
+
};
|
|
187
|
+
}, [remountTarget, headerHeight, scrollPosition, scrollTo]);
|
|
188
|
+
const pullSearchInitialized = useRef(false);
|
|
189
|
+
useLayoutEffect(() => {
|
|
190
|
+
if (remountTarget !== null || !hasPullSearch || phase !== "ready" || pullSearchInitialized.current || !headerHeight || !pullSearchHeight || !scrollReady) return;
|
|
191
|
+
pullSearchInitialized.current = true;
|
|
192
|
+
scrollPosition.value = -headerHeight + pullSearchHeight;
|
|
193
|
+
scrollTo(-headerHeight + pullSearchHeight, false);
|
|
194
|
+
}, [remountTarget, hasPullSearch, phase, headerHeight, pullSearchHeight, scrollPosition, scrollReady, scrollTo]);
|
|
195
|
+
useEffect(() => {
|
|
196
|
+
if (pullSearchHeight) setProgressing(refreshing);
|
|
197
|
+
}, [pullSearchHeight, refreshing, setProgressing]);
|
|
198
|
+
const handleScrollBeginDrag = useCallback(
|
|
199
|
+
(e) => {
|
|
200
|
+
if (snapVerifyTimeout.current !== null) {
|
|
201
|
+
clearTimeout(snapVerifyTimeout.current);
|
|
202
|
+
snapVerifyTimeout.current = null;
|
|
203
|
+
}
|
|
204
|
+
pendingSnapTarget.current = null;
|
|
205
|
+
if (pullSearchHeight) dragStartY.current = e.nativeEvent.contentOffset.y;
|
|
206
|
+
externalScrollBeginDrag?.(e);
|
|
207
|
+
},
|
|
208
|
+
[externalScrollBeginDrag, pullSearchHeight]
|
|
209
|
+
);
|
|
210
|
+
const handleScrollEndDrag = useCallback(
|
|
211
|
+
(e) => {
|
|
212
|
+
if (pullSearchHeight && headerHeight) {
|
|
213
|
+
const y = e.nativeEvent.contentOffset.y;
|
|
214
|
+
const showY = -headerHeight;
|
|
215
|
+
const hideY = -headerHeight + pullSearchHeight;
|
|
216
|
+
const startY = dragStartY.current;
|
|
217
|
+
dragStartY.current = null;
|
|
218
|
+
const pulledDown = (startY ?? hideY) <= hideY;
|
|
219
|
+
const dragDistance = startY !== null ? startY - y : 0;
|
|
220
|
+
if (pulledDown && dragDistance >= pullSearchHeight * 0.5) {
|
|
221
|
+
if (y <= showY && !refreshing && onRefresh) {
|
|
222
|
+
setRefreshing(true);
|
|
223
|
+
Promise.resolve(onRefresh()).finally(() => setRefreshing(false));
|
|
224
|
+
}
|
|
225
|
+
scrollTo(showY, true);
|
|
226
|
+
scheduleSnapVerification(showY, SNAP_VERIFY_INITIAL_DELAY_MS);
|
|
227
|
+
} else if (y < hideY) {
|
|
228
|
+
scrollTo(hideY, true);
|
|
229
|
+
scheduleSnapVerification(hideY, SNAP_VERIFY_INITIAL_DELAY_MS);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
externalScrollEndDrag?.(e);
|
|
233
|
+
},
|
|
234
|
+
[externalScrollEndDrag, headerHeight, onRefresh, pullSearchHeight, refreshing, scheduleSnapVerification, scrollTo]
|
|
235
|
+
);
|
|
236
|
+
const handleMomentumScrollEnd = useCallback(
|
|
237
|
+
(e) => {
|
|
238
|
+
if (pullSearchHeight && headerHeight && !refreshing && pendingSnapTarget.current === null) {
|
|
239
|
+
const y = e.nativeEvent.contentOffset.y;
|
|
240
|
+
const hideY = -headerHeight + pullSearchHeight;
|
|
241
|
+
if (y < hideY - 1) {
|
|
242
|
+
scrollTo(hideY, true);
|
|
243
|
+
scheduleSnapVerification(hideY, SNAP_VERIFY_INITIAL_DELAY_MS);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
externalMomentumScrollEnd?.(e);
|
|
247
|
+
},
|
|
248
|
+
[externalMomentumScrollEnd, headerHeight, pullSearchHeight, refreshing, scheduleSnapVerification, scrollTo]
|
|
249
|
+
);
|
|
250
|
+
const activeListHeader = hasPullSearch && phase === "measuring" ? null : listHeaderComponent;
|
|
251
|
+
const hiddenHeader = phase === "measuring" && listHeaderComponent != null ? typeof listHeaderComponent === "function" ? createElement(listHeaderComponent) : listHeaderComponent : null;
|
|
252
|
+
return { activeListHeader, handleMomentumScrollEnd, handleScrollBeginDrag, handleScrollEndDrag, hiddenHeader, onRemountSyncRetry, onRemountSynced, pullSearchMinHeight: pullSearchHeight ?? 0, remountSyncTarget, remountTarget, scrollReady };
|
|
253
|
+
}
|
|
254
|
+
|
|
60
255
|
// src/internal/useScrollHandler.ts
|
|
61
|
-
function useScrollHandler({ chipHidden, footerFixed, headerFixed, isHorizontal,
|
|
62
|
-
const { footerHeightShared, footerOffset, headerHeightShared, headerOffset, pullSearchHeightShared, scrollPosition, snapBackFooterShared, snapBackHeaderShared } =
|
|
63
|
-
const snapUpAccum =
|
|
64
|
-
const fromBottomBounce =
|
|
65
|
-
const isMomentum = useSharedValue(false);
|
|
66
|
-
const momentumPullSearchFired = useSharedValue(false);
|
|
256
|
+
function useScrollHandler({ capturedGeneration, chipHidden, chipThreshold = 100, footerFixed, headerFixed, isHorizontal, listGeneration, onRemountSyncRetry, onRemountSynced, remountSyncTarget }) {
|
|
257
|
+
const { footerHeightShared, footerOffset, headerHeightShared, headerOffset, pullSearchHeightShared, scrollPosition, snapBackFooterShared, snapBackHeaderShared } = useContext2(ScrollViewContext);
|
|
258
|
+
const snapUpAccum = useSharedValue2(0);
|
|
259
|
+
const fromBottomBounce = useSharedValue2(false);
|
|
67
260
|
return useAnimatedScrollHandler(
|
|
68
261
|
{
|
|
69
262
|
onScroll: ({ contentOffset: { x, y }, contentSize: { height: contentHeight }, layoutMeasurement: { height: layoutHeight } }) => {
|
|
70
263
|
"worklet";
|
|
264
|
+
if (remountSyncTarget && remountSyncTarget.value !== null) {
|
|
265
|
+
const target = remountSyncTarget.value;
|
|
266
|
+
if (Math.abs(y - target) < REMOUNT_SYNC_TOLERANCE) {
|
|
267
|
+
remountSyncTarget.value = null;
|
|
268
|
+
if (onRemountSynced) runOnJS(onRemountSynced)(y);
|
|
269
|
+
} else if (onRemountSyncRetry) {
|
|
270
|
+
runOnJS(onRemountSyncRetry)(y);
|
|
271
|
+
}
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
if (listGeneration.value !== capturedGeneration.value) return;
|
|
71
275
|
if (isHorizontal) {
|
|
72
276
|
scrollPosition.value = x;
|
|
73
|
-
chipHidden.value = x <
|
|
277
|
+
chipHidden.value = x < chipThreshold ? 1 : 0;
|
|
74
278
|
return;
|
|
75
279
|
}
|
|
76
280
|
const delta = y - scrollPosition.value;
|
|
77
281
|
scrollPosition.value = y;
|
|
78
|
-
chipHidden.value = y <
|
|
282
|
+
chipHidden.value = y < chipThreshold ? 1 : 0;
|
|
79
283
|
const maxScroll = contentHeight - layoutHeight;
|
|
80
284
|
if (maxScroll > 0 && y >= maxScroll) {
|
|
81
285
|
fromBottomBounce.value = true;
|
|
@@ -83,13 +287,6 @@ function useScrollHandler({ chipHidden, footerFixed, headerFixed, isHorizontal,
|
|
|
83
287
|
} else if (fromBottomBounce.value) {
|
|
84
288
|
fromBottomBounce.value = false;
|
|
85
289
|
}
|
|
86
|
-
if (isMomentum.value && pullSearchHeightShared.value > 0 && !momentumPullSearchFired.value) {
|
|
87
|
-
const hideY = -headerHeightShared.value + pullSearchHeightShared.value;
|
|
88
|
-
if (y < hideY) {
|
|
89
|
-
momentumPullSearchFired.value = true;
|
|
90
|
-
if (onPullSearchZoneEnter) runOnJS(onPullSearchZoneEnter)();
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
290
|
const snapHeader = snapBackHeaderShared.value && !headerFixed;
|
|
94
291
|
const snapFooter = snapBackFooterShared.value && !footerFixed;
|
|
95
292
|
if (snapHeader || snapFooter) {
|
|
@@ -115,16 +312,9 @@ function useScrollHandler({ chipHidden, footerFixed, headerFixed, isHorizontal,
|
|
|
115
312
|
},
|
|
116
313
|
onBeginDrag: () => {
|
|
117
314
|
"worklet";
|
|
118
|
-
isMomentum.value = false;
|
|
119
|
-
momentumPullSearchFired.value = false;
|
|
120
315
|
fromBottomBounce.value = false;
|
|
121
316
|
snapUpAccum.value = 0;
|
|
122
317
|
},
|
|
123
|
-
onMomentumBegin: () => {
|
|
124
|
-
"worklet";
|
|
125
|
-
isMomentum.value = true;
|
|
126
|
-
momentumPullSearchFired.value = false;
|
|
127
|
-
},
|
|
128
318
|
onEndDrag: ({ contentOffset: { y }, contentSize: { height: contentHeight }, layoutMeasurement: { height: layoutHeight } }) => {
|
|
129
319
|
"worklet";
|
|
130
320
|
if (isHorizontal) return;
|
|
@@ -135,28 +325,26 @@ function useScrollHandler({ chipHidden, footerFixed, headerFixed, isHorizontal,
|
|
|
135
325
|
},
|
|
136
326
|
onMomentumEnd: () => {
|
|
137
327
|
"worklet";
|
|
138
|
-
isMomentum.value = false;
|
|
139
|
-
momentumPullSearchFired.value = false;
|
|
140
328
|
fromBottomBounce.value = false;
|
|
141
329
|
snapUpAccum.value = 0;
|
|
142
330
|
}
|
|
143
331
|
},
|
|
144
|
-
[headerFixed, footerFixed, isHorizontal,
|
|
332
|
+
[capturedGeneration, headerFixed, footerFixed, isHorizontal, chipThreshold, listGeneration, onRemountSyncRetry, onRemountSynced, remountSyncTarget]
|
|
145
333
|
);
|
|
146
334
|
}
|
|
147
335
|
|
|
148
336
|
// src/internal/useScrollList.ts
|
|
149
|
-
import { useContext as
|
|
337
|
+
import { useContext as useContext3, useEffect as useEffect2, useMemo, useState as useState3 } from "react";
|
|
150
338
|
import { StyleSheet as StyleSheet2 } from "react-native";
|
|
151
|
-
import { useAnimatedStyle, useSharedValue as
|
|
339
|
+
import { useAnimatedStyle, useSharedValue as useSharedValue3, withTiming as withTiming2 } from "react-native-reanimated";
|
|
152
340
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
153
341
|
|
|
154
342
|
// src/useKeyboardInset.ts
|
|
155
|
-
import { useState } from "react";
|
|
343
|
+
import { useState as useState2 } from "react";
|
|
156
344
|
import { useKeyboardHandler } from "react-native-keyboard-controller";
|
|
157
345
|
import { runOnJS as runOnJS2 } from "react-native-reanimated";
|
|
158
346
|
var useKeyboardInset = () => {
|
|
159
|
-
const [keyboardHeight, setKeyboardHeight] =
|
|
347
|
+
const [keyboardHeight, setKeyboardHeight] = useState2(0);
|
|
160
348
|
useKeyboardHandler(
|
|
161
349
|
{
|
|
162
350
|
onMove: (e) => {
|
|
@@ -178,28 +366,30 @@ var CHIP_SLIDE = 48;
|
|
|
178
366
|
function useScrollList({ footerFixed: footerFixedProp, headerFixed: headerFixedProp, isHorizontal, keyboardAware, pullSearchHeight, style } = {}) {
|
|
179
367
|
const insets = useSafeAreaInsets();
|
|
180
368
|
const keyboardHeight = useKeyboardInset();
|
|
181
|
-
const { footerHeight, footerFixed: contextFooterFixed, headerHeight, headerFixed: contextHeaderFixed, headerOffset, pullSearchHeightShared, scrollPosition, snapBackHeaderShared } =
|
|
369
|
+
const { footerHeight, footerFixed: contextFooterFixed, headerHeight, headerFixed: contextHeaderFixed, headerOffset, pullSearchHeightShared, scrollPosition, snapBackHeaderShared } = useContext3(ScrollViewContext);
|
|
182
370
|
const headerFixed = isHorizontal ? true : headerFixedProp ?? contextHeaderFixed;
|
|
183
371
|
const footerFixed = isHorizontal ? true : footerFixedProp ?? contextFooterFixed;
|
|
184
|
-
|
|
372
|
+
useEffect2(() => {
|
|
185
373
|
pullSearchHeightShared.value = pullSearchHeight ?? 0;
|
|
186
374
|
}, [pullSearchHeight, pullSearchHeightShared]);
|
|
187
|
-
const containerStyle = useMemo(() => headerHeight ===
|
|
188
|
-
const contentInset = useMemo(() => ({ bottom: (footerFixed ? footerHeight || insets.bottom : insets.bottom) + (keyboardAware ? keyboardHeight : 0), top: headerHeight }), [footerFixed, footerHeight, insets.bottom, headerHeight, keyboardAware, keyboardHeight]);
|
|
189
|
-
const
|
|
190
|
-
const
|
|
375
|
+
const containerStyle = useMemo(() => headerHeight === null ? [{ flex: 1, opacity: 0 }, style] : [StyleSheet2.absoluteFill, style], [headerHeight, style]);
|
|
376
|
+
const contentInset = useMemo(() => ({ bottom: (footerFixed ? footerHeight || insets.bottom : insets.bottom) + (keyboardAware ? keyboardHeight : 0), top: headerHeight ?? 0 }), [footerFixed, footerHeight, insets.bottom, headerHeight, keyboardAware, keyboardHeight]);
|
|
377
|
+
const [startedWithHeader] = useState3(headerHeight !== null);
|
|
378
|
+
const contentOffset = useMemo(() => ({ x: 0, y: headerHeight !== null ? -headerHeight + (startedWithHeader && !isHorizontal && pullSearchHeight ? pullSearchHeight : 0) : 0 }), [headerHeight, isHorizontal, pullSearchHeight, startedWithHeader]);
|
|
379
|
+
const chipHidden = useSharedValue3(1);
|
|
191
380
|
const chipStyle = useAnimatedStyle(() => {
|
|
192
381
|
const pointerEvents = chipHidden.value ? "none" : "box-none";
|
|
193
382
|
if (isHorizontal) {
|
|
194
383
|
return {
|
|
195
384
|
opacity: chipHidden.value ? withTiming2(0) : withTiming2(1),
|
|
196
385
|
pointerEvents,
|
|
197
|
-
top: Math.max(headerHeight, insets.top) + 4,
|
|
386
|
+
top: Math.max(headerHeight ?? 0, insets.top) + 4,
|
|
198
387
|
transform: [{ translateX: chipHidden.value ? withTiming2(-CHIP_SLIDE) : withTiming2(0) }]
|
|
199
388
|
};
|
|
200
389
|
}
|
|
201
|
-
const
|
|
202
|
-
const
|
|
390
|
+
const h = headerHeight ?? 0;
|
|
391
|
+
const slide = headerFixed ? 0 : snapBackHeaderShared.value ? -headerOffset.value : Math.max(0, scrollPosition.value + h - pullSearchHeightShared.value);
|
|
392
|
+
const top = Math.max(h - slide, insets.top) + 4;
|
|
203
393
|
return {
|
|
204
394
|
opacity: chipHidden.value ? withTiming2(0) : withTiming2(1),
|
|
205
395
|
pointerEvents,
|
|
@@ -210,90 +400,21 @@ function useScrollList({ footerFixed: footerFixedProp, headerFixed: headerFixedP
|
|
|
210
400
|
return { chipHidden, chipStyle, containerStyle, contentInset, contentOffset, footerFixed, headerFixed, headerHeight, insets, isHorizontal: isHorizontal ?? false };
|
|
211
401
|
}
|
|
212
402
|
|
|
213
|
-
// src/useScrollInit.ts
|
|
214
|
-
import { createElement, useCallback, useContext as useContext3, useEffect as useEffect2, useLayoutEffect, useRef, useState as useState2 } from "react";
|
|
215
|
-
function useScrollInit({ listHeaderComponent, onMomentumScrollEnd: externalMomentumScrollEnd, onRefresh, onScrollBeginDrag: externalScrollBeginDrag, onScrollEndDrag: externalScrollEndDrag, pullSearchHeight, scrollTo }) {
|
|
216
|
-
const { headerHeight, scrollPosition, setProgressing } = useContext3(ScrollViewContext);
|
|
217
|
-
const hasPullSearch = pullSearchHeight !== void 0;
|
|
218
|
-
const [phase, setPhase] = useState2(hasPullSearch ? "measuring" : "ready");
|
|
219
|
-
const [refreshing, setRefreshing] = useState2(false);
|
|
220
|
-
const dragStartY = useRef(null);
|
|
221
|
-
const deliberatelyOpened = useRef(false);
|
|
222
|
-
useEffect2(() => {
|
|
223
|
-
if (phase === "ready" || !headerHeight || !pullSearchHeight) return;
|
|
224
|
-
scrollPosition.value = -headerHeight + pullSearchHeight;
|
|
225
|
-
setPhase("ready");
|
|
226
|
-
}, [phase, headerHeight, pullSearchHeight, scrollPosition]);
|
|
227
|
-
const headerInitialized = useRef(false);
|
|
228
|
-
useLayoutEffect(() => {
|
|
229
|
-
if (!headerHeight || headerInitialized.current) return;
|
|
230
|
-
headerInitialized.current = true;
|
|
231
|
-
scrollPosition.value = -headerHeight;
|
|
232
|
-
scrollTo(-headerHeight, false);
|
|
233
|
-
}, [headerHeight, scrollPosition, scrollTo]);
|
|
234
|
-
const pullSearchInitialized = useRef(false);
|
|
235
|
-
useLayoutEffect(() => {
|
|
236
|
-
if (!hasPullSearch || phase !== "ready" || pullSearchInitialized.current || !headerHeight || !pullSearchHeight) return;
|
|
237
|
-
pullSearchInitialized.current = true;
|
|
238
|
-
scrollPosition.value = -headerHeight + pullSearchHeight;
|
|
239
|
-
scrollTo(-headerHeight + pullSearchHeight, false);
|
|
240
|
-
}, [hasPullSearch, phase, headerHeight, pullSearchHeight, scrollPosition, scrollTo]);
|
|
241
|
-
useEffect2(() => {
|
|
242
|
-
if (pullSearchHeight) setProgressing(refreshing);
|
|
243
|
-
}, [pullSearchHeight, refreshing, setProgressing]);
|
|
244
|
-
const handleScrollBeginDrag = useCallback(
|
|
245
|
-
(e) => {
|
|
246
|
-
deliberatelyOpened.current = false;
|
|
247
|
-
if (pullSearchHeight) dragStartY.current = e.nativeEvent.contentOffset.y;
|
|
248
|
-
externalScrollBeginDrag?.(e);
|
|
249
|
-
},
|
|
250
|
-
[externalScrollBeginDrag, pullSearchHeight]
|
|
251
|
-
);
|
|
252
|
-
const handleScrollEndDrag = useCallback(
|
|
253
|
-
(e) => {
|
|
254
|
-
if (pullSearchHeight && headerHeight) {
|
|
255
|
-
const y = e.nativeEvent.contentOffset.y;
|
|
256
|
-
const showY = -headerHeight;
|
|
257
|
-
const hideY = -headerHeight + pullSearchHeight;
|
|
258
|
-
const pulledDown = (dragStartY.current ?? hideY) <= hideY;
|
|
259
|
-
dragStartY.current = null;
|
|
260
|
-
if (pulledDown && y <= showY + pullSearchHeight * 0.5) {
|
|
261
|
-
deliberatelyOpened.current = true;
|
|
262
|
-
if (y <= showY && !refreshing && onRefresh) {
|
|
263
|
-
setRefreshing(true);
|
|
264
|
-
Promise.resolve(onRefresh()).finally(() => setRefreshing(false));
|
|
265
|
-
}
|
|
266
|
-
scrollTo(showY, true);
|
|
267
|
-
} else if (y < hideY) {
|
|
268
|
-
scrollTo(hideY, true);
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
externalScrollEndDrag?.(e);
|
|
272
|
-
},
|
|
273
|
-
[externalScrollEndDrag, headerHeight, onRefresh, pullSearchHeight, refreshing, scrollTo]
|
|
274
|
-
);
|
|
275
|
-
const handleMomentumScrollEnd = useCallback(
|
|
276
|
-
(e) => {
|
|
277
|
-
if (pullSearchHeight && headerHeight && !deliberatelyOpened.current && !refreshing) {
|
|
278
|
-
const y = e.nativeEvent.contentOffset.y;
|
|
279
|
-
const hideY = -headerHeight + pullSearchHeight;
|
|
280
|
-
if (y < hideY - 1) scrollTo(hideY, true);
|
|
281
|
-
}
|
|
282
|
-
deliberatelyOpened.current = false;
|
|
283
|
-
externalMomentumScrollEnd?.(e);
|
|
284
|
-
},
|
|
285
|
-
[externalMomentumScrollEnd, headerHeight, pullSearchHeight, refreshing, scrollTo]
|
|
286
|
-
);
|
|
287
|
-
const activeListHeader = hasPullSearch && phase === "measuring" ? null : listHeaderComponent;
|
|
288
|
-
const hiddenHeader = phase === "measuring" && listHeaderComponent != null ? typeof listHeaderComponent === "function" ? createElement(listHeaderComponent) : listHeaderComponent : null;
|
|
289
|
-
return { activeListHeader, handleMomentumScrollEnd, handleScrollBeginDrag, handleScrollEndDrag, hiddenHeader, pullSearchMinHeight: pullSearchHeight ?? 0 };
|
|
290
|
-
}
|
|
291
|
-
|
|
292
403
|
// src/CustomList.tsx
|
|
293
404
|
import { Fragment, jsx as jsx3, jsxs } from "react/jsx-runtime";
|
|
294
|
-
var CustomListInner = ({ component: List, renderFilters, footerFixed: footerFixedProp, gesture, headerFixed: headerFixedProp, keyboardAware, onMomentumScrollEnd: externalMomentumScrollEnd, onRefresh, onScrollBeginDrag: externalScrollBeginDrag, onScrollEndDrag: externalScrollEndDrag, pullSearchHeight, scrollRef, style, ...props }) => {
|
|
405
|
+
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 }) => {
|
|
295
406
|
const { ListHeaderComponent: listHeaderComponent, contentContainerStyle: externalContentContainerStyle, ...restProps } = props;
|
|
296
407
|
const { chipHidden, chipStyle, containerStyle, contentInset, contentOffset, footerFixed, headerFixed } = useScrollList({ footerFixed: footerFixedProp, headerFixed: headerFixedProp, keyboardAware, pullSearchHeight, style });
|
|
408
|
+
const { listGeneration, onListUnmount } = useContext4(ScrollViewContext);
|
|
409
|
+
const capturedGeneration = useSharedValue4(-1);
|
|
410
|
+
useLayoutEffect2(() => {
|
|
411
|
+
const generation = listGeneration.value;
|
|
412
|
+
runOnUI((gen) => {
|
|
413
|
+
"worklet";
|
|
414
|
+
capturedGeneration.value = gen;
|
|
415
|
+
})(generation);
|
|
416
|
+
}, [capturedGeneration, listGeneration]);
|
|
417
|
+
useLayoutEffect2(() => () => onListUnmount(), [onListUnmount]);
|
|
297
418
|
const scrollViewInternal = useRef2(null);
|
|
298
419
|
const handleRef = useCallback2(
|
|
299
420
|
(el) => {
|
|
@@ -311,7 +432,10 @@ var CustomListInner = ({ component: List, renderFilters, footerFixed: footerFixe
|
|
|
311
432
|
handleScrollBeginDrag,
|
|
312
433
|
handleScrollEndDrag,
|
|
313
434
|
hiddenHeader,
|
|
314
|
-
|
|
435
|
+
onRemountSyncRetry,
|
|
436
|
+
onRemountSynced,
|
|
437
|
+
pullSearchMinHeight,
|
|
438
|
+
remountSyncTarget
|
|
315
439
|
} = useScrollInit({
|
|
316
440
|
listHeaderComponent,
|
|
317
441
|
onMomentumScrollEnd: externalMomentumScrollEnd,
|
|
@@ -330,11 +454,7 @@ var CustomListInner = ({ component: List, renderFilters, footerFixed: footerFixe
|
|
|
330
454
|
] });
|
|
331
455
|
}, [pullSearchHeader, renderFilters]);
|
|
332
456
|
const contentContainerStyle = useMemo2(() => [{ minHeight: Dimensions.get("window").height - contentInset.top - contentInset.bottom + pullSearchMinHeight }, externalContentContainerStyle], [contentInset.bottom, contentInset.top, externalContentContainerStyle, pullSearchMinHeight]);
|
|
333
|
-
const
|
|
334
|
-
if (!pullSearchHeight) return;
|
|
335
|
-
scrollViewInternal.current?.scrollToOffset({ offset: -contentInset.top + pullSearchHeight, animated: true });
|
|
336
|
-
}, [contentInset.top, pullSearchHeight]);
|
|
337
|
-
const onScroll = useScrollHandler({ chipHidden, footerFixed, headerFixed, onPullSearchZoneEnter: pullSearchHeight ? onPullSearchZoneEnter : void 0 });
|
|
457
|
+
const onScroll = useScrollHandler({ capturedGeneration, chipHidden, chipThreshold, footerFixed, headerFixed, listGeneration, onRemountSyncRetry, onRemountSynced, remountSyncTarget });
|
|
338
458
|
const handleScrollToTop = useCallback2(() => {
|
|
339
459
|
const offset = pullSearchHeight ? -contentInset.top + pullSearchHeight : -contentInset.top;
|
|
340
460
|
scrollViewInternal.current?.scrollToOffset({ offset, animated: true });
|
|
@@ -347,7 +467,7 @@ var CustomListInner = ({ component: List, renderFilters, footerFixed: footerFixe
|
|
|
347
467
|
const content = /* @__PURE__ */ jsxs(View, { style: containerStyle, children: [
|
|
348
468
|
/* @__PURE__ */ jsx3(TypedList, { ...restProps, contentContainerStyle, contentInset, contentOffset, ListHeaderComponent: activeListHeader, onMomentumScrollEnd: handleMomentumScrollEnd, onScroll, onScrollBeginDrag: handleScrollBeginDrag, onScrollEndDrag: handleScrollEndDrag, ref: handleRef, refreshControl, scrollEventThrottle: 16 }),
|
|
349
469
|
hiddenHeader && /* @__PURE__ */ jsx3(View, { pointerEvents: "none", style: styles2.measureContainer, children: hiddenHeader }),
|
|
350
|
-
/* @__PURE__ */ jsx3(ScrollViewChip, { onPress: handleScrollToTop, style: chipStyle })
|
|
470
|
+
/* @__PURE__ */ jsx3(ScrollViewChip, { chipProps, onChipPress, onPress: handleScrollToTop, style: chipStyle })
|
|
351
471
|
] });
|
|
352
472
|
return detectorGesture ? /* @__PURE__ */ jsx3(GestureDetector, { gesture: detectorGesture, children: content }) : content;
|
|
353
473
|
};
|
|
@@ -355,14 +475,13 @@ var styles2 = { measureContainer: { left: 0, opacity: 0, position: "absolute", r
|
|
|
355
475
|
var CustomList = memo(CustomListInner);
|
|
356
476
|
|
|
357
477
|
// src/FlatList.tsx
|
|
358
|
-
import { memo as memo2, useCallback as
|
|
359
|
-
import { Dimensions as Dimensions2, View as View3 } from "react-native";
|
|
478
|
+
import { Fragment as Fragment2, memo as memo2, useCallback as useCallback4, useContext as useContext7, useLayoutEffect as useLayoutEffect3, useMemo as useMemo3, useRef as useRef4 } from "react";
|
|
479
|
+
import { Dimensions as Dimensions2, FlatList as RNFlatList, View as View3 } from "react-native";
|
|
360
480
|
import { Gesture as Gesture2, GestureDetector as GestureDetector2 } from "react-native-gesture-handler";
|
|
361
|
-
import Animated3 from "react-native-reanimated";
|
|
362
481
|
|
|
363
482
|
// src/internal/HorizontalDots.tsx
|
|
364
483
|
import { BlurView } from "@rific/auto-paper";
|
|
365
|
-
import { useContext as
|
|
484
|
+
import { useContext as useContext5 } from "react";
|
|
366
485
|
import { StyleSheet as StyleSheet3, useWindowDimensions, View as View2 } from "react-native";
|
|
367
486
|
import { useTheme } from "react-native-paper";
|
|
368
487
|
import Animated2, { interpolateColor, useAnimatedStyle as useAnimatedStyle2 } from "react-native-reanimated";
|
|
@@ -391,7 +510,7 @@ var Dot = ({ activeColor, index, inactiveColor, pageWidth, scrollPosition }) =>
|
|
|
391
510
|
return /* @__PURE__ */ jsx4(View2, { style: styles3.dotContainer, children: /* @__PURE__ */ jsx4(Animated2.View, { style: circleStyle }) });
|
|
392
511
|
};
|
|
393
512
|
var HorizontalDots = ({ total }) => {
|
|
394
|
-
const { blur, footerHeightShared, scrollPosition } =
|
|
513
|
+
const { blur, footerHeightShared, scrollPosition } = useContext5(ScrollViewContext);
|
|
395
514
|
const { width } = useWindowDimensions();
|
|
396
515
|
const insets = useSafeAreaInsets2();
|
|
397
516
|
const theme = useTheme();
|
|
@@ -427,14 +546,144 @@ var styles3 = StyleSheet3.create({
|
|
|
427
546
|
pillContainer: { alignItems: "center", left: 0, position: "absolute", right: 0, zIndex: 3 }
|
|
428
547
|
});
|
|
429
548
|
|
|
549
|
+
// src/internal/useScrollHandlerJS.ts
|
|
550
|
+
import { useCallback as useCallback3, useContext as useContext6, useRef as useRef3 } from "react";
|
|
551
|
+
import { withTiming as withTiming3 } from "react-native-reanimated";
|
|
552
|
+
var REMOUNT_RETRY_TOLERANCE = 1;
|
|
553
|
+
var REMOUNT_RETRY_MAX_ATTEMPTS = 8;
|
|
554
|
+
function useScrollHandlerJS({ capturedGeneration, chipHidden, chipThreshold = 100, footerFixed, headerFixed, isHorizontal, jsListGeneration, remountTarget = null, scrollTo }) {
|
|
555
|
+
const { footerHeightShared, footerOffset, headerHeightShared, headerOffset, pullSearchHeightShared, scrollPosition, snapBackFooterShared, snapBackHeaderShared } = useContext6(ScrollViewContext);
|
|
556
|
+
const snapUpAccum = useRef3(0);
|
|
557
|
+
const fromBottomBounce = useRef3(false);
|
|
558
|
+
const pendingRemountTarget = useRef3(remountTarget);
|
|
559
|
+
const remountAttempts = useRef3(0);
|
|
560
|
+
const onScroll = useCallback3(
|
|
561
|
+
(event) => {
|
|
562
|
+
if (jsListGeneration.current !== capturedGeneration.current) return;
|
|
563
|
+
const {
|
|
564
|
+
contentOffset: { x, y },
|
|
565
|
+
contentSize: { height: contentHeight },
|
|
566
|
+
layoutMeasurement: { height: layoutHeight }
|
|
567
|
+
} = event.nativeEvent;
|
|
568
|
+
if (pendingRemountTarget.current !== null) {
|
|
569
|
+
const target = pendingRemountTarget.current;
|
|
570
|
+
if (Math.abs(y - target) < REMOUNT_RETRY_TOLERANCE) {
|
|
571
|
+
pendingRemountTarget.current = null;
|
|
572
|
+
} else {
|
|
573
|
+
remountAttempts.current += 1;
|
|
574
|
+
if (remountAttempts.current > REMOUNT_RETRY_MAX_ATTEMPTS) {
|
|
575
|
+
pendingRemountTarget.current = null;
|
|
576
|
+
} else {
|
|
577
|
+
scrollTo?.(target, false);
|
|
578
|
+
return;
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
if (isHorizontal) {
|
|
583
|
+
scrollPosition.value = x;
|
|
584
|
+
chipHidden.value = x < chipThreshold ? 1 : 0;
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
587
|
+
const delta = y - scrollPosition.value;
|
|
588
|
+
scrollPosition.value = y;
|
|
589
|
+
chipHidden.value = y < chipThreshold ? 1 : 0;
|
|
590
|
+
const maxScroll = contentHeight - layoutHeight;
|
|
591
|
+
if (maxScroll > 0 && y >= maxScroll) {
|
|
592
|
+
fromBottomBounce.current = true;
|
|
593
|
+
snapUpAccum.current = 0;
|
|
594
|
+
} else if (fromBottomBounce.current) {
|
|
595
|
+
fromBottomBounce.current = false;
|
|
596
|
+
}
|
|
597
|
+
const snapHeader = snapBackHeaderShared.value && !headerFixed;
|
|
598
|
+
const snapFooter = snapBackFooterShared.value && !footerFixed;
|
|
599
|
+
if (snapHeader || snapFooter) {
|
|
600
|
+
if (y <= -headerHeightShared.value) {
|
|
601
|
+
snapUpAccum.current = 0;
|
|
602
|
+
if (snapHeader) headerOffset.value = 0;
|
|
603
|
+
if (snapFooter) footerOffset.value = 0;
|
|
604
|
+
} else if (delta > 0) {
|
|
605
|
+
snapUpAccum.current = 0;
|
|
606
|
+
if (y >= -headerHeightShared.value + pullSearchHeightShared.value) {
|
|
607
|
+
if (snapHeader) headerOffset.value = Math.max(-headerHeightShared.value, Math.min(0, headerOffset.value - delta));
|
|
608
|
+
if (snapFooter) footerOffset.value = Math.max(0, Math.min(footerHeightShared.value, footerOffset.value + delta));
|
|
609
|
+
}
|
|
610
|
+
} else if (delta < 0 && !fromBottomBounce.current) {
|
|
611
|
+
if (y >= -headerHeightShared.value + pullSearchHeightShared.value) snapUpAccum.current -= delta;
|
|
612
|
+
if (snapUpAccum.current >= 10) {
|
|
613
|
+
snapUpAccum.current = 999;
|
|
614
|
+
if (snapHeader) headerOffset.value = withTiming3(0, { duration: 200 });
|
|
615
|
+
if (snapFooter) footerOffset.value = withTiming3(0, { duration: 200 });
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
},
|
|
620
|
+
[capturedGeneration, chipHidden, chipThreshold, footerFixed, footerHeightShared, footerOffset, headerFixed, headerHeightShared, headerOffset, isHorizontal, jsListGeneration, pullSearchHeightShared, scrollPosition, scrollTo, snapBackFooterShared, snapBackHeaderShared]
|
|
621
|
+
);
|
|
622
|
+
const onScrollBeginDrag = useCallback3(() => {
|
|
623
|
+
fromBottomBounce.current = false;
|
|
624
|
+
snapUpAccum.current = 0;
|
|
625
|
+
}, []);
|
|
626
|
+
const onMomentumScrollBegin = useCallback3(() => {
|
|
627
|
+
}, []);
|
|
628
|
+
const onScrollEndDrag = useCallback3(
|
|
629
|
+
(event) => {
|
|
630
|
+
if (isHorizontal) return;
|
|
631
|
+
const {
|
|
632
|
+
contentOffset: { y },
|
|
633
|
+
contentSize: { height: contentHeight },
|
|
634
|
+
layoutMeasurement: { height: layoutHeight }
|
|
635
|
+
} = event.nativeEvent;
|
|
636
|
+
if (y >= contentHeight - layoutHeight - 10) {
|
|
637
|
+
fromBottomBounce.current = true;
|
|
638
|
+
snapUpAccum.current = 0;
|
|
639
|
+
}
|
|
640
|
+
},
|
|
641
|
+
[isHorizontal]
|
|
642
|
+
);
|
|
643
|
+
const onMomentumScrollEnd = useCallback3(() => {
|
|
644
|
+
fromBottomBounce.current = false;
|
|
645
|
+
snapUpAccum.current = 0;
|
|
646
|
+
}, []);
|
|
647
|
+
return { onMomentumScrollBegin, onMomentumScrollEnd, onScroll, onScrollBeginDrag, onScrollEndDrag };
|
|
648
|
+
}
|
|
649
|
+
|
|
430
650
|
// src/FlatList.tsx
|
|
431
|
-
import { Fragment as
|
|
432
|
-
var FlatListInner = ({ contentContainerStyle: externalContentContainerStyle, data, initialNumToRender = 20, maxToRenderPerBatch = 50, renderFilters, footerFixed: footerFixedProp, gesture, headerFixed: headerFixedProp, horizontal, keyboardAware, ListHeaderComponent: externalListHeaderComponent, onMomentumScrollEnd: externalMomentumScrollEnd, onRefresh, onScrollBeginDrag: externalScrollBeginDrag, onScrollEndDrag: externalScrollEndDrag, pagingEnabled, pullSearchHeight, removeClippedSubviews = false, showsHorizontalScrollIndicator, showsVerticalScrollIndicator, style, onContentSizeChange, ref: externalRef, windowSize = 100, ...props }) => {
|
|
433
|
-
const scrollView =
|
|
651
|
+
import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
652
|
+
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 }) => {
|
|
653
|
+
const scrollView = useRef4(null);
|
|
434
654
|
const isHorizontal = horizontal === true;
|
|
435
655
|
const showDots = isHorizontal && pagingEnabled === true && (data?.length ?? 0) > 1;
|
|
656
|
+
const cols = numColumns && numColumns > 1 ? numColumns : 1;
|
|
657
|
+
const rowData = useMemo3(() => {
|
|
658
|
+
if (cols <= 1 || !data) return data;
|
|
659
|
+
const items = Array.from(data);
|
|
660
|
+
const rows = [];
|
|
661
|
+
for (let i = 0; i < items.length; i += cols) rows.push(items.slice(i, i + cols));
|
|
662
|
+
return rows;
|
|
663
|
+
}, [cols, data]);
|
|
664
|
+
const rowKeyExtractor = useCallback4(
|
|
665
|
+
(row, rowIndex) => {
|
|
666
|
+
if (cols <= 1) return keyExtractor ? keyExtractor(row, rowIndex) : defaultKeyExtractor(row, rowIndex);
|
|
667
|
+
return row.map((item, kk) => keyExtractor ? keyExtractor(item, rowIndex * cols + kk) : defaultKeyExtractor(item, rowIndex * cols + kk)).join(":");
|
|
668
|
+
},
|
|
669
|
+
[cols, keyExtractor]
|
|
670
|
+
);
|
|
671
|
+
const rowRenderItem = useCallback4(
|
|
672
|
+
(info) => {
|
|
673
|
+
if (cols <= 1) return renderItem ? renderItem(info) : null;
|
|
674
|
+
const row = info.item;
|
|
675
|
+
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)) });
|
|
676
|
+
},
|
|
677
|
+
[cols, columnWrapperStyle, renderItem]
|
|
678
|
+
);
|
|
436
679
|
const { chipHidden, chipStyle, containerStyle, contentInset, contentOffset, footerFixed, headerFixed } = useScrollList({ footerFixed: footerFixedProp, headerFixed: headerFixedProp, isHorizontal, keyboardAware, pullSearchHeight, style });
|
|
437
|
-
const
|
|
680
|
+
const { jsListGeneration, onJsListUnmount } = useContext7(ScrollViewContext);
|
|
681
|
+
const capturedGeneration = useRef4(jsListGeneration.current);
|
|
682
|
+
useLayoutEffect3(() => {
|
|
683
|
+
capturedGeneration.current = jsListGeneration.current;
|
|
684
|
+
}, [jsListGeneration]);
|
|
685
|
+
useLayoutEffect3(() => () => onJsListUnmount(), [onJsListUnmount]);
|
|
686
|
+
const scrollTo = useCallback4((offset, animated) => {
|
|
438
687
|
scrollView.current?.scrollToOffset({ offset, animated });
|
|
439
688
|
}, []);
|
|
440
689
|
const {
|
|
@@ -443,7 +692,8 @@ var FlatListInner = ({ contentContainerStyle: externalContentContainerStyle, dat
|
|
|
443
692
|
handleScrollBeginDrag,
|
|
444
693
|
handleScrollEndDrag,
|
|
445
694
|
hiddenHeader,
|
|
446
|
-
pullSearchMinHeight
|
|
695
|
+
pullSearchMinHeight,
|
|
696
|
+
remountTarget
|
|
447
697
|
} = useScrollInit({
|
|
448
698
|
listHeaderComponent: externalListHeaderComponent,
|
|
449
699
|
onMomentumScrollEnd: externalMomentumScrollEnd,
|
|
@@ -456,18 +706,35 @@ var FlatListInner = ({ contentContainerStyle: externalContentContainerStyle, dat
|
|
|
456
706
|
const activeListHeader = useMemo3(() => {
|
|
457
707
|
if (!renderFilters) return pullSearchHeader;
|
|
458
708
|
const Inner = pullSearchHeader;
|
|
459
|
-
return () => /* @__PURE__ */ jsxs3(
|
|
709
|
+
return () => /* @__PURE__ */ jsxs3(Fragment3, { children: [
|
|
460
710
|
Inner ? typeof Inner === "function" ? /* @__PURE__ */ jsx5(Inner, {}) : Inner : null,
|
|
461
711
|
renderFilters
|
|
462
712
|
] });
|
|
463
713
|
}, [pullSearchHeader, renderFilters]);
|
|
464
714
|
const contentContainerStyle = useMemo3(() => isHorizontal ? externalContentContainerStyle : [{ minHeight: Dimensions2.get("window").height - contentInset.top - contentInset.bottom + pullSearchMinHeight }, externalContentContainerStyle], [isHorizontal, contentInset.bottom, contentInset.top, externalContentContainerStyle, pullSearchMinHeight]);
|
|
465
|
-
const
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
715
|
+
const scrollHandler = useScrollHandlerJS({ capturedGeneration, chipHidden, chipThreshold, footerFixed, headerFixed, isHorizontal, jsListGeneration, remountTarget, scrollTo });
|
|
716
|
+
const onScrollBeginDrag = useCallback4(
|
|
717
|
+
(e) => {
|
|
718
|
+
scrollHandler.onScrollBeginDrag(e);
|
|
719
|
+
handleScrollBeginDrag(e);
|
|
720
|
+
},
|
|
721
|
+
[scrollHandler, handleScrollBeginDrag]
|
|
722
|
+
);
|
|
723
|
+
const onScrollEndDrag = useCallback4(
|
|
724
|
+
(e) => {
|
|
725
|
+
scrollHandler.onScrollEndDrag(e);
|
|
726
|
+
handleScrollEndDrag(e);
|
|
727
|
+
},
|
|
728
|
+
[scrollHandler, handleScrollEndDrag]
|
|
729
|
+
);
|
|
730
|
+
const onMomentumScrollEnd = useCallback4(
|
|
731
|
+
(e) => {
|
|
732
|
+
scrollHandler.onMomentumScrollEnd(e);
|
|
733
|
+
handleMomentumScrollEnd(e);
|
|
734
|
+
},
|
|
735
|
+
[scrollHandler, handleMomentumScrollEnd]
|
|
736
|
+
);
|
|
737
|
+
const handleScrollToTop = useCallback4(() => {
|
|
471
738
|
if (isHorizontal) {
|
|
472
739
|
scrollView.current?.scrollToOffset({ offset: 0, animated: true });
|
|
473
740
|
return;
|
|
@@ -475,7 +742,7 @@ var FlatListInner = ({ contentContainerStyle: externalContentContainerStyle, dat
|
|
|
475
742
|
const offset = pullSearchHeight ? -contentInset.top + pullSearchHeight : -contentInset.top;
|
|
476
743
|
scrollView.current?.scrollToOffset({ offset, animated: true });
|
|
477
744
|
}, [isHorizontal, contentInset.top, pullSearchHeight]);
|
|
478
|
-
const handleContentSizeChange =
|
|
745
|
+
const handleContentSizeChange = useCallback4(
|
|
479
746
|
(w, h) => {
|
|
480
747
|
if (onContentSizeChange) onContentSizeChange(w, h);
|
|
481
748
|
},
|
|
@@ -487,23 +754,27 @@ var FlatListInner = ({ contentContainerStyle: externalContentContainerStyle, dat
|
|
|
487
754
|
const detectorGesture = gesture !== void 0 ? combinedGesture : void 0;
|
|
488
755
|
const content = /* @__PURE__ */ jsxs3(View3, { style: containerStyle, children: [
|
|
489
756
|
/* @__PURE__ */ jsx5(
|
|
490
|
-
|
|
757
|
+
RNFlatList,
|
|
491
758
|
{
|
|
492
759
|
...props,
|
|
493
760
|
contentContainerStyle,
|
|
494
761
|
contentInset,
|
|
762
|
+
contentInsetAdjustmentBehavior: "never",
|
|
495
763
|
contentOffset,
|
|
496
|
-
data,
|
|
764
|
+
data: cols > 1 ? rowData : data,
|
|
497
765
|
horizontal: isHorizontal,
|
|
498
766
|
initialNumToRender,
|
|
767
|
+
keyExtractor: cols > 1 ? rowKeyExtractor : keyExtractor,
|
|
499
768
|
ListHeaderComponent: activeListHeader,
|
|
500
769
|
maxToRenderPerBatch,
|
|
501
770
|
onContentSizeChange: handleContentSizeChange,
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
771
|
+
onMomentumScrollBegin: scrollHandler.onMomentumScrollBegin,
|
|
772
|
+
onMomentumScrollEnd,
|
|
773
|
+
onScroll: scrollHandler.onScroll,
|
|
774
|
+
onScrollBeginDrag,
|
|
775
|
+
onScrollEndDrag,
|
|
506
776
|
pagingEnabled,
|
|
777
|
+
renderItem: cols > 1 ? rowRenderItem : renderItem,
|
|
507
778
|
ref: (el) => {
|
|
508
779
|
if (externalRef) externalRef.current = el;
|
|
509
780
|
scrollView.current = el;
|
|
@@ -517,27 +788,31 @@ var FlatListInner = ({ contentContainerStyle: externalContentContainerStyle, dat
|
|
|
517
788
|
}
|
|
518
789
|
),
|
|
519
790
|
hiddenHeader && /* @__PURE__ */ jsx5(View3, { pointerEvents: "none", style: styles4.measureContainer, children: hiddenHeader }),
|
|
520
|
-
/* @__PURE__ */ jsx5(ScrollViewChip, { isHorizontal, onPress: handleScrollToTop, style: chipStyle }),
|
|
791
|
+
/* @__PURE__ */ jsx5(ScrollViewChip, { chipProps, isHorizontal, onChipPress, onPress: handleScrollToTop, style: chipStyle }),
|
|
521
792
|
showDots && /* @__PURE__ */ jsx5(HorizontalDots, { total: data?.length ?? 0 })
|
|
522
793
|
] });
|
|
523
794
|
return detectorGesture ? /* @__PURE__ */ jsx5(GestureDetector2, { gesture: detectorGesture, children: content }) : content;
|
|
524
795
|
};
|
|
525
|
-
var
|
|
796
|
+
var defaultKeyExtractor = (item, index) => {
|
|
797
|
+
const key = item?.key ?? item?.id;
|
|
798
|
+
return key != null ? String(key) : String(index);
|
|
799
|
+
};
|
|
800
|
+
var styles4 = { measureContainer: { left: 0, opacity: 0, position: "absolute", right: 0, top: -9999 }, row: { flexDirection: "row" } };
|
|
526
801
|
var FlatList = memo2(FlatListInner);
|
|
527
802
|
|
|
528
803
|
// src/PullSearch.tsx
|
|
529
|
-
import { forwardRef, useCallback as
|
|
804
|
+
import { forwardRef, useCallback as useCallback5, useContext as useContext8, useEffect as useEffect3, useImperativeHandle, useRef as useRef5, useState as useState4 } from "react";
|
|
530
805
|
import { StyleSheet as StyleSheet4 } from "react-native";
|
|
531
806
|
import { Searchbar, useTheme as useTheme2 } from "react-native-paper";
|
|
532
|
-
import
|
|
807
|
+
import Animated3, { Extrapolation, interpolate, runOnJS as runOnJS3, useAnimatedReaction, useAnimatedStyle as useAnimatedStyle3 } from "react-native-reanimated";
|
|
533
808
|
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
534
809
|
var PullSearch = forwardRef(function PullSearch2({ debounce, onChangeText, onHeightChange, placeholder, value: propValue }, ref) {
|
|
535
|
-
const { headerHeight, scrollPosition } =
|
|
810
|
+
const { headerHeight, scrollPosition } = useContext8(ScrollViewContext);
|
|
536
811
|
const theme = useTheme2();
|
|
537
|
-
const inputRef =
|
|
538
|
-
const [barHeight, setBarHeight] =
|
|
539
|
-
const [value, setValue] =
|
|
540
|
-
const prevPropValueRef =
|
|
812
|
+
const inputRef = useRef5(null);
|
|
813
|
+
const [barHeight, setBarHeight] = useState4(0);
|
|
814
|
+
const [value, setValue] = useState4(propValue ?? "");
|
|
815
|
+
const prevPropValueRef = useRef5(propValue);
|
|
541
816
|
useEffect3(() => {
|
|
542
817
|
if (prevPropValueRef.current === propValue) return;
|
|
543
818
|
prevPropValueRef.current = propValue;
|
|
@@ -547,22 +822,22 @@ var PullSearch = forwardRef(function PullSearch2({ debounce, onChangeText, onHei
|
|
|
547
822
|
blur: () => inputRef.current?.blur(),
|
|
548
823
|
focus: () => inputRef.current?.focus()
|
|
549
824
|
}));
|
|
550
|
-
const blurInput =
|
|
825
|
+
const blurInput = useCallback5(() => inputRef.current?.blur(), []);
|
|
551
826
|
useAnimatedReaction(
|
|
552
827
|
() => {
|
|
553
828
|
if (barHeight === 0) return false;
|
|
554
|
-
return scrollPosition.value >= -headerHeight + barHeight;
|
|
829
|
+
return scrollPosition.value >= -(headerHeight ?? 0) + barHeight;
|
|
555
830
|
},
|
|
556
831
|
(isHidden, wasHidden) => {
|
|
557
832
|
if (isHidden && !wasHidden) runOnJS3(blurInput)();
|
|
558
833
|
},
|
|
559
834
|
[barHeight, headerHeight, blurInput]
|
|
560
835
|
);
|
|
561
|
-
const handleClear =
|
|
836
|
+
const handleClear = useCallback5(() => {
|
|
562
837
|
setValue("");
|
|
563
838
|
onChangeText("");
|
|
564
839
|
}, [onChangeText]);
|
|
565
|
-
const handleLayout =
|
|
840
|
+
const handleLayout = useCallback5(
|
|
566
841
|
({
|
|
567
842
|
nativeEvent: {
|
|
568
843
|
layout: { height }
|
|
@@ -583,11 +858,12 @@ var PullSearch = forwardRef(function PullSearch2({ debounce, onChangeText, onHei
|
|
|
583
858
|
}, [debounce, onChangeText, value]);
|
|
584
859
|
const animatedStyle = useAnimatedStyle3(() => {
|
|
585
860
|
if (barHeight === 0) return { opacity: 0 };
|
|
586
|
-
const
|
|
587
|
-
const
|
|
861
|
+
const h = headerHeight ?? 0;
|
|
862
|
+
const showY = -h;
|
|
863
|
+
const hideY = -h + barHeight;
|
|
588
864
|
return { opacity: interpolate(scrollPosition.value, [showY, hideY], [1, 0], Extrapolation.CLAMP) };
|
|
589
865
|
}, [barHeight, headerHeight]);
|
|
590
|
-
return /* @__PURE__ */ jsx6(
|
|
866
|
+
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 }) });
|
|
591
867
|
});
|
|
592
868
|
var styles5 = StyleSheet4.create({
|
|
593
869
|
container: { paddingVertical: 8 },
|
|
@@ -1088,6 +1364,24 @@ var objectTraps = {
|
|
|
1088
1364
|
get(state, prop) {
|
|
1089
1365
|
if (prop === DRAFT_STATE)
|
|
1090
1366
|
return state;
|
|
1367
|
+
if (prop === "constructor" || prop === "__proto__") {
|
|
1368
|
+
const source2 = latest(state);
|
|
1369
|
+
const value2 = source2[prop];
|
|
1370
|
+
return new Proxy(value2 || {}, {
|
|
1371
|
+
get: (target, key) => {
|
|
1372
|
+
if (key === "__proto__" || key === "prototype") {
|
|
1373
|
+
return Object.freeze(/* @__PURE__ */ Object.create(null));
|
|
1374
|
+
}
|
|
1375
|
+
return Reflect.get(target, key);
|
|
1376
|
+
},
|
|
1377
|
+
set: () => {
|
|
1378
|
+
return true;
|
|
1379
|
+
},
|
|
1380
|
+
apply: (target, thisArg, args) => {
|
|
1381
|
+
return Reflect.apply(target, thisArg, args);
|
|
1382
|
+
}
|
|
1383
|
+
});
|
|
1384
|
+
}
|
|
1091
1385
|
let arrayPlugin = state.scope_.arrayMethodsPlugin_;
|
|
1092
1386
|
const isArrayWithStringProp = state.type_ === 1 && typeof prop === "string";
|
|
1093
1387
|
if (isArrayWithStringProp) {
|
|
@@ -1117,12 +1411,18 @@ var objectTraps = {
|
|
|
1117
1411
|
return value;
|
|
1118
1412
|
},
|
|
1119
1413
|
has(state, prop) {
|
|
1414
|
+
if (prop === "constructor" || prop === "__proto__" || prop === "prototype") {
|
|
1415
|
+
return false;
|
|
1416
|
+
}
|
|
1120
1417
|
return prop in latest(state);
|
|
1121
1418
|
},
|
|
1122
1419
|
ownKeys(state) {
|
|
1123
1420
|
return Reflect.ownKeys(latest(state));
|
|
1124
1421
|
},
|
|
1125
1422
|
set(state, prop, value) {
|
|
1423
|
+
if (prop === "constructor" || prop === "__proto__" || prop === "prototype") {
|
|
1424
|
+
return true;
|
|
1425
|
+
}
|
|
1126
1426
|
const desc = getDescriptorFromProto(latest(state), prop);
|
|
1127
1427
|
if (desc?.set) {
|
|
1128
1428
|
desc.set.call(state.draft_, value);
|
|
@@ -1142,7 +1442,7 @@ var objectTraps = {
|
|
|
1142
1442
|
markChanged(state);
|
|
1143
1443
|
}
|
|
1144
1444
|
if (state.copy_[prop] === value && // special case: handle new props with value 'undefined'
|
|
1145
|
-
(value !== void 0 || prop
|
|
1445
|
+
(value !== void 0 || has(state.copy_, prop, state.type_)) || // special case: NaN
|
|
1146
1446
|
Number.isNaN(value) && Number.isNaN(state.copy_[prop]))
|
|
1147
1447
|
return true;
|
|
1148
1448
|
state.copy_[prop] = value;
|
|
@@ -2158,16 +2458,26 @@ var scrollViewActions = slice.actions;
|
|
|
2158
2458
|
var scrollViewReducer = slice.reducer;
|
|
2159
2459
|
|
|
2160
2460
|
// src/ScrollView.tsx
|
|
2161
|
-
import { memo as memo3, useCallback as
|
|
2461
|
+
import { memo as memo3, useCallback as useCallback6, useContext as useContext9, useLayoutEffect as useLayoutEffect4, useMemo as useMemo4, useRef as useRef6 } from "react";
|
|
2162
2462
|
import { View as View4 } from "react-native";
|
|
2163
2463
|
import { Gesture as Gesture3, GestureDetector as GestureDetector3 } from "react-native-gesture-handler";
|
|
2164
|
-
import
|
|
2464
|
+
import Animated4, { runOnUI as runOnUI2, useSharedValue as useSharedValue5 } from "react-native-reanimated";
|
|
2165
2465
|
import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
2166
|
-
var ScrollViewInner = ({ children, footerFixed: footerFixedProp, gesture, headerFixed: headerFixedProp, horizontal, keyboardAware, onMomentumScrollEnd: externalMomentumScrollEnd, onRefresh, onScrollBeginDrag: externalScrollBeginDrag, onScrollEndDrag: externalScrollEndDrag, pullSearchHeight, refreshing, style, ...props }) => {
|
|
2167
|
-
const scrollView =
|
|
2466
|
+
var ScrollViewInner = ({ chipProps, chipThreshold, children, footerFixed: footerFixedProp, gesture, headerFixed: headerFixedProp, horizontal, keyboardAware, onChipPress, onMomentumScrollEnd: externalMomentumScrollEnd, onRefresh, onScrollBeginDrag: externalScrollBeginDrag, onScrollEndDrag: externalScrollEndDrag, pullSearchHeight, refreshing, style, ...props }) => {
|
|
2467
|
+
const scrollView = useRef6(null);
|
|
2168
2468
|
const isHorizontal = horizontal === true;
|
|
2169
2469
|
const { chipHidden, chipStyle, containerStyle, contentInset, contentOffset, footerFixed, headerFixed } = useScrollList({ footerFixed: footerFixedProp, headerFixed: headerFixedProp, isHorizontal, keyboardAware, pullSearchHeight, style });
|
|
2170
|
-
const
|
|
2470
|
+
const { listGeneration, onListUnmount } = useContext9(ScrollViewContext);
|
|
2471
|
+
const capturedGeneration = useSharedValue5(-1);
|
|
2472
|
+
useLayoutEffect4(() => {
|
|
2473
|
+
const generation = listGeneration.value;
|
|
2474
|
+
runOnUI2((gen) => {
|
|
2475
|
+
"worklet";
|
|
2476
|
+
capturedGeneration.value = gen;
|
|
2477
|
+
})(generation);
|
|
2478
|
+
}, [capturedGeneration, listGeneration]);
|
|
2479
|
+
useLayoutEffect4(() => () => onListUnmount(), [onListUnmount]);
|
|
2480
|
+
const scrollTo = useCallback6((offset, animated) => {
|
|
2171
2481
|
scrollView.current?.scrollTo({ y: offset, animated });
|
|
2172
2482
|
}, []);
|
|
2173
2483
|
const { handleMomentumScrollEnd, handleScrollBeginDrag, handleScrollEndDrag } = useScrollInit({
|
|
@@ -2177,12 +2487,8 @@ var ScrollViewInner = ({ children, footerFixed: footerFixedProp, gesture, header
|
|
|
2177
2487
|
pullSearchHeight,
|
|
2178
2488
|
scrollTo
|
|
2179
2489
|
});
|
|
2180
|
-
const
|
|
2181
|
-
|
|
2182
|
-
scrollTo(-contentInset.top + pullSearchHeight, true);
|
|
2183
|
-
}, [contentInset.top, pullSearchHeight, scrollTo]);
|
|
2184
|
-
const handleScroll = useScrollHandler({ chipHidden, footerFixed, headerFixed, isHorizontal, onPullSearchZoneEnter: pullSearchHeight ? onPullSearchZoneEnter : void 0 });
|
|
2185
|
-
const handleScrollToTop = useCallback5(() => {
|
|
2490
|
+
const handleScroll = useScrollHandler({ capturedGeneration, chipHidden, chipThreshold, footerFixed, headerFixed, isHorizontal, listGeneration });
|
|
2491
|
+
const handleScrollToTop = useCallback6(() => {
|
|
2186
2492
|
if (isHorizontal) {
|
|
2187
2493
|
scrollView.current?.scrollTo({ x: 0, animated: true });
|
|
2188
2494
|
return;
|
|
@@ -2196,7 +2502,7 @@ var ScrollViewInner = ({ children, footerFixed: footerFixedProp, gesture, header
|
|
|
2196
2502
|
const detectorGesture = gesture !== void 0 ? combinedGesture : void 0;
|
|
2197
2503
|
const content = /* @__PURE__ */ jsxs4(View4, { style: containerStyle, children: [
|
|
2198
2504
|
/* @__PURE__ */ jsx7(
|
|
2199
|
-
|
|
2505
|
+
Animated4.ScrollView,
|
|
2200
2506
|
{
|
|
2201
2507
|
...props,
|
|
2202
2508
|
contentInset,
|
|
@@ -2214,7 +2520,7 @@ var ScrollViewInner = ({ children, footerFixed: footerFixedProp, gesture, header
|
|
|
2214
2520
|
children
|
|
2215
2521
|
}
|
|
2216
2522
|
),
|
|
2217
|
-
/* @__PURE__ */ jsx7(ScrollViewChip, { isHorizontal, onPress: handleScrollToTop, style: chipStyle })
|
|
2523
|
+
/* @__PURE__ */ jsx7(ScrollViewChip, { chipProps, isHorizontal, onChipPress, onPress: handleScrollToTop, style: chipStyle })
|
|
2218
2524
|
] });
|
|
2219
2525
|
return detectorGesture ? /* @__PURE__ */ jsx7(GestureDetector3, { gesture: detectorGesture, children: content }) : content;
|
|
2220
2526
|
};
|
|
@@ -2222,13 +2528,13 @@ var ScrollView = memo3(ScrollViewInner);
|
|
|
2222
2528
|
|
|
2223
2529
|
// src/ScrollViewFooter.tsx
|
|
2224
2530
|
import { BlurView as BlurView2 } from "@rific/auto-paper";
|
|
2225
|
-
import { useContext as
|
|
2531
|
+
import { useContext as useContext10, useEffect as useEffect4 } from "react";
|
|
2226
2532
|
import { StyleSheet as StyleSheet5, View as View5 } from "react-native";
|
|
2227
|
-
import
|
|
2533
|
+
import Animated5, { useAnimatedStyle as useAnimatedStyle4 } from "react-native-reanimated";
|
|
2228
2534
|
import { useSafeAreaInsets as useSafeAreaInsets3 } from "react-native-safe-area-context";
|
|
2229
2535
|
import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
2230
2536
|
var ScrollViewFooter = ({ children, style }) => {
|
|
2231
|
-
const { blur, footerHeight, footerFixed, footerOffset, headerHeightShared, pullSearchHeightShared, scrollPosition, setFooterHeight, snapBackFooterShared } =
|
|
2537
|
+
const { blur, footerHeight, footerFixed, footerOffset, headerHeightShared, pullSearchHeightShared, scrollPosition, setFooterHeight, snapBackFooterShared } = useContext10(ScrollViewContext);
|
|
2232
2538
|
const insets = useSafeAreaInsets3();
|
|
2233
2539
|
useEffect4(
|
|
2234
2540
|
() => () => {
|
|
@@ -2250,7 +2556,7 @@ var ScrollViewFooter = ({ children, style }) => {
|
|
|
2250
2556
|
if (effective <= 0) return { transform: [{ translateY: 0 }] };
|
|
2251
2557
|
return { transform: [{ translateY: Math.min(effective, footerHeight) }] };
|
|
2252
2558
|
}, [footerHeight, footerFixed]);
|
|
2253
|
-
return /* @__PURE__ */ jsxs5(
|
|
2559
|
+
return /* @__PURE__ */ jsxs5(Animated5.View, { onLayout: handleLayout, pointerEvents: "box-none", style: [styles6.footer, footerStyle], children: [
|
|
2254
2560
|
footerHeight > 0 && /* @__PURE__ */ jsx8(BlurView2, { blur, style: StyleSheet5.absoluteFill }),
|
|
2255
2561
|
/* @__PURE__ */ jsx8(View5, { style: [styles6.row, { paddingBottom: insets.bottom }, style], children })
|
|
2256
2562
|
] });
|
|
@@ -2262,16 +2568,16 @@ var styles6 = StyleSheet5.create({
|
|
|
2262
2568
|
|
|
2263
2569
|
// src/ScrollViewHeader.tsx
|
|
2264
2570
|
import { BlurView as BlurView3 } from "@rific/auto-paper";
|
|
2265
|
-
import { useContext as
|
|
2571
|
+
import { useContext as useContext11 } from "react";
|
|
2266
2572
|
import { StyleSheet as StyleSheet6, Text, View as View6 } from "react-native";
|
|
2267
2573
|
import { Appbar, ProgressBar, Surface, useTheme as useTheme3 } from "react-native-paper";
|
|
2268
|
-
import
|
|
2574
|
+
import Animated6, { useAnimatedStyle as useAnimatedStyle5 } from "react-native-reanimated";
|
|
2269
2575
|
import { useSafeAreaInsets as useSafeAreaInsets4 } from "react-native-safe-area-context";
|
|
2270
|
-
import { Fragment as
|
|
2576
|
+
import { Fragment as Fragment4, jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
2271
2577
|
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 }) });
|
|
2272
2578
|
var ScrollViewHeader = ({ actionSize = 48, actionStyle, backAction, backActionFixed, caption, centerContent, children, iconSize, style, title, topInset = true, trailingAction, trailingActionFixed = true }) => {
|
|
2273
|
-
const { blur, headerHeight, headerFixed, headerOffset, progress, progressing, pullSearchHeightShared, scrollPosition, setHeaderHeight, snapBackHeaderShared } =
|
|
2274
|
-
const { settings } =
|
|
2579
|
+
const { blur, headerHeight, headerFixed, headerOffset, progress, progressing, pullSearchHeightShared, scrollPosition, setHeaderHeight, snapBackHeaderShared } = useContext11(ScrollViewContext);
|
|
2580
|
+
const { settings } = useContext11(ScrollViewSettingsContext);
|
|
2275
2581
|
const effectiveBackActionFixed = backActionFixed ?? settings.backActionFixed;
|
|
2276
2582
|
const insets = useSafeAreaInsets4();
|
|
2277
2583
|
const theme = useTheme3();
|
|
@@ -2286,20 +2592,22 @@ var ScrollViewHeader = ({ actionSize = 48, actionStyle, backAction, backActionFi
|
|
|
2286
2592
|
const translateStyle = useAnimatedStyle5(() => {
|
|
2287
2593
|
if (headerFixed) return { transform: [{ translateY: 0 }] };
|
|
2288
2594
|
if (snapBackHeaderShared.value) return { transform: [{ translateY: headerOffset.value }] };
|
|
2289
|
-
const effective = scrollPosition.value + headerHeight - pullSearchHeightShared.value;
|
|
2595
|
+
const effective = scrollPosition.value + (headerHeight ?? 0) - pullSearchHeightShared.value;
|
|
2290
2596
|
if (effective <= 0) return { transform: [{ translateY: 0 }] };
|
|
2291
2597
|
return { transform: [{ translateY: -effective }] };
|
|
2292
2598
|
}, [headerFixed, headerHeight]);
|
|
2293
2599
|
const blurStyle = useAnimatedStyle5(() => {
|
|
2294
2600
|
if (!headerHeight) return { height: 0 };
|
|
2295
2601
|
if (headerFixed) return { height: headerHeight };
|
|
2296
|
-
const
|
|
2297
|
-
|
|
2602
|
+
const h = headerHeight ?? 0;
|
|
2603
|
+
const translateY = snapBackHeaderShared.value ? headerOffset.value : -Math.max(0, scrollPosition.value + h - pullSearchHeightShared.value);
|
|
2604
|
+
return { height: Math.max(h + translateY, top) };
|
|
2298
2605
|
}, [headerFixed, headerHeight, top]);
|
|
2299
2606
|
const progressStyle = useAnimatedStyle5(() => {
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2607
|
+
const h = headerHeight ?? 0;
|
|
2608
|
+
if (headerFixed) return { top: h };
|
|
2609
|
+
const slide = snapBackHeaderShared.value ? -headerOffset.value : Math.max(0, scrollPosition.value + h - pullSearchHeightShared.value);
|
|
2610
|
+
return { top: Math.max(h - slide, top) };
|
|
2303
2611
|
}, [headerFixed, headerHeight, top]);
|
|
2304
2612
|
const actionMargin = 4;
|
|
2305
2613
|
const contentMinHeight = actionSize + 2 * actionMargin;
|
|
@@ -2308,32 +2616,31 @@ var ScrollViewHeader = ({ actionSize = 48, actionStyle, backAction, backActionFi
|
|
|
2308
2616
|
const actionShadow = { borderRadius: actionSize / 2, elevation: 2, shadowColor: "#000", shadowOffset: { width: 0, height: 1 }, shadowOpacity: 0.15, shadowRadius: 2 };
|
|
2309
2617
|
const leadingStyle = { alignItems: "center", height: actionSize, justifyContent: "center", left: actionMargin, position: "absolute", top: actionTop, width: actionSize, zIndex: 3, ...actionShadow };
|
|
2310
2618
|
const trailingStyle = { alignItems: "center", height: actionSize, justifyContent: "center", position: "absolute", right: actionMargin, top: actionTop, width: actionSize, zIndex: 3, ...actionShadow };
|
|
2311
|
-
return /* @__PURE__ */ jsxs6(
|
|
2312
|
-
/* @__PURE__ */ jsx9(
|
|
2313
|
-
/* @__PURE__ */ jsxs6(
|
|
2314
|
-
/* @__PURE__ */ jsx9(View6, { style: [{ paddingTop: top }, style], children: /* @__PURE__ */ jsxs6(View6, { style: [styles7.content, { minHeight: contentMinHeight }], children: [
|
|
2619
|
+
return /* @__PURE__ */ jsxs6(Fragment4, { children: [
|
|
2620
|
+
/* @__PURE__ */ jsx9(Animated6.View, { pointerEvents: "none", style: [styles7.blur, blurStyle], children: headerHeight !== null && headerHeight > 0 && /* @__PURE__ */ jsx9(BlurView3, { blur, style: [styles7.blurInner, { height: headerHeight }] }) }),
|
|
2621
|
+
/* @__PURE__ */ jsxs6(Animated6.View, { onLayout: handleLayout, pointerEvents: "box-none", style: [headerHeight === null ? styles7.headerInit : styles7.header, translateStyle], children: [
|
|
2622
|
+
/* @__PURE__ */ jsx9(View6, { style: [{ paddingTop: top }, style], children: children ?? /* @__PURE__ */ jsxs6(View6, { style: [styles7.content, { minHeight: contentMinHeight }], children: [
|
|
2315
2623
|
/* @__PURE__ */ jsx9(View6, { style: styles7.side }),
|
|
2316
2624
|
/* @__PURE__ */ jsx9(View6, { style: styles7.spacer }),
|
|
2317
|
-
/* @__PURE__ */ jsx9(View6, { style: styles7.
|
|
2318
|
-
(centerContent || title || caption) && /* @__PURE__ */ jsx9(View6, { style: [StyleSheet6.absoluteFill, styles7.titleContainer], pointerEvents: centerContent ? "box-none" : "none", children: centerContent ?? /* @__PURE__ */ jsxs6(Fragment3, { children: [
|
|
2625
|
+
(centerContent || title || caption) && /* @__PURE__ */ jsx9(View6, { style: [StyleSheet6.absoluteFill, styles7.titleContainer], pointerEvents: centerContent ? "box-none" : "none", children: centerContent ?? /* @__PURE__ */ jsxs6(Fragment4, { children: [
|
|
2319
2626
|
title && /* @__PURE__ */ jsx9(Text, { numberOfLines: 1, style: [styles7.title, { color: theme.colors.onSurface }], children: title }),
|
|
2320
2627
|
caption && /* @__PURE__ */ jsx9(Text, { numberOfLines: 1, style: [styles7.caption, { color: theme.colors.onSurfaceVariant }], children: caption })
|
|
2321
2628
|
] }) })
|
|
2322
2629
|
] }) }),
|
|
2323
2630
|
!blur && /* @__PURE__ */ jsx9(View6, { style: [styles7.divider, { backgroundColor: theme.colors.outlineVariant }] })
|
|
2324
2631
|
] }),
|
|
2325
|
-
/* @__PURE__ */ jsx9(
|
|
2326
|
-
backAction && (effectiveBackActionFixed ? /* @__PURE__ */ jsxs6(
|
|
2632
|
+
/* @__PURE__ */ jsx9(Animated6.View, { pointerEvents: "none", style: [styles7.progress, progressStyle], children: /* @__PURE__ */ jsx9(ProgressBar, { indeterminate: progress === null, visible: progressing, progress: progress ?? void 0 }) }),
|
|
2633
|
+
backAction && (effectiveBackActionFixed ? /* @__PURE__ */ jsxs6(Animated6.View, { style: leadingStyle, children: [
|
|
2327
2634
|
/* @__PURE__ */ jsx9(ActionBg, { blur, style: actionStyle }),
|
|
2328
2635
|
/* @__PURE__ */ jsx9(Appbar.BackAction, { onPress: backAction, size: iconSize ?? actionSize / 2, style: buttonStyle })
|
|
2329
|
-
] }) : /* @__PURE__ */ jsxs6(
|
|
2636
|
+
] }) : /* @__PURE__ */ jsxs6(Animated6.View, { style: [leadingStyle, translateStyle], children: [
|
|
2330
2637
|
/* @__PURE__ */ jsx9(ActionBg, { blur, style: actionStyle }),
|
|
2331
2638
|
/* @__PURE__ */ jsx9(Appbar.BackAction, { onPress: backAction, size: iconSize ?? actionSize / 2, style: buttonStyle })
|
|
2332
2639
|
] })),
|
|
2333
2640
|
trailingAction && (trailingActionFixed ? /* @__PURE__ */ jsxs6(View6, { style: trailingStyle, children: [
|
|
2334
2641
|
/* @__PURE__ */ jsx9(ActionBg, { blur, style: actionStyle }),
|
|
2335
2642
|
trailingAction
|
|
2336
|
-
] }) : /* @__PURE__ */ jsxs6(
|
|
2643
|
+
] }) : /* @__PURE__ */ jsxs6(Animated6.View, { style: [trailingStyle, translateStyle], children: [
|
|
2337
2644
|
/* @__PURE__ */ jsx9(ActionBg, { blur, style: actionStyle }),
|
|
2338
2645
|
trailingAction
|
|
2339
2646
|
] }))
|
|
@@ -2357,62 +2664,77 @@ var styles7 = StyleSheet6.create({
|
|
|
2357
2664
|
|
|
2358
2665
|
// src/ScrollViewProvider.tsx
|
|
2359
2666
|
import { useBlur } from "@rific/auto-paper";
|
|
2360
|
-
import { useCallback as
|
|
2667
|
+
import { useCallback as useCallback7, useContext as useContext12, useEffect as useEffect5, useMemo as useMemo5, useRef as useRef7, useState as useState5 } from "react";
|
|
2361
2668
|
import { Dimensions as Dimensions3 } from "react-native";
|
|
2362
|
-
import { useSharedValue as
|
|
2669
|
+
import { useSharedValue as useSharedValue6 } from "react-native-reanimated";
|
|
2363
2670
|
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
2364
2671
|
var ScrollViewProvider = ({ blur, children, fixed = false, footerFixed, headerFixed, snapBack, snapBackFooter, snapBackHeader, tabBarHeight = 60 }) => {
|
|
2365
|
-
const { settings } =
|
|
2672
|
+
const { settings } = useContext12(ScrollViewSettingsContext);
|
|
2366
2673
|
const effectiveBlur = useBlur(blur);
|
|
2367
2674
|
const effectiveSnapBack = snapBack ?? settings.snapBack;
|
|
2368
2675
|
const effectiveSnapBackHeader = snapBackHeader ?? settings.snapBackHeader;
|
|
2369
2676
|
const effectiveSnapBackFooter = snapBackFooter ?? settings.snapBackFooter;
|
|
2370
|
-
const [headerHeight, setHeaderHeightState] =
|
|
2371
|
-
const [footerHeight, setFooterHeightState] =
|
|
2372
|
-
const [progress, setProgress] =
|
|
2373
|
-
const [progressing, setProgressing] =
|
|
2374
|
-
const scrollPosition =
|
|
2375
|
-
const
|
|
2376
|
-
const
|
|
2377
|
-
const
|
|
2378
|
-
const
|
|
2379
|
-
const
|
|
2380
|
-
const
|
|
2381
|
-
const
|
|
2677
|
+
const [headerHeight, setHeaderHeightState] = useState5(null);
|
|
2678
|
+
const [footerHeight, setFooterHeightState] = useState5(0);
|
|
2679
|
+
const [progress, setProgress] = useState5(null);
|
|
2680
|
+
const [progressing, setProgressing] = useState5(false);
|
|
2681
|
+
const scrollPosition = useSharedValue6(0);
|
|
2682
|
+
const listGeneration = useSharedValue6(0);
|
|
2683
|
+
const jsListGeneration = useRef7(0);
|
|
2684
|
+
const headerHeightShared = useSharedValue6(0);
|
|
2685
|
+
const footerHeightShared = useSharedValue6(0);
|
|
2686
|
+
const headerOffset = useSharedValue6(0);
|
|
2687
|
+
const footerOffset = useSharedValue6(0);
|
|
2688
|
+
const pullSearchHeightShared = useSharedValue6(0);
|
|
2689
|
+
const snapBackHeaderShared = useSharedValue6(false);
|
|
2690
|
+
const snapBackFooterShared = useSharedValue6(false);
|
|
2382
2691
|
useEffect5(() => {
|
|
2383
2692
|
snapBackHeaderShared.value = effectiveSnapBackHeader ?? effectiveSnapBack;
|
|
2384
2693
|
snapBackFooterShared.value = effectiveSnapBackFooter ?? effectiveSnapBack;
|
|
2385
2694
|
}, [effectiveSnapBack, effectiveSnapBackFooter, effectiveSnapBackHeader, snapBackFooterShared, snapBackHeaderShared]);
|
|
2386
|
-
const setHeaderHeight =
|
|
2695
|
+
const setHeaderHeight = useCallback7(
|
|
2387
2696
|
(h) => {
|
|
2388
2697
|
setHeaderHeightState(h);
|
|
2389
|
-
headerHeightShared.value = h;
|
|
2698
|
+
headerHeightShared.value = h ?? 0;
|
|
2390
2699
|
},
|
|
2391
2700
|
[headerHeightShared]
|
|
2392
2701
|
);
|
|
2393
|
-
const
|
|
2702
|
+
const onListUnmount = useCallback7(() => {
|
|
2703
|
+
listGeneration.value += 1;
|
|
2704
|
+
}, [listGeneration]);
|
|
2705
|
+
const onJsListUnmount = useCallback7(() => {
|
|
2706
|
+
jsListGeneration.current += 1;
|
|
2707
|
+
}, []);
|
|
2708
|
+
useEffect5(() => {
|
|
2709
|
+
if (!__DEV__ || headerHeight !== null) return;
|
|
2710
|
+
const timeout = setTimeout(() => {
|
|
2711
|
+
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.");
|
|
2712
|
+
}, 3e3);
|
|
2713
|
+
return () => clearTimeout(timeout);
|
|
2714
|
+
}, [headerHeight]);
|
|
2715
|
+
const setFooterHeight = useCallback7(
|
|
2394
2716
|
(h) => {
|
|
2395
2717
|
setFooterHeightState(h);
|
|
2396
2718
|
footerHeightShared.value = h;
|
|
2397
2719
|
},
|
|
2398
2720
|
[footerHeightShared]
|
|
2399
2721
|
);
|
|
2400
|
-
const scrollHeight = useMemo5(() => Dimensions3.get("window").height - headerHeight - footerHeight, [headerHeight, footerHeight]);
|
|
2722
|
+
const scrollHeight = useMemo5(() => Dimensions3.get("window").height - (headerHeight ?? 0) - footerHeight, [headerHeight, footerHeight]);
|
|
2401
2723
|
const effectiveHeaderFixed = fixed || (headerFixed ?? settings.headerFixed);
|
|
2402
2724
|
const effectiveFooterFixed = fixed || (footerFixed ?? settings.footerFixed);
|
|
2403
|
-
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]);
|
|
2725
|
+
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]);
|
|
2404
2726
|
return /* @__PURE__ */ jsx10(ScrollViewContext.Provider, { value, children });
|
|
2405
2727
|
};
|
|
2406
2728
|
|
|
2407
2729
|
// src/ScrollViewSettingsProvider.tsx
|
|
2408
|
-
import { useCallback as
|
|
2730
|
+
import { useCallback as useCallback8, useMemo as useMemo6, useState as useState6 } from "react";
|
|
2409
2731
|
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
2410
|
-
var ScrollViewSettingsProvider = ({ children, onChange,
|
|
2411
|
-
const [settings, setSettings] =
|
|
2732
|
+
var ScrollViewSettingsProvider = ({ children, onChange, initialValue }) => {
|
|
2733
|
+
const [settings, setSettings] = useState6(() => ({
|
|
2412
2734
|
...defaultScrollViewSettings,
|
|
2413
|
-
...
|
|
2735
|
+
...initialValue
|
|
2414
2736
|
}));
|
|
2415
|
-
const set2 =
|
|
2737
|
+
const set2 = useCallback8(
|
|
2416
2738
|
(patch) => {
|
|
2417
2739
|
setSettings((prev) => {
|
|
2418
2740
|
const next = { ...prev, ...patch };
|
|
@@ -2427,27 +2749,27 @@ var ScrollViewSettingsProvider = ({ children, onChange, value }) => {
|
|
|
2427
2749
|
};
|
|
2428
2750
|
|
|
2429
2751
|
// src/SectionList.tsx
|
|
2430
|
-
import { memo as memo4, useCallback as
|
|
2752
|
+
import { memo as memo4, useCallback as useCallback10, useContext as useContext14, useEffect as useEffect6, useLayoutEffect as useLayoutEffect6, useMemo as useMemo7, useRef as useRef9 } from "react";
|
|
2431
2753
|
import { Dimensions as Dimensions4, SectionList as RNSectionList, View as View7 } from "react-native";
|
|
2432
2754
|
import { Gesture as Gesture4, GestureDetector as GestureDetector4 } from "react-native-gesture-handler";
|
|
2433
|
-
import
|
|
2755
|
+
import Animated7, { runOnUI as runOnUI3, useSharedValue as useSharedValue8 } from "react-native-reanimated";
|
|
2434
2756
|
|
|
2435
2757
|
// src/internal/useStickyHeaders.ts
|
|
2436
|
-
import { useCallback as
|
|
2437
|
-
import { runOnJS as runOnJS4, useAnimatedReaction as useAnimatedReaction2, useAnimatedStyle as useAnimatedStyle6, useSharedValue as
|
|
2758
|
+
import { useCallback as useCallback9, useContext as useContext13, useLayoutEffect as useLayoutEffect5, useRef as useRef8, useState as useState7 } from "react";
|
|
2759
|
+
import { runOnJS as runOnJS4, useAnimatedReaction as useAnimatedReaction2, useAnimatedStyle as useAnimatedStyle6, useSharedValue as useSharedValue7 } from "react-native-reanimated";
|
|
2438
2760
|
import { useSafeAreaInsets as useSafeAreaInsets5 } from "react-native-safe-area-context";
|
|
2439
2761
|
function useStickyHeaders(headerFixed, enabled) {
|
|
2440
|
-
const { headerHeightShared, headerOffset, pullSearchHeightShared, scrollPosition, snapBackHeaderShared } =
|
|
2762
|
+
const { headerHeightShared, headerOffset, pullSearchHeightShared, scrollPosition, snapBackHeaderShared } = useContext13(ScrollViewContext);
|
|
2441
2763
|
const insetsTop = useSafeAreaInsets5().top;
|
|
2442
|
-
const sectionYPositions =
|
|
2443
|
-
const sectionHeights =
|
|
2444
|
-
const [activeIndex, setActiveIndex] =
|
|
2445
|
-
const contentIndexShared =
|
|
2446
|
-
|
|
2764
|
+
const sectionYPositions = useSharedValue7([]);
|
|
2765
|
+
const sectionHeights = useSharedValue7([]);
|
|
2766
|
+
const [activeIndex, setActiveIndex] = useState7(-1);
|
|
2767
|
+
const contentIndexShared = useSharedValue7(-1);
|
|
2768
|
+
useLayoutEffect5(() => {
|
|
2447
2769
|
contentIndexShared.value = activeIndex;
|
|
2448
2770
|
}, [activeIndex, contentIndexShared]);
|
|
2449
|
-
const positionsCache =
|
|
2450
|
-
const heightsCache =
|
|
2771
|
+
const positionsCache = useRef8([]);
|
|
2772
|
+
const heightsCache = useRef8([]);
|
|
2451
2773
|
useAnimatedReaction2(
|
|
2452
2774
|
() => {
|
|
2453
2775
|
if (!enabled) return -1;
|
|
@@ -2519,7 +2841,7 @@ function useStickyHeaders(headerFixed, enabled) {
|
|
|
2519
2841
|
}
|
|
2520
2842
|
return { opacity: 1, top: 0, transform: [{ translateY }] };
|
|
2521
2843
|
}, [enabled, headerFixed, insetsTop]);
|
|
2522
|
-
const measureHeader =
|
|
2844
|
+
const measureHeader = useCallback9(
|
|
2523
2845
|
(index, pageY, height) => {
|
|
2524
2846
|
const contentY = pageY + scrollPosition.value;
|
|
2525
2847
|
positionsCache.current[index] = contentY;
|
|
@@ -2529,7 +2851,7 @@ function useStickyHeaders(headerFixed, enabled) {
|
|
|
2529
2851
|
},
|
|
2530
2852
|
[scrollPosition, sectionHeights, sectionYPositions]
|
|
2531
2853
|
);
|
|
2532
|
-
const resetPositions =
|
|
2854
|
+
const resetPositions = useCallback9(
|
|
2533
2855
|
(count) => {
|
|
2534
2856
|
positionsCache.current = Array.from({ length: count }, () => -1);
|
|
2535
2857
|
sectionYPositions.value = positionsCache.current.slice();
|
|
@@ -2542,18 +2864,27 @@ function useStickyHeaders(headerFixed, enabled) {
|
|
|
2542
2864
|
}
|
|
2543
2865
|
|
|
2544
2866
|
// src/SectionList.tsx
|
|
2545
|
-
import { Fragment as
|
|
2546
|
-
var AnimatedSectionList = createAnimatedComponent(RNSectionList);
|
|
2547
|
-
var SectionListInner = ({ contentContainerStyle: externalContentContainerStyle, initialNumToRender = 20, maxToRenderPerBatch = 50, renderFilters, footerFixed: footerFixedProp, gesture, headerFixed: headerFixedProp, keyboardAware, ListHeaderComponent: externalListHeaderComponent, onMomentumScrollEnd: externalMomentumScrollEnd, onRefresh, onContentSizeChange, onScrollBeginDrag: externalScrollBeginDrag, onScrollEndDrag: externalScrollEndDrag, pullSearchHeight, refreshing, removeClippedSubviews = false, sections, showsVerticalScrollIndicator, style, ref: externalRef, windowSize = 100, ...props }) => {
|
|
2548
|
-
const scrollView =
|
|
2867
|
+
import { Fragment as Fragment5, jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
2868
|
+
var AnimatedSectionList = Animated7.createAnimatedComponent(RNSectionList);
|
|
2869
|
+
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 }) => {
|
|
2870
|
+
const scrollView = useRef9(null);
|
|
2549
2871
|
const { stickySectionHeadersEnabled = true, renderSectionHeader, ...passThroughProps } = props;
|
|
2550
2872
|
const { chipHidden, chipStyle, containerStyle, contentInset, contentOffset, footerFixed, headerFixed, headerHeight } = useScrollList({ footerFixed: footerFixedProp, headerFixed: headerFixedProp, keyboardAware, pullSearchHeight, style });
|
|
2873
|
+
const { listGeneration, onListUnmount } = useContext14(ScrollViewContext);
|
|
2874
|
+
const capturedGeneration = useSharedValue8(-1);
|
|
2875
|
+
useLayoutEffect6(() => {
|
|
2876
|
+
const generation = listGeneration.value;
|
|
2877
|
+
runOnUI3((gen) => {
|
|
2878
|
+
"worklet";
|
|
2879
|
+
capturedGeneration.value = gen;
|
|
2880
|
+
})(generation);
|
|
2881
|
+
}, [capturedGeneration, listGeneration]);
|
|
2551
2882
|
const usesCustomSticky = stickySectionHeadersEnabled && renderSectionHeader != null;
|
|
2552
2883
|
const { activeIndex, clipStyle, measureHeader, overlayStyle, resetPositions } = useStickyHeaders(headerFixed, usesCustomSticky);
|
|
2553
|
-
|
|
2884
|
+
useLayoutEffect6(() => {
|
|
2554
2885
|
if (usesCustomSticky) resetPositions(sections.length);
|
|
2555
2886
|
}, [sections, usesCustomSticky, resetPositions, headerHeight]);
|
|
2556
|
-
const sectionViewRefs =
|
|
2887
|
+
const sectionViewRefs = useRef9(/* @__PURE__ */ new Map());
|
|
2557
2888
|
const wrappedRenderSectionHeader = useMemo7(() => {
|
|
2558
2889
|
if (!usesCustomSticky) return renderSectionHeader ?? void 0;
|
|
2559
2890
|
return (info) => {
|
|
@@ -2575,7 +2906,8 @@ var SectionListInner = ({ contentContainerStyle: externalContentContainerStyle,
|
|
|
2575
2906
|
);
|
|
2576
2907
|
};
|
|
2577
2908
|
}, [usesCustomSticky, renderSectionHeader, sections, measureHeader]);
|
|
2578
|
-
|
|
2909
|
+
useLayoutEffect6(() => () => onListUnmount(), [onListUnmount]);
|
|
2910
|
+
const scrollTo = useCallback10((offset, animated) => {
|
|
2579
2911
|
scrollView.current?.getScrollResponder()?.scrollTo({ y: offset, animated });
|
|
2580
2912
|
}, []);
|
|
2581
2913
|
const {
|
|
@@ -2596,12 +2928,12 @@ var SectionListInner = ({ contentContainerStyle: externalContentContainerStyle,
|
|
|
2596
2928
|
const activeListHeader = useMemo7(() => {
|
|
2597
2929
|
if (!renderFilters) return pullSearchHeader;
|
|
2598
2930
|
const Inner = pullSearchHeader;
|
|
2599
|
-
return () => /* @__PURE__ */ jsxs7(
|
|
2931
|
+
return () => /* @__PURE__ */ jsxs7(Fragment5, { children: [
|
|
2600
2932
|
Inner ? typeof Inner === "function" ? /* @__PURE__ */ jsx12(Inner, {}) : Inner : null,
|
|
2601
2933
|
renderFilters
|
|
2602
2934
|
] });
|
|
2603
2935
|
}, [pullSearchHeader, renderFilters]);
|
|
2604
|
-
const pullSearchSettled =
|
|
2936
|
+
const pullSearchSettled = useRef9(false);
|
|
2605
2937
|
useEffect6(() => {
|
|
2606
2938
|
if (!usesCustomSticky || activeListHeader == null || pullSearchSettled.current) return;
|
|
2607
2939
|
pullSearchSettled.current = true;
|
|
@@ -2615,16 +2947,12 @@ var SectionListInner = ({ contentContainerStyle: externalContentContainerStyle,
|
|
|
2615
2947
|
return () => cancelAnimationFrame(handle);
|
|
2616
2948
|
}, [activeListHeader, usesCustomSticky, measureHeader]);
|
|
2617
2949
|
const contentContainerStyle = useMemo7(() => [{ minHeight: Dimensions4.get("window").height - contentInset.top - contentInset.bottom + pullSearchMinHeight }, externalContentContainerStyle], [contentInset.bottom, contentInset.top, externalContentContainerStyle, pullSearchMinHeight]);
|
|
2618
|
-
const
|
|
2619
|
-
|
|
2620
|
-
scrollTo(-contentInset.top + pullSearchHeight, true);
|
|
2621
|
-
}, [contentInset.top, pullSearchHeight, scrollTo]);
|
|
2622
|
-
const handleScroll = useScrollHandler({ chipHidden, footerFixed, headerFixed, onPullSearchZoneEnter: pullSearchHeight ? onPullSearchZoneEnter : void 0 });
|
|
2623
|
-
const handleScrollToTop = useCallback9(() => {
|
|
2950
|
+
const handleScroll = useScrollHandler({ capturedGeneration, chipHidden, chipThreshold, footerFixed, headerFixed, listGeneration });
|
|
2951
|
+
const handleScrollToTop = useCallback10(() => {
|
|
2624
2952
|
const offset = pullSearchHeight ? -contentInset.top + pullSearchHeight : -contentInset.top;
|
|
2625
2953
|
scrollView.current?.getScrollResponder()?.scrollTo({ y: offset, animated: true });
|
|
2626
2954
|
}, [contentInset.top, pullSearchHeight]);
|
|
2627
|
-
const handleContentSizeChange =
|
|
2955
|
+
const handleContentSizeChange = useCallback10(
|
|
2628
2956
|
(w, h) => {
|
|
2629
2957
|
if (onContentSizeChange) onContentSizeChange(w, h);
|
|
2630
2958
|
},
|
|
@@ -2663,11 +2991,11 @@ var SectionListInner = ({ contentContainerStyle: externalContentContainerStyle,
|
|
|
2663
2991
|
stickySectionHeadersEnabled: false,
|
|
2664
2992
|
windowSize
|
|
2665
2993
|
},
|
|
2666
|
-
headerHeight > 0 ? 1 : 0
|
|
2994
|
+
headerHeight !== null && headerHeight > 0 ? 1 : 0
|
|
2667
2995
|
),
|
|
2668
2996
|
hiddenHeader && /* @__PURE__ */ jsx12(View7, { pointerEvents: "none", style: styles8.measureContainer, children: hiddenHeader }),
|
|
2669
|
-
/* @__PURE__ */ jsx12(ScrollViewChip, { onPress: handleScrollToTop, style: chipStyle }),
|
|
2670
|
-
usesCustomSticky && /* @__PURE__ */ jsx12(
|
|
2997
|
+
/* @__PURE__ */ jsx12(ScrollViewChip, { chipProps, onChipPress, onPress: handleScrollToTop, style: chipStyle }),
|
|
2998
|
+
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] }) }) })
|
|
2671
2999
|
] });
|
|
2672
3000
|
return detectorGesture ? /* @__PURE__ */ jsx12(GestureDetector4, { gesture: detectorGesture, children: content }) : content;
|
|
2673
3001
|
};
|
|
@@ -2679,15 +3007,15 @@ var styles8 = {
|
|
|
2679
3007
|
var SectionList = memo4(SectionListInner);
|
|
2680
3008
|
|
|
2681
3009
|
// src/useScrollView.ts
|
|
2682
|
-
import { useContext as
|
|
3010
|
+
import { useContext as useContext15 } from "react";
|
|
2683
3011
|
var useScrollView = () => {
|
|
2684
|
-
const { progress, progressing, scrollHeight, scrollPosition, setProgress, setProgressing } =
|
|
3012
|
+
const { progress, progressing, scrollHeight, scrollPosition, setProgress, setProgressing } = useContext15(ScrollViewContext);
|
|
2685
3013
|
return { progress, progressing, scrollHeight, scrollPosition, setProgress, setProgressing };
|
|
2686
3014
|
};
|
|
2687
3015
|
|
|
2688
3016
|
// src/useScrollViewSettings.ts
|
|
2689
|
-
import { useContext as
|
|
2690
|
-
var useScrollViewSettings = () =>
|
|
3017
|
+
import { useContext as useContext16 } from "react";
|
|
3018
|
+
var useScrollViewSettings = () => useContext16(ScrollViewSettingsContext);
|
|
2691
3019
|
export {
|
|
2692
3020
|
CustomList,
|
|
2693
3021
|
FlatList,
|