@hero-design/rn 8.128.3 → 8.129.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hero-design/rn",
3
- "version": "8.128.3",
3
+ "version": "8.129.0",
4
4
  "license": "MIT",
5
5
  "main": "lib/index.js",
6
6
  "module": "es/index.js",
@@ -5,11 +5,11 @@ import {
5
5
  Animated,
6
6
  KeyboardAvoidingView,
7
7
  Pressable,
8
- SafeAreaView,
9
8
  StyleSheet,
10
9
  TouchableOpacity,
11
10
  View,
12
11
  } from 'react-native';
12
+ import { SafeAreaView } from 'react-native-safe-area-context';
13
13
 
14
14
  const AnimatedPressable = Animated.createAnimatedComponent(Pressable);
15
15
  const AnimatedSafeAreaView = Animated.createAnimatedComponent(SafeAreaView);
@@ -0,0 +1,32 @@
1
+ import { createContext, useContext } from 'react';
2
+ import type { MutableRefObject } from 'react';
3
+
4
+ interface DragableDrawerContextValue {
5
+ /** Whether the drawer has settled at maximum height (offset === 0). */
6
+ isAtMaxHeight: boolean;
7
+ /** Current vertical scroll offset reported by DragableScrollView. */
8
+ scrollYRef: MutableRefObject<number>;
9
+ /** Report scroll offset changes from DragableScrollView. */
10
+ onScrollY: (y: number) => void;
11
+ /** Begin a drawer pan gesture (stops any running animation). */
12
+ beginPan: () => void;
13
+ /** Move the drawer by dy pixels during an active pan. */
14
+ movePan: (dy: number) => void;
15
+ /** End pan and snap to the nearest snap point. */
16
+ releasePan: (dy: number, vy: number) => void;
17
+ }
18
+
19
+ const noop = () => ({});
20
+
21
+ const DragableDrawerContext = createContext<DragableDrawerContextValue>({
22
+ isAtMaxHeight: false,
23
+ scrollYRef: { current: 0 },
24
+ onScrollY: noop,
25
+ beginPan: noop,
26
+ movePan: noop,
27
+ releasePan: noop,
28
+ });
29
+
30
+ export const useDragableDrawerContext = () => useContext(DragableDrawerContext);
31
+
32
+ export default DragableDrawerContext;
@@ -0,0 +1,113 @@
1
+ import React, { useRef } from 'react';
2
+ import { PanResponder, ScrollView, View } from 'react-native';
3
+ import type {
4
+ NativeScrollEvent,
5
+ NativeSyntheticEvent,
6
+ ScrollViewProps,
7
+ } from 'react-native';
8
+ import type { ReactElement } from 'react';
9
+
10
+ import { useDragableDrawerContext } from './DragableDrawerContext';
11
+
12
+ export type DragableScrollViewProps = ScrollViewProps;
13
+
14
+ // scrollY tolerance: treat anything within this many pixels of the top as
15
+ // "at scroll top" to handle fractional pixels and throttled scroll events.
16
+ const SCROLL_TOP_THRESHOLD_PX = 5;
17
+ // Minimum downward finger movement before the pull-down collapse is triggered.
18
+ const PULL_DOWN_THRESHOLD_PX = 10;
19
+ const DEFAULT_SCROLL_EVENT_THROTTLE = 16;
20
+
21
+ /**
22
+ * A ScrollView that coordinates with a parent DragableDrawer.
23
+ *
24
+ * - Drawer below max height: all gestures move the drawer; scroll is locked.
25
+ * - Drawer at max height: native scrolling works normally.
26
+ * - Drawer at max + scrolled to top + pull down: drawer collapses.
27
+ *
28
+ * The native ScrollView with bounces={false}/overScrollMode="never" will not
29
+ * intercept a downward gesture at scrollY=0 (nothing left to scroll), so
30
+ * onMoveShouldSetPanResponderCapture fires cleanly on both platforms.
31
+ * onScrollEndDrag + onMomentumScrollEnd ensure scrollYRef is up-to-date
32
+ * before the next gesture starts.
33
+ */
34
+ const DragableScrollView = ({
35
+ onScroll,
36
+ onScrollEndDrag: onScrollEndDragProp,
37
+ onMomentumScrollEnd: onMomentumScrollEndProp,
38
+ scrollEventThrottle = DEFAULT_SCROLL_EVENT_THROTTLE,
39
+ children,
40
+ ...props
41
+ }: DragableScrollViewProps): ReactElement => {
42
+ const {
43
+ isAtMaxHeight,
44
+ scrollYRef,
45
+ onScrollY,
46
+ beginPan,
47
+ movePan,
48
+ releasePan,
49
+ } = useDragableDrawerContext();
50
+
51
+ // Mirror context value into a ref so PanResponder closures always read
52
+ // the latest value (PanResponder is created once and closures are frozen).
53
+ const isAtMaxHeightRef = useRef(isAtMaxHeight);
54
+ isAtMaxHeightRef.current = isAtMaxHeight;
55
+
56
+ const panResponder = useRef(
57
+ PanResponder.create({
58
+ // Drawer below max: capture on start so the native ScrollView never
59
+ // gets the touch and scroll is completely locked.
60
+ onStartShouldSetPanResponderCapture: () => !isAtMaxHeightRef.current,
61
+
62
+ // Drawer at max + scroll at top + pull down: recapture for collapse.
63
+ // bounces={false} / overScrollMode="never" means the native ScrollView
64
+ // has nothing to do here, so it will not intercept the gesture and this
65
+ // capture fires reliably before any scroll activity begins.
66
+ onMoveShouldSetPanResponderCapture: (_, gesture) =>
67
+ isAtMaxHeightRef.current &&
68
+ scrollYRef.current <= SCROLL_TOP_THRESHOLD_PX &&
69
+ gesture.dy > PULL_DOWN_THRESHOLD_PX,
70
+
71
+ onPanResponderGrant: () => beginPan(),
72
+ onPanResponderMove: (_, gesture) => movePan(gesture.dy),
73
+ onPanResponderRelease: (_, gesture) => releasePan(gesture.dy, gesture.vy),
74
+ })
75
+ ).current;
76
+
77
+ const handleScroll = (e: NativeSyntheticEvent<NativeScrollEvent>) => {
78
+ onScrollY(e.nativeEvent.contentOffset.y);
79
+ onScroll?.(e);
80
+ };
81
+
82
+ // Keep scrollYRef accurate at every scroll boundary so the next gesture
83
+ // checks the correct position even when onScroll is throttled.
84
+ const handleScrollEndDrag = (e: NativeSyntheticEvent<NativeScrollEvent>) => {
85
+ onScrollY(e.nativeEvent.contentOffset.y);
86
+ onScrollEndDragProp?.(e);
87
+ };
88
+
89
+ const handleMomentumScrollEnd = (
90
+ e: NativeSyntheticEvent<NativeScrollEvent>
91
+ ) => {
92
+ onScrollY(e.nativeEvent.contentOffset.y);
93
+ onMomentumScrollEndProp?.(e);
94
+ };
95
+
96
+ return (
97
+ <View {...panResponder.panHandlers} style={{ flex: 1 }}>
98
+ <ScrollView
99
+ {...props}
100
+ scrollEnabled={isAtMaxHeight}
101
+ onScroll={handleScroll}
102
+ onScrollEndDrag={handleScrollEndDrag}
103
+ onMomentumScrollEnd={handleMomentumScrollEnd}
104
+ scrollEventThrottle={scrollEventThrottle}
105
+ overScrollMode="always"
106
+ >
107
+ {children}
108
+ </ScrollView>
109
+ </View>
110
+ );
111
+ };
112
+
113
+ export default DragableScrollView;
@@ -1,5 +1,4 @@
1
- import React, { useEffect, useRef, useState } from 'react';
2
- import { Animated, PanResponder, Easing, Platform } from 'react-native';
1
+ import React, { useMemo, useState } from 'react';
3
2
 
