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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (367) 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 +150 -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 +1217 -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/ViewUtils.kt +30 -0
  37. package/android/src/main/jni/CMakeLists.txt +63 -0
  38. package/android/src/main/jni/TrueSheetSpec.h +19 -0
  39. package/android/src/main/jni/TrueSheetStateUpdater.cpp +96 -0
  40. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewComponentDescriptor.h +24 -0
  41. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewShadowNode.cpp +43 -0
  42. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewShadowNode.h +28 -0
  43. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewState.cpp +11 -0
  44. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewState.h +37 -0
  45. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewComponentDescriptor.h +24 -0
  46. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewShadowNode.cpp +56 -0
  47. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewShadowNode.h +28 -0
  48. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewState.cpp +11 -0
  49. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewState.h +41 -0
  50. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetInsets.cpp +18 -0
  51. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetInsets.h +16 -0
  52. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewComponentDescriptor.h +28 -0
  53. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewShadowNode.cpp +61 -0
  54. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewShadowNode.h +45 -0
  55. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewState.cpp +23 -0
  56. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewState.h +52 -0
  57. package/ios/TrueSheetContainerView.h +81 -6
  58. package/ios/TrueSheetContainerView.mm +275 -21
  59. package/ios/TrueSheetContentView.h +38 -1
  60. package/ios/TrueSheetContentView.mm +413 -43
  61. package/ios/TrueSheetFooterView.h +27 -2
  62. package/ios/TrueSheetFooterView.mm +141 -35
  63. package/ios/{events/OnDidDismissEvent.h → TrueSheetHeaderView.h} +10 -7
  64. package/ios/TrueSheetHeaderView.mm +64 -0
  65. package/ios/TrueSheetModule.mm +92 -5
  66. package/ios/TrueSheetPeekView.h +32 -0
  67. package/ios/TrueSheetPeekView.mm +99 -0
  68. package/ios/TrueSheetView.h +7 -15
  69. package/ios/TrueSheetView.mm +633 -215
  70. package/ios/TrueSheetViewController.h +84 -16
  71. package/ios/TrueSheetViewController.mm +1136 -333
  72. package/ios/core/RNScreensEventObserver.h +46 -0
  73. package/ios/core/RNScreensEventObserver.mm +280 -0
  74. package/ios/core/TrueSheetBlurView.h +27 -0
  75. package/ios/core/TrueSheetBlurView.mm +82 -0
  76. package/ios/core/TrueSheetDetentCalculator.h +107 -0
  77. package/ios/core/TrueSheetDetentCalculator.mm +197 -0
  78. package/ios/core/TrueSheetGrabberView.h +72 -0
  79. package/ios/core/TrueSheetGrabberView.mm +178 -0
  80. package/ios/core/TrueSheetKeyboardObserver.h +39 -0
  81. package/ios/core/TrueSheetKeyboardObserver.mm +112 -0
  82. package/ios/events/TrueSheetDragEvents.h +39 -0
  83. package/ios/events/TrueSheetDragEvents.mm +62 -0
  84. package/ios/events/{OnPositionChangeEvent.h → TrueSheetFocusEvents.h} +8 -5
  85. package/ios/events/TrueSheetFocusEvents.mm +49 -0
  86. package/ios/events/TrueSheetLifecycleEvents.h +40 -0
  87. package/ios/events/TrueSheetLifecycleEvents.mm +71 -0
  88. package/ios/events/TrueSheetStateEvents.h +35 -0
  89. package/ios/events/TrueSheetStateEvents.mm +49 -0
  90. package/ios/tvos/TrueSheetStubs.mm +154 -0
  91. package/ios/{events/OnMountEvent.h → utils/BlurUtil.h} +5 -7
  92. package/ios/utils/BlurUtil.mm +69 -0
  93. package/ios/utils/GestureUtil.h +7 -0
  94. package/ios/utils/GestureUtil.mm +12 -0
  95. package/ios/utils/PlatformUtil.h +15 -0
  96. package/ios/utils/UIView+FirstResponder.h +15 -0
  97. package/ios/utils/UIView+FirstResponder.mm +26 -0
  98. package/ios/{events/OnWillDismissEvent.h → utils/UIView+ScrollEdgeInteraction.h} +6 -7
  99. package/ios/utils/UIView+ScrollEdgeInteraction.mm +62 -0
  100. package/ios/utils/WindowUtil.mm +17 -1
  101. package/lib/module/TrueSheet.js +224 -64
  102. package/lib/module/TrueSheet.js.map +1 -1
  103. package/lib/module/TrueSheet.web.js +1201 -0
  104. package/lib/module/TrueSheet.web.js.map +1 -0
  105. package/lib/module/TrueSheetPeek.js +15 -0
  106. package/lib/module/TrueSheetPeek.js.map +1 -0
  107. package/lib/module/TrueSheetPeek.web.js +55 -0
  108. package/lib/module/TrueSheetPeek.web.js.map +1 -0
  109. package/lib/module/TrueSheetProvider.js +28 -0
  110. package/lib/module/TrueSheetProvider.js.map +1 -0
  111. package/lib/module/TrueSheetProvider.web.js +157 -0
  112. package/lib/module/TrueSheetProvider.web.js.map +1 -0
  113. package/lib/module/fabric/TrueSheetContainerViewNativeComponent.ts +1 -1
  114. package/lib/module/fabric/TrueSheetContentViewNativeComponent.ts +5 -1
  115. package/lib/module/fabric/TrueSheetFooterViewNativeComponent.ts +10 -2
  116. package/lib/module/fabric/TrueSheetHeaderViewNativeComponent.ts +8 -0
  117. package/lib/module/fabric/TrueSheetPeekViewNativeComponent.ts +8 -0
  118. package/lib/module/fabric/TrueSheetViewNativeComponent.ts +105 -18
  119. package/lib/module/index.js +3 -3
  120. package/lib/module/index.js.map +1 -1
  121. package/lib/module/mocks/index.js +93 -0
  122. package/lib/module/mocks/index.js.map +1 -0
  123. package/lib/module/mocks/navigation.js +85 -0
  124. package/lib/module/mocks/navigation.js.map +1 -0
  125. package/lib/module/mocks/reanimated.js +91 -0
  126. package/lib/module/mocks/reanimated.js.map +1 -0
  127. package/lib/module/navigation/TrueSheetRouter.js +170 -0
  128. package/lib/module/navigation/TrueSheetRouter.js.map +1 -0
  129. package/lib/module/navigation/TrueSheetView.js +71 -0
  130. package/lib/module/navigation/TrueSheetView.js.map +1 -0
  131. package/lib/module/navigation/createTrueSheetNavigator.js +63 -0
  132. package/lib/module/navigation/createTrueSheetNavigator.js.map +1 -0
  133. package/lib/module/navigation/index.js +6 -0
  134. package/lib/module/navigation/index.js.map +1 -0
  135. package/lib/module/navigation/screen/ReanimatedTrueSheetScreen.js +56 -0
  136. package/lib/module/navigation/screen/ReanimatedTrueSheetScreen.js.map +1 -0
  137. package/lib/module/navigation/screen/TrueSheetScreen.js +49 -0
  138. package/lib/module/navigation/screen/TrueSheetScreen.js.map +1 -0
  139. package/lib/module/navigation/screen/index.js +5 -0
  140. package/lib/module/navigation/screen/index.js.map +1 -0
  141. package/lib/module/navigation/screen/types.js +4 -0
  142. package/lib/module/navigation/screen/types.js.map +1 -0
  143. package/lib/module/navigation/screen/useSheetScreenState.js +68 -0
  144. package/lib/module/navigation/screen/useSheetScreenState.js.map +1 -0
  145. package/lib/module/navigation/types.js +4 -0
  146. package/lib/module/navigation/types.js.map +1 -0
  147. package/lib/module/navigation/useTrueSheetNavigation.js +24 -0
  148. package/lib/module/navigation/useTrueSheetNavigation.js.map +1 -0
  149. package/lib/module/reanimated/ReanimatedTrueSheet.js +15 -9
  150. package/lib/module/reanimated/ReanimatedTrueSheet.js.map +1 -1
  151. package/lib/module/reanimated/ReanimatedTrueSheet.web.js +81 -0
  152. package/lib/module/reanimated/ReanimatedTrueSheet.web.js.map +1 -0
  153. package/lib/module/reanimated/ReanimatedTrueSheetProvider.js +4 -2
  154. package/lib/module/reanimated/ReanimatedTrueSheetProvider.js.map +1 -1
  155. package/lib/module/reanimated/index.js +2 -2
  156. package/lib/module/reanimated/index.js.map +1 -1
  157. package/lib/module/reanimated/useReanimatedPositionChangeHandler.web.js +20 -0
  158. package/lib/module/reanimated/useReanimatedPositionChangeHandler.web.js.map +1 -0
  159. package/lib/module/specs/NativeTrueSheetModule.js.map +1 -1
  160. package/lib/module/web/constants.js +16 -0
  161. package/lib/module/web/constants.js.map +1 -0
  162. package/lib/module/web/vaul/README.md +9 -0
  163. package/lib/module/web/vaul/browser.js +30 -0
  164. package/lib/module/web/vaul/browser.js.map +1 -0
  165. package/lib/module/web/vaul/constants.js +15 -0
  166. package/lib/module/web/vaul/constants.js.map +1 -0
  167. package/lib/module/web/vaul/context.js +59 -0
  168. package/lib/module/web/vaul/context.js.map +1 -0
  169. package/lib/module/web/vaul/helpers.js +93 -0
  170. package/lib/module/web/vaul/helpers.js.map +1 -0
  171. package/lib/module/web/vaul/index.js +1309 -0
  172. package/lib/module/web/vaul/index.js.map +1 -0
  173. package/lib/module/web/vaul/style.css +287 -0
  174. package/lib/module/web/vaul/style.css.d.js +2 -0
  175. package/lib/module/web/vaul/style.css.d.js.map +1 -0
  176. package/lib/module/web/vaul/types.js +2 -0
  177. package/lib/module/web/vaul/types.js.map +1 -0
  178. package/lib/module/web/vaul/use-composed-refs.js +34 -0
  179. package/lib/module/web/vaul/use-composed-refs.js.map +1 -0
  180. package/lib/module/web/vaul/use-controllable-state.js +54 -0
  181. package/lib/module/web/vaul/use-controllable-state.js.map +1 -0
  182. package/lib/module/web/vaul/use-position-fixed.js +123 -0
  183. package/lib/module/web/vaul/use-position-fixed.js.map +1 -0
  184. package/lib/module/web/vaul/use-prevent-scroll.js +258 -0
  185. package/lib/module/web/vaul/use-prevent-scroll.js.map +1 -0
  186. package/lib/module/web/vaul/use-scale-background.js +57 -0
  187. package/lib/module/web/vaul/use-scale-background.js.map +1 -0
  188. package/lib/module/web/vaul/use-snap-points.js +305 -0
  189. package/lib/module/web/vaul/use-snap-points.js.map +1 -0
  190. package/lib/typescript/src/TrueSheet.d.ts +51 -14
  191. package/lib/typescript/src/TrueSheet.d.ts.map +1 -1
  192. package/lib/typescript/src/TrueSheet.types.d.ts +463 -54
  193. package/lib/typescript/src/TrueSheet.types.d.ts.map +1 -1
  194. package/lib/typescript/src/TrueSheet.web.d.ts +5 -0
  195. package/lib/typescript/src/TrueSheet.web.d.ts.map +1 -0
  196. package/lib/typescript/src/TrueSheetPeek.d.ts +9 -0
  197. package/lib/typescript/src/TrueSheetPeek.d.ts.map +1 -0
  198. package/lib/typescript/src/TrueSheetPeek.web.d.ts +28 -0
  199. package/lib/typescript/src/TrueSheetPeek.web.d.ts.map +1 -0
  200. package/lib/typescript/src/TrueSheetProvider.d.ts +18 -0
  201. package/lib/typescript/src/TrueSheetProvider.d.ts.map +1 -0
  202. package/lib/typescript/src/TrueSheetProvider.web.d.ts +27 -0
  203. package/lib/typescript/src/TrueSheetProvider.web.d.ts.map +1 -0
  204. package/lib/typescript/src/fabric/TrueSheetContainerViewNativeComponent.d.ts.map +1 -1
  205. package/lib/typescript/src/fabric/TrueSheetContentViewNativeComponent.d.ts.map +1 -1
  206. package/lib/typescript/src/fabric/TrueSheetFooterViewNativeComponent.d.ts +2 -0
  207. package/lib/typescript/src/fabric/TrueSheetFooterViewNativeComponent.d.ts.map +1 -1
  208. package/lib/typescript/src/fabric/TrueSheetHeaderViewNativeComponent.d.ts +6 -0
  209. package/lib/typescript/src/fabric/TrueSheetHeaderViewNativeComponent.d.ts.map +1 -0
  210. package/lib/typescript/src/fabric/TrueSheetPeekViewNativeComponent.d.ts +6 -0
  211. package/lib/typescript/src/fabric/TrueSheetPeekViewNativeComponent.d.ts.map +1 -0
  212. package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts +67 -16
  213. package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts.map +1 -1
  214. package/lib/typescript/src/index.d.ts +2 -2
  215. package/lib/typescript/src/index.d.ts.map +1 -1
  216. package/lib/typescript/src/mocks/index.d.ts +43 -0
  217. package/lib/typescript/src/mocks/index.d.ts.map +1 -0
  218. package/lib/typescript/src/mocks/navigation.d.ts +66 -0
  219. package/lib/typescript/src/mocks/navigation.d.ts.map +1 -0
  220. package/lib/typescript/src/mocks/reanimated.d.ts +48 -0
  221. package/lib/typescript/src/mocks/reanimated.d.ts.map +1 -0
  222. package/lib/typescript/src/navigation/TrueSheetRouter.d.ts +57 -0
  223. package/lib/typescript/src/navigation/TrueSheetRouter.d.ts.map +1 -0
  224. package/lib/typescript/src/navigation/TrueSheetView.d.ts +10 -0
  225. package/lib/typescript/src/navigation/TrueSheetView.d.ts.map +1 -0
  226. package/lib/typescript/src/navigation/createTrueSheetNavigator.d.ts +35 -0
  227. package/lib/typescript/src/navigation/createTrueSheetNavigator.d.ts.map +1 -0
  228. package/lib/typescript/src/navigation/index.d.ts +6 -0
  229. package/lib/typescript/src/navigation/index.d.ts.map +1 -0
  230. package/lib/typescript/src/navigation/screen/ReanimatedTrueSheetScreen.d.ts +3 -0
  231. package/lib/typescript/src/navigation/screen/ReanimatedTrueSheetScreen.d.ts.map +1 -0
  232. package/lib/typescript/src/navigation/screen/TrueSheetScreen.d.ts +3 -0
  233. package/lib/typescript/src/navigation/screen/TrueSheetScreen.d.ts.map +1 -0
  234. package/lib/typescript/src/navigation/screen/index.d.ts +4 -0
  235. package/lib/typescript/src/navigation/screen/index.d.ts.map +1 -0
  236. package/lib/typescript/src/navigation/screen/types.d.ts +15 -0
  237. package/lib/typescript/src/navigation/screen/types.d.ts.map +1 -0
  238. package/lib/typescript/src/navigation/screen/useSheetScreenState.d.ts +35 -0
  239. package/lib/typescript/src/navigation/screen/useSheetScreenState.d.ts.map +1 -0
  240. package/lib/typescript/src/navigation/types.d.ts +153 -0
  241. package/lib/typescript/src/navigation/types.d.ts.map +1 -0
  242. package/lib/typescript/src/navigation/useTrueSheetNavigation.d.ts +23 -0
  243. package/lib/typescript/src/navigation/useTrueSheetNavigation.d.ts.map +1 -0
  244. package/lib/typescript/src/reanimated/ReanimatedTrueSheet.d.ts.map +1 -1
  245. package/lib/typescript/src/reanimated/ReanimatedTrueSheet.web.d.ts +41 -0
  246. package/lib/typescript/src/reanimated/ReanimatedTrueSheet.web.d.ts.map +1 -0
  247. package/lib/typescript/src/reanimated/ReanimatedTrueSheetProvider.d.ts +8 -2
  248. package/lib/typescript/src/reanimated/ReanimatedTrueSheetProvider.d.ts.map +1 -1
  249. package/lib/typescript/src/reanimated/useReanimatedPositionChangeHandler.web.d.ts +15 -0
  250. package/lib/typescript/src/reanimated/useReanimatedPositionChangeHandler.web.d.ts.map +1 -0
  251. package/lib/typescript/src/specs/NativeTrueSheetModule.d.ts +25 -3
  252. package/lib/typescript/src/specs/NativeTrueSheetModule.d.ts.map +1 -1
  253. package/lib/typescript/src/web/constants.d.ts +14 -0
  254. package/lib/typescript/src/web/constants.d.ts.map +1 -0
  255. package/lib/typescript/src/web/vaul/browser.d.ts +8 -0
  256. package/lib/typescript/src/web/vaul/browser.d.ts.map +1 -0
  257. package/lib/typescript/src/web/vaul/constants.d.ts +13 -0
  258. package/lib/typescript/src/web/vaul/constants.d.ts.map +1 -0
  259. package/lib/typescript/src/web/vaul/context.d.ts +53 -0
  260. package/lib/typescript/src/web/vaul/context.d.ts.map +1 -0
  261. package/lib/typescript/src/web/vaul/helpers.d.ts +17 -0
  262. package/lib/typescript/src/web/vaul/helpers.d.ts.map +1 -0
  263. package/lib/typescript/src/web/vaul/index.d.ts +228 -0
  264. package/lib/typescript/src/web/vaul/index.d.ts.map +1 -0
  265. package/lib/typescript/src/web/vaul/types.d.ts +7 -0
  266. package/lib/typescript/src/web/vaul/types.d.ts.map +1 -0
  267. package/lib/typescript/src/web/vaul/use-composed-refs.d.ts +14 -0
  268. package/lib/typescript/src/web/vaul/use-composed-refs.d.ts.map +1 -0
  269. package/lib/typescript/src/web/vaul/use-controllable-state.d.ts +9 -0
  270. package/lib/typescript/src/web/vaul/use-controllable-state.d.ts.map +1 -0
  271. package/lib/typescript/src/web/vaul/use-position-fixed.d.ts +19 -0
  272. package/lib/typescript/src/web/vaul/use-position-fixed.d.ts.map +1 -0
  273. package/lib/typescript/src/web/vaul/use-prevent-scroll.d.ts +18 -0
  274. package/lib/typescript/src/web/vaul/use-prevent-scroll.d.ts.map +1 -0
  275. package/lib/typescript/src/web/vaul/use-scale-background.d.ts +2 -0
  276. package/lib/typescript/src/web/vaul/use-scale-background.d.ts.map +1 -0
  277. package/lib/typescript/src/web/vaul/use-snap-points.d.ts +38 -0
  278. package/lib/typescript/src/web/vaul/use-snap-points.d.ts.map +1 -0
  279. package/package.json +78 -34
  280. package/react-native.config.js +9 -2
  281. package/src/TrueSheet.tsx +276 -60
  282. package/src/TrueSheet.types.ts +525 -71
  283. package/src/TrueSheet.web.tsx +1366 -0
  284. package/src/TrueSheetPeek.tsx +11 -0
  285. package/src/TrueSheetPeek.web.tsx +63 -0
  286. package/src/TrueSheetProvider.tsx +33 -0
  287. package/src/TrueSheetProvider.web.tsx +220 -0
  288. package/src/fabric/TrueSheetContainerViewNativeComponent.ts +1 -1
  289. package/src/fabric/TrueSheetContentViewNativeComponent.ts +5 -1
  290. package/src/fabric/TrueSheetFooterViewNativeComponent.ts +10 -2
  291. package/src/fabric/TrueSheetHeaderViewNativeComponent.ts +8 -0
  292. package/src/fabric/TrueSheetPeekViewNativeComponent.ts +8 -0
  293. package/src/fabric/TrueSheetViewNativeComponent.ts +105 -18
  294. package/src/index.ts +2 -2
  295. package/src/mocks/index.ts +89 -0
  296. package/src/mocks/navigation.ts +72 -0
  297. package/src/mocks/reanimated.ts +101 -0
  298. package/src/navigation/TrueSheetRouter.ts +234 -0
  299. package/src/navigation/TrueSheetView.tsx +99 -0
  300. package/src/navigation/createTrueSheetNavigator.tsx +93 -0
  301. package/src/navigation/index.ts +14 -0
  302. package/src/navigation/screen/ReanimatedTrueSheetScreen.tsx +61 -0
  303. package/src/navigation/screen/TrueSheetScreen.tsx +54 -0
  304. package/src/navigation/screen/index.ts +3 -0
  305. package/src/navigation/screen/types.ts +21 -0
  306. package/src/navigation/screen/useSheetScreenState.ts +107 -0
  307. package/src/navigation/types.ts +219 -0
  308. package/src/navigation/useTrueSheetNavigation.ts +26 -0
  309. package/src/reanimated/ReanimatedTrueSheet.tsx +12 -7
  310. package/src/reanimated/ReanimatedTrueSheet.web.tsx +75 -0
  311. package/src/reanimated/ReanimatedTrueSheetProvider.tsx +12 -8
  312. package/src/reanimated/useReanimatedPositionChangeHandler.web.ts +31 -0
  313. package/src/specs/NativeTrueSheetModule.ts +28 -3
  314. package/src/web/constants.ts +13 -0
  315. package/src/web/vaul/README.md +9 -0
  316. package/src/web/vaul/browser.ts +38 -0
  317. package/src/web/vaul/constants.ts +20 -0
  318. package/src/web/vaul/context.ts +101 -0
  319. package/src/web/vaul/helpers.ts +124 -0
  320. package/src/web/vaul/index.tsx +1740 -0
  321. package/src/web/vaul/style.css +287 -0
  322. package/src/web/vaul/style.css.d.ts +1 -0
  323. package/src/web/vaul/types.ts +7 -0
  324. package/src/web/vaul/use-composed-refs.ts +35 -0
  325. package/src/web/vaul/use-controllable-state.ts +66 -0
  326. package/src/web/vaul/use-position-fixed.ts +147 -0
  327. package/src/web/vaul/use-prevent-scroll.ts +309 -0
  328. package/src/web/vaul/use-scale-background.ts +64 -0
  329. package/src/web/vaul/use-snap-points.ts +455 -0
  330. package/android/src/main/java/com/lodev09/truesheet/events/DetentChangeEvent.kt +0 -26
  331. package/android/src/main/java/com/lodev09/truesheet/events/DidDismissEvent.kt +0 -20
  332. package/android/src/main/java/com/lodev09/truesheet/events/DidPresentEvent.kt +0 -26
  333. package/android/src/main/java/com/lodev09/truesheet/events/DragBeginEvent.kt +0 -26
  334. package/android/src/main/java/com/lodev09/truesheet/events/DragChangeEvent.kt +0 -26
  335. package/android/src/main/java/com/lodev09/truesheet/events/DragEndEvent.kt +0 -26
  336. package/android/src/main/java/com/lodev09/truesheet/events/MountEvent.kt +0 -20
  337. package/android/src/main/java/com/lodev09/truesheet/events/PositionChangeEvent.kt +0 -32
  338. package/android/src/main/java/com/lodev09/truesheet/events/SizeChangeEvent.kt +0 -27
  339. package/android/src/main/java/com/lodev09/truesheet/events/WillDismissEvent.kt +0 -20
  340. package/android/src/main/java/com/lodev09/truesheet/events/WillPresentEvent.kt +0 -26
  341. package/android/src/main/res/values/styles.xml +0 -8
  342. package/ios/events/OnDetentChangeEvent.h +0 -28
  343. package/ios/events/OnDetentChangeEvent.mm +0 -30
  344. package/ios/events/OnDidDismissEvent.mm +0 -25
  345. package/ios/events/OnDidPresentEvent.h +0 -28
  346. package/ios/events/OnDidPresentEvent.mm +0 -30
  347. package/ios/events/OnDragBeginEvent.h +0 -28
  348. package/ios/events/OnDragBeginEvent.mm +0 -30
  349. package/ios/events/OnDragChangeEvent.h +0 -28
  350. package/ios/events/OnDragChangeEvent.mm +0 -30
  351. package/ios/events/OnDragEndEvent.h +0 -28
  352. package/ios/events/OnDragEndEvent.mm +0 -30
  353. package/ios/events/OnMountEvent.mm +0 -25
  354. package/ios/events/OnPositionChangeEvent.mm +0 -32
  355. package/ios/events/OnSizeChangeEvent.h +0 -28
  356. package/ios/events/OnSizeChangeEvent.mm +0 -30
  357. package/ios/events/OnWillDismissEvent.mm +0 -25
  358. package/ios/events/OnWillPresentEvent.h +0 -28
  359. package/ios/events/OnWillPresentEvent.mm +0 -30
  360. package/ios/utils/LayoutUtil.h +0 -44
  361. package/ios/utils/LayoutUtil.mm +0 -50
  362. package/lib/module/TrueSheetGrabber.js +0 -51
  363. package/lib/module/TrueSheetGrabber.js.map +0 -1
  364. package/lib/typescript/src/TrueSheetGrabber.d.ts +0 -39
  365. package/lib/typescript/src/TrueSheetGrabber.d.ts.map +0 -1
  366. package/src/TrueSheetGrabber.tsx +0 -82
  367. package/src/__mocks__/index.js +0 -67
