@lodev09/react-native-true-sheet 4.0.0-beta.3 → 4.0.0-beta.30

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 (244) hide show
  1. package/README.md +28 -5
  2. package/android/build.gradle +23 -1
  3. package/android/proguard-rules.pro +3 -0
  4. package/android/src/main/java/com/lodev09/truesheet/TrueSheetContainerView.kt +50 -16
  5. package/android/src/main/java/com/lodev09/truesheet/TrueSheetContentView.kt +303 -184
  6. package/android/src/main/java/com/lodev09/truesheet/TrueSheetContentViewManager.kt +5 -1
  7. package/android/src/main/java/com/lodev09/truesheet/TrueSheetFooterView.kt +38 -109
  8. package/android/src/main/java/com/lodev09/truesheet/TrueSheetModule.kt +13 -0
  9. package/android/src/main/java/com/lodev09/truesheet/TrueSheetOverlayView.kt +127 -0
  10. package/android/src/main/java/com/lodev09/truesheet/TrueSheetOverlayViewManager.kt +45 -0
  11. package/android/src/main/java/com/lodev09/truesheet/TrueSheetPackage.kt +2 -1
  12. package/android/src/main/java/com/lodev09/truesheet/TrueSheetStateUpdater.kt +29 -3
  13. package/android/src/main/java/com/lodev09/truesheet/TrueSheetView.kt +234 -66
  14. package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewController.kt +491 -186
  15. package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewManager.kt +64 -10
  16. package/android/src/main/java/com/lodev09/truesheet/core/RNScreensEventObserver.kt +31 -14
  17. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetBottomSheetBehavior.kt +135 -0
  18. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetBottomSheetView.kt +23 -23
  19. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetCoordinatorLayout.kt +130 -6
  20. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDetentCalculator.kt +104 -39
  21. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDimView.kt +14 -17
  22. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetGrabberView.kt +2 -4
  23. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetOverlayRootView.kt +148 -0
  24. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetStackManager.kt +33 -40
  25. package/android/src/main/java/com/lodev09/truesheet/events/TrueSheetLifecycleEvents.kt +15 -0
  26. package/android/src/main/java/com/lodev09/truesheet/utils/ColorUtils.kt +19 -0
  27. package/android/src/main/java/com/lodev09/truesheet/utils/KeyboardUtils.kt +15 -2
  28. package/android/src/main/java/com/lodev09/truesheet/utils/ScreenUtils.kt +0 -12
  29. package/android/src/main/java/com/lodev09/truesheet/utils/ViewUtils.kt +19 -7
  30. package/android/src/main/jni/TrueSheetSpec.h +1 -0
  31. package/android/src/main/jni/TrueSheetStateUpdater.cpp +37 -6
  32. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewComponentDescriptor.h +1 -9
  33. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewShadowNode.cpp +114 -30
  34. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewShadowNode.h +30 -7
  35. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewState.cpp +2 -2
  36. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewState.h +9 -8
  37. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewComponentDescriptor.h +3 -5
  38. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewShadowNode.cpp +14 -3
  39. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewShadowNode.h +5 -6
  40. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewState.cpp +1 -1
  41. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewState.h +10 -6
  42. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetInsets.cpp +1 -1
  43. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetInsets.h +1 -1
  44. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetLayoutUtils.h +43 -0
  45. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetOverlayViewComponentDescriptor.h +21 -0
  46. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetOverlayViewShadowNode.cpp +17 -0
  47. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetOverlayViewShadowNode.h +33 -0
  48. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewComponentDescriptor.h +3 -5
  49. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewShadowNode.cpp +7 -40
  50. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewShadowNode.h +3 -7
  51. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewState.cpp +3 -5
  52. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewState.h +4 -5
  53. package/ios/TrueSheetContainerView.h +23 -7
  54. package/ios/TrueSheetContainerView.mm +45 -25
  55. package/ios/TrueSheetContentView.h +44 -15
  56. package/ios/TrueSheetContentView.mm +221 -190
  57. package/ios/TrueSheetFooterView.mm +133 -28
  58. package/ios/TrueSheetModule.h +2 -7
  59. package/ios/TrueSheetModule.mm +18 -18
  60. package/ios/TrueSheetOverlayView.h +42 -0
  61. package/ios/TrueSheetOverlayView.mm +175 -0
  62. package/ios/TrueSheetView.h +2 -0
  63. package/ios/TrueSheetView.mm +268 -52
  64. package/ios/TrueSheetViewController.h +36 -3
  65. package/ios/TrueSheetViewController.mm +797 -102
  66. package/ios/core/RNScreensEventObserver.mm +31 -28
  67. package/ios/core/TrueSheetBlurView.h +0 -2
  68. package/ios/core/TrueSheetBlurView.mm +3 -36
  69. package/ios/core/TrueSheetDetentCalculator.h +18 -1
  70. package/ios/core/TrueSheetDetentCalculator.mm +44 -9
  71. package/ios/core/TrueSheetDimView.h +27 -0
  72. package/ios/core/TrueSheetDimView.mm +41 -0
  73. package/ios/core/TrueSheetGrabberView.mm +13 -3
  74. package/ios/core/TrueSheetKeyboardObserver.h +7 -0
  75. package/ios/core/TrueSheetKeyboardObserver.mm +107 -15
  76. package/ios/core/TrueSheetOverlayContainerView.h +31 -0
  77. package/ios/core/TrueSheetOverlayContainerView.mm +35 -0
  78. package/ios/events/TrueSheetLifecycleEvents.h +2 -0
  79. package/ios/events/TrueSheetLifecycleEvents.mm +8 -0
  80. package/ios/tvos/TrueSheetStubs.mm +12 -0
  81. package/ios/utils/UIView+ScrollEdgeInteraction.h +1 -0
  82. package/ios/utils/UIView+ScrollEdgeInteraction.mm +24 -2
  83. package/lib/module/TrueSheet.js +222 -54
  84. package/lib/module/TrueSheet.js.map +1 -1
  85. package/lib/module/TrueSheet.web.js +364 -275
  86. package/lib/module/TrueSheet.web.js.map +1 -1
  87. package/lib/module/TrueSheetBackground.js +15 -0
  88. package/lib/module/TrueSheetBackground.js.map +1 -0
  89. package/lib/module/TrueSheetOverlay.js +30 -0
  90. package/lib/module/TrueSheetOverlay.js.map +1 -0
  91. package/lib/module/TrueSheetOverlay.web.js +35 -0
  92. package/lib/module/TrueSheetOverlay.web.js.map +1 -0
  93. package/lib/module/TrueSheetPeek.web.js +20 -15
  94. package/lib/module/TrueSheetPeek.web.js.map +1 -1
  95. package/lib/module/TrueSheetProvider.web.js +13 -9
  96. package/lib/module/TrueSheetProvider.web.js.map +1 -1
  97. package/lib/module/detentBackgrounds.js +21 -0
  98. package/lib/module/detentBackgrounds.js.map +1 -0
  99. package/lib/module/fabric/TrueSheetContentViewNativeComponent.ts +1 -1
  100. package/lib/module/fabric/TrueSheetFooterViewNativeComponent.ts +2 -3
  101. package/lib/module/fabric/TrueSheetOverlayViewNativeComponent.ts +12 -0
  102. package/lib/module/fabric/TrueSheetViewNativeComponent.ts +89 -73
  103. package/lib/module/index.js +1 -0
  104. package/lib/module/index.js.map +1 -1
  105. package/lib/module/mocks/index.js +18 -2
  106. package/lib/module/mocks/index.js.map +1 -1
  107. package/lib/module/mocks/navigationExpoRouter.js.map +1 -1
  108. package/lib/module/navigation/base-types.js +2 -0
  109. package/lib/module/navigation/base-types.js.map +1 -0
  110. package/lib/module/navigation/createTrueSheetRouter.js +158 -100
  111. package/lib/module/navigation/createTrueSheetRouter.js.map +1 -1
  112. package/lib/module/navigation/expo-router/base-types.js +2 -0
  113. package/lib/module/navigation/expo-router/base-types.js.map +1 -0
  114. package/lib/module/navigation/expo-router/extendTrueSheetRouter.js +71 -0
  115. package/lib/module/navigation/expo-router/extendTrueSheetRouter.js.map +1 -0
  116. package/lib/module/navigation/expo-router/index.js +18 -7
  117. package/lib/module/navigation/expo-router/index.js.map +1 -1
  118. package/lib/module/navigation/expo-router/types.js +4 -0
  119. package/lib/module/navigation/expo-router/types.js.map +1 -0
  120. package/lib/module/navigation/index.js.map +1 -1
  121. package/lib/module/navigation/screen/useSheetScreenState.js +1 -0
  122. package/lib/module/navigation/screen/useSheetScreenState.js.map +1 -1
  123. package/lib/module/scrollable.js +28 -0
  124. package/lib/module/scrollable.js.map +1 -0
  125. package/lib/module/web/constants.js +1 -1
  126. package/lib/module/web/constants.js.map +1 -1
  127. package/lib/module/web/keyboard.js +69 -0
  128. package/lib/module/web/keyboard.js.map +1 -0
  129. package/lib/module/web/layout.js +168 -0
  130. package/lib/module/web/layout.js.map +1 -0
  131. package/lib/module/web/vaul/constants.js +9 -0
  132. package/lib/module/web/vaul/constants.js.map +1 -1
  133. package/lib/module/web/vaul/context.js +4 -0
  134. package/lib/module/web/vaul/context.js.map +1 -1
  135. package/lib/module/web/vaul/helpers.js +1 -0
  136. package/lib/module/web/vaul/helpers.js.map +1 -1
  137. package/lib/module/web/vaul/index.js +83 -21
  138. package/lib/module/web/vaul/index.js.map +1 -1
  139. package/lib/module/web/vaul/use-snap-points.js +57 -28
  140. package/lib/module/web/vaul/use-snap-points.js.map +1 -1
  141. package/lib/typescript/src/TrueSheet.d.ts +18 -1
  142. package/lib/typescript/src/TrueSheet.d.ts.map +1 -1
  143. package/lib/typescript/src/TrueSheet.types.d.ts +209 -35
  144. package/lib/typescript/src/TrueSheet.types.d.ts.map +1 -1
  145. package/lib/typescript/src/TrueSheet.web.d.ts.map +1 -1
  146. package/lib/typescript/src/TrueSheetBackground.d.ts +3 -0
  147. package/lib/typescript/src/TrueSheetBackground.d.ts.map +1 -0
  148. package/lib/typescript/src/TrueSheetOverlay.d.ts +8 -0
  149. package/lib/typescript/src/TrueSheetOverlay.d.ts.map +1 -0
  150. package/lib/typescript/src/TrueSheetOverlay.web.d.ts +8 -0
  151. package/lib/typescript/src/TrueSheetOverlay.web.d.ts.map +1 -0
  152. package/lib/typescript/src/TrueSheetPeek.web.d.ts +8 -4
  153. package/lib/typescript/src/TrueSheetPeek.web.d.ts.map +1 -1
  154. package/lib/typescript/src/TrueSheetProvider.web.d.ts +5 -1
  155. package/lib/typescript/src/TrueSheetProvider.web.d.ts.map +1 -1
  156. package/lib/typescript/src/detentBackgrounds.d.ts +10 -0
  157. package/lib/typescript/src/detentBackgrounds.d.ts.map +1 -0
  158. package/lib/typescript/src/fabric/TrueSheetFooterViewNativeComponent.d.ts +2 -3
  159. package/lib/typescript/src/fabric/TrueSheetFooterViewNativeComponent.d.ts.map +1 -1
  160. package/lib/typescript/src/fabric/TrueSheetOverlayViewNativeComponent.d.ts +6 -0
  161. package/lib/typescript/src/fabric/TrueSheetOverlayViewNativeComponent.d.ts.map +1 -0
  162. package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts +76 -65
  163. package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts.map +1 -1
  164. package/lib/typescript/src/index.d.ts +1 -0
  165. package/lib/typescript/src/index.d.ts.map +1 -1
  166. package/lib/typescript/src/mocks/index.d.ts +4 -0
  167. package/lib/typescript/src/mocks/index.d.ts.map +1 -1
  168. package/lib/typescript/src/mocks/navigationExpoRouter.d.ts +3 -3
  169. package/lib/typescript/src/mocks/navigationExpoRouter.d.ts.map +1 -1
  170. package/lib/typescript/src/navigation/base-types.d.ts +9 -0
  171. package/lib/typescript/src/navigation/base-types.d.ts.map +1 -0
  172. package/lib/typescript/src/navigation/createTrueSheetRouter.d.ts +36 -10
  173. package/lib/typescript/src/navigation/createTrueSheetRouter.d.ts.map +1 -1
  174. package/lib/typescript/src/navigation/expo-router/base-types.d.ts +8 -0
  175. package/lib/typescript/src/navigation/expo-router/base-types.d.ts.map +1 -0
  176. package/lib/typescript/src/navigation/expo-router/extendTrueSheetRouter.d.ts +33 -0
  177. package/lib/typescript/src/navigation/expo-router/extendTrueSheetRouter.d.ts.map +1 -0
  178. package/lib/typescript/src/navigation/expo-router/index.d.ts +9 -6
  179. package/lib/typescript/src/navigation/expo-router/index.d.ts.map +1 -1
  180. package/lib/typescript/src/navigation/expo-router/types.d.ts +44 -0
  181. package/lib/typescript/src/navigation/expo-router/types.d.ts.map +1 -0
  182. package/lib/typescript/src/navigation/index.d.ts +3 -4
  183. package/lib/typescript/src/navigation/index.d.ts.map +1 -1
  184. package/lib/typescript/src/navigation/screen/useSheetScreenState.d.ts +2 -1
  185. package/lib/typescript/src/navigation/screen/useSheetScreenState.d.ts.map +1 -1
  186. package/lib/typescript/src/navigation/types.d.ts +43 -6
  187. package/lib/typescript/src/navigation/types.d.ts.map +1 -1
  188. package/lib/typescript/src/scrollable.d.ts +2 -0
  189. package/lib/typescript/src/scrollable.d.ts.map +1 -0
  190. package/lib/typescript/src/web/constants.d.ts +1 -1
  191. package/lib/typescript/src/web/constants.d.ts.map +1 -1
  192. package/lib/typescript/src/web/keyboard.d.ts +15 -0
  193. package/lib/typescript/src/web/keyboard.d.ts.map +1 -0
  194. package/lib/typescript/src/web/layout.d.ts +20 -0
  195. package/lib/typescript/src/web/layout.d.ts.map +1 -0
  196. package/lib/typescript/src/web/vaul/constants.d.ts +3 -0
  197. package/lib/typescript/src/web/vaul/constants.d.ts.map +1 -1
  198. package/lib/typescript/src/web/vaul/context.d.ts +5 -1
  199. package/lib/typescript/src/web/vaul/context.d.ts.map +1 -1
  200. package/lib/typescript/src/web/vaul/helpers.d.ts +1 -0
  201. package/lib/typescript/src/web/vaul/helpers.d.ts.map +1 -1
  202. package/lib/typescript/src/web/vaul/index.d.ts +20 -1
  203. package/lib/typescript/src/web/vaul/index.d.ts.map +1 -1
  204. package/lib/typescript/src/web/vaul/types.d.ts +9 -0
  205. package/lib/typescript/src/web/vaul/types.d.ts.map +1 -1
  206. package/lib/typescript/src/web/vaul/use-snap-points.d.ts +6 -4
  207. package/lib/typescript/src/web/vaul/use-snap-points.d.ts.map +1 -1
  208. package/package.json +18 -8
  209. package/react-native.config.js +1 -0
  210. package/src/TrueSheet.tsx +257 -62
  211. package/src/TrueSheet.types.ts +225 -35
  212. package/src/TrueSheet.web.tsx +445 -333
  213. package/src/TrueSheetBackground.tsx +17 -0
  214. package/src/TrueSheetOverlay.tsx +24 -0
  215. package/src/TrueSheetOverlay.web.tsx +33 -0
  216. package/src/TrueSheetPeek.web.tsx +25 -23
  217. package/src/TrueSheetProvider.web.tsx +22 -13
  218. package/src/detentBackgrounds.ts +24 -0
  219. package/src/fabric/TrueSheetContentViewNativeComponent.ts +1 -1
  220. package/src/fabric/TrueSheetFooterViewNativeComponent.ts +2 -3
  221. package/src/fabric/TrueSheetOverlayViewNativeComponent.ts +12 -0
  222. package/src/fabric/TrueSheetViewNativeComponent.ts +89 -73
  223. package/src/index.ts +1 -0
  224. package/src/mocks/index.ts +17 -2
  225. package/src/mocks/navigationExpoRouter.ts +6 -5
  226. package/src/navigation/base-types.ts +20 -0
  227. package/src/navigation/createTrueSheetRouter.ts +220 -144
  228. package/src/navigation/expo-router/base-types.ts +18 -0
  229. package/src/navigation/expo-router/extendTrueSheetRouter.ts +99 -0
  230. package/src/navigation/expo-router/index.ts +41 -30
  231. package/src/navigation/expo-router/types.ts +116 -0
  232. package/src/navigation/index.ts +6 -7
  233. package/src/navigation/screen/useSheetScreenState.ts +2 -0
  234. package/src/navigation/types.ts +81 -23
  235. package/src/scrollable.ts +25 -0
  236. package/src/web/constants.ts +1 -1
  237. package/src/web/keyboard.ts +79 -0
  238. package/src/web/layout.ts +196 -0
  239. package/src/web/vaul/constants.ts +9 -0
  240. package/src/web/vaul/context.ts +7 -1
  241. package/src/web/vaul/helpers.ts +5 -0
  242. package/src/web/vaul/index.tsx +113 -16
  243. package/src/web/vaul/types.ts +10 -0
  244. package/src/web/vaul/use-snap-points.ts +86 -33
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Expo Router flavour of `../types`: same shapes, but bound to Expo Router's
3
+ * vendored React Navigation types so apps that only install `expo-router` still
4
+ * get real types instead of `any` — see `./base-types`.
5
+ */
6
+ import type { TrueSheetActionType } from '../actions';
7
+ import type {
8
+ TrueSheetActionHelpersOf,
9
+ TrueSheetDispatch,
10
+ TrueSheetNavigationEventMap,
11
+ TrueSheetNavigationOptions,
12
+ TrueSheetStateOf,
13
+ } from '../types';
14
+ import type {
15
+ DefaultNavigatorOptions,
16
+ NavigationAction,
17
+ NavigationHelpers,
18
+ NavigationProp,
19
+ NavigationState,
20
+ ParamListBase,
21
+ RouteProp,
22
+ Router,
23
+ StackActionHelpers,
24
+ StackRouterOptions,
25
+ } from './base-types';
26
+
27
+ export type TrueSheetRouterOptions = StackRouterOptions;
28
+
29
+ export type TrueSheetNavigationState<ParamList extends ParamListBase> = TrueSheetStateOf<
30
+ NavigationState<ParamList>
31
+ >;
32
+
33
+ export type TrueSheetRouterState = TrueSheetNavigationState<ParamListBase>;
34
+
35
+ export type TrueSheetRouter = Router<TrueSheetRouterState, TrueSheetActionType>;
36
+
37
+ export type TrueSheetRouterFactory = (options: TrueSheetRouterOptions) => TrueSheetRouter;
38
+
39
+ /**
40
+ * The base `StackRouter` factory to wrap — see `../types` for the shared contract.
41
+ */
42
+ export type StackRouterFactory = <
43
+ State extends NavigationState<ParamListBase>,
44
+ Action extends NavigationAction,
45
+ >(
46
+ options: TrueSheetRouterOptions
47
+ ) => Router<State, Action>;
48
+
49
+ export type TrueSheetRoute = TrueSheetNavigationState<ParamListBase>['routes'][number];
50
+
51
+ /**
52
+ * Props injected into the navigator content by Expo Router's `createProps`.
53
+ * Raw routes carry the custom fields (`closing`, `dismissing`, `resizeIndex`, `resizeKey`)
54
+ * that the standard state strips out.
55
+ */
56
+ export interface TrueSheetNavigatorContentExtraProps {
57
+ routes: TrueSheetRoute[];
58
+ dispatch: TrueSheetDispatch;
59
+ }
60
+
61
+ export type TrueSheetActionHelpers<ParamList extends ParamListBase> = TrueSheetActionHelpersOf<
62
+ StackActionHelpers<ParamList>
63
+ >;
64
+
65
+ export type TrueSheetNavigationProp<
66
+ ParamList extends ParamListBase,
67
+ RouteName extends keyof ParamList = string,
68
+ NavigatorID extends string | undefined = undefined,
69
+ > = NavigationProp<
70
+ ParamList,
71
+ RouteName,
72
+ NavigatorID,
73
+ TrueSheetNavigationState<ParamList>,
74
+ TrueSheetNavigationOptions,
75
+ TrueSheetNavigationEventMap
76
+ > &
77
+ TrueSheetActionHelpers<ParamList>;
78
+
79
+ export type TrueSheetScreenProps<
80
+ ParamList extends ParamListBase,
81
+ RouteName extends keyof ParamList = string,
82
+ NavigatorID extends string | undefined = undefined,
83
+ > = {
84
+ navigation: TrueSheetNavigationProp<ParamList, RouteName, NavigatorID>;
85
+ route: RouteProp<ParamList, RouteName>;
86
+ };
87
+
88
+ export type TrueSheetNavigationHelpers = NavigationHelpers<
89
+ ParamListBase,
90
+ TrueSheetNavigationEventMap
91
+ >;
92
+
93
+ export type TrueSheetNavigatorProps = DefaultNavigatorOptions<
94
+ ParamListBase,
95
+ string | undefined,
96
+ TrueSheetNavigationState<ParamListBase>,
97
+ TrueSheetNavigationOptions,
98
+ TrueSheetNavigationEventMap,
99
+ unknown
100
+ > & {
101
+ /**
102
+ * The name of the route to use as the base screen.
103
+ * This screen will be rendered as a regular screen, while other screens are presented as sheets.
104
+ * Defaults to the first screen defined in the navigator.
105
+ */
106
+ initialRouteName?: string;
107
+ };
108
+
109
+ export type {
110
+ PositionChangeHandler,
111
+ TrueSheetDispatch,
112
+ TrueSheetNavigationEventMap,
113
+ TrueSheetNavigationOptions,
114
+ TrueSheetNavigationSheetProps,
115
+ TrueSheetStandardEventMap,
116
+ } from '../types';
@@ -4,16 +4,17 @@ import {
4
4
  type StandardNavigationTypeBagBase,
5
5
  } from '@react-navigation/native';
