@lodev09/react-native-true-sheet 4.0.0-beta.0 → 4.0.0-beta.10

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 (430) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +62 -30
  3. package/RNTrueSheet.podspec +10 -2
  4. package/android/build.gradle +24 -2
  5. package/android/src/main/java/com/lodev09/truesheet/TrueSheetContainerView.kt +189 -47
  6. package/android/src/main/java/com/lodev09/truesheet/TrueSheetContainerViewManager.kt +7 -0
  7. package/android/src/main/java/com/lodev09/truesheet/TrueSheetContentView.kt +401 -19
  8. package/android/src/main/java/com/lodev09/truesheet/TrueSheetContentViewManager.kt +18 -0
  9. package/android/src/main/java/com/lodev09/truesheet/TrueSheetFooterView.kt +145 -21
  10. package/android/src/main/java/com/lodev09/truesheet/TrueSheetFooterViewManager.kt +14 -0
  11. package/android/src/main/java/com/lodev09/truesheet/TrueSheetHeaderView.kt +38 -0
  12. package/android/src/main/java/com/lodev09/truesheet/TrueSheetHeaderViewManager.kt +28 -0
  13. package/android/src/main/java/com/lodev09/truesheet/TrueSheetModule.kt +84 -24
  14. package/android/src/main/java/com/lodev09/truesheet/TrueSheetOverlayView.kt +106 -0
  15. package/android/src/main/java/com/lodev09/truesheet/TrueSheetOverlayViewManager.kt +45 -0
  16. package/android/src/main/java/com/lodev09/truesheet/TrueSheetPackage.kt +6 -4
  17. package/android/src/main/java/com/lodev09/truesheet/TrueSheetPeekView.kt +72 -0
  18. package/android/src/main/java/com/lodev09/truesheet/TrueSheetPeekViewManager.kt +33 -0
  19. package/android/src/main/java/com/lodev09/truesheet/TrueSheetStateUpdater.kt +63 -0
  20. package/android/src/main/java/com/lodev09/truesheet/TrueSheetView.kt +564 -226
  21. package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewController.kt +1399 -598
  22. package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewManager.kt +161 -29
  23. package/android/src/main/java/com/lodev09/truesheet/core/RNScreensEventObserver.kt +63 -0
  24. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetBottomSheetBehavior.kt +36 -0
  25. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetBottomSheetView.kt +255 -0
  26. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetCoordinatorLayout.kt +375 -0
  27. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDetentCalculator.kt +299 -0
  28. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDimView.kt +162 -0
  29. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetGrabberView.kt +180 -0
  30. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetKeyboardObserver.kt +207 -0
  31. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetOverlayRootView.kt +137 -0
  32. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetStackManager.kt +220 -0
  33. package/android/src/main/java/com/lodev09/truesheet/events/TrueSheetDragEvents.kt +71 -0
  34. package/android/src/main/java/com/lodev09/truesheet/events/TrueSheetFocusEvents.kt +65 -0
  35. package/android/src/main/java/com/lodev09/truesheet/events/TrueSheetLifecycleEvents.kt +127 -0
  36. package/android/src/main/java/com/lodev09/truesheet/events/TrueSheetStateEvents.kt +56 -0
  37. package/android/src/main/java/com/lodev09/truesheet/utils/KeyboardUtils.kt +84 -0
  38. package/android/src/main/java/com/lodev09/truesheet/utils/ScreenUtils.kt +93 -67
  39. package/android/src/main/java/com/lodev09/truesheet/utils/TouchEventDeduper.kt +31 -0
  40. package/android/src/main/java/com/lodev09/truesheet/utils/ViewUtils.kt +42 -0
  41. package/android/src/main/jni/CMakeLists.txt +63 -0
  42. package/android/src/main/jni/TrueSheetSpec.h +20 -0
  43. package/android/src/main/jni/TrueSheetStateUpdater.cpp +96 -0
  44. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewComponentDescriptor.h +16 -0
  45. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewShadowNode.cpp +68 -0
  46. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewShadowNode.h +33 -0
  47. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewState.cpp +11 -0
  48. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewState.h +39 -0
  49. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewComponentDescriptor.h +24 -0
  50. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewShadowNode.cpp +63 -0
  51. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewShadowNode.h +28 -0
  52. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewState.cpp +11 -0
  53. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewState.h +41 -0
  54. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetInsets.cpp +18 -0
  55. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetInsets.h +16 -0
  56. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetLayoutUtils.h +46 -0
  57. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetOverlayViewComponentDescriptor.h +21 -0
  58. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetOverlayViewShadowNode.cpp +17 -0
  59. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetOverlayViewShadowNode.h +36 -0
  60. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewComponentDescriptor.h +28 -0
  61. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewShadowNode.cpp +30 -0
  62. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewShadowNode.h +45 -0
  63. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewState.cpp +23 -0
  64. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewState.h +52 -0
  65. package/ios/TrueSheetContainerView.h +88 -6
  66. package/ios/TrueSheetContainerView.mm +278 -21
  67. package/ios/TrueSheetContentView.h +54 -1
  68. package/ios/TrueSheetContentView.mm +371 -47
  69. package/ios/TrueSheetFooterView.h +33 -2
  70. package/ios/TrueSheetFooterView.mm +187 -35
  71. package/ios/{events/OnWillDismissEvent.h → TrueSheetHeaderView.h} +10 -7
  72. package/ios/TrueSheetHeaderView.mm +64 -0
  73. package/ios/TrueSheetModule.h +2 -7
  74. package/ios/TrueSheetModule.mm +98 -20
  75. package/ios/TrueSheetOverlayView.h +32 -0
  76. package/ios/TrueSheetOverlayView.mm +161 -0
  77. package/ios/TrueSheetPeekView.h +32 -0
  78. package/ios/TrueSheetPeekView.mm +99 -0
  79. package/ios/TrueSheetView.h +7 -15
  80. package/ios/TrueSheetView.mm +775 -215
  81. package/ios/TrueSheetViewController.h +94 -16
  82. package/ios/TrueSheetViewController.mm +1316 -331
  83. package/ios/core/RNScreensEventObserver.h +46 -0
  84. package/ios/core/RNScreensEventObserver.mm +280 -0
  85. package/ios/core/TrueSheetBlurView.h +27 -0
  86. package/ios/core/TrueSheetBlurView.mm +82 -0
  87. package/ios/core/TrueSheetDetentCalculator.h +107 -0
  88. package/ios/core/TrueSheetDetentCalculator.mm +197 -0
  89. package/ios/core/TrueSheetGrabberView.h +72 -0
  90. package/ios/core/TrueSheetGrabberView.mm +188 -0
  91. package/ios/core/TrueSheetKeyboardObserver.h +39 -0
  92. package/ios/core/TrueSheetKeyboardObserver.mm +112 -0
  93. package/ios/core/TrueSheetOverlayContainerView.h +31 -0
  94. package/ios/core/TrueSheetOverlayContainerView.mm +35 -0
  95. package/ios/events/TrueSheetDragEvents.h +39 -0
  96. package/ios/events/TrueSheetDragEvents.mm +62 -0
  97. package/ios/events/{OnPositionChangeEvent.h → TrueSheetFocusEvents.h} +8 -5
  98. package/ios/events/TrueSheetFocusEvents.mm +49 -0
  99. package/ios/events/TrueSheetLifecycleEvents.h +42 -0
  100. package/ios/events/TrueSheetLifecycleEvents.mm +79 -0
  101. package/ios/events/TrueSheetStateEvents.h +35 -0
  102. package/ios/events/TrueSheetStateEvents.mm +49 -0
  103. package/ios/tvos/TrueSheetStubs.mm +166 -0
  104. package/ios/{events/OnMountEvent.h → utils/BlurUtil.h} +5 -7
  105. package/ios/utils/BlurUtil.mm +69 -0
  106. package/ios/utils/GestureUtil.h +7 -0
  107. package/ios/utils/GestureUtil.mm +12 -0
  108. package/ios/utils/PlatformUtil.h +15 -0
  109. package/ios/utils/UIView+FirstResponder.h +15 -0
  110. package/ios/utils/UIView+FirstResponder.mm +26 -0
  111. package/ios/utils/UIView+ScrollEdgeInteraction.h +26 -0
  112. package/ios/utils/UIView+ScrollEdgeInteraction.mm +84 -0
  113. package/ios/utils/WindowUtil.mm +17 -1
  114. package/lib/module/TrueSheet.js +349 -74
  115. package/lib/module/TrueSheet.js.map +1 -1
  116. package/lib/module/TrueSheet.web.js +1270 -0
  117. package/lib/module/TrueSheet.web.js.map +1 -0
  118. package/lib/module/TrueSheetOverlay.js +30 -0
  119. package/lib/module/TrueSheetOverlay.js.map +1 -0
  120. package/lib/module/TrueSheetOverlay.web.js +35 -0
  121. package/lib/module/TrueSheetOverlay.web.js.map +1 -0
  122. package/lib/module/TrueSheetPeek.js +15 -0
  123. package/lib/module/TrueSheetPeek.js.map +1 -0
  124. package/lib/module/TrueSheetPeek.web.js +55 -0
  125. package/lib/module/TrueSheetPeek.web.js.map +1 -0
  126. package/lib/module/TrueSheetProvider.js +28 -0
  127. package/lib/module/TrueSheetProvider.js.map +1 -0
  128. package/lib/module/TrueSheetProvider.web.js +157 -0
  129. package/lib/module/TrueSheetProvider.web.js.map +1 -0
  130. package/lib/module/fabric/TrueSheetContainerViewNativeComponent.ts +1 -1
  131. package/lib/module/fabric/TrueSheetContentViewNativeComponent.ts +5 -1
  132. package/lib/module/fabric/TrueSheetFooterViewNativeComponent.ts +10 -2
  133. package/lib/module/fabric/TrueSheetHeaderViewNativeComponent.ts +8 -0
  134. package/lib/module/fabric/TrueSheetOverlayViewNativeComponent.ts +12 -0
  135. package/lib/module/fabric/TrueSheetPeekViewNativeComponent.ts +8 -0
  136. package/lib/module/fabric/TrueSheetViewNativeComponent.ts +110 -18
  137. package/lib/module/index.js +4 -3
  138. package/lib/module/index.js.map +1 -1
  139. package/lib/module/mocks/index.js +103 -0
  140. package/lib/module/mocks/index.js.map +1 -0
  141. package/lib/module/mocks/navigation.js +95 -0
  142. package/lib/module/mocks/navigation.js.map +1 -0
  143. package/lib/module/mocks/navigationExpoRouter.js +21 -0
  144. package/lib/module/mocks/navigationExpoRouter.js.map +1 -0
  145. package/lib/module/mocks/reanimated.js +91 -0
  146. package/lib/module/mocks/reanimated.js.map +1 -0
  147. package/lib/module/navigation/TrueSheetNavigatorContent.js +73 -0
  148. package/lib/module/navigation/TrueSheetNavigatorContent.js.map +1 -0
  149. package/lib/module/navigation/actions.js +50 -0
  150. package/lib/module/navigation/actions.js.map +1 -0
  151. package/lib/module/navigation/base-types.js +2 -0
  152. package/lib/module/navigation/base-types.js.map +1 -0
  153. package/lib/module/navigation/createTrueSheetRouter.js +157 -0
  154. package/lib/module/navigation/createTrueSheetRouter.js.map +1 -0
  155. package/lib/module/navigation/expo-router/base-types.js +2 -0
  156. package/lib/module/navigation/expo-router/base-types.js.map +1 -0
  157. package/lib/module/navigation/expo-router/index.js +50 -0
  158. package/lib/module/navigation/expo-router/index.js.map +1 -0
  159. package/lib/module/navigation/expo-router/types.js +4 -0
  160. package/lib/module/navigation/expo-router/types.js.map +1 -0
  161. package/lib/module/navigation/index.js +47 -0
  162. package/lib/module/navigation/index.js.map +1 -0
  163. package/lib/module/navigation/navigator.js +10 -0
  164. package/lib/module/navigation/navigator.js.map +1 -0
  165. package/lib/module/navigation/screen/ReanimatedTrueSheetScreen.js +56 -0
  166. package/lib/module/navigation/screen/ReanimatedTrueSheetScreen.js.map +1 -0
  167. package/lib/module/navigation/screen/TrueSheetScreen.js +49 -0
  168. package/lib/module/navigation/screen/TrueSheetScreen.js.map +1 -0
  169. package/lib/module/navigation/screen/index.js +5 -0
  170. package/lib/module/navigation/screen/index.js.map +1 -0
  171. package/lib/module/navigation/screen/types.js +4 -0
  172. package/lib/module/navigation/screen/types.js.map +1 -0
  173. package/lib/module/navigation/screen/useSheetScreenState.js +69 -0
  174. package/lib/module/navigation/screen/useSheetScreenState.js.map +1 -0
  175. package/lib/module/navigation/types.js +4 -0
  176. package/lib/module/navigation/types.js.map +1 -0
  177. package/lib/module/navigation/useTrueSheetNavigation.js +24 -0
  178. package/lib/module/navigation/useTrueSheetNavigation.js.map +1 -0
  179. package/lib/module/reanimated/ReanimatedTrueSheet.js +15 -9
  180. package/lib/module/reanimated/ReanimatedTrueSheet.js.map +1 -1
  181. package/lib/module/reanimated/ReanimatedTrueSheet.web.js +81 -0
  182. package/lib/module/reanimated/ReanimatedTrueSheet.web.js.map +1 -0
  183. package/lib/module/reanimated/ReanimatedTrueSheetProvider.js +4 -2
  184. package/lib/module/reanimated/ReanimatedTrueSheetProvider.js.map +1 -1
  185. package/lib/module/reanimated/index.js +2 -2
  186. package/lib/module/reanimated/index.js.map +1 -1
  187. package/lib/module/reanimated/useReanimatedPositionChangeHandler.web.js +20 -0
  188. package/lib/module/reanimated/useReanimatedPositionChangeHandler.web.js.map +1 -0
  189. package/lib/module/specs/NativeTrueSheetModule.js.map +1 -1
  190. package/lib/module/web/constants.js +16 -0
  191. package/lib/module/web/constants.js.map +1 -0
  192. package/lib/module/web/dom.js +10 -0
  193. package/lib/module/web/dom.js.map +1 -0
  194. package/lib/module/web/vaul/README.md +9 -0
  195. package/lib/module/web/vaul/browser.js +30 -0
  196. package/lib/module/web/vaul/browser.js.map +1 -0
  197. package/lib/module/web/vaul/constants.js +19 -0
  198. package/lib/module/web/vaul/constants.js.map +1 -0
  199. package/lib/module/web/vaul/context.js +59 -0
  200. package/lib/module/web/vaul/context.js.map +1 -0
  201. package/lib/module/web/vaul/helpers.js +99 -0
  202. package/lib/module/web/vaul/helpers.js.map +1 -0
  203. package/lib/module/web/vaul/index.js +1342 -0
  204. package/lib/module/web/vaul/index.js.map +1 -0
  205. package/lib/module/web/vaul/style.css +287 -0
  206. package/lib/module/web/vaul/style.css.d.js +2 -0
  207. package/lib/module/web/vaul/style.css.d.js.map +1 -0
  208. package/lib/module/web/vaul/types.js +2 -0
  209. package/lib/module/web/vaul/types.js.map +1 -0
  210. package/lib/module/web/vaul/use-composed-refs.js +34 -0
  211. package/lib/module/web/vaul/use-composed-refs.js.map +1 -0
  212. package/lib/module/web/vaul/use-controllable-state.js +54 -0
  213. package/lib/module/web/vaul/use-controllable-state.js.map +1 -0
  214. package/lib/module/web/vaul/use-position-fixed.js +123 -0
  215. package/lib/module/web/vaul/use-position-fixed.js.map +1 -0
  216. package/lib/module/web/vaul/use-prevent-scroll.js +258 -0
  217. package/lib/module/web/vaul/use-prevent-scroll.js.map +1 -0
  218. package/lib/module/web/vaul/use-scale-background.js +57 -0
  219. package/lib/module/web/vaul/use-scale-background.js.map +1 -0
  220. package/lib/module/web/vaul/use-snap-points.js +305 -0
  221. package/lib/module/web/vaul/use-snap-points.js.map +1 -0
  222. package/lib/typescript/src/TrueSheet.d.ts +57 -14
  223. package/lib/typescript/src/TrueSheet.d.ts.map +1 -1
  224. package/lib/typescript/src/TrueSheet.types.d.ts +535 -55
  225. package/lib/typescript/src/TrueSheet.types.d.ts.map +1 -1
  226. package/lib/typescript/src/TrueSheet.web.d.ts +5 -0
  227. package/lib/typescript/src/TrueSheet.web.d.ts.map +1 -0
  228. package/lib/typescript/src/TrueSheetOverlay.d.ts +8 -0
  229. package/lib/typescript/src/TrueSheetOverlay.d.ts.map +1 -0
  230. package/lib/typescript/src/TrueSheetOverlay.web.d.ts +8 -0
  231. package/lib/typescript/src/TrueSheetOverlay.web.d.ts.map +1 -0
  232. package/lib/typescript/src/TrueSheetPeek.d.ts +9 -0
  233. package/lib/typescript/src/TrueSheetPeek.d.ts.map +1 -0
  234. package/lib/typescript/src/TrueSheetPeek.web.d.ts +28 -0
  235. package/lib/typescript/src/TrueSheetPeek.web.d.ts.map +1 -0
  236. package/lib/typescript/src/TrueSheetProvider.d.ts +18 -0
  237. package/lib/typescript/src/TrueSheetProvider.d.ts.map +1 -0
  238. package/lib/typescript/src/TrueSheetProvider.web.d.ts +27 -0
  239. package/lib/typescript/src/TrueSheetProvider.web.d.ts.map +1 -0
  240. package/lib/typescript/src/fabric/TrueSheetContainerViewNativeComponent.d.ts.map +1 -1
  241. package/lib/typescript/src/fabric/TrueSheetContentViewNativeComponent.d.ts.map +1 -1
  242. package/lib/typescript/src/fabric/TrueSheetFooterViewNativeComponent.d.ts +2 -0
  243. package/lib/typescript/src/fabric/TrueSheetFooterViewNativeComponent.d.ts.map +1 -1
  244. package/lib/typescript/src/fabric/TrueSheetHeaderViewNativeComponent.d.ts +6 -0
  245. package/lib/typescript/src/fabric/TrueSheetHeaderViewNativeComponent.d.ts.map +1 -0
  246. package/lib/typescript/src/fabric/TrueSheetOverlayViewNativeComponent.d.ts +6 -0
  247. package/lib/typescript/src/fabric/TrueSheetOverlayViewNativeComponent.d.ts.map +1 -0
  248. package/lib/typescript/src/fabric/TrueSheetPeekViewNativeComponent.d.ts +6 -0
  249. package/lib/typescript/src/fabric/TrueSheetPeekViewNativeComponent.d.ts.map +1 -0
  250. package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts +71 -16
  251. package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts.map +1 -1
  252. package/lib/typescript/src/index.d.ts +3 -2
  253. package/lib/typescript/src/index.d.ts.map +1 -1
  254. package/lib/typescript/src/mocks/index.d.ts +47 -0
  255. package/lib/typescript/src/mocks/index.d.ts.map +1 -0
  256. package/lib/typescript/src/mocks/navigation.d.ts +70 -0
  257. package/lib/typescript/src/mocks/navigation.d.ts.map +1 -0
  258. package/lib/typescript/src/mocks/navigationExpoRouter.d.ts +22 -0
  259. package/lib/typescript/src/mocks/navigationExpoRouter.d.ts.map +1 -0
  260. package/lib/typescript/src/mocks/reanimated.d.ts +48 -0
  261. package/lib/typescript/src/mocks/reanimated.d.ts.map +1 -0
  262. package/lib/typescript/src/navigation/TrueSheetNavigatorContent.d.ts +5 -0
  263. package/lib/typescript/src/navigation/TrueSheetNavigatorContent.d.ts.map +1 -0
  264. package/lib/typescript/src/navigation/actions.d.ts +71 -0
  265. package/lib/typescript/src/navigation/actions.d.ts.map +1 -0
  266. package/lib/typescript/src/navigation/base-types.d.ts +9 -0
  267. package/lib/typescript/src/navigation/base-types.d.ts.map +1 -0
  268. package/lib/typescript/src/navigation/createTrueSheetRouter.d.ts +3 -0
  269. package/lib/typescript/src/navigation/createTrueSheetRouter.d.ts.map +1 -0
  270. package/lib/typescript/src/navigation/expo-router/base-types.d.ts +8 -0
  271. package/lib/typescript/src/navigation/expo-router/base-types.d.ts.map +1 -0
  272. package/lib/typescript/src/navigation/expo-router/index.d.ts +37 -0
  273. package/lib/typescript/src/navigation/expo-router/index.d.ts.map +1 -0
  274. package/lib/typescript/src/navigation/expo-router/types.d.ts +44 -0
  275. package/lib/typescript/src/navigation/expo-router/types.d.ts.map +1 -0
  276. package/lib/typescript/src/navigation/index.d.ts +45 -0
  277. package/lib/typescript/src/navigation/index.d.ts.map +1 -0
  278. package/lib/typescript/src/navigation/navigator.d.ts +7 -0
  279. package/lib/typescript/src/navigation/navigator.d.ts.map +1 -0
  280. package/lib/typescript/src/navigation/screen/ReanimatedTrueSheetScreen.d.ts +3 -0
  281. package/lib/typescript/src/navigation/screen/ReanimatedTrueSheetScreen.d.ts.map +1 -0
  282. package/lib/typescript/src/navigation/screen/TrueSheetScreen.d.ts +3 -0
  283. package/lib/typescript/src/navigation/screen/TrueSheetScreen.d.ts.map +1 -0
  284. package/lib/typescript/src/navigation/screen/index.d.ts +4 -0
  285. package/lib/typescript/src/navigation/screen/index.d.ts.map +1 -0
  286. package/lib/typescript/src/navigation/screen/types.d.ts +14 -0
  287. package/lib/typescript/src/navigation/screen/types.d.ts.map +1 -0
  288. package/lib/typescript/src/navigation/screen/useSheetScreenState.d.ts +34 -0
  289. package/lib/typescript/src/navigation/screen/useSheetScreenState.d.ts.map +1 -0
  290. package/lib/typescript/src/navigation/types.d.ts +213 -0
  291. package/lib/typescript/src/navigation/types.d.ts.map +1 -0
  292. package/lib/typescript/src/navigation/useTrueSheetNavigation.d.ts +23 -0
  293. package/lib/typescript/src/navigation/useTrueSheetNavigation.d.ts.map +1 -0
  294. package/lib/typescript/src/reanimated/ReanimatedTrueSheet.d.ts.map +1 -1
  295. package/lib/typescript/src/reanimated/ReanimatedTrueSheet.web.d.ts +41 -0
  296. package/lib/typescript/src/reanimated/ReanimatedTrueSheet.web.d.ts.map +1 -0
  297. package/lib/typescript/src/reanimated/ReanimatedTrueSheetProvider.d.ts +8 -2
  298. package/lib/typescript/src/reanimated/ReanimatedTrueSheetProvider.d.ts.map +1 -1
  299. package/lib/typescript/src/reanimated/useReanimatedPositionChangeHandler.web.d.ts +15 -0
  300. package/lib/typescript/src/reanimated/useReanimatedPositionChangeHandler.web.d.ts.map +1 -0
  301. package/lib/typescript/src/specs/NativeTrueSheetModule.d.ts +25 -3
  302. package/lib/typescript/src/specs/NativeTrueSheetModule.d.ts.map +1 -1
  303. package/lib/typescript/src/web/constants.d.ts +14 -0
  304. package/lib/typescript/src/web/constants.d.ts.map +1 -0
  305. package/lib/typescript/src/web/dom.d.ts +7 -0
  306. package/lib/typescript/src/web/dom.d.ts.map +1 -0
  307. package/lib/typescript/src/web/vaul/browser.d.ts +8 -0
  308. package/lib/typescript/src/web/vaul/browser.d.ts.map +1 -0
  309. package/lib/typescript/src/web/vaul/constants.d.ts +14 -0
  310. package/lib/typescript/src/web/vaul/constants.d.ts.map +1 -0
  311. package/lib/typescript/src/web/vaul/context.d.ts +54 -0
  312. package/lib/typescript/src/web/vaul/context.d.ts.map +1 -0
  313. package/lib/typescript/src/web/vaul/helpers.d.ts +17 -0
  314. package/lib/typescript/src/web/vaul/helpers.d.ts.map +1 -0
  315. package/lib/typescript/src/web/vaul/index.d.ts +234 -0
  316. package/lib/typescript/src/web/vaul/index.d.ts.map +1 -0
  317. package/lib/typescript/src/web/vaul/types.d.ts +7 -0
  318. package/lib/typescript/src/web/vaul/types.d.ts.map +1 -0
  319. package/lib/typescript/src/web/vaul/use-composed-refs.d.ts +14 -0
  320. package/lib/typescript/src/web/vaul/use-composed-refs.d.ts.map +1 -0
  321. package/lib/typescript/src/web/vaul/use-controllable-state.d.ts +9 -0
  322. package/lib/typescript/src/web/vaul/use-controllable-state.d.ts.map +1 -0
  323. package/lib/typescript/src/web/vaul/use-position-fixed.d.ts +19 -0
  324. package/lib/typescript/src/web/vaul/use-position-fixed.d.ts.map +1 -0
  325. package/lib/typescript/src/web/vaul/use-prevent-scroll.d.ts +18 -0
  326. package/lib/typescript/src/web/vaul/use-prevent-scroll.d.ts.map +1 -0
  327. package/lib/typescript/src/web/vaul/use-scale-background.d.ts +2 -0
  328. package/lib/typescript/src/web/vaul/use-scale-background.d.ts.map +1 -0
  329. package/lib/typescript/src/web/vaul/use-snap-points.d.ts +38 -0
  330. package/lib/typescript/src/web/vaul/use-snap-points.d.ts.map +1 -0
  331. package/package.json +104 -37
  332. package/react-native.config.js +10 -2
  333. package/src/TrueSheet.tsx +424 -70
  334. package/src/TrueSheet.types.ts +602 -72
  335. package/src/TrueSheet.web.tsx +1437 -0
  336. package/src/TrueSheetOverlay.tsx +24 -0
  337. package/src/TrueSheetOverlay.web.tsx +33 -0
  338. package/src/TrueSheetPeek.tsx +11 -0
  339. package/src/TrueSheetPeek.web.tsx +64 -0
  340. package/src/TrueSheetProvider.tsx +33 -0
  341. package/src/TrueSheetProvider.web.tsx +220 -0
  342. package/src/fabric/TrueSheetContainerViewNativeComponent.ts +1 -1
  343. package/src/fabric/TrueSheetContentViewNativeComponent.ts +5 -1
  344. package/src/fabric/TrueSheetFooterViewNativeComponent.ts +10 -2
  345. package/src/fabric/TrueSheetHeaderViewNativeComponent.ts +8 -0
  346. package/src/fabric/TrueSheetOverlayViewNativeComponent.ts +12 -0
  347. package/src/fabric/TrueSheetPeekViewNativeComponent.ts +8 -0
  348. package/src/fabric/TrueSheetViewNativeComponent.ts +110 -18
  349. package/src/index.ts +3 -2
  350. package/src/mocks/index.ts +96 -0
  351. package/src/mocks/navigation.ts +79 -0
  352. package/src/mocks/navigationExpoRouter.ts +41 -0
  353. package/src/mocks/reanimated.ts +100 -0
  354. package/src/navigation/TrueSheetNavigatorContent.tsx +106 -0
  355. package/src/navigation/actions.ts +78 -0
  356. package/src/navigation/base-types.ts +20 -0
  357. package/src/navigation/createTrueSheetRouter.ts +194 -0
  358. package/src/navigation/expo-router/base-types.ts +18 -0
  359. package/src/navigation/expo-router/index.ts +90 -0
  360. package/src/navigation/expo-router/types.ts +116 -0
  361. package/src/navigation/index.ts +80 -0
  362. package/src/navigation/navigator.ts +18 -0
  363. package/src/navigation/screen/ReanimatedTrueSheetScreen.tsx +61 -0
  364. package/src/navigation/screen/TrueSheetScreen.tsx +54 -0
  365. package/src/navigation/screen/index.ts +3 -0
  366. package/src/navigation/screen/types.ts +19 -0
  367. package/src/navigation/screen/useSheetScreenState.ts +102 -0
  368. package/src/navigation/types.ts +302 -0
  369. package/src/navigation/useTrueSheetNavigation.ts +26 -0
  370. package/src/reanimated/ReanimatedTrueSheet.tsx +12 -7
  371. package/src/reanimated/ReanimatedTrueSheet.web.tsx +75 -0
  372. package/src/reanimated/ReanimatedTrueSheetProvider.tsx +12 -8
  373. package/src/reanimated/useReanimatedPositionChangeHandler.web.ts +31 -0
  374. package/src/specs/NativeTrueSheetModule.ts +28 -3
  375. package/src/web/constants.ts +13 -0
  376. package/src/web/dom.ts +9 -0
  377. package/src/web/vaul/README.md +9 -0
  378. package/src/web/vaul/browser.ts +38 -0
  379. package/src/web/vaul/constants.ts +24 -0
  380. package/src/web/vaul/context.ts +102 -0
  381. package/src/web/vaul/helpers.ts +131 -0
  382. package/src/web/vaul/index.tsx +1785 -0
  383. package/src/web/vaul/style.css +287 -0
  384. package/src/web/vaul/style.css.d.ts +1 -0
  385. package/src/web/vaul/types.ts +7 -0
  386. package/src/web/vaul/use-composed-refs.ts +35 -0
  387. package/src/web/vaul/use-controllable-state.ts +66 -0
  388. package/src/web/vaul/use-position-fixed.ts +147 -0
  389. package/src/web/vaul/use-prevent-scroll.ts +309 -0
  390. package/src/web/vaul/use-scale-background.ts +64 -0
  391. package/src/web/vaul/use-snap-points.ts +455 -0
  392. package/android/src/main/java/com/lodev09/truesheet/events/DetentChangeEvent.kt +0 -26
  393. package/android/src/main/java/com/lodev09/truesheet/events/DidDismissEvent.kt +0 -20
  394. package/android/src/main/java/com/lodev09/truesheet/events/DidPresentEvent.kt +0 -26
  395. package/android/src/main/java/com/lodev09/truesheet/events/DragBeginEvent.kt +0 -26
  396. package/android/src/main/java/com/lodev09/truesheet/events/DragChangeEvent.kt +0 -26
  397. package/android/src/main/java/com/lodev09/truesheet/events/DragEndEvent.kt +0 -26
  398. package/android/src/main/java/com/lodev09/truesheet/events/MountEvent.kt +0 -20
  399. package/android/src/main/java/com/lodev09/truesheet/events/PositionChangeEvent.kt +0 -32
  400. package/android/src/main/java/com/lodev09/truesheet/events/SizeChangeEvent.kt +0 -27
  401. package/android/src/main/java/com/lodev09/truesheet/events/WillDismissEvent.kt +0 -20
  402. package/android/src/main/java/com/lodev09/truesheet/events/WillPresentEvent.kt +0 -26
  403. package/android/src/main/res/values/styles.xml +0 -8
  404. package/ios/events/OnDetentChangeEvent.h +0 -28
  405. package/ios/events/OnDetentChangeEvent.mm +0 -30
  406. package/ios/events/OnDidDismissEvent.h +0 -26
  407. package/ios/events/OnDidDismissEvent.mm +0 -25
  408. package/ios/events/OnDidPresentEvent.h +0 -28
  409. package/ios/events/OnDidPresentEvent.mm +0 -30
  410. package/ios/events/OnDragBeginEvent.h +0 -28
  411. package/ios/events/OnDragBeginEvent.mm +0 -30
  412. package/ios/events/OnDragChangeEvent.h +0 -28
  413. package/ios/events/OnDragChangeEvent.mm +0 -30
  414. package/ios/events/OnDragEndEvent.h +0 -28
  415. package/ios/events/OnDragEndEvent.mm +0 -30
  416. package/ios/events/OnMountEvent.mm +0 -25
  417. package/ios/events/OnPositionChangeEvent.mm +0 -32
  418. package/ios/events/OnSizeChangeEvent.h +0 -28
  419. package/ios/events/OnSizeChangeEvent.mm +0 -30
  420. package/ios/events/OnWillDismissEvent.mm +0 -25
  421. package/ios/events/OnWillPresentEvent.h +0 -28
  422. package/ios/events/OnWillPresentEvent.mm +0 -30
  423. package/ios/utils/LayoutUtil.h +0 -44
  424. package/ios/utils/LayoutUtil.mm +0 -50
  425. package/lib/module/TrueSheetGrabber.js +0 -51
  426. package/lib/module/TrueSheetGrabber.js.map +0 -1
  427. package/lib/typescript/src/TrueSheetGrabber.d.ts +0 -39
  428. package/lib/typescript/src/TrueSheetGrabber.d.ts.map +0 -1
  429. package/src/TrueSheetGrabber.tsx +0 -82
  430. package/src/__mocks__/index.js +0 -67
