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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (388) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +42 -31
  3. package/RNTrueSheet.podspec +10 -2
  4. package/android/build.gradle +2 -1
  5. package/android/src/main/java/com/lodev09/truesheet/TrueSheetContainerView.kt +174 -49
  6. package/android/src/main/java/com/lodev09/truesheet/TrueSheetContainerViewManager.kt +7 -0
  7. package/android/src/main/java/com/lodev09/truesheet/TrueSheetContentView.kt +371 -18
  8. package/android/src/main/java/com/lodev09/truesheet/TrueSheetContentViewManager.kt +14 -0
  9. package/android/src/main/java/com/lodev09/truesheet/TrueSheetFooterView.kt +156 -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/TrueSheetPackage.kt +5 -4
  15. package/android/src/main/java/com/lodev09/truesheet/TrueSheetPeekView.kt +72 -0
  16. package/android/src/main/java/com/lodev09/truesheet/TrueSheetPeekViewManager.kt +33 -0
  17. package/android/src/main/java/com/lodev09/truesheet/TrueSheetStateUpdater.kt +45 -0
  18. package/android/src/main/java/com/lodev09/truesheet/TrueSheetView.kt +526 -231
  19. package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewController.kt +1224 -603
  20. package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewManager.kt +136 -29
  21. package/android/src/main/java/com/lodev09/truesheet/core/RNScreensEventObserver.kt +63 -0
  22. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetBottomSheetBehavior.kt +36 -0
  23. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetBottomSheetView.kt +255 -0
  24. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetCoordinatorLayout.kt +303 -0
  25. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDetentCalculator.kt +277 -0
  26. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDimView.kt +162 -0
  27. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetGrabberView.kt +180 -0
  28. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetKeyboardObserver.kt +207 -0
  29. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetStackManager.kt +220 -0
  30. package/android/src/main/java/com/lodev09/truesheet/events/TrueSheetDragEvents.kt +71 -0
  31. package/android/src/main/java/com/lodev09/truesheet/events/TrueSheetFocusEvents.kt +65 -0
  32. package/android/src/main/java/com/lodev09/truesheet/events/TrueSheetLifecycleEvents.kt +112 -0
  33. package/android/src/main/java/com/lodev09/truesheet/events/TrueSheetStateEvents.kt +56 -0
  34. package/android/src/main/java/com/lodev09/truesheet/utils/KeyboardUtils.kt +84 -0
  35. package/android/src/main/java/com/lodev09/truesheet/utils/ScreenUtils.kt +93 -67
  36. package/android/src/main/java/com/lodev09/truesheet/utils/TouchEventDeduper.kt +31 -0
  37. package/android/src/main/java/com/lodev09/truesheet/utils/ViewUtils.kt +30 -0
  38. package/android/src/main/jni/CMakeLists.txt +63 -0
  39. package/android/src/main/jni/TrueSheetSpec.h +19 -0
  40. package/android/src/main/jni/TrueSheetStateUpdater.cpp +96 -0
  41. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewComponentDescriptor.h +24 -0
  42. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewShadowNode.cpp +43 -0
  43. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewShadowNode.h +28 -0
  44. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewState.cpp +11 -0
  45. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewState.h +37 -0
  46. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewComponentDescriptor.h +24 -0
  47. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewShadowNode.cpp +56 -0
  48. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewShadowNode.h +28 -0
  49. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewState.cpp +11 -0
  50. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewState.h +41 -0
  51. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetInsets.cpp +18 -0
  52. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetInsets.h +16 -0
  53. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewComponentDescriptor.h +28 -0
  54. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewShadowNode.cpp +61 -0
  55. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewShadowNode.h +45 -0
  56. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewState.cpp +23 -0
  57. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewState.h +52 -0
  58. package/ios/TrueSheetContainerView.h +81 -6
  59. package/ios/TrueSheetContainerView.mm +275 -21
  60. package/ios/TrueSheetContentView.h +38 -1
  61. package/ios/TrueSheetContentView.mm +413 -43
  62. package/ios/TrueSheetFooterView.h +27 -2
  63. package/ios/TrueSheetFooterView.mm +141 -35
  64. package/ios/{events/OnDidDismissEvent.h → TrueSheetHeaderView.h} +10 -7
  65. package/ios/TrueSheetHeaderView.mm +64 -0
  66. package/ios/TrueSheetModule.mm +92 -5
  67. package/ios/TrueSheetPeekView.h +32 -0
  68. package/ios/TrueSheetPeekView.mm +99 -0
  69. package/ios/TrueSheetView.h +7 -15
  70. package/ios/TrueSheetView.mm +633 -215
  71. package/ios/TrueSheetViewController.h +84 -16
  72. package/ios/TrueSheetViewController.mm +1133 -333
  73. package/ios/core/RNScreensEventObserver.h +46 -0
  74. package/ios/core/RNScreensEventObserver.mm +280 -0
  75. package/ios/core/TrueSheetBlurView.h +27 -0
  76. package/ios/core/TrueSheetBlurView.mm +82 -0
  77. package/ios/core/TrueSheetDetentCalculator.h +107 -0
  78. package/ios/core/TrueSheetDetentCalculator.mm +197 -0
  79. package/ios/core/TrueSheetGrabberView.h +72 -0
  80. package/ios/core/TrueSheetGrabberView.mm +178 -0
  81. package/ios/core/TrueSheetKeyboardObserver.h +39 -0
  82. package/ios/core/TrueSheetKeyboardObserver.mm +112 -0
  83. package/ios/events/TrueSheetDragEvents.h +39 -0
  84. package/ios/events/TrueSheetDragEvents.mm +62 -0
  85. package/ios/events/{OnPositionChangeEvent.h → TrueSheetFocusEvents.h} +8 -5
  86. package/ios/events/TrueSheetFocusEvents.mm +49 -0
  87. package/ios/events/TrueSheetLifecycleEvents.h +40 -0
  88. package/ios/events/TrueSheetLifecycleEvents.mm +71 -0
  89. package/ios/events/TrueSheetStateEvents.h +35 -0
  90. package/ios/events/TrueSheetStateEvents.mm +49 -0
  91. package/ios/tvos/TrueSheetStubs.mm +154 -0
  92. package/ios/{events/OnMountEvent.h → utils/BlurUtil.h} +5 -7
  93. package/ios/utils/BlurUtil.mm +69 -0
  94. package/ios/utils/GestureUtil.h +7 -0
  95. package/ios/utils/GestureUtil.mm +12 -0
  96. package/ios/utils/PlatformUtil.h +15 -0
  97. package/ios/utils/UIView+FirstResponder.h +15 -0
  98. package/ios/utils/UIView+FirstResponder.mm +26 -0
  99. package/ios/{events/OnWillDismissEvent.h → utils/UIView+ScrollEdgeInteraction.h} +6 -7
  100. package/ios/utils/UIView+ScrollEdgeInteraction.mm +62 -0
  101. package/ios/utils/WindowUtil.mm +17 -1
  102. package/lib/module/TrueSheet.js +230 -64
  103. package/lib/module/TrueSheet.js.map +1 -1
  104. package/lib/module/TrueSheet.web.js +1203 -0
  105. package/lib/module/TrueSheet.web.js.map +1 -0
  106. package/lib/module/TrueSheetPeek.js +15 -0
  107. package/lib/module/TrueSheetPeek.js.map +1 -0
  108. package/lib/module/TrueSheetPeek.web.js +55 -0
  109. package/lib/module/TrueSheetPeek.web.js.map +1 -0
  110. package/lib/module/TrueSheetProvider.js +28 -0
  111. package/lib/module/TrueSheetProvider.js.map +1 -0
  112. package/lib/module/TrueSheetProvider.web.js +157 -0
  113. package/lib/module/TrueSheetProvider.web.js.map +1 -0
  114. package/lib/module/fabric/TrueSheetContainerViewNativeComponent.ts +1 -1
  115. package/lib/module/fabric/TrueSheetContentViewNativeComponent.ts +5 -1
  116. package/lib/module/fabric/TrueSheetFooterViewNativeComponent.ts +10 -2
  117. package/lib/module/fabric/TrueSheetHeaderViewNativeComponent.ts +8 -0
  118. package/lib/module/fabric/TrueSheetPeekViewNativeComponent.ts +8 -0
  119. package/lib/module/fabric/TrueSheetViewNativeComponent.ts +105 -18
  120. package/lib/module/index.js +3 -3
  121. package/lib/module/index.js.map +1 -1
  122. package/lib/module/mocks/index.js +93 -0
  123. package/lib/module/mocks/index.js.map +1 -0
  124. package/lib/module/mocks/navigation.js +95 -0
  125. package/lib/module/mocks/navigation.js.map +1 -0
  126. package/lib/module/mocks/navigationExpoRouter.js +21 -0
  127. package/lib/module/mocks/navigationExpoRouter.js.map +1 -0
  128. package/lib/module/mocks/reanimated.js +91 -0
  129. package/lib/module/mocks/reanimated.js.map +1 -0
  130. package/lib/module/navigation/TrueSheetNavigatorContent.js +73 -0
  131. package/lib/module/navigation/TrueSheetNavigatorContent.js.map +1 -0
  132. package/lib/module/navigation/actions.js +50 -0
  133. package/lib/module/navigation/actions.js.map +1 -0
  134. package/lib/module/navigation/createTrueSheetRouter.js +166 -0
  135. package/lib/module/navigation/createTrueSheetRouter.js.map +1 -0
  136. package/lib/module/navigation/expo-router/index.js +48 -0
  137. package/lib/module/navigation/expo-router/index.js.map +1 -0
  138. package/lib/module/navigation/index.js +47 -0
  139. package/lib/module/navigation/index.js.map +1 -0
  140. package/lib/module/navigation/navigator.js +10 -0
  141. package/lib/module/navigation/navigator.js.map +1 -0
  142. package/lib/module/navigation/screen/ReanimatedTrueSheetScreen.js +56 -0
  143. package/lib/module/navigation/screen/ReanimatedTrueSheetScreen.js.map +1 -0
  144. package/lib/module/navigation/screen/TrueSheetScreen.js +49 -0
  145. package/lib/module/navigation/screen/TrueSheetScreen.js.map +1 -0
  146. package/lib/module/navigation/screen/index.js +5 -0
  147. package/lib/module/navigation/screen/index.js.map +1 -0
  148. package/lib/module/navigation/screen/types.js +4 -0
  149. package/lib/module/navigation/screen/types.js.map +1 -0
  150. package/lib/module/navigation/screen/useSheetScreenState.js +68 -0
  151. package/lib/module/navigation/screen/useSheetScreenState.js.map +1 -0
  152. package/lib/module/navigation/types.js +4 -0
  153. package/lib/module/navigation/types.js.map +1 -0
  154. package/lib/module/navigation/useTrueSheetNavigation.js +24 -0
  155. package/lib/module/navigation/useTrueSheetNavigation.js.map +1 -0
  156. package/lib/module/reanimated/ReanimatedTrueSheet.js +15 -9
  157. package/lib/module/reanimated/ReanimatedTrueSheet.js.map +1 -1
  158. package/lib/module/reanimated/ReanimatedTrueSheet.web.js +81 -0
  159. package/lib/module/reanimated/ReanimatedTrueSheet.web.js.map +1 -0
  160. package/lib/module/reanimated/ReanimatedTrueSheetProvider.js +4 -2
  161. package/lib/module/reanimated/ReanimatedTrueSheetProvider.js.map +1 -1
  162. package/lib/module/reanimated/index.js +2 -2
  163. package/lib/module/reanimated/index.js.map +1 -1
  164. package/lib/module/reanimated/useReanimatedPositionChangeHandler.web.js +20 -0
  165. package/lib/module/reanimated/useReanimatedPositionChangeHandler.web.js.map +1 -0
  166. package/lib/module/specs/NativeTrueSheetModule.js.map +1 -1
  167. package/lib/module/web/constants.js +16 -0
  168. package/lib/module/web/constants.js.map +1 -0
  169. package/lib/module/web/dom.js +10 -0
  170. package/lib/module/web/dom.js.map +1 -0
  171. package/lib/module/web/vaul/README.md +9 -0
  172. package/lib/module/web/vaul/browser.js +30 -0
  173. package/lib/module/web/vaul/browser.js.map +1 -0
  174. package/lib/module/web/vaul/constants.js +15 -0
  175. package/lib/module/web/vaul/constants.js.map +1 -0
  176. package/lib/module/web/vaul/context.js +59 -0
  177. package/lib/module/web/vaul/context.js.map +1 -0
  178. package/lib/module/web/vaul/helpers.js +99 -0
  179. package/lib/module/web/vaul/helpers.js.map +1 -0
  180. package/lib/module/web/vaul/index.js +1309 -0
  181. package/lib/module/web/vaul/index.js.map +1 -0
  182. package/lib/module/web/vaul/style.css +287 -0
  183. package/lib/module/web/vaul/style.css.d.js +2 -0
  184. package/lib/module/web/vaul/style.css.d.js.map +1 -0
  185. package/lib/module/web/vaul/types.js +2 -0
  186. package/lib/module/web/vaul/types.js.map +1 -0
  187. package/lib/module/web/vaul/use-composed-refs.js +34 -0
  188. package/lib/module/web/vaul/use-composed-refs.js.map +1 -0
  189. package/lib/module/web/vaul/use-controllable-state.js +54 -0
  190. package/lib/module/web/vaul/use-controllable-state.js.map +1 -0
  191. package/lib/module/web/vaul/use-position-fixed.js +123 -0
  192. package/lib/module/web/vaul/use-position-fixed.js.map +1 -0
  193. package/lib/module/web/vaul/use-prevent-scroll.js +258 -0
  194. package/lib/module/web/vaul/use-prevent-scroll.js.map +1 -0
  195. package/lib/module/web/vaul/use-scale-background.js +57 -0
  196. package/lib/module/web/vaul/use-scale-background.js.map +1 -0
  197. package/lib/module/web/vaul/use-snap-points.js +305 -0
  198. package/lib/module/web/vaul/use-snap-points.js.map +1 -0
  199. package/lib/typescript/src/TrueSheet.d.ts +51 -14
  200. package/lib/typescript/src/TrueSheet.d.ts.map +1 -1
  201. package/lib/typescript/src/TrueSheet.types.d.ts +463 -54
  202. package/lib/typescript/src/TrueSheet.types.d.ts.map +1 -1
  203. package/lib/typescript/src/TrueSheet.web.d.ts +5 -0
  204. package/lib/typescript/src/TrueSheet.web.d.ts.map +1 -0
  205. package/lib/typescript/src/TrueSheetPeek.d.ts +9 -0
  206. package/lib/typescript/src/TrueSheetPeek.d.ts.map +1 -0
  207. package/lib/typescript/src/TrueSheetPeek.web.d.ts +28 -0
  208. package/lib/typescript/src/TrueSheetPeek.web.d.ts.map +1 -0
  209. package/lib/typescript/src/TrueSheetProvider.d.ts +18 -0
  210. package/lib/typescript/src/TrueSheetProvider.d.ts.map +1 -0
  211. package/lib/typescript/src/TrueSheetProvider.web.d.ts +27 -0
  212. package/lib/typescript/src/TrueSheetProvider.web.d.ts.map +1 -0
  213. package/lib/typescript/src/fabric/TrueSheetContainerViewNativeComponent.d.ts.map +1 -1
  214. package/lib/typescript/src/fabric/TrueSheetContentViewNativeComponent.d.ts.map +1 -1
  215. package/lib/typescript/src/fabric/TrueSheetFooterViewNativeComponent.d.ts +2 -0
  216. package/lib/typescript/src/fabric/TrueSheetFooterViewNativeComponent.d.ts.map +1 -1
  217. package/lib/typescript/src/fabric/TrueSheetHeaderViewNativeComponent.d.ts +6 -0
  218. package/lib/typescript/src/fabric/TrueSheetHeaderViewNativeComponent.d.ts.map +1 -0
  219. package/lib/typescript/src/fabric/TrueSheetPeekViewNativeComponent.d.ts +6 -0
  220. package/lib/typescript/src/fabric/TrueSheetPeekViewNativeComponent.d.ts.map +1 -0
  221. package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts +67 -16
  222. package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts.map +1 -1
  223. package/lib/typescript/src/index.d.ts +2 -2
  224. package/lib/typescript/src/index.d.ts.map +1 -1
  225. package/lib/typescript/src/mocks/index.d.ts +43 -0
  226. package/lib/typescript/src/mocks/index.d.ts.map +1 -0
  227. package/lib/typescript/src/mocks/navigation.d.ts +70 -0
  228. package/lib/typescript/src/mocks/navigation.d.ts.map +1 -0
  229. package/lib/typescript/src/mocks/navigationExpoRouter.d.ts +22 -0
  230. package/lib/typescript/src/mocks/navigationExpoRouter.d.ts.map +1 -0
  231. package/lib/typescript/src/mocks/reanimated.d.ts +48 -0
  232. package/lib/typescript/src/mocks/reanimated.d.ts.map +1 -0
  233. package/lib/typescript/src/navigation/TrueSheetNavigatorContent.d.ts +5 -0
  234. package/lib/typescript/src/navigation/TrueSheetNavigatorContent.d.ts.map +1 -0
  235. package/lib/typescript/src/navigation/actions.d.ts +71 -0
  236. package/lib/typescript/src/navigation/actions.d.ts.map +1 -0
  237. package/lib/typescript/src/navigation/createTrueSheetRouter.d.ts +14 -0
  238. package/lib/typescript/src/navigation/createTrueSheetRouter.d.ts.map +1 -0
  239. package/lib/typescript/src/navigation/expo-router/index.d.ts +37 -0
  240. package/lib/typescript/src/navigation/expo-router/index.d.ts.map +1 -0
  241. package/lib/typescript/src/navigation/index.d.ts +46 -0
  242. package/lib/typescript/src/navigation/index.d.ts.map +1 -0
  243. package/lib/typescript/src/navigation/navigator.d.ts +7 -0
  244. package/lib/typescript/src/navigation/navigator.d.ts.map +1 -0
  245. package/lib/typescript/src/navigation/screen/ReanimatedTrueSheetScreen.d.ts +3 -0
  246. package/lib/typescript/src/navigation/screen/ReanimatedTrueSheetScreen.d.ts.map +1 -0
  247. package/lib/typescript/src/navigation/screen/TrueSheetScreen.d.ts +3 -0
  248. package/lib/typescript/src/navigation/screen/TrueSheetScreen.d.ts.map +1 -0
  249. package/lib/typescript/src/navigation/screen/index.d.ts +4 -0
  250. package/lib/typescript/src/navigation/screen/index.d.ts.map +1 -0
  251. package/lib/typescript/src/navigation/screen/types.d.ts +14 -0
  252. package/lib/typescript/src/navigation/screen/types.d.ts.map +1 -0
  253. package/lib/typescript/src/navigation/screen/useSheetScreenState.d.ts +33 -0
  254. package/lib/typescript/src/navigation/screen/useSheetScreenState.d.ts.map +1 -0
  255. package/lib/typescript/src/navigation/types.d.ts +177 -0
  256. package/lib/typescript/src/navigation/types.d.ts.map +1 -0
  257. package/lib/typescript/src/navigation/useTrueSheetNavigation.d.ts +23 -0
  258. package/lib/typescript/src/navigation/useTrueSheetNavigation.d.ts.map +1 -0
  259. package/lib/typescript/src/reanimated/ReanimatedTrueSheet.d.ts.map +1 -1
  260. package/lib/typescript/src/reanimated/ReanimatedTrueSheet.web.d.ts +41 -0
  261. package/lib/typescript/src/reanimated/ReanimatedTrueSheet.web.d.ts.map +1 -0
  262. package/lib/typescript/src/reanimated/ReanimatedTrueSheetProvider.d.ts +8 -2
  263. package/lib/typescript/src/reanimated/ReanimatedTrueSheetProvider.d.ts.map +1 -1
  264. package/lib/typescript/src/reanimated/useReanimatedPositionChangeHandler.web.d.ts +15 -0
  265. package/lib/typescript/src/reanimated/useReanimatedPositionChangeHandler.web.d.ts.map +1 -0
  266. package/lib/typescript/src/specs/NativeTrueSheetModule.d.ts +25 -3
  267. package/lib/typescript/src/specs/NativeTrueSheetModule.d.ts.map +1 -1
  268. package/lib/typescript/src/web/constants.d.ts +14 -0
  269. package/lib/typescript/src/web/constants.d.ts.map +1 -0
  270. package/lib/typescript/src/web/dom.d.ts +7 -0
  271. package/lib/typescript/src/web/dom.d.ts.map +1 -0
  272. package/lib/typescript/src/web/vaul/browser.d.ts +8 -0
  273. package/lib/typescript/src/web/vaul/browser.d.ts.map +1 -0
  274. package/lib/typescript/src/web/vaul/constants.d.ts +13 -0
  275. package/lib/typescript/src/web/vaul/constants.d.ts.map +1 -0
  276. package/lib/typescript/src/web/vaul/context.d.ts +53 -0
  277. package/lib/typescript/src/web/vaul/context.d.ts.map +1 -0
  278. package/lib/typescript/src/web/vaul/helpers.d.ts +17 -0
  279. package/lib/typescript/src/web/vaul/helpers.d.ts.map +1 -0
  280. package/lib/typescript/src/web/vaul/index.d.ts +228 -0
  281. package/lib/typescript/src/web/vaul/index.d.ts.map +1 -0
  282. package/lib/typescript/src/web/vaul/types.d.ts +7 -0
  283. package/lib/typescript/src/web/vaul/types.d.ts.map +1 -0
  284. package/lib/typescript/src/web/vaul/use-composed-refs.d.ts +14 -0
  285. package/lib/typescript/src/web/vaul/use-composed-refs.d.ts.map +1 -0
  286. package/lib/typescript/src/web/vaul/use-controllable-state.d.ts +9 -0
  287. package/lib/typescript/src/web/vaul/use-controllable-state.d.ts.map +1 -0
  288. package/lib/typescript/src/web/vaul/use-position-fixed.d.ts +19 -0
  289. package/lib/typescript/src/web/vaul/use-position-fixed.d.ts.map +1 -0
  290. package/lib/typescript/src/web/vaul/use-prevent-scroll.d.ts +18 -0
  291. package/lib/typescript/src/web/vaul/use-prevent-scroll.d.ts.map +1 -0
  292. package/lib/typescript/src/web/vaul/use-scale-background.d.ts +2 -0
  293. package/lib/typescript/src/web/vaul/use-scale-background.d.ts.map +1 -0
  294. package/lib/typescript/src/web/vaul/use-snap-points.d.ts +38 -0
  295. package/lib/typescript/src/web/vaul/use-snap-points.d.ts.map +1 -0
  296. package/package.json +95 -36
  297. package/react-native.config.js +9 -2
  298. package/src/TrueSheet.tsx +281 -62
  299. package/src/TrueSheet.types.ts +525 -71
  300. package/src/TrueSheet.web.tsx +1362 -0
  301. package/src/TrueSheetPeek.tsx +11 -0
  302. package/src/TrueSheetPeek.web.tsx +64 -0
  303. package/src/TrueSheetProvider.tsx +33 -0
  304. package/src/TrueSheetProvider.web.tsx +220 -0
  305. package/src/fabric/TrueSheetContainerViewNativeComponent.ts +1 -1
  306. package/src/fabric/TrueSheetContentViewNativeComponent.ts +5 -1
  307. package/src/fabric/TrueSheetFooterViewNativeComponent.ts +10 -2
  308. package/src/fabric/TrueSheetHeaderViewNativeComponent.ts +8 -0
  309. package/src/fabric/TrueSheetPeekViewNativeComponent.ts +8 -0
  310. package/src/fabric/TrueSheetViewNativeComponent.ts +105 -18
  311. package/src/index.ts +2 -2
  312. package/src/mocks/index.ts +89 -0
  313. package/src/mocks/navigation.ts +79 -0
  314. package/src/mocks/navigationExpoRouter.ts +40 -0
  315. package/src/mocks/reanimated.ts +100 -0
  316. package/src/navigation/TrueSheetNavigatorContent.tsx +106 -0
  317. package/src/navigation/actions.ts +78 -0
  318. package/src/navigation/createTrueSheetRouter.ts +222 -0
  319. package/src/navigation/expo-router/index.ts +89 -0
  320. package/src/navigation/index.ts +81 -0
  321. package/src/navigation/navigator.ts +18 -0
  322. package/src/navigation/screen/ReanimatedTrueSheetScreen.tsx +61 -0
  323. package/src/navigation/screen/TrueSheetScreen.tsx +54 -0
  324. package/src/navigation/screen/index.ts +3 -0
  325. package/src/navigation/screen/types.ts +19 -0
  326. package/src/navigation/screen/useSheetScreenState.ts +100 -0
  327. package/src/navigation/types.ts +251 -0
  328. package/src/navigation/useTrueSheetNavigation.ts +26 -0
  329. package/src/reanimated/ReanimatedTrueSheet.tsx +12 -7
  330. package/src/reanimated/ReanimatedTrueSheet.web.tsx +75 -0
  331. package/src/reanimated/ReanimatedTrueSheetProvider.tsx +12 -8
  332. package/src/reanimated/useReanimatedPositionChangeHandler.web.ts +31 -0
  333. package/src/specs/NativeTrueSheetModule.ts +28 -3
  334. package/src/web/constants.ts +13 -0
  335. package/src/web/dom.ts +9 -0
  336. package/src/web/vaul/README.md +9 -0
  337. package/src/web/vaul/browser.ts +38 -0
  338. package/src/web/vaul/constants.ts +20 -0
  339. package/src/web/vaul/context.ts +101 -0
  340. package/src/web/vaul/helpers.ts +131 -0
  341. package/src/web/vaul/index.tsx +1740 -0
  342. package/src/web/vaul/style.css +287 -0
  343. package/src/web/vaul/style.css.d.ts +1 -0
  344. package/src/web/vaul/types.ts +7 -0
  345. package/src/web/vaul/use-composed-refs.ts +35 -0
  346. package/src/web/vaul/use-controllable-state.ts +66 -0
  347. package/src/web/vaul/use-position-fixed.ts +147 -0
  348. package/src/web/vaul/use-prevent-scroll.ts +309 -0
  349. package/src/web/vaul/use-scale-background.ts +64 -0
  350. package/src/web/vaul/use-snap-points.ts +455 -0
  351. package/android/src/main/java/com/lodev09/truesheet/events/DetentChangeEvent.kt +0 -26
  352. package/android/src/main/java/com/lodev09/truesheet/events/DidDismissEvent.kt +0 -20
  353. package/android/src/main/java/com/lodev09/truesheet/events/DidPresentEvent.kt +0 -26
  354. package/android/src/main/java/com/lodev09/truesheet/events/DragBeginEvent.kt +0 -26
  355. package/android/src/main/java/com/lodev09/truesheet/events/DragChangeEvent.kt +0 -26
  356. package/android/src/main/java/com/lodev09/truesheet/events/DragEndEvent.kt +0 -26
  357. package/android/src/main/java/com/lodev09/truesheet/events/MountEvent.kt +0 -20
  358. package/android/src/main/java/com/lodev09/truesheet/events/PositionChangeEvent.kt +0 -32
  359. package/android/src/main/java/com/lodev09/truesheet/events/SizeChangeEvent.kt +0 -27
  360. package/android/src/main/java/com/lodev09/truesheet/events/WillDismissEvent.kt +0 -20
  361. package/android/src/main/java/com/lodev09/truesheet/events/WillPresentEvent.kt +0 -26
  362. package/android/src/main/res/values/styles.xml +0 -8
  363. package/ios/events/OnDetentChangeEvent.h +0 -28
  364. package/ios/events/OnDetentChangeEvent.mm +0 -30
  365. package/ios/events/OnDidDismissEvent.mm +0 -25
  366. package/ios/events/OnDidPresentEvent.h +0 -28
  367. package/ios/events/OnDidPresentEvent.mm +0 -30
  368. package/ios/events/OnDragBeginEvent.h +0 -28
  369. package/ios/events/OnDragBeginEvent.mm +0 -30
  370. package/ios/events/OnDragChangeEvent.h +0 -28
  371. package/ios/events/OnDragChangeEvent.mm +0 -30
  372. package/ios/events/OnDragEndEvent.h +0 -28
  373. package/ios/events/OnDragEndEvent.mm +0 -30
  374. package/ios/events/OnMountEvent.mm +0 -25
  375. package/ios/events/OnPositionChangeEvent.mm +0 -32
  376. package/ios/events/OnSizeChangeEvent.h +0 -28
  377. package/ios/events/OnSizeChangeEvent.mm +0 -30
  378. package/ios/events/OnWillDismissEvent.mm +0 -25
  379. package/ios/events/OnWillPresentEvent.h +0 -28
  380. package/ios/events/OnWillPresentEvent.mm +0 -30
  381. package/ios/utils/LayoutUtil.h +0 -44
  382. package/ios/utils/LayoutUtil.mm +0 -50
  383. package/lib/module/TrueSheetGrabber.js +0 -51
  384. package/lib/module/TrueSheetGrabber.js.map +0 -1
  385. package/lib/typescript/src/TrueSheetGrabber.d.ts +0 -39
  386. package/lib/typescript/src/TrueSheetGrabber.d.ts.map +0 -1
  387. package/src/TrueSheetGrabber.tsx +0 -82
  388. package/src/__mocks__/index.js +0 -67
