@rific/scroll-view 0.6.7 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/index.d.mts +4 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +18 -7
- package/dist/index.mjs +21 -10
- package/package.json +4 -4
- package/src/CustomList.tsx +3 -2
- package/src/FlatList.tsx +3 -2
- package/src/ScrollViewHeader.tsx +3 -3
- package/src/ScrollViewProvider.tsx +20 -1
package/README.md
CHANGED
|
@@ -150,6 +150,7 @@ Drop-in for React Native's `FlatList`. Accepts all `FlatListProps<T>` plus:
|
|
|
150
150
|
| `onRefresh` | `() => Promise<void> \| void` | Enables pull-to-refresh |
|
|
151
151
|
| `pullSearchHeight` | `number` | Reserve space above content for `PullSearch` |
|
|
152
152
|
| `ref` | `RefObject<RNFlatList>` | Forward ref to the underlying list |
|
|
153
|
+
| `refreshing` | `boolean` | Controlled refreshing state |
|
|
153
154
|
| `renderFilters` | `ReactNode` | Rendered below `ListHeaderComponent`, above list items |
|
|
154
155
|
|
|
155
156
|
Performance props are user-overridable with sensible defaults:
|
|
@@ -194,6 +195,7 @@ import { CustomList } from '@rific/scroll-view'
|
|
|
194
195
|
| `keyboardAware` | `boolean` | Add keyboard height to bottom content inset |
|
|
195
196
|
| `onRefresh` | `() => Promise<void> \| void` | Enables pull-to-refresh |
|
|
196
197
|
| `pullSearchHeight` | `number` | Reserve space above content for `PullSearch` |
|
|
198
|
+
| `refreshing` | `boolean` | Controlled refreshing state |
|
|
197
199
|
| `renderFilters` | `ReactNode` | Rendered below `ListHeaderComponent`, above list items |
|
|
198
200
|
| `scrollRef` | `RefObject<{ scrollToOffset }>` | Forward ref to the underlying list |
|
|
199
201
|
|
package/dist/index.d.mts
CHANGED
|
@@ -31,10 +31,11 @@ type CustomListProps<P extends object> = Omit<P, 'contentInset' | 'contentOffset
|
|
|
31
31
|
onScrollBeginDrag?: (e: NativeSyntheticEvent<NativeScrollEvent>) => void;
|
|
32
32
|
onScrollEndDrag?: (e: NativeSyntheticEvent<NativeScrollEvent>) => void;
|
|
33
33
|
pullSearchHeight?: number;
|
|
34
|
+
refreshing?: boolean;
|
|
34
35
|
scrollRef?: RefObject<ScrollToOffsetRef | null>;
|
|
35
36
|
style?: StyleProp<ViewStyle>;
|
|
36
37
|
};
|
|
37
|
-
declare const CustomListInner: <P extends object>({ chipProps, chipThreshold, component: List, renderFilters, footerFixed: footerFixedProp, gesture, headerFixed: headerFixedProp, keyboardAware, onChipPress, onMomentumScrollEnd: externalMomentumScrollEnd, onRefresh, onScrollBeginDrag: externalScrollBeginDrag, onScrollEndDrag: externalScrollEndDrag, pullSearchHeight, scrollRef, style, ...props }: CustomListProps<P>) => react.JSX.Element;
|
|
38
|
+
declare const CustomListInner: <P extends object>({ chipProps, chipThreshold, component: List, renderFilters, footerFixed: footerFixedProp, gesture, headerFixed: headerFixedProp, keyboardAware, onChipPress, onMomentumScrollEnd: externalMomentumScrollEnd, onRefresh, onScrollBeginDrag: externalScrollBeginDrag, onScrollEndDrag: externalScrollEndDrag, pullSearchHeight, refreshing, scrollRef, style, ...props }: CustomListProps<P>) => react.JSX.Element;
|
|
38
39
|
declare const CustomList: typeof CustomListInner;
|
|
39
40
|
|
|
40
41
|
type FlatListProps<T> = Omit<FlatListProps$1<T>, 'onRefresh' | 'refreshing'> & {
|
|
@@ -52,8 +53,9 @@ type FlatListProps<T> = Omit<FlatListProps$1<T>, 'onRefresh' | 'refreshing'> & {
|
|
|
52
53
|
onScrollEndDrag?: (e: NativeSyntheticEvent<NativeScrollEvent>) => void;
|
|
53
54
|
pullSearchHeight?: number;
|
|
54
55
|
ref?: RefObject<FlatList$1 | null>;
|
|
56
|
+
refreshing?: boolean;
|
|
55
57
|
};
|
|
56
|
-
declare const FlatListInner: <T>({ chipProps, chipThreshold, columnWrapperStyle, contentContainerStyle: externalContentContainerStyle, data, initialNumToRender, keyExtractor, maxToRenderPerBatch, numColumns, renderFilters, renderItem, footerFixed: footerFixedProp, gesture, headerFixed: headerFixedProp, horizontal, keyboardAware, ListHeaderComponent: externalListHeaderComponent, onChipPress, onMomentumScrollEnd: externalMomentumScrollEnd, onRefresh, onScrollBeginDrag: externalScrollBeginDrag, onScrollEndDrag: externalScrollEndDrag, pagingEnabled, pullSearchHeight, removeClippedSubviews, showsHorizontalScrollIndicator, showsVerticalScrollIndicator, style, onContentSizeChange, ref: externalRef, windowSize, ...props }: FlatListProps<T>) => react.JSX.Element;
|
|
58
|
+
declare const FlatListInner: <T>({ chipProps, chipThreshold, columnWrapperStyle, contentContainerStyle: externalContentContainerStyle, data, initialNumToRender, keyExtractor, maxToRenderPerBatch, numColumns, renderFilters, renderItem, footerFixed: footerFixedProp, gesture, headerFixed: headerFixedProp, horizontal, keyboardAware, ListHeaderComponent: externalListHeaderComponent, onChipPress, onMomentumScrollEnd: externalMomentumScrollEnd, onRefresh, onScrollBeginDrag: externalScrollBeginDrag, onScrollEndDrag: externalScrollEndDrag, pagingEnabled, pullSearchHeight, refreshing, removeClippedSubviews, showsHorizontalScrollIndicator, showsVerticalScrollIndicator, style, onContentSizeChange, ref: externalRef, windowSize, ...props }: FlatListProps<T>) => react.JSX.Element;
|
|
57
59
|
declare const FlatList: typeof FlatListInner;
|
|
58
60
|
|
|
59
61
|
type PullSearchHandle = {
|
package/dist/index.d.ts
CHANGED
|
@@ -31,10 +31,11 @@ type CustomListProps<P extends object> = Omit<P, 'contentInset' | 'contentOffset
|
|
|
31
31
|
onScrollBeginDrag?: (e: NativeSyntheticEvent<NativeScrollEvent>) => void;
|
|
32
32
|
onScrollEndDrag?: (e: NativeSyntheticEvent<NativeScrollEvent>) => void;
|
|
33
33
|
pullSearchHeight?: number;
|
|
34
|
+
refreshing?: boolean;
|
|
34
35
|
scrollRef?: RefObject<ScrollToOffsetRef | null>;
|
|
35
36
|
style?: StyleProp<ViewStyle>;
|
|
36
37
|
};
|
|
37
|
-
declare const CustomListInner: <P extends object>({ chipProps, chipThreshold, component: List, renderFilters, footerFixed: footerFixedProp, gesture, headerFixed: headerFixedProp, keyboardAware, onChipPress, onMomentumScrollEnd: externalMomentumScrollEnd, onRefresh, onScrollBeginDrag: externalScrollBeginDrag, onScrollEndDrag: externalScrollEndDrag, pullSearchHeight, scrollRef, style, ...props }: CustomListProps<P>) => react.JSX.Element;
|
|
38
|
+
declare const CustomListInner: <P extends object>({ chipProps, chipThreshold, component: List, renderFilters, footerFixed: footerFixedProp, gesture, headerFixed: headerFixedProp, keyboardAware, onChipPress, onMomentumScrollEnd: externalMomentumScrollEnd, onRefresh, onScrollBeginDrag: externalScrollBeginDrag, onScrollEndDrag: externalScrollEndDrag, pullSearchHeight, refreshing, scrollRef, style, ...props }: CustomListProps<P>) => react.JSX.Element;
|
|
38
39
|
declare const CustomList: typeof CustomListInner;
|
|
39
40
|
|
|
40
41
|
type FlatListProps<T> = Omit<FlatListProps$1<T>, 'onRefresh' | 'refreshing'> & {
|
|
@@ -52,8 +53,9 @@ type FlatListProps<T> = Omit<FlatListProps$1<T>, 'onRefresh' | 'refreshing'> & {
|
|
|
52
53
|
onScrollEndDrag?: (e: NativeSyntheticEvent<NativeScrollEvent>) => void;
|
|
53
54
|
pullSearchHeight?: number;
|
|
54
55
|
ref?: RefObject<FlatList$1 | null>;
|
|
56
|
+
refreshing?: boolean;
|
|
55
57
|
};
|
|
56
|
-
declare const FlatListInner: <T>({ chipProps, chipThreshold, columnWrapperStyle, contentContainerStyle: externalContentContainerStyle, data, initialNumToRender, keyExtractor, maxToRenderPerBatch, numColumns, renderFilters, renderItem, footerFixed: footerFixedProp, gesture, headerFixed: headerFixedProp, horizontal, keyboardAware, ListHeaderComponent: externalListHeaderComponent, onChipPress, onMomentumScrollEnd: externalMomentumScrollEnd, onRefresh, onScrollBeginDrag: externalScrollBeginDrag, onScrollEndDrag: externalScrollEndDrag, pagingEnabled, pullSearchHeight, removeClippedSubviews, showsHorizontalScrollIndicator, showsVerticalScrollIndicator, style, onContentSizeChange, ref: externalRef, windowSize, ...props }: FlatListProps<T>) => react.JSX.Element;
|
|
58
|
+
declare const FlatListInner: <T>({ chipProps, chipThreshold, columnWrapperStyle, contentContainerStyle: externalContentContainerStyle, data, initialNumToRender, keyExtractor, maxToRenderPerBatch, numColumns, renderFilters, renderItem, footerFixed: footerFixedProp, gesture, headerFixed: headerFixedProp, horizontal, keyboardAware, ListHeaderComponent: externalListHeaderComponent, onChipPress, onMomentumScrollEnd: externalMomentumScrollEnd, onRefresh, onScrollBeginDrag: externalScrollBeginDrag, onScrollEndDrag: externalScrollEndDrag, pagingEnabled, pullSearchHeight, refreshing, removeClippedSubviews, showsHorizontalScrollIndicator, showsVerticalScrollIndicator, style, onContentSizeChange, ref: externalRef, windowSize, ...props }: FlatListProps<T>) => react.JSX.Element;
|
|
57
59
|
declare const FlatList: typeof FlatListInner;
|
|
58
60
|
|
|
59
61
|
type PullSearchHandle = {
|
package/dist/index.js
CHANGED
|
@@ -474,7 +474,7 @@ function useScrollList({ footerFixed: footerFixedProp, headerFixed: headerFixedP
|
|
|
474
474
|
|
|
475
475
|
// src/CustomList.tsx
|
|
476
476
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
477
|
-
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 }) => {
|
|
477
|
+
var CustomListInner = ({ chipProps, chipThreshold, component: List, renderFilters, footerFixed: footerFixedProp, gesture, headerFixed: headerFixedProp, keyboardAware, onChipPress, onMomentumScrollEnd: externalMomentumScrollEnd, onRefresh, onScrollBeginDrag: externalScrollBeginDrag, onScrollEndDrag: externalScrollEndDrag, pullSearchHeight, refreshing, scrollRef, style, ...props }) => {
|
|
478
478
|
const { ListHeaderComponent: listHeaderComponent, contentContainerStyle: externalContentContainerStyle, ...restProps } = props;
|
|
479
479
|
const { chipHidden, chipStyle, containerStyle, contentInset, contentOffset, contentPadding, footerFixed, headerFixed } = useScrollList({ footerFixed: footerFixedProp, headerFixed: headerFixedProp, keyboardAware, pullSearchHeight, style });
|
|
480
480
|
const { listGeneration, onListUnmount } = (0, import_react6.useContext)(ScrollViewContext);
|
|
@@ -535,7 +535,7 @@ var CustomListInner = ({ chipProps, chipThreshold, component: List, renderFilter
|
|
|
535
535
|
const offset = pullSearchHeight ? -contentInset.top + pullSearchHeight : -contentInset.top;
|
|
536
536
|
scrollViewInternal.current?.scrollToOffset({ offset, animated: true });
|
|
537
537
|
}, [contentInset.top, pullSearchHeight]);
|
|
538
|
-
const refreshControl = (0, import_react6.useMemo)(() => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(RefreshControl, {}), []);
|
|
538
|
+
const refreshControl = (0, import_react6.useMemo)(() => onRefresh ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(RefreshControl, { onRefresh, refreshing: refreshing ?? false }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(RefreshControl, {}), [onRefresh, refreshing]);
|
|
539
539
|
const nativeGesture = (0, import_react6.useMemo)(() => import_react_native_gesture_handler.Gesture.Native(), []);
|
|
540
540
|
const combinedGesture = (0, import_react6.useMemo)(() => gesture !== void 0 ? import_react_native_gesture_handler.Gesture.Simultaneous(gesture, nativeGesture) : nativeGesture, [gesture, nativeGesture]);
|
|
541
541
|
const detectorGesture = gesture !== void 0 ? combinedGesture : void 0;
|
|
@@ -729,7 +729,7 @@ function useScrollHandlerJS({ capturedGeneration, chipHidden, chipThreshold = 10
|
|
|
729
729
|
|
|
730
730
|
// src/FlatList.tsx
|
|
731
731
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
732
|
-
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 }) => {
|
|
732
|
+
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, refreshing, removeClippedSubviews = false, showsHorizontalScrollIndicator, showsVerticalScrollIndicator, style, onContentSizeChange, ref: externalRef, windowSize = 100, ...props }) => {
|
|
733
733
|
const scrollView = (0, import_react9.useRef)(null);
|
|
734
734
|
const isHorizontal = horizontal === true;
|
|
735
735
|
const showDots = isHorizontal && pagingEnabled === true && (data?.length ?? 0) > 1;
|
|
@@ -828,7 +828,7 @@ var FlatListInner = ({ chipProps, chipThreshold, columnWrapperStyle, contentCont
|
|
|
828
828
|
},
|
|
829
829
|
[onContentSizeChange]
|
|
830
830
|
);
|
|
831
|
-
const refreshControl = (0, import_react9.useMemo)(() => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(RefreshControl, {}), []);
|
|
831
|
+
const refreshControl = (0, import_react9.useMemo)(() => onRefresh ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(RefreshControl, { onRefresh, refreshing: refreshing ?? false }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(RefreshControl, {}), [onRefresh, refreshing]);
|
|
832
832
|
const nativeGesture = (0, import_react9.useMemo)(() => import_react_native_gesture_handler2.Gesture.Native(), []);
|
|
833
833
|
const combinedGesture = (0, import_react9.useMemo)(() => gesture !== void 0 ? import_react_native_gesture_handler2.Gesture.Simultaneous(gesture, nativeGesture) : nativeGesture, [gesture, nativeGesture]);
|
|
834
834
|
const detectorGesture = gesture !== void 0 ? combinedGesture : void 0;
|
|
@@ -1193,11 +1193,11 @@ var ScrollViewHeader = ({ actionSize = 48, actionStyle, backAction, backActionAc
|
|
|
1193
1193
|
};
|
|
1194
1194
|
var styles7 = import_react_native12.StyleSheet.create({
|
|
1195
1195
|
actionBg: { borderRadius: 100, overflow: "hidden" },
|
|
1196
|
-
divider: { bottom: 0, height: import_react_native12.StyleSheet.hairlineWidth, left: 0, position: "absolute", right: 0 },
|
|
1197
|
-
caption: { fontSize: 12, fontWeight: "400", textAlign: "center" },
|
|
1198
|
-
content: { alignItems: "center", flexDirection: "row", width: "100%" },
|
|
1199
1196
|
blur: { left: 0, overflow: "hidden", position: "absolute", right: 0, top: 0, zIndex: 2 },
|
|
1200
1197
|
blurInner: { left: 0, position: "absolute", right: 0, top: 0 },
|
|
1198
|
+
caption: { fontSize: 12, fontWeight: "400", textAlign: "center" },
|
|
1199
|
+
content: { alignItems: "center", flexDirection: "row", width: "100%" },
|
|
1200
|
+
divider: { bottom: 0, height: import_react_native12.StyleSheet.hairlineWidth, left: 0, position: "absolute", right: 0 },
|
|
1201
1201
|
header: { left: 0, overflow: "hidden", position: "absolute", right: 0, top: 0, zIndex: 2 },
|
|
1202
1202
|
headerInit: { left: 0, overflow: "hidden", right: 0, zIndex: 2 },
|
|
1203
1203
|
progress: { left: 0, position: "absolute", right: 0, zIndex: 3 },
|
|
@@ -1258,6 +1258,17 @@ var ScrollViewProvider = ({ blur, children, fixed = false, footerAboveKeyboard =
|
|
|
1258
1258
|
}, 3e3);
|
|
1259
1259
|
return () => clearTimeout(timeout);
|
|
1260
1260
|
}, [headerHeight]);
|
|
1261
|
+
(0, import_react15.useEffect)(() => {
|
|
1262
|
+
if (import_react_native13.Platform.OS !== "web" || headerHeight !== null) return;
|
|
1263
|
+
let raf2 = 0;
|
|
1264
|
+
const raf1 = requestAnimationFrame(() => {
|
|
1265
|
+
raf2 = requestAnimationFrame(() => setHeaderHeight(0));
|
|
1266
|
+
});
|
|
1267
|
+
return () => {
|
|
1268
|
+
cancelAnimationFrame(raf1);
|
|
1269
|
+
cancelAnimationFrame(raf2);
|
|
1270
|
+
};
|
|
1271
|
+
}, [headerHeight, setHeaderHeight]);
|
|
1261
1272
|
const setFooterHeight = (0, import_react15.useCallback)(
|
|
1262
1273
|
(h) => {
|
|
1263
1274
|
if (h === 0 && footerHeight) return;
|
package/dist/index.mjs
CHANGED
|
@@ -422,7 +422,7 @@ function useScrollList({ footerFixed: footerFixedProp, headerFixed: headerFixedP
|
|
|
422
422
|
|
|
423
423
|
// src/CustomList.tsx
|
|
424
424
|
import { Fragment, jsx as jsx3, jsxs } from "react/jsx-runtime";
|
|
425
|
-
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 }) => {
|
|
425
|
+
var CustomListInner = ({ chipProps, chipThreshold, component: List, renderFilters, footerFixed: footerFixedProp, gesture, headerFixed: headerFixedProp, keyboardAware, onChipPress, onMomentumScrollEnd: externalMomentumScrollEnd, onRefresh, onScrollBeginDrag: externalScrollBeginDrag, onScrollEndDrag: externalScrollEndDrag, pullSearchHeight, refreshing, scrollRef, style, ...props }) => {
|
|
426
426
|
const { ListHeaderComponent: listHeaderComponent, contentContainerStyle: externalContentContainerStyle, ...restProps } = props;
|
|
427
427
|
const { chipHidden, chipStyle, containerStyle, contentInset, contentOffset, contentPadding, footerFixed, headerFixed } = useScrollList({ footerFixed: footerFixedProp, headerFixed: headerFixedProp, keyboardAware, pullSearchHeight, style });
|
|
428
428
|
const { listGeneration, onListUnmount } = useContext4(ScrollViewContext);
|
|
@@ -483,7 +483,7 @@ var CustomListInner = ({ chipProps, chipThreshold, component: List, renderFilter
|
|
|
483
483
|
const offset = pullSearchHeight ? -contentInset.top + pullSearchHeight : -contentInset.top;
|
|
484
484
|
scrollViewInternal.current?.scrollToOffset({ offset, animated: true });
|
|
485
485
|
}, [contentInset.top, pullSearchHeight]);
|
|
486
|
-
const refreshControl = useMemo2(() => /* @__PURE__ */ jsx3(RefreshControl, {}), []);
|
|
486
|
+
const refreshControl = useMemo2(() => onRefresh ? /* @__PURE__ */ jsx3(RefreshControl, { onRefresh, refreshing: refreshing ?? false }) : /* @__PURE__ */ jsx3(RefreshControl, {}), [onRefresh, refreshing]);
|
|
487
487
|
const nativeGesture = useMemo2(() => Gesture.Native(), []);
|
|
488
488
|
const combinedGesture = useMemo2(() => gesture !== void 0 ? Gesture.Simultaneous(gesture, nativeGesture) : nativeGesture, [gesture, nativeGesture]);
|
|
489
489
|
const detectorGesture = gesture !== void 0 ? combinedGesture : void 0;
|
|
@@ -677,7 +677,7 @@ function useScrollHandlerJS({ capturedGeneration, chipHidden, chipThreshold = 10
|
|
|
677
677
|
|
|
678
678
|
// src/FlatList.tsx
|
|
679
679
|
import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
680
|
-
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 }) => {
|
|
680
|
+
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, refreshing, removeClippedSubviews = false, showsHorizontalScrollIndicator, showsVerticalScrollIndicator, style, onContentSizeChange, ref: externalRef, windowSize = 100, ...props }) => {
|
|
681
681
|
const scrollView = useRef4(null);
|
|
682
682
|
const isHorizontal = horizontal === true;
|
|
683
683
|
const showDots = isHorizontal && pagingEnabled === true && (data?.length ?? 0) > 1;
|
|
@@ -776,7 +776,7 @@ var FlatListInner = ({ chipProps, chipThreshold, columnWrapperStyle, contentCont
|
|
|
776
776
|
},
|
|
777
777
|
[onContentSizeChange]
|
|
778
778
|
);
|
|
779
|
-
const refreshControl = useMemo3(() => /* @__PURE__ */ jsx5(RefreshControl, {}), []);
|
|
779
|
+
const refreshControl = useMemo3(() => onRefresh ? /* @__PURE__ */ jsx5(RefreshControl, { onRefresh, refreshing: refreshing ?? false }) : /* @__PURE__ */ jsx5(RefreshControl, {}), [onRefresh, refreshing]);
|
|
780
780
|
const nativeGesture = useMemo3(() => Gesture2.Native(), []);
|
|
781
781
|
const combinedGesture = useMemo3(() => gesture !== void 0 ? Gesture2.Simultaneous(gesture, nativeGesture) : nativeGesture, [gesture, nativeGesture]);
|
|
782
782
|
const detectorGesture = gesture !== void 0 ? combinedGesture : void 0;
|
|
@@ -1141,11 +1141,11 @@ var ScrollViewHeader = ({ actionSize = 48, actionStyle, backAction, backActionAc
|
|
|
1141
1141
|
};
|
|
1142
1142
|
var styles7 = StyleSheet6.create({
|
|
1143
1143
|
actionBg: { borderRadius: 100, overflow: "hidden" },
|
|
1144
|
-
divider: { bottom: 0, height: StyleSheet6.hairlineWidth, left: 0, position: "absolute", right: 0 },
|
|
1145
|
-
caption: { fontSize: 12, fontWeight: "400", textAlign: "center" },
|
|
1146
|
-
content: { alignItems: "center", flexDirection: "row", width: "100%" },
|
|
1147
1144
|
blur: { left: 0, overflow: "hidden", position: "absolute", right: 0, top: 0, zIndex: 2 },
|
|
1148
1145
|
blurInner: { left: 0, position: "absolute", right: 0, top: 0 },
|
|
1146
|
+
caption: { fontSize: 12, fontWeight: "400", textAlign: "center" },
|
|
1147
|
+
content: { alignItems: "center", flexDirection: "row", width: "100%" },
|
|
1148
|
+
divider: { bottom: 0, height: StyleSheet6.hairlineWidth, left: 0, position: "absolute", right: 0 },
|
|
1149
1149
|
header: { left: 0, overflow: "hidden", position: "absolute", right: 0, top: 0, zIndex: 2 },
|
|
1150
1150
|
headerInit: { left: 0, overflow: "hidden", right: 0, zIndex: 2 },
|
|
1151
1151
|
progress: { left: 0, position: "absolute", right: 0, zIndex: 3 },
|
|
@@ -1158,7 +1158,7 @@ var styles7 = StyleSheet6.create({
|
|
|
1158
1158
|
// src/ScrollViewProvider.tsx
|
|
1159
1159
|
import { useBlur } from "@rific/auto-paper";
|
|
1160
1160
|
import { useCallback as useCallback7, useContext as useContext12, useEffect as useEffect5, useMemo as useMemo5, useRef as useRef8, useState as useState5 } from "react";
|
|
1161
|
-
import { Dimensions as Dimensions3 } from "react-native";
|
|
1161
|
+
import { Dimensions as Dimensions3, Platform as Platform5 } from "react-native";
|
|
1162
1162
|
import { useSharedValue as useSharedValue7 } from "react-native-reanimated";
|
|
1163
1163
|
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
1164
1164
|
var ScrollViewProvider = ({ blur, children, fixed = false, footerAboveKeyboard = false, footerFixed, headerFixed, snapBack, snapBackFooter, snapBackHeader, tabBarHeight = 0 }) => {
|
|
@@ -1206,6 +1206,17 @@ var ScrollViewProvider = ({ blur, children, fixed = false, footerAboveKeyboard =
|
|
|
1206
1206
|
}, 3e3);
|
|
1207
1207
|
return () => clearTimeout(timeout);
|
|
1208
1208
|
}, [headerHeight]);
|
|
1209
|
+
useEffect5(() => {
|
|
1210
|
+
if (Platform5.OS !== "web" || headerHeight !== null) return;
|
|
1211
|
+
let raf2 = 0;
|
|
1212
|
+
const raf1 = requestAnimationFrame(() => {
|
|
1213
|
+
raf2 = requestAnimationFrame(() => setHeaderHeight(0));
|
|
1214
|
+
});
|
|
1215
|
+
return () => {
|
|
1216
|
+
cancelAnimationFrame(raf1);
|
|
1217
|
+
cancelAnimationFrame(raf2);
|
|
1218
|
+
};
|
|
1219
|
+
}, [headerHeight, setHeaderHeight]);
|
|
1209
1220
|
const setFooterHeight = useCallback7(
|
|
1210
1221
|
(h) => {
|
|
1211
1222
|
if (h === 0 && footerHeight) return;
|
|
@@ -1245,7 +1256,7 @@ var ScrollViewSettingsProvider = ({ children, onChange, initialValue }) => {
|
|
|
1245
1256
|
|
|
1246
1257
|
// src/SectionList.tsx
|
|
1247
1258
|
import { memo as memo4, useCallback as useCallback10, useContext as useContext14, useEffect as useEffect6, useLayoutEffect as useLayoutEffect6, useMemo as useMemo7, useRef as useRef10 } from "react";
|
|
1248
|
-
import { Dimensions as Dimensions4, Platform as
|
|
1259
|
+
import { Dimensions as Dimensions4, Platform as Platform6, SectionList as RNSectionList, View as View7 } from "react-native";
|
|
1249
1260
|
import { Gesture as Gesture4, GestureDetector as GestureDetector4 } from "react-native-gesture-handler";
|
|
1250
1261
|
import Animated7, { runOnUI as runOnUI3, useSharedValue as useSharedValue9 } from "react-native-reanimated";
|
|
1251
1262
|
|
|
@@ -1374,7 +1385,7 @@ var SectionListInner = ({ chipProps, chipThreshold, contentContainerStyle: exter
|
|
|
1374
1385
|
const capturedGeneration = useSharedValue9(-1);
|
|
1375
1386
|
useLayoutEffect6(() => {
|
|
1376
1387
|
const generation = listGeneration.value;
|
|
1377
|
-
if (
|
|
1388
|
+
if (Platform6.OS === "web") {
|
|
1378
1389
|
capturedGeneration.value = generation;
|
|
1379
1390
|
return;
|
|
1380
1391
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rific/scroll-view",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"description": "Blur styled scroll system for React Native. Floating headers/footers, keyboard awareness, and scroll-away chrome",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react-native",
|
|
@@ -61,9 +61,9 @@
|
|
|
61
61
|
},
|
|
62
62
|
"prettier": "@infinitetoken/eslint-config/prettier",
|
|
63
63
|
"devDependencies": {
|
|
64
|
-
"@infinitetoken/eslint-config": "
|
|
65
|
-
"@infinitetoken/jest-config": "^0.
|
|
66
|
-
"@infinitetoken/tsconfig": "^0.
|
|
64
|
+
"@infinitetoken/eslint-config": "0.2.0",
|
|
65
|
+
"@infinitetoken/jest-config": "^0.3.0",
|
|
66
|
+
"@infinitetoken/tsconfig": "^0.4.1",
|
|
67
67
|
"@reduxjs/toolkit": "^2.12.0",
|
|
68
68
|
"@rific/auto-paper": "^0.10.3",
|
|
69
69
|
"@testing-library/dom": "^10.4.1",
|
package/src/CustomList.tsx
CHANGED
|
@@ -27,11 +27,12 @@ export type CustomListProps<P extends object> = Omit<P, 'contentInset' | 'conten
|
|
|
27
27
|
onScrollBeginDrag?: (e: NativeSyntheticEvent<NativeScrollEvent>) => void
|
|
28
28
|
onScrollEndDrag?: (e: NativeSyntheticEvent<NativeScrollEvent>) => void
|
|
29
29
|
pullSearchHeight?: number
|
|
30
|
+
refreshing?: boolean
|
|
30
31
|
scrollRef?: RefObject<ScrollToOffsetRef | null>
|
|
31
32
|
style?: StyleProp<ViewStyle>
|
|
32
33
|
}
|
|
33
34
|
|
|
34
|
-
const CustomListInner = <P extends object>({ chipProps, chipThreshold, component: List, renderFilters, footerFixed: footerFixedProp, gesture, headerFixed: headerFixedProp, keyboardAware, onChipPress, onMomentumScrollEnd: externalMomentumScrollEnd, onRefresh, onScrollBeginDrag: externalScrollBeginDrag, onScrollEndDrag: externalScrollEndDrag, pullSearchHeight, scrollRef, style, ...props }: CustomListProps<P>) => {
|
|
35
|
+
const CustomListInner = <P extends object>({ chipProps, chipThreshold, component: List, renderFilters, footerFixed: footerFixedProp, gesture, headerFixed: headerFixedProp, keyboardAware, onChipPress, onMomentumScrollEnd: externalMomentumScrollEnd, onRefresh, onScrollBeginDrag: externalScrollBeginDrag, onScrollEndDrag: externalScrollEndDrag, pullSearchHeight, refreshing, scrollRef, style, ...props }: CustomListProps<P>) => {
|
|
35
36
|
// Intercept ListHeaderComponent so useScrollInit can apply the same 2-phase measurement as FlatList.
|
|
36
37
|
const { ListHeaderComponent: listHeaderComponent, contentContainerStyle: externalContentContainerStyle, ...restProps } = props as Record<string, unknown>
|
|
37
38
|
|
|
@@ -123,7 +124,7 @@ const CustomListInner = <P extends object>({ chipProps, chipThreshold, component
|
|
|
123
124
|
scrollViewInternal.current?.scrollToOffset({ offset, animated: true })
|
|
124
125
|
}, [contentInset.top, pullSearchHeight])
|
|
125
126
|
|
|
126
|
-
const refreshControl = useMemo(() => <RefreshControl
|
|
127
|
+
const refreshControl = useMemo(() => (onRefresh ? <RefreshControl onRefresh={onRefresh} refreshing={refreshing ?? false} /> : <RefreshControl />), [onRefresh, refreshing])
|
|
127
128
|
const nativeGesture = useMemo(() => Gesture.Native(), [])
|
|
128
129
|
const combinedGesture = useMemo(() => (gesture !== undefined ? Gesture.Simultaneous(gesture, nativeGesture) : nativeGesture), [gesture, nativeGesture])
|
|
129
130
|
const detectorGesture = gesture !== undefined ? combinedGesture : undefined
|
package/src/FlatList.tsx
CHANGED
|
@@ -25,9 +25,10 @@ export type FlatListProps<T> = Omit<RNFlatListProps<T>, 'onRefresh' | 'refreshin
|
|
|
25
25
|
onScrollEndDrag?: (e: NativeSyntheticEvent<NativeScrollEvent>) => void
|
|
26
26
|
pullSearchHeight?: number
|
|
27
27
|
ref?: RefObject<RNFlatList | null>
|
|
28
|
+
refreshing?: boolean
|
|
28
29
|
}
|
|
29
30
|
|
|
30
|
-
const FlatListInner = <T,>({ 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 }: FlatListProps<T>) => {
|
|
31
|
+
const FlatListInner = <T,>({ 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, refreshing, removeClippedSubviews = false, showsHorizontalScrollIndicator, showsVerticalScrollIndicator, style, onContentSizeChange, ref: externalRef, windowSize = 100, ...props }: FlatListProps<T>) => {
|
|
31
32
|
// Plain (non-Animated) FlatList: react-native-reanimated's Animated.FlatList does not reliably
|
|
32
33
|
// honor the initial `contentOffset` prop on a key-forced remount — the header/list can briefly
|
|
33
34
|
// render at the wrong position. A plain FlatList honors it correctly, so scroll position is driven
|
|
@@ -164,7 +165,7 @@ const FlatListInner = <T,>({ chipProps, chipThreshold, columnWrapperStyle, conte
|
|
|
164
165
|
[onContentSizeChange]
|
|
165
166
|
)
|
|
166
167
|
|
|
167
|
-
const refreshControl = useMemo(() => <RefreshControl
|
|
168
|
+
const refreshControl = useMemo(() => (onRefresh ? <RefreshControl onRefresh={onRefresh} refreshing={refreshing ?? false} /> : <RefreshControl />), [onRefresh, refreshing])
|
|
168
169
|
const nativeGesture = useMemo(() => Gesture.Native(), [])
|
|
169
170
|
const combinedGesture = useMemo(() => (gesture !== undefined ? Gesture.Simultaneous(gesture, nativeGesture) : nativeGesture), [gesture, nativeGesture])
|
|
170
171
|
const detectorGesture = gesture !== undefined ? combinedGesture : undefined
|
package/src/ScrollViewHeader.tsx
CHANGED
|
@@ -180,11 +180,11 @@ export const ScrollViewHeader = ({ actionSize = 48, actionStyle, backAction, bac
|
|
|
180
180
|
|
|
181
181
|
const styles = StyleSheet.create({
|
|
182
182
|
actionBg: { borderRadius: 100, overflow: 'hidden' },
|
|
183
|
-
divider: { bottom: 0, height: StyleSheet.hairlineWidth, left: 0, position: 'absolute', right: 0 },
|
|
184
|
-
caption: { fontSize: 12, fontWeight: '400', textAlign: 'center' },
|
|
185
|
-
content: { alignItems: 'center', flexDirection: 'row', width: '100%' },
|
|
186
183
|
blur: { left: 0, overflow: 'hidden', position: 'absolute', right: 0, top: 0, zIndex: 2 },
|
|
187
184
|
blurInner: { left: 0, position: 'absolute', right: 0, top: 0 },
|
|
185
|
+
caption: { fontSize: 12, fontWeight: '400', textAlign: 'center' },
|
|
186
|
+
content: { alignItems: 'center', flexDirection: 'row', width: '100%' },
|
|
187
|
+
divider: { bottom: 0, height: StyleSheet.hairlineWidth, left: 0, position: 'absolute', right: 0 },
|
|
188
188
|
header: { left: 0, overflow: 'hidden', position: 'absolute', right: 0, top: 0, zIndex: 2 },
|
|
189
189
|
headerInit: { left: 0, overflow: 'hidden', right: 0, zIndex: 2 },
|
|
190
190
|
progress: { left: 0, position: 'absolute', right: 0, zIndex: 3 },
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useBlur } from '@rific/auto-paper'
|
|
2
2
|
import { type ReactNode, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'
|
|
3
|
-
import { Dimensions } from 'react-native'
|
|
3
|
+
import { Dimensions, Platform } from 'react-native'
|
|
4
4
|
import { useSharedValue } from 'react-native-reanimated'
|
|
5
5
|
|
|
6
6
|
import { ScrollViewContext } from './ScrollViewContext'
|
|
@@ -70,6 +70,25 @@ export const ScrollViewProvider = ({ blur, children, fixed = false, footerAboveK
|
|
|
70
70
|
}, 3000)
|
|
71
71
|
return () => clearTimeout(timeout)
|
|
72
72
|
}, [headerHeight])
|
|
73
|
+
// Web-only recovery for a real race: a header's ResizeObserver-backed onLayout can simply never
|
|
74
|
+
// fire on the very first mount through Expo Router (observed in practice, not just theorized —
|
|
75
|
+
// content stuck at opacity: 0 indefinitely, with no error, only escaping via an unrelated resize
|
|
76
|
+
// forcing a fresh layout pass). Native RN doesn't have this race — onLayout is reliable there, and
|
|
77
|
+
// a persistently-null headerHeight really does mean "no header was ever rendered," which the
|
|
78
|
+
// warning above should keep flagging. On web, give a real first layout two frames to arrive before
|
|
79
|
+
// assuming there isn't one; setHeaderHeight(0) is exactly what a genuinely header-less screen would
|
|
80
|
+
// report anyway, so this is indistinguishable from that case once it fires.
|
|
81
|
+
useEffect(() => {
|
|
82
|
+
if (Platform.OS !== 'web' || headerHeight !== null) return
|
|
83
|
+
let raf2 = 0
|
|
84
|
+
const raf1 = requestAnimationFrame(() => {
|
|
85
|
+
raf2 = requestAnimationFrame(() => setHeaderHeight(0))
|
|
86
|
+
})
|
|
87
|
+
return () => {
|
|
88
|
+
cancelAnimationFrame(raf1)
|
|
89
|
+
cancelAnimationFrame(raf2)
|
|
90
|
+
}
|
|
91
|
+
}, [headerHeight, setHeaderHeight])
|
|
73
92
|
const setFooterHeight = useCallback(
|
|
74
93
|
(h: number | null) => {
|
|
75
94
|
// Same race setHeaderHeight guards against, on the footer side: react-native-screens' web
|