@rific/scroll-view 0.6.3 → 0.6.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1072,11 +1072,13 @@ var ScrollViewFooter = ({ children, style }) => {
1072
1072
  const { blur, footerAboveKeyboard, footerHeight, footerFixed, footerOffset, headerHeightShared, pullSearchHeightShared, scrollPosition, setFooterHeight, snapBackFooterShared, tabBarHeight } = (0, import_react13.useContext)(ScrollViewContext);
1073
1073
  const insets = (0, import_react_native_safe_area_context3.useSafeAreaInsets)();
1074
1074
  const keyboardHeight = useKeyboardInset();
1075
+ const setFooterHeightRef = (0, import_react13.useRef)(setFooterHeight);
1076
+ setFooterHeightRef.current = setFooterHeight;
1075
1077
  (0, import_react13.useEffect)(
1076
1078
  () => () => {
1077
- setFooterHeight(null);
1079
+ setFooterHeightRef.current(null);
1078
1080
  },
1079
- [setFooterHeight]
1081
+ []
1080
1082
  );
1081
1083
  const handleLayout = ({
1082
1084
  nativeEvent: {
@@ -1094,9 +1096,10 @@ var ScrollViewFooter = ({ children, style }) => {
1094
1096
  }, [footerHeight, footerFixed, headerHeightShared, pullSearchHeightShared, scrollPosition, snapBackFooterShared, footerOffset]);
1095
1097
  const containerPaddingBottom = footerFixed && footerAboveKeyboard ? keyboardHeight : 0;
1096
1098
  const rowPaddingBottom = footerFixed && footerAboveKeyboard ? Math.max(insets.bottom - keyboardHeight, 0) : insets.bottom;
1099
+ const { paddingBottom: consumerPaddingBottom, ...restStyle } = style ?? {};
1097
1100
  return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native_reanimated11.default.View, { onLayout: handleLayout, pointerEvents: "box-none", style: [styles6.footer, { bottom: tabBarHeight, paddingBottom: containerPaddingBottom }, footerStyle], children: [
1098
1101
  (footerHeight ?? 0) > 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_auto_paper3.BlurView, { blur, style: import_react_native11.StyleSheet.absoluteFill }),
1099
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native11.View, { style: [styles6.row, { paddingBottom: rowPaddingBottom }, style], children })
1102
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native11.View, { style: [styles6.row, restStyle, { paddingBottom: rowPaddingBottom + (typeof consumerPaddingBottom === "number" ? consumerPaddingBottom : 0) }], children })
1100
1103
  ] });
1101
1104
  };