@@ -1,10 +1,12 @@
1
1
  package com.lodev09.truesheet
2
2
 
3
- import android.graphics.Color
4
3
  import android.view.WindowManager
5
4
  import com.facebook.react.bridge.ReadableArray
5
+ import com.facebook.react.bridge.ReadableMap
6
6
  import com.facebook.react.module.annotations.ReactModule
7
7
  import com.facebook.react.uimanager.PixelUtil.dpToPx
8
+ import com.facebook.react.uimanager.ReactStylesDiffMap
9
+ import com.facebook.react.uimanager.StateWrapper
8
10
  import com.facebook.react.uimanager.ThemedReactContext
9
11
  import com.facebook.react.uimanager.UIManagerHelper
10
12
  import com.facebook.react.uimanager.ViewGroupManager
@@ -12,6 +14,8 @@ import com.facebook.react.uimanager.ViewManagerDelegate
12
14
  import com.facebook.react.uimanager.annotations.ReactProp
13
15
  import com.facebook.react.viewmanagers.TrueSheetViewManagerDelegate
14
16
  import com.facebook.react.viewmanagers.TrueSheetViewManagerInterface
17
+ import com.lodev09.truesheet.core.AccessibilityOptions
18
+ import com.lodev09.truesheet.core.GrabberOptions
15
19
  import com.lodev09.truesheet.events.*
