@shaquillehinds/react-native-bottom-sheet 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (187) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +880 -0
  3. package/lib/commonjs/BottomSheet/animations/drag.animation.js +72 -0
  4. package/lib/commonjs/BottomSheet/animations/drag.animation.js.map +1 -0
  5. package/lib/commonjs/BottomSheet/components/BottomSheet.js +92 -0
  6. package/lib/commonjs/BottomSheet/components/BottomSheet.js.map +1 -0
  7. package/lib/commonjs/BottomSheet/components/BottomSheetFlatlist.js +38 -0
  8. package/lib/commonjs/BottomSheet/components/BottomSheetFlatlist.js.map +1 -0
  9. package/lib/commonjs/BottomSheet/components/BottomSheetModal.js +34 -0
  10. package/lib/commonjs/BottomSheet/components/BottomSheetModal.js.map +1 -0
  11. package/lib/commonjs/BottomSheet/components/BottomSheetScrollView.js +37 -0
  12. package/lib/commonjs/BottomSheet/components/BottomSheetScrollView.js.map +1 -0
  13. package/lib/commonjs/BottomSheet/config/bottomSheet.constants.js +35 -0
  14. package/lib/commonjs/BottomSheet/config/bottomSheet.constants.js.map +1 -0
  15. package/lib/commonjs/BottomSheet/config/bottomSheet.styles.js +42 -0
  16. package/lib/commonjs/BottomSheet/config/bottomSheet.styles.js.map +1 -0
  17. package/lib/commonjs/BottomSheet/config/bottomSheet.types.js +14 -0
  18. package/lib/commonjs/BottomSheet/config/bottomSheet.types.js.map +1 -0
  19. package/lib/commonjs/BottomSheet/controller/bottomFlatlist.controller.js +69 -0
  20. package/lib/commonjs/BottomSheet/controller/bottomFlatlist.controller.js.map +1 -0
  21. package/lib/commonjs/BottomSheet/controller/bottomScrollView.controller.js +41 -0
  22. package/lib/commonjs/BottomSheet/controller/bottomScrollView.controller.js.map +1 -0
  23. package/lib/commonjs/BottomSheet/controller/bottomSheet.controller.js +216 -0
  24. package/lib/commonjs/BottomSheet/controller/bottomSheet.controller.js.map +1 -0
  25. package/lib/commonjs/BottomSheet/controller/callbacks.controller.js +135 -0
  26. package/lib/commonjs/BottomSheet/controller/callbacks.controller.js.map +1 -0
  27. package/lib/commonjs/BottomSheet/controller/dragAnimation.controller.js +127 -0
  28. package/lib/commonjs/BottomSheet/controller/dragAnimation.controller.js.map +1 -0
  29. package/lib/commonjs/BottomSheet/controller/hooks/useBottomSheetRef.js +60 -0
  30. package/lib/commonjs/BottomSheet/controller/hooks/useBottomSheetRef.js.map +1 -0
  31. package/lib/commonjs/BottomSheet/controller/hooks/useBottomSheetUtils.js +74 -0
  32. package/lib/commonjs/BottomSheet/controller/hooks/useBottomSheetUtils.js.map +1 -0
  33. package/lib/commonjs/BottomSheet/controller/index.js +17 -0
  34. package/lib/commonjs/BottomSheet/controller/index.js.map +1 -0
  35. package/lib/commonjs/BottomSheet/controller/keyboardAnimation.controller.js +88 -0
  36. package/lib/commonjs/BottomSheet/controller/keyboardAnimation.controller.js.map +1 -0
  37. package/lib/commonjs/BottomSheet/controller/scrollContent.controller.js +89 -0
  38. package/lib/commonjs/BottomSheet/controller/scrollContent.controller.js.map +1 -0
  39. package/lib/commonjs/BottomSheet/index.js +130 -0
  40. package/lib/commonjs/BottomSheet/index.js.map +1 -0
  41. package/lib/commonjs/index.js +17 -0
  42. package/lib/commonjs/index.js.map +1 -0
  43. package/lib/commonjs/package.json +1 -0
  44. package/lib/module/BottomSheet/animations/drag.animation.js +68 -0
  45. package/lib/module/BottomSheet/animations/drag.animation.js.map +1 -0
  46. package/lib/module/BottomSheet/components/BottomSheet.js +87 -0
  47. package/lib/module/BottomSheet/components/BottomSheet.js.map +1 -0
  48. package/lib/module/BottomSheet/components/BottomSheetFlatlist.js +32 -0
  49. package/lib/module/BottomSheet/components/BottomSheetFlatlist.js.map +1 -0
  50. package/lib/module/BottomSheet/components/BottomSheetModal.js +30 -0
  51. package/lib/module/BottomSheet/components/BottomSheetModal.js.map +1 -0
  52. package/lib/module/BottomSheet/components/BottomSheetScrollView.js +31 -0
  53. package/lib/module/BottomSheet/components/BottomSheetScrollView.js.map +1 -0
  54. package/lib/module/BottomSheet/config/bottomSheet.constants.js +30 -0
  55. package/lib/module/BottomSheet/config/bottomSheet.constants.js.map +1 -0
  56. package/lib/module/BottomSheet/config/bottomSheet.styles.js +38 -0
  57. package/lib/module/BottomSheet/config/bottomSheet.styles.js.map +1 -0
  58. package/lib/module/BottomSheet/config/bottomSheet.types.js +10 -0
  59. package/lib/module/BottomSheet/config/bottomSheet.types.js.map +1 -0
  60. package/lib/module/BottomSheet/controller/bottomFlatlist.controller.js +64 -0
  61. package/lib/module/BottomSheet/controller/bottomFlatlist.controller.js.map +1 -0
  62. package/lib/module/BottomSheet/controller/bottomScrollView.controller.js +37 -0
  63. package/lib/module/BottomSheet/controller/bottomScrollView.controller.js.map +1 -0
  64. package/lib/module/BottomSheet/controller/bottomSheet.controller.js +212 -0
  65. package/lib/module/BottomSheet/controller/bottomSheet.controller.js.map +1 -0
  66. package/lib/module/BottomSheet/controller/callbacks.controller.js +130 -0
  67. package/lib/module/BottomSheet/controller/callbacks.controller.js.map +1 -0
  68. package/lib/module/BottomSheet/controller/dragAnimation.controller.js +122 -0
  69. package/lib/module/BottomSheet/controller/dragAnimation.controller.js.map +1 -0
  70. package/lib/module/BottomSheet/controller/hooks/useBottomSheetRef.js +56 -0
  71. package/lib/module/BottomSheet/controller/hooks/useBottomSheetRef.js.map +1 -0
  72. package/lib/module/BottomSheet/controller/hooks/useBottomSheetUtils.js +70 -0
  73. package/lib/module/BottomSheet/controller/hooks/useBottomSheetUtils.js.map +1 -0
  74. package/lib/module/BottomSheet/controller/index.js +4 -0
  75. package/lib/module/BottomSheet/controller/index.js.map +1 -0
  76. package/lib/module/BottomSheet/controller/keyboardAnimation.controller.js +84 -0
  77. package/lib/module/BottomSheet/controller/keyboardAnimation.controller.js.map +1 -0
  78. package/lib/module/BottomSheet/controller/scrollContent.controller.js +84 -0
  79. package/lib/module/BottomSheet/controller/scrollContent.controller.js.map +1 -0
  80. package/lib/module/BottomSheet/index.js +112 -0
  81. package/lib/module/BottomSheet/index.js.map +1 -0
  82. package/lib/module/index.js +4 -0
  83. package/lib/module/index.js.map +1 -0
  84. package/lib/module/package.json +1 -0
  85. package/lib/typescript/commonjs/package.json +1 -0
  86. package/lib/typescript/commonjs/src/BottomSheet/animations/drag.animation.d.ts +31 -0
  87. package/lib/typescript/commonjs/src/BottomSheet/animations/drag.animation.d.ts.map +1 -0
  88. package/lib/typescript/commonjs/src/BottomSheet/components/BottomSheet.d.ts +9 -0
  89. package/lib/typescript/commonjs/src/BottomSheet/components/BottomSheet.d.ts.map +1 -0
  90. package/lib/typescript/commonjs/src/BottomSheet/components/BottomSheetFlatlist.d.ts +3 -0
  91. package/lib/typescript/commonjs/src/BottomSheet/components/BottomSheetFlatlist.d.ts.map +1 -0
  92. package/lib/typescript/commonjs/src/BottomSheet/components/BottomSheetModal.d.ts +8 -0
  93. package/lib/typescript/commonjs/src/BottomSheet/components/BottomSheetModal.d.ts.map +1 -0
  94. package/lib/typescript/commonjs/src/BottomSheet/components/BottomSheetScrollView.d.ts +3 -0
  95. package/lib/typescript/commonjs/src/BottomSheet/components/BottomSheetScrollView.d.ts.map +1 -0
  96. package/lib/typescript/commonjs/src/BottomSheet/config/bottomSheet.constants.d.ts +30 -0
  97. package/lib/typescript/commonjs/src/BottomSheet/config/bottomSheet.constants.d.ts.map +1 -0
  98. package/lib/typescript/commonjs/src/BottomSheet/config/bottomSheet.styles.d.ts +37 -0
  99. package/lib/typescript/commonjs/src/BottomSheet/config/bottomSheet.styles.d.ts.map +1 -0
  100. package/lib/typescript/commonjs/src/BottomSheet/config/bottomSheet.types.d.ts +185 -0
  101. package/lib/typescript/commonjs/src/BottomSheet/config/bottomSheet.types.d.ts.map +1 -0
  102. package/lib/typescript/commonjs/src/BottomSheet/controller/bottomFlatlist.controller.d.ts +480 -0
  103. package/lib/typescript/commonjs/src/BottomSheet/controller/bottomFlatlist.controller.d.ts.map +1 -0
  104. package/lib/typescript/commonjs/src/BottomSheet/controller/bottomScrollView.controller.d.ts +338 -0
  105. package/lib/typescript/commonjs/src/BottomSheet/controller/bottomScrollView.controller.d.ts.map +1 -0
  106. package/lib/typescript/commonjs/src/BottomSheet/controller/bottomSheet.controller.d.ts +51 -0
  107. package/lib/typescript/commonjs/src/BottomSheet/controller/bottomSheet.controller.d.ts.map +1 -0
  108. package/lib/typescript/commonjs/src/BottomSheet/controller/callbacks.controller.d.ts +36 -0
  109. package/lib/typescript/commonjs/src/BottomSheet/controller/callbacks.controller.d.ts.map +1 -0
  110. package/lib/typescript/commonjs/src/BottomSheet/controller/dragAnimation.controller.d.ts +27 -0
  111. package/lib/typescript/commonjs/src/BottomSheet/controller/dragAnimation.controller.d.ts.map +1 -0
  112. package/lib/typescript/commonjs/src/BottomSheet/controller/hooks/useBottomSheetRef.d.ts +12 -0
  113. package/lib/typescript/commonjs/src/BottomSheet/controller/hooks/useBottomSheetRef.d.ts.map +1 -0
  114. package/lib/typescript/commonjs/src/BottomSheet/controller/hooks/useBottomSheetUtils.d.ts +40 -0
  115. package/lib/typescript/commonjs/src/BottomSheet/controller/hooks/useBottomSheetUtils.d.ts.map +1 -0
  116. package/lib/typescript/commonjs/src/BottomSheet/controller/index.d.ts +2 -0
  117. package/lib/typescript/commonjs/src/BottomSheet/controller/index.d.ts.map +1 -0
  118. package/lib/typescript/commonjs/src/BottomSheet/controller/keyboardAnimation.controller.d.ts +15 -0
  119. package/lib/typescript/commonjs/src/BottomSheet/controller/keyboardAnimation.controller.d.ts.map +1 -0
  120. package/lib/typescript/commonjs/src/BottomSheet/controller/scrollContent.controller.d.ts +20 -0
  121. package/lib/typescript/commonjs/src/BottomSheet/controller/scrollContent.controller.d.ts.map +1 -0
  122. package/lib/typescript/commonjs/src/BottomSheet/index.d.ts +23 -0
  123. package/lib/typescript/commonjs/src/BottomSheet/index.d.ts.map +1 -0
  124. package/lib/typescript/commonjs/src/index.d.ts +2 -0
  125. package/lib/typescript/commonjs/src/index.d.ts.map +1 -0
  126. package/lib/typescript/module/package.json +1 -0
  127. package/lib/typescript/module/src/BottomSheet/animations/drag.animation.d.ts +31 -0
  128. package/lib/typescript/module/src/BottomSheet/animations/drag.animation.d.ts.map +1 -0
  129. package/lib/typescript/module/src/BottomSheet/components/BottomSheet.d.ts +9 -0
  130. package/lib/typescript/module/src/BottomSheet/components/BottomSheet.d.ts.map +1 -0
  131. package/lib/typescript/module/src/BottomSheet/components/BottomSheetFlatlist.d.ts +3 -0
  132. package/lib/typescript/module/src/BottomSheet/components/BottomSheetFlatlist.d.ts.map +1 -0
  133. package/lib/typescript/module/src/BottomSheet/components/BottomSheetModal.d.ts +8 -0
  134. package/lib/typescript/module/src/BottomSheet/components/BottomSheetModal.d.ts.map +1 -0
  135. package/lib/typescript/module/src/BottomSheet/components/BottomSheetScrollView.d.ts +3 -0
  136. package/lib/typescript/module/src/BottomSheet/components/BottomSheetScrollView.d.ts.map +1 -0
  137. package/lib/typescript/module/src/BottomSheet/config/bottomSheet.constants.d.ts +30 -0
  138. package/lib/typescript/module/src/BottomSheet/config/bottomSheet.constants.d.ts.map +1 -0
  139. package/lib/typescript/module/src/BottomSheet/config/bottomSheet.styles.d.ts +37 -0
  140. package/lib/typescript/module/src/BottomSheet/config/bottomSheet.styles.d.ts.map +1 -0
  141. package/lib/typescript/module/src/BottomSheet/config/bottomSheet.types.d.ts +185 -0
  142. package/lib/typescript/module/src/BottomSheet/config/bottomSheet.types.d.ts.map +1 -0
  143. package/lib/typescript/module/src/BottomSheet/controller/bottomFlatlist.controller.d.ts +480 -0
  144. package/lib/typescript/module/src/BottomSheet/controller/bottomFlatlist.controller.d.ts.map +1 -0
  145. package/lib/typescript/module/src/BottomSheet/controller/bottomScrollView.controller.d.ts +338 -0
  146. package/lib/typescript/module/src/BottomSheet/controller/bottomScrollView.controller.d.ts.map +1 -0
  147. package/lib/typescript/module/src/BottomSheet/controller/bottomSheet.controller.d.ts +51 -0
  148. package/lib/typescript/module/src/BottomSheet/controller/bottomSheet.controller.d.ts.map +1 -0
  149. package/lib/typescript/module/src/BottomSheet/controller/callbacks.controller.d.ts +36 -0
  150. package/lib/typescript/module/src/BottomSheet/controller/callbacks.controller.d.ts.map +1 -0
  151. package/lib/typescript/module/src/BottomSheet/controller/dragAnimation.controller.d.ts +27 -0
  152. package/lib/typescript/module/src/BottomSheet/controller/dragAnimation.controller.d.ts.map +1 -0
  153. package/lib/typescript/module/src/BottomSheet/controller/hooks/useBottomSheetRef.d.ts +12 -0
  154. package/lib/typescript/module/src/BottomSheet/controller/hooks/useBottomSheetRef.d.ts.map +1 -0
  155. package/lib/typescript/module/src/BottomSheet/controller/hooks/useBottomSheetUtils.d.ts +40 -0
  156. package/lib/typescript/module/src/BottomSheet/controller/hooks/useBottomSheetUtils.d.ts.map +1 -0
  157. package/lib/typescript/module/src/BottomSheet/controller/index.d.ts +2 -0
  158. package/lib/typescript/module/src/BottomSheet/controller/index.d.ts.map +1 -0
  159. package/lib/typescript/module/src/BottomSheet/controller/keyboardAnimation.controller.d.ts +15 -0
  160. package/lib/typescript/module/src/BottomSheet/controller/keyboardAnimation.controller.d.ts.map +1 -0
  161. package/lib/typescript/module/src/BottomSheet/controller/scrollContent.controller.d.ts +20 -0
  162. package/lib/typescript/module/src/BottomSheet/controller/scrollContent.controller.d.ts.map +1 -0
  163. package/lib/typescript/module/src/BottomSheet/index.d.ts +23 -0
  164. package/lib/typescript/module/src/BottomSheet/index.d.ts.map +1 -0
  165. package/lib/typescript/module/src/index.d.ts +2 -0
  166. package/lib/typescript/module/src/index.d.ts.map +1 -0
  167. package/package.json +203 -0
  168. package/src/BottomSheet/animations/drag.animation.ts +86 -0
  169. package/src/BottomSheet/components/BottomSheet.tsx +157 -0
  170. package/src/BottomSheet/components/BottomSheetFlatlist.tsx +46 -0
  171. package/src/BottomSheet/components/BottomSheetModal.tsx +47 -0
  172. package/src/BottomSheet/components/BottomSheetScrollView.tsx +46 -0
  173. package/src/BottomSheet/config/bottomSheet.constants.ts +31 -0
  174. package/src/BottomSheet/config/bottomSheet.styles.ts +42 -0
  175. package/src/BottomSheet/config/bottomSheet.types.ts +246 -0
  176. package/src/BottomSheet/controller/bottomFlatlist.controller.ts +87 -0
  177. package/src/BottomSheet/controller/bottomScrollView.controller.ts +43 -0
  178. package/src/BottomSheet/controller/bottomSheet.controller.ts +238 -0
  179. package/src/BottomSheet/controller/callbacks.controller.ts +222 -0
  180. package/src/BottomSheet/controller/dragAnimation.controller.ts +211 -0
  181. package/src/BottomSheet/controller/hooks/useBottomSheetRef.ts +73 -0
  182. package/src/BottomSheet/controller/hooks/useBottomSheetUtils.ts +75 -0
  183. package/src/BottomSheet/controller/index.ts +1 -0
  184. package/src/BottomSheet/controller/keyboardAnimation.controller.ts +148 -0
  185. package/src/BottomSheet/controller/scrollContent.controller.ts +120 -0
  186. package/src/BottomSheet/index.tsx +139 -0
  187. package/src/index.tsx +1 -0