@@ -14,59 +14,82 @@
14
14
  #import "TrueSheetFooterView.h"
15
15
  #import "TrueSheetModule.h"
16
16
  #import "TrueSheetViewController.h"
17
- #import "events/OnDetentChangeEvent.h"
18
- #import "events/OnDidDismissEvent.h"
19
- #import "events/OnDidPresentEvent.h"
20
- #import "events/OnDragBeginEvent.h"
21
- #import "events/OnDragChangeEvent.h"
22
- #import "events/OnDragEndEvent.h"
23
- #import "events/OnMountEvent.h"
24
- #import "events/OnPositionChangeEvent.h"
25
- #import "events/OnSizeChangeEvent.h"
26
- #import "events/OnWillDismissEvent.h"
27
- #import "events/OnWillPresentEvent.h"
28
- #import "utils/LayoutUtil.h"
17
+ #import "core/RNScreensEventObserver.h"
18
+ #import "events/TrueSheetDragEvents.h"
19
+ #import "events/TrueSheetFocusEvents.h"
20
+ #import "events/TrueSheetLifecycleEvents.h"
21
+ #import "events/TrueSheetStateEvents.h"
29
22
  #import "utils/WindowUtil.h"
30
23
 
31
- #import <react/renderer/components/TrueSheetSpec/ComponentDescriptors.h>
32
24
  #import <react/renderer/components/TrueSheetSpec/EventEmitters.h>