4
3
  import type { ReactElement, ReactNode } from 'react';
5
4
  import {
@@ -8,12 +7,8 @@ import {
8
7
  StyledHandler,
9
8
  StyledHandlerContainer,
10
9
  } from '../StyledDrawer';
11
- import {
12
- calculateAnimatedToValue,
13
- calculateSnapPointsData,
14
- getOffset,
15
- } from './helpers';
16
- import type { SnapPointsData } from './helpers';
10
+ import DragableDrawerContext from './DragableDrawerContext';
11
+ import useDragablePan from './useDragablePan';
17
12
 
18
13
  export interface DragableDrawerProps {
19
14
  /**
@@ -56,148 +51,60 @@ const DragableDrawer = ({
56
51
  testID,
57
52
  }: DragableDrawerProps): ReactElement => {
58
53
  const [height, setHeight] = useState(0);
59
- const baseHeightForMeasure = useRef(0);
60
- const snapPointsData = useRef<SnapPointsData>({
61
- list: [],
62
- minHeightOffset: 0,
63
- maxHeightOffset: 0,
64
- });
65
-
66
- // Track drag
67
- const pan = useRef(new Animated.Value(0)).current;
68
- const offset = useRef(0);
69
- const offsetBeforePan = useRef(0);
70
- const [animatedToValue, setAnimatedToValue] = useState<number>(-1);
71
-
72
- useEffect(() => {
73
- const id = pan.addListener(({ value }) => {
74
- offset.current = value;
75
- });
76
-
77
- return () => pan.removeListener(id);
78
- }, []);
79
-
80
- useEffect(() => {
81
- if (height > 0) {
82
- const initialOffset = getOffset(
83
- height,
84
- initialHeightPercentage || minimumHeightPercentage
85
- );
86
- setAnimatedToValue(initialOffset);
87
- }
88
- }, [height]);
89
-
90
- useEffect(() => {
91
- if (height > 0) {
92
- pan.setValue(height);
93
- offset.current = height;
94
-
95
- baseHeightForMeasure.current = height;
96
-
97
- // Calculate snap points information
98
- snapPointsData.current = calculateSnapPointsData(
99
- minimumHeightPercentage,
100
- height,
101
- snapPoints
102
- );
103
- }
104
- }, [height, minimumHeightPercentage]);
105
54
 
106
- useEffect(() => {
107
- if (animatedToValue >= 0) {
108
- const animation = Animated.timing(pan, {
109
- toValue: animatedToValue,
110
- useNativeDriver: Platform.OS !== 'web',
111
- easing: Easing.inOut(Easing.cubic),
112
- });
113
-
114
- animation.start(() => {
115
- if (animatedToValue === 0) {
116
- onExpanded?.();
117
- } else if (
118
- animatedToValue === getOffset(height, minimumHeightPercentage)
119
- ) {
120
- onCollapsed?.();
121
- }
122
- setAnimatedToValue(-1);
123
- });
124
-
125
- return () => animation.stop();
126
- }
127
- }, [animatedToValue]);
128
-
129
- const panResponder = useRef(
130
- PanResponder.create({
131
- onMoveShouldSetPanResponder: () => true,
132
- onPanResponderGrant: () => {
133
- offsetBeforePan.current = offset.current;
134
- pan.setOffset(offset.current);
135
- pan.setValue(0);
136
- },
137
- onPanResponderMove: (_, gesture) => {
138
- const panDistance = gesture.dy;
139
-
140
- // Moving toward top, stop at highest snap point
141
- if (offsetBeforePan.current + panDistance < 0) {
142
- pan.setValue(-offsetBeforePan.current);
143
- return;
144
- }
145
-
146
- // Moving toward bottom, stop at lowest snap point
147
- if (
148
- offsetBeforePan.current + panDistance >
149
- snapPointsData.current?.minHeightOffset
150
- ) {
151
- pan.setValue(
152
- baseHeightForMeasure.current -
153
- baseHeightForMeasure.current * (minimumHeightPercentage / 100) -
154
- offsetBeforePan.current
155
- );
156
- return;
157
- }
158
-
159
- pan.setValue(panDistance);
160
- },
161
- onPanResponderRelease: (_, gesture) => {
162
- pan.flattenOffset();
163
-
164
- // Attach to nearest snappoint
165
- const panDistance = gesture.dy;
166
- const offsetAfterPan = offsetBeforePan.current + panDistance;
167
- const animatedValue = calculateAnimatedToValue(
168
- offsetAfterPan,
169
- snapPointsData.current.list
170
- );
55
+ const {
56
+ pan,
57
+ isAtMaxHeight,
58
+ scrollYRef,
59
+ onScrollY,
60
+ beginPan,
61
+ movePan,
62
+ releasePan,
63
+ panHandlers,
64
+ } = useDragablePan({
65
+ height,
66
+ initialHeightPercentage,
67
+ minimumHeightPercentage,
68
+ snapPoints,
69
+ onExpanded,
70
+ onCollapsed,
71
+ });
171
72
 
172
- setAnimatedToValue(animatedValue);
173
- },
174
- })
175
- ).current;
73
+ const contextValue = useMemo(
74
+ () => ({
75
+ isAtMaxHeight,
76
+ scrollYRef,
77
+ onScrollY,
78
+ beginPan,
79
+ movePan,
80
+ releasePan,
81
+ }),
82
+ [isAtMaxHeight, onScrollY, beginPan, movePan, releasePan]
83
+ );
176
84
 
177
85
  return (
178
- <StyledDragableContainer
179
- testID={testID}
180
- enableShadow
181
- pointerEvents="box-none"
182
- >
183
- <StyledDragableDrawerContainer
86
+ <DragableDrawerContext.Provider value={contextValue}>
87
+ <StyledDragableContainer
88
+ testID={testID}
184
89
  enableShadow
185
- style={{
186
- transform: [
187
- { scaleY: baseHeightForMeasure.current > 0 ? 1 : 0 },
188
- { translateY: pan },
189
- ],
190
- }}
191
- onLayout={({ nativeEvent }) => {
192
- setHeight(nativeEvent.layout.height);
193
- }}
90
+ pointerEvents="box-none"
194
91
  >
195
- <StyledHandlerContainer {...panResponder.panHandlers}>
196
- <StyledHandler />
197
- </StyledHandlerContainer>
198
- {children}
199
- </StyledDragableDrawerContainer>
200
- </StyledDragableContainer>
92
+ <StyledDragableDrawerContainer
93
+ enableShadow
94
+ style={{
95
+ transform: [{ scaleY: height > 0 ? 1 : 0 }, { translateY: pan }],
96
+ }}
97
+ onLayout={({ nativeEvent }) => {
98
+ setHeight(nativeEvent.layout.height);
99
+ }}
100
+ >
101
+ <StyledHandlerContainer {...panHandlers}>
102
+ <StyledHandler />
103
+ </StyledHandlerContainer>
104
+ {children}
105
+ </StyledDragableDrawerContainer>
106
+ </StyledDragableContainer>
107
+ </DragableDrawerContext.Provider>
201
108
  );
202
109
  };
203
110
 
@@ -0,0 +1,223 @@
1
+ import { useCallback, useEffect, useRef, useState } from 'react';
2
+ import type { MutableRefObject } from 'react';
3
+ import { Animated, Easing, PanResponder, Platform } from 'react-native';
4
+ import type { GestureResponderHandlers } from 'react-native';
5
+
6
+ import {
7
+ calculateAnimatedToValue,
8
+ calculateSnapPointsData,
9
+ getOffset,
10
+ } from './helpers';
11
+ import type { SnapPointsData } from './helpers';
12
+
13
+ const FLICK_VELOCITY_THRESHOLD = 0.3;
14
+ const SHORT_DRAG_THRESHOLD_PX = 20;
15
+ const VELOCITY_PROJECTION_FACTOR = 200;
16
+
17
+ interface UseDragablePanOptions {
18
+ height: number;
19
+ initialHeightPercentage: number | undefined;
20
+ minimumHeightPercentage: number;
21
+ snapPoints: number[];
22
+ onExpanded?: () => void;
23
+ onCollapsed?: () => void;
24
+ }
25
+
26
+ interface UseDragablePanResult {
27
+ pan: Animated.Value;
28
+ isAtMaxHeight: boolean;
29
+ scrollYRef: MutableRefObject<number>;
30
+ onScrollY: (y: number) => void;
31
+ beginPan: () => void;
32
+ movePan: (dy: number) => void;
33
+ releasePan: (dy: number, vy: number) => void;
34
+ panHandlers: GestureResponderHandlers;
35
+ }
36
+
37
+ const useDragablePan = ({
38
+ height,
39
+ initialHeightPercentage,
40
+ minimumHeightPercentage,
41
+ snapPoints,
42
+ onExpanded,
43
+ onCollapsed,
44
+ }: UseDragablePanOptions): UseDragablePanResult => {
45
+ const baseHeightForMeasure = useRef(0);
46
+ const snapPointsData = useRef<SnapPointsData>({
47
+ list: [],
48
+ minHeightOffset: 0,
49
+ maxHeightOffset: 0,
50
+ });
51
+
52
+ const pan = useRef(new Animated.Value(0)).current;
53
+ const offset = useRef(0);
54
+ const offsetBeforePan = useRef(0);
55
+ const [animatedToValue, setAnimatedToValue] = useState<number>(-1);
56
+
57
+ const [isAtMaxHeight, setIsAtMaxHeight] = useState(false);
58
+ const scrollYRef = useRef(0);
59
+ const minimumHeightPercentageRef = useRef(minimumHeightPercentage);
60
+ minimumHeightPercentageRef.current = minimumHeightPercentage;
61
+
62
+ const onScrollY = useCallback((y: number) => {
63
+ scrollYRef.current = y;
64
+ }, []);
65
+
66
+ useEffect(() => {
67
+ const id = pan.addListener(({ value }) => {
68
+ offset.current = value;
69
+ });
70
+
71
+ return () => pan.removeListener(id);
72
+ }, []);
73
+
74
+ useEffect(() => {
75
+ if (height > 0) {
76
+ const initialOffset = getOffset(
77
+ height,
78
+ initialHeightPercentage || minimumHeightPercentage
79
+ );
80
+ setAnimatedToValue(initialOffset);
81
+ }
82
+ }, [height, initialHeightPercentage, minimumHeightPercentage]);
83
+
84
+ useEffect(() => {
85
+ if (height > 0) {
86
+ pan.setValue(height);
87
+ offset.current = height;
88
+
89
+ baseHeightForMeasure.current = height;
90
+
91
+ snapPointsData.current = calculateSnapPointsData(
92
+ minimumHeightPercentage,
93
+ height,
94
+ snapPoints
95
+ );
96
+ }
97
+ }, [height, minimumHeightPercentage]);
98
+
99
+ useEffect(() => {
100
+ if (animatedToValue >= 0) {
101
+ const animation = Animated.timing(pan, {
102
+ toValue: animatedToValue,
103
+ useNativeDriver: Platform.OS !== 'web',
104
+ easing: Easing.inOut(Easing.cubic),
105
+ });
106
+
107
+ animation.start(({ finished }) => {
108
+ if (finished) {
109
+ if (animatedToValue === 0) {
110
+ setIsAtMaxHeight(true);
111
+ onExpanded?.();
112
+ } else {
113
+ setIsAtMaxHeight(false);
114
+ if (
115
+ animatedToValue === getOffset(height, minimumHeightPercentage)
116
+ ) {
117
+ onCollapsed?.();
118
+ }
119
+ }
120
+ }
121
+ setAnimatedToValue(-1);
122
+ });
123
+
124
+ return () => animation.stop();
125
+ }
126
+ }, [
127
+ animatedToValue,
128
+ onExpanded,
129
+ onCollapsed,
130
+ height,
131
+ minimumHeightPercentage,
132
+ ]);
133
+
134
+ const beginPan = useCallback(() => {
135
+ pan.stopAnimation();
136
+ setIsAtMaxHeight(false);
137
+ offsetBeforePan.current = offset.current;
138
+ pan.setOffset(offset.current);
139
+ pan.setValue(0);
140
+ }, []);
141
+
142
+ const movePan = useCallback((dy: number) => {
143
+ // Moving toward top, stop at highest snap point
144
+ if (offsetBeforePan.current + dy < 0) {
145
+ pan.setValue(-offsetBeforePan.current);
146
+ return;
147
+ }
148
+
149
+ // Moving toward bottom, stop at lowest snap point
150
+ if (
151
+ offsetBeforePan.current + dy >
152
+ snapPointsData.current?.minHeightOffset
153
+ ) {
154
+ pan.setValue(
155
+ baseHeightForMeasure.current -
156
+ baseHeightForMeasure.current *
157
+ (minimumHeightPercentageRef.current / 100) -
158
+ offsetBeforePan.current
159
+ );
160
+ return;
161
+ }
162
+
163
+ pan.setValue(dy);
164
+ }, []);
165
+
166
+ const releasePan = useCallback((dy: number, vy: number) => {
167
+ pan.flattenOffset();
168
+
169
+ const offsetAfterPan = offsetBeforePan.current + dy;
170
+
171
+ // Flick or short downward drag: snap to the next lower snap point.
172
+ if (vy > FLICK_VELOCITY_THRESHOLD || dy > SHORT_DRAG_THRESHOLD_PX) {
173
+ const lowerPoints = snapPointsData.current.list
174
+ .filter((p) => p > offsetBeforePan.current)
175
+ .sort((a, b) => a - b);
176
+ if (lowerPoints.length > 0) {
177
+ setAnimatedToValue(lowerPoints[0]);
178
+ return;
179
+ }
180
+ }
181
+
182
+ // Upward flick or drag: project the intended landing position using
183
+ // velocity, then snap to the nearest higher snap point to that projection.
184
+ // This allows fast flicks to skip intermediate snap points.
185
+ if (vy < -FLICK_VELOCITY_THRESHOLD || dy < -SHORT_DRAG_THRESHOLD_PX) {
186
+ const projected = offsetAfterPan + vy * VELOCITY_PROJECTION_FACTOR;
187
+ const higherPoints = snapPointsData.current.list
188
+ .filter((p) => p < offsetBeforePan.current)
189
+ .sort((a, b) => b - a);
190
+ if (higherPoints.length > 0) {
191
+ setAnimatedToValue(calculateAnimatedToValue(projected, higherPoints));
192
+ return;
193
+ }
194
+ }
195
+
196
+ // Otherwise: snap to nearest.
197
+ setAnimatedToValue(
198
+ calculateAnimatedToValue(offsetAfterPan, snapPointsData.current.list)
199
+ );
200
+ }, []);
201
+
202
+ const panResponder = useRef(
203
+ PanResponder.create({
204
+ onMoveShouldSetPanResponder: () => true,
205
+ onPanResponderGrant: () => beginPan(),
206
+ onPanResponderMove: (_, gesture) => movePan(gesture.dy),
207
+ onPanResponderRelease: (_, gesture) => releasePan(gesture.dy, gesture.vy),
208
+ })
209
+ ).current;
210
+
211
+ return {
212
+ pan,
213
+ isAtMaxHeight,
214
+ scrollYRef,
215
+ onScrollY,
216
+ beginPan,
217
+ movePan,
218
+ releasePan,
219
+ panHandlers: panResponder.panHandlers,
220
+ };
221
+ };
222
+
223
+ export default useDragablePan;
@@ -57,7 +57,7 @@ const StyledDragableDrawerContainer = styled(Animated.View)<{
57
57
  backgroundColor: theme.__hd__.drawer.colors.background,
58
58
  elevation: enableShadow ? theme.__hd__.drawer.shadows.elevation : undefined,
59
59
  overflow: 'hidden',
60
- maxHeight: '100%',
60
+ height: '100%',
61
61
  }));
62
62
 
63
63
  const StyledHandlerContainer = styled(View)<ViewProps>(({ theme }) => ({
@@ -2,6 +2,7 @@ import type { ReactElement, ReactNode } from 'react';
2
2
  import React, { useEffect, useRef, useState } from 'react';
3
3
  import { Animated, Dimensions, Easing } from 'react-native';
4
4
  import DragableDrawer from './DragableDrawer';
5
+ import DragableScrollView from './DragableDrawer/DragableScrollView';
5
6
 
6
7
  import {
7
8
  StyledBackdrop,
@@ -97,4 +98,5 @@ const Drawer = ({
97
98
 
98
99
  export default Object.assign(Drawer, {
99
100
  Dragable: DragableDrawer,
101
+ DragableScrollView,
100
102
  });
@@ -1,5 +1,5 @@
1
1
  import type { ViewProps, KeyboardAvoidingViewProps } from 'react-native';
2
- import { Animated, KeyboardAvoidingView, SafeAreaView, View } from 'react-native';
2
+ import { Animated, KeyboardAvoidingView, View } from 'react-native';
3
3
  declare const StyledWrapper: import("@emotion/native").StyledComponent<ViewProps & {
4
4
  theme?: import("@emotion/react").Theme;
5
5
  as?: React.ElementType;
@@ -12,7 +12,7 @@ declare const StyledKeyboardAvoidingView: import("@emotion/native").StyledCompon
12
12
  }, {}, {
13
13
  ref?: import("react").Ref<KeyboardAvoidingView> | undefined;
14
14
  }>;
15
- declare const StyledFloatingWrapper: import("@emotion/native").StyledComponent<Animated.AnimatedProps<ViewProps & import("react").RefAttributes<SafeAreaView>> & {
15
+ declare const StyledFloatingWrapper: import("@emotion/native").StyledComponent<Animated.AnimatedProps<import("react-native-safe-area-context").NativeSafeAreaViewProps & import("react").RefAttributes<import("react").Component<import("react-native-safe-area-context/lib/typescript/src/specs/NativeSafeAreaView").NativeProps, {}, any> & import("react-native").NativeMethods>> & {
16
16
  theme?: import("@emotion/react").Theme;
17
17
  as?: React.ElementType;
18
18
  }, {}, {}>;
@@ -20,7 +20,7 @@ declare const StyledFloatingBottomSheet: import("@emotion/native").StyledCompone
20
20
  theme?: import("@emotion/react").Theme;
21
21
  as?: React.ElementType;
22
22
  }, {}, {}>;
23
- declare const StyledBottomSheet: import("@emotion/native").StyledComponent<Animated.AnimatedProps<ViewProps & import("react").RefAttributes<SafeAreaView>> & {
23
+ declare const StyledBottomSheet: import("@emotion/native").StyledComponent<Animated.AnimatedProps<import("react-native-safe-area-context").NativeSafeAreaViewProps & import("react").RefAttributes<import("react").Component<import("react-native-safe-area-context/lib/typescript/src/specs/NativeSafeAreaView").NativeProps, {}, any> & import("react-native").NativeMethods>> & {
24
24
  theme?: import("@emotion/react").Theme;
25
25
  as?: React.ElementType;
26
26
  }, {}, {}>;
@@ -0,0 +1,18 @@
1
+ import type { MutableRefObject } from 'react';
2
+ interface DragableDrawerContextValue {
3
+ /** Whether the drawer has settled at maximum height (offset === 0). */
4
+ isAtMaxHeight: boolean;
5
+ /** Current vertical scroll offset reported by DragableScrollView. */
6
+ scrollYRef: MutableRefObject<number>;
7
+ /** Report scroll offset changes from DragableScrollView. */
8
+ onScrollY: (y: number) => void;
9
+ /** Begin a drawer pan gesture (stops any running animation). */
10
+ beginPan: () => void;
11
+ /** Move the drawer by dy pixels during an active pan. */
12
+ movePan: (dy: number) => void;
13
+ /** End pan and snap to the nearest snap point. */
14
+ releasePan: (dy: number, vy: number) => void;
15
+ }
16
+ declare const DragableDrawerContext: import("react").Context<DragableDrawerContextValue>;
17
+ export declare const useDragableDrawerContext: () => DragableDrawerContextValue;
18
+ export default DragableDrawerContext;