@@ -0,0 +1,222 @@
1
+ //$lf-ignore
2
+ import {
3
+ runOnJS,
4
+ runOnUI,
5
+ withTiming,
6
+ type SharedValue,
7
+ } from 'react-native-reanimated';
8
+ import { useCallback } from 'react';
9
+ import {
10
+ animateOpenTimingConfig,
11
+ animateCloseTimingConfig,
12
+ modalTransitionTimingConfig,
13
+ } from '../config/bottomSheet.constants';
14
+ import { type LayoutChangeEvent } from 'react-native';
15
+ import {
16
+ ModalState,
17
+ type AnimateCloseModalProps,
18
+ type SnapPoint,
19
+ } from '../config/bottomSheet.types';
20
+ import type { UseBottomSheetUtilsReturn } from './hooks/useBottomSheetUtils';
21
+
22
+ type CallbackControllerProps = {
23
+ unMounter?: () => void;
24
+
25
+ snapPoints: SharedValue<SnapPoint[]>;
26
+ modalState: React.MutableRefObject<ModalState>;
27
+ translationX: SharedValue<number>;
28
+ translationY: SharedValue<number>;
29
+ currentSnapPoint: SharedValue<SnapPoint>;
30
+ prevTranslationY: SharedValue<number>;
31
+ backdropOpacity: SharedValue<number>;
32
+ closedYPosition: SharedValue<number>;
33
+ fullyOpenYPosition: SharedValue<number>;
34
+ disableLayoutAnimation: React.MutableRefObject<boolean>;
35
+ setDisableLayoutAnimation: (bool: boolean) => void;
36
+ disableCloseOnBackdropPress?: boolean;
37
+ onBackDropPress?: (animateModalClose?: () => void) => void;
38
+ setShowModal?:
39
+ | React.Dispatch<React.SetStateAction<boolean>>
40
+ | ((bool: boolean) => void);
41
+ utils: UseBottomSheetUtilsReturn;
42
+ onSnapPointReach?: (snapPointIndex: number) => Promise<void> | void;
43
+ };
44
+
45
+ export function callbackController(props: CallbackControllerProps) {
46
+ const {
47
+ unMounter,
48
+ snapPoints,
49
+ modalState,
50
+ backdropOpacity,
51
+ translationX,
52
+ translationY,
53
+ onBackDropPress,
54
+ closedYPosition,
55
+ currentSnapPoint,
56
+ prevTranslationY,
57
+ onSnapPointReach,
58
+ fullyOpenYPosition,
59
+ disableLayoutAnimation,
60
+ disableCloseOnBackdropPress,
61
+ } = props;
62
+ const {
63
+ orientation,
64
+ getMaxMinSnapPointsWorklet,
65
+ percentageToSnapPointWorklet,
66
+ } = props.utils;
67
+ const setModalState = useCallback((state: ModalState) => {
68
+ if (
69
+ modalState.current === ModalState.CLOSING &&
70
+ state !== ModalState.CLOSED
71
+ )
72
+ return;
73
+ modalState.current = state;
74
+ }, []);
75
+ const animateModalOpen = useCallback(
76
+ (height: number, modalHeight: number) => {
77
+ 'worklet';
78
+ if (height > modalHeight) height = modalHeight;
79
+ const translateYHeight = -height;
80
+ translationY.value = withTiming(
81
+ translateYHeight,
82
+ animateOpenTimingConfig,
83
+ () => {
84
+ prevTranslationY.value = translateYHeight;
85
+ runOnJS(setModalState)(ModalState.OPEN);
86
+ }
87
+ );
88
+ if (snapPoints.value.length) {
89
+ let maxOpenPosition = fullyOpenYPosition.value;
90
+ if (!maxOpenPosition)
91
+ maxOpenPosition = getMaxMinSnapPointsWorklet(snapPoints).maxSnapPoint;
92
+ backdropOpacity.value = withTiming(
93
+ translateYHeight / maxOpenPosition,
94
+ animateOpenTimingConfig
95
+ );
96
+ } else backdropOpacity.value = withTiming(1, animateOpenTimingConfig);
97
+ },
98
+ [orientation]
99
+ );
100
+
101
+ const animateModalClose = useCallback((prop?: AnimateCloseModalProps) => {
102
+ 'worklet';
103
+ const timing = {
104
+ duration: prop?.duration || animateCloseTimingConfig.duration,
105
+ easing: prop?.easing || animateCloseTimingConfig.easing,
106
+ };
107
+ translationY.value = withTiming(closedYPosition.value, timing);
108
+ backdropOpacity.value = withTiming(0, timing);
109
+ }, []);
110
+
111
+ const onPlatformViewLayout = useCallback((e: LayoutChangeEvent) => {
112
+ translationX.value = -e.nativeEvent.layout.x;
113
+ }, []);
114
+
115
+ const animateToSnapPoint = useCallback(
116
+ (snapPoint?: SnapPoint, index?: number) => {
117
+ 'worklet';
118
+ if (!snapPoint) return;
119
+ currentSnapPoint.value = { offset: snapPoint.offset };
120
+ translationY.value = withTiming(
121
+ snapPoint.offset,
122
+ modalTransitionTimingConfig,
123
+ () => {
124
+ typeof index === 'number' &&
125
+ onSnapPointReach &&
126
+ runOnJS(onSnapPointReach)(index);
127
+ }
128
+ );
129
+ backdropOpacity.value = withTiming(
130
+ snapPoint.offset / fullyOpenYPosition.value,
131
+ modalTransitionTimingConfig
132
+ );
133
+ },
134
+ []
135
+ );
136
+
137
+ const animateToSnapPointIndex = useCallback((snapPointIndex: number) => {
138
+ 'worklet';
139
+ const snapPoint = snapPoints.value[snapPointIndex];
140
+ animateToSnapPoint(snapPoint, snapPointIndex);
141
+ }, []);
142
+
143
+ const animateToPercentage = useCallback(
144
+ (percentage: string | number, screenHeight: number) => {
145
+ 'worklet';
146
+ const snapPoint = percentageToSnapPointWorklet(percentage, screenHeight);
147
+ animateToSnapPoint(snapPoint);
148
+ },
149
+ [orientation]
150
+ );
151
+
152
+ const onModalContentLayout = useCallback(
153
+ (e: LayoutChangeEvent) => {
154
+ if (modalState.current === ModalState.OPENING) return;
155
+ if (!modalState.current) setModalState(ModalState.OPENING);
156
+ if (snapPoints.value.length && modalState.current === ModalState.OPEN)
157
+ return;
158
+ if (!snapPoints.value.length) {
159
+ if (e.nativeEvent.layout.height > props.utils.modalHeight)
160
+ fullyOpenYPosition.value = -props.utils.modalHeight;
161
+ else fullyOpenYPosition.value = -e.nativeEvent.layout.height;
162
+ }
163
+ if (!disableLayoutAnimation.current)
164
+ runOnUI(animateModalOpen)(
165
+ Math.abs(snapPoints.value[0]?.offset || e.nativeEvent.layout.height),
166
+ props.utils.modalHeight
167
+ );
168
+ },
169
+ [orientation]
170
+ );
171
+
172
+ const closeModal = useCallback(
173
+ (delayMS?: number) => {
174
+ setModalState(ModalState.CLOSING);
175
+ delayMS
176
+ ? setTimeout(
177
+ () =>
178
+ props.setShowModal ? props.setShowModal(false) : unMounter?.(),
179
+ delayMS
180
+ )
181
+ : props.setShowModal
182
+ ? props.setShowModal(false)
183
+ : unMounter?.();
184
+ props.setDisableLayoutAnimation(true);
185
+ setTimeout(() => {
186
+ setModalState(ModalState.CLOSED);
187
+ }, delayMS || animateCloseTimingConfig.duration);
188
+ },
189
+ [unMounter]
190
+ );
191
+
192
+ const onModalBackdropPress = useCallback(() => {
193
+ onBackDropPress?.();
194
+ if (disableCloseOnBackdropPress) return;
195
+ closeModal();
196
+ runOnUI(animateModalClose)();
197
+ }, []);
198
+
199
+ const onRequestClose = useCallback(() => {
200
+ disableLayoutAnimation.current = true;
201
+ runOnUI(animateModalClose)();
202
+ if (props.setShowModal) {
203
+ props.setShowModal(false);
204
+ } else {
205
+ props.unMounter?.();
206
+ }
207
+ }, []);
208
+
209
+ return {
210
+ closeModal,
211
+
212
+ animateModalOpen,
213
+ animateModalClose,
214
+ animateToPercentage,
215
+ animateToSnapPointIndex,
216
+
217
+ onRequestClose,
218
+ onPlatformViewLayout,
219
+ onModalContentLayout,
220
+ onModalBackdropPress,
221
+ };
222
+ }
@@ -0,0 +1,211 @@
1
+ //$lf-ignore
2
+ import {
3
+ runOnJS,
4
+ withTiming,
5
+ type WithTimingConfig,
6
+ type SharedValue,
7
+ } from 'react-native-reanimated';
8
+ import { type DragGestureProps } from '@shaquillehinds/react-native-essentials';
9
+ import { useCallback } from 'react';
10
+ import { modalTransitionTimingConfig } from '../config/bottomSheet.constants';
11
+ import { type OnMoveAnimationProps } from '../animations/drag.animation';
12
+ import type { SnapPoint } from '../config/bottomSheet.types';
13
+
14
+ type DragAnimationControllerProps = {
15
+ snapPoints: SharedValue<SnapPoint[]>;
16
+ currentSnapPoint: SharedValue<SnapPoint>;
17
+ keyboardHeight: SharedValue<number>;
18
+ translationY: SharedValue<number>;
19
+ prevTranslationY: SharedValue<number>;
20
+ fullyOpenYPosition: SharedValue<number>;
21
+ lowestSnapPointPosition: SharedValue<number>;
22
+ backdropOpacity: SharedValue<number>;
23
+ closedYPosition: SharedValue<number>;
24
+
25
+ keepMounted?: boolean;
26
+ allowDragWhileKeyboardVisible?: boolean;
27
+
28
+ onDrag: (props: OnMoveAnimationProps) => void;
29
+ onDragStart: () => void;
30
+ closeModal: (delayMS?: number) => void;
31
+ onSnapPointReach?: (snapPointIndex: number) => Promise<void> | void;
32
+ };
33
+
34
+ export function dragAnimationController(props: DragAnimationControllerProps) {
35
+ const {
36
+ snapPoints,
37
+ currentSnapPoint,
38
+ allowDragWhileKeyboardVisible,
39
+ keyboardHeight,
40
+ backdropOpacity,
41
+ closeModal,
42
+ keepMounted,
43
+ closedYPosition,
44
+ onSnapPointReach,
45
+ onDragStart,
46
+ lowestSnapPointPosition,
47
+ translationY,
48
+ prevTranslationY,
49
+ fullyOpenYPosition,
50
+ } = props;
51
+ // Gesture event handlers
52
+ const onDragStartGesture: DragGestureProps['onDragStart'] =
53
+ useCallback(() => {
54
+ 'worklet';
55
+ if (keyboardHeight.value && !allowDragWhileKeyboardVisible) return;
56
+ onDragStart();
57
+ }, []);
58
+ const onDragGesture: DragGestureProps['onDrag'] = useCallback((e) => {
59
+ 'worklet';
60
+ if (keyboardHeight.value && !allowDragWhileKeyboardVisible) return;
61
+ const val = prevTranslationY.value + e.translationY;
62
+ const stretch = 100;
63
+ translationY.value =
64
+ val >= fullyOpenYPosition.value
65
+ ? val
66
+ : fullyOpenYPosition.value -
67
+ stretch +
68
+ stretch / ((fullyOpenYPosition.value - val) / stretch + 1);
69
+ if (snapPoints.value.length)
70
+ backdropOpacity.value =
71
+ -(currentSnapPoint.value.offset + e.translationY) /
72
+ -fullyOpenYPosition.value;
73
+ else {
74
+ if (prevTranslationY.value === fullyOpenYPosition.value)
75
+ backdropOpacity.value =
76
+ -(e.translationY + fullyOpenYPosition.value) /
77
+ -fullyOpenYPosition.value;
78
+ else if (e.translationY < 0)
79
+ backdropOpacity.value = e.translationY / -fullyOpenYPosition.value;
80
+ }
81
+ }, []);
82
+
83
+ const onDragEndGesture: NonNullable<DragGestureProps['onDragEnd']> =
84
+ useCallback((e) => {
85
+ 'worklet';
86
+ if (keyboardHeight.value && !allowDragWhileKeyboardVisible) return;
87
+ const animate = (
88
+ to: number,
89
+ timing: WithTimingConfig,
90
+ opacity: number,
91
+ index?: number
92
+ ) => {
93
+ translationY.value = withTiming(to, timing, () => {
94
+ typeof index === 'number' &&
95
+ onSnapPointReach &&
96
+ runOnJS(onSnapPointReach)(index);
97
+ });
98
+ backdropOpacity.value = withTiming(
99
+ opacity,
100
+ modalTransitionTimingConfig
101
+ );
102
+ };
103
+ if (snapPoints.value.length) {
104
+ const fullyOpenIndex = snapPoints.value.length - 1;
105
+ if (e.velocityY > 1500) {
106
+ if (
107
+ currentSnapPoint.value.offset === lowestSnapPointPosition.value &&
108
+ !keepMounted
109
+ ) {
110
+ animate(closedYPosition.value, modalTransitionTimingConfig, 0);
111
+ return runOnJS(closeModal)(175);
112
+ }
113
+ if (e.velocityY > 3500 && !keepMounted) {
114
+ animate(closedYPosition.value, modalTransitionTimingConfig, 0);
115
+ return runOnJS(closeModal)(175);
116
+ }
117
+ if (e.velocityY > 1500) {
118
+ animate(
119
+ lowestSnapPointPosition.value,
120
+ modalTransitionTimingConfig,
121
+ lowestSnapPointPosition.value / fullyOpenYPosition.value,
122
+ 0
123
+ );
124
+ currentSnapPoint.value = {
125
+ offset: lowestSnapPointPosition.value,
126
+ };
127
+ return;
128
+ }
129
+ } else if (e.velocityY < -1500) {
130
+ animate(
131
+ fullyOpenYPosition.value,
132
+ modalTransitionTimingConfig,
133
+ 1,
134
+ fullyOpenIndex
135
+ );
136
+ currentSnapPoint.value = {
137
+ offset: fullyOpenYPosition.value,
138
+ };
139
+ return;
140
+ }
141
+ let closestSnapPointValue = Math.abs(
142
+ currentSnapPoint.value.offset + e.translationY + 100
143
+ );
144
+ let closestSnapPointOffset = 0;
145
+ let closestSnapPointIndex = 0;
146
+ for (let i = 0; i < snapPoints.value.length; i++) {
147
+ const snapPoint = snapPoints.value[i];
148
+ if (!snapPoint)
149
+ return animate(
150
+ fullyOpenYPosition.value,
151
+ modalTransitionTimingConfig,
152
+ 1,
153
+ fullyOpenIndex
154
+ );
155
+ const currSnapPointValue = Math.abs(
156
+ currentSnapPoint.value.offset + e.translationY - snapPoint.offset
157
+ );
158
+ if (currSnapPointValue < closestSnapPointValue) {
159
+ closestSnapPointValue = currSnapPointValue;
160
+ closestSnapPointOffset = snapPoint.offset;
161
+ closestSnapPointIndex = i;
162
+ }
163
+ }
164
+ if (closestSnapPointOffset) {
165
+ currentSnapPoint.value = {
166
+ offset: closestSnapPointOffset,
167
+ };
168
+ return animate(
169
+ closestSnapPointOffset,
170
+ modalTransitionTimingConfig,
171
+ closestSnapPointOffset / fullyOpenYPosition.value,
172
+ closestSnapPointIndex
173
+ );
174
+ }
175
+ if (!keepMounted) {
176
+ runOnJS(closeModal)(175);
177
+ return animate(closedYPosition.value, modalTransitionTimingConfig, 0);
178
+ } else
179
+ return animate(
180
+ lowestSnapPointPosition.value,
181
+ modalTransitionTimingConfig,
182
+ lowestSnapPointPosition.value / fullyOpenYPosition.value,
183
+ 0
184
+ );
185
+ }
186
+ const halfContentHeight = -(fullyOpenYPosition.value / 2);
187
+ const isClosed = prevTranslationY.value === closedYPosition.value;
188
+ const isMovedPastHalf = Math.abs(e.translationY) > halfContentHeight;
189
+ const isHighVelocity = isClosed
190
+ ? e.velocityY < -1000
191
+ : e.velocityY > 1000;
192
+ if (isClosed) {
193
+ if (e.translationY > 50 || isMovedPastHalf)
194
+ animate(fullyOpenYPosition.value, modalTransitionTimingConfig, 1);
195
+ else if (isHighVelocity)
196
+ animate(fullyOpenYPosition.value, modalTransitionTimingConfig, 1);
197
+ else animate(closedYPosition.value, modalTransitionTimingConfig, 0);
198
+ return;
199
+ }
200
+ if (isMovedPastHalf || isHighVelocity) {
201
+ if (e.velocityY > 1000)
202
+ animate(closedYPosition.value, modalTransitionTimingConfig, 0);
203
+ else animate(closedYPosition.value, modalTransitionTimingConfig, 0);
204
+ runOnJS(closeModal)(175);
205
+ } else if (e.translationY <= halfContentHeight) {
206
+ animate(fullyOpenYPosition.value, modalTransitionTimingConfig, 1);
207
+ }
208
+ }, []);
209
+
210
+ return { onDragGesture, onDragEndGesture, onDragStartGesture };
211
+ }
@@ -0,0 +1,73 @@
1
+ import { useImperativeHandle, useMemo, useRef } from 'react';
2
+ import type {
3
+ BottomSheetRef,
4
+ BottomModalRef,
5
+ BottomModalRefObject,
6
+ BottomSheetProps,
7
+ } from '../../config/bottomSheet.types';
8
+ import type { ComponentMounterController } from '@shaquillehinds/react-native-essentials';
9
+ import { animateCloseTimingConfig } from '../../config/bottomSheet.constants';
10
+
11
+ type UseBottomModalRefProps = {
12
+ ref: BottomModalRefObject;
13
+ } & Pick<BottomSheetProps, 'showModal' | 'setShowModal'>;
14
+
15
+ export function useBottomSheetRef({
16
+ ref,
17
+ showModal,
18
+ setShowModal,
19
+ }: UseBottomModalRefProps) {
20
+ const mounterRef = useRef<ComponentMounterController | null>(null);
21
+ const sheetRef = useRef<BottomSheetRef | null>(null);
22
+ const modalRef: BottomModalRef = useMemo(() => {
23
+ const hasState = setShowModal && typeof showModal === 'boolean';
24
+ return {
25
+ getModalState: () => sheetRef.current?.getModalState(),
26
+ openModal: (openModalProps) => {
27
+ if (hasState && !openModalProps?.onOpen) setShowModal(true);
28
+ else mounterRef.current?.mountComponent(openModalProps);
29
+ },
30
+ closeModal: (closeModalProps) => {
31
+ if (closeModalProps?.skipAnimation) {
32
+ mounterRef.current?.hardUnMountComponent(closeModalProps);
33
+ hasState && setShowModal(false);
34
+ return;
35
+ }
36
+ if (closeModalProps?.isNavigating) {
37
+ const closeProps = {
38
+ duration: closeModalProps.duration || 100,
39
+ easing: closeModalProps?.easing,
40
+ onClose: closeModalProps?.onClose,
41
+ };
42
+ sheetRef.current?.animateCloseModal(closeProps);
43
+ mounterRef.current?.unMountComponent(closeProps);
44
+ if (hasState)
45
+ setTimeout(() => setShowModal(false), closeProps.duration);
46
+ return;
47
+ }
48
+ if (hasState && !closeModalProps?.duration && !closeModalProps?.onClose)
49
+ return setShowModal(false);
50
+ sheetRef.current?.animateCloseModal(closeModalProps);
51
+ mounterRef.current?.unMountComponent(closeModalProps);
52
+ if (hasState)
53
+ setTimeout(
54
+ () => setShowModal(false),
55
+ animateCloseTimingConfig.duration
56
+ );
57
+ },
58
+ closeWithoutAnimation: () => {
59
+ mounterRef.current?.hardUnMountComponent();
60
+ hasState && setShowModal(false);
61
+ },
62
+ snapToIndex: (index) => sheetRef.current?.snapToIndex(index),
63
+ snapToPercentage: (percentage) =>
64
+ sheetRef.current?.snapToPercentage(percentage),
65
+ };
66
+ }, []);
67
+ useImperativeHandle(ref, () => modalRef, []);
68
+ return {
69
+ mounterRef,
70
+ sheetRef,
71
+ modalRef,
72
+ };
73
+ }
@@ -0,0 +1,75 @@
1
+ import {
2
+ useDeviceOrientation,
3
+ strToNumPercentage,
4
+ strToNumPercentageWorklet,
5
+ } from '@shaquillehinds/react-native-essentials';
6
+ import type { SharedValue } from 'react-native-reanimated';
7
+ import type { SnapPoint } from '../../config/bottomSheet.types';
8
+ import { extraHeightPercent } from '../../config/bottomSheet.constants';
9
+
10
+ export function useBottomSheetUtils() {
11
+ const deviceOrientation = useDeviceOrientation();
12
+
13
+ const extraHeight = deviceOrientation.relativeY(extraHeightPercent);
14
+ const modalHeight = deviceOrientation.relativeY(100) + extraHeight;
15
+ const modalBottomOffset = -modalHeight * 2;
16
+
17
+ const getMaxMinSnapPoints = (snapPoints: SnapPoint[]) => {
18
+ const firstSnapPoint = snapPoints[0]!;
19
+ let maxSnapPoint = firstSnapPoint.offset;
20
+ let minSnapPoint = firstSnapPoint.offset;
21
+ for (const snapPoint of snapPoints) {
22
+ if (snapPoint.offset < maxSnapPoint) maxSnapPoint = snapPoint.offset;
23
+ if (snapPoint.offset > minSnapPoint) minSnapPoint = snapPoint.offset;
24
+ }
25
+ return { maxSnapPoint, minSnapPoint, firstSnapPoint };
26
+ };
27
+
28
+ const getMaxMinSnapPointsWorklet = (snapPoints: SharedValue<SnapPoint[]>) => {
29
+ 'worklet';
30
+ const firstSnapPoint = snapPoints.value[0]!;
31
+ let maxSnapPoint = firstSnapPoint.offset;
32
+ let minSnapPoint = firstSnapPoint.offset;
33
+ for (const snapPoint of snapPoints.value) {
34
+ if (snapPoint.offset < maxSnapPoint) maxSnapPoint = snapPoint.offset;
35
+ if (snapPoint.offset > minSnapPoint) minSnapPoint = snapPoint.offset;
36
+ }
37
+ return { maxSnapPoint, minSnapPoint, firstSnapPoint };
38
+ };
39
+
40
+ const percentageToSnapPoint = (p: string | number) => {
41
+ const percentage = strToNumPercentage(p);
42
+ return {
43
+ percentage: percentage / 100,
44
+ offset: -(deviceOrientation.relativeY(percentage) + extraHeight),
45
+ };
46
+ };
47
+
48
+ const percentageToSnapPointWorklet = (
49
+ p: string | number,
50
+ screenHeight: number
51
+ ) => {
52
+ 'worklet';
53
+ const percentage = strToNumPercentageWorklet(p);
54
+ const decimal = percentage / 100;
55
+ const snapPointOffset = screenHeight * decimal;
56
+ const extraSnapPointHeight = screenHeight * (extraHeightPercent / 100);
57
+ return {
58
+ percentage: decimal,
59
+ offset: -(snapPointOffset + extraSnapPointHeight),
60
+ };
61
+ };
62
+
63
+ return {
64
+ ...deviceOrientation,
65
+ extraHeight,
66
+ modalHeight,
67
+ modalBottomOffset,
68
+ getMaxMinSnapPoints,
69
+ getMaxMinSnapPointsWorklet,
70
+ percentageToSnapPoint,
71
+ percentageToSnapPointWorklet,
72
+ };
73
+ }
74
+
75
+ export type UseBottomSheetUtilsReturn = ReturnType<typeof useBottomSheetUtils>;
@@ -0,0 +1 @@
1
+ export * from './bottomSheet.controller';