6
6
 
7
- import { createTrueSheetRouter, type StackRouterFactory } from './createTrueSheetRouter';
7
+ import { createTrueSheetRouter } from './createTrueSheetRouter';
8
8
  import { trueSheetNavigator } from './navigator';
9
9
  import type {
10
+ StackRouterFactory,
10
11
  TrueSheetActionHelpers,
11
12
  TrueSheetNavigationOptions,
12
13
  TrueSheetNavigationEventMap,
13
14
  TrueSheetNavigationState,
14
15
  TrueSheetNavigatorContentExtraProps,
16
+ TrueSheetRouterOptions,
15
17
  } from './types';
16
- import type { TrueSheetRouterOptions } from './createTrueSheetRouter';
17
18
 
18
19
  export interface TrueSheetNavigationTypeBag extends StandardNavigationTypeBagBase {
19
20
  State: TrueSheetNavigationState<this['ParamList']>;
@@ -62,20 +63,18 @@ export const createTrueSheetNavigator = createNavigator;
62
63
  export const createTrueSheetScreen = createScreen;
63
64
 
64
65
  export { TrueSheetActions, type TrueSheetActionType } from './actions';
65
- export {
66
- createTrueSheetRouter,
67
- type StackRouterFactory,
68
- type TrueSheetRouterOptions,
69
- } from './createTrueSheetRouter';
66
+ export { createTrueSheetRouter } from './createTrueSheetRouter';
70
67
  export { useTrueSheetNavigation } from './useTrueSheetNavigation';
71
68
 
72
69
  export type { DetentInfoEventPayload, PositionChangeEventPayload } from '../TrueSheet.types';
73
70
 
74
71
  export type {
72
+ StackRouterFactory,
75
73
  TrueSheetNavigationEventMap,
76
74
  TrueSheetNavigationHelpers,
77
75
  TrueSheetNavigationOptions,
78
76
  TrueSheetNavigationProp,
79
77
  TrueSheetNavigationState,
78
+ TrueSheetRouterOptions,
80
79
  TrueSheetScreenProps,
81
80
  } from './types';
@@ -14,6 +14,7 @@ import type {
14
14
  PositionChangeEventPayload,
15
15
  WillBlurEvent,
16
16
  WillDismissEvent,
17
+ DismissAttemptEvent,
17
18
  WillFocusEvent,
18
19
  WillPresentEvent,
19
20
  } from '../../TrueSheet.types';
@@ -78,6 +79,7 @@ export const useSheetScreenState = (props: UseSheetScreenStateProps) => {
78
79
  onDidPresent: (e: DidPresentEvent) => emitEvent('sheetDidPresent', e.nativeEvent),
79
80
  onWillDismiss: (_e: WillDismissEvent) => emitEvent('sheetWillDismiss', undefined),
80
81
  onDidDismiss,
82
+ onDismissAttempt: (_e: DismissAttemptEvent) => emitEvent('sheetDismissAttempt', undefined),
81
83
  onDetentChange: (e: DetentChangeEvent) => emitEvent('sheetDetentChange', e.nativeEvent),
82
84
  onDragBegin: (e: DragBeginEvent) => emitEvent('sheetDragBegin', e.nativeEvent),
83
85
  onDragChange: (e: DragChangeEvent) => emitEvent('sheetDragChange', e.nativeEvent),
@@ -1,21 +1,24 @@
1
+ import type { NavigatorArgs } from 'standard-navigation';
2
+
3
+ import type {
4
+ DetentInfoEventPayload,
5
+ PositionChangeEventPayload,
6
+ TrueSheetProps,
7
+ } from '../TrueSheet.types';
8
+ import type { TrueSheetActionType } from './actions';
1
9
  import type {
2
10
  DefaultNavigatorOptions,
3
11
  Descriptor,
12
+ NavigationAction,
4
13
  NavigationHelpers,
5
14
  NavigationProp,
6
15
  NavigationState,
7
16
  ParamListBase,
8
17
  RouteProp,
18
+ Router,
9
19
  StackActionHelpers,
10
- } from '@react-navigation/core';
11
- import type { NavigatorArgs } from 'standard-navigation';
12
-
13
- import type {
14
- DetentInfoEventPayload,
15
- PositionChangeEventPayload,
16
- TrueSheetProps,
17
- } from '../TrueSheet.types';
18
- import type { TrueSheetActionType } from './actions';
20
+ StackRouterOptions,
21
+ } from './base-types';
19
22
 
20
23
  export type PositionChangeHandler = (payload: PositionChangeEventPayload) => void;
21
24
 
@@ -36,6 +39,10 @@ export type TrueSheetNavigationEventMap = {
36
39
  * Event fired when the sheet has been dismissed.
37
40
  */
38
41
  sheetDidDismiss: { data: undefined };
42
+ /**
43
+ * Event fired when the user tries to dismiss a non-dismissible sheet.
44
+ */
45
+ sheetDismissAttempt: { data: undefined };
39
46
  /**
40
47
  * Event fired when the sheet's detent changes.
41
48
  */
@@ -74,18 +81,56 @@ export type TrueSheetNavigationEventMap = {
74
81
  sheetDidBlur: { data: undefined };
75
82
  };
76
83
 
77
- export type TrueSheetNavigationState<ParamList extends ParamListBase> = Omit<
78
- NavigationState<ParamList>,
84
+ /**
85
+ * A navigation state tagged as `true-sheet`, with the sheet fields the router
86
+ * adds to each route.
87
+ * Generic over the base state so each entry point can bind its own
88
+ * `NavigationState` — see `./base-types`.
89
+ */
90
+ export type TrueSheetStateOf<State extends { routes: readonly unknown[] }> = Omit<
91
+ State,
79
92
  'routes'
80
93
  > & {
81
94
  type: 'true-sheet';
82
- routes: (NavigationState<ParamList>['routes'][number] & {
95
+ routes: (State['routes'][number] & {
83
96
  resizeIndex?: number;
84
97
  resizeKey?: number;
85
98
  closing?: boolean;
99
+ // Stacked above a `closing` route and dismissed natively with it
100
+ dismissing?: boolean;
86
101
  })[];
87
102
  };
88
103
 
104
+ export type TrueSheetNavigationState<ParamList extends ParamListBase> = TrueSheetStateOf<
105
+ NavigationState<ParamList>
106
+ >;
107
+
108
+ export type TrueSheetRouterState = TrueSheetNavigationState<ParamListBase>;
109
+
110
+ export type TrueSheetRouterOptions = StackRouterOptions;
111
+
112
+ export type TrueSheetRouter = Router<TrueSheetRouterState, TrueSheetActionType>;
113
+
114
+ /**
115
+ * The wrapped router factory — also the shape `createTrueSheetRouter` accepts,
116
+ * pre-instantiated so either entry point's `StackRouterFactory` fits it.
117
+ */
118
+ export type TrueSheetRouterFactory = (options: TrueSheetRouterOptions) => TrueSheetRouter;
119
+
120
+ /**
121
+ * The base `StackRouter` factory to wrap, typed generically over the state and
122
+ * action types the wrapper threads through — `StackRouter` is structural and
123
+ * never touches the sheet-specific fields.
124
+ * Injected by each entry point so the shared router never imports
125
+ * `@react-navigation/*` at runtime (Expo Router apps don't install it).
126
+ */
127
+ export type StackRouterFactory = <
128
+ State extends NavigationState<ParamListBase>,
129
+ Action extends NavigationAction,
130
+ >(
131
+ options: TrueSheetRouterOptions
132
+ ) => Router<State, Action>;
133
+
89
134
  /**
90
135
  * `TrueSheetNavigationEventMap` in the `standard-navigation` event-map shape.
91
136
  */
@@ -108,7 +153,7 @@ export type TrueSheetEmitFn = NavigatorArgs<
108
153
  /**
109
154
  * Props injected into the navigator content by each adapter
110
155
  * (React Navigation's `mapper` / Expo Router's `createProps`).
111
- * Raw routes carry the custom fields (`closing`, `resizeIndex`, `resizeKey`)
156
+ * Raw routes carry the custom fields (`closing`, `dismissing`, `resizeIndex`, `resizeKey`)
112
157
  * that the standard state strips out.
113
158
  */
114
159
  export interface TrueSheetNavigatorContentExtraProps {
@@ -116,13 +161,20 @@ export interface TrueSheetNavigatorContentExtraProps {
116
161
  dispatch: TrueSheetDispatch;
117
162
  }
118
163
 
119
- export type TrueSheetActionHelpers<ParamList extends ParamListBase> =
120
- StackActionHelpers<ParamList> & {
121
- /**
122
- * Resize the sheet to a specific detent index.
123
- */
124
- resize(index?: number): void;
125
- };
164
+ /**
165
+ * Generic over the base helpers so each entry point can bind its own
166
+ * `StackActionHelpers` — see `./base-types`.
167
+ */
168
+ export type TrueSheetActionHelpersOf<Helpers> = Helpers & {
169
+ /**
170
+ * Resize the sheet to a specific detent index.
171
+ */
172
+ resize(index?: number): void;
173
+ };
174
+
175
+ export type TrueSheetActionHelpers<ParamList extends ParamListBase> = TrueSheetActionHelpersOf<
176
+ StackActionHelpers<ParamList>
177
+ >;
126
178
 
127
179
  export type TrueSheetNavigationProp<
128
180
  ParamList extends ParamListBase,
@@ -156,6 +208,9 @@ export type TrueSheetNavigationSheetProps = Pick<
156
208
  TrueSheetProps,
157
209
  | 'detents'
158
210
  | 'backgroundColor'
211
+ | 'detentBackgrounds'
212
+ | 'background'
213
+ | 'backgroundStyle'
159
214
  | 'cornerRadius'
160
215
  | 'dismissible'
161
216
  | 'draggable'
@@ -163,9 +218,10 @@ export type TrueSheetNavigationSheetProps = Pick<
163
218
  | 'grabberOptions'
164
219
  | 'accessibilityOptions'
165
220
  | 'dimmed'
221
+ | 'dimColor'
222
+ | 'dimOpacity'
166
223
  | 'dimmedDetentIndex'
167
224
  | 'backgroundBlur'
168
- | 'blurOptions'
169
225
  | 'maxContentHeight'
170
226
  | 'maxContentWidth'
171
227
  | 'presentation'
@@ -176,10 +232,12 @@ export type TrueSheetNavigationSheetProps = Pick<
176
232
  | 'footer'
177
233
  | 'footerStyle'
178
234
  | 'footerOptions'
235
+ | 'scrollableRef'
179
236
  | 'scrollableOptions'
180
237
  | 'insetAdjustment'
181
- | 'anchor'
182
- | 'anchorOffset'
238
+ | 'placement'
239
+ | 'placementOffset'
240
+ | 'foldOptions'
183
241
  | 'elevation'
184
242
  | 'detached'
185
243
  | 'detachedOffset'
@@ -0,0 +1,25 @@
1
+ const ACCESSORS = ['getScrollableNode', 'getNativeScrollRef'] as const;
2
+
3
+ // Resolves a `scrollableRef` value to its scroll node: a native tag on native,
4
+ // a DOM node on web. Imperative-handle lists (e.g. LegendList, FlashList) are
5
+ // not host components, so they go through the accessors ScrollView/FlatList
6
+ // also expose. A composite result is resolved again until it yields a tag or
7
+ // host node. `getScrollResponder` is skipped: it returns the ScrollView class
8
+ // instance, which findNodeHandle resolves to its first host child (the
9
+ // SwipeRefreshLayout on Android when a refreshControl is set).
10
+ export function resolveScrollable(scrollable: unknown): unknown {
11
+ if (!scrollable || typeof scrollable !== 'object') return scrollable;
12
+ for (const name of ACCESSORS) {
13
+ const accessor = (scrollable as Record<string, unknown>)[name];
14
+ if (typeof accessor !== 'function') continue;
15
+ let node: unknown;
16
+ try {
17
+ node = accessor.call(scrollable);
18
+ } catch {
19
+ // e.g. LegendList forwarding to a custom scroll component that lacks it
20
+ continue;
21
+ }
22
+ if (node != null && node !== scrollable) return resolveScrollable(node);
23
+ }
24
+ return scrollable;
25
+ }
@@ -4,7 +4,7 @@ export const DEFAULT_FORM_SHEET_WIDTH = 580;
4
4
  export const DEFAULT_FORM_SHEET_HEIGHT_RATIO = 0.5;
5
5
  export const COLOR_SURFACE_CONTAINER_LOW_LIGHT = '#F7F2FA';
6
6
  export const COLOR_SURFACE_CONTAINER_LOW_DARK = '#1D1B20';
7
- export const DEFAULT_ANCHOR_OFFSET = 16;
7
+ export const DEFAULT_PLACEMENT_OFFSET = 16;
8
8
  export const DEFAULT_DETACHED_OFFSET = 16;
9
9
  export const DEFAULT_GRABBER_COLOR_LIGHT = 'rgba(0, 0, 0, 0.3)';
10
10
  export const DEFAULT_GRABBER_COLOR_DARK = 'rgba(255, 255, 255, 0.3)';
@@ -0,0 +1,79 @@
1
+ /// <reference lib="dom" />
2
+ import { useEffect, useState } from 'react';
3
+
4
+ import { FOOTER_INSET } from './layout';
5
+ import { getScrollParent } from './vaul/use-prevent-scroll';
6
+ import type { KeyboardViewport } from './vaul/types';
7
+
8
+ // Subpixel tolerance between the visual and layout viewport heights
9
+ const VIEWPORT_EPSILON = 1;
10
+
11
+ const readKeyboardViewport = (): KeyboardViewport | undefined => {
12
+ const vv = window.visualViewport;
13
+ if (!vv) return undefined;
14
+ const layoutHeight = document.documentElement.clientHeight;
15
+ // Pinch-zoom shrinks the visual viewport too — scaling it back out leaves
16
+ // only what the keyboard covers.
17
+ if (vv.height * vv.scale >= layoutHeight - VIEWPORT_EPSILON) return undefined;
18
+ return { top: vv.offsetTop, height: vv.height, layoutHeight };
19
+ };
20
+
21
+ const isSameViewport = (a: KeyboardViewport | undefined, b: KeyboardViewport | undefined) =>
22
+ a === b ||
23
+ (a !== undefined &&
24
+ b !== undefined &&
25
+ a.top === b.top &&
26
+ a.height === b.height &&
27
+ a.layoutHeight === b.layoutHeight);
28
+
29
+ /**
30
+ * Tracks the visual viewport while a soft keyboard shrinks it. iOS Safari and
31
+ * Chrome (default `interactive-widget`) keep the layout viewport — and every
32
+ * fixed element — full height under the keyboard, so the sheet has to be laid
33
+ * out against the visual viewport instead.
34
+ */
35
+ export function useKeyboardViewport(enabled: boolean): KeyboardViewport | undefined {
36
+ const [viewport, setViewport] = useState<KeyboardViewport | undefined>();
37
+
38
+ useEffect(() => {
39
+ const vv = window.visualViewport;
40
+ if (!enabled || !vv) {
41
+ setViewport(undefined);
42
+ return undefined;
43
+ }
44
+
45
+ const update = () => {
46
+ const next = readKeyboardViewport();
47
+ setViewport((current) => (isSameViewport(current, next) ? current : next));
48
+ };
49
+
50
+ update();
51
+ vv.addEventListener('resize', update);
52
+ vv.addEventListener('scroll', update);
53
+ window.addEventListener('resize', update);
54
+ return () => {
55
+ vv.removeEventListener('resize', update);
56
+ vv.removeEventListener('scroll', update);
57
+ window.removeEventListener('resize', update);
58
+ };
59
+ }, [enabled]);
60
+
61
+ return viewport;
62
+ }
63
+
64
+ /**
65
+ * Scrolls the focused field in `container` back above its scroll parent's
66
+ * bottom edge, clearing a floating footer. The browser only reveals it on
67
+ * focus — before the sheet fits above the keyboard.
68
+ */
69
+ export function revealFocusedElement(container: HTMLElement) {
70
+ const focused = document.activeElement;
71
+ if (!(focused instanceof HTMLElement) || !container.contains(focused)) return;
72
+ const scroller = getScrollParent(focused);
73
+ if (!container.contains(scroller)) return;
74
+ const footerInset = parseFloat(getComputedStyle(scroller).getPropertyValue(FOOTER_INSET)) || 0;
75
+ const overflow =
76
+ focused.getBoundingClientRect().bottom -
77
+ (scroller.getBoundingClientRect().bottom - footerInset);
78
+ if (overflow > 0) scroller.scrollTop += overflow;
79
+ }
@@ -0,0 +1,196 @@
1
+ /// <reference lib="dom" />
2
+
3
+ export const FOOTER_INSET = '--truesheet-footer-inset';
4
+
5
+ interface SheetLayoutOptions {
6
+ drawer: HTMLElement;
7
+ layout: HTMLElement;
8
+ getContent: () => HTMLElement | null;
9
+ getHeader: () => HTMLElement | null;
10
+ getFooter: () => HTMLElement | null;
11
+ getScrollable: () => HTMLElement | null;
12
+ absoluteHeader: boolean;
13
+ absoluteFooter: boolean;
14
+ footerInsetAdjustment: boolean;
15
+ measureContent: boolean;
16
+ onHeightChange: (height: number) => void;
17
+ }
18
+
19
+ export function observeSheetLayout({
20
+ drawer,
21
+ layout,
22
+ getContent,
23
+ getHeader,
24
+ getFooter,
25
+ getScrollable,
26
+ absoluteHeader,
27
+ absoluteFooter,
28
+ footerInsetAdjustment,
29
+ measureContent,
30
+ onHeightChange,
31
+ }: SheetLayoutOptions) {
32
+ let frame = 0;
33
+ let disposed = false;
34
+ let width = -1;
35
+ let height = -1;
36
+ let scroller: HTMLElement | null = null;
37
+ let originalPadding = '';
38
+ let insetPadding = '';
39
+ let appliedInset = 0;
40
+ const observed = new Set<Element>();
41
+
42
+ // This tree has no viewport constraint or injected footer inset. Its resize
43
+ // observer catches intrinsic changes without observing the live flex layout.
44
+ const measurement = measureContent ? document.createElement('div') : null;
45
+ if (measurement) {
46
+ Object.assign(measurement.style, {
47
+ position: 'absolute',
48
+ top: '0',
49
+ left: '0',
50
+ display: 'flex',
51
+ flexDirection: 'column',
52
+ visibility: 'hidden',
53
+ pointerEvents: 'none',
54
+ });
55
+ measurement.style.setProperty(FOOTER_INSET, '0px');
56
+ measurement.inert = true;
57
+ measurement.setAttribute('aria-hidden', 'true');
58
+ measurement.setAttribute('data-truesheet-measure', '');
59
+ drawer.appendChild(measurement);
60
+ }
61
+
62
+ const measure = () => {
63
+ if (!measurement?.isConnected) return;
64
+ const headerHeight = absoluteHeader ? 0 : (getHeader()?.offsetHeight ?? 0);
65
+ const footerHeight =
66
+ !absoluteFooter || (footerInsetAdjustment && scroller) ? (getFooter()?.offsetHeight ?? 0) : 0;
67
+ const next = measurement.offsetHeight + headerHeight + footerHeight;
68
+ if (height === next) return;
69
+ height = next;
70
+ onHeightChange(next);
71
+ };
72
+
73
+ const updateInset = () => {
74
+ let inset = 0;
75
+ const footer = getFooter();
76
+ if (footerInsetAdjustment && scroller && footer) {
77
+ let bottom = scroller.offsetTop + scroller.offsetHeight;
78
+ let parent = scroller.offsetParent;
79
+ while (parent instanceof HTMLElement && parent !== layout) {
80
+ bottom += parent.offsetTop;
81
+ parent = parent.offsetParent;
82
+ }
83
+ if (parent === layout) {
84
+ inset = Math.min(
85
+ footer.offsetHeight,
86
+ Math.max(0, bottom - (layout.clientHeight - footer.offsetHeight))
87
+ );
88
+ }
89
+ }
90
+ if (inset === appliedInset) return;
91
+ appliedInset = inset;
92
+ layout.style.setProperty(FOOTER_INSET, `${inset}px`);
93
+ };
94
+
95
+ const resizeObserver = new ResizeObserver(() => {
96
+ if (measurement && width !== layout.clientWidth) {
97
+ width = layout.clientWidth;
98
+ measurement.style.width = `${width}px`;
99
+ }
100
+ updateInset();
101
+ measure();
102
+ });
103
+ const measurementObserver = new ResizeObserver(measure);
104
+ if (measurement) measurementObserver.observe(measurement);
105
+
106
+ const restorePadding = () => {
107
+ if (scroller && scroller.style.paddingBottom === insetPadding) {
108
+ scroller.style.paddingBottom = originalPadding;
109
+ }
110
+ };
111
+
112
+ const sync = () => {
113
+ if (disposed) return;
114
+ const content = getContent();
115
+ const nextScroller = getScrollable();
116
+ if (nextScroller !== scroller) {
117
+ restorePadding();
118
+ scroller = nextScroller;
119
+ insetPadding = '';
120
+ }
121
+ if (
122
+ footerInsetAdjustment &&
123
+ scroller &&
124
+ (!insetPadding || scroller.style.paddingBottom !== insetPadding)
125
+ ) {
126
+ originalPadding = scroller.style.paddingBottom;
127
+ const base = getComputedStyle(scroller).paddingBottom;
128
+ insetPadding = `calc(${base} + var(${FOOTER_INSET}, 0px))`;
129
+ scroller.style.paddingBottom = insetPadding;
130
+ insetPadding = scroller.style.paddingBottom;
131
+ }
132
+
133
+ const nodes = new Set<Element>([layout]);
134
+ for (const node of [getHeader(), getFooter(), scroller]) {
135
+ if (node) nodes.add(node);
136
+ }
137
+ for (const node of observed) {
138
+ if (!nodes.has(node)) {
139
+ resizeObserver.unobserve(node);
140
+ observed.delete(node);
141
+ }
142
+ }
143
+ for (const node of nodes) {
144
+ if (!observed.has(node)) {
145
+ resizeObserver.observe(node);
146
+ observed.add(node);
147
+ }
148
+ }
149
+
150
+ if (measurement && content) {
151
+ width = layout.clientWidth;
152
+ measurement.style.width = `${width}px`;
153
+ measurement.replaceChildren(content.cloneNode(true));
154
+ }
155
+ updateInset();
156
+ measure();
157
+ };
158
+
159
+ const mutationObserver = new MutationObserver((mutations) => {
160
+ const changed = mutations.some(
161
+ (mutation) => mutation.target !== layout || mutation.type === 'childList'
162
+ );
163
+ if (!changed || frame) return;
164
+ frame = requestAnimationFrame(() => {
165
+ frame = 0;
166
+ sync();
167
+ });
168
+ });
169
+
170
+ sync();
171
+ mutationObserver.observe(layout, {
172
+ childList: true,
173
+ characterData: true,
174
+ attributes: true,
175
+ attributeFilter: ['style', 'class'],
176
+ subtree: true,
177
+ });
178
+ const footer = getFooter();
179
+ if (absoluteFooter && footer) {
180
+ mutationObserver.observe(footer, { childList: true, characterData: true, subtree: true });
181
+ }
182
+
183
+ return {
184
+ measure,
185
+ disconnect: () => {
186
+ disposed = true;
187
+ cancelAnimationFrame(frame);
188
+ mutationObserver.disconnect();
189
+ resizeObserver.disconnect();
190
+ measurementObserver.disconnect();
191
+ restorePadding();
192
+ layout.style.removeProperty(FOOTER_INSET);
193
+ measurement?.remove();
194
+ },
195
+ };
196
+ }
@@ -9,6 +9,15 @@ export const DEFAULT_PEEK_HEIGHT = 150;
9
9
 
10
10
  export const CLOSE_THRESHOLD = 0.25;
11
11
 
12
+ // Compose Material3 SheetState's dismiss thresholds, used by the 'short'
13
+ // dismiss threshold: velocity in px/ms, distance in px.
14
+ export const SHORT_DISMISS_VELOCITY = 0.125;
15
+ export const SHORT_DISMISS_DISTANCE = 56;
16
+
17
+ // Minimum downward pull (px) on a non-dismissible drawer at its first snap
18
+ // point before the release counts as a dismiss attempt.
19
+ export const DISMISS_ATTEMPT_THRESHOLD = 24;
20
+
12
21
  export const SCROLL_LOCK_TIMEOUT = 100;
13
22
 
14
23
  export const BORDER_RADIUS = 8;