16
20
 
17
21
  /**
@@ -36,7 +40,7 @@ class TrueSheetViewManager :
36
40
 
37
41
  override fun onAfterUpdateTransaction(view: TrueSheetView) {
38
42
  super.onAfterUpdateTransaction(view)
39
- view.showOrUpdate()
43
+ view.finalizeUpdates()
40
44
  }
41
45
 
42
46
  override fun addEventEmitters(reactContext: ThemedReactContext, view: TrueSheetView) {
@@ -44,6 +48,11 @@ class TrueSheetViewManager :
44
48
  view.eventDispatcher = dispatcher
45
49
  }
46
50
 
51
+ override fun updateState(view: TrueSheetView, props: ReactStylesDiffMap?, stateWrapper: StateWrapper?): Any? {
52
+ view.stateWrapper = stateWrapper
53
+ return null
54
+ }
55
+
47
56
  override fun getDelegate(): ViewManagerDelegate<TrueSheetView> = delegate
48
57
 
49
58
  /**
@@ -62,7 +71,11 @@ class TrueSheetViewManager :
62
71
  DragChangeEvent.EVENT_NAME to hashMapOf("registrationName" to DragChangeEvent.REGISTRATION_NAME),
63
72
  DragEndEvent.EVENT_NAME to hashMapOf("registrationName" to DragEndEvent.REGISTRATION_NAME),
64
73
  PositionChangeEvent.EVENT_NAME to hashMapOf("registrationName" to PositionChangeEvent.REGISTRATION_NAME),
65
- SizeChangeEvent.EVENT_NAME to hashMapOf("registrationName" to SizeChangeEvent.REGISTRATION_NAME)
74
+ WillFocusEvent.EVENT_NAME to hashMapOf("registrationName" to WillFocusEvent.REGISTRATION_NAME),
75
+ FocusEvent.EVENT_NAME to hashMapOf("registrationName" to FocusEvent.REGISTRATION_NAME),
76
+ WillBlurEvent.EVENT_NAME to hashMapOf("registrationName" to WillBlurEvent.REGISTRATION_NAME),
77
+ BlurEvent.EVENT_NAME to hashMapOf("registrationName" to BlurEvent.REGISTRATION_NAME),
78
+ VisibilityChangeEvent.EVENT_NAME to hashMapOf("registrationName" to VisibilityChangeEvent.REGISTRATION_NAME)
66
79
  )
67
80
 
68
81
  // ==================== Props ====================
@@ -85,16 +98,14 @@ class TrueSheetViewManager :
85
98
  view.setDetents(detents)
86
99
  }
87
100
 
88
- @ReactProp(name = "background", defaultInt = Color.WHITE)
89
- override fun setBackground(view: TrueSheetView, color: Int) {
101
+ @ReactProp(name = "backgroundColor", customType = "Color")
102
+ override fun setBackgroundColor(view: TrueSheetView, color: Int?) {
90
103
  view.setSheetBackgroundColor(color)
91
104
  }
92
105
 
93
106
  @ReactProp(name = "cornerRadius", defaultDouble = -1.0)
94
107
  override fun setCornerRadius(view: TrueSheetView, radius: Double) {
95
- if (radius >= 0) {
96
- view.setCornerRadius(radius.dpToPx())
97
- }
108
+ view.setCornerRadius(radius.dpToPx())
98
109
  }
99
110
 
100
111
  @ReactProp(name = "grabber", defaultBoolean = true)
@@ -102,19 +113,67 @@ class TrueSheetViewManager :
102
113
  view.setGrabber(grabber)
103
114
  }
104
115
 
116
+ @ReactProp(name = "grabberOptions")
117
+ override fun setGrabberOptions(view: TrueSheetView, options: ReadableMap?) {
118
+ if (options == null) {
119
+ view.setGrabberOptions(null)
120
+ return
121
+ }
122
+
123
+ val grabberOptions = GrabberOptions(
124
+ width = if (options.hasKey("width")) options.getDouble("width").toFloat() else null,
125
+ height = if (options.hasKey("height")) options.getDouble("height").toFloat() else null,
126
+ topMargin = if (options.hasKey("topMargin")) options.getDouble("topMargin").toFloat() else null,
127
+ cornerRadius = if (options.hasKey("cornerRadius") &&
128
+ options.getDouble("cornerRadius") >= 0
129
+ ) {
130
+ options.getDouble("cornerRadius").toFloat()
131
+ } else {
132
+ null
133
+ },
134
+ color = if (options.hasKey("color") && !options.isNull("color")) options.getInt("color") else null,
135
+ adaptive = if (options.hasKey("adaptive")) options.getBoolean("adaptive") else true
136
+ )
137
+ view.setGrabberOptions(grabberOptions)
138
+ }
139
+
140
+ @ReactProp(name = "accessibilityOptions")
141
+ override fun setAccessibilityOptions(view: TrueSheetView, options: ReadableMap?) {
142
+ if (options == null) {
143
+ view.setAccessibilityOptions(null)
144
+ return
145
+ }
146
+
147
+ val accessibilityOptions = AccessibilityOptions(
148
+ grabberLabel = if (options.hasKey("grabberLabel")) options.getString("grabberLabel") else null,
149
+ expandedValue = if (options.hasKey("expandedValue")) options.getString("expandedValue") else null,
150
+ collapsedValue = if (options.hasKey("collapsedValue")) options.getString("collapsedValue") else null,
151
+ detentValue = if (options.hasKey("detentValue")) options.getString("detentValue") else null,
152
+ expandActionLabel = if (options.hasKey("expandActionLabel")) options.getString("expandActionLabel") else null,
153
+ collapseActionLabel = if (options.hasKey("collapseActionLabel")) options.getString("collapseActionLabel") else null,
154
+ paneTitle = if (options.hasKey("paneTitle")) options.getString("paneTitle") else null
155
+ )
156
+ view.setAccessibilityOptions(accessibilityOptions)
157
+ }
158
+
105
159
  @ReactProp(name = "dismissible", defaultBoolean = true)
106
160
  override fun setDismissible(view: TrueSheetView, dismissible: Boolean) {
107
161
  view.setDismissible(dismissible)
108
162
  }
109
163
 
164
+ @ReactProp(name = "draggable", defaultBoolean = true)
165
+ override fun setDraggable(view: TrueSheetView, draggable: Boolean) {
166
+ view.setDraggable(draggable)
167
+ }
168
+
110
169
  @ReactProp(name = "dimmed", defaultBoolean = true)
111
170
  override fun setDimmed(view: TrueSheetView, dimmed: Boolean) {
112
171
  view.setDimmed(dimmed)
113
172
  }
114
173
 
115
- @ReactProp(name = "dimmedIndex", defaultInt = 0)
116
- override fun setDimmedIndex(view: TrueSheetView, index: Int) {
117
- view.setDimmedIndex(index)
174
+ @ReactProp(name = "dimmedDetentIndex", defaultInt = 0)
175
+ override fun setDimmedDetentIndex(view: TrueSheetView, index: Int) {
176
+ view.setDimmedDetentIndex(index)
118
177
  }
119
178
 
120
179
  @ReactProp(name = "initialDetentIndex", defaultInt = -1)
@@ -127,31 +186,79 @@ class TrueSheetViewManager :
127
186
  view.initialDetentAnimated = animate
128
187
  }
129
188
 
130
- @ReactProp(name = "maxHeight", defaultDouble = 0.0)
131
- override fun setMaxHeight(view: TrueSheetView, height: Double) {
132
- if (height > 0) {
133
- view.setMaxHeight(height.dpToPx().toInt())
134
- }
189
+ @ReactProp(name = "maxContentHeight", defaultDouble = 0.0)
190
+ override fun setMaxContentHeight(view: TrueSheetView, height: Double) {
191
+ view.setMaxContentHeight(if (height > 0) height.dpToPx().toInt() else null)
135
192
  }
136
193
 
137
- @ReactProp(name = "keyboardMode")
138
- override fun setKeyboardMode(view: TrueSheetView, mode: String?) {
139
- val softInputMode = when (mode) {
140
- "pan" -> WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN
141
- else -> WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
142
- }
143
- view.setSoftInputMode(softInputMode)
194
+ @ReactProp(name = "maxContentWidth", defaultDouble = 0.0)
195
+ override fun setMaxContentWidth(view: TrueSheetView, width: Double) {
196
+ view.setMaxContentWidth(if (width > 0) width.dpToPx().toInt() else null)
197
+ }
198
+
199
+ @ReactProp(name = "anchor")
200
+ override fun setAnchor(view: TrueSheetView, anchor: String?) {
201
+ view.setAnchor(anchor)
144
202
  }
145
203
 
146
- @ReactProp(name = "blurTint")
147
- override fun setBlurTint(view: TrueSheetView, tint: String?) {
204
+ @ReactProp(name = "anchorOffset", defaultDouble = 0.0)
205
+ override fun setAnchorOffset(view: TrueSheetView, offset: Double) {
206
+ view.setAnchorOffset(if (offset > 0) offset.dpToPx().toInt() else 0)
207
+ }
208
+
209
+ @ReactProp(name = "backgroundBlur")
210
+ override fun setBackgroundBlur(view: TrueSheetView, tint: String?) {
211
+ // iOS-specific prop - no-op on Android
212
+ }
213
+
214
+ @ReactProp(name = "blurOptions")
215
+ override fun setBlurOptions(view: TrueSheetView, options: ReadableMap?) {
148
216
  // iOS-specific prop - no-op on Android
149
- view.setBlurTint(tint)
150
217
  }
151
218
 
152
- @ReactProp(name = "edgeToEdgeFullScreen", defaultBoolean = false)
153
- override fun setEdgeToEdgeFullScreen(view: TrueSheetView, edgeToEdgeFullScreen: Boolean) {
154
- view.setEdgeToEdgeFullScreen(edgeToEdgeFullScreen)
219
+ @ReactProp(name = "insetAdjustment")
220
+ override fun setInsetAdjustment(view: TrueSheetView, insetAdjustment: String?) {
221
+ view.setInsetAdjustment(insetAdjustment ?: "automatic")
222
+ }
223
+
224
+ @ReactProp(name = "presentation")
225
+ override fun setPresentation(view: TrueSheetView, value: String?) {
226
+ // iOS/web-specific prop - no-op on Android
227
+ }
228
+
229
+ @ReactProp(name = "elevation", defaultDouble = -1.0)
230
+ override fun setElevation(view: TrueSheetView, elevation: Double) {
231
+ view.setSheetElevation(elevation.toFloat())
232
+ }
233
+
234
+ @ReactProp(name = "scrollableOptions")
235
+ override fun setScrollableOptions(view: TrueSheetView, options: ReadableMap?) {
236
+ if (options == null) {
237
+ view.setScrollableOptions(null)
238
+ return
239
+ }
240
+
241
+ val scrollableOptions = ScrollableOptions(
242
+ keyboardScrollOffset = if (options.hasKey("keyboardScrollOffset")) options.getDouble("keyboardScrollOffset").toFloat() else 0f,
243
+ scrollingExpandsSheet = if (options.hasKey("scrollingExpandsSheet")) options.getBoolean("scrollingExpandsSheet") else true
244
+ )
245
+ view.setScrollableOptions(scrollableOptions)
246
+ }
247
+
248
+ @ReactProp(name = "headerOptions")
249
+ override fun setHeaderOptions(view: TrueSheetView, options: ReadableMap?) {
250
+ val position = if (options != null && options.hasKey("position")) options.getString("position") else null
251
+ view.setAbsoluteHeader(position == "absolute")
252
+ }
253
+
254
+ @ReactProp(name = "footerOptions")
255
+ override fun setFooterOptions(view: TrueSheetView, options: ReadableMap?) {
256
+ val position = if (options != null && options.hasKey("footerPosition")) options.getString("footerPosition") else null
257
+ view.setAbsoluteFooter(position == "absolute")
258
+
259
+ val keyboardOffset =
260
+ if (options != null && options.hasKey("keyboardOffset")) options.getDouble("keyboardOffset").toFloat() else 0f
261
+ view.setFooterKeyboardOffset(keyboardOffset)
155
262
  }
156
263
 
157
264
  companion object {
@@ -0,0 +1,63 @@
1
+ package com.lodev09.truesheet.core
2
+
3
+ import android.view.View
4
+ import com.facebook.react.uimanager.events.Event
5
+ import com.facebook.react.uimanager.events.EventDispatcher
6
+ import com.facebook.react.uimanager.events.EventDispatcherListener
7
+
8
+ private const val RN_SCREENS_VIEW_CLASS = "com.swmansion.rnscreens.Screen"
9
+
10
+ interface RNScreensEventObserverDelegate {
11
+ fun presenterScreenWillDisappear()
12
+ fun presenterScreenWillAppear()
13
+ }
14
+
15
+ /**
16
+ * Observes react-native-screens lifecycle events via EventDispatcherListener.
17
+ * Detects when the presenting screen unmounts while sheet is presented.
18
+ */
19
+ class RNScreensEventObserver : EventDispatcherListener {
20
+ var delegate: RNScreensEventObserverDelegate? = null
21
+
22
+ private var eventDispatcher: EventDispatcher? = null
23
+ var presenterScreenTag: Int = 0
24
+
25
+ fun startObserving(dispatcher: EventDispatcher?) {
26
+ if (eventDispatcher != null || dispatcher == null) return
27
+
28
+ eventDispatcher = dispatcher
29
+ dispatcher.addListener(this)
30
+ }
31
+
32
+ fun stopObserving() {
33
+ eventDispatcher?.removeListener(this)
34
+ eventDispatcher = null
35
+ }
36
+
37
+ fun capturePresenterScreenFromView(view: View?) {
38
+ presenterScreenTag = 0
39
+
40
+ var current: View? = view
41
+ while (current != null) {
42
+ if (isScreenView(current)) {
43
+ presenterScreenTag = current.id
44
+ break
45
+ }
46
+ current = (current.parent as? View)
47
+ }
48
+ }
49
+
50
+ override fun onEventDispatch(event: Event<*>) {
51
+ // Only process events for the presenter screen
52
+ if (presenterScreenTag == 0 || event.viewTag != presenterScreenTag) return
53
+
54
+ when (event.eventName) {
55
+ "topWillDisappear" -> delegate?.presenterScreenWillDisappear()
56
+ "topWillAppear" -> delegate?.presenterScreenWillAppear()
57
+ }
58
+ }
59
+
60
+ companion object {
61
+ private fun isScreenView(view: View): Boolean = view.javaClass.name == RN_SCREENS_VIEW_CLASS
62
+ }
63
+ }
@@ -0,0 +1,36 @@
1
+ package com.lodev09.truesheet.core
2
+
3
+ import android.view.View
4
+ import androidx.coordinatorlayout.widget.CoordinatorLayout
5
+ import com.google.android.material.bottomsheet.BottomSheetBehavior
6
+
7
+ class TrueSheetBottomSheetBehavior<V : View> : BottomSheetBehavior<V>() {
8
+ var scrollingExpandsSheet: Boolean = true
9
+
10
+ override fun onNestedPreScroll(
11
+ coordinatorLayout: CoordinatorLayout,
12
+ child: V,
13
+ target: View,
14
+ dx: Int,
15
+ dy: Int,
16
+ consumed: IntArray,
17
+ type: Int
18
+ ) {
19
+ // dy > 0 = user swiping up = sheet expanding
20
+ // Block expansion from scroll, but allow if sheet is already being dragged
21
+ if (!scrollingExpandsSheet && dy > 0 && state != STATE_DRAGGING) return
22
+ super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type)
23
+ }
24
+
25
+ override fun onNestedPreFling(
26
+ coordinatorLayout: CoordinatorLayout,
27
+ child: V,
28
+ target: View,
29
+ velocityX: Float,
30
+ velocityY: Float
31
+ ): Boolean {
32
+ // Don't consume flings — let the ScrollView decelerate naturally
33
+ if (!scrollingExpandsSheet) return false
34
+ return super.onNestedPreFling(coordinatorLayout, child, target, velocityX, velocityY)
35
+ }
36
+ }
@@ -0,0 +1,255 @@
1
+ package com.lodev09.truesheet.core
2
+
3
+ import android.annotation.SuppressLint
4
+ import android.content.res.Configuration
5
+ import android.graphics.Color
6
+ import android.graphics.Outline
7
+ import android.graphics.Rect
8
+ import android.graphics.drawable.ShapeDrawable
9
+ import android.graphics.drawable.shapes.RoundRectShape
10
+ import android.view.GestureDetector
11
+ import android.view.Gravity
12
+ import android.view.MotionEvent
13
+ import android.view.View
14
+ import android.view.ViewOutlineProvider
15
+ import android.widget.FrameLayout
16
+ import androidx.coordinatorlayout.widget.CoordinatorLayout
17
+ import androidx.core.view.ViewCompat
18
+ import com.facebook.react.uimanager.PixelUtil.dpToPx
19
+ import com.facebook.react.uimanager.ThemedReactContext
20
+ import com.google.android.material.bottomsheet.BottomSheetBehavior
21
+ import com.lodev09.truesheet.TrueSheetAnchor
22
+ import com.lodev09.truesheet.utils.ScreenUtils
23
+
24
+ interface TrueSheetBottomSheetViewDelegate {
25
+ val isTopmostSheet: Boolean
26
+ val sheetCornerRadius: Float
27
+ val sheetElevation: Float
28
+ val sheetBackgroundColor: Int?
29
+ val maxContentWidth: Int?
30
+ val anchor: TrueSheetAnchor
31
+ val anchorOffset: Int
32
+ val grabber: Boolean
33
+ val grabberOptions: GrabberOptions?
34
+ val accessibilityOptions: AccessibilityOptions?
35
+ val draggable: Boolean
36
+ fun bottomSheetViewDidTapGrabber()
37
+ fun bottomSheetViewDidAccessibilityIncrement()
38
+ fun bottomSheetViewDidAccessibilityDecrement()
39
+ }
40
+
41
+ /**
42
+ * The bottom sheet view that holds the content.
43
+ * This view has BottomSheetBehavior attached via CoordinatorLayout.LayoutParams.
44
+ *
45
+ * Touch dispatching to React Native is handled by TrueSheetViewController,
46
+ * which is the actual RootView containing the React content.
47
+ */
48
+ @SuppressLint("ViewConstructor")
49
+ class TrueSheetBottomSheetView(private val reactContext: ThemedReactContext) : FrameLayout(reactContext) {
50
+
51
+ companion object {
52
+ private const val GRABBER_TAG = "TrueSheetGrabber"
53
+ private const val DEFAULT_CORNER_RADIUS = 16f // dp
54
+ private const val DEFAULT_MAX_WIDTH = 640 // dp
55
+ private const val DEFAULT_ELEVATION = 4f // dp
56
+
57
+ // M3 baseline surfaceContainerLow
58
+ private val COLOR_SURFACE_CONTAINER_LOW_LIGHT = Color.parseColor("#F7F2FA")
59
+ private val COLOR_SURFACE_CONTAINER_LOW_DARK = Color.parseColor("#1D1B20")
60
+ }
61
+
62
+ // =============================================================================
63
+ // MARK: - Properties
64
+ // =============================================================================
65
+
66
+ var delegate: TrueSheetBottomSheetViewDelegate? = null
67
+
68
+ // Behavior reference (set after adding to CoordinatorLayout)
69
+ @Suppress("UNCHECKED_CAST")
70
+ val behavior: TrueSheetBottomSheetBehavior<TrueSheetBottomSheetView>?
71
+ get() = (layoutParams as? CoordinatorLayout.LayoutParams)
72
+ ?.behavior as? TrueSheetBottomSheetBehavior<TrueSheetBottomSheetView>
73
+
74
+ // =============================================================================
75
+ // MARK: - Initialization
76
+ // =============================================================================
77
+
78
+ init {
79
+ // Allow content to extend beyond bounds (for footer positioning)
80
+ clipChildren = false
81
+ clipToPadding = false
82
+ }
83
+
84
+ override fun setTranslationY(translationY: Float) {
85
+ // This prevents keyboard inset animations from resetting parent sheet translation
86
+ if (translationY == 0f && this.translationY != 0f) {
87
+ return
88
+ }
89
+ super.setTranslationY(translationY)
90
+ }
91
+
92
+ // =============================================================================
93
+ // MARK: - Layout
94
+ // =============================================================================
95
+
96
+ private fun resolveAnchor(): Pair<Int, Int> {
97
+ val anchor = if (ScreenUtils.isPortraitPhone(reactContext)) null else delegate?.anchor
98
+ val gravity = when (anchor) {
99
+ TrueSheetAnchor.LEFT -> Gravity.START
100
+ TrueSheetAnchor.RIGHT -> Gravity.END
101
+ else -> Gravity.CENTER_HORIZONTAL
102
+ } or Gravity.BOTTOM
103
+ val margin = if (anchor == TrueSheetAnchor.LEFT || anchor == TrueSheetAnchor.RIGHT) delegate?.anchorOffset ?: 0 else 0
104
+ return Pair(gravity, margin)
105
+ }
106
+
107
+ /**
108
+ * Creates layout params with BottomSheetBehavior attached.
109
+ */
110
+ fun createLayoutParams(): CoordinatorLayout.LayoutParams {
111
+ val applyMaxWidth = delegate?.maxContentWidth != null && !ScreenUtils.isPortraitPhone(reactContext)
112
+ val effectiveMaxWidth = if (applyMaxWidth) delegate!!.maxContentWidth!! else DEFAULT_MAX_WIDTH.dpToPx().toInt()
113
+ val behavior = TrueSheetBottomSheetBehavior<TrueSheetBottomSheetView>().apply {
114
+ isHideable = true
115
+ maxWidth = effectiveMaxWidth
116
+ }
117
+
118
+ val (gravity, margin) = resolveAnchor()
119
+
120
+ return CoordinatorLayout.LayoutParams(
121
+ CoordinatorLayout.LayoutParams.MATCH_PARENT,
122
+ CoordinatorLayout.LayoutParams.MATCH_PARENT
123
+ ).apply {
124
+ this.behavior = behavior
125
+ this.gravity = gravity
126
+ this.marginStart = margin
127
+ this.marginEnd = margin
128
+ }
129
+ }
130
+
131
+ fun updateGravity() {
132
+ val params = layoutParams as? CoordinatorLayout.LayoutParams ?: return
133
+ val (gravity, margin) = resolveAnchor()
134
+
135
+ if (params.gravity == gravity && params.marginStart == margin) return
136
+
137
+ params.gravity = gravity
138
+ params.marginStart = margin
139
+ params.marginEnd = margin
140
+ layoutParams = params
141
+ }
142
+
143
+ // =============================================================================
144
+ // MARK: - Background & Styling
145
+ // =============================================================================
146
+
147
+ fun setupBackground() {
148
+ val radius = delegate?.sheetCornerRadius ?: DEFAULT_CORNER_RADIUS.dpToPx()
149
+ val effectiveRadius = if (radius < 0) DEFAULT_CORNER_RADIUS.dpToPx() else radius
150
+
151
+ val outerRadii = floatArrayOf(
152
+ effectiveRadius,
153
+ effectiveRadius, // top-left
154
+ effectiveRadius,
155
+ effectiveRadius, // top-right
156
+ 0f,
157
+ 0f, // bottom-right
158
+ 0f,
159
+ 0f // bottom-left
160
+ )
161
+
162
+ val color = delegate?.sheetBackgroundColor ?: getDefaultBackgroundColor()
163
+
164
+ background = ShapeDrawable(RoundRectShape(outerRadii, null, null)).apply {
165
+ paint.color = color
166
+ }
167
+
168
+ outlineProvider = object : ViewOutlineProvider() {
169
+ override fun getOutline(view: View, outline: Outline) {
170
+ outline.setRoundRect(0, 0, view.width, view.height, effectiveRadius)
171
+ }
172
+ }
173
+ clipToOutline = true
174
+ }
175
+
176
+ private fun getDefaultBackgroundColor(): Int {
177
+ val isNight = (
178
+ reactContext.resources.configuration.uiMode and
179
+ Configuration.UI_MODE_NIGHT_MASK
180
+ ) == Configuration.UI_MODE_NIGHT_YES
181
+ return if (isNight) COLOR_SURFACE_CONTAINER_LOW_DARK else COLOR_SURFACE_CONTAINER_LOW_LIGHT
182
+ }
183
+
184
+ fun setupElevation() {
185
+ val value = delegate?.sheetElevation ?: DEFAULT_ELEVATION
186
+ val effectiveElevation = if (value < 0) DEFAULT_ELEVATION else value
187
+ elevation = effectiveElevation.dpToPx()
188
+ }
189
+
190
+ // =============================================================================
191
+ // MARK: - Grabber
192
+ // =============================================================================
193
+
194
+ fun setupGrabber() {
195
+ findViewWithTag<View>(GRABBER_TAG)?.let { removeView(it) }
196
+
197
+ // Content view is the controller, added before the grabber (delegate is the controller)
198
+ val contentView = delegate as? View
199
+
200
+ val isEnabled = delegate?.grabber ?: true
201
+ val isDraggable = delegate?.draggable ?: true
202
+ if (!isEnabled || !isDraggable) {
203
+ contentView?.accessibilityTraversalAfter = View.NO_ID
204
+ return
205
+ }
206
+
207
+ val grabberView = TrueSheetGrabberView(reactContext, delegate?.grabberOptions, delegate?.accessibilityOptions).apply {
208
+ tag = GRABBER_TAG
209
+ id = View.generateViewId()
210
+ onAccessibilityIncrement = { delegate?.bottomSheetViewDidAccessibilityIncrement() }
211
+ onAccessibilityDecrement = { delegate?.bottomSheetViewDidAccessibilityDecrement() }
212
+ }
213
+
214
+ addView(grabberView)
215
+
216
+ // Grabber is added after content for z-ordering, but should be announced first
217
+ contentView?.accessibilityTraversalAfter = grabberView.id
218
+ }
219
+
220
+ fun updateGrabberAccessibilityValue(index: Int, detentCount: Int) {
221
+ findViewWithTag<TrueSheetGrabberView>(GRABBER_TAG)?.updateAccessibilityValue(index, detentCount)
222
+ }
223
+
224
+ fun setupAccessibility() {
225
+ ViewCompat.setAccessibilityPaneTitle(this, delegate?.accessibilityOptions?.paneTitle ?: "Bottom sheet")
226
+ }
227
+
228
+ // =============================================================================
229
+ // MARK: - Grabber Tap Detection
230
+ // =============================================================================
231
+
232
+ private val grabberTapDetector = GestureDetector(
233
+ context,
234
+ object : GestureDetector.SimpleOnGestureListener() {
235
+ override fun onSingleTapUp(e: MotionEvent): Boolean {
236
+ delegate?.bottomSheetViewDidTapGrabber()
237
+ return true
238
+ }
239
+ }
240
+ )
241
+
242
+ override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
243
+ val grabber = findViewWithTag<View>(GRABBER_TAG)
244
+ if (grabber != null) {
245
+ val rect = Rect()
246
+ grabber.getHitRect(rect)
247
+ if (rect.contains(ev.x.toInt(), ev.y.toInt())) {
248
+ if (grabberTapDetector.onTouchEvent(ev)) {
249
+ return true
250
+ }
251
+ }
252
+ }
253
+ return super.dispatchTouchEvent(ev)
254
+ }
255
+ }