package/src/TrueSheet.tsx CHANGED
@@ -4,12 +4,16 @@ import {
4
4
  createRef,
5
5
  type ReactNode,
6
6
  type ComponentRef,
7
+ type ComponentType,
7
8
  isValidElement,
8
9
  createElement,
10
+ useEffect,
9
11
  } from 'react';
10
12
 
11
13
  import type {
12
14
  TrueSheetProps,
15
+ TrueSheetMethods,
16
+ TrueSheetStaticMethods,
13
17
  DragBeginEvent,
14
18
  DragChangeEvent,
15
19
  DragEndEvent,
@@ -19,17 +23,49 @@ import type {
19
23
  PositionChangeEvent,
20
24
  DidDismissEvent,
21
25
  WillDismissEvent,
26
+ DismissAttemptEvent,
22
27
  MountEvent,
23
- SizeChangeEvent,
28
+ WillFocusEvent,
29
+ DidFocusEvent,
30
+ WillBlurEvent,
31
+ DidBlurEvent,
24
32
  } from './TrueSheet.types';
25
33
  import TrueSheetViewNativeComponent from './fabric/TrueSheetViewNativeComponent';
26
34
  import TrueSheetContainerViewNativeComponent from './fabric/TrueSheetContainerViewNativeComponent';
27
35
  import TrueSheetContentViewNativeComponent from './fabric/TrueSheetContentViewNativeComponent';
36
+ import TrueSheetHeaderViewNativeComponent from './fabric/TrueSheetHeaderViewNativeComponent';
28
37
  import TrueSheetFooterViewNativeComponent from './fabric/TrueSheetFooterViewNativeComponent';
29
38
 
30
39
  import TrueSheetModule from './specs/NativeTrueSheetModule';
31
40
 
32
- import { Platform, processColor, StyleSheet, findNodeHandle } from 'react-native';
41
+ import {
42
+ Platform,
43
+ StyleSheet,
44
+ BackHandler,
45
+ RootTagContext,
46
+ findNodeHandle,
47
+ processColor,
48
+ type NativeEventSubscription,
49
+ type GestureResponderEvent,
50
+ type RootTag,
51
+ type StyleProp,
52
+ type ViewStyle,
53
+ } from 'react-native';
54
+
55
+ interface AppContainerProps {
56
+ rootTag: RootTag;
57
+ rootViewStyle?: StyleProp<ViewStyle>;
58
+ internal_excludeLogBox?: boolean;
59
+ children?: ReactNode;
60
+ }
61
+
62
+ // RN has no public API for hosting the element inspector inside a presented view;
63
+ // this is the internal RN's Modal uses. Dev-only so prod bundles never resolve it.
64
+ // The template literal keeps the RN babel preset's deep-import warning off while
65
+ // Metro still resolves the module statically.
66
+ const AppContainer: ComponentType<AppContainerProps> | null = __DEV__
67
+ ? require(`react-native/Libraries/ReactNative/AppContainer`).default
68
+ : null;
33
69
 
34
70
  const LINKING_ERROR =
35
71
  `The package '@lodev09/react-native-true-sheet' doesn't seem to be linked. Make sure: \n\n` +
@@ -44,17 +80,57 @@ if (!TrueSheetModule) {
44
80
 
45
81
  type NativeRef = ComponentRef<typeof TrueSheetViewNativeComponent>;
46
82
 
83
+ // Stop raw touch events from bubbling past the sheet to outside ancestors
84
+ const stopTouchPropagation = (event: GestureResponderEvent) => event.stopPropagation();
85
+
86
+ // Stop the responder negotiation at the sheet boundary without claiming the
87
+ // responder. Views inside the sheet are asked before this one, so in-sheet
88
+ // touchables work normally; views outside are asked after, so stopping here
89
+ // keeps unclaimed touches from leaking to touchables behind the sheet.
90
+ // Claiming instead (returning true) would steal the responder from a pressed
91
+ // touchable whenever the negotiation re-runs mid-gesture — e.g. a second
92
+ // finger, or the duplicate touch stream from a nested react-native-screens
93
+ // screen that attaches its own touch handler inside the sheet.
94
+ const stopResponderNegotiation = (event: GestureResponderEvent) => {
95
+ event.stopPropagation();
96
+ return false;
97
+ };
98
+
47
99
  interface TrueSheetState {
48
100
  shouldRenderNativeView: boolean;
49
- containerWidth?: number;
50
- containerHeight?: number;
101
+ initialPresentReady: boolean;
102
+ scrollableHandle: number | null;
51
103
  }
52
104
 
53
- export class TrueSheet extends PureComponent<TrueSheetProps, TrueSheetState> {
105
+ // Gates auto-present (initialDetentIndex) by one commit. Rendered last in the
106
+ // sheet subtree so its mount effect runs after the content's mount effects —
107
+ // updates they schedule (e.g. a navigation footer via setOptions) batch with
108
+ // onReady's, so native receives initialDetentIndex together with the settled
109
+ // tree and presents at the final height instead of resizing mid-flight.
110
+ const InitialPresentGate = ({ onReady }: { onReady: () => void }) => {
111
+ useEffect(() => {
112
+ onReady();
113
+ }, [onReady]);
114
+
115
+ return null;
116
+ };
117
+
118
+ export class TrueSheet
119
+ extends PureComponent<TrueSheetProps, TrueSheetState>
120
+ implements TrueSheetMethods
121
+ {
54
122
  displayName = 'TrueSheet';
55
123
 
124
+ static contextType = RootTagContext;
125
+
56
126
  private readonly nativeRef: RefObject<NativeRef | null>;
57
127
 
128
+ private cachedGrabberOptions: TrueSheetProps['grabberOptions'] | undefined;
129
+ private resolvedGrabberOptions: Record<string, unknown> | undefined;
130
+ private backHandlerSubscription: NativeEventSubscription | null = null;
131
+ private isPresented: boolean = false;
132
+ private isSheetVisible: boolean = true;
133
+
58
134
  /**
59
135
  * Map of sheet names against their instances.
60
136
  */
@@ -65,6 +141,11 @@ export class TrueSheet extends PureComponent<TrueSheetProps, TrueSheetState> {
65
141
  */
66
142
  private presentationResolver: (() => void) | null = null;
67
143
 
144
+ /**
145
+ * Tracks if a present operation is in progress
146
+ */
147
+ private isPresenting: boolean = false;
148
+
68
149
  constructor(props: TrueSheetProps) {
69
150
  super(props);
70
151
 
@@ -72,19 +153,21 @@ export class TrueSheet extends PureComponent<TrueSheetProps, TrueSheetState> {
72
153
 
73
154
  this.validateDetents();
74
155
 
75
- // Lazy load by default, except when initialDetentIndex is set (for auto-presentation)
156
+ // Lazy load by default, except when auto-presenting or when lazy is disabled
76
157
  const shouldRenderImmediately =
77
- props.initialDetentIndex !== undefined && props.initialDetentIndex >= 0;
158
+ (props.initialDetentIndex !== undefined && props.initialDetentIndex >= 0) ||
159
+ props.lazy === false;
78
160
 
79
161
  this.state = {
80
162
  shouldRenderNativeView: shouldRenderImmediately,
81
- containerWidth: undefined,
82
- containerHeight: undefined,
163
+ initialPresentReady: false,
164
+ scrollableHandle: null,
83
165
  };
84
166
 
85
167
  this.onMount = this.onMount.bind(this);
86
168
  this.onWillDismiss = this.onWillDismiss.bind(this);
87
169
  this.onDidDismiss = this.onDidDismiss.bind(this);
170
+ this.onDismissAttempt = this.onDismissAttempt.bind(this);
88
171
  this.onWillPresent = this.onWillPresent.bind(this);
89
172
  this.onDidPresent = this.onDidPresent.bind(this);
90
173
  this.onDetentChange = this.onDetentChange.bind(this);
@@ -92,7 +175,28 @@ export class TrueSheet extends PureComponent<TrueSheetProps, TrueSheetState> {
92
175
  this.onDragChange = this.onDragChange.bind(this);
93
176
  this.onDragEnd = this.onDragEnd.bind(this);
94
177
  this.onPositionChange = this.onPositionChange.bind(this);
95
- this.onSizeChange = this.onSizeChange.bind(this);
178
+ this.onWillFocus = this.onWillFocus.bind(this);
179
+ this.onDidFocus = this.onDidFocus.bind(this);
180
+ this.onWillBlur = this.onWillBlur.bind(this);
181
+ this.onDidBlur = this.onDidBlur.bind(this);
182
+ this.handleBackPress = this.handleBackPress.bind(this);
183
+ this.onVisibilityChange = this.onVisibilityChange.bind(this);
184
+ this.onInitialPresentReady = this.onInitialPresentReady.bind(this);
185
+ }
186
+
187
+ private onInitialPresentReady(): void {
188
+ this.setState({ initialPresentReady: true });
189
+ }
190
+
191
+ // Resolves after commit (didMount/didUpdate) — the scrollable mounts with the
192
+ // sheet content, so its ref is only populated once the native tree renders.
193
+ private updateScrollableHandle(): void {
194
+ const { scrollableRef } = this.props;
195
+ const scrollableHandle = scrollableRef?.current ? findNodeHandle(scrollableRef.current) : null;
196
+
197
+ if (scrollableHandle !== this.state.scrollableHandle) {
198
+ this.setState({ scrollableHandle });
199
+ }
96
200
  }
97
201
 
98
202
  private validateDetents(): void {
@@ -108,7 +212,7 @@ export class TrueSheet extends PureComponent<TrueSheetProps, TrueSheetState> {
108
212
  // Warn for invalid detent fractions
109
213
  if (detents) {
110
214
  detents.forEach((detent, index) => {
111
- if (detent !== 'auto' && typeof detent === 'number') {
215
+ if (typeof detent === 'number' && detent !== -1 && detent !== -2) {
112
216
  if (detent <= 0 || detent > 1) {
113
217
  console.warn(
114
218
  `TrueSheet: detent at index ${index} (${detent}) should be between 0 and 1. It will be clamped.`
@@ -152,31 +256,53 @@ export class TrueSheet extends PureComponent<TrueSheetProps, TrueSheetState> {
152
256
  * Present the sheet by given `name` (Promise-based)
153
257
  * @param name - Sheet name (must match sheet's name prop)
154
258
  * @param index - Detent index (default: 0)
259
+ * @param animated - Whether to animate the presentation (default: true)
155
260
  * @returns Promise that resolves when sheet is fully presented
156
261
  * @throws Error if sheet not found or presentation fails
157
262
  */
158
- public static async present(name: string, index: number = 0): Promise<void> {
263
+ public static async present(
264
+ name: string,
265
+ index: number = 0,
266
+ animated: boolean = true
267
+ ): Promise<void> {
159
268
  const instance = TrueSheet.getInstance(name);
160
269
  if (!instance) {
161
270
  throw new Error(`Sheet with name "${name}" not found`);
162
271
  }
163
272
 
164
- return instance.present(index);
273
+ return instance.present(index, animated);
165
274
  }
166
275
 
167
276
  /**
168
277
  * Dismiss the sheet by given `name` (Promise-based)
169
278
  * @param name - Sheet name
279
+ * @param animated - Whether to animate the dismissal (default: true)
170
280
  * @returns Promise that resolves when sheet is fully dismissed
171
281
  * @throws Error if sheet not found or dismissal fails
172
282
  */
173
- public static async dismiss(name: string): Promise<void> {
283
+ public static async dismiss(name: string, animated: boolean = true): Promise<void> {
174
284
  const instance = TrueSheet.getInstance(name);
175
285
  if (!instance) {
176
286
  throw new Error(`Sheet with name "${name}" not found`);
177
287
  }
178
288
 
179
- return instance.dismiss();
289
+ return instance.dismiss(animated);
290
+ }
291
+
292
+ /**
293
+ * Dismiss only the sheets presented on top of a sheet by given `name`
294
+ * @param name - Sheet name
295
+ * @param animated - Whether to animate the dismissal (default: true)
296
+ * @returns Promise that resolves when all child sheets are dismissed
297
+ * @throws Error if sheet not found
298
+ */
299
+ public static async dismissStack(name: string, animated: boolean = true): Promise<void> {
300
+ const instance = TrueSheet.getInstance(name);
301
+ if (!instance) {
302
+ throw new Error(`Sheet with name "${name}" not found`);
303
+ }
304
+
305
+ return instance.dismissStack(animated);
180
306
  }
181
307
 
182
308
  /**
@@ -195,6 +321,16 @@ export class TrueSheet extends PureComponent<TrueSheetProps, TrueSheetState> {
195
321
  return instance.resize(index);
196
322
  }
197
323
 
324
+ /**
325
+ * Dismiss all presented sheets by dismissing from the bottom of the stack.
326
+ * This ensures child sheets are dismissed first before their parent.
327
+ * @param animated - Whether to animate the dismissals (default: true)
328
+ * @returns Promise that resolves when all sheets are dismissed
329
+ */
330
+ public static async dismissAll(animated: boolean = true): Promise<void> {
331
+ return TrueSheetModule?.dismissAll(animated);
332
+ }
333
+
198
334
  private registerInstance(): void {
199
335
  if (this.props.name) {
200
336
  TrueSheet.instances[this.props.name] = this;
@@ -216,6 +352,16 @@ export class TrueSheet extends PureComponent<TrueSheetProps, TrueSheetState> {
216
352
  }
217
353
 
218
354
  private onDidPresent(event: DidPresentEvent): void {
355
+ this.isPresented = true;
356
+
357
+ if (Platform.OS === 'android') {
358
+ this.backHandlerSubscription?.remove();
359
+ this.backHandlerSubscription = BackHandler.addEventListener(
360
+ 'hardwareBackPress',
361
+ this.handleBackPress
362
+ );
363
+ }
364
+
219
365
  this.props.onDidPresent?.(event);
220
366
  }
221
367
 
@@ -223,9 +369,21 @@ export class TrueSheet extends PureComponent<TrueSheetProps, TrueSheetState> {
223
369
  this.props.onWillDismiss?.(event);
224
370
  }
225
371
 
372
+ private onDismissAttempt(event: DismissAttemptEvent): void {
373
+ this.props.onDismissAttempt?.(event);
374
+ }
375
+
226
376
  private onDidDismiss(event: DidDismissEvent): void {
227
- // Clean up native view after dismiss for lazy loading
228
- this.setState({ shouldRenderNativeView: false });
377
+ this.isPresented = false;
378
+ this.isSheetVisible = true;
379
+ this.backHandlerSubscription?.remove();
380
+ this.backHandlerSubscription = null;
381
+
382
+ // Non-lazy content stays mounted; otherwise clean it up unless another presentation is active.
383
+ if (!this.isPresenting && this.props.lazy !== false) {
384
+ this.setState({ shouldRenderNativeView: false });
385
+ }
386
+
229
387
  this.props.onDidDismiss?.(event);
230
388
  }
231
389
 
@@ -255,23 +413,53 @@ export class TrueSheet extends PureComponent<TrueSheetProps, TrueSheetState> {
255
413
  this.props.onPositionChange?.(event);
256
414
  }
257
415
 
258
- private onSizeChange(event: SizeChangeEvent): void {
259
- const { width, height } = event.nativeEvent;
416
+ private onWillFocus(event: WillFocusEvent): void {
417
+ this.props.onWillFocus?.(event);
418
+ }
260
419
 
261
- // Update container view dimensions in state
262
- this.setState({
263
- containerWidth: width,
264
- containerHeight: height,
265
- });
420
+ private onDidFocus(event: DidFocusEvent): void {
421
+ this.props.onDidFocus?.(event);
422
+ }
266
423
 
267
- // Internal handler only - not exposed to users
424
+ private onWillBlur(event: WillBlurEvent): void {
425
+ this.props.onWillBlur?.(event);
426
+ }
427
+
428
+ private onDidBlur(event: DidBlurEvent): void {
429
+ this.props.onDidBlur?.(event);
430
+ }
431
+
432
+ private onVisibilityChange(event: { nativeEvent: { visible: boolean } }): void {
433
+ this.isSheetVisible = event.nativeEvent.visible;
434
+ }
435
+
436
+ private handleBackPress(): boolean {
437
+ if (!this.isPresented || !this.isSheetVisible) return false;
438
+
439
+ // The native view can be detached (e.g. host screen unmounted by navigation)
440
+ // before onDidDismiss removes this subscription. Treat back press as a no-op
441
+ // instead of throwing from the handle getter.
442
+ const nodeHandle = findNodeHandle(this.nativeRef.current);
443
+ if (nodeHandle == null || nodeHandle === -1) return false;
444
+
445
+ // When not dismissible, report the attempt. An attempt handler consumes the back
446
+ // press; otherwise let it propagate (e.g. navigation goes back to the previous screen)
447
+ if (this.props.dismissible === false) {
448
+ const { onDismissAttempt, onBackPress } = this.props;
449
+ onDismissAttempt?.({ nativeEvent: null } as DismissAttemptEvent);
450
+ return onBackPress?.() ?? onDismissAttempt != null;
451
+ }
452
+
453
+ TrueSheetModule?.handleBackPress(nodeHandle);
454
+ return this.props.onBackPress?.() ?? true;
268
455
  }
269
456
 
270
457
  /**
271
- * Present the Sheet by `index` (Promise-based)
272
- * @param index - Detent index (default: 0)
458
+ * Present the sheet at a given detent index.
459
+ * @param index - The detent index to present at (default: 0)
460
+ * @param animated - Whether to animate the presentation (default: true)
273
461
  */
274
- public async present(index: number = 0): Promise<void> {
462
+ public async present(index: number = 0, animated: boolean = true): Promise<void> {
275
463
  const detentsLength = Math.min(this.props.detents?.length ?? 2, 3); // Max 3 detents
276
464
  if (index < 0 || index >= detentsLength) {
277
465
  throw new Error(
@@ -279,6 +467,8 @@ export class TrueSheet extends PureComponent<TrueSheetProps, TrueSheetState> {
279
467
  );
280
468
  }
281
469
 
470
+ this.isPresenting = true;
471
+
282
472
  // Lazy load: render native view if not already rendered
283
473
  if (!this.state.shouldRenderNativeView) {
284
474
  await new Promise<void>((resolve) => {
@@ -287,68 +477,117 @@ export class TrueSheet extends PureComponent<TrueSheetProps, TrueSheetState> {
287
477
  });
288
478
  }
289
479
 
290
- return TrueSheetModule?.presentByRef(this.handle, index);
480
+ await TrueSheetModule?.presentByRef(this.handle, index, animated);
481
+ this.isPresenting = false;
291
482
  }
292
483
 
293
484
  /**
294
- * Resizes the Sheet programmatically by `index`.
295
- * This is an alias of the `present(index)` method.
485
+ * Resize the sheet to a given detent index.
486
+ * @param index - The detent index to resize to
296
487
  */
297
488
  public async resize(index: number): Promise<void> {
298
- await this.present(index);
489
+ await TrueSheetModule?.resizeByRef(this.handle, index);
490
+ }
491
+
492
+ /**
493
+ * Dismiss this sheet and all sheets presented on top of it in a single animation.
494
+ * @param animated - Whether to animate the dismissal (default: true)
495
+ */
496
+ public async dismiss(animated: boolean = true): Promise<void> {
497
+ return TrueSheetModule?.dismissByRef(this.handle, animated);
299
498
  }
300
499
 
301
500
  /**
302
- * Dismisses the Sheet
501
+ * Dismiss only the sheets presented on top of this sheet, keeping this sheet presented.
502
+ * If no sheets are presented on top, this method does nothing.
503
+ * @param animated - Whether to animate the dismissal (default: true)
303
504
  */
304
- public async dismiss(): Promise<void> {
305
- return TrueSheetModule?.dismissByRef(this.handle);
505
+ public async dismissStack(animated: boolean = true): Promise<void> {
506
+ return TrueSheetModule?.dismissStackByRef(this.handle, animated);
306
507
  }
307
508
 
308
509
  componentDidMount(): void {
309
510
  this.registerInstance();
511
+ this.updateScrollableHandle();
310
512
  }
311
513
 
312
514
  componentDidUpdate(prevProps: TrueSheetProps): void {
313
515
  this.registerInstance();
516
+ this.updateScrollableHandle();
517
+
518
+ if (
519
+ prevProps.lazy !== false &&
520
+ this.props.lazy === false &&
521
+ !this.state.shouldRenderNativeView
522
+ ) {
523
+ this.setState({ shouldRenderNativeView: true });
524
+ }
314
525
 
315
526
  // Validate when detents prop changes
316
527
  if (prevProps.detents !== this.props.detents) {
317
528
  this.validateDetents();
318
529
  }
530
+
531
+ // initialDetentIndex set at runtime on a lazily-mounted sheet: render the
532
+ // native tree so InitialPresentGate can deliver the index (constructor
533
+ // only computes this for the initial prop).
534
+ const prevInitialDetentIndex = prevProps.initialDetentIndex ?? -1;
535
+ const initialDetentIndex = this.props.initialDetentIndex ?? -1;
536
+ if (
537
+ prevInitialDetentIndex < 0 &&
538
+ initialDetentIndex >= 0 &&
539
+ !this.state.shouldRenderNativeView
540
+ ) {
541
+ this.setState({ shouldRenderNativeView: true });
542
+ }
319
543
  }
320
544
 
321
545
  componentWillUnmount(): void {
322
546
  this.unregisterInstance();
323
-
324
- // Clean up presentation resolver
547
+ this.backHandlerSubscription?.remove();
548
+ this.backHandlerSubscription = null;
325
549
  this.presentationResolver = null;
326
550
  }
327
551
 
328
552
  render(): ReactNode {
329
553
  const {
330
554
  detents = [0.5, 1],
331
- backgroundColor = 'white',
555
+ backgroundColor,
332
556
  dismissible = true,
557
+ draggable = true,
333
558
  grabber = true,
559
+ grabberOptions,
560
+ accessibilityOptions,
334
561
  dimmed = true,
335
562
  initialDetentIndex = -1,
336
563
  initialDetentAnimated = true,
337
- keyboardMode = 'resize',
338
- dimmedIndex,
339
- blurTint,
564
+ dimmedDetentIndex,
565
+ backgroundBlur,
566
+ blurOptions,
340
567
  cornerRadius,
341
- maxHeight,
342
- edgeToEdgeFullScreen,
568
+ maxContentHeight,
569
+ maxContentWidth,
570
+ anchor = 'center',
571
+ anchorOffset,
572
+ scrollableOptions,
573
+ footerOptions,
574
+ presentation = 'page',
343
575
  children,
344
576
  style,
577
+ header,
578
+ headerStyle,
579
+ headerOptions,
345
580
  footer,
346
- testID,
581
+ footerStyle,
582
+ insetAdjustment = 'automatic',
583
+ ...rest
347
584
  } = this.props;
585
+ delete rest.lazy;
348
586
 
349
587
  // Trim to max 3 detents and clamp fractions
350
- const resolvedDetents = detents.slice(0, 3).map((detent) => {
588
+ const resolvedDetents: number[] = detents.slice(0, 3).map((detent) => {
351
589
  if (detent === 'auto' || detent === -1) return -1;
590
+ if (detent === 'peek' || detent === -2) return -2;
352
591
 
353
592
  // Default to 0.1 if zero or below
354
593
  if (detent <= 0) return 0.1;
@@ -357,51 +596,135 @@ export class TrueSheet extends PureComponent<TrueSheetProps, TrueSheetState> {
357
596
  return Math.min(1, detent);
358
597
  });
359
598
 
599
+ // Hold initialDetentIndex back from native until the gate's effect flushes
600
+ // (see InitialPresentGate) — native presents when the prop lands.
601
+ const autoPresent = initialDetentIndex >= 0;
602
+ const gatedInitialDetentIndex =
603
+ autoPresent && !this.state.initialPresentReady ? -1 : initialDetentIndex;
604
+
605
+ // Cache grabberOptions to avoid creating a new object every render
606
+ if (grabberOptions !== this.cachedGrabberOptions) {
607
+ this.cachedGrabberOptions = grabberOptions;
608
+ this.resolvedGrabberOptions = {
609
+ ...grabberOptions,
610
+ color: processColor(grabberOptions?.color),
611
+ };
612
+ }
613
+
614
+ const sheetContent = (
615
+ <>
616
+ {header && (
617
+ <TrueSheetHeaderViewNativeComponent
618
+ style={[
619
+ styles.header,
620
+ headerOptions?.position === 'absolute' && styles.absoluteHeader,
621
+ headerStyle,
622
+ ]}
623
+ >
624
+ {isValidElement(header) ? header : createElement(header)}
625
+ </TrueSheetHeaderViewNativeComponent>
626
+ )}
627
+ <TrueSheetContentViewNativeComponent style={style}>
628
+ {children}
629
+ </TrueSheetContentViewNativeComponent>
630
+ {footer && (
631
+ <TrueSheetFooterViewNativeComponent
632
+ autoBottomInset={insetAdjustment === 'automatic'}
633
+ style={[
634
+ styles.footer,
635
+ footerOptions?.position === 'absolute'
636
+ ? styles.absoluteFooter
637
+ : styles.relativeFooter,
638
+ footerStyle,
639
+ ]}
640
+ >
641
+ {isValidElement(footer) ? footer : createElement(footer)}
642
+ </TrueSheetFooterViewNativeComponent>
643
+ )}
644
+ {autoPresent && !this.state.initialPresentReady && (
645
+ <InitialPresentGate onReady={this.onInitialPresentReady} />
646
+ )}
647
+ </>
648
+ );
649
+
360
650
  return (
361
651
  <TrueSheetViewNativeComponent
652
+ {...rest}
362
653
  ref={this.nativeRef}
363
654
  style={styles.sheetView}
364
655
  detents={resolvedDetents}
365
- blurTint={blurTint}
366
- background={(processColor(backgroundColor) as number) ?? 0}
656
+ backgroundBlur={backgroundBlur}
657
+ blurOptions={blurOptions}
658
+ backgroundColor={backgroundColor}
367
659
  cornerRadius={cornerRadius}
368
660
  grabber={grabber}
661
+ grabberOptions={this.resolvedGrabberOptions}
662
+ accessibilityOptions={accessibilityOptions}
369
663
  dimmed={dimmed}
370
- dimmedIndex={dimmedIndex}
371
- keyboardMode={keyboardMode}
372
- initialDetentIndex={initialDetentIndex}
664
+ dimmedDetentIndex={dimmedDetentIndex}
665
+ initialDetentIndex={gatedInitialDetentIndex}
373
666
  initialDetentAnimated={initialDetentAnimated}
374
667
  dismissible={dismissible}
375
- maxHeight={maxHeight}
376
- edgeToEdgeFullScreen={edgeToEdgeFullScreen}
668
+ draggable={draggable}
669
+ maxContentHeight={maxContentHeight}
670
+ maxContentWidth={maxContentWidth}
671
+ anchor={anchor}
672
+ anchorOffset={anchorOffset}
673
+ scrollableHandle={this.state.scrollableHandle ?? -1}
674
+ scrollableOptions={scrollableOptions}
675
+ headerOptions={headerOptions}
676
+ footerOptions={{
677
+ footerPosition: footerOptions?.position,
678
+ keyboardOffset: footerOptions?.keyboardOffset,
679
+ }}
680
+ presentation={presentation}
681
+ insetAdjustment={insetAdjustment}
377
682
  onMount={this.onMount}
378
683
  onWillPresent={this.onWillPresent}
379
684
  onDidPresent={this.onDidPresent}
380
685
  onWillDismiss={this.onWillDismiss}
381
686
  onDidDismiss={this.onDidDismiss}
687
+ onDismissAttempt={this.onDismissAttempt}
382
688
  onDetentChange={this.onDetentChange}
383
689
  onDragBegin={this.onDragBegin}
384
690
  onDragChange={this.onDragChange}
385
691
  onDragEnd={this.onDragEnd}
386
692
  onPositionChange={this.onPositionChange}
387
- onSizeChange={this.onSizeChange}
693
+ onWillFocus={this.onWillFocus}
694
+ onDidFocus={this.onDidFocus}
695
+ onWillBlur={this.onWillBlur}
696
+ onDidBlur={this.onDidBlur}
697
+ onVisibilityChange={this.onVisibilityChange}
698
+ // These must stay on this host view, not on the container. The container is
699
+ // reparented into the native sheet, so this view is never a native ancestor of
700
+ // the sheet content — this is the React-tree boundary between the sheet and
701
+ // the presenting screen, where both the responder negotiation and raw touch
702
+ // bubbling must stop.
703
+ onStartShouldSetResponder={stopResponderNegotiation}
704
+ onMoveShouldSetResponder={stopResponderNegotiation}
705
+ onTouchStart={stopTouchPropagation}
706
+ onTouchMove={stopTouchPropagation}
707
+ onTouchEnd={stopTouchPropagation}
708
+ onTouchCancel={stopTouchPropagation}
388
709
  >
389
710
  {this.state.shouldRenderNativeView && (
390
- <TrueSheetContainerViewNativeComponent
391
- testID={testID}
392
- style={{
393
- width: this.state.containerWidth,
394
- height: this.state.containerHeight,
395
- }}
396
- collapsable={false}
397
- >
398
- <TrueSheetContentViewNativeComponent style={style} collapsable={false}>
399
- {children}
400
- </TrueSheetContentViewNativeComponent>
401
- {footer && (
402
- <TrueSheetFooterViewNativeComponent style={styles.footer} collapsable={false}>
403
- {isValidElement(footer) ? footer : createElement(footer)}
404
- </TrueSheetFooterViewNativeComponent>
711
+ <TrueSheetContainerViewNativeComponent style={styles.container}>
712
+ {AppContainer ? (
713
+ // Hosts the element inspector inside the sheet, like RN's Modal does —
714
+ // the app-level one sits behind the presented sheet.
715
+ // `display: contents` keeps AppContainer's wrapper views out of both
716
+ // Yoga layout and the native tree, so header/content/footer remain the
717
+ // container's direct native children, while the inspector overlay
718
+ // anchors to the container and lines up with measured frames.
719
+ <AppContainer
720
+ rootTag={this.context as RootTag}
721
+ rootViewStyle={styles.inspectorHost}
722
+ internal_excludeLogBox
723
+ >
724
+ {sheetContent}
725
+ </AppContainer>
726
+ ) : (
727
+ sheetContent
405
728
  )}
406
729
  </TrueSheetContainerViewNativeComponent>
407
730
  )}
@@ -410,15 +733,46 @@ export class TrueSheet extends PureComponent<TrueSheetProps, TrueSheetState> {
410
733
  }
411
734
  }
412
735
 
736
+ // Compile-time check: `TrueSheet`'s static surface must satisfy `TrueSheetStaticMethods`.
737
+ TrueSheet satisfies TrueSheetStaticMethods;
738
+
413
739
  const styles = StyleSheet.create({
414
740
  sheetView: {
415
- position: 'absolute',
416
- width: '100%',
741
+ ...StyleSheet.absoluteFill,
417
742
  zIndex: -9999,
743
+ pointerEvents: 'box-none',
744
+ },
745
+ // Fill the sheet so flex layouts track the sheet's size per detent
746
+ container: {
747
+ ...StyleSheet.absoluteFill,
748
+ },
749
+ inspectorHost: {
750
+ display: 'contents',
751
+ },
752
+ header: {
753
+ pointerEvents: 'box-none',
754
+ },
755
+ // Floats over the content so it doesn't take up layout space
756
+ absoluteHeader: {
757
+ position: 'absolute',
758
+ top: 0,
759
+ left: 0,
760
+ right: 0,
761
+ zIndex: 1,
418
762
  },
419
763
  footer: {
764
+ pointerEvents: 'box-none',
765
+ },
766
+ // Pinned to the sheet's bottom edge via Yoga since the container tracks the
767
+ // sheet's visible height — takes up layout space below the content
768
+ relativeFooter: {
769
+ marginTop: 'auto',
770
+ },
771
+ // Floats over the content so it doesn't take up layout space
772
+ absoluteFooter: {
420
773
  position: 'absolute',
421
774
  left: 0,
422
775
  right: 0,
776
+ bottom: 0,
423
777
  },
424
778
  });