33
25
  #import <react/renderer/components/TrueSheetSpec/Props.h>
34
26
  #import <react/renderer/components/TrueSheetSpec/RCTComponentViewHelpers.h>
27
+ #import <react/renderer/components/TrueSheetSpec/TrueSheetInsets.h>
28
+ #import <react/renderer/components/TrueSheetSpec/TrueSheetViewComponentDescriptor.h>
29
+ #import <react/renderer/components/TrueSheetSpec/TrueSheetViewShadowNode.h>
30
+ #import <react/renderer/components/TrueSheetSpec/TrueSheetViewState.h>
35
31
 
36
32
  #import <React/RCTConversions.h>
37
33
  #import <React/RCTFabricComponentsPlugins.h>
34
+ #import <React/RCTLog.h>
38
35
  #import <React/RCTSurfaceTouchHandler.h>
39
36
  #import <React/RCTUtils.h>
37
+ #import <react/renderer/core/State.h>
40
38
 
41
39
  using namespace facebook::react;
42
40
 
43
- @interface TrueSheetView () <TrueSheetViewControllerDelegate, TrueSheetContainerViewDelegate>
41
+ @interface TrueSheetView () <TrueSheetViewControllerDelegate,
42
+ TrueSheetContainerViewDelegate,
43
+ RNScreensEventObserverDelegate>
44
44
  @end