1102
1105
  var styles6 = import_react_native11.StyleSheet.create({
package/dist/index.mjs CHANGED
@@ -1005,7 +1005,7 @@ var ScrollView = memo3(ScrollViewInner);
1005
1005
 
1006
1006
  // src/ScrollViewFooter.tsx
1007
1007
  import { BlurView as BlurView2 } from "@rific/auto-paper";
1008
- import { useContext as useContext10, useEffect as useEffect4 } from "react";
1008
+ import { useContext as useContext10, useEffect as useEffect4, useRef as useRef7 } from "react";
1009
1009
  import { StyleSheet as StyleSheet5, View as View5 } from "react-native";
1010
1010
  import Animated5, { useAnimatedStyle as useAnimatedStyle4 } from "react-native-reanimated";
1011
1011
  import { useSafeAreaInsets as useSafeAreaInsets3 } from "react-native-safe-area-context";
@@ -1014,11 +1014,13 @@ var ScrollViewFooter = ({ children, style }) => {
1014
1014
  const { blur, footerAboveKeyboard, footerHeight, footerFixed, footerOffset, headerHeightShared, pullSearchHeightShared, scrollPosition, setFooterHeight, snapBackFooterShared, tabBarHeight } = useContext10(ScrollViewContext);
1015
1015
  const insets = useSafeAreaInsets3();
1016
1016
  const keyboardHeight = useKeyboardInset();
1017
+ const setFooterHeightRef = useRef7(setFooterHeight);
1018
+ setFooterHeightRef.current = setFooterHeight;
1017
1019
  useEffect4(
1018
1020
  () => () => {
1019
- setFooterHeight(null);
1021
+ setFooterHeightRef.current(null);
1020
1022
  },
1021
- [setFooterHeight]
1023
+ []
1022
1024
  );
1023
1025
  const handleLayout = ({
1024
1026
  nativeEvent: {
@@ -1036,6 +1038,7 @@ var ScrollViewFooter = ({ children, style }) => {
1036
1038
  }, [footerHeight, footerFixed, headerHeightShared, pullSearchHeightShared, scrollPosition, snapBackFooterShared, footerOffset]);
1037
1039
  const containerPaddingBottom = footerFixed && footerAboveKeyboard ? keyboardHeight : 0;
1038
1040
  const rowPaddingBottom = footerFixed && footerAboveKeyboard ? Math.max(insets.bottom - keyboardHeight, 0) : insets.bottom;
1041
+ const { paddingBottom: consumerPaddingBottom, ...restStyle } = style ?? {};
1039
1042
  return (
1040
1043
  // bottom: tabBarHeight (not the styles.footer default of 0) - a consuming app's own persistent
1041
1044
  // tab bar (a fixture outside this package's header/footer concepts entirely, same as
@@ -1043,7 +1046,7 @@ var ScrollViewFooter = ({ children, style }) => {
1043
1046
  // bar has to clear it rather than rendering flush against 0 and overlapping/hiding behind it.
1044
1047
  /* @__PURE__ */ jsxs5(Animated5.View, { onLayout: handleLayout, pointerEvents: "box-none", style: [styles6.footer, { bottom: tabBarHeight, paddingBottom: containerPaddingBottom }, footerStyle], children: [
1045
1048
  (footerHeight ?? 0) > 0 && /* @__PURE__ */ jsx8(BlurView2, { blur, style: StyleSheet5.absoluteFill }),
1046
- /* @__PURE__ */ jsx8(View5, { style: [styles6.row, { paddingBottom: rowPaddingBottom }, style], children })
1049
+ /* @__PURE__ */ jsx8(View5, { style: [styles6.row, restStyle, { paddingBottom: rowPaddingBottom + (typeof consumerPaddingBottom === "number" ? consumerPaddingBottom : 0) }], children })
1047
1050
  ] })
1048
1051
  );
1049
1052
  };
@@ -1153,7 +1156,7 @@ var styles7 = StyleSheet6.create({
1153
1156
 
1154
1157
  // src/ScrollViewProvider.tsx
1155
1158
  import { useBlur } from "@rific/auto-paper";
1156
- import { useCallback as useCallback7, useContext as useContext12, useEffect as useEffect5, useMemo as useMemo5, useRef as useRef7, useState as useState5 } from "react";
1159
+ import { useCallback as useCallback7, useContext as useContext12, useEffect as useEffect5, useMemo as useMemo5, useRef as useRef8, useState as useState5 } from "react";
1157
1160
  import { Dimensions as Dimensions3 } from "react-native";
1158
1161
  import { useSharedValue as useSharedValue7 } from "react-native-reanimated";
1159
1162
  import { jsx as jsx10 } from "react/jsx-runtime";
@@ -1169,7 +1172,7 @@ var ScrollViewProvider = ({ blur, children, fixed = false, footerAboveKeyboard =
1169
1172
  const [progressing, setProgressing] = useState5(false);
1170
1173
  const scrollPosition = useSharedValue7(0);
1171
1174
  const listGeneration = useSharedValue7(0);
1172
- const jsListGeneration = useRef7(0);
1175
+ const jsListGeneration = useRef8(0);
1173
1176
  const headerHeightShared = useSharedValue7(0);
1174
1177
  const footerHeightShared = useSharedValue7(0);
1175
1178
  const headerOffset = useSharedValue7(0);
@@ -1240,13 +1243,13 @@ var ScrollViewSettingsProvider = ({ children, onChange, initialValue }) => {
1240
1243
  };
1241
1244
 
1242
1245
  // src/SectionList.tsx
1243
- import { memo as memo4, useCallback as useCallback10, useContext as useContext14, useEffect as useEffect6, useLayoutEffect as useLayoutEffect6, useMemo as useMemo7, useRef as useRef9 } from "react";
1246
+ import { memo as memo4, useCallback as useCallback10, useContext as useContext14, useEffect as useEffect6, useLayoutEffect as useLayoutEffect6, useMemo as useMemo7, useRef as useRef10 } from "react";
1244
1247
  import { Dimensions as Dimensions4, Platform as Platform5, SectionList as RNSectionList, View as View7 } from "react-native";
1245
1248
  import { Gesture as Gesture4, GestureDetector as GestureDetector4 } from "react-native-gesture-handler";
1246
1249
  import Animated7, { runOnUI as runOnUI3, useSharedValue as useSharedValue9 } from "react-native-reanimated";
1247
1250
 
1248
1251
  // src/internal/useStickyHeaders.ts
1249
- import { useCallback as useCallback9, useContext as useContext13, useLayoutEffect as useLayoutEffect5, useRef as useRef8, useState as useState7 } from "react";
1252
+ import { useCallback as useCallback9, useContext as useContext13, useLayoutEffect as useLayoutEffect5, useRef as useRef9, useState as useState7 } from "react";
1250
1253
  import { runOnJS as runOnJS4, useAnimatedReaction as useAnimatedReaction2, useAnimatedStyle as useAnimatedStyle6, useSharedValue as useSharedValue8 } from "react-native-reanimated";
1251
1254
  import { useSafeAreaInsets as useSafeAreaInsets5 } from "react-native-safe-area-context";
1252
1255
  function useStickyHeaders(headerFixed, enabled) {
@@ -1259,8 +1262,8 @@ function useStickyHeaders(headerFixed, enabled) {
1259
1262
  useLayoutEffect5(() => {
1260
1263
  contentIndexShared.value = activeIndex;
1261
1264
  }, [activeIndex, contentIndexShared]);
1262
- const positionsCache = useRef8([]);
1263
- const heightsCache = useRef8([]);
1265
+ const positionsCache = useRef9([]);
1266
+ const heightsCache = useRef9([]);
1264
1267
  useAnimatedReaction2(
1265
1268
  () => {
1266
1269
  if (!enabled) return -1;
@@ -1363,7 +1366,7 @@ function useStickyHeaders(headerFixed, enabled) {
1363
1366
  import { Fragment as Fragment5, jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
1364
1367
  var AnimatedSectionList = Animated7.createAnimatedComponent(RNSectionList);
1365
1368
  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 }) => {
1366
- const scrollView = useRef9(null);
1369
+ const scrollView = useRef10(null);
1367
1370
  const { stickySectionHeadersEnabled = true, renderSectionHeader, ...passThroughProps } = props;
1368
1371
  const { chipHidden, chipStyle, containerStyle, contentInset, contentOffset, contentPadding, footerFixed, headerFixed, headerHeight } = useScrollList({ footerFixed: footerFixedProp, headerFixed: headerFixedProp, hideUntilMeasured: true, keyboardAware, pullSearchHeight, style });
1369
1372
  const { listGeneration, onListUnmount } = useContext14(ScrollViewContext);
@@ -1384,7 +1387,7 @@ var SectionListInner = ({ chipProps, chipThreshold, contentContainerStyle: exter
1384
1387
  useLayoutEffect6(() => {
1385
1388
  if (usesCustomSticky) resetPositions(sections.length);
1386
1389
  }, [sections, usesCustomSticky, resetPositions, headerHeight]);
1387
- const sectionViewRefs = useRef9(/* @__PURE__ */ new Map());
1390
+ const sectionViewRefs = useRef10(/* @__PURE__ */ new Map());
1388
1391
  const wrappedRenderSectionHeader = useMemo7(() => {
1389
1392
  if (!usesCustomSticky) return renderSectionHeader ?? void 0;
1390
1393
  return (info) => {
@@ -1433,7 +1436,7 @@ var SectionListInner = ({ chipProps, chipThreshold, contentContainerStyle: exter
1433
1436
  renderFilters
1434
1437
  ] });
1435
1438
  }, [pullSearchHeader, renderFilters]);
1436
- const pullSearchSettled = useRef9(false);
1439
+ const pullSearchSettled = useRef10(false);
1437
1440
  useEffect6(() => {
1438
1441
  if (!usesCustomSticky || activeListHeader == null || pullSearchSettled.current) return;
1439
1442
  pullSearchSettled.current = true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rific/scroll-view",
3
- "version": "0.6.3",
3
+ "version": "0.6.5",
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",
@@ -1,5 +1,5 @@
1
1
  import { BlurView } from '@rific/auto-paper'
2
- import { type ReactNode, useContext, useEffect } from 'react'
2
+ import { type ReactNode, useContext, useEffect, useRef } from 'react'
3
3
  import { type LayoutChangeEvent, StyleSheet, View, type ViewStyle } from 'react-native'
4
4
  import Animated, { useAnimatedStyle } from 'react-native-reanimated'
5
5
  import { useSafeAreaInsets } from 'react-native-safe-area-context'
@@ -16,11 +16,21 @@ export const ScrollViewFooter = ({ children, style }: ScrollViewFooterProps) =>
16
16
  const { blur, footerAboveKeyboard, footerHeight, footerFixed, footerOffset, headerHeightShared, pullSearchHeightShared, scrollPosition, setFooterHeight, snapBackFooterShared, tabBarHeight } = useContext(ScrollViewContext)
17
17
  const insets = useSafeAreaInsets()
18
18
  const keyboardHeight = useKeyboardInset()
19
+ // setFooterHeight's own identity changes on every real measurement (ScrollViewProvider's
20
+ // useCallback closes over `footerHeight` itself, so setting it recreates the callback). Depending
21
+ // on it directly here re-ran this effect on every measurement too — tearing down the PREVIOUS
22
+ // closure as a "cleanup" and calling ITS setFooterHeight(null) right after the real height had
23
+ // just been set, permanently clobbering it back to null with no further layout event left to
24
+ // recover it (the DOM node's true size never changed, so onLayout never fires again). Reading
25
+ // through a ref sidesteps that: the effect itself only ever runs once, on mount/unmount, so its
26
+ // cleanup fires exactly when it's meant to (a real unmount) rather than after every measurement.
27
+ const setFooterHeightRef = useRef(setFooterHeight)
28
+ setFooterHeightRef.current = setFooterHeight
19
29
  useEffect(
20
30
  () => () => {
21
- setFooterHeight(null)
31
+ setFooterHeightRef.current(null)
22
32
  },
23
- [setFooterHeight]
33
+ []
24
34
  )
25
35
  const handleLayout = ({
26
36
  nativeEvent: {
@@ -65,6 +75,12 @@ export const ScrollViewFooter = ({ children, style }: ScrollViewFooterProps) =>
65
75
  // padding's growth cancel out exactly, so the content holds still at the safe-area line instead
66
76
  // of dropping past it and correcting back up.
67
77
  const rowPaddingBottom = footerFixed && footerAboveKeyboard ? Math.max(insets.bottom - keyboardHeight, 0) : insets.bottom
78
+ // A consumer's own `style.paddingBottom` (e.g. tightening the row's vertical rhythm to match a
79
+ // header's actionMargin) is spread after rowPaddingBottom below, so it has to be added to it
80
+ // rather than assigned after it — plain style-array merge would otherwise let it silently
81
+ // replace the safe-area clearance instead of sitting on top of it, leaving the row's real
82
+ // content (buttons, etc.) flush against the home indicator.
83
+ const { paddingBottom: consumerPaddingBottom, ...restStyle } = style ?? {}
68
84
  return (
69
85
  // bottom: tabBarHeight (not the styles.footer default of 0) - a consuming app's own persistent
70
86
  // tab bar (a fixture outside this package's header/footer concepts entirely, same as
@@ -72,7 +88,7 @@ export const ScrollViewFooter = ({ children, style }: ScrollViewFooterProps) =>
72
88
  // bar has to clear it rather than rendering flush against 0 and overlapping/hiding behind it.
73
89
  <Animated.View onLayout={handleLayout} pointerEvents='box-none' style={[styles.footer, { bottom: tabBarHeight, paddingBottom: containerPaddingBottom }, footerStyle]}>
74
90
  {(footerHeight ?? 0) > 0 && <BlurView blur={blur} style={StyleSheet.absoluteFill} />}
75
- <View style={[styles.row, { paddingBottom: rowPaddingBottom }, style]}>{children}</View>
91
+ <View style={[styles.row, restStyle, { paddingBottom: rowPaddingBottom + (typeof consumerPaddingBottom === 'number' ? consumerPaddingBottom : 0) }]}>{children}</View>
76
92
  </Animated.View>
77
93
  )
78
94
  }