@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
@@ -0,0 +1,162 @@
1
+ package com.lodev09.truesheet.core
2
+
3
+ import android.annotation.SuppressLint
4
+ import android.graphics.Color
5
+ import android.graphics.Outline
6
+ import android.view.MotionEvent
7
+ import android.view.View
8
+ import android.view.ViewGroup
9
+ import android.view.ViewOutlineProvider
10
+ import com.facebook.react.uimanager.PointerEvents
11
+ import com.facebook.react.uimanager.ReactPointerEventsView
12
+ import com.facebook.react.uimanager.ThemedReactContext
13
+ import com.lodev09.truesheet.utils.ScreenUtils
14
+
15
+ /**
16
+ * Delegate for handling dim view interactions.
17
+ */
18
+ interface TrueSheetDimViewDelegate {
19
+ fun dimViewDidTap()
20
+ }
21
+
22
+ /**
23
+ * Dim view that sits behind the bottom sheet in the CoordinatorLayout.
24
+ *
25
+ * Key behaviors:
26
+ * - When alpha > 0 (dimmed): blocks touches and calls delegate on tap
27
+ * - When alpha == 0 (not dimmed): passes touches through to views below
28
+ *
29
+ * This implements the "dimmedDetentIndex" equivalent functionality:
30
+ * the view only becomes interactive when the sheet is at or above the dimmed detent.
31
+ */
32
+ @SuppressLint("ViewConstructor")
33
+ class TrueSheetDimView(private val reactContext: ThemedReactContext) :
34
+ View(reactContext),
35
+ ReactPointerEventsView {
36
+
37
+ companion object {
38
+ private const val MAX_ALPHA = 0.5f
39
+ }
40
+
41
+ var delegate: TrueSheetDimViewDelegate? = null
42
+
43
+ private var targetView: ViewGroup? = null
44
+
45
+ /**
46
+ * Whether this view should block gestures (when dimmed).
47
+ */
48
+ private val blockGestures: Boolean
49
+ get() = alpha > 0f
50
+
51
+ init {
52
+ layoutParams = ViewGroup.LayoutParams(
53
+ ViewGroup.LayoutParams.MATCH_PARENT,
54
+ ViewGroup.LayoutParams.MATCH_PARENT
55
+ )
56
+ setBackgroundColor(Color.BLACK)
57
+ alpha = 0f
58
+
59
+ // Handle taps on the dim view
60
+ setOnClickListener {
61
+ delegate?.dimViewDidTap()
62
+ }
63
+
64
+ importantForAccessibility = IMPORTANT_FOR_ACCESSIBILITY_NO
65
+ }
66
+
67
+ // =============================================================================
68
+ // MARK: - Attachment
69
+ // =============================================================================
70
+
71
+ /**
72
+ * Attaches this dim view to a target view group.
73
+ * For CoordinatorLayout usage, pass null to use the default (activity's decor view).
74
+ * For stacked sheets, pass the parent sheet's bottom sheet view with corner radius.
75
+ */
76
+ fun attach(view: ViewGroup? = null, cornerRadius: Float = 0f) {
77
+ if (parent != null) return
78
+ targetView = view ?: reactContext.currentActivity?.window?.decorView as? ViewGroup
79
+
80
+ if (cornerRadius > 0f) {
81
+ outlineProvider = object : ViewOutlineProvider() {
82
+ override fun getOutline(v: View, outline: Outline) {
83
+ outline.setRoundRect(0, 0, v.width, v.height, cornerRadius)
84
+ }
85
+ }
86
+ clipToOutline = true
87
+ } else {
88
+ outlineProvider = null
89
+ clipToOutline = false
90
+ }
91
+
92
+ targetView?.addView(this)
93
+ }
94
+
95
+ /**
96
+ * Attaches this dim view to a CoordinatorLayout at index 0 (behind the sheet).
97
+ */
98
+ fun attachToCoordinator(coordinator: TrueSheetCoordinatorLayout) {
99
+ if (parent != null) return
100
+ targetView = coordinator
101
+ outlineProvider = null
102
+ clipToOutline = false
103
+ coordinator.addView(this, 0)
104
+ }
105
+
106
+ fun detach() {
107
+ targetView?.removeView(this)
108
+ targetView = null
109
+ }
110
+
111
+ // =============================================================================
112
+ // MARK: - Alpha Calculation
113
+ // =============================================================================
114
+
115
+ fun calculateAlpha(sheetTop: Int, dimmedDetentIndex: Int, getSheetTopForDetentIndex: (Int) -> Int): Float {
116
+ val realHeight = ScreenUtils.getRealScreenHeight(reactContext)
117
+ val dimmedDetentTop = getSheetTopForDetentIndex(dimmedDetentIndex)
118
+ val belowDimmedTop = if (dimmedDetentIndex > 0) getSheetTopForDetentIndex(dimmedDetentIndex - 1) else realHeight
119
+
120
+ return when {
121
+ sheetTop <= dimmedDetentTop -> MAX_ALPHA
122
+
123
+ sheetTop >= belowDimmedTop -> 0f
124
+
125
+ else -> {
126
+ val progress = 1f - (sheetTop - dimmedDetentTop).toFloat() / (belowDimmedTop - dimmedDetentTop)
127
+ (progress * MAX_ALPHA).coerceIn(0f, MAX_ALPHA)
128
+ }
129
+ }
130
+ }
131
+
132
+ fun interpolateAlpha(sheetTop: Int, dimmedDetentIndex: Int, getSheetTopForDetentIndex: (Int) -> Int) {
133
+ alpha = calculateAlpha(sheetTop, dimmedDetentIndex, getSheetTopForDetentIndex)
134
+ }
135
+
136
+ // =============================================================================
137
+ // MARK: - Touch Handling
138
+ // =============================================================================
139
+
140
+ override fun onTouchEvent(event: MotionEvent): Boolean {
141
+ if (blockGestures) {
142
+ // When dimmed, consume touch and trigger click on ACTION_UP
143
+ if (event.action == MotionEvent.ACTION_UP) {
144
+ performClick()
145
+ }
146
+ return true
147
+ }
148
+ // When not dimmed, let touches pass through
149
+ return false
150
+ }
151
+
152
+ // =============================================================================
153
+ // MARK: - ReactPointerEventsView
154
+ // =============================================================================
155
+
156
+ /**
157
+ * When dimmed (alpha > 0), intercept touches (AUTO).
158
+ * When not dimmed (alpha == 0), pass through (NONE).
159
+ */
160
+ override val pointerEvents: PointerEvents
161
+ get() = if (blockGestures) PointerEvents.AUTO else PointerEvents.NONE
162
+ }
@@ -0,0 +1,180 @@
1
+ package com.lodev09.truesheet.core
2
+
3
+ import android.annotation.SuppressLint
4
+ import android.content.Context
5
+ import android.content.res.Configuration
6
+ import android.graphics.Color
7
+ import android.graphics.drawable.GradientDrawable
8
+ import android.os.Bundle
9
+ import android.view.Gravity
10
+ import android.view.View
11
+ import android.view.accessibility.AccessibilityNodeInfo
12
+ import android.widget.FrameLayout
13
+ import androidx.core.graphics.ColorUtils
14
+ import androidx.core.view.ViewCompat
15
+ import com.facebook.react.uimanager.PixelUtil.dpToPx
16
+
17
+ /**
18
+ * Options for customizing the grabber appearance.
19
+ */
20
+ data class GrabberOptions(
21
+ val width: Float? = null,
22
+ val height: Float? = null,
23
+ val topMargin: Float? = null,
24
+ val cornerRadius: Float? = null,
25
+ val color: Int? = null,
26
+ val adaptive: Boolean = true
27
+ )
28
+
29
+ /**
30
+ * Options for customizing (e.g. localizing) accessibility strings.
31
+ */
32
+ data class AccessibilityOptions(
33
+ val grabberLabel: String? = null,
34
+ val expandedValue: String? = null,
35
+ val collapsedValue: String? = null,
36
+ val detentValue: String? = null,
37
+ val expandActionLabel: String? = null,
38
+ val collapseActionLabel: String? = null,
39
+ val paneTitle: String? = null
40
+ )
41
+
42
+ /**
43
+ * Native grabber (drag handle) view for the bottom sheet.
44
+ * Displays a small pill-shaped indicator at the top of the sheet with a tappable hitbox.
45
+ */
46
+ @SuppressLint("ViewConstructor")
47
+ class TrueSheetGrabberView(
48
+ context: Context,
49
+ private val options: GrabberOptions? = null,
50
+ private val accessibilityOptions: AccessibilityOptions? = null
51
+ ) : FrameLayout(context) {
52
+
53
+ companion object {
54
+ private const val DEFAULT_WIDTH = 32f // dp
55
+ private const val DEFAULT_HEIGHT = 4f // dp
56
+ private const val DEFAULT_TOP_MARGIN = 16f // dp
57
+ private const val DEFAULT_ALPHA = 0.4f
58
+ private const val HITBOX_PADDING_HORIZONTAL = 16f // dp
59
+ private const val HITBOX_PADDING_VERTICAL = 16f // dp
60
+ private val DEFAULT_COLOR = Color.argb((DEFAULT_ALPHA * 255).toInt(), 73, 69, 79) // #49454F @ 40%
61
+ }
62
+
63
+ private val grabberWidth: Float
64
+ get() = options?.width ?: DEFAULT_WIDTH
65
+
66
+ private val grabberHeight: Float
67
+ get() = options?.height ?: DEFAULT_HEIGHT
68
+
69
+ private val grabberTopMargin: Float
70
+ get() = options?.topMargin ?: DEFAULT_TOP_MARGIN
71
+
72
+ private val grabberCornerRadius: Float
73
+ get() = options?.cornerRadius ?: (grabberHeight / 2)
74
+
75
+ private val isAdaptive: Boolean
76
+ get() = options?.adaptive ?: true
77
+
78
+ private val grabberColor: Int
79
+ get() = if (isAdaptive) getAdaptiveColor(options?.color) else options?.color ?: DEFAULT_COLOR
80
+
81
+ var onAccessibilityIncrement: (() -> Unit)? = null
82
+ var onAccessibilityDecrement: (() -> Unit)? = null
83
+
84
+ init {
85
+ val hitboxWidth = grabberWidth + (HITBOX_PADDING_HORIZONTAL * 2)
86
+ val hitboxHeight = grabberHeight + (HITBOX_PADDING_VERTICAL * 2)
87
+
88
+ layoutParams = LayoutParams(
89
+ hitboxWidth.dpToPx().toInt(),
90
+ hitboxHeight.dpToPx().toInt()
91
+ ).apply {
92
+ gravity = Gravity.CENTER_HORIZONTAL or Gravity.TOP
93
+ topMargin = (grabberTopMargin - HITBOX_PADDING_VERTICAL).dpToPx().toInt()
94
+ }
95
+
96
+ // The visible pill centered inside the hitbox
97
+ val pillView = View(context).apply {
98
+ layoutParams = LayoutParams(
99
+ grabberWidth.dpToPx().toInt(),
100
+ grabberHeight.dpToPx().toInt()
101
+ ).apply {
102
+ gravity = Gravity.CENTER
103
+ }
104
+ background = GradientDrawable().apply {
105
+ shape = GradientDrawable.RECTANGLE
106
+ cornerRadius = grabberCornerRadius.dpToPx()
107
+ setColor(grabberColor)
108
+ }
109
+ }
110
+
111
+ addView(pillView)
112
+
113
+ isFocusable = true
114
+ contentDescription = accessibilityOptions?.grabberLabel ?: "Drag handle"
115
+
116
+ accessibilityDelegate = object : View.AccessibilityDelegate() {
117
+ override fun onInitializeAccessibilityNodeInfo(host: View, info: AccessibilityNodeInfo) {
118
+ super.onInitializeAccessibilityNodeInfo(host, info)
119
+ info.addAction(
120
+ AccessibilityNodeInfo.AccessibilityAction(
121
+ AccessibilityNodeInfo.ACTION_SCROLL_FORWARD,
122
+ accessibilityOptions?.expandActionLabel ?: "Expand"
123
+ )
124
+ )
125
+ info.addAction(
126
+ AccessibilityNodeInfo.AccessibilityAction(
127
+ AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD,
128
+ accessibilityOptions?.collapseActionLabel ?: "Collapse"
129
+ )
130
+ )
131
+ info.className = "android.widget.SeekBar"
132
+ }
133
+
134
+ override fun performAccessibilityAction(host: View, action: Int, args: Bundle?): Boolean =
135
+ when (action) {
136
+ AccessibilityNodeInfo.ACTION_SCROLL_FORWARD -> {
137
+ onAccessibilityIncrement?.invoke()
138
+ true
139
+ }
140
+
141
+ AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD -> {
142
+ onAccessibilityDecrement?.invoke()
143
+ true
144
+ }
145
+
146
+ else -> super.performAccessibilityAction(host, action, args)
147
+ }
148
+ }
149
+ }
150
+
151
+ fun updateAccessibilityValue(index: Int, detentCount: Int) {
152
+ val description: CharSequence? = when {
153
+ index < 0 || detentCount <= 0 -> null
154
+
155
+ index >= detentCount - 1 -> accessibilityOptions?.expandedValue ?: "Expanded"
156
+
157
+ index == 0 -> accessibilityOptions?.collapsedValue ?: "Collapsed"
158
+
159
+ else ->
160
+ (accessibilityOptions?.detentValue ?: "Detent {index} of {count}")
161
+ .replace("{index}", "${index + 1}")
162
+ .replace("{count}", "$detentCount")
163
+ }
164
+ ViewCompat.setStateDescription(this, description)
165
+ }
166
+
167
+ private fun getAdaptiveColor(baseColor: Int? = null): Int {
168
+ val nightMode = context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
169
+ val isDarkMode = nightMode == Configuration.UI_MODE_NIGHT_YES
170
+ val modeColor = if (isDarkMode) Color.WHITE else Color.BLACK
171
+
172
+ return if (baseColor != null) {
173
+ // Blend user color with mode color for adaptive effect
174
+ val blendedColor = ColorUtils.blendARGB(baseColor, modeColor, 0.3f)
175
+ ColorUtils.setAlphaComponent(blendedColor, (DEFAULT_ALPHA * 255).toInt())
176
+ } else {
177
+ ColorUtils.setAlphaComponent(modeColor, (DEFAULT_ALPHA * 255).toInt())
178
+ }
179
+ }
180
+ }
@@ -0,0 +1,207 @@
1
+ package com.lodev09.truesheet.core
2
+
3
+ import android.graphics.Rect
4
+ import android.os.Build
5
+ import android.view.View
6
+ import android.view.ViewTreeObserver
7
+ import androidx.core.view.ViewCompat
8
+ import androidx.core.view.WindowInsetsAnimationCompat
9
+ import androidx.core.view.WindowInsetsCompat
10
+ import com.facebook.react.uimanager.ThemedReactContext
11
+ import com.lodev09.truesheet.utils.KeyboardUtils
12
+ import com.lodev09.truesheet.utils.isDescendantOf
13
+
14
+ interface TrueSheetKeyboardObserverDelegate {
15
+ fun keyboardWillShow(height: Int) {}
16
+ fun keyboardDidShow(height: Int) {}
17
+ fun keyboardWillHide() {}
18
+ fun keyboardDidHide() {}
19
+ fun keyboardDidChangeHeight(height: Int) {}
20
+ fun focusDidChange(newFocus: View) {}
21
+ }
22
+
23
+ /**
24
+ * Tracks keyboard height and notifies delegate on changes.
25
+ * Uses WindowInsetsAnimationCompat on API 30+, ViewTreeObserver fallback on older versions.
26
+ */
27
+ class TrueSheetKeyboardObserver(private val targetView: View, private val reactContext: ThemedReactContext) {
28
+
29
+ var delegate: TrueSheetKeyboardObserverDelegate? = null
30
+
31
+ var currentHeight: Int = 0
32
+ private set
33
+
34
+ var targetHeight: Int = 0
35
+ private set
36
+
37
+ var isTransitioning: Boolean = false
38
+ private set
39
+
40
+ fun isFocusedViewWithinSheet(sheetView: View): Boolean {
41
+ val focusedView = targetView.rootView?.findFocus() ?: return false
42
+ var current: View? = focusedView
43
+ while (current != null && current !== targetView) {
44
+ if (current === sheetView) return true
45
+ val parent = current.parent
46
+ current = if (parent is View) parent else null
47
+ }
48
+ return false
49
+ }
50
+
51
+ var isHiding: Boolean = false
52
+ private set
53
+ private var globalLayoutListener: ViewTreeObserver.OnGlobalLayoutListener? = null
54
+ private var focusChangeListener: ViewTreeObserver.OnGlobalFocusChangeListener? = null
55
+ private var activityRootView: View? = null
56
+
57
+ fun start() {
58
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
59
+ setupAnimationCallback()
60
+ } else {
61
+ setupLegacyListener()
62
+ }
63
+ setupFocusChangeListener()
64
+ }
65
+
66
+ fun stop() {
67
+ try {
68
+ globalLayoutListener?.let { listener ->
69
+ activityRootView?.viewTreeObserver?.let { observer ->
70
+ if (observer.isAlive) observer.removeOnGlobalLayoutListener(listener)
71
+ }
72
+ globalLayoutListener = null
73
+ }
74
+ focusChangeListener?.let { listener ->
75
+ activityRootView?.viewTreeObserver?.let { observer ->
76
+ if (observer.isAlive) observer.removeOnGlobalFocusChangeListener(listener)
77
+ }
78
+ focusChangeListener = null
79
+ }
80
+ } finally {
81
+ activityRootView = null
82
+ ViewCompat.setWindowInsetsAnimationCallback(targetView, null)
83
+ }
84
+ }
85
+
86
+ private fun updateHeight(from: Int, to: Int, fraction: Float) {
87
+ val newHeight = (from + (to - from) * fraction).toInt()
88
+ if (currentHeight != newHeight) {
89
+ currentHeight = newHeight
90
+ delegate?.keyboardDidChangeHeight(newHeight)
91
+ }
92
+ }
93
+
94
+ private fun getKeyboardHeight(): Int = KeyboardUtils.getKeyboardHeight(targetView)
95
+
96
+ private fun setupAnimationCallback() {
97
+ ViewCompat.setWindowInsetsAnimationCallback(
98
+ targetView,
99
+ object : WindowInsetsAnimationCompat.Callback(DISPATCH_MODE_CONTINUE_ON_SUBTREE) {
100
+ private var startHeight = 0
101
+ private var endHeight = 0
102
+
103
+ override fun onPrepare(animation: WindowInsetsAnimationCompat) {
104
+ startHeight = getKeyboardHeight()
105
+ }
106
+
107
+ override fun onStart(
108
+ animation: WindowInsetsAnimationCompat,
109
+ bounds: WindowInsetsAnimationCompat.BoundsCompat
110
+ ): WindowInsetsAnimationCompat.BoundsCompat {
111
+ endHeight = getKeyboardHeight()
112
+ targetHeight = endHeight
113
+ isHiding = endHeight < startHeight
114
+ isTransitioning = true
115
+ if (endHeight > startHeight) {
116
+ delegate?.keyboardWillShow(endHeight)
117
+ } else if (isHiding) {
118
+ delegate?.keyboardWillHide()
119
+ }
120
+ return bounds
121
+ }
122
+
123
+ override fun onProgress(insets: WindowInsetsCompat, runningAnimations: List<WindowInsetsAnimationCompat>): WindowInsetsCompat {
124
+ val imeAnimation = runningAnimations.find {
125
+ it.typeMask and WindowInsetsCompat.Type.ime() != 0
126
+ } ?: return insets
127
+
128
+ val fraction = imeAnimation.interpolatedFraction
129
+ updateHeight(startHeight, endHeight, fraction)
130
+
131
+ return insets
132
+ }
133
+
134
+ override fun onEnd(animation: WindowInsetsAnimationCompat) {
135
+ val finalHeight = getKeyboardHeight()
136
+ updateHeight(startHeight, finalHeight, 1f)
137
+ isTransitioning = false
138
+ if (isHiding) {
139
+ delegate?.keyboardDidHide()
140
+ isHiding = false
141
+ } else if (finalHeight > 0) {
142
+ delegate?.keyboardDidShow(finalHeight)
143
+ }
144
+ }
145
+ }
146
+ )
147
+ }
148
+
149
+ private fun setupLegacyListener() {
150
+ // Ensure we don't add duplicate listeners
151
+ if (globalLayoutListener != null) return
152
+
153
+ val rootView = targetView.rootView ?: return
154
+ activityRootView = rootView
155
+
156
+ globalLayoutListener = ViewTreeObserver.OnGlobalLayoutListener {
157
+ val rect = Rect()
158
+ rootView.getWindowVisibleDisplayFrame(rect)
159
+
160
+ val screenHeight = rootView.height
161
+ val keyboardHeight = screenHeight - rect.bottom
162
+
163
+ val newHeight = if (keyboardHeight > screenHeight * 0.15) keyboardHeight else 0
164
+
165
+ // Skip if already at this height
166
+ if (targetHeight == newHeight) return@OnGlobalLayoutListener
167
+
168
+ val previousHeight = currentHeight
169
+ targetHeight = newHeight
170
+ isHiding = newHeight < previousHeight
171
+
172
+ isTransitioning = true
173
+ if (newHeight > previousHeight) {
174
+ delegate?.keyboardWillShow(newHeight)
175
+ } else if (isHiding) {
176
+ delegate?.keyboardWillHide()
177
+ }
178
+
179
+ // On legacy API, keyboard has already animated - just update immediately
180
+ updateHeight(previousHeight, newHeight, 1f)
181
+ isTransitioning = false
182
+
183
+ if (isHiding && newHeight == 0) {
184
+ delegate?.keyboardDidHide()
185
+ isHiding = false
186
+ } else if (newHeight > 0) {
187
+ delegate?.keyboardDidShow(newHeight)
188
+ }
189
+ }
190
+
191
+ rootView.viewTreeObserver.addOnGlobalLayoutListener(globalLayoutListener)
192
+ }
193
+
194
+ private fun setupFocusChangeListener() {
195
+ if (focusChangeListener != null) return
196
+
197
+ val rootView = targetView.rootView ?: return
198
+ activityRootView = rootView
199
+
200
+ focusChangeListener = ViewTreeObserver.OnGlobalFocusChangeListener { _, newFocus ->
201
+ if (currentHeight > 0 && newFocus != null && newFocus.isDescendantOf(targetView)) {
202
+ delegate?.focusDidChange(newFocus)
203
+ }
204
+ }
205
+ rootView.viewTreeObserver.addOnGlobalFocusChangeListener(focusChangeListener)
206
+ }
207
+ }