@rific/scroll-view 0.6.0 → 0.6.2
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.d.mts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +52 -40
- package/dist/index.mjs +67 -55
- package/package.json +13 -11
- package/src/ScrollViewContext.ts +3 -3
- package/src/ScrollViewFooter.tsx +10 -6
- package/src/ScrollViewHeader.tsx +42 -22
- package/src/ScrollViewProvider.tsx +12 -5
- package/src/internal/ScrollViewChip.tsx +21 -3
- package/src/internal/useScrollList.ts +12 -8
package/dist/index.d.mts
CHANGED
|
@@ -6,7 +6,7 @@ import { ChipProps as ChipProps$1 } from '@rific/auto-paper';
|
|
|
6
6
|
import * as react_native_reanimated from 'react-native-reanimated';
|
|
7
7
|
import { SharedValue } from 'react-native-reanimated';
|
|
8
8
|
|
|
9
|
-
type ChipProps = Omit<ChipProps$1, 'compact' | 'icon' | 'onPress'> & {
|
|
9
|
+
type ChipProps = Omit<ChipProps$1, 'compact' | 'icon' | 'onPress' | 'children'> & {
|
|
10
10
|
label?: ReactNode;
|
|
11
11
|
};
|
|
12
12
|
|
|
@@ -122,7 +122,7 @@ declare const ScrollView: typeof ScrollViewInner;
|
|
|
122
122
|
type ScrollViewContextType = {
|
|
123
123
|
blur: boolean;
|
|
124
124
|
footerAboveKeyboard: boolean;
|
|
125
|
-
footerHeight: number;
|
|
125
|
+
footerHeight: number | null;
|
|
126
126
|
footerHeightShared: SharedValue<number>;
|
|
127
127
|
footerFixed: boolean;
|
|
128
128
|
footerOffset: SharedValue<number>;
|
|
@@ -141,7 +141,7 @@ type ScrollViewContextType = {
|
|
|
141
141
|
progressing: boolean;
|
|
142
142
|
scrollHeight: number;
|
|
143
143
|
scrollPosition: SharedValue<number>;
|
|
144
|
-
setFooterHeight: (h: number) => void;
|
|
144
|
+
setFooterHeight: (h: number | null) => void;
|
|
145
145
|
setHeaderHeight: (h: number | null) => void;
|
|
146
146
|
setProgress: (p: number | null) => void;
|
|
147
147
|
setProgressing: (b: boolean) => void;
|
|
@@ -158,7 +158,7 @@ declare const ScrollViewFooter: ({ children, style }: ScrollViewFooterProps) =>
|
|
|
158
158
|
type ScrollViewHeaderProps = {
|
|
159
159
|
actionSize?: number;
|
|
160
160
|
actionStyle?: ViewStyle;
|
|
161
|
-
backAction?: () => void;
|
|
161
|
+
backAction?: (() => void) | ReactNode;
|
|
162
162
|
backActionAccessibilityLabel?: string;
|
|
163
163
|
backActionFixed?: boolean;
|
|
164
164
|
caption?: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { ChipProps as ChipProps$1 } from '@rific/auto-paper';
|
|
|
6
6
|
import * as react_native_reanimated from 'react-native-reanimated';
|
|
7
7
|
import { SharedValue } from 'react-native-reanimated';
|
|
8
8
|
|
|
9
|
-
type ChipProps = Omit<ChipProps$1, 'compact' | 'icon' | 'onPress'> & {
|
|
9
|
+
type ChipProps = Omit<ChipProps$1, 'compact' | 'icon' | 'onPress' | 'children'> & {
|
|
10
10
|
label?: ReactNode;
|
|
11
11
|
};
|
|
12
12
|
|
|
@@ -122,7 +122,7 @@ declare const ScrollView: typeof ScrollViewInner;
|
|
|
122
122
|
type ScrollViewContextType = {
|
|
123
123
|
blur: boolean;
|
|
124
124
|
footerAboveKeyboard: boolean;
|
|
125
|
-
footerHeight: number;
|
|
125
|
+
footerHeight: number | null;
|
|
126
126
|
footerHeightShared: SharedValue<number>;
|
|
127
127
|
footerFixed: boolean;
|
|
128
128
|
footerOffset: SharedValue<number>;
|
|
@@ -141,7 +141,7 @@ type ScrollViewContextType = {
|
|
|
141
141
|
progressing: boolean;
|
|
142
142
|
scrollHeight: number;
|
|
143
143
|
scrollPosition: SharedValue<number>;
|
|
144
|
-
setFooterHeight: (h: number) => void;
|
|
144
|
+
setFooterHeight: (h: number | null) => void;
|
|
145
145
|
setHeaderHeight: (h: number | null) => void;
|
|
146
146
|
setProgress: (p: number | null) => void;
|
|
147
147
|
setProgressing: (b: boolean) => void;
|
|
@@ -158,7 +158,7 @@ declare const ScrollViewFooter: ({ children, style }: ScrollViewFooterProps) =>
|
|
|
158
158
|
type ScrollViewHeaderProps = {
|
|
159
159
|
actionSize?: number;
|
|
160
160
|
actionStyle?: ViewStyle;
|
|
161
|
-
backAction?: () => void;
|
|
161
|
+
backAction?: (() => void) | ReactNode;
|
|
162
162
|
backActionAccessibilityLabel?: string;
|
|
163
163
|
backActionFixed?: boolean;
|
|
164
164
|
caption?: string;
|
package/dist/index.js
CHANGED
|
@@ -64,15 +64,18 @@ var RefreshControl = (props) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(impo
|
|
|
64
64
|
// src/internal/ScrollViewChip.tsx
|
|
65
65
|
var import_auto_paper = require("@rific/auto-paper");
|
|
66
66
|
var import_react_native2 = require("react-native");
|
|
67
|
+
var import_react_native_paper = require("react-native-paper");
|
|
67
68
|
var import_react_native_reanimated = __toESM(require("react-native-reanimated"));
|
|
68
69
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
69
70
|
var ScrollViewChip = ({ chipProps, isHorizontal, onChipPress, onPress, style }) => {
|
|
70
|
-
const {
|
|
71
|
+
const { colors } = (0, import_react_native_paper.useTheme)();
|
|
72
|
+
const { label, selectedColor, style: chipStyle, ...restChipProps } = chipProps ?? {};
|
|
71
73
|
const handlePress = onChipPress ? () => {
|
|
72
74
|
onPress();
|
|
73
75
|
onChipPress();
|
|
74
76
|
} : onPress;
|
|
75
|
-
|
|
77
|
+
const iconColor = selectedColor ?? (restChipProps.mode === "outlined" ? colors.onSurfaceVariant : colors.onSecondaryContainer);
|
|
78
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_reanimated.default.View, { style: [styles.chip, style], children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_auto_paper.Chip, { compact: true, selectedColor, ...restChipProps, avatar: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_paper.Icon, { source: isHorizontal ? "chevron-left" : "chevron-up", size: 18, color: iconColor }), onPress: handlePress, style: [styles.chipInner, chipStyle], children: label ?? (isHorizontal ? "Start" : "Top") }) });
|
|
76
79
|
};
|
|
77
80
|
var styles = import_react_native2.StyleSheet.create({
|
|
78
81
|
chip: { alignItems: "center", left: 0, position: "absolute", right: 0, zIndex: 3 },
|
|
@@ -88,7 +91,7 @@ var import_react = require("react");
|
|
|
88
91
|
var ScrollViewContext = (0, import_react.createContext)({
|
|
89
92
|
blur: true,
|
|
90
93
|
footerAboveKeyboard: false,
|
|
91
|
-
footerHeight:
|
|
94
|
+
footerHeight: null,
|
|
92
95
|
footerHeightShared: null,
|
|
93
96
|
footerFixed: false,
|
|
94
97
|
footerOffset: null,
|
|
@@ -428,7 +431,7 @@ var CHIP_SLIDE = 48;
|
|
|
428
431
|
function useScrollList({ footerFixed: footerFixedProp, headerFixed: headerFixedProp, hideUntilMeasured, isHorizontal, keyboardAware, pullSearchHeight, style } = {}) {
|
|
429
432
|
const insets = (0, import_react_native_safe_area_context.useSafeAreaInsets)();
|
|
430
433
|
const keyboardHeight = useKeyboardInset();
|
|
431
|
-
const { footerAboveKeyboard, footerHeight, footerFixed: contextFooterFixed, headerHeight, headerFixed: contextHeaderFixed, headerOffset, pullSearchHeightShared, scrollPosition, snapBackHeaderShared, tabBarHeight } = (0, import_react5.useContext)(ScrollViewContext);
|
|
434
|
+
const { footerAboveKeyboard, footerHeight, footerFixed: contextFooterFixed, headerHeight, headerHeightShared, headerFixed: contextHeaderFixed, headerOffset, pullSearchHeightShared, scrollPosition, snapBackHeaderShared, tabBarHeight } = (0, import_react5.useContext)(ScrollViewContext);
|
|
432
435
|
const headerFixed = isHorizontal ? true : headerFixedProp ?? contextHeaderFixed;
|
|
433
436
|
const footerFixed = isHorizontal ? true : footerFixedProp ?? contextFooterFixed;
|
|
434
437
|
(0, import_react5.useEffect)(() => {
|
|
@@ -452,11 +455,11 @@ function useScrollList({ footerFixed: footerFixedProp, headerFixed: headerFixedP
|
|
|
452
455
|
return {
|
|
453
456
|
opacity: chipHidden.value ? (0, import_react_native_reanimated5.withTiming)(0) : (0, import_react_native_reanimated5.withTiming)(1),
|
|
454
457
|
pointerEvents,
|
|
455
|
-
top: Math.max(
|
|
458
|
+
top: Math.max(headerHeightShared.value, insets.top) + 4,
|
|
456
459
|
transform: [{ translateX: chipHidden.value ? (0, import_react_native_reanimated5.withTiming)(-CHIP_SLIDE) : (0, import_react_native_reanimated5.withTiming)(0) }]
|
|
457
460
|
};
|
|
458
461
|
}
|
|
459
|
-
const h =
|
|
462
|
+
const h = headerHeightShared.value;
|
|
460
463
|
const slide = headerFixed ? 0 : snapBackHeaderShared.value ? -headerOffset.value : Math.max(0, scrollPosition.value + h - pullSearchHeightShared.value);
|
|
461
464
|
const top = Math.max(h - slide, insets.top) + 4;
|
|
462
465
|
return {
|
|
@@ -465,7 +468,7 @@ function useScrollList({ footerFixed: footerFixedProp, headerFixed: headerFixedP
|
|
|
465
468
|
top,
|
|
466
469
|
transform: [{ translateY: chipHidden.value ? (0, import_react_native_reanimated5.withTiming)(-CHIP_SLIDE) : (0, import_react_native_reanimated5.withTiming)(0) }]
|
|
467
470
|
};
|
|
468
|
-
}, [isHorizontal, headerFixed,
|
|
471
|
+
}, [isHorizontal, headerFixed, headerHeightShared, insets.top, chipHidden, snapBackHeaderShared, headerOffset, scrollPosition, pullSearchHeightShared]);
|
|
469
472
|
return { chipHidden, chipStyle, containerStyle, contentInset, contentOffset, contentPadding, footerFixed, headerFixed, headerHeight, insets, isHorizontal: isHorizontal ?? false };
|
|
470
473
|
}
|
|
471
474
|
|
|
@@ -556,7 +559,7 @@ var import_react_native_gesture_handler2 = require("react-native-gesture-handler
|
|
|
556
559
|
var import_auto_paper2 = require("@rific/auto-paper");
|
|
557
560
|
var import_react7 = require("react");
|
|
558
561
|
var import_react_native7 = require("react-native");
|
|
559
|
-
var
|
|
562
|
+
var import_react_native_paper2 = require("react-native-paper");
|
|
560
563
|
var import_react_native_reanimated7 = __toESM(require("react-native-reanimated"));
|
|
561
564
|
var import_react_native_safe_area_context2 = require("react-native-safe-area-context");
|
|
562
565
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
@@ -586,7 +589,7 @@ var HorizontalDots = ({ total }) => {
|
|
|
586
589
|
const { blur, footerHeightShared, scrollPosition } = (0, import_react7.useContext)(ScrollViewContext);
|
|
587
590
|
const { width } = (0, import_react_native7.useWindowDimensions)();
|
|
588
591
|
const insets = (0, import_react_native_safe_area_context2.useSafeAreaInsets)();
|
|
589
|
-
const theme = (0,
|
|
592
|
+
const theme = (0, import_react_native_paper2.useTheme)();
|
|
590
593
|
const insetsBottom = insets.bottom;
|
|
591
594
|
const activeColor = theme.colors.primary;
|
|
592
595
|
const inactiveColor = theme.colors.outlineVariant;
|
|
@@ -880,12 +883,12 @@ var FlatList = (0, import_react9.memo)(FlatListInner);
|
|
|
880
883
|
// src/PullSearch.tsx
|
|
881
884
|
var import_react10 = require("react");
|
|
882
885
|
var import_react_native9 = require("react-native");
|
|
883
|
-
var
|
|
886
|
+
var import_react_native_paper3 = require("react-native-paper");
|
|
884
887
|
var import_react_native_reanimated9 = __toESM(require("react-native-reanimated"));
|
|
885
888
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
886
889
|
var PullSearch = (0, import_react10.forwardRef)(function PullSearch2({ debounce, onChangeText, onHeightChange, placeholder, value: propValue }, ref) {
|
|
887
890
|
const { headerHeight, scrollPosition } = (0, import_react10.useContext)(ScrollViewContext);
|
|
888
|
-
const theme = (0,
|
|
891
|
+
const theme = (0, import_react_native_paper3.useTheme)();
|
|
889
892
|
const inputRef = (0, import_react10.useRef)(null);
|
|
890
893
|
const [barHeight, setBarHeight] = (0, import_react10.useState)(0);
|
|
891
894
|
const [value, setValue] = (0, import_react10.useState)(propValue ?? "");
|
|
@@ -943,7 +946,7 @@ var PullSearch = (0, import_react10.forwardRef)(function PullSearch2({ debounce,
|
|
|
943
946
|
const hideY = -h + barHeight;
|
|
944
947
|
return { opacity: (0, import_react_native_reanimated9.interpolate)(scrollPosition.value, [showY, hideY], [1, 0], import_react_native_reanimated9.Extrapolation.CLAMP) };
|
|
945
948
|
}, [barHeight, headerHeight, scrollPosition]);
|
|
946
|
-
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native_reanimated9.default.View, { onLayout: handleLayout, style: [styles5.container, animatedStyle], children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
949
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native_reanimated9.default.View, { onLayout: handleLayout, style: [styles5.container, animatedStyle], children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native_paper3.Searchbar, { autoCorrect: false, onChangeText: (text) => setValue((text || "").trimStart()), onClearIconPress: handleClear, placeholder, placeholderTextColor: theme.colors.onSurfaceVariant, ref: inputRef, spellCheck: false, style: styles5.input, value }) });
|
|
947
950
|
});
|
|
948
951
|
var styles5 = import_react_native9.StyleSheet.create({
|
|
949
952
|
container: { paddingVertical: 8 },
|
|
@@ -1058,14 +1061,20 @@ var import_react13 = require("react");
|
|
|
1058
1061
|
var import_react_native11 = require("react-native");
|
|
1059
1062
|
var import_react_native_reanimated11 = __toESM(require("react-native-reanimated"));
|
|
1060
1063
|
var import_react_native_safe_area_context3 = require("react-native-safe-area-context");
|
|
1061
|
-
var import_jsx_runtime8 =
|
|
1064
|
+
var import_jsx_runtime8 = (
|
|
1065
|
+
// bottom: tabBarHeight (not the styles.footer default of 0) - a consuming app's own persistent
|
|
1066
|
+
// tab bar (a fixture outside this package's header/footer concepts entirely, same as
|
|
1067
|
+
// useScrollList's content-inset reservation) sits below this at the true screen bottom, so this
|
|
1068
|
+
// bar has to clear it rather than rendering flush against 0 and overlapping/hiding behind it.
|
|
1069
|
+
require("react/jsx-runtime")
|
|
1070
|
+
);
|
|
1062
1071
|
var ScrollViewFooter = ({ children, style }) => {
|
|
1063
|
-
const { blur, footerAboveKeyboard, footerHeight, footerFixed, footerOffset, headerHeightShared, pullSearchHeightShared, scrollPosition, setFooterHeight, snapBackFooterShared } = (0, import_react13.useContext)(ScrollViewContext);
|
|
1072
|
+
const { blur, footerAboveKeyboard, footerHeight, footerFixed, footerOffset, headerHeightShared, pullSearchHeightShared, scrollPosition, setFooterHeight, snapBackFooterShared, tabBarHeight } = (0, import_react13.useContext)(ScrollViewContext);
|
|
1064
1073
|
const insets = (0, import_react_native_safe_area_context3.useSafeAreaInsets)();
|
|
1065
1074
|
const keyboardHeight = useKeyboardInset();
|
|
1066
1075
|
(0, import_react13.useEffect)(
|
|
1067
1076
|
() => () => {
|
|
1068
|
-
setFooterHeight(
|
|
1077
|
+
setFooterHeight(null);
|
|
1069
1078
|
},
|
|
1070
1079
|
[setFooterHeight]
|
|
1071
1080
|
);
|
|
@@ -1081,17 +1090,17 @@ var ScrollViewFooter = ({ children, style }) => {
|
|
|
1081
1090
|
if (snapBackFooterShared.value) return { transform: [{ translateY: footerOffset.value }] };
|
|
1082
1091
|
const effective = scrollPosition.value + headerHeightShared.value - pullSearchHeightShared.value;
|
|
1083
1092
|
if (effective <= 0) return { transform: [{ translateY: 0 }] };
|
|
1084
|
-
return { transform: [{ translateY: Math.min(effective, footerHeight) }] };
|
|
1093
|
+
return { transform: [{ translateY: Math.min(effective, footerHeight ?? 0) }] };
|
|
1085
1094
|
}, [footerHeight, footerFixed, headerHeightShared, pullSearchHeightShared, scrollPosition, snapBackFooterShared, footerOffset]);
|
|
1086
1095
|
const containerPaddingBottom = footerFixed && footerAboveKeyboard ? keyboardHeight : 0;
|
|
1087
1096
|
const rowPaddingBottom = footerFixed && footerAboveKeyboard ? Math.max(insets.bottom - keyboardHeight, 0) : insets.bottom;
|
|
1088
|
-
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native_reanimated11.default.View, { onLayout: handleLayout, pointerEvents: "box-none", style: [styles6.footer, { paddingBottom: containerPaddingBottom }, footerStyle], children: [
|
|
1089
|
-
footerHeight > 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_auto_paper3.BlurView, { blur, style: import_react_native11.StyleSheet.absoluteFill }),
|
|
1097
|
+
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
|
+
(footerHeight ?? 0) > 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_auto_paper3.BlurView, { blur, style: import_react_native11.StyleSheet.absoluteFill }),
|
|
1090
1099
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native11.View, { style: [styles6.row, { paddingBottom: rowPaddingBottom }, style], children })
|
|
1091
1100
|
] });
|
|
1092
1101
|
};
|
|
1093
1102
|
var styles6 = import_react_native11.StyleSheet.create({
|
|
1094
|
-
footer: {
|
|
1103
|
+
footer: { left: 0, position: "absolute", right: 0, zIndex: 2 },
|
|
1095
1104
|
row: { alignItems: "center", flexDirection: "row", zIndex: 1 }
|
|
1096
1105
|
});
|
|
1097
1106
|
|
|
@@ -1099,23 +1108,25 @@ var styles6 = import_react_native11.StyleSheet.create({
|
|
|
1099
1108
|
var import_auto_paper4 = require("@rific/auto-paper");
|
|
1100
1109
|
var import_react14 = require("react");
|
|
1101
1110
|
var import_react_native12 = require("react-native");
|
|
1102
|
-
var
|
|
1111
|
+
var import_react_native_paper4 = require("react-native-paper");
|
|
1103
1112
|
var import_react_native_reanimated12 = __toESM(require("react-native-reanimated"));
|
|
1104
1113
|
var import_react_native_safe_area_context4 = require("react-native-safe-area-context");
|
|
1105
1114
|
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
1106
|
-
var ActionBg = ({ blur, style }) => blur ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native12.View, { style: [import_react_native12.StyleSheet.absoluteFill, styles7.actionBg, style], children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_auto_paper4.BlurView, { blur: true, style: import_react_native12.StyleSheet.absoluteFill }) }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native12.View, { style: [import_react_native12.StyleSheet.absoluteFill, styles7.actionBg, style], pointerEvents: "none", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1115
|
+
var ActionBg = ({ blur, style }) => blur ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native12.View, { style: [import_react_native12.StyleSheet.absoluteFill, styles7.actionBg, style], children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_auto_paper4.BlurView, { blur: true, style: import_react_native12.StyleSheet.absoluteFill }) }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native12.View, { style: [import_react_native12.StyleSheet.absoluteFill, styles7.actionBg, style], pointerEvents: "none", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper4.Surface, { style: import_react_native12.StyleSheet.absoluteFill, elevation: 1, children: null }) });
|
|
1107
1116
|
var ScrollViewHeader = ({ actionSize = 48, actionStyle, backAction, backActionAccessibilityLabel, backActionFixed, caption, centerContent, children, iconSize, style, title, topInset = true, trailingAction, trailingActionFixed = true }) => {
|
|
1108
|
-
const { blur, headerHeight, headerFixed, headerOffset, progress, progressing, pullSearchHeightShared, scrollPosition, setHeaderHeight, snapBackHeaderShared } = (0, import_react14.useContext)(ScrollViewContext);
|
|
1117
|
+
const { blur, headerHeight, headerFixed, headerHeightShared, headerOffset, progress, progressing, pullSearchHeightShared, scrollPosition, setHeaderHeight, snapBackHeaderShared } = (0, import_react14.useContext)(ScrollViewContext);
|
|
1109
1118
|
const { settings } = (0, import_react14.useContext)(ScrollViewSettingsContext);
|
|
1110
1119
|
const effectiveBackActionFixed = backActionFixed ?? settings.backActionFixed;
|
|
1111
1120
|
const insets = (0, import_react_native_safe_area_context4.useSafeAreaInsets)();
|
|
1112
|
-
const theme = (0,
|
|
1121
|
+
const theme = (0, import_react_native_paper4.useTheme)();
|
|
1113
1122
|
const top = topInset ? insets.top : 0;
|
|
1123
|
+
const measuredShared = (0, import_react_native_reanimated12.useSharedValue)(false);
|
|
1114
1124
|
const handleLayout = ({
|
|
1115
1125
|
nativeEvent: {
|
|
1116
1126
|
layout: { height }
|
|
1117
1127
|
}
|
|
1118
1128
|
}) => {
|
|
1129
|
+
measuredShared.value = true;
|
|
1119
1130
|
if (headerHeight !== height) setHeaderHeight(height);
|
|
1120
1131
|
};
|
|
1121
1132
|
const actionMargin = 4;
|
|
@@ -1124,23 +1135,23 @@ var ScrollViewHeader = ({ actionSize = 48, actionStyle, backAction, backActionAc
|
|
|
1124
1135
|
const translateStyle = (0, import_react_native_reanimated12.useAnimatedStyle)(() => {
|
|
1125
1136
|
if (headerFixed) return { transform: [{ translateY: 0 }] };
|
|
1126
1137
|
if (snapBackHeaderShared.value) return { transform: [{ translateY: headerOffset.value }] };
|
|
1127
|
-
const effective = scrollPosition.value +
|
|
1138
|
+
const effective = scrollPosition.value + headerHeightShared.value - pullSearchHeightShared.value;
|
|
1128
1139
|
if (effective <= 0) return { transform: [{ translateY: 0 }] };
|
|
1129
1140
|
return { transform: [{ translateY: -effective }] };
|
|
1130
|
-
}, [headerFixed,
|
|
1141
|
+
}, [headerFixed, headerHeightShared, headerOffset, pullSearchHeightShared, scrollPosition, snapBackHeaderShared]);
|
|
1131
1142
|
const blurStyle = (0, import_react_native_reanimated12.useAnimatedStyle)(() => {
|
|
1132
|
-
if (
|
|
1133
|
-
if (!
|
|
1134
|
-
if (headerFixed) return { height:
|
|
1135
|
-
const translateY = snapBackHeaderShared.value ? headerOffset.value : -Math.max(0, scrollPosition.value +
|
|
1136
|
-
return { height: Math.max(
|
|
1137
|
-
}, [headerFixed,
|
|
1143
|
+
if (!measuredShared.value) return { height: unmeasuredHeight };
|
|
1144
|
+
if (!headerHeightShared.value) return { height: 0 };
|
|
1145
|
+
if (headerFixed) return { height: headerHeightShared.value };
|
|
1146
|
+
const translateY = snapBackHeaderShared.value ? headerOffset.value : -Math.max(0, scrollPosition.value + headerHeightShared.value - pullSearchHeightShared.value);
|
|
1147
|
+
return { height: Math.max(headerHeightShared.value + translateY, top) };
|
|
1148
|
+
}, [headerFixed, top, unmeasuredHeight, measuredShared, headerHeightShared, headerOffset, pullSearchHeightShared, scrollPosition, snapBackHeaderShared]);
|
|
1138
1149
|
const progressStyle = (0, import_react_native_reanimated12.useAnimatedStyle)(() => {
|
|
1139
|
-
const h =
|
|
1150
|
+
const h = headerHeightShared.value;
|
|
1140
1151
|
if (headerFixed) return { top: h };
|
|
1141
1152
|
const slide = snapBackHeaderShared.value ? -headerOffset.value : Math.max(0, scrollPosition.value + h - pullSearchHeightShared.value);
|
|
1142
1153
|
return { top: Math.max(h - slide, top) };
|
|
1143
|
-
}, [headerFixed,
|
|
1154
|
+
}, [headerFixed, headerHeightShared, top, headerOffset, pullSearchHeightShared, scrollPosition, snapBackHeaderShared]);
|
|
1144
1155
|
const actionTop = top + actionMargin;
|
|
1145
1156
|
const buttonStyle = { borderRadius: actionSize, height: actionSize, margin: 0, width: actionSize };
|
|
1146
1157
|
const actionShadow = { borderRadius: actionSize / 2, elevation: 2, shadowColor: "#000", shadowOffset: { width: 0, height: 1 }, shadowOpacity: 0.15, shadowRadius: 2 };
|
|
@@ -1159,13 +1170,13 @@ var ScrollViewHeader = ({ actionSize = 48, actionStyle, backAction, backActionAc
|
|
|
1159
1170
|
] }) }),
|
|
1160
1171
|
!blur && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native12.View, { style: [styles7.divider, { backgroundColor: theme.colors.outlineVariant }] })
|
|
1161
1172
|
] }),
|
|
1162
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_reanimated12.default.View, { pointerEvents: "none", style: [styles7.progress, progressStyle], children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1173
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_reanimated12.default.View, { pointerEvents: "none", style: [styles7.progress, progressStyle], children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper4.ProgressBar, { indeterminate: progress === null, visible: progressing, progress: progress ?? void 0 }) }),
|
|
1163
1174
|
backAction && (effectiveBackActionFixed ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native_reanimated12.default.View, { style: leadingStyle, children: [
|
|
1164
1175
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ActionBg, { blur, style: actionStyle }),
|
|
1165
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1176
|
+
typeof backAction === "function" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper4.Appbar.BackAction, { accessibilityLabel: backActionAccessibilityLabel, onPress: backAction, size: iconSize ?? actionSize / 2, style: buttonStyle }) : backAction
|
|
1166
1177
|
] }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native_reanimated12.default.View, { style: [leadingStyle, translateStyle], children: [
|
|
1167
1178
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ActionBg, { blur, style: actionStyle }),
|
|
1168
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1179
|
+
typeof backAction === "function" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper4.Appbar.BackAction, { accessibilityLabel: backActionAccessibilityLabel, onPress: backAction, size: iconSize ?? actionSize / 2, style: buttonStyle }) : backAction
|
|
1169
1180
|
] })),
|
|
1170
1181
|
trailingAction && (trailingActionFixed ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native12.View, { style: trailingStyle, children: [
|
|
1171
1182
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ActionBg, { blur, style: actionStyle }),
|
|
@@ -1205,7 +1216,7 @@ var ScrollViewProvider = ({ blur, children, fixed = false, footerAboveKeyboard =
|
|
|
1205
1216
|
const effectiveSnapBackHeader = snapBackHeader ?? settings.snapBackHeader;
|
|
1206
1217
|
const effectiveSnapBackFooter = snapBackFooter ?? settings.snapBackFooter;
|
|
1207
1218
|
const [headerHeight, setHeaderHeightState] = (0, import_react15.useState)(null);
|
|
1208
|
-
const [footerHeight, setFooterHeightState] = (0, import_react15.useState)(
|
|
1219
|
+
const [footerHeight, setFooterHeightState] = (0, import_react15.useState)(null);
|
|
1209
1220
|
const [progress, setProgress] = (0, import_react15.useState)(null);
|
|
1210
1221
|
const [progressing, setProgressing] = (0, import_react15.useState)(false);
|
|
1211
1222
|
const scrollPosition = (0, import_react_native_reanimated13.useSharedValue)(0);
|
|
@@ -1245,12 +1256,13 @@ var ScrollViewProvider = ({ blur, children, fixed = false, footerAboveKeyboard =
|
|
|
1245
1256
|
}, [headerHeight]);
|
|
1246
1257
|
const setFooterHeight = (0, import_react15.useCallback)(
|
|
1247
1258
|
(h) => {
|
|
1259
|
+
if (h === 0 && footerHeight) return;
|
|
1248
1260
|
setFooterHeightState(h);
|
|
1249
|
-
footerHeightShared.value = h;
|
|
1261
|
+
footerHeightShared.value = h ?? 0;
|
|
1250
1262
|
},
|
|
1251
|
-
[footerHeightShared]
|
|
1263
|
+
[footerHeight, footerHeightShared]
|
|
1252
1264
|
);
|
|
1253
|
-
const scrollHeight = (0, import_react15.useMemo)(() => import_react_native13.Dimensions.get("window").height - (headerHeight ?? 0) - footerHeight, [headerHeight, footerHeight]);
|
|
1265
|
+
const scrollHeight = (0, import_react15.useMemo)(() => import_react_native13.Dimensions.get("window").height - (headerHeight ?? 0) - (footerHeight ?? 0), [headerHeight, footerHeight]);
|
|
1254
1266
|
const effectiveHeaderFixed = fixed || (headerFixed ?? settings.headerFixed);
|
|
1255
1267
|
const effectiveFooterFixed = fixed || (footerFixed ?? settings.footerFixed);
|
|
1256
1268
|
const value = (0, import_react15.useMemo)(() => ({ blur: effectiveBlur, footerAboveKeyboard, 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, footerAboveKeyboard, effectiveFooterFixed, effectiveHeaderFixed, footerHeight, footerHeightShared, footerOffset, headerHeight, headerHeightShared, headerOffset, jsListGeneration, listGeneration, onJsListUnmount, onListUnmount, progress, pullSearchHeightShared, progressing, scrollHeight, scrollPosition, setFooterHeight, setHeaderHeight, snapBackFooterShared, snapBackHeaderShared, tabBarHeight]);
|
package/dist/index.mjs
CHANGED
|
@@ -12,15 +12,18 @@ var RefreshControl = (props) => /* @__PURE__ */ jsx(RNRefreshControl, { refreshi
|
|
|
12
12
|
// src/internal/ScrollViewChip.tsx
|
|
13
13
|
import { Chip } from "@rific/auto-paper";
|
|
14
14
|
import { StyleSheet } from "react-native";
|
|
15
|
+
import { Icon, useTheme } from "react-native-paper";
|
|
15
16
|
import Animated from "react-native-reanimated";
|
|
16
17
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
17
18
|
var ScrollViewChip = ({ chipProps, isHorizontal, onChipPress, onPress, style }) => {
|
|
18
|
-
const {
|
|
19
|
+
const { colors } = useTheme();
|
|
20
|
+
const { label, selectedColor, style: chipStyle, ...restChipProps } = chipProps ?? {};
|
|
19
21
|
const handlePress = onChipPress ? () => {
|
|
20
22
|
onPress();
|
|
21
23
|
onChipPress();
|
|
22
24
|
} : onPress;
|
|
23
|
-
|
|
25
|
+
const iconColor = selectedColor ?? (restChipProps.mode === "outlined" ? colors.onSurfaceVariant : colors.onSecondaryContainer);
|
|
26
|
+
return /* @__PURE__ */ jsx2(Animated.View, { style: [styles.chip, style], children: /* @__PURE__ */ jsx2(Chip, { compact: true, selectedColor, ...restChipProps, avatar: /* @__PURE__ */ jsx2(Icon, { source: isHorizontal ? "chevron-left" : "chevron-up", size: 18, color: iconColor }), onPress: handlePress, style: [styles.chipInner, chipStyle], children: label ?? (isHorizontal ? "Start" : "Top") }) });
|
|
24
27
|
};
|
|
25
28
|
var styles = StyleSheet.create({
|
|
26
29
|
chip: { alignItems: "center", left: 0, position: "absolute", right: 0, zIndex: 3 },
|
|
@@ -36,7 +39,7 @@ import { createContext } from "react";
|
|
|
36
39
|
var ScrollViewContext = createContext({
|
|
37
40
|
blur: true,
|
|
38
41
|
footerAboveKeyboard: false,
|
|
39
|
-
footerHeight:
|
|
42
|
+
footerHeight: null,
|
|
40
43
|
footerHeightShared: null,
|
|
41
44
|
footerFixed: false,
|
|
42
45
|
footerOffset: null,
|
|
@@ -376,7 +379,7 @@ var CHIP_SLIDE = 48;
|
|
|
376
379
|
function useScrollList({ footerFixed: footerFixedProp, headerFixed: headerFixedProp, hideUntilMeasured, isHorizontal, keyboardAware, pullSearchHeight, style } = {}) {
|
|
377
380
|
const insets = useSafeAreaInsets();
|
|
378
381
|
const keyboardHeight = useKeyboardInset();
|
|
379
|
-
const { footerAboveKeyboard, footerHeight, footerFixed: contextFooterFixed, headerHeight, headerFixed: contextHeaderFixed, headerOffset, pullSearchHeightShared, scrollPosition, snapBackHeaderShared, tabBarHeight } = useContext3(ScrollViewContext);
|
|
382
|
+
const { footerAboveKeyboard, footerHeight, footerFixed: contextFooterFixed, headerHeight, headerHeightShared, headerFixed: contextHeaderFixed, headerOffset, pullSearchHeightShared, scrollPosition, snapBackHeaderShared, tabBarHeight } = useContext3(ScrollViewContext);
|
|
380
383
|
const headerFixed = isHorizontal ? true : headerFixedProp ?? contextHeaderFixed;
|
|
381
384
|
const footerFixed = isHorizontal ? true : footerFixedProp ?? contextFooterFixed;
|
|
382
385
|
useEffect2(() => {
|
|
@@ -400,11 +403,11 @@ function useScrollList({ footerFixed: footerFixedProp, headerFixed: headerFixedP
|
|
|
400
403
|
return {
|
|
401
404
|
opacity: chipHidden.value ? withTiming2(0) : withTiming2(1),
|
|
402
405
|
pointerEvents,
|
|
403
|
-
top: Math.max(
|
|
406
|
+
top: Math.max(headerHeightShared.value, insets.top) + 4,
|
|
404
407
|
transform: [{ translateX: chipHidden.value ? withTiming2(-CHIP_SLIDE) : withTiming2(0) }]
|
|
405
408
|
};
|
|
406
409
|
}
|
|
407
|
-
const h =
|
|
410
|
+
const h = headerHeightShared.value;
|
|
408
411
|
const slide = headerFixed ? 0 : snapBackHeaderShared.value ? -headerOffset.value : Math.max(0, scrollPosition.value + h - pullSearchHeightShared.value);
|
|
409
412
|
const top = Math.max(h - slide, insets.top) + 4;
|
|
410
413
|
return {
|
|
@@ -413,7 +416,7 @@ function useScrollList({ footerFixed: footerFixedProp, headerFixed: headerFixedP
|
|
|
413
416
|
top,
|
|
414
417
|
transform: [{ translateY: chipHidden.value ? withTiming2(-CHIP_SLIDE) : withTiming2(0) }]
|
|
415
418
|
};
|
|
416
|
-
}, [isHorizontal, headerFixed,
|
|
419
|
+
}, [isHorizontal, headerFixed, headerHeightShared, insets.top, chipHidden, snapBackHeaderShared, headerOffset, scrollPosition, pullSearchHeightShared]);
|
|
417
420
|
return { chipHidden, chipStyle, containerStyle, contentInset, contentOffset, contentPadding, footerFixed, headerFixed, headerHeight, insets, isHorizontal: isHorizontal ?? false };
|
|
418
421
|
}
|
|
419
422
|
|
|
@@ -504,7 +507,7 @@ import { Gesture as Gesture2, GestureDetector as GestureDetector2 } from "react-
|
|
|
504
507
|
import { BlurView } from "@rific/auto-paper";
|
|
505
508
|
import { useContext as useContext5 } from "react";
|
|
506
509
|
import { StyleSheet as StyleSheet3, useWindowDimensions, View as View2 } from "react-native";
|
|
507
|
-
import { useTheme } from "react-native-paper";
|
|
510
|
+
import { useTheme as useTheme2 } from "react-native-paper";
|
|
508
511
|
import Animated2, { interpolateColor, useAnimatedStyle as useAnimatedStyle2 } from "react-native-reanimated";
|
|
509
512
|
import { useSafeAreaInsets as useSafeAreaInsets2 } from "react-native-safe-area-context";
|
|
510
513
|
import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
@@ -534,7 +537,7 @@ var HorizontalDots = ({ total }) => {
|
|
|
534
537
|
const { blur, footerHeightShared, scrollPosition } = useContext5(ScrollViewContext);
|
|
535
538
|
const { width } = useWindowDimensions();
|
|
536
539
|
const insets = useSafeAreaInsets2();
|
|
537
|
-
const theme =
|
|
540
|
+
const theme = useTheme2();
|
|
538
541
|
const insetsBottom = insets.bottom;
|
|
539
542
|
const activeColor = theme.colors.primary;
|
|
540
543
|
const inactiveColor = theme.colors.outlineVariant;
|
|
@@ -828,12 +831,12 @@ var FlatList = memo2(FlatListInner);
|
|
|
828
831
|
// src/PullSearch.tsx
|
|
829
832
|
import { forwardRef, useCallback as useCallback5, useContext as useContext8, useEffect as useEffect3, useImperativeHandle, useRef as useRef5, useState as useState4 } from "react";
|
|
830
833
|
import { StyleSheet as StyleSheet4 } from "react-native";
|
|
831
|
-
import { Searchbar, useTheme as
|
|
834
|
+
import { Searchbar, useTheme as useTheme3 } from "react-native-paper";
|
|
832
835
|
import Animated3, { Extrapolation, interpolate, runOnJS as runOnJS3, useAnimatedReaction, useAnimatedStyle as useAnimatedStyle3 } from "react-native-reanimated";
|
|
833
836
|
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
834
837
|
var PullSearch = forwardRef(function PullSearch2({ debounce, onChangeText, onHeightChange, placeholder, value: propValue }, ref) {
|
|
835
838
|
const { headerHeight, scrollPosition } = useContext8(ScrollViewContext);
|
|
836
|
-
const theme =
|
|
839
|
+
const theme = useTheme3();
|
|
837
840
|
const inputRef = useRef5(null);
|
|
838
841
|
const [barHeight, setBarHeight] = useState4(0);
|
|
839
842
|
const [value, setValue] = useState4(propValue ?? "");
|
|
@@ -1008,12 +1011,12 @@ import Animated5, { useAnimatedStyle as useAnimatedStyle4 } from "react-native-r
|
|
|
1008
1011
|
import { useSafeAreaInsets as useSafeAreaInsets3 } from "react-native-safe-area-context";
|
|
1009
1012
|
import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1010
1013
|
var ScrollViewFooter = ({ children, style }) => {
|
|
1011
|
-
const { blur, footerAboveKeyboard, footerHeight, footerFixed, footerOffset, headerHeightShared, pullSearchHeightShared, scrollPosition, setFooterHeight, snapBackFooterShared } = useContext10(ScrollViewContext);
|
|
1014
|
+
const { blur, footerAboveKeyboard, footerHeight, footerFixed, footerOffset, headerHeightShared, pullSearchHeightShared, scrollPosition, setFooterHeight, snapBackFooterShared, tabBarHeight } = useContext10(ScrollViewContext);
|
|
1012
1015
|
const insets = useSafeAreaInsets3();
|
|
1013
1016
|
const keyboardHeight = useKeyboardInset();
|
|
1014
1017
|
useEffect4(
|
|
1015
1018
|
() => () => {
|
|
1016
|
-
setFooterHeight(
|
|
1019
|
+
setFooterHeight(null);
|
|
1017
1020
|
},
|
|
1018
1021
|
[setFooterHeight]
|
|
1019
1022
|
);
|
|
@@ -1029,17 +1032,23 @@ var ScrollViewFooter = ({ children, style }) => {
|
|
|
1029
1032
|
if (snapBackFooterShared.value) return { transform: [{ translateY: footerOffset.value }] };
|
|
1030
1033
|
const effective = scrollPosition.value + headerHeightShared.value - pullSearchHeightShared.value;
|
|
1031
1034
|
if (effective <= 0) return { transform: [{ translateY: 0 }] };
|
|
1032
|
-
return { transform: [{ translateY: Math.min(effective, footerHeight) }] };
|
|
1035
|
+
return { transform: [{ translateY: Math.min(effective, footerHeight ?? 0) }] };
|
|
1033
1036
|
}, [footerHeight, footerFixed, headerHeightShared, pullSearchHeightShared, scrollPosition, snapBackFooterShared, footerOffset]);
|
|
1034
1037
|
const containerPaddingBottom = footerFixed && footerAboveKeyboard ? keyboardHeight : 0;
|
|
1035
1038
|
const rowPaddingBottom = footerFixed && footerAboveKeyboard ? Math.max(insets.bottom - keyboardHeight, 0) : insets.bottom;
|
|
1036
|
-
return
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1039
|
+
return (
|
|
1040
|
+
// bottom: tabBarHeight (not the styles.footer default of 0) - a consuming app's own persistent
|
|
1041
|
+
// tab bar (a fixture outside this package's header/footer concepts entirely, same as
|
|
1042
|
+
// useScrollList's content-inset reservation) sits below this at the true screen bottom, so this
|
|
1043
|
+
// bar has to clear it rather than rendering flush against 0 and overlapping/hiding behind it.
|
|
1044
|
+
/* @__PURE__ */ jsxs5(Animated5.View, { onLayout: handleLayout, pointerEvents: "box-none", style: [styles6.footer, { bottom: tabBarHeight, paddingBottom: containerPaddingBottom }, footerStyle], children: [
|
|
1045
|
+
(footerHeight ?? 0) > 0 && /* @__PURE__ */ jsx8(BlurView2, { blur, style: StyleSheet5.absoluteFill }),
|
|
1046
|
+
/* @__PURE__ */ jsx8(View5, { style: [styles6.row, { paddingBottom: rowPaddingBottom }, style], children })
|
|
1047
|
+
] })
|
|
1048
|
+
);
|
|
1040
1049
|
};
|
|
1041
1050
|
var styles6 = StyleSheet5.create({
|
|
1042
|
-
footer: {
|
|
1051
|
+
footer: { left: 0, position: "absolute", right: 0, zIndex: 2 },
|
|
1043
1052
|
row: { alignItems: "center", flexDirection: "row", zIndex: 1 }
|
|
1044
1053
|
});
|
|
1045
1054
|
|
|
@@ -1047,23 +1056,25 @@ var styles6 = StyleSheet5.create({
|
|
|
1047
1056
|
import { BlurView as BlurView3 } from "@rific/auto-paper";
|
|
1048
1057
|
import { useContext as useContext11 } from "react";
|
|
1049
1058
|
import { StyleSheet as StyleSheet6, Text, View as View6 } from "react-native";
|
|
1050
|
-
import { Appbar, ProgressBar, Surface, useTheme as
|
|
1051
|
-
import Animated6, { useAnimatedStyle as useAnimatedStyle5 } from "react-native-reanimated";
|
|
1059
|
+
import { Appbar, ProgressBar, Surface, useTheme as useTheme4 } from "react-native-paper";
|
|
1060
|
+
import Animated6, { useAnimatedStyle as useAnimatedStyle5, useSharedValue as useSharedValue6 } from "react-native-reanimated";
|
|
1052
1061
|
import { useSafeAreaInsets as useSafeAreaInsets4 } from "react-native-safe-area-context";
|
|
1053
1062
|
import { Fragment as Fragment4, jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1054
1063
|
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 }) });
|
|
1055
1064
|
var ScrollViewHeader = ({ actionSize = 48, actionStyle, backAction, backActionAccessibilityLabel, backActionFixed, caption, centerContent, children, iconSize, style, title, topInset = true, trailingAction, trailingActionFixed = true }) => {
|
|
1056
|
-
const { blur, headerHeight, headerFixed, headerOffset, progress, progressing, pullSearchHeightShared, scrollPosition, setHeaderHeight, snapBackHeaderShared } = useContext11(ScrollViewContext);
|
|
1065
|
+
const { blur, headerHeight, headerFixed, headerHeightShared, headerOffset, progress, progressing, pullSearchHeightShared, scrollPosition, setHeaderHeight, snapBackHeaderShared } = useContext11(ScrollViewContext);
|
|
1057
1066
|
const { settings } = useContext11(ScrollViewSettingsContext);
|
|
1058
1067
|
const effectiveBackActionFixed = backActionFixed ?? settings.backActionFixed;
|
|
1059
1068
|
const insets = useSafeAreaInsets4();
|
|
1060
|
-
const theme =
|
|
1069
|
+
const theme = useTheme4();
|
|
1061
1070
|
const top = topInset ? insets.top : 0;
|
|
1071
|
+
const measuredShared = useSharedValue6(false);
|
|
1062
1072
|
const handleLayout = ({
|
|
1063
1073
|
nativeEvent: {
|
|
1064
1074
|
layout: { height }
|
|
1065
1075
|
}
|
|
1066
1076
|
}) => {
|
|
1077
|
+
measuredShared.value = true;
|
|
1067
1078
|
if (headerHeight !== height) setHeaderHeight(height);
|
|
1068
1079
|
};
|
|
1069
1080
|
const actionMargin = 4;
|
|
@@ -1072,23 +1083,23 @@ var ScrollViewHeader = ({ actionSize = 48, actionStyle, backAction, backActionAc
|
|
|
1072
1083
|
const translateStyle = useAnimatedStyle5(() => {
|
|
1073
1084
|
if (headerFixed) return { transform: [{ translateY: 0 }] };
|
|
1074
1085
|
if (snapBackHeaderShared.value) return { transform: [{ translateY: headerOffset.value }] };
|
|
1075
|
-
const effective = scrollPosition.value +
|
|
1086
|
+
const effective = scrollPosition.value + headerHeightShared.value - pullSearchHeightShared.value;
|
|
1076
1087
|
if (effective <= 0) return { transform: [{ translateY: 0 }] };
|
|
1077
1088
|
return { transform: [{ translateY: -effective }] };
|
|
1078
|
-
}, [headerFixed,
|
|
1089
|
+
}, [headerFixed, headerHeightShared, headerOffset, pullSearchHeightShared, scrollPosition, snapBackHeaderShared]);
|
|
1079
1090
|
const blurStyle = useAnimatedStyle5(() => {
|
|
1080
|
-
if (
|
|
1081
|
-
if (!
|
|
1082
|
-
if (headerFixed) return { height:
|
|
1083
|
-
const translateY = snapBackHeaderShared.value ? headerOffset.value : -Math.max(0, scrollPosition.value +
|
|
1084
|
-
return { height: Math.max(
|
|
1085
|
-
}, [headerFixed,
|
|
1091
|
+
if (!measuredShared.value) return { height: unmeasuredHeight };
|
|
1092
|
+
if (!headerHeightShared.value) return { height: 0 };
|
|
1093
|
+
if (headerFixed) return { height: headerHeightShared.value };
|
|
1094
|
+
const translateY = snapBackHeaderShared.value ? headerOffset.value : -Math.max(0, scrollPosition.value + headerHeightShared.value - pullSearchHeightShared.value);
|
|
1095
|
+
return { height: Math.max(headerHeightShared.value + translateY, top) };
|
|
1096
|
+
}, [headerFixed, top, unmeasuredHeight, measuredShared, headerHeightShared, headerOffset, pullSearchHeightShared, scrollPosition, snapBackHeaderShared]);
|
|
1086
1097
|
const progressStyle = useAnimatedStyle5(() => {
|
|
1087
|
-
const h =
|
|
1098
|
+
const h = headerHeightShared.value;
|
|
1088
1099
|
if (headerFixed) return { top: h };
|
|
1089
1100
|
const slide = snapBackHeaderShared.value ? -headerOffset.value : Math.max(0, scrollPosition.value + h - pullSearchHeightShared.value);
|
|
1090
1101
|
return { top: Math.max(h - slide, top) };
|
|
1091
|
-
}, [headerFixed,
|
|
1102
|
+
}, [headerFixed, headerHeightShared, top, headerOffset, pullSearchHeightShared, scrollPosition, snapBackHeaderShared]);
|
|
1092
1103
|
const actionTop = top + actionMargin;
|
|
1093
1104
|
const buttonStyle = { borderRadius: actionSize, height: actionSize, margin: 0, width: actionSize };
|
|
1094
1105
|
const actionShadow = { borderRadius: actionSize / 2, elevation: 2, shadowColor: "#000", shadowOffset: { width: 0, height: 1 }, shadowOpacity: 0.15, shadowRadius: 2 };
|
|
@@ -1110,10 +1121,10 @@ var ScrollViewHeader = ({ actionSize = 48, actionStyle, backAction, backActionAc
|
|
|
1110
1121
|
/* @__PURE__ */ jsx9(Animated6.View, { pointerEvents: "none", style: [styles7.progress, progressStyle], children: /* @__PURE__ */ jsx9(ProgressBar, { indeterminate: progress === null, visible: progressing, progress: progress ?? void 0 }) }),
|
|
1111
1122
|
backAction && (effectiveBackActionFixed ? /* @__PURE__ */ jsxs6(Animated6.View, { style: leadingStyle, children: [
|
|
1112
1123
|
/* @__PURE__ */ jsx9(ActionBg, { blur, style: actionStyle }),
|
|
1113
|
-
/* @__PURE__ */ jsx9(Appbar.BackAction, { accessibilityLabel: backActionAccessibilityLabel, onPress: backAction, size: iconSize ?? actionSize / 2, style: buttonStyle })
|
|
1124
|
+
typeof backAction === "function" ? /* @__PURE__ */ jsx9(Appbar.BackAction, { accessibilityLabel: backActionAccessibilityLabel, onPress: backAction, size: iconSize ?? actionSize / 2, style: buttonStyle }) : backAction
|
|
1114
1125
|
] }) : /* @__PURE__ */ jsxs6(Animated6.View, { style: [leadingStyle, translateStyle], children: [
|
|
1115
1126
|
/* @__PURE__ */ jsx9(ActionBg, { blur, style: actionStyle }),
|
|
1116
|
-
/* @__PURE__ */ jsx9(Appbar.BackAction, { accessibilityLabel: backActionAccessibilityLabel, onPress: backAction, size: iconSize ?? actionSize / 2, style: buttonStyle })
|
|
1127
|
+
typeof backAction === "function" ? /* @__PURE__ */ jsx9(Appbar.BackAction, { accessibilityLabel: backActionAccessibilityLabel, onPress: backAction, size: iconSize ?? actionSize / 2, style: buttonStyle }) : backAction
|
|
1117
1128
|
] })),
|
|
1118
1129
|
trailingAction && (trailingActionFixed ? /* @__PURE__ */ jsxs6(View6, { style: trailingStyle, children: [
|
|
1119
1130
|
/* @__PURE__ */ jsx9(ActionBg, { blur, style: actionStyle }),
|
|
@@ -1144,7 +1155,7 @@ var styles7 = StyleSheet6.create({
|
|
|
1144
1155
|
import { useBlur } from "@rific/auto-paper";
|
|
1145
1156
|
import { useCallback as useCallback7, useContext as useContext12, useEffect as useEffect5, useMemo as useMemo5, useRef as useRef7, useState as useState5 } from "react";
|
|
1146
1157
|
import { Dimensions as Dimensions3 } from "react-native";
|
|
1147
|
-
import { useSharedValue as
|
|
1158
|
+
import { useSharedValue as useSharedValue7 } from "react-native-reanimated";
|
|
1148
1159
|
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
1149
1160
|
var ScrollViewProvider = ({ blur, children, fixed = false, footerAboveKeyboard = false, footerFixed, headerFixed, snapBack, snapBackFooter, snapBackHeader, tabBarHeight = 0 }) => {
|
|
1150
1161
|
const { settings } = useContext12(ScrollViewSettingsContext);
|
|
@@ -1153,19 +1164,19 @@ var ScrollViewProvider = ({ blur, children, fixed = false, footerAboveKeyboard =
|
|
|
1153
1164
|
const effectiveSnapBackHeader = snapBackHeader ?? settings.snapBackHeader;
|
|
1154
1165
|
const effectiveSnapBackFooter = snapBackFooter ?? settings.snapBackFooter;
|
|
1155
1166
|
const [headerHeight, setHeaderHeightState] = useState5(null);
|
|
1156
|
-
const [footerHeight, setFooterHeightState] = useState5(
|
|
1167
|
+
const [footerHeight, setFooterHeightState] = useState5(null);
|
|
1157
1168
|
const [progress, setProgress] = useState5(null);
|
|
1158
1169
|
const [progressing, setProgressing] = useState5(false);
|
|
1159
|
-
const scrollPosition =
|
|
1160
|
-
const listGeneration =
|
|
1170
|
+
const scrollPosition = useSharedValue7(0);
|
|
1171
|
+
const listGeneration = useSharedValue7(0);
|
|
1161
1172
|
const jsListGeneration = useRef7(0);
|
|
1162
|
-
const headerHeightShared =
|
|
1163
|
-
const footerHeightShared =
|
|
1164
|
-
const headerOffset =
|
|
1165
|
-
const footerOffset =
|
|
1166
|
-
const pullSearchHeightShared =
|
|
1167
|
-
const snapBackHeaderShared =
|
|
1168
|
-
const snapBackFooterShared =
|
|
1173
|
+
const headerHeightShared = useSharedValue7(0);
|
|
1174
|
+
const footerHeightShared = useSharedValue7(0);
|
|
1175
|
+
const headerOffset = useSharedValue7(0);
|
|
1176
|
+
const footerOffset = useSharedValue7(0);
|
|
1177
|
+
const pullSearchHeightShared = useSharedValue7(0);
|
|
1178
|
+
const snapBackHeaderShared = useSharedValue7(false);
|
|
1179
|
+
const snapBackFooterShared = useSharedValue7(false);
|
|
1169
1180
|
useEffect5(() => {
|
|
1170
1181
|
snapBackHeaderShared.value = effectiveSnapBackHeader ?? effectiveSnapBack;
|
|
1171
1182
|
snapBackFooterShared.value = effectiveSnapBackFooter ?? effectiveSnapBack;
|
|
@@ -1193,12 +1204,13 @@ var ScrollViewProvider = ({ blur, children, fixed = false, footerAboveKeyboard =
|
|
|
1193
1204
|
}, [headerHeight]);
|
|
1194
1205
|
const setFooterHeight = useCallback7(
|
|
1195
1206
|
(h) => {
|
|
1207
|
+
if (h === 0 && footerHeight) return;
|
|
1196
1208
|
setFooterHeightState(h);
|
|
1197
|
-
footerHeightShared.value = h;
|
|
1209
|
+
footerHeightShared.value = h ?? 0;
|
|
1198
1210
|
},
|
|
1199
|
-
[footerHeightShared]
|
|
1211
|
+
[footerHeight, footerHeightShared]
|
|
1200
1212
|
);
|
|
1201
|
-
const scrollHeight = useMemo5(() => Dimensions3.get("window").height - (headerHeight ?? 0) - footerHeight, [headerHeight, footerHeight]);
|
|
1213
|
+
const scrollHeight = useMemo5(() => Dimensions3.get("window").height - (headerHeight ?? 0) - (footerHeight ?? 0), [headerHeight, footerHeight]);
|
|
1202
1214
|
const effectiveHeaderFixed = fixed || (headerFixed ?? settings.headerFixed);
|
|
1203
1215
|
const effectiveFooterFixed = fixed || (footerFixed ?? settings.footerFixed);
|
|
1204
1216
|
const value = useMemo5(() => ({ blur: effectiveBlur, footerAboveKeyboard, 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, footerAboveKeyboard, effectiveFooterFixed, effectiveHeaderFixed, footerHeight, footerHeightShared, footerOffset, headerHeight, headerHeightShared, headerOffset, jsListGeneration, listGeneration, onJsListUnmount, onListUnmount, progress, pullSearchHeightShared, progressing, scrollHeight, scrollPosition, setFooterHeight, setHeaderHeight, snapBackFooterShared, snapBackHeaderShared, tabBarHeight]);
|
|
@@ -1231,19 +1243,19 @@ var ScrollViewSettingsProvider = ({ children, onChange, initialValue }) => {
|
|
|
1231
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";
|
|
1232
1244
|
import { Dimensions as Dimensions4, Platform as Platform5, SectionList as RNSectionList, View as View7 } from "react-native";
|
|
1233
1245
|
import { Gesture as Gesture4, GestureDetector as GestureDetector4 } from "react-native-gesture-handler";
|
|
1234
|
-
import Animated7, { runOnUI as runOnUI3, useSharedValue as
|
|
1246
|
+
import Animated7, { runOnUI as runOnUI3, useSharedValue as useSharedValue9 } from "react-native-reanimated";
|
|
1235
1247
|
|
|
1236
1248
|
// src/internal/useStickyHeaders.ts
|
|
1237
1249
|
import { useCallback as useCallback9, useContext as useContext13, useLayoutEffect as useLayoutEffect5, useRef as useRef8, useState as useState7 } from "react";
|
|
1238
|
-
import { runOnJS as runOnJS4, useAnimatedReaction as useAnimatedReaction2, useAnimatedStyle as useAnimatedStyle6, useSharedValue as
|
|
1250
|
+
import { runOnJS as runOnJS4, useAnimatedReaction as useAnimatedReaction2, useAnimatedStyle as useAnimatedStyle6, useSharedValue as useSharedValue8 } from "react-native-reanimated";
|
|
1239
1251
|
import { useSafeAreaInsets as useSafeAreaInsets5 } from "react-native-safe-area-context";
|
|
1240
1252
|
function useStickyHeaders(headerFixed, enabled) {
|
|
1241
1253
|
const { headerHeightShared, headerOffset, pullSearchHeightShared, scrollPosition, snapBackHeaderShared } = useContext13(ScrollViewContext);
|
|
1242
1254
|
const insetsTop = useSafeAreaInsets5().top;
|
|
1243
|
-
const sectionYPositions =
|
|
1244
|
-
const sectionHeights =
|
|
1255
|
+
const sectionYPositions = useSharedValue8([]);
|
|
1256
|
+
const sectionHeights = useSharedValue8([]);
|
|
1245
1257
|
const [activeIndex, setActiveIndex] = useState7(-1);
|
|
1246
|
-
const contentIndexShared =
|
|
1258
|
+
const contentIndexShared = useSharedValue8(-1);
|
|
1247
1259
|
useLayoutEffect5(() => {
|
|
1248
1260
|
contentIndexShared.value = activeIndex;
|
|
1249
1261
|
}, [activeIndex, contentIndexShared]);
|
|
@@ -1355,7 +1367,7 @@ var SectionListInner = ({ chipProps, chipThreshold, contentContainerStyle: exter
|
|
|
1355
1367
|
const { stickySectionHeadersEnabled = true, renderSectionHeader, ...passThroughProps } = props;
|
|
1356
1368
|
const { chipHidden, chipStyle, containerStyle, contentInset, contentOffset, contentPadding, footerFixed, headerFixed, headerHeight } = useScrollList({ footerFixed: footerFixedProp, headerFixed: headerFixedProp, hideUntilMeasured: true, keyboardAware, pullSearchHeight, style });
|
|
1357
1369
|
const { listGeneration, onListUnmount } = useContext14(ScrollViewContext);
|
|
1358
|
-
const capturedGeneration =
|
|
1370
|
+
const capturedGeneration = useSharedValue9(-1);
|
|
1359
1371
|
useLayoutEffect6(() => {
|
|
1360
1372
|
const generation = listGeneration.value;
|
|
1361
1373
|
if (Platform5.OS === "web") {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rific/scroll-view",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.2",
|
|
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",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"type": "commonjs",
|
|
28
28
|
"exports": {
|
|
29
29
|
".": {
|
|
30
|
-
"react-native": "./
|
|
30
|
+
"react-native": "./src/index.ts",
|
|
31
31
|
"types": "./dist/index.d.ts",
|
|
32
32
|
"import": "./dist/index.mjs",
|
|
33
33
|
"require": "./dist/index.js"
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
},
|
|
36
36
|
"main": "dist/index.js",
|
|
37
37
|
"module": "dist/index.mjs",
|
|
38
|
-
"react-native": "
|
|
38
|
+
"react-native": "src/index.ts",
|
|
39
39
|
"types": "dist/index.d.ts",
|
|
40
40
|
"files": [
|
|
41
41
|
"dist",
|
|
@@ -79,12 +79,13 @@
|
|
|
79
79
|
"prettier": "^3.8.3",
|
|
80
80
|
"react": "^19.0.0",
|
|
81
81
|
"react-dom": "^19.0.0",
|
|
82
|
-
"react-native": "^0.
|
|
83
|
-
"react-native-gesture-handler": "
|
|
82
|
+
"react-native": "^0.83.0",
|
|
83
|
+
"react-native-gesture-handler": "^2.32.0",
|
|
84
84
|
"react-native-keyboard-controller": "*",
|
|
85
85
|
"react-native-paper": "^5.12.0",
|
|
86
|
-
"react-native-reanimated": "
|
|
86
|
+
"react-native-reanimated": "^4.5.1",
|
|
87
87
|
"react-native-safe-area-context": "*",
|
|
88
|
+
"react-native-worklets": "^0.10.3",
|
|
88
89
|
"ts-jest": "^29.4.9",
|
|
89
90
|
"ts-node": "^10.9.2",
|
|
90
91
|
"tsup": "^8.0.0",
|
|
@@ -93,13 +94,14 @@
|
|
|
93
94
|
},
|
|
94
95
|
"peerDependencies": {
|
|
95
96
|
"@rific/auto-paper": "^0.8.0",
|
|
96
|
-
"react": ">=
|
|
97
|
-
"react-native": ">=0.
|
|
98
|
-
"react-native-gesture-handler": ">=2.0.0",
|
|
97
|
+
"react": ">=19.0.0",
|
|
98
|
+
"react-native": ">=0.83.0",
|
|
99
|
+
"react-native-gesture-handler": ">=2.0.0 <3.0.0",
|
|
99
100
|
"react-native-keyboard-controller": ">=1.0.0",
|
|
100
101
|
"react-native-paper": ">=5.0.0",
|
|
101
|
-
"react-native-reanimated": ">=
|
|
102
|
-
"react-native-safe-area-context": ">=5.0.0"
|
|
102
|
+
"react-native-reanimated": ">=4.0.0",
|
|
103
|
+
"react-native-safe-area-context": ">=5.0.0",
|
|
104
|
+
"react-native-worklets": "0.10.x"
|
|
103
105
|
},
|
|
104
106
|
"publishConfig": {
|
|
105
107
|
"access": "public"
|
package/src/ScrollViewContext.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { SharedValue } from 'react-native-reanimated'
|
|
|
4
4
|
export type ScrollViewContextType = {
|
|
5
5
|
blur: boolean
|
|
6
6
|
footerAboveKeyboard: boolean
|
|
7
|
-
footerHeight: number
|
|
7
|
+
footerHeight: number | null
|
|
8
8
|
footerHeightShared: SharedValue<number>
|
|
9
9
|
footerFixed: boolean
|
|
10
10
|
footerOffset: SharedValue<number>
|
|
@@ -28,7 +28,7 @@ export type ScrollViewContextType = {
|
|
|
28
28
|
progressing: boolean
|
|
29
29
|
scrollHeight: number
|
|
30
30
|
scrollPosition: SharedValue<number>
|
|
31
|
-
setFooterHeight: (h: number) => void
|
|
31
|
+
setFooterHeight: (h: number | null) => void
|
|
32
32
|
setHeaderHeight: (h: number | null) => void
|
|
33
33
|
setProgress: (p: number | null) => void
|
|
34
34
|
setProgressing: (b: boolean) => void
|
|
@@ -38,7 +38,7 @@ export type ScrollViewContextType = {
|
|
|
38
38
|
export const ScrollViewContext = createContext<ScrollViewContextType>({
|
|
39
39
|
blur: true,
|
|
40
40
|
footerAboveKeyboard: false,
|
|
41
|
-
footerHeight:
|
|
41
|
+
footerHeight: null,
|
|
42
42
|
footerHeightShared: null as unknown as SharedValue<number>,
|
|
43
43
|
footerFixed: false,
|
|
44
44
|
footerOffset: null as unknown as SharedValue<number>,
|
package/src/ScrollViewFooter.tsx
CHANGED
|
@@ -13,12 +13,12 @@ export type ScrollViewFooterProps = {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
export const ScrollViewFooter = ({ children, style }: ScrollViewFooterProps) => {
|
|
16
|
-
const { blur, footerAboveKeyboard, footerHeight, footerFixed, footerOffset, headerHeightShared, pullSearchHeightShared, scrollPosition, setFooterHeight, snapBackFooterShared } = useContext(ScrollViewContext)
|
|
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
19
|
useEffect(
|
|
20
20
|
() => () => {
|
|
21
|
-
setFooterHeight(
|
|
21
|
+
setFooterHeight(null)
|
|
22
22
|
},
|
|
23
23
|
[setFooterHeight]
|
|
24
24
|
)
|
|
@@ -38,7 +38,7 @@ export const ScrollViewFooter = ({ children, style }: ScrollViewFooterProps) =>
|
|
|
38
38
|
if (snapBackFooterShared.value) return { transform: [{ translateY: footerOffset.value }] }
|
|
39
39
|
const effective = scrollPosition.value + headerHeightShared.value - pullSearchHeightShared.value
|
|
40
40
|
if (effective <= 0) return { transform: [{ translateY: 0 }] }
|
|
41
|
-
return { transform: [{ translateY: Math.min(effective, footerHeight) }] }
|
|
41
|
+
return { transform: [{ translateY: Math.min(effective, footerHeight ?? 0) }] }
|
|
42
42
|
}, [footerHeight, footerFixed, headerHeightShared, pullSearchHeightShared, scrollPosition, snapBackFooterShared, footerOffset])
|
|
43
43
|
// Floating above the keyboard is done by GROWING this container (via paddingBottom) rather than
|
|
44
44
|
// translating it. Translating the whole bar left its bottom edge — and the BlurView filling it —
|
|
@@ -66,14 +66,18 @@ export const ScrollViewFooter = ({ children, style }: ScrollViewFooterProps) =>
|
|
|
66
66
|
// of dropping past it and correcting back up.
|
|
67
67
|
const rowPaddingBottom = footerFixed && footerAboveKeyboard ? Math.max(insets.bottom - keyboardHeight, 0) : insets.bottom
|
|
68
68
|
return (
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
// bottom: tabBarHeight (not the styles.footer default of 0) - a consuming app's own persistent
|
|
70
|
+
// tab bar (a fixture outside this package's header/footer concepts entirely, same as
|
|
71
|
+
// useScrollList's content-inset reservation) sits below this at the true screen bottom, so this
|
|
72
|
+
// bar has to clear it rather than rendering flush against 0 and overlapping/hiding behind it.
|
|
73
|
+
<Animated.View onLayout={handleLayout} pointerEvents='box-none' style={[styles.footer, { bottom: tabBarHeight, paddingBottom: containerPaddingBottom }, footerStyle]}>
|
|
74
|
+
{(footerHeight ?? 0) > 0 && <BlurView blur={blur} style={StyleSheet.absoluteFill} />}
|
|
71
75
|
<View style={[styles.row, { paddingBottom: rowPaddingBottom }, style]}>{children}</View>
|
|
72
76
|
</Animated.View>
|
|
73
77
|
)
|
|
74
78
|
}
|
|
75
79
|
|
|
76
80
|
const styles = StyleSheet.create({
|
|
77
|
-
footer: {
|
|
81
|
+
footer: { left: 0, position: 'absolute', right: 0, zIndex: 2 },
|
|
78
82
|
row: { alignItems: 'center', flexDirection: 'row', zIndex: 1 }
|
|
79
83
|
})
|
package/src/ScrollViewHeader.tsx
CHANGED
|
@@ -2,7 +2,7 @@ import { BlurView } from '@rific/auto-paper'
|
|
|
2
2
|
import { type ReactNode, useContext } from 'react'
|
|
3
3
|
import { type LayoutChangeEvent, StyleSheet, Text, View, type ViewStyle } from 'react-native'
|
|
4
4
|
import { Appbar, ProgressBar, Surface, useTheme } from 'react-native-paper'
|
|
5
|
-
import Animated, { useAnimatedStyle } from 'react-native-reanimated'
|
|
5
|
+
import Animated, { useAnimatedStyle, useSharedValue } from 'react-native-reanimated'
|
|
6
6
|
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
|
7
7
|
|
|
8
8
|
import { ScrollViewContext } from './ScrollViewContext'
|
|
@@ -11,7 +11,14 @@ import { ScrollViewSettingsContext } from './ScrollViewSettingsContext'
|
|
|
11
11
|
export type ScrollViewHeaderProps = {
|
|
12
12
|
actionSize?: number
|
|
13
13
|
actionStyle?: ViewStyle
|
|
14
|
-
|
|
14
|
+
// A plain callback renders the default Appbar.BackAction (themed onSurface, sized/positioned by
|
|
15
|
+
// actionSize/iconSize below) — the common case, unchanged from before. Passing a ReactNode
|
|
16
|
+
// instead skips that default entirely and renders the given element in its place, same escape
|
|
17
|
+
// hatch trailingAction already gave the other corner: a caller that wants its own color, icon,
|
|
18
|
+
// or component altogether (a colored IconButton, say) isn't stuck fighting Appbar.BackAction's
|
|
19
|
+
// own fixed color/no-customization API to get it. backActionAccessibilityLabel/iconSize below
|
|
20
|
+
// only apply to the default-rendered case — a custom element carries its own.
|
|
21
|
+
backAction?: (() => void) | ReactNode
|
|
15
22
|
backActionAccessibilityLabel?: string
|
|
16
23
|
backActionFixed?: boolean
|
|
17
24
|
caption?: string
|
|
@@ -41,17 +48,24 @@ const ActionBg = ({ blur, style }: ActionBgProps) =>
|
|
|
41
48
|
)
|
|
42
49
|
|
|
43
50
|
export const ScrollViewHeader = ({ actionSize = 48, actionStyle, backAction, backActionAccessibilityLabel, backActionFixed, caption, centerContent, children, iconSize, style, title, topInset = true, trailingAction, trailingActionFixed = true }: ScrollViewHeaderProps) => {
|
|
44
|
-
const { blur, headerHeight, headerFixed, headerOffset, progress, progressing, pullSearchHeightShared, scrollPosition, setHeaderHeight, snapBackHeaderShared } = useContext(ScrollViewContext)
|
|
51
|
+
const { blur, headerHeight, headerFixed, headerHeightShared, headerOffset, progress, progressing, pullSearchHeightShared, scrollPosition, setHeaderHeight, snapBackHeaderShared } = useContext(ScrollViewContext)
|
|
45
52
|
const { settings } = useContext(ScrollViewSettingsContext)
|
|
46
53
|
const effectiveBackActionFixed = backActionFixed ?? settings.backActionFixed
|
|
47
54
|
const insets = useSafeAreaInsets()
|
|
48
55
|
const theme = useTheme()
|
|
49
56
|
const top = topInset ? insets.top : 0
|
|
57
|
+
// Tracks "has this header's own onLayout fired yet" as a SharedValue rather than deriving it from
|
|
58
|
+
// headerHeight (a plain, React-state-backed number) so the worklets below never have to list a
|
|
59
|
+
// value that flips from null to a real measured number in their dependency arrays — see the
|
|
60
|
+
// comment on translateStyle/blurStyle/progressStyle for why that recreation was a real crash, not
|
|
61
|
+
// just a perf concern.
|
|
62
|
+
const measuredShared = useSharedValue(false)
|
|
50
63
|
const handleLayout = ({
|
|
51
64
|
nativeEvent: {
|
|
52
65
|
layout: { height }
|
|
53
66
|
}
|
|
54
67
|
}: LayoutChangeEvent) => {
|
|
68
|
+
measuredShared.value = true
|
|
55
69
|
if (headerHeight !== height) setHeaderHeight(height)
|
|
56
70
|
}
|
|
57
71
|
const actionMargin = 4
|
|
@@ -61,33 +75,39 @@ export const ScrollViewHeader = ({ actionSize = 48, actionStyle, backAction, bac
|
|
|
61
75
|
// pattern) — used as the blur backdrop's own height for that same pre-measurement window, so it
|
|
62
76
|
// doesn't render as a flat, unblurred box for the ~60-80ms an onLayout round trip takes on web.
|
|
63
77
|
const unmeasuredHeight = top + contentMinHeight
|
|
64
|
-
// Every one of these worklets reads
|
|
65
|
-
// headerOffset, pullSearchHeightShared
|
|
66
|
-
//
|
|
67
|
-
//
|
|
68
|
-
//
|
|
69
|
-
//
|
|
70
|
-
//
|
|
78
|
+
// Every one of these worklets reads SharedValues only (scrollPosition, snapBackHeaderShared,
|
|
79
|
+
// headerOffset, pullSearchHeightShared, headerHeightShared, measuredShared) — deliberately NOT the
|
|
80
|
+
// plain `headerHeight` context value, even though it holds the same number. `headerHeight` is a
|
|
81
|
+
// React-state-backed `number | null` that changes identity on every measurement (starting at null,
|
|
82
|
+
// then flipping to a real pixel value within a frame of mount); putting it in a useAnimatedStyle
|
|
83
|
+
// dependency array forces Reanimated to tear down and recreate the worklet the moment that happens
|
|
84
|
+
// — which crashed outright ("[Worklets] Tried to synchronously call a Remote Function") on
|
|
85
|
+
// react-native-worklets 0.10.1. SharedValues never change identity, only their `.value`, so they're
|
|
86
|
+
// safe to depend on and don't retrigger this. They still have to be LISTED here despite that: on
|
|
87
|
+
// web, without the Reanimated Babel plugin's automatic worklet dependency capture, a SharedValue's
|
|
88
|
+
// mutations aren't picked up as reactive unless its reference appears in this array — omitting one
|
|
89
|
+
// silently freezes that value's contribution to the header/blur/progress-bar's scroll tracking at
|
|
90
|
+
// whatever it was when the array last changed.
|
|
71
91
|
const translateStyle = useAnimatedStyle(() => {
|
|
72
92
|
if (headerFixed) return { transform: [{ translateY: 0 }] }
|
|
73
93
|
if (snapBackHeaderShared.value) return { transform: [{ translateY: headerOffset.value }] }
|
|
74
|
-
const effective = scrollPosition.value +
|
|
94
|
+
const effective = scrollPosition.value + headerHeightShared.value - pullSearchHeightShared.value
|
|
75
95
|
if (effective <= 0) return { transform: [{ translateY: 0 }] }
|
|
76
96
|
return { transform: [{ translateY: -effective }] }
|
|
77
|
-
}, [headerFixed,
|
|
97
|
+
}, [headerFixed, headerHeightShared, headerOffset, pullSearchHeightShared, scrollPosition, snapBackHeaderShared])
|
|
78
98
|
const blurStyle = useAnimatedStyle(() => {
|
|
79
|
-
if (
|
|
80
|
-
if (!
|
|
81
|
-
if (headerFixed) return { height:
|
|
82
|
-
const translateY = snapBackHeaderShared.value ? headerOffset.value : -Math.max(0, scrollPosition.value +
|
|
83
|
-
return { height: Math.max(
|
|
84
|
-
}, [headerFixed,
|
|
99
|
+
if (!measuredShared.value) return { height: unmeasuredHeight }
|
|
100
|
+
if (!headerHeightShared.value) return { height: 0 }
|
|
101
|
+
if (headerFixed) return { height: headerHeightShared.value }
|
|
102
|
+
const translateY = snapBackHeaderShared.value ? headerOffset.value : -Math.max(0, scrollPosition.value + headerHeightShared.value - pullSearchHeightShared.value)
|
|
103
|
+
return { height: Math.max(headerHeightShared.value + translateY, top) }
|
|
104
|
+
}, [headerFixed, top, unmeasuredHeight, measuredShared, headerHeightShared, headerOffset, pullSearchHeightShared, scrollPosition, snapBackHeaderShared])
|
|
85
105
|
const progressStyle = useAnimatedStyle(() => {
|
|
86
|
-
const h =
|
|
106
|
+
const h = headerHeightShared.value
|
|
87
107
|
if (headerFixed) return { top: h }
|
|
88
108
|
const slide = snapBackHeaderShared.value ? -headerOffset.value : Math.max(0, scrollPosition.value + h - pullSearchHeightShared.value)
|
|
89
109
|
return { top: Math.max(h - slide, top) }
|
|
90
|
-
}, [headerFixed,
|
|
110
|
+
}, [headerFixed, headerHeightShared, top, headerOffset, pullSearchHeightShared, scrollPosition, snapBackHeaderShared])
|
|
91
111
|
const actionTop = top + actionMargin
|
|
92
112
|
const buttonStyle = { borderRadius: actionSize, height: actionSize, margin: 0, width: actionSize }
|
|
93
113
|
const actionShadow = { borderRadius: actionSize / 2, elevation: 2, shadowColor: '#000', shadowOffset: { width: 0, height: 1 }, shadowOpacity: 0.15, shadowRadius: 2 }
|
|
@@ -134,12 +154,12 @@ export const ScrollViewHeader = ({ actionSize = 48, actionStyle, backAction, bac
|
|
|
134
154
|
(effectiveBackActionFixed ? (
|
|
135
155
|
<Animated.View style={leadingStyle}>
|
|
136
156
|
<ActionBg blur={blur} style={actionStyle} />
|
|
137
|
-
<Appbar.BackAction accessibilityLabel={backActionAccessibilityLabel} onPress={backAction} size={iconSize ?? actionSize / 2} style={buttonStyle} />
|
|
157
|
+
{typeof backAction === 'function' ? <Appbar.BackAction accessibilityLabel={backActionAccessibilityLabel} onPress={backAction} size={iconSize ?? actionSize / 2} style={buttonStyle} /> : backAction}
|
|
138
158
|
</Animated.View>
|
|
139
159
|
) : (
|
|
140
160
|
<Animated.View style={[leadingStyle, translateStyle]}>
|
|
141
161
|
<ActionBg blur={blur} style={actionStyle} />
|
|
142
|
-
<Appbar.BackAction accessibilityLabel={backActionAccessibilityLabel} onPress={backAction} size={iconSize ?? actionSize / 2} style={buttonStyle} />
|
|
162
|
+
{typeof backAction === 'function' ? <Appbar.BackAction accessibilityLabel={backActionAccessibilityLabel} onPress={backAction} size={iconSize ?? actionSize / 2} style={buttonStyle} /> : backAction}
|
|
143
163
|
</Animated.View>
|
|
144
164
|
))}
|
|
145
165
|
{trailingAction &&
|
|
@@ -26,7 +26,7 @@ export const ScrollViewProvider = ({ blur, children, fixed = false, footerAboveK
|
|
|
26
26
|
const effectiveSnapBackHeader = snapBackHeader ?? settings.snapBackHeader
|
|
27
27
|
const effectiveSnapBackFooter = snapBackFooter ?? settings.snapBackFooter
|
|
28
28
|
const [headerHeight, setHeaderHeightState] = useState<number | null>(null)
|
|
29
|
-
const [footerHeight, setFooterHeightState] = useState(
|
|
29
|
+
const [footerHeight, setFooterHeightState] = useState<number | null>(null)
|
|
30
30
|
const [progress, setProgress] = useState<number | null>(null)
|
|
31
31
|
const [progressing, setProgressing] = useState(false)
|
|
32
32
|
const scrollPosition = useSharedValue(0)
|
|
@@ -71,13 +71,20 @@ export const ScrollViewProvider = ({ blur, children, fixed = false, footerAboveK
|
|
|
71
71
|
return () => clearTimeout(timeout)
|
|
72
72
|
}, [headerHeight])
|
|
73
73
|
const setFooterHeight = useCallback(
|
|
74
|
-
(h: number) => {
|
|
74
|
+
(h: number | null) => {
|
|
75
|
+
// Same race setHeaderHeight guards against, on the footer side: react-native-screens' web
|
|
76
|
+
// shim (and a footer's own unmount cleanup below, which now passes null instead of 0 for
|
|
77
|
+
// exactly this reason) can report/force a spurious 0 while a real footer is effectively
|
|
78
|
+
// still on screen (e.g. a wizard cycling through several <ScrollViewFooter> instances).
|
|
79
|
+
// Never let that clobber a known height — only an explicit null (genuinely no footer
|
|
80
|
+
// mounted) may reset it.
|
|
81
|
+
if (h === 0 && footerHeight) return
|
|
75
82
|
setFooterHeightState(h)
|
|
76
|
-
footerHeightShared.value = h
|
|
83
|
+
footerHeightShared.value = h ?? 0
|
|
77
84
|
},
|
|
78
|
-
[footerHeightShared]
|
|
85
|
+
[footerHeight, footerHeightShared]
|
|
79
86
|
)
|
|
80
|
-
const scrollHeight = useMemo(() => Dimensions.get('window').height - (headerHeight ?? 0) - footerHeight, [headerHeight, footerHeight])
|
|
87
|
+
const scrollHeight = useMemo(() => Dimensions.get('window').height - (headerHeight ?? 0) - (footerHeight ?? 0), [headerHeight, footerHeight])
|
|
81
88
|
const effectiveHeaderFixed = fixed || (headerFixed ?? settings.headerFixed)
|
|
82
89
|
const effectiveFooterFixed = fixed || (footerFixed ?? settings.footerFixed)
|
|
83
90
|
const value = useMemo(() => ({ blur: effectiveBlur, footerAboveKeyboard, 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, footerAboveKeyboard, effectiveFooterFixed, effectiveHeaderFixed, footerHeight, footerHeightShared, footerOffset, headerHeight, headerHeightShared, headerOffset, jsListGeneration, listGeneration, onJsListUnmount, onListUnmount, progress, pullSearchHeightShared, progressing, scrollHeight, scrollPosition, setFooterHeight, setHeaderHeight, snapBackFooterShared, snapBackHeaderShared, tabBarHeight])
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import { Chip, type ChipProps as AutoPaperChipProps } from '@rific/auto-paper'
|
|
2
2
|
import { type ReactNode } from 'react'
|
|
3
3
|
import { StyleSheet, type ViewStyle } from 'react-native'
|
|
4
|
+
import { Icon, useTheme } from 'react-native-paper'
|
|
4
5
|
import Animated, { type AnimatedStyle } from 'react-native-reanimated'
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
// 'children' omitted alongside the rest — this chip's own text always comes from `label` (or the
|
|
8
|
+
// isHorizontal-driven 'Start'/'Top' default below), passed as the real JSX children the underlying
|
|
9
|
+
// Chip renders with, which is what actually wins: React always takes the children an element is
|
|
10
|
+
// given between its tags over one merely passed as a "children" prop via spread. A `children` in
|
|
11
|
+
// chipProps would therefore type-check but silently do nothing at runtime — omitting it here means
|
|
12
|
+
// TypeScript catches that mismatch instead of a caller finding out the hard way.
|
|
13
|
+
export type ChipProps = Omit<AutoPaperChipProps, 'compact' | 'icon' | 'onPress' | 'children'> & {
|
|
7
14
|
label?: ReactNode
|
|
8
15
|
}
|
|
9
16
|
|
|
@@ -16,16 +23,27 @@ type Props = {
|
|
|
16
23
|
}
|
|
17
24
|
|
|
18
25
|
export const ScrollViewChip = ({ chipProps, isHorizontal, onChipPress, onPress, style }: Props) => {
|
|
19
|
-
const {
|
|
26
|
+
const { colors } = useTheme()
|
|
27
|
+
const { label, selectedColor, style: chipStyle, ...restChipProps } = (chipProps ?? {}) as Partial<ChipProps>
|
|
20
28
|
const handlePress = onChipPress
|
|
21
29
|
? () => {
|
|
22
30
|
onPress()
|
|
23
31
|
onChipPress()
|
|
24
32
|
}
|
|
25
33
|
: onPress
|
|
34
|
+
// Rendered via `avatar`, not Chip's own `icon` prop: react-native-paper's MD3 Chip hardcodes
|
|
35
|
+
// `icon`'s color to theme.colors.primary and ignores `selectedColor` entirely (its own doc
|
|
36
|
+
// comment: "With theme version 3 selectedColor doesn't apply to the icon. If you want [a]
|
|
37
|
+
// custom color for the icon, render your own Icon component") — a chip whose own background
|
|
38
|
+
// IS theme.colors.primary (this library's callers all set that; see Hangman's own vivid-chip
|
|
39
|
+
// convention) renders that icon invisible against itself. `avatar` has no such override; it
|
|
40
|
+
// clones whatever element/color it's given. Falls back to the same default Paper itself would
|
|
41
|
+
// resolve for unselected/non-outlined text (onSecondaryContainer) or outlined text
|
|
42
|
+
// (onSurfaceVariant), so the icon still matches the label color when no selectedColor is set.
|
|
43
|
+
const iconColor = selectedColor ?? (restChipProps.mode === 'outlined' ? colors.onSurfaceVariant : colors.onSecondaryContainer)
|
|
26
44
|
return (
|
|
27
45
|
<Animated.View style={[styles.chip, style]}>
|
|
28
|
-
<Chip compact {...restChipProps}
|
|
46
|
+
<Chip compact selectedColor={selectedColor} {...restChipProps} avatar={<Icon source={isHorizontal ? 'chevron-left' : 'chevron-up'} size={18} color={iconColor} />} onPress={handlePress} style={[styles.chipInner, chipStyle]}>
|
|
29
47
|
{label ?? (isHorizontal ? 'Start' : 'Top')}
|
|
30
48
|
</Chip>
|
|
31
49
|
</Animated.View>
|
|
@@ -25,7 +25,7 @@ export type UseScrollListOptions = {
|
|
|
25
25
|
export function useScrollList({ footerFixed: footerFixedProp, headerFixed: headerFixedProp, hideUntilMeasured, isHorizontal, keyboardAware, pullSearchHeight, style }: UseScrollListOptions = {}) {
|
|
26
26
|
const insets = useSafeAreaInsets()
|
|
27
27
|
const keyboardHeight = useKeyboardInset()
|
|
28
|
-
const { footerAboveKeyboard, footerHeight, footerFixed: contextFooterFixed, headerHeight, headerFixed: contextHeaderFixed, headerOffset, pullSearchHeightShared, scrollPosition, snapBackHeaderShared, tabBarHeight } = useContext(ScrollViewContext)
|
|
28
|
+
const { footerAboveKeyboard, footerHeight, footerFixed: contextFooterFixed, headerHeight, headerHeightShared, headerFixed: contextHeaderFixed, headerOffset, pullSearchHeightShared, scrollPosition, snapBackHeaderShared, tabBarHeight } = useContext(ScrollViewContext)
|
|
29
29
|
|
|
30
30
|
const headerFixed = isHorizontal ? true : (headerFixedProp ?? contextHeaderFixed)
|
|
31
31
|
const footerFixed = isHorizontal ? true : (footerFixedProp ?? contextFooterFixed)
|
|
@@ -79,21 +79,25 @@ export function useScrollList({ footerFixed: footerFixedProp, headerFixed: heade
|
|
|
79
79
|
const contentOffset = usesContentInset ? insetContentOffset : ZERO_OFFSET
|
|
80
80
|
|
|
81
81
|
const chipHidden = useSharedValue(1)
|
|
82
|
-
// chipHidden/snapBackHeaderShared/headerOffset/scrollPosition/pullSearchHeightShared
|
|
83
|
-
// be listed here too, not just read — see ScrollViewHeader's
|
|
84
|
-
// reanimated reactivity gap: a SharedValue's mutations don't
|
|
85
|
-
// the value itself is in this array).
|
|
82
|
+
// chipHidden/snapBackHeaderShared/headerOffset/scrollPosition/pullSearchHeightShared/
|
|
83
|
+
// headerHeightShared all need to be listed here too, not just read — see ScrollViewHeader's
|
|
84
|
+
// translateStyle for why (web-only reanimated reactivity gap: a SharedValue's mutations don't
|
|
85
|
+
// retrigger useAnimatedStyle unless the value itself is in this array). headerHeightShared is
|
|
86
|
+
// used here rather than the plain `headerHeight` context value specifically because the latter
|
|
87
|
+
// changes identity (null -> a real number) shortly after mount, which forces Reanimated to
|
|
88
|
+
// recreate this worklet — a crash on react-native-worklets 0.10.1, not just a perf concern. See
|
|
89
|
+
// ScrollViewHeader's translateStyle/blurStyle/progressStyle for the full explanation.
|
|
86
90
|
const chipStyle = useAnimatedStyle(() => {
|
|
87
91
|
const pointerEvents = chipHidden.value ? ('none' as const) : ('box-none' as const)
|
|
88
92
|
if (isHorizontal) {
|
|
89
93
|
return {
|
|
90
94
|
opacity: chipHidden.value ? withTiming(0) : withTiming(1),
|
|
91
95
|
pointerEvents,
|
|
92
|
-
top: Math.max(
|
|
96
|
+
top: Math.max(headerHeightShared.value, insets.top) + 4,
|
|
93
97
|
transform: [{ translateX: chipHidden.value ? withTiming(-CHIP_SLIDE) : withTiming(0) }]
|
|
94
98
|
}
|
|
95
99
|
}
|
|
96
|
-
const h =
|
|
100
|
+
const h = headerHeightShared.value
|
|
97
101
|
const slide = headerFixed ? 0 : snapBackHeaderShared.value ? -headerOffset.value : Math.max(0, scrollPosition.value + h - pullSearchHeightShared.value)
|
|
98
102
|
const top = Math.max(h - slide, insets.top) + 4
|
|
99
103
|
return {
|
|
@@ -102,7 +106,7 @@ export function useScrollList({ footerFixed: footerFixedProp, headerFixed: heade
|
|
|
102
106
|
top,
|
|
103
107
|
transform: [{ translateY: chipHidden.value ? withTiming(-CHIP_SLIDE) : withTiming(0) }]
|
|
104
108
|
}
|
|
105
|
-
}, [isHorizontal, headerFixed,
|
|
109
|
+
}, [isHorizontal, headerFixed, headerHeightShared, insets.top, chipHidden, snapBackHeaderShared, headerOffset, scrollPosition, pullSearchHeightShared])
|
|
106
110
|
|
|
107
111
|
return { chipHidden, chipStyle, containerStyle, contentInset, contentOffset, contentPadding, footerFixed, headerFixed, headerHeight, insets, isHorizontal: isHorizontal ?? false }
|
|
108
112
|
}
|