45
45
 
46
46
  @implementation TrueSheetView {
47
47
  TrueSheetContainerView *_containerView;
48
48
  TrueSheetViewController *_controller;
49
49
  RCTSurfaceTouchHandler *_touchHandler;
50
+ TrueSheetViewShadowNode::ConcreteState::Shared _state;
51
+ UIView *_snapshotView;
52
+ CGSize _lastStateSize;
50
53
  NSInteger _initialDetentIndex;
54
+ TrueSheetViewInsetAdjustment _insetAdjustment;
55
+ ScrollableOptions *_scrollableOptions;
56
+ BOOL _hasAutoDetent;
51
57
  BOOL _initialDetentAnimated;
58
+ BOOL _isSheetUpdatePending;
59
+ BOOL _pendingLayoutUpdate;
60
+ BOOL _didInitiallyPresent;
61
+ BOOL _dismissedByNavigation;
62
+ BOOL _pendingNavigationRepresent;
63
+ BOOL _pendingMountEvent;
64
+ BOOL _pendingSizeChange;
65
+ BOOL _pendingPropsUpdate;
66
+ NSArray *_pendingDetents;
67
+ RNScreensEventObserver *_screensEventObserver;
52
68
  }
53
69
 
70
+ #pragma mark - Initialization
71
+
54
72
  - (instancetype)initWithFrame:(CGRect)frame {
55
73
  if (self = [super initWithFrame:frame]) {
56
74
  static const auto defaultProps = std::make_shared<const TrueSheetViewProps>();
57
75
  _props = defaultProps;
58
76
 
59
- // Initialize controller - persists across container lifecycle
77
+ self.hidden = YES;
78
+ self.userInteractionEnabled = NO;
79
+
60
80
  _controller = [[TrueSheetViewController alloc] init];
61
81
  _controller.delegate = self;
62
82
 
63
- // Initialize touch handler - will be attached to container when mounted
64
83
  _touchHandler = [[RCTSurfaceTouchHandler alloc] init];
65
-
66
84
  _containerView = nil;
67
-
85
+ _snapshotView = nil;
86
+ _lastStateSize = CGSizeZero;
68
87
  _initialDetentIndex = -1;
69
88
  _initialDetentAnimated = YES;
89
+ _isSheetUpdatePending = NO;
90
+
91
+ _screensEventObserver = [[RNScreensEventObserver alloc] init];
92
+ _screensEventObserver.delegate = self;
70
93
  }
71
94
  return self;
72
95
  }
@@ -74,28 +97,56 @@ using namespace facebook::react;
74
97
  - (void)didMoveToWindow {
75
98
  [super didMoveToWindow];
76
99
 
77
- if (!self.window) {
100
+ if (!self.window)
78
101
  return;
79
- }
80
102
 
81
- // Register this view with the TurboModule when added to window
82
- // This ensures the tag is properly set by the framework
83
103
  if (self.tag > 0) {
84
104
  [TrueSheetModule registerView:self withTag:@(self.tag)];
85
105
  }
106
+
107
+ if (_pendingNavigationRepresent && !_controller.isPresented) {
108
+ _pendingNavigationRepresent = NO;
109
+ [self presentAtIndex:_controller.activeDetentIndex animated:YES completion:nil];
110
+ return;
111
+ }
112
+
113
+ if (_initialDetentIndex >= 0 && !_didInitiallyPresent) {
114
+ UIViewController *vc = [self findPresentingViewController];
115
+
116
+ // Only present if the view controller is in the same window and not being dismissed
117
+ if (vc && vc.view.window == self.window && !_controller.isBeingDismissed) {
118
+ _didInitiallyPresent = YES;
119
+ [self presentAtIndex:_initialDetentIndex animated:_initialDetentAnimated completion:nil];
120
+ } else {
121
+ // Animate next time when sheet finally moves to the correct window
122
+ _initialDetentAnimated = YES;
123
+ }
124
+ }
86
125
  }
87
126
 
88
127
  - (void)dealloc {
89
- // Dismiss controller if presented
128
+ [_screensEventObserver stopObserving];
129
+ _screensEventObserver = nil;
130
+
90
131
  if (_controller && _controller.presentingViewController) {
91
- [_controller dismissViewControllerAnimated:NO completion:nil];
132
+ // Find the root presenting controller to dismiss the entire stack
133
+ UIViewController *root = _controller.presentingViewController;
134
+ while (root.presentingViewController != nil) {
135
+ root = root.presentingViewController;
136
+ }
137
+ [root dismissViewControllerAnimated:YES completion:nil];
92
138
  }
93
139
 
94
- // Clean up controller
140
+ _didInitiallyPresent = NO;
141
+ _dismissedByNavigation = NO;
142
+ _pendingNavigationRepresent = NO;
143
+
95
144
  _controller.delegate = nil;
96
145
  _controller = nil;
97
146
 
98
- // Unregister this view from the TurboModule
147
+ [_snapshotView removeFromSuperview];
148
+ _snapshotView = nil;
149
+
99
150
  [TrueSheetModule unregisterViewWithTag:@(self.tag)];
100
151
  }
101
152
 
@@ -105,319 +156,686 @@ using namespace facebook::react;
105
156
  return concreteComponentDescriptorProvider<TrueSheetViewComponentDescriptor>();
106
157
  }
107
158
 
159
+ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps {
160
+ [super updateProps:props oldProps:oldProps];
161
+
162
+ const auto &newProps = *std::static_pointer_cast<TrueSheetViewProps const>(props);
163
+
164
+ // Detents (-1 represents "auto")
165
+ NSMutableArray *detents = [NSMutableArray new];
166
+ _hasAutoDetent = NO;
167
+ for (const auto &detent : newProps.detents) {
168
+ [detents addObject:@(detent)];
169
+ if (detent == -1) {
170
+ _hasAutoDetent = YES;
171
+ }
172
+ }
173
+
174
+ if (oldProps) {
175
+ const auto &prevProps = *std::static_pointer_cast<TrueSheetViewProps const>(oldProps);
176
+ if (newProps.detents != prevProps.detents || newProps.insetAdjustment != prevProps.insetAdjustment) {
177
+ _pendingLayoutUpdate = YES;
178
+ }
179
+ }
180
+
181
+ if (_controller.isBeingPresented) {
182
+ _pendingDetents = detents;
183
+ } else {
184
+ _controller.detents = detents;
185
+ }
186
+
187
+ // Background color
188
+ _controller.backgroundColor = RCTUIColorFromSharedColor(newProps.backgroundColor);
189
+
190
+ // Blur tint
191
+ _controller.backgroundBlur = newProps.backgroundBlur;
192
+
193
+ // Blur options
194
+ const auto &blurOpts = newProps.blurOptions;
195
+ _controller.blurIntensity = blurOpts.intensity >= 0 ? @(blurOpts.intensity) : nil;
196
+ _controller.blurInteraction = blurOpts.interaction;
197
+
198
+ // Corner radius
199
+ _controller.cornerRadius = newProps.cornerRadius < 0 ? nil : @(newProps.cornerRadius);
200
+
201
+ // Content height
202
+ _controller.maxContentHeight = newProps.maxContentHeight != 0.0 ? @(newProps.maxContentHeight) : nil;
203
+
204
+ // Content width
205
+ _controller.maxContentWidth = newProps.maxContentWidth != 0.0 ? @(newProps.maxContentWidth) : nil;
206
+
207
+ // Anchor
208
+ _controller.anchor = newProps.anchor;
209
+
210
+ _controller.grabber = newProps.grabber;
211
+
212
+ // Grabber options - check if any non-default values are set
213
+ const auto &grabberOpts = newProps.grabberOptions;
214
+ UIColor *grabberColor = RCTUIColorFromSharedColor(grabberOpts.color);
215
+ BOOL hasGrabberOptions = grabberOpts.width > 0 || grabberOpts.height > 0 || grabberOpts.topMargin > 0 ||
216
+ grabberOpts.cornerRadius >= 0 || grabberColor != nil || !grabberOpts.adaptive;
217
+
218
+ if (hasGrabberOptions) {
219
+ GrabberOptions *options = [[GrabberOptions alloc] init];
220
+ if (grabberOpts.width > 0)
221
+ options.width = @(grabberOpts.width);
222
+ if (grabberOpts.height > 0)
223
+ options.height = @(grabberOpts.height);
224
+ if (grabberOpts.topMargin > 0)
225
+ options.topMargin = @(grabberOpts.topMargin);
226
+ if (grabberOpts.cornerRadius >= 0)
227
+ options.cornerRadius = @(grabberOpts.cornerRadius);
228
+ if (grabberColor)
229
+ options.color = grabberColor;
230
+ options.adaptive = grabberOpts.adaptive;
231
+ _controller.grabberOptions = options;
232
+ } else {
233
+ _controller.grabberOptions = nil;
234
+ }
235
+
236
+ // Accessibility options - applied to the custom grabber
237
+ _controller.accessibilityOptions = newProps.accessibilityOptions;
238
+
239
+ _controller.presentation = newProps.presentation;
240
+ _controller.dismissible = newProps.dismissible;
241
+ _controller.draggable = newProps.draggable;
242
+ _controller.dimmed = newProps.dimmed;
243
+
244
+ if (newProps.dimmedDetentIndex >= 0) {
245
+ _controller.dimmedDetentIndex = @(newProps.dimmedDetentIndex);
246
+ }
247
+
248
+ _initialDetentIndex = newProps.initialDetentIndex;
249
+ _initialDetentAnimated = newProps.initialDetentAnimated;
250
+
251
+ const auto &scrollableOpts = newProps.scrollableOptions;
252
+ BOOL scrollingExpandsSheet = scrollableOpts.scrollingExpandsSheet;
253
+ auto topEdgeEffect = scrollableOpts.topScrollEdgeEffect;
254
+ auto bottomEdgeEffect = scrollableOpts.bottomScrollEdgeEffect;
255
+ BOOL hasScrollableOptions = scrollableOpts.keyboardScrollOffset > 0 || !scrollingExpandsSheet ||
256
+ topEdgeEffect != TrueSheetViewTopScrollEdgeEffect::Hidden ||
257
+ bottomEdgeEffect != TrueSheetViewBottomScrollEdgeEffect::Hidden;
258
+
259
+ if (hasScrollableOptions) {
260
+ ScrollableOptions *options = [[ScrollableOptions alloc] init];
261
+ options.keyboardScrollOffset = scrollableOpts.keyboardScrollOffset;
262
+ options.scrollingExpandsSheet = scrollingExpandsSheet;
263
+ options.topScrollEdgeEffect = topEdgeEffect;
264
+ options.bottomScrollEdgeEffect = bottomEdgeEffect;
265
+ _scrollableOptions = options;
266
+ } else {
267
+ _scrollableOptions = nil;
268
+ }
269
+
270
+ _controller.scrollingExpandsSheet = scrollingExpandsSheet;
271
+
272
+ _controller.absoluteHeader = newProps.headerOptions.position == TrueSheetViewPosition::Absolute;
273
+ _controller.absoluteFooter = newProps.footerOptions.footerPosition == TrueSheetViewFooterPosition::Absolute;
274
+
275
+ CGFloat footerKeyboardOffset = newProps.footerOptions.keyboardOffset;
276
+ if (_controller.footerKeyboardOffset != footerKeyboardOffset) {
277
+ _controller.footerKeyboardOffset = footerKeyboardOffset;
278
+ [_containerView updateFooterKeyboardOffset];
279
+ }
280
+
281
+ _insetAdjustment = newProps.insetAdjustment;
282
+ _controller.insetAdjustment = _insetAdjustment;
283
+
284
+ [self setupScrollable];
285
+ }
286
+
287
+ - (void)updateState:(const State::Shared &)state oldState:(const State::Shared &)oldState {
288
+ _state = std::static_pointer_cast<TrueSheetViewShadowNode::ConcreteState const>(state);
289
+
290
+ if (_controller && !_controller.isStackedBehindChild) {
291
+ CGSize size = _controller.view.frame.size;
292
+ if (size.width < 1 || size.height < 1) {
293
+ // Pre-present the controller has no layout yet. Seed with screen
294
+ // dimensions so content (e.g. a FlatList viewport) can lay out and
295
+ // measure before the sheet presents (parity with Android).
296
+ UIWindow *window = [WindowUtil keyWindow];
297
+ size = window ? window.bounds.size : UIScreen.mainScreen.bounds.size;
298
+ }
299
+ [self viewControllerDidChangeSize:size];
300
+ }
301
+ }
302
+
303
+ /**
304
+ * Updates Fabric state with container dimensions for Yoga layout.
305
+ */
306
+ - (void)updateStateWithSize:(CGSize)size {
307
+ if (!_state)
308
+ return;
309
+
310
+ if (fabs(size.width - _lastStateSize.width) < 0.5 && fabs(size.height - _lastStateSize.height) < 0.5)
311
+ return;
312
+
313
+ _lastStateSize = size;
314
+
315
+ auto stateData = _state->getData();
316
+ stateData.containerWidth = static_cast<float>(size.width);
317
+ stateData.containerHeight = static_cast<float>(size.height);
318
+
319
+ // RN 0.82+ processes immediate state updates in the same layout pass, so Yoga
320
+ // resizes the container synchronously with the sheet (e.g. inside UIKit's
321
+ // animation block during detent transitions).
322
+ _state->updateState(std::move(stateData), facebook::react::EventQueue::UpdateMode::unstable_Immediate);
323
+ }
324
+
325
+ - (void)finalizeUpdates:(RNComponentViewUpdateMask)updateMask {
326
+ [super finalizeUpdates:updateMask];
327
+
328
+ // Emit pending mount event now that eventEmitter is available
329
+ if (_pendingMountEvent && (updateMask & RNComponentViewUpdateMaskEventEmitter)) {
330
+ _pendingMountEvent = NO;
331
+ [TrueSheetLifecycleEvents emitMount:_eventEmitter];
332
+ }
333
+
334
+ if (!(updateMask & RNComponentViewUpdateMaskProps) || !_controller)
335
+ return;
336
+
337
+ [self setupScrollable];
338
+
339
+ if (_controller.isPresented) {
340
+ [self applySheetPropsUpdate];
341
+ } else if (_controller.isBeingPresented) {
342
+ _pendingPropsUpdate = YES;
343
+ } else if (_initialDetentIndex >= 0) {
344
+ _pendingLayoutUpdate = NO;
345
+ }
346
+ }
347
+
348
+ - (void)prepareForRecycle {
349
+ [super prepareForRecycle];
350
+
351
+ [TrueSheetModule unregisterViewWithTag:@(self.tag)];
352
+
353
+ _lastStateSize = CGSizeZero;
354
+ _didInitiallyPresent = NO;
355
+ _dismissedByNavigation = NO;
356
+ _pendingNavigationRepresent = NO;
357
+ }
358
+
359
+ #pragma mark - Child Component Mounting
360
+
361
+ - (void)cleanupContainerView {
362
+ if (_containerView == nil)
363
+ return;
364
+
365
+ _containerView.delegate = nil;
366
+ [_touchHandler detachFromView:_containerView];
367
+ [_containerView removeFromSuperview];
368
+
369
+ _containerView = nil;
370
+ }
371
+
372
+ - (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index {
373
+ if (![childComponentView isKindOfClass:[TrueSheetContainerView class]])
374
+ return;
375
+
376
+ if (_containerView != nil && _containerView != childComponentView) {
377
+ RCTLogWarn(@"TrueSheet: Sheet can only have one container component.");
378
+ [self cleanupContainerView];
379
+ }
380
+
381
+ if (_snapshotView) {
382
+ [_snapshotView removeFromSuperview];
383
+ _snapshotView = nil;
384
+ }
385
+
386
+ _containerView = (TrueSheetContainerView *)childComponentView;
387
+ _containerView.delegate = self;
388
+
389
+ [_touchHandler attachToView:_containerView];
390
+ [_controller.view addSubview:_containerView];
391
+ [_controller.view bringSubviewToFront:_containerView];
392
+ _containerView.accessibilityViewIsModal = YES;
393
+ _controller.accessibilityContentView = _containerView;
394
+ [_controller setupAccessibilityContainer];
395
+
396
+ CGFloat contentHeight = [_containerView contentHeight];
397
+ if (contentHeight > 0) {
398
+ _controller.contentHeight = @(contentHeight);
399
+ }
400
+
401
+ CGFloat headerHeight = [_containerView headerHeight];
402
+ if (headerHeight > 0) {
403
+ _controller.headerHeight = @(headerHeight);
404
+ }
405
+
406
+ CGFloat footerHeight = [_containerView footerHeight];
407
+ if (footerHeight > 0) {
408
+ _controller.footerHeight = @(footerHeight);
409
+ }
410
+
411
+ CGFloat peekContentHeight = [_containerView peekContentHeight];
412
+ if (peekContentHeight > 0) {
413
+ _controller.peekContentHeight = @(peekContentHeight);
414
+ }
415
+
416
+ if (_eventEmitter) {
417
+ [TrueSheetLifecycleEvents emitMount:_eventEmitter];
418
+ } else {
419
+ _pendingMountEvent = YES;
420
+ }
421
+ }
422
+
423
+ - (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index {
424
+ if (![childComponentView isKindOfClass:[TrueSheetContainerView class]])
425
+ return;
426
+
427
+ if (_containerView == nil || _containerView != childComponentView)
428
+ return;
429
+
430
+ if (_controller.isPresented) {
431
+ UIView *superView = _containerView.superview;
432
+ UIView *snapshot = [_containerView snapshotViewAfterScreenUpdates:NO];
433
+ if (snapshot) {
434
+ snapshot.frame = _containerView.frame;
435
+ [superView insertSubview:snapshot belowSubview:_containerView];
436
+ _snapshotView = snapshot;
437
+ }
438
+ }
439
+
440
+ [self cleanupContainerView];
441
+ }
442
+
108
443
  #pragma mark - TurboModule Methods
109
444
 
110
445
  - (void)presentAtIndex:(NSInteger)index
111
446
  animated:(BOOL)animated
112
447
  completion:(nullable TrueSheetCompletionBlock)completion {
113
- if (_controller.isPresented) {
114
- [_controller.sheetPresentationController animateChanges:^{
115
- [self->_controller setupActiveDetentWithIndex:index];
116
- }];
117
-
448
+ if (_controller.isBeingPresented || _controller.isPresented) {
449
+ RCTLogWarn(@"TrueSheet: sheet is already presented. Use resize() to change detent.");
118
450
  if (completion) {
119
451
  completion(YES, nil);
120
452
  }
121
453
  return;
122
454
  }
123
455
 
124
- UIViewController *presentingViewController = [self findPresentingViewController];
456
+ // Reset navigation dismiss flag when presenting (handles view recycling edge cases)
457
+ _dismissedByNavigation = NO;
125
458
 
459
+ UIViewController *presentingViewController = [self findPresentingViewController];
126
460
  if (!presentingViewController) {
127
461
  NSError *error = [NSError errorWithDomain:@"com.lodev09.TrueSheet"
128
462
  code:1001
129
463
  userInfo:@{NSLocalizedDescriptionKey : @"No presenting view controller found"}];
130
-
131
464
  if (completion) {
132
465
  completion(NO, error);
133
466
  }
134
467
  return;
135
468
  }
136
469
 
137
- // Setup our sheet properties
470
+ [_controller setupAnchorViewInView:presentingViewController.view];
471
+ [_controller setupSheetSizing];
138
472
  [_controller setupSheetProps];
139
- [_controller setupSheetDetents];
140
473
 
141
- // Set to the given detent index
474
+ // Pin before measuring so a first-time pin doesn't shift sizes mid-animation.
475
+ [self setupScrollable];
476
+
477
+ // Measure synchronously so the presentation starts at the right height —
478
+ // async size reports would otherwise land mid-animation and force a
479
+ // detent retarget that snaps the presentation stack.
480
+ if (_containerView) {
481
+ _controller.contentHeight = @([_containerView contentHeight]);
482
+ _controller.headerHeight = @([_containerView headerHeight]);
483
+ _controller.footerHeight = @([_containerView footerHeight]);
484
+ _controller.peekContentHeight = @([_containerView peekContentHeight]);
485
+ }
486
+ _pendingSizeChange = NO;
487
+
488
+ [_controller setupSheetDetents];
142
489
  [_controller setupActiveDetentWithIndex:index];
143
490
 
144
- // Present our sheet
145
- [presentingViewController presentViewController:self->_controller
491
+ [_screensEventObserver capturePresenterScreenFromView:self];
492
+ [_screensEventObserver startObservingWithState:_state.get()->getData()];
493
+
494
+ [presentingViewController presentViewController:_controller
146
495
  animated:animated
147
496
  completion:^{
148
- // Call completion handler
149
497
  if (completion) {
150
498
  completion(YES, nil);
151
499
  }
152
500
  }];
153
501
  }
154
502
 
155
- - (void)dismissAnimated:(BOOL)animated completion:(nullable TrueSheetCompletionBlock)completion {
503
+ - (void)resizeToIndex:(NSInteger)index completion:(nullable TrueSheetCompletionBlock)completion {
156
504
  if (!_controller.isPresented) {
505
+ RCTLogWarn(@"TrueSheet: Cannot resize. Sheet is not presented.");
157
506
  if (completion) {
158
507
  completion(YES, nil);
159
508
  }
160
509
  return;
161
510
  }
162
511
 
163
- [_controller dismissViewControllerAnimated:animated
164
- completion:^{
165
- if (completion) {
166
- completion(YES, nil);
167
- }
168
- }];
169
- }
512
+ [_controller.sheetPresentationController animateChanges:^{
513
+ [self->_controller resizeToDetentIndex:index];
514
+ }];
170
515
 
171
- - (void)resizeToIndex:(NSInteger)index {
172
- if (_controller.isPresented) {
173
- [_controller.sheetPresentationController animateChanges:^{
174
- [self->_controller setupActiveDetentWithIndex:index];
175
- }];
516
+ if (completion) {
517
+ completion(YES, nil);
176
518
  }
177
519
  }
178
520
 
179
- - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps {
180
- [super updateProps:props oldProps:oldProps];
181
-
182
- const auto &newProps = *std::static_pointer_cast<TrueSheetViewProps const>(props);
183
-
184
- // Update detents - pass numbers directly (-1 represents "auto")
185
- NSMutableArray *detents = [NSMutableArray new];
186
- for (const auto &detent : newProps.detents) {
187
- [detents addObject:@(detent)];
188
- }
189
-
190
- _controller.detents = detents;
191
-
192
- // Update background color - always set it, even if 0 (which could be a valid color like black)
193
- UIColor *color = RCTUIColorFromSharedColor(SharedColor(newProps.background));
194
- _controller.backgroundColor = color;
195
-
196
- // Update blur tint - always set it to clear when removed
197
- _controller.blurTint = !newProps.blurTint.empty() ? RCTNSStringFromString(newProps.blurTint) : nil;
198
-
199
- // Update corner radius
200
- if (newProps.cornerRadius < 0) {
201
- _controller.cornerRadius = nil;
202
- } else {
203
- _controller.cornerRadius = @(newProps.cornerRadius);
204
- }
205
-
206
- // Update max height
207
- if (newProps.maxHeight != 0.0) {
208
- _controller.maxHeight = @(newProps.maxHeight);
209
- }
210
-
211
- // Update grabber
212
- _controller.grabber = newProps.grabber;
521
+ - (TrueSheetViewController *)viewController {
522
+ return _controller;
523
+ }
213
524
 
214
- // Update dismissible
215
- _controller.modalInPresentation = !newProps.dismissible;
525
+ - (void)emitDismissedPosition {
526
+ [TrueSheetStateEvents emitPositionChange:_eventEmitter
527
+ index:-1
528
+ position:_controller.screenHeight
529
+ detent:0
530
+ realtime:NO];
531
+ }
216
532
 
217
- // Update dimmed
218
- _controller.dimmed = newProps.dimmed;
533
+ - (void)dismissAnimated:(BOOL)animated completion:(nullable TrueSheetCompletionBlock)completion {
534
+ if (_controller.isBeingDismissed || !_controller.isPresented) {
535
+ RCTLogWarn(@"TrueSheet: sheet is already dismissed. No need to dismiss it again.");
219
536
 
220
- // Update dimmedIndex
221
- if (newProps.dimmedIndex >= 0) {
222
- _controller.dimmedIndex = @(newProps.dimmedIndex);
537
+ if (completion) {
538
+ completion(YES, nil);
539
+ }
540
+ return;
223
541
  }
224
542
 
225
- // Store initial presentation settings
226
- _initialDetentIndex = newProps.initialDetentIndex;
227
- _initialDetentAnimated = newProps.initialDetentAnimated;
543
+ // Dismiss from the presenting view controller to dismiss this sheet and all its children
544
+ UIViewController *presenter = _controller.presentingViewController;
545
+ [presenter dismissViewControllerAnimated:animated
546
+ completion:^{
547
+ if (completion) {
548
+ completion(YES, nil);
549
+ }
550
+ }];
228
551
  }
229
552
 
230
- - (void)finalizeUpdates:(RNComponentViewUpdateMask)updateMask {
231
- [super finalizeUpdates:updateMask];
553
+ - (void)dismissStackAnimated:(BOOL)animated completion:(nullable TrueSheetCompletionBlock)completion {
554
+ if (_controller.isBeingDismissed || !_controller.isPresented) {
555
+ RCTLogWarn(@"TrueSheet: sheet is already dismissed. No need to dismiss it again.");
232
556
 
233
- // Apply controller updates after all props and children are updated
234
- if (updateMask & RNComponentViewUpdateMaskProps) {
235
- // Apply changes to presented sheet if needed
236
- if (_controller.isPresented) {
237
- [_controller.sheetPresentationController animateChanges:^{
238
- [self->_controller setupSheetDetents];
239
- [self->_controller applyActiveDetent];
240
- }];
241
- } else {
242
- // Handle initial presentation
243
- if (_initialDetentIndex >= 0 && !_controller.isPresented) {
244
- [self presentAtIndex:_initialDetentIndex animated:_initialDetentAnimated completion:nil];
245
- }
557
+ if (completion) {
558
+ completion(YES, nil);
246
559
  }
560
+ return;
247
561
  }
248
- }
249
562
 
250
- - (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index {
251
- // Check if it's a container view
252
- if ([childComponentView isKindOfClass:[TrueSheetContainerView class]]) {
253
- if (_containerView != nil) {
254
- NSLog(@"TrueSheet: Sheet can only have one container component.");
255
- return;
563
+ // Only dismiss presented children, not this sheet itself
564
+ if (!_controller.presentedViewController) {
565
+ if (completion) {
566
+ completion(YES, nil);
256
567
  }
568
+ return;
569
+ }
257
570
 
258
- _containerView = (TrueSheetContainerView *)childComponentView;
571
+ // Calling dismiss on _controller dismisses all VCs presented on top of it, but keeps _controller presented
572
+ [_controller dismissViewControllerAnimated:animated
573
+ completion:^{
574
+ if (completion) {
575
+ completion(YES, nil);
576
+ }
577
+ }];
578
+ }
259
579
 
260
- // Set this view as the container's delegate
261
- _containerView.delegate = self;
580
+ #pragma mark - TrueSheetContainerViewDelegate
262
581
 
263
- // Attach touch handler to container for touch event handling
264
- [_touchHandler attachToView:_containerView];
582
+ /**
583
+ * Debounced sheet update to handle rapid content/header size changes.
584
+ */
585
+ - (void)setupSheetDetentsForSizeChange {
586
+ // Retargeting the in-flight presentation makes UIKit snap the whole stack
587
+ // (including the sheet behind) instead of animating. Defer to didPresent —
588
+ // presentAtIndex measured synchronously, so this is usually a no-op.
589
+ if (_controller.isBeingPresented) {
590
+ _pendingSizeChange = YES;
591
+ return;
592
+ }
265
593
 
266
- // Add to parent view hierarchy
267
- [_controller.view addSubview:_containerView];
594
+ // Not presented: presentAtIndex measures at present time.
595
+ // Dismissing: the sheet is going away — touching detents perturbs the
596
+ // presentation stack, visibly glitching the sheet behind.
597
+ if (!_controller.isPresented || _controller.isBeingDismissed)
598
+ return;
268
599
 
269
- // Pin container to fill the entire parent view
270
- [LayoutUtil pinView:_containerView toParentView:_controller.view edges:UIRectEdgeAll];
600
+ if (_isSheetUpdatePending)
601
+ return;
271
602
 
272
- // Ensure container is above background view
273
- [_controller.view bringSubviewToFront:_containerView];
603
+ _isSheetUpdatePending = YES;
274
604
 
275
- // Get initial content height from container
276
- CGFloat contentHeight = [_containerView contentHeight];
277
- if (contentHeight > 0) {
278
- _controller.contentHeight = @(contentHeight);
279
- }
605
+ dispatch_async(dispatch_get_main_queue(), ^{
606
+ self->_isSheetUpdatePending = NO;
607
+ if (!self->_containerView || self->_controller.isBeingDismissed)
608
+ return;
280
609
 
281
- // Emit onMount event when container is mounted
282
- [OnMountEvent emit:_eventEmitter];
283
- }
610
+ // Refresh here (not just on peek size events) since the peek's offset
611
+ // within the content can change without its own size changing.
612
+ self->_controller.peekContentHeight = @([self->_containerView peekContentHeight]);
613
+ [self->_controller setupSheetDetentsForSizeChange];
614
+ });
284
615
  }
285
616
 
286
- - (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index {
287
- if ([childComponentView isKindOfClass:[TrueSheetContainerView class]]) {
288
- _containerView.delegate = nil;
289
-
290
- // Detach touch handler
291
- if (_touchHandler) {
292
- [_touchHandler detachFromView:_containerView];
293
- }
294
-
295
- // Unpin and remove from view hierarchy
296
- [LayoutUtil unpinView:_containerView];
297
- [_containerView removeFromSuperview];
298
-
299
- _containerView = nil;
300
- }
617
+ - (void)containerViewContentDidChangeSize:(CGSize)newSize {
618
+ _controller.contentHeight = @(newSize.height);
619
+ [self setupSheetDetentsForSizeChange];
301
620
  }
302
621
 
303
- - (void)prepareForRecycle {
304
- [super prepareForRecycle];
305
- [self invalidate];
306
-
307
- // Unregister from the registry
308
- // Note: Re-registration will happen automatically when the component is reused
309
- [TrueSheetModule unregisterViewWithTag:@(self.tag)];
622
+ - (void)containerViewHeaderDidChangeSize:(CGSize)newSize {
623
+ _controller.headerHeight = @(newSize.height);
624
+ [self setupSheetDetentsForSizeChange];
310
625
  }
311
626
 
312
- #pragma mark - TrueSheetContainerViewDelegate
313
-
314
- - (void)containerViewContentDidChangeSize:(CGSize)newSize {
315
- // Clamp content height to container height to prevent unbounded growth with scrollable content
316
- CGFloat containerHeight = _controller.containerHeight;
317
- CGFloat contentHeight = containerHeight > 0 ? MIN(newSize.height, containerHeight) : newSize.height;
318
-
319
- _controller.contentHeight = @(contentHeight);
627
+ - (void)containerViewFooterDidChangeSize:(CGSize)newSize {
628
+ _controller.footerHeight = @(newSize.height);
629
+ [self setupSheetDetentsForSizeChange];
630
+ [_controller setupAccessibilityContainer];
631
+ }
320
632
 
321
- // Update detents if sheet is already presented
322
- if (_controller.isPresented) {
323
- // Tell controller that we are transitioning from layout changes.
324
- // Controller viewDidLayoutSubviews will handle position notification.
325
- _controller.layoutTransitioning = YES;
633
+ - (void)containerViewPeekDidChangeSize:(CGSize)newSize {
634
+ [self setupSheetDetentsForSizeChange];
635
+ }
326
636
 
327
- [_controller.sheetPresentationController animateChanges:^{
328
- [self->_controller setupSheetDetents];
329
- }];
330
- }
637
+ // When the ScrollView changes (e.g. conditional remount), re-pin the new ScrollView.
638
+ - (void)containerViewScrollViewDidChange {
639
+ [self setupScrollable];
331
640
  }
332
641
 
333
642
  #pragma mark - TrueSheetViewControllerDelegate
334
643
 
335
- - (void)viewControllerWillPresent {
336
- NSInteger index = [_controller currentDetentIndex];
337
- CGFloat position = _controller.currentPosition;
338
-
644
+ - (void)viewControllerWillPresentAtIndex:(NSInteger)index position:(CGFloat)position detent:(CGFloat)detent {
339
645
  _controller.activeDetentIndex = index;
340
-
341
- [OnWillPresentEvent emit:_eventEmitter index:index position:position];
342
-
343
- // Emit onChangeSize event to layout our container on JS
344
- CGSize controllerSize = _controller.view.frame.size;
345
- [OnSizeChangeEvent emit:_eventEmitter width:controllerSize.width height:controllerSize.height];
646
+ [TrueSheetLifecycleEvents emitWillPresent:_eventEmitter index:index position:position detent:detent];
346
647
  }
347
648
 
348
- - (void)viewControllerDidPresent {
349
- NSInteger index = [_controller currentDetentIndex];
350
- CGFloat position = _controller.currentPosition;
649
+ - (void)viewControllerDidPresentAtIndex:(NSInteger)index position:(CGFloat)position detent:(CGFloat)detent {
650
+ [_containerView setupKeyboardObserverWithViewController:_controller];
651
+ [TrueSheetLifecycleEvents emitDidPresent:_eventEmitter index:index position:position detent:detent];
652
+
653
+ if (_pendingPropsUpdate) {
654
+ _pendingPropsUpdate = NO;
655
+ [self applySheetPropsUpdate];
656
+ }
351
657
 
352
- [OnDidPresentEvent emit:_eventEmitter index:index position:position];
658
+ if (_pendingSizeChange) {
659
+ _pendingSizeChange = NO;
660
+ [self setupSheetDetentsForSizeChange];
661
+ }
353
662
  }
354
663
 
355
- - (void)viewControllerDidDrag:(UIGestureRecognizerState)state index:(NSInteger)index position:(CGFloat)position {
664
+ - (void)viewControllerDidDrag:(UIGestureRecognizerState)state
665
+ index:(NSInteger)index
666
+ position:(CGFloat)position
667
+ detent:(CGFloat)detent {
356
668
  switch (state) {
357
669
  case UIGestureRecognizerStateBegan:
358
- [OnDragBeginEvent emit:_eventEmitter index:index position:position];
670
+ [TrueSheetDragEvents emitDragBegin:_eventEmitter index:index position:position detent:detent];
359
671
  break;
360
-
361
672
  case UIGestureRecognizerStateChanged:
362
- [OnDragChangeEvent emit:_eventEmitter index:index position:position];
673
+ [TrueSheetDragEvents emitDragChange:_eventEmitter index:index position:position detent:detent];
363
674
  break;
364
-
365
675
  case UIGestureRecognizerStateEnded:
366
676
  case UIGestureRecognizerStateCancelled:
367
- [OnDragEndEvent emit:_eventEmitter index:index position:position];
677
+ [TrueSheetDragEvents emitDragEnd:_eventEmitter index:index position:position detent:detent];
368
678
  break;
369
-
370
679
  default:
371
680
  break;
372
681
  }
373
682
  }
374
683
 
375
684
  - (void)viewControllerWillDismiss {
376
- [OnWillDismissEvent emit:_eventEmitter];
685
+ if (!_dismissedByNavigation) {
686
+ [TrueSheetLifecycleEvents emitWillDismiss:_eventEmitter];
687
+ }
377
688
  }
378
689
 
379
690
  - (void)viewControllerDidDismiss {
380
- _controller.activeDetentIndex = -1;
691
+ [_containerView cleanupKeyboardObserver];
692
+ if (!_dismissedByNavigation) {
693
+ _dismissedByNavigation = NO;
694
+ _pendingNavigationRepresent = NO;
381
695
 
382
- [OnDidDismissEvent emit:_eventEmitter];
696
+ _controller.activeDetentIndex = -1;
697
+ [TrueSheetLifecycleEvents emitDidDismiss:_eventEmitter];
698
+ }
383
699
  }
384
700
 
385
- - (void)viewControllerDidChangeDetent:(NSInteger)index position:(CGFloat)position {
701
+ - (void)viewControllerDidChangeDetent:(NSInteger)index position:(CGFloat)position detent:(CGFloat)detent {
386
702
  if (_controller.activeDetentIndex != index) {
387
703
  _controller.activeDetentIndex = index;
388
704
  }
389
-
390
- [OnDetentChangeEvent emit:_eventEmitter index:index position:position];
705
+ [TrueSheetStateEvents emitDetentChange:_eventEmitter index:index position:position detent:detent];
391
706
  }
392
707
 
393
- - (void)viewControllerDidChangePosition:(NSInteger)index position:(CGFloat)position transitioning:(BOOL)transitioning {
394
- [OnPositionChangeEvent emit:_eventEmitter index:index position:position transitioning:transitioning];
708
+ - (void)viewControllerDidChangePosition:(CGFloat)index
709
+ position:(CGFloat)position
710
+ detent:(CGFloat)detent
711
+ realtime:(BOOL)realtime {
712
+ [TrueSheetStateEvents emitPositionChange:_eventEmitter index:index position:position detent:detent realtime:realtime];
395
713
  }
396
714
 
397
715
  - (void)viewControllerDidChangeSize:(CGSize)size {
398
- [OnSizeChangeEvent emit:_eventEmitter width:size.width height:size.height];
716
+ [self updateStateWithSize:size];
717
+ }
718
+
719
+ - (void)viewControllerWillFocus {
720
+ [TrueSheetFocusEvents emitWillFocus:_eventEmitter];
721
+ }
722
+
723
+ - (void)viewControllerDidFocus {
724
+ [TrueSheetFocusEvents emitDidFocus:_eventEmitter];
725
+ }
726
+
727
+ - (void)viewControllerWillBlur {
728
+ [TrueSheetFocusEvents emitWillBlur:_eventEmitter];
729
+ }
730
+
731
+ - (void)viewControllerDidBlur {
732
+ [TrueSheetFocusEvents emitDidBlur:_eventEmitter];
733
+ }
734
+
735
+ #pragma mark - RNScreensEventObserverDelegate
736
+
737
+ - (void)presenterScreenWillDisappear {
738
+ if (_controller.isPresented && !_controller.isBeingDismissed) {
739
+ _dismissedByNavigation = YES;
740
+ [self dismissAnimated:YES completion:nil];
741
+ }
742
+ }
743
+
744
+ - (void)presenterScreenWillAppear {
745
+ if (_dismissedByNavigation && !_controller.isPresented && !_controller.isBeingPresented) {
746
+ _dismissedByNavigation = NO;
747
+
748
+ if (self.window) {
749
+ [self presentAtIndex:_controller.activeDetentIndex animated:YES completion:nil];
750
+ } else {
751
+ _pendingNavigationRepresent = YES;
752
+ }
753
+ }
754
+ }
755
+
756
+ - (void)presenterInteractiveDismissDidBegin {
757
+ [_controller beginInteractiveDismiss];
758
+ }
759
+
760
+ - (void)presenterInteractiveDismissDidUpdate:(CGFloat)progress {
761
+ [_controller updateInteractiveDismiss:progress];
762
+ }
763
+
764
+ - (void)presenterInteractiveDismissDidEnd:(BOOL)cancelled duration:(NSTimeInterval)duration {
765
+ if (cancelled) {
766
+ [_controller cancelInteractiveDismissWithDuration:duration];
767
+ return;
768
+ }
769
+
770
+ _dismissedByNavigation = YES;
771
+ __weak __typeof(self) weakSelf = self;
772
+ [_controller finishInteractiveDismissWithDuration:duration
773
+ completion:^{
774
+ [weakSelf dismissAnimated:NO completion:nil];
775
+ }];
399
776
  }
400
777
 
401
778
  #pragma mark - Private Helpers
402
779
 
403
- - (UIViewController *)findPresentingViewController {
404
- UIWindow *keyWindow = [WindowUtil keyWindow];
780
+ - (void)setupScrollable {
781
+ if (!_containerView)
782
+ return;
405
783
 
406
- if (!keyWindow) {
407
- return nil;
784
+ _containerView.insetAdjustment = _insetAdjustment;
785
+ _containerView.scrollableOptions = _scrollableOptions;
786
+ _containerView.hasAutoDetent = _hasAutoDetent;
787
+ _containerView.footerBottomInset = _controller.footerBottomInset;
788
+ [_containerView setupScrollable];
789
+
790
+ // Publish the inset so a footer set later (e.g. navigation setOptions) is
791
+ // padded on its very first layout instead of resizing the sheet twice.
792
+ if (_insetAdjustment == TrueSheetViewInsetAdjustment::Automatic) {
793
+ TrueSheetInsets::setBottomSafeArea(_controller.footerBottomInset);
408
794
  }
795
+ }
796
+
797
+ - (void)applySheetPropsUpdate {
798
+ BOOL pendingLayoutUpdate = _pendingLayoutUpdate;
799
+ _pendingLayoutUpdate = NO;
800
+
801
+ if (_pendingDetents) {
802
+ _controller.detents = _pendingDetents;
803
+ _pendingDetents = nil;
804
+ }
805
+
806
+ UIView *presenterView = _controller.presentingViewController.view;
807
+ [_controller setupAnchorViewInView:presenterView];
808
+
809
+ [_controller setupSheetSizing];
810
+
811
+ [_controller.sheetPresentationController animateChanges:^{
812
+ [self->_controller setupSheetProps];
813
+ if (pendingLayoutUpdate) {
814
+ [self->_controller setupSheetDetentsForDetentsChange];
815
+ } else {
816
+ [self->_controller setupSheetDetents];
817
+ }
818
+ [self->_controller applyActiveDetent];
819
+ }];
820
+ [_controller setupDraggable];
821
+ }
409
822
 
410
- UIViewController *rootViewController = keyWindow.rootViewController;
823
+ - (UIViewController *)findPresentingViewController {
824
+ if (!self.window)
825
+ return nil;
826
+
827
+ UIViewController *rootViewController = self.window.rootViewController;
828
+ if (!rootViewController)
829
+ return nil;
411
830
 
412
- // Find the top-most presented view controller
831
+ // Find topmost presented view controller that is not being dismissed
413
832
  while (rootViewController.presentedViewController) {
414
833
  UIViewController *presented = rootViewController.presentedViewController;
415
834
 
416
- // Skip TrueSheetViewController if it's being dismissed
417
- if ([presented isKindOfClass:[TrueSheetViewController class]] && presented.isBeingDismissed) {
835
+ // Skip any view controller that is being dismissed
836
+ if (presented.isBeingDismissed) {
418
837
  break;
419
838
  }
420
-
421
839
  rootViewController = presented;
422
840
  }
423
841