@hanzogui/sheet 2.0.0

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 (347) hide show
  1. package/LICENSE +21 -0
  2. package/controller/index.cjs +2 -0
  3. package/controller/index.d.ts +5 -0
  4. package/controller/index.js +2 -0
  5. package/controller/index.native.cjs +2 -0
  6. package/controller/index.native.js +2 -0
  7. package/dist/cjs/GestureDetectorWrapper.cjs +48 -0
  8. package/dist/cjs/GestureDetectorWrapper.native.js +53 -0
  9. package/dist/cjs/GestureDetectorWrapper.native.js.map +1 -0
  10. package/dist/cjs/GestureSheetContext.cjs +52 -0
  11. package/dist/cjs/GestureSheetContext.native.js +56 -0
  12. package/dist/cjs/GestureSheetContext.native.js.map +1 -0
  13. package/dist/cjs/Sheet.cjs +117 -0
  14. package/dist/cjs/Sheet.native.js +120 -0
  15. package/dist/cjs/Sheet.native.js.map +1 -0
  16. package/dist/cjs/SheetContext.cjs +32 -0
  17. package/dist/cjs/SheetContext.native.js +35 -0
  18. package/dist/cjs/SheetContext.native.js.map +1 -0
  19. package/dist/cjs/SheetController.cjs +65 -0
  20. package/dist/cjs/SheetController.native.js +71 -0
  21. package/dist/cjs/SheetController.native.js.map +1 -0
  22. package/dist/cjs/SheetImplementationCustom.cjs +472 -0
  23. package/dist/cjs/SheetImplementationCustom.native.js +524 -0
  24. package/dist/cjs/SheetImplementationCustom.native.js.map +1 -0
  25. package/dist/cjs/SheetScrollView.cjs +180 -0
  26. package/dist/cjs/SheetScrollView.native.js +197 -0
  27. package/dist/cjs/SheetScrollView.native.js.map +1 -0
  28. package/dist/cjs/constants.cjs +32 -0
  29. package/dist/cjs/constants.native.js +35 -0
  30. package/dist/cjs/constants.native.js.map +1 -0
  31. package/dist/cjs/contexts.cjs +42 -0
  32. package/dist/cjs/contexts.native.js +45 -0
  33. package/dist/cjs/contexts.native.js.map +1 -0
  34. package/dist/cjs/controller.cjs +29 -0
  35. package/dist/cjs/controller.native.js +32 -0
  36. package/dist/cjs/controller.native.js.map +1 -0
  37. package/dist/cjs/createSheet.cjs +191 -0
  38. package/dist/cjs/createSheet.native.js +208 -0
  39. package/dist/cjs/createSheet.native.js.map +1 -0
  40. package/dist/cjs/gestureState.cjs +39 -0
  41. package/dist/cjs/gestureState.native.js +42 -0
  42. package/dist/cjs/gestureState.native.js.map +1 -0
  43. package/dist/cjs/helpers.cjs +31 -0
  44. package/dist/cjs/helpers.native.js +35 -0
  45. package/dist/cjs/helpers.native.js.map +1 -0
  46. package/dist/cjs/index.cjs +28 -0
  47. package/dist/cjs/index.native.js +31 -0
  48. package/dist/cjs/index.native.js.map +1 -0
  49. package/dist/cjs/nativeSheet.cjs +87 -0
  50. package/dist/cjs/nativeSheet.native.js +101 -0
  51. package/dist/cjs/nativeSheet.native.js.map +1 -0
  52. package/dist/cjs/setupGestureHandler.cjs +46 -0
  53. package/dist/cjs/setupGestureHandler.native.js +50 -0
  54. package/dist/cjs/setupGestureHandler.native.js.map +1 -0
  55. package/dist/cjs/types.cjs +16 -0
  56. package/dist/cjs/types.native.js +19 -0
  57. package/dist/cjs/types.native.js.map +1 -0
  58. package/dist/cjs/useGestureHandlerPan.cjs +136 -0
  59. package/dist/cjs/useGestureHandlerPan.native.js +145 -0
  60. package/dist/cjs/useGestureHandlerPan.native.js.map +1 -0
  61. package/dist/cjs/useKeyboardControllerSheet.cjs +38 -0
  62. package/dist/cjs/useKeyboardControllerSheet.native.js +114 -0
  63. package/dist/cjs/useKeyboardControllerSheet.native.js.map +1 -0
  64. package/dist/cjs/useSheet.cjs +27 -0
  65. package/dist/cjs/useSheet.native.js +32 -0
  66. package/dist/cjs/useSheet.native.js.map +1 -0
  67. package/dist/cjs/useSheetController.cjs +50 -0
  68. package/dist/cjs/useSheetController.native.js +53 -0
  69. package/dist/cjs/useSheetController.native.js.map +1 -0
  70. package/dist/cjs/useSheetOffscreenSize.cjs +51 -0
  71. package/dist/cjs/useSheetOffscreenSize.native.js +61 -0
  72. package/dist/cjs/useSheetOffscreenSize.native.js.map +1 -0
  73. package/dist/cjs/useSheetOpenState.cjs +49 -0
  74. package/dist/cjs/useSheetOpenState.native.js +56 -0
  75. package/dist/cjs/useSheetOpenState.native.js.map +1 -0
  76. package/dist/cjs/useSheetProviderProps.cjs +133 -0
  77. package/dist/cjs/useSheetProviderProps.native.js +153 -0
  78. package/dist/cjs/useSheetProviderProps.native.js.map +1 -0
  79. package/dist/cjs/useSheetScrollViewGestures.cjs +123 -0
  80. package/dist/cjs/useSheetScrollViewGestures.native.js +110 -0
  81. package/dist/cjs/useSheetScrollViewGestures.native.js.map +1 -0
  82. package/dist/esm/GestureDetectorWrapper.mjs +25 -0
  83. package/dist/esm/GestureDetectorWrapper.mjs.map +1 -0
  84. package/dist/esm/GestureDetectorWrapper.native.js +27 -0
  85. package/dist/esm/GestureDetectorWrapper.native.js.map +1 -0
  86. package/dist/esm/GestureSheetContext.mjs +28 -0
  87. package/dist/esm/GestureSheetContext.mjs.map +1 -0
  88. package/dist/esm/GestureSheetContext.native.js +29 -0
  89. package/dist/esm/GestureSheetContext.native.js.map +1 -0
  90. package/dist/esm/Sheet.mjs +89 -0
  91. package/dist/esm/Sheet.mjs.map +1 -0
  92. package/dist/esm/Sheet.native.js +89 -0
  93. package/dist/esm/Sheet.native.js.map +1 -0
  94. package/dist/esm/SheetContext.mjs +6 -0
  95. package/dist/esm/SheetContext.mjs.map +1 -0
  96. package/dist/esm/SheetContext.native.js +6 -0
  97. package/dist/esm/SheetContext.native.js.map +1 -0
  98. package/dist/esm/SheetController.mjs +31 -0
  99. package/dist/esm/SheetController.mjs.map +1 -0
  100. package/dist/esm/SheetController.native.js +34 -0
  101. package/dist/esm/SheetController.native.js.map +1 -0
  102. package/dist/esm/SheetImplementationCustom.mjs +437 -0
  103. package/dist/esm/SheetImplementationCustom.mjs.map +1 -0
  104. package/dist/esm/SheetImplementationCustom.native.js +487 -0
  105. package/dist/esm/SheetImplementationCustom.native.js.map +1 -0
  106. package/dist/esm/SheetScrollView.mjs +146 -0
  107. package/dist/esm/SheetScrollView.mjs.map +1 -0
  108. package/dist/esm/SheetScrollView.native.js +160 -0
  109. package/dist/esm/SheetScrollView.native.js.map +1 -0
  110. package/dist/esm/constants.mjs +6 -0
  111. package/dist/esm/constants.mjs.map +1 -0
  112. package/dist/esm/constants.native.js +6 -0
  113. package/dist/esm/constants.native.js.map +1 -0
  114. package/dist/esm/contexts.mjs +7 -0
  115. package/dist/esm/contexts.mjs.map +1 -0
  116. package/dist/esm/contexts.native.js +7 -0
  117. package/dist/esm/contexts.native.js.map +1 -0
  118. package/dist/esm/controller.mjs +4 -0
  119. package/dist/esm/controller.mjs.map +1 -0
  120. package/dist/esm/controller.native.js +4 -0
  121. package/dist/esm/controller.native.js.map +1 -0
  122. package/dist/esm/createSheet.mjs +168 -0
  123. package/dist/esm/createSheet.mjs.map +1 -0
  124. package/dist/esm/createSheet.native.js +182 -0
  125. package/dist/esm/createSheet.native.js.map +1 -0
  126. package/dist/esm/gestureState.mjs +13 -0
  127. package/dist/esm/gestureState.mjs.map +1 -0
  128. package/dist/esm/gestureState.native.js +13 -0
  129. package/dist/esm/gestureState.native.js.map +1 -0
  130. package/dist/esm/helpers.mjs +8 -0
  131. package/dist/esm/helpers.mjs.map +1 -0
  132. package/dist/esm/helpers.native.js +9 -0
  133. package/dist/esm/helpers.native.js.map +1 -0
  134. package/dist/esm/index.js +12 -0
  135. package/dist/esm/index.js.map +1 -0
  136. package/dist/esm/index.mjs +12 -0
  137. package/dist/esm/index.mjs.map +1 -0
  138. package/dist/esm/index.native.js +12 -0
  139. package/dist/esm/index.native.js.map +1 -0
  140. package/dist/esm/nativeSheet.mjs +63 -0
  141. package/dist/esm/nativeSheet.mjs.map +1 -0
  142. package/dist/esm/nativeSheet.native.js +74 -0
  143. package/dist/esm/nativeSheet.native.js.map +1 -0
  144. package/dist/esm/setupGestureHandler.mjs +22 -0
  145. package/dist/esm/setupGestureHandler.mjs.map +1 -0
  146. package/dist/esm/setupGestureHandler.native.js +23 -0
  147. package/dist/esm/setupGestureHandler.native.js.map +1 -0
  148. package/dist/esm/types.mjs +2 -0
  149. package/dist/esm/types.mjs.map +1 -0
  150. package/dist/esm/types.native.js +2 -0
  151. package/dist/esm/types.native.js.map +1 -0
  152. package/dist/esm/useGestureHandlerPan.mjs +113 -0
  153. package/dist/esm/useGestureHandlerPan.mjs.map +1 -0
  154. package/dist/esm/useGestureHandlerPan.native.js +119 -0
  155. package/dist/esm/useGestureHandlerPan.native.js.map +1 -0
  156. package/dist/esm/useKeyboardControllerSheet.mjs +15 -0
  157. package/dist/esm/useKeyboardControllerSheet.mjs.map +1 -0
  158. package/dist/esm/useKeyboardControllerSheet.native.js +88 -0
  159. package/dist/esm/useKeyboardControllerSheet.native.js.map +1 -0
  160. package/dist/esm/useSheet.mjs +4 -0
  161. package/dist/esm/useSheet.mjs.map +1 -0
  162. package/dist/esm/useSheet.native.js +6 -0
  163. package/dist/esm/useSheet.native.js.map +1 -0
  164. package/dist/esm/useSheetController.mjs +15 -0
  165. package/dist/esm/useSheetController.mjs.map +1 -0
  166. package/dist/esm/useSheetController.native.js +15 -0
  167. package/dist/esm/useSheetController.native.js.map +1 -0
  168. package/dist/esm/useSheetOffscreenSize.mjs +28 -0
  169. package/dist/esm/useSheetOffscreenSize.mjs.map +1 -0
  170. package/dist/esm/useSheetOffscreenSize.native.js +35 -0
  171. package/dist/esm/useSheetOffscreenSize.native.js.map +1 -0
  172. package/dist/esm/useSheetOpenState.mjs +26 -0
  173. package/dist/esm/useSheetOpenState.mjs.map +1 -0
  174. package/dist/esm/useSheetOpenState.native.js +30 -0
  175. package/dist/esm/useSheetOpenState.native.js.map +1 -0
  176. package/dist/esm/useSheetProviderProps.mjs +99 -0
  177. package/dist/esm/useSheetProviderProps.mjs.map +1 -0
  178. package/dist/esm/useSheetProviderProps.native.js +116 -0
  179. package/dist/esm/useSheetProviderProps.native.js.map +1 -0
  180. package/dist/esm/useSheetScrollViewGestures.mjs +100 -0
  181. package/dist/esm/useSheetScrollViewGestures.mjs.map +1 -0
  182. package/dist/esm/useSheetScrollViewGestures.native.js +84 -0
  183. package/dist/esm/useSheetScrollViewGestures.native.js.map +1 -0
  184. package/dist/jsx/GestureDetectorWrapper.mjs +25 -0
  185. package/dist/jsx/GestureDetectorWrapper.mjs.map +1 -0
  186. package/dist/jsx/GestureDetectorWrapper.native.js +53 -0
  187. package/dist/jsx/GestureDetectorWrapper.native.js.map +1 -0
  188. package/dist/jsx/GestureSheetContext.mjs +28 -0
  189. package/dist/jsx/GestureSheetContext.mjs.map +1 -0
  190. package/dist/jsx/GestureSheetContext.native.js +56 -0
  191. package/dist/jsx/GestureSheetContext.native.js.map +1 -0
  192. package/dist/jsx/Sheet.mjs +89 -0
  193. package/dist/jsx/Sheet.mjs.map +1 -0
  194. package/dist/jsx/Sheet.native.js +120 -0
  195. package/dist/jsx/Sheet.native.js.map +1 -0
  196. package/dist/jsx/SheetContext.mjs +6 -0
  197. package/dist/jsx/SheetContext.mjs.map +1 -0
  198. package/dist/jsx/SheetContext.native.js +35 -0
  199. package/dist/jsx/SheetContext.native.js.map +1 -0
  200. package/dist/jsx/SheetController.mjs +31 -0
  201. package/dist/jsx/SheetController.mjs.map +1 -0
  202. package/dist/jsx/SheetController.native.js +71 -0
  203. package/dist/jsx/SheetController.native.js.map +1 -0
  204. package/dist/jsx/SheetImplementationCustom.mjs +437 -0
  205. package/dist/jsx/SheetImplementationCustom.mjs.map +1 -0
  206. package/dist/jsx/SheetImplementationCustom.native.js +524 -0
  207. package/dist/jsx/SheetImplementationCustom.native.js.map +1 -0
  208. package/dist/jsx/SheetScrollView.mjs +146 -0
  209. package/dist/jsx/SheetScrollView.mjs.map +1 -0
  210. package/dist/jsx/SheetScrollView.native.js +197 -0
  211. package/dist/jsx/SheetScrollView.native.js.map +1 -0
  212. package/dist/jsx/constants.mjs +6 -0
  213. package/dist/jsx/constants.mjs.map +1 -0
  214. package/dist/jsx/constants.native.js +35 -0
  215. package/dist/jsx/constants.native.js.map +1 -0
  216. package/dist/jsx/contexts.mjs +7 -0
  217. package/dist/jsx/contexts.mjs.map +1 -0
  218. package/dist/jsx/contexts.native.js +45 -0
  219. package/dist/jsx/contexts.native.js.map +1 -0
  220. package/dist/jsx/controller.mjs +4 -0
  221. package/dist/jsx/controller.mjs.map +1 -0
  222. package/dist/jsx/controller.native.js +32 -0
  223. package/dist/jsx/controller.native.js.map +1 -0
  224. package/dist/jsx/createSheet.mjs +168 -0
  225. package/dist/jsx/createSheet.mjs.map +1 -0
  226. package/dist/jsx/createSheet.native.js +208 -0
  227. package/dist/jsx/createSheet.native.js.map +1 -0
  228. package/dist/jsx/gestureState.mjs +13 -0
  229. package/dist/jsx/gestureState.mjs.map +1 -0
  230. package/dist/jsx/gestureState.native.js +42 -0
  231. package/dist/jsx/gestureState.native.js.map +1 -0
  232. package/dist/jsx/helpers.mjs +8 -0
  233. package/dist/jsx/helpers.mjs.map +1 -0
  234. package/dist/jsx/helpers.native.js +35 -0
  235. package/dist/jsx/helpers.native.js.map +1 -0
  236. package/dist/jsx/index.js +12 -0
  237. package/dist/jsx/index.js.map +1 -0
  238. package/dist/jsx/index.mjs +12 -0
  239. package/dist/jsx/index.mjs.map +1 -0
  240. package/dist/jsx/index.native.js +31 -0
  241. package/dist/jsx/index.native.js.map +1 -0
  242. package/dist/jsx/nativeSheet.mjs +63 -0
  243. package/dist/jsx/nativeSheet.mjs.map +1 -0
  244. package/dist/jsx/nativeSheet.native.js +101 -0
  245. package/dist/jsx/nativeSheet.native.js.map +1 -0
  246. package/dist/jsx/setupGestureHandler.mjs +22 -0
  247. package/dist/jsx/setupGestureHandler.mjs.map +1 -0
  248. package/dist/jsx/setupGestureHandler.native.js +50 -0
  249. package/dist/jsx/setupGestureHandler.native.js.map +1 -0
  250. package/dist/jsx/types.mjs +2 -0
  251. package/dist/jsx/types.mjs.map +1 -0
  252. package/dist/jsx/types.native.js +19 -0
  253. package/dist/jsx/types.native.js.map +1 -0
  254. package/dist/jsx/useGestureHandlerPan.mjs +113 -0
  255. package/dist/jsx/useGestureHandlerPan.mjs.map +1 -0
  256. package/dist/jsx/useGestureHandlerPan.native.js +145 -0
  257. package/dist/jsx/useGestureHandlerPan.native.js.map +1 -0
  258. package/dist/jsx/useKeyboardControllerSheet.mjs +15 -0
  259. package/dist/jsx/useKeyboardControllerSheet.mjs.map +1 -0
  260. package/dist/jsx/useKeyboardControllerSheet.native.js +114 -0
  261. package/dist/jsx/useKeyboardControllerSheet.native.js.map +1 -0
  262. package/dist/jsx/useSheet.mjs +4 -0
  263. package/dist/jsx/useSheet.mjs.map +1 -0
  264. package/dist/jsx/useSheet.native.js +32 -0
  265. package/dist/jsx/useSheet.native.js.map +1 -0
  266. package/dist/jsx/useSheetController.mjs +15 -0
  267. package/dist/jsx/useSheetController.mjs.map +1 -0
  268. package/dist/jsx/useSheetController.native.js +53 -0
  269. package/dist/jsx/useSheetController.native.js.map +1 -0
  270. package/dist/jsx/useSheetOffscreenSize.mjs +28 -0
  271. package/dist/jsx/useSheetOffscreenSize.mjs.map +1 -0
  272. package/dist/jsx/useSheetOffscreenSize.native.js +61 -0
  273. package/dist/jsx/useSheetOffscreenSize.native.js.map +1 -0
  274. package/dist/jsx/useSheetOpenState.mjs +26 -0
  275. package/dist/jsx/useSheetOpenState.mjs.map +1 -0
  276. package/dist/jsx/useSheetOpenState.native.js +56 -0
  277. package/dist/jsx/useSheetOpenState.native.js.map +1 -0
  278. package/dist/jsx/useSheetProviderProps.mjs +99 -0
  279. package/dist/jsx/useSheetProviderProps.mjs.map +1 -0
  280. package/dist/jsx/useSheetProviderProps.native.js +153 -0
  281. package/dist/jsx/useSheetProviderProps.native.js.map +1 -0
  282. package/dist/jsx/useSheetScrollViewGestures.mjs +100 -0
  283. package/dist/jsx/useSheetScrollViewGestures.mjs.map +1 -0
  284. package/dist/jsx/useSheetScrollViewGestures.native.js +110 -0
  285. package/dist/jsx/useSheetScrollViewGestures.native.js.map +1 -0
  286. package/next.md +78 -0
  287. package/package.json +96 -0
  288. package/setup-gesture-handler/index.cjs +2 -0
  289. package/setup-gesture-handler/index.js +2 -0
  290. package/setup-gesture-handler/index.native.cjs +2 -0
  291. package/setup-gesture-handler/index.native.js +2 -0
  292. package/setup-gesture-handler.cjs +1 -0
  293. package/src/GestureDetectorWrapper.tsx +41 -0
  294. package/src/GestureSheetContext.tsx +62 -0
  295. package/src/Sheet.tsx +114 -0
  296. package/src/SheetContext.tsx +11 -0
  297. package/src/SheetController.tsx +44 -0
  298. package/src/SheetImplementationCustom.tsx +868 -0
  299. package/src/SheetScrollView.tsx +195 -0
  300. package/src/constants.tsx +5 -0
  301. package/src/contexts.ts +9 -0
  302. package/src/controller.ts +9 -0
  303. package/src/createSheet.tsx +296 -0
  304. package/src/gestureState.ts +24 -0
  305. package/src/helpers.tsx +31 -0
  306. package/src/index.ts +11 -0
  307. package/src/nativeSheet.tsx +89 -0
  308. package/src/setupGestureHandler.ts +34 -0
  309. package/src/types.tsx +181 -0
  310. package/src/useGestureHandlerPan.tsx +364 -0
  311. package/src/useKeyboardControllerSheet.native.ts +136 -0
  312. package/src/useKeyboardControllerSheet.ts +26 -0
  313. package/src/useSheet.tsx +3 -0
  314. package/src/useSheetController.tsx +27 -0
  315. package/src/useSheetOffscreenSize.tsx +49 -0
  316. package/src/useSheetOpenState.tsx +33 -0
  317. package/src/useSheetProviderProps.tsx +223 -0
  318. package/src/useSheetScrollViewGestures.native.ts +163 -0
  319. package/src/useSheetScrollViewGestures.ts +194 -0
  320. package/tsconfig.json +56 -0
  321. package/types/GestureDetectorWrapper.d.ts +14 -0
  322. package/types/GestureSheetContext.d.ts +36 -0
  323. package/types/Sheet.d.ts +183 -0
  324. package/types/SheetContext.d.ts +43 -0
  325. package/types/SheetController.d.ts +6 -0
  326. package/types/SheetImplementationCustom.d.ts +36 -0
  327. package/types/SheetScrollView.d.ts +40 -0
  328. package/types/constants.d.ts +5 -0
  329. package/types/contexts.d.ts +6 -0
  330. package/types/controller.d.ts +3 -0
  331. package/types/createSheet.d.ts +194 -0
  332. package/types/gestureState.d.ts +11 -0
  333. package/types/helpers.d.ts +2 -0
  334. package/types/index.d.ts +12 -0
  335. package/types/nativeSheet.d.ts +10 -0
  336. package/types/setupGestureHandler.d.ts +11 -0
  337. package/types/types.d.ts +147 -0
  338. package/types/useGestureHandlerPan.d.ts +44 -0
  339. package/types/useKeyboardControllerSheet.d.ts +7 -0
  340. package/types/useKeyboardControllerSheet.native.d.ts +13 -0
  341. package/types/useSheet.d.ts +2 -0
  342. package/types/useSheetController.d.ts +17 -0
  343. package/types/useSheetOffscreenSize.d.ts +3 -0
  344. package/types/useSheetOpenState.d.ts +9 -0
  345. package/types/useSheetProviderProps.d.ts +36 -0
  346. package/types/useSheetScrollViewGestures.d.ts +12 -0
  347. package/types/useSheetScrollViewGestures.native.d.ts +21 -0
@@ -0,0 +1,868 @@
1
+ import { ProvideAdaptContext, useAdaptContext } from '@hanzogui/adapt'
2
+ import { AnimatePresence } from '@hanzogui/animate-presence'
3
+ import { useComposedRefs } from '@hanzogui/compose-refs'
4
+ import { isWeb, useIsomorphicLayoutEffect } from '@hanzogui/constants'
5
+ import {
6
+ LayoutMeasurementController,
7
+ View as GuiView,
8
+ useConfiguration,
9
+ useDidFinishSSR,
10
+ useEvent,
11
+ useThemeName,
12
+ } from '@hanzogui/core'
13
+ import { getSafeArea } from '@hanzogui/native'
14
+ import { needsPortalRepropagation, Portal } from '@hanzogui/portal'
15
+ import React, { useState } from 'react'
16
+ import type {
17
+ Animated,
18
+ GestureResponderEvent,
19
+ LayoutChangeEvent,
20
+ PanResponderGestureState,
21
+ } from 'react-native'
22
+ import { Dimensions, PanResponder, View } from 'react-native'
23
+ import { ParentSheetContext, SheetInsideSheetContext } from './contexts'
24
+ import { GestureDetectorWrapper } from './GestureDetectorWrapper'
25
+ import { GestureSheetProvider } from './GestureSheetContext'
26
+ import { resisted } from './helpers'
27
+ import { SheetProvider } from './SheetContext'
28
+ import type { SheetProps, SnapPointsMode } from './types'
29
+ import { useGestureHandlerPan } from './useGestureHandlerPan'
30
+ import { useKeyboardControllerSheet } from './useKeyboardControllerSheet'
31
+ import { useSheetOpenState } from './useSheetOpenState'
32
+ import { useSheetProviderProps } from './useSheetProviderProps'
33
+
34
+ const hiddenSize = 10_000.1
35
+
36
+ // safe area top inset, cached per-session (device-constant value)
37
+ let _cachedSafeAreaTop: number | undefined
38
+ function getSafeAreaTopInset(): number {
39
+ if (_cachedSafeAreaTop !== undefined) return _cachedSafeAreaTop
40
+ // use @hanzogui/native abstraction - returns 0 when not enabled
41
+ _cachedSafeAreaTop = getSafeArea().getInsets().top
42
+ return _cachedSafeAreaTop
43
+ }
44
+
45
+ let sheetHiddenStyleSheet: HTMLStyleElement | null = null
46
+
47
+ // on web we are always relative to window, on to screen
48
+ const relativeDimensionTo = isWeb ? 'window' : 'screen'
49
+
50
+ export const SheetImplementationCustom = React.forwardRef<View, SheetProps>(
51
+ function SheetImplementationCustom(props, forwardedRef) {
52
+ const parentSheet = React.useContext(ParentSheetContext)
53
+
54
+ const {
55
+ transition,
56
+ transitionConfig: transitionConfigProp,
57
+ modal = false,
58
+ zIndex = parentSheet.zIndex + 1,
59
+ moveOnKeyboardChange = false,
60
+ unmountChildrenWhenHidden = false,
61
+ portalProps,
62
+ containerComponent: ContainerComponent = React.Fragment,
63
+ onAnimationComplete,
64
+ } = props
65
+
66
+ const state = useSheetOpenState(props)
67
+ const [overlayComponent, setOverlayComponent] = React.useState<React.ReactNode>(null)
68
+
69
+ const providerProps = useSheetProviderProps(props, state, {
70
+ onOverlayComponent: setOverlayComponent,
71
+ })
72
+ const {
73
+ frameSize,
74
+ setFrameSize,
75
+ snapPoints,
76
+ snapPointsMode,
77
+ hasFit,
78
+ position,
79
+ setPosition,
80
+ scrollBridge,
81
+ screenSize,
82
+ setMaxContentSize,
83
+ maxSnapPoint,
84
+ } = providerProps
85
+ const { open, controller, isHidden } = state
86
+ const openRef = React.useRef(open)
87
+ openRef.current = open
88
+
89
+ const sheetRef = React.useRef<View>(undefined as unknown as View)
90
+ const ref = useComposedRefs(forwardedRef, sheetRef, providerProps.contentRef as any)
91
+
92
+ // TODO this can be extracted into a helper getAnimationConfig(animationProp as array | string)
93
+ const { animationDriver } = useConfiguration()
94
+
95
+ if (!animationDriver) {
96
+ throw new Error(`Sheet requires an animation driver to be set`)
97
+ }
98
+
99
+ const transitionConfig = (() => {
100
+ // explicit transitionConfig prop always takes precedence
101
+ if (transitionConfigProp) {
102
+ return transitionConfigProp
103
+ }
104
+
105
+ const [animationProp, animationPropConfig] = !transition
106
+ ? []
107
+ : Array.isArray(transition)
108
+ ? transition
109
+ : ([transition] as const)
110
+
111
+ // look up named animation config from driver if available
112
+ if (animationProp && animationDriver.animations?.[animationProp as string]) {
113
+ return {
114
+ ...animationDriver.animations[animationProp as string],
115
+ ...animationPropConfig,
116
+ }
117
+ }
118
+
119
+ return null
120
+ })()
121
+
122
+ /**
123
+ * This is a hacky workaround for native:
124
+ */
125
+ const [isShowingInnerSheet, setIsShowingInnerSheet] = React.useState(false)
126
+ // when using Gorhom portal (no teleport), inner sheets need to hide parent
127
+ const shouldHideParentSheet =
128
+ !isWeb && modal && isShowingInnerSheet && needsPortalRepropagation()
129
+
130
+ const sheetInsideSheet = React.useContext(SheetInsideSheetContext)
131
+ const onInnerSheet = React.useCallback((hasChild: boolean) => {
132
+ setIsShowingInnerSheet(hasChild)
133
+ }, [])
134
+
135
+ // FIX: Store stable frameSize to prevent recalculation during exit animation
136
+ const stableFrameSize = React.useRef(frameSize)
137
+
138
+ React.useEffect(() => {
139
+ // Only update stable size when sheet is open
140
+ if (open && frameSize) {
141
+ stableFrameSize.current = frameSize
142
+ }
143
+ }, [open, frameSize])
144
+
145
+ // use stableFrameSize when closing to prevent position jumps during exit animation
146
+ // but when opening, always use the current frameSize so positions update correctly
147
+ const effectiveFrameSize = open ? frameSize : stableFrameSize.current || frameSize
148
+
149
+ const positions = React.useMemo(
150
+ () =>
151
+ snapPoints.map((point) =>
152
+ getYPositions(snapPointsMode, point, screenSize, effectiveFrameSize)
153
+ ),
154
+ [screenSize, effectiveFrameSize, snapPoints, snapPointsMode]
155
+ )
156
+
157
+ // keyboard state tracking — just tracks height/visibility, no position animation.
158
+ // Position animation is handled via keyboard-adjusted positions below,
159
+ // matching the react-native-actions-sheet pattern.
160
+ const {
161
+ keyboardHeight,
162
+ isKeyboardVisible,
163
+ dismissKeyboard,
164
+ pauseKeyboardHandler,
165
+ flushPendingHide,
166
+ } = useKeyboardControllerSheet({
167
+ enabled: !isWeb && Boolean(moveOnKeyboardChange),
168
+ })
169
+
170
+ const [isDragging, setIsDragging_] = React.useState(false)
171
+
172
+ // synchronous dragging ref — set BEFORE async state commits.
173
+ // RNGH onBegin fires before keyboard hide event reaches JS,
174
+ // so the ref is true by the time activePositions memo re-evaluates.
175
+ // Also controls pauseKeyboardHandler to freeze keyboard state during drag.
176
+ const isDraggingRef = React.useRef(false)
177
+ const setIsDragging = React.useCallback(
178
+ (val: boolean) => {
179
+ isDraggingRef.current = val
180
+ pauseKeyboardHandler.current = val
181
+ setIsDragging_(val)
182
+ // when drag ends, flush any keyboard hide that was suppressed during drag
183
+ // so isKeyboardVisible/keyboardHeight reflect actual state
184
+ if (!val) {
185
+ flushPendingHide()
186
+ }
187
+ },
188
+ [pauseKeyboardHandler, flushPendingHide]
189
+ )
190
+
191
+ // keyboard-adjusted positions: shift snap points up by keyboard height
192
+ // when keyboard is visible. This drives both gesture snap calculation
193
+ // and animation targets — keyboard never dismissed during drag.
194
+ // Capped at safe area top inset so the sheet never goes above the notch/status bar
195
+ // (matching the react-native-actions-sheet pattern).
196
+ //
197
+ // IMPORTANT: frozen during drag to prevent gesture handler recreation.
198
+ // When user drags, TextInput may blur → keyboard dismisses → positions would revert,
199
+ // causing the gesture useMemo to recreate and cancel the active drag.
200
+ // The post-drag reconciliation effect handles animating to correct position after drag ends.
201
+ const activePositionsRef = React.useRef(positions)
202
+ const activePositions = React.useMemo(() => {
203
+ // during drag, return frozen positions to prevent gesture handler recreation.
204
+ // check both state (for re-render trigger) and ref (for synchronous check
205
+ // when keyboard hide event fires before isDragging state commits)
206
+ if (isDragging || isDraggingRef.current) return activePositionsRef.current
207
+
208
+ let result: number[]
209
+ if (!isKeyboardVisible || keyboardHeight <= 0) {
210
+ result = positions
211
+ } else {
212
+ const safeAreaTop = isWeb ? 0 : getSafeAreaTopInset()
213
+ result = positions.map((p) => {
214
+ // don't adjust the off-screen/close position (from dismissOnSnapToBottom's 0% snap)
215
+ // — it must stay at screenSize so the user can drag between real snap points
216
+ // without accidentally closing the sheet
217
+ if (screenSize && p >= screenSize) return p
218
+ return Math.max(safeAreaTop, p - keyboardHeight)
219
+ })
220
+ }
221
+ activePositionsRef.current = result
222
+ return result
223
+ }, [positions, isKeyboardVisible, keyboardHeight, screenSize, isDragging])
224
+
225
+ const { useAnimatedNumber, useAnimatedNumberStyle, useAnimatedNumberReaction } =
226
+ animationDriver
227
+ const AnimatedView = (animationDriver.View ?? GuiView) as typeof Animated.View
228
+
229
+ useIsomorphicLayoutEffect(() => {
230
+ if (!(sheetInsideSheet && open)) return
231
+ sheetInsideSheet(true)
232
+ return () => {
233
+ sheetInsideSheet(false)
234
+ }
235
+ }, [sheetInsideSheet, open])
236
+
237
+ const nextParentContext = React.useMemo(
238
+ () => ({
239
+ zIndex,
240
+ }),
241
+ [zIndex]
242
+ )
243
+
244
+ const isMounted = useDidFinishSSR()
245
+ const startPosition = isMounted && screenSize ? screenSize : hiddenSize
246
+ const animatedNumber = useAnimatedNumber(startPosition)
247
+ const at = React.useRef(startPosition)
248
+ const hasntMeasured = at.current === hiddenSize
249
+ const [disableAnimation, setDisableAnimation] = useState(hasntMeasured)
250
+
251
+ // use skipNextAnimation signal from controller (set when adapt handoff occurs)
252
+ const skipAdaptAnimation = React.useRef(false)
253
+ if (controller?.skipNextAnimation) {
254
+ skipAdaptAnimation.current = true
255
+ }
256
+
257
+ const hasScrollView = React.useRef(false)
258
+
259
+ // safety fallback timer for sheet close opacity
260
+ const opacityFallbackTimer = React.useRef<ReturnType<typeof setTimeout> | null>(null)
261
+
262
+ useAnimatedNumberReaction(
263
+ {
264
+ value: animatedNumber,
265
+ hostRef: sheetRef,
266
+ },
267
+ React.useCallback(
268
+ (value) => {
269
+ at.current = value
270
+ scrollBridge.paneY = value
271
+ // update isAtTop for scroll enable/disable
272
+ // activePositions[0] is the top snap point (keyboard-adjusted minY)
273
+ const minY = activePositions[0]
274
+ const wasAtTop = scrollBridge.isAtTop
275
+ const nowAtTop = value <= minY + 5
276
+ if (wasAtTop !== nowAtTop) {
277
+ scrollBridge.isAtTop = nowAtTop
278
+ // when reaching top, enable scroll; when leaving top, disable scroll
279
+ // this preemptively sets scroll state before any gestures start
280
+ if (nowAtTop) {
281
+ // if scroll drifted during drag (e.g. fast swipe from position 1),
282
+ // reset it to 0 before enabling free scroll
283
+ if (scrollBridge.y > 0) {
284
+ scrollBridge.forceScrollTo?.(0)
285
+ scrollBridge.y = 0
286
+ }
287
+ scrollBridge.scrollLockY = undefined
288
+ scrollBridge.setScrollEnabled?.(true)
289
+ } else {
290
+ scrollBridge.scrollLockY = 0
291
+ scrollBridge.setScrollEnabled?.(false)
292
+ }
293
+ }
294
+ },
295
+ [animationDriver, activePositions]
296
+ )
297
+ )
298
+
299
+ function stopSpring() {
300
+ animatedNumber.stop()
301
+ if (scrollBridge.onFinishAnimate) {
302
+ scrollBridge.onFinishAnimate()
303
+ scrollBridge.onFinishAnimate = undefined
304
+ }
305
+ }
306
+
307
+ const animateTo = useEvent((position: number, animationOverride?: any) => {
308
+ if (frameSize === 0) return
309
+
310
+ let toValue = isHidden || position === -1 ? screenSize : activePositions[position]
311
+
312
+ if (at.current === toValue) return
313
+
314
+ at.current = toValue
315
+ stopSpring()
316
+
317
+ const isOpenAnimation = position !== -1 && !isHidden
318
+
319
+ // clear any pending fallback timer
320
+ if (opacityFallbackTimer.current) {
321
+ clearTimeout(opacityFallbackTimer.current)
322
+ opacityFallbackTimer.current = null
323
+ }
324
+
325
+ const animationCompleteCallback = () => {
326
+ if (opacityFallbackTimer.current) {
327
+ clearTimeout(opacityFallbackTimer.current)
328
+ opacityFallbackTimer.current = null
329
+ }
330
+ if (!isOpenAnimation && !open) {
331
+ setOpacity(0)
332
+ }
333
+ onAnimationComplete?.({ open: isOpenAnimation })
334
+ }
335
+
336
+ // safety fallback: if animation callback never fires, still hide the sheet
337
+ if (!isOpenAnimation) {
338
+ opacityFallbackTimer.current = setTimeout(() => {
339
+ opacityFallbackTimer.current = null
340
+ // check live open state via ref — sheet may have reopened (e.g. adapt handoff)
341
+ if (!openRef.current) {
342
+ setOpacity(0)
343
+ }
344
+ }, 1000)
345
+ }
346
+
347
+ // skip animation when adapting from dialog to sheet
348
+ if (skipAdaptAnimation.current) {
349
+ skipAdaptAnimation.current = false
350
+ animatedNumber.setValue(
351
+ toValue,
352
+ { type: 'timing', duration: 0 },
353
+ animationCompleteCallback
354
+ )
355
+ return
356
+ }
357
+
358
+ animatedNumber.setValue(
359
+ toValue,
360
+ animationOverride || {
361
+ type: 'spring',
362
+ ...transitionConfig,
363
+ },
364
+ animationCompleteCallback
365
+ )
366
+ })
367
+
368
+ useIsomorphicLayoutEffect(() => {
369
+ // we need to do a *three* step process for the css driver
370
+ // first render off screen for ssr safety (hiddenSize)
371
+ // then render to bottom of screen without animation (screenSize)
372
+ // then add the animation as it animates from screenSize to position
373
+
374
+ if (hasntMeasured && screenSize && frameSize) {
375
+ at.current = screenSize
376
+ animatedNumber.setValue(
377
+ screenSize,
378
+ {
379
+ type: 'timing',
380
+ duration: 0,
381
+ },
382
+ () => {
383
+ // imperfect but struggling to render properly here
384
+ setTimeout(() => {
385
+ setDisableAnimation(false)
386
+ }, 10)
387
+ }
388
+ )
389
+ return
390
+ }
391
+
392
+ if (disableAnimation) {
393
+ return
394
+ }
395
+
396
+ if (!frameSize || !screenSize || isHidden || (hasntMeasured && !open)) {
397
+ return
398
+ }
399
+
400
+ // finally, animate
401
+ animateTo(position)
402
+
403
+ // reset scroll bridge
404
+ if (position === -1) {
405
+ scrollBridge.scrollLock = false
406
+ scrollBridge.scrollStartY = -1
407
+ }
408
+
409
+ // set initial isAtTop state when sheet opens
410
+ // position 0 = top snap point, so isAtTop = true
411
+ if (open && position >= 0) {
412
+ const isTopPosition = position === 0
413
+ scrollBridge.isAtTop = isTopPosition
414
+ if (isTopPosition) {
415
+ scrollBridge.scrollLockY = undefined
416
+ scrollBridge.setScrollEnabled?.(true)
417
+ } else {
418
+ scrollBridge.scrollLockY = 0
419
+ scrollBridge.setScrollEnabled?.(false)
420
+ }
421
+ }
422
+ }, [hasntMeasured, disableAnimation, isHidden, frameSize, screenSize, open, position])
423
+
424
+ const disableDrag = props.disableDrag ?? controller?.disableDrag
425
+ const themeName = useThemeName()
426
+ const [blockPan, setBlockPan] = React.useState(false)
427
+
428
+ const panResponder = React.useMemo(() => {
429
+ if (disableDrag) return
430
+ if (!frameSize) return
431
+ if (isShowingInnerSheet) return
432
+
433
+ const minY = positions[0]
434
+ scrollBridge.paneMinY = minY
435
+ let startY = at.current
436
+
437
+ function setPanning(val: boolean) {
438
+ setIsDragging(val)
439
+
440
+ // make unselectable:
441
+ if (process.env.HANZO_GUI_TARGET === 'web') {
442
+ if (!sheetHiddenStyleSheet) {
443
+ sheetHiddenStyleSheet = document.createElement('style')
444
+ if (typeof document.head !== 'undefined') {
445
+ document.head.appendChild(sheetHiddenStyleSheet)
446
+ }
447
+ }
448
+ if (!val) {
449
+ sheetHiddenStyleSheet.innerText = ''
450
+ } else {
451
+ sheetHiddenStyleSheet.innerText =
452
+ ':root * { user-select: none !important; -webkit-user-select: none !important; }'
453
+ }
454
+ }
455
+ }
456
+
457
+ const release = ({ vy }: { dragAt: number; vy: number }) => {
458
+ scrollBridge.setParentDragging(false)
459
+ if (scrollBridge.scrollLock) {
460
+ return
461
+ }
462
+
463
+ isExternalDrag = false
464
+ previouslyScrolling = false
465
+ setPanning(false)
466
+ // use the actual current animated position rather than dragAt + startY.
467
+ // after mid-gesture handoffs (pan→scroll→pan), startY can be stale
468
+ // causing the computed position to be wildly wrong (triggering dismiss).
469
+ const currentPos = at.current
470
+ // vy goes up to about 4 at most (+ is down, - is up)
471
+ const end = currentPos + frameSize * vy * 0.2
472
+
473
+ let closestPoint = 0
474
+ let dist = Number.POSITIVE_INFINITY
475
+
476
+ for (let i = 0; i < positions.length; i++) {
477
+ const position = positions[i]
478
+ const curDist = end > position ? end - position : position - end
479
+ if (curDist < dist) {
480
+ dist = curDist
481
+ closestPoint = i
482
+ }
483
+ }
484
+
485
+ // have to call both because state may not change but need to snap back
486
+ setPosition(closestPoint)
487
+ animateTo(closestPoint)
488
+ }
489
+
490
+ const finish = (_e: GestureResponderEvent, state: PanResponderGestureState) => {
491
+ release({
492
+ vy: state.vy,
493
+ dragAt: state.dy,
494
+ })
495
+ }
496
+
497
+ let previouslyScrolling = false
498
+
499
+ const onMoveShouldSet = (
500
+ e: GestureResponderEvent,
501
+ { dy }: PanResponderGestureState
502
+ ): boolean => {
503
+ function getShouldSet() {
504
+ // if dragging handle always allow:
505
+ if (e.target === providerProps.handleRef.current) {
506
+ return true
507
+ }
508
+
509
+ if (scrollBridge.hasScrollableContent === true) {
510
+ if (scrollBridge.scrollLock) {
511
+ return false
512
+ }
513
+
514
+ const isScrolled = scrollBridge.y !== 0
515
+
516
+ // Update the dragging direction
517
+ const isDraggingUp = dy < 0
518
+
519
+ // we can treat near top instead of exactly to avoid trouble with springs
520
+ const isNearTop = scrollBridge.paneY - 5 <= scrollBridge.paneMinY
521
+ if (isScrolled) {
522
+ previouslyScrolling = true
523
+ return false
524
+ }
525
+ // prevent drag once at top and pulling up
526
+ if (isNearTop) {
527
+ if (hasScrollView.current && isDraggingUp) {
528
+ return false
529
+ }
530
+ }
531
+ }
532
+
533
+ // we could do some detection of other touchables and cancel here..
534
+ return Math.abs(dy) > 10
535
+ }
536
+
537
+ const granted = getShouldSet()
538
+
539
+ if (granted) {
540
+ scrollBridge.setParentDragging(true)
541
+ }
542
+
543
+ return granted
544
+ }
545
+
546
+ const grant = () => {
547
+ setPanning(true)
548
+ stopSpring()
549
+ startY = at.current
550
+ }
551
+
552
+ let isExternalDrag = false
553
+
554
+ scrollBridge.drag = (dy) => {
555
+ if (!isExternalDrag) {
556
+ isExternalDrag = true
557
+ grant()
558
+ }
559
+ const to = dy + startY
560
+ animatedNumber.setValue(resisted(to, minY), { type: 'direct' })
561
+ }
562
+
563
+ scrollBridge.release = release
564
+
565
+ // direct snap to position without release calculation (for handoff cases)
566
+ scrollBridge.snapToPosition = (positionIndex: number) => {
567
+ isExternalDrag = false
568
+ previouslyScrolling = false
569
+ setPanning(false)
570
+ setPosition(positionIndex)
571
+ animateTo(positionIndex)
572
+ }
573
+
574
+ return PanResponder.create({
575
+ onMoveShouldSetPanResponder: onMoveShouldSet,
576
+ onPanResponderGrant: grant,
577
+ onPanResponderMove: (_e, { dy }) => {
578
+ const toFull = dy + startY
579
+ const to = resisted(toFull, minY)
580
+
581
+ // handles the case where you hand off back and forth more than once
582
+ const isAtTop = to <= minY
583
+ if (isAtTop) {
584
+ scrollBridge.setParentDragging(false)
585
+ } else {
586
+ scrollBridge.setParentDragging(true)
587
+ }
588
+
589
+ animatedNumber.setValue(to, { type: 'direct' })
590
+ },
591
+ onPanResponderEnd: finish,
592
+ onPanResponderTerminate: finish,
593
+ onPanResponderRelease: finish,
594
+ })
595
+ }, [disableDrag, isShowingInnerSheet, animateTo, frameSize, positions, setPosition])
596
+
597
+ // animate to keyboard-adjusted position when keyboard state changes
598
+ React.useEffect(() => {
599
+ if (isDragging || isHidden || !open || disableAnimation) return
600
+ if (!frameSize || !screenSize) return
601
+ // use timing animation to match iOS keyboard animation (~250ms)
602
+ animateTo(position, { type: 'timing', duration: 250 })
603
+ }, [isKeyboardVisible, keyboardHeight])
604
+
605
+ // reconcile position after drag ends — if keyboard dismissed during drag
606
+ // (e.g., input blur), activePositions reverted but onEnd used frozen positions
607
+ // for snap index. This effect ensures the sheet animates to the correct
608
+ // non-keyboard-adjusted position for the chosen snap index.
609
+ const wasDragging = React.useRef(false)
610
+ React.useEffect(() => {
611
+ if (isDragging) {
612
+ wasDragging.current = true
613
+ return
614
+ }
615
+ if (!wasDragging.current) return
616
+ wasDragging.current = false
617
+ // drag just ended — reconcile position with latest activePositions
618
+ if (!frameSize || !screenSize || isHidden || !open) return
619
+ animateTo(position)
620
+ }, [isDragging])
621
+
622
+ // dismiss keyboard when sheet closes
623
+ React.useEffect(() => {
624
+ if (!open && isKeyboardVisible) {
625
+ dismissKeyboard()
626
+ }
627
+ }, [open])
628
+
629
+ // gesture handler hook for RNGH-based gesture coordination
630
+ const { panGesture, panGestureRef, gestureHandlerEnabled } = useGestureHandlerPan({
631
+ positions: activePositions,
632
+ frameSize,
633
+ setPosition,
634
+ animateTo,
635
+ stopSpring,
636
+ scrollBridge,
637
+ setIsDragging,
638
+ getCurrentPosition: () => at.current,
639
+ resisted,
640
+ disableDrag,
641
+ isShowingInnerSheet,
642
+ setAnimatedPosition: (val: number) => {
643
+ // directly set the animated value for smooth dragging
644
+ at.current = val
645
+ animatedNumber.setValue(val, { type: 'direct' })
646
+ },
647
+ pauseKeyboardHandler,
648
+ })
649
+
650
+ const handleAnimationViewLayout = useEvent((e: LayoutChangeEvent) => {
651
+ // don't update frameSize during exit animation to prevent position jumps
652
+ if (!open && stableFrameSize.current !== 0) {
653
+ return
654
+ }
655
+
656
+ // avoid bugs where it grows forever for whatever reason
657
+ // For inline mode (non-modal), don't cap at window height - use actual layout
658
+ const layoutHeight = e.nativeEvent?.layout.height
659
+ const next = modal
660
+ ? Math.min(layoutHeight, Dimensions.get(relativeDimensionTo).height)
661
+ : layoutHeight
662
+ if (!next) return
663
+ setFrameSize(next)
664
+ })
665
+
666
+ const handleMaxContentViewLayout = React.useCallback((e: LayoutChangeEvent) => {
667
+ // avoid bugs where it grows forever for whatever reason
668
+ const next = Math.min(
669
+ e.nativeEvent?.layout.height,
670
+ Dimensions.get(relativeDimensionTo).height
671
+ )
672
+ if (!next) return
673
+ setMaxContentSize(next)
674
+ }, [])
675
+
676
+ const animatedStyle = useAnimatedNumberStyle(animatedNumber, (val) => {
677
+ 'worklet'
678
+ const translateY = frameSize === 0 ? hiddenSize : val
679
+
680
+ return {
681
+ transform: [{ translateY }],
682
+ }
683
+ })
684
+
685
+ // we need to set this *after* fully closed to 0, to avoid it overlapping
686
+ // the page when resizing quickly on web for example
687
+ const [opacity, setOpacity] = React.useState(open ? 1 : 0)
688
+ if (open && opacity === 0) {
689
+ setOpacity(1)
690
+ // cancel any pending close fallback — sheet is reopening
691
+ if (opacityFallbackTimer.current) {
692
+ clearTimeout(opacityFallbackTimer.current)
693
+ opacityFallbackTimer.current = null
694
+ }
695
+ }
696
+
697
+ const forcedContentHeight = hasFit
698
+ ? undefined
699
+ : snapPointsMode === 'percent'
700
+ ? // Use dvh for modal (viewport-relative), % for inline (container-relative)
701
+ `${maxSnapPoint}${isWeb ? (modal ? 'dvh' : '%') : '%'}`
702
+ : maxSnapPoint
703
+
704
+ const setHasScrollView = React.useCallback((val: boolean) => {
705
+ hasScrollView.current = val
706
+ }, [])
707
+ // const id = useId()
708
+ // const { AdaptProvider, when, children } = useAdaptParent({
709
+ // scope: `${id}Sheet`,
710
+ // portal: true,
711
+ // })
712
+
713
+ let contents = (
714
+ <LayoutMeasurementController disable={!open}>
715
+ <ParentSheetContext.Provider value={nextParentContext}>
716
+ <SheetProvider {...providerProps} setHasScrollView={setHasScrollView}>
717
+ <GestureSheetProvider
718
+ isDragging={isDragging}
719
+ blockPan={blockPan}
720
+ setBlockPan={setBlockPan}
721
+ panGesture={panGesture}
722
+ panGestureRef={panGestureRef}
723
+ >
724
+ <AnimatePresence custom={{ open }}>
725
+ {shouldHideParentSheet || !open ? null : overlayComponent}
726
+ </AnimatePresence>
727
+
728
+ {snapPointsMode !== 'percent' && (
729
+ <View
730
+ style={{
731
+ opacity: 0,
732
+ position: 'absolute',
733
+ top: 0,
734
+ left: 0,
735
+ right: 0,
736
+ bottom: 0,
737
+ pointerEvents: 'none',
738
+ }}
739
+ onLayout={handleMaxContentViewLayout}
740
+ />
741
+ )}
742
+
743
+ <AnimatedView
744
+ ref={ref}
745
+ onLayout={handleAnimationViewLayout}
746
+ // @ts-ignore for CSS driver this is necessary to attach the transition
747
+ // also motion driver at least though i suspect all drivers?
748
+ transition={isDragging || disableAnimation ? null : transition}
749
+ // @ts-ignore
750
+ disableClassName
751
+ style={[
752
+ {
753
+ position: 'absolute',
754
+ zIndex,
755
+ width: '100%',
756
+ height: forcedContentHeight,
757
+ minHeight: forcedContentHeight,
758
+ opacity: !shouldHideParentSheet ? opacity : 0,
759
+ ...((shouldHideParentSheet || !open) && {
760
+ pointerEvents: 'none',
761
+ }),
762
+ },
763
+ animatedStyle,
764
+ ]}
765
+ >
766
+ {/* wrap children with plain RN View for panResponder - gui views no longer handle responder events on web */}
767
+ {gestureHandlerEnabled && panGesture ? (
768
+ <GestureDetectorWrapper gesture={panGesture} style={{ flex: 1 }}>
769
+ {props.children}
770
+ </GestureDetectorWrapper>
771
+ ) : (
772
+ <View
773
+ {...panResponder?.panHandlers}
774
+ style={{ flex: 1, width: '100%', height: '100%' }}
775
+ >
776
+ {props.children}
777
+ </View>
778
+ )}
779
+ </AnimatedView>
780
+ </GestureSheetProvider>
781
+ </SheetProvider>
782
+ </ParentSheetContext.Provider>
783
+ </LayoutMeasurementController>
784
+ )
785
+
786
+ if (process.env.HANZO_GUI_TARGET === 'native' && needsPortalRepropagation()) {
787
+ // TODO alongside sheet scope="" need to pass scope here
788
+ const adaptContext = useAdaptContext()
789
+ contents = (
790
+ <ProvideAdaptContext {...adaptContext}>
791
+ {/* @ts-ignore */}
792
+ {contents}
793
+ </ProvideAdaptContext>
794
+ )
795
+ }
796
+
797
+ // start mounted so we get an accurate measurement the first time
798
+ const shouldMountChildren = unmountChildrenWhenHidden ? !!opacity : true
799
+
800
+ if (modal) {
801
+ const modalContents = (
802
+ <Portal stackZIndex={zIndex} {...portalProps}>
803
+ {shouldMountChildren && <ContainerComponent>{contents}</ContainerComponent>}
804
+ </Portal>
805
+ )
806
+
807
+ if (isWeb) {
808
+ return modalContents
809
+ }
810
+
811
+ // on native we don't support multiple modals yet... fix for now is to hide outer one
812
+ return (
813
+ <SheetInsideSheetContext.Provider value={onInnerSheet}>
814
+ {modalContents}
815
+ </SheetInsideSheetContext.Provider>
816
+ )
817
+ }
818
+
819
+ return contents
820
+ }
821
+ )
822
+
823
+ function getYPositions(
824
+ mode: SnapPointsMode,
825
+ point: string | number,
826
+ screenSize?: number,
827
+ frameSize?: number
828
+ ) {
829
+ if (!screenSize || !frameSize) {
830
+ return 0
831
+ }
832
+
833
+ if (mode === 'mixed') {
834
+ if (typeof point === 'number') {
835
+ return screenSize - Math.min(screenSize, Math.max(0, point))
836
+ }
837
+ if (point === 'fit') {
838
+ return screenSize - Math.min(screenSize, frameSize)
839
+ }
840
+ if (point.endsWith('%')) {
841
+ const pct = Math.min(100, Math.max(0, Number(point.slice(0, -1)))) / 100
842
+ if (Number.isNaN(pct)) {
843
+ console.warn('Invalid snapPoint percentage string')
844
+ return 0
845
+ }
846
+ return Math.round(screenSize - pct * screenSize)
847
+ }
848
+ console.warn('Invalid snapPoint unknown value')
849
+ return 0
850
+ }
851
+
852
+ if (mode === 'fit') {
853
+ if (point === 0) return screenSize
854
+ return screenSize - Math.min(screenSize, frameSize)
855
+ }
856
+
857
+ if (mode === 'constant' && typeof point === 'number') {
858
+ return screenSize - Math.min(screenSize, Math.max(0, point))
859
+ }
860
+
861
+ const pct = Math.min(100, Math.max(0, Number(point))) / 100
862
+ if (Number.isNaN(pct)) {
863
+ console.warn('Invalid snapPoint percentage')
864
+ return 0
865
+ }
866
+
867
+ return Math.round(screenSize - pct * screenSize)
868
+ }