@tamagui/sheet 2.0.0-rc.9 → 2.1.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 (469) hide show
  1. package/.turbo/turbo-build.log +2 -0
  2. package/controller/index.cjs +2 -1
  3. package/controller/index.js +2 -0
  4. package/controller/index.native.cjs +2 -0
  5. package/controller/index.native.js +2 -0
  6. package/dist/cjs/GestureDetectorWrapper.cjs +27 -21
  7. package/dist/cjs/GestureDetectorWrapper.native.js +33 -28
  8. package/dist/cjs/GestureDetectorWrapper.native.js.map +1 -1
  9. package/dist/cjs/GestureSheetContext.cjs +14 -12
  10. package/dist/cjs/GestureSheetContext.native.js +29 -27
  11. package/dist/cjs/GestureSheetContext.native.js.map +1 -1
  12. package/dist/cjs/Sheet.cjs +88 -86
  13. package/dist/cjs/Sheet.native.js +88 -86
  14. package/dist/cjs/Sheet.native.js.map +1 -1
  15. package/dist/cjs/SheetContext.cjs +16 -14
  16. package/dist/cjs/SheetContext.native.js +16 -14
  17. package/dist/cjs/SheetContext.native.js.map +1 -1
  18. package/dist/cjs/SheetController.cjs +40 -32
  19. package/dist/cjs/SheetController.native.js +62 -54
  20. package/dist/cjs/SheetController.native.js.map +1 -1
  21. package/dist/cjs/SheetImplementationCustom.cjs +617 -429
  22. package/dist/cjs/SheetImplementationCustom.native.js +647 -474
  23. package/dist/cjs/SheetImplementationCustom.native.js.map +1 -1
  24. package/dist/cjs/SheetScrollView.cjs +198 -135
  25. package/dist/cjs/SheetScrollView.native.js +216 -163
  26. package/dist/cjs/SheetScrollView.native.js.map +1 -1
  27. package/dist/cjs/constants.cjs +16 -14
  28. package/dist/cjs/constants.native.js +16 -14
  29. package/dist/cjs/constants.native.js.map +1 -1
  30. package/dist/cjs/contexts.cjs +27 -25
  31. package/dist/cjs/contexts.native.js +29 -27
  32. package/dist/cjs/contexts.native.js.map +1 -1
  33. package/dist/cjs/controller.cjs +14 -12
  34. package/dist/cjs/controller.native.js +14 -12
  35. package/dist/cjs/controller.native.js.map +1 -1
  36. package/dist/cjs/createSheet.cjs +159 -160
  37. package/dist/cjs/createSheet.native.js +172 -180
  38. package/dist/cjs/createSheet.native.js.map +1 -1
  39. package/dist/cjs/gestureState.cjs +12 -10
  40. package/dist/cjs/gestureState.native.js +12 -10
  41. package/dist/cjs/gestureState.native.js.map +1 -1
  42. package/dist/cjs/helpers.cjs +17 -13
  43. package/dist/cjs/helpers.native.js +17 -13
  44. package/dist/cjs/helpers.native.js.map +1 -1
  45. package/dist/cjs/index.cjs +7 -5
  46. package/dist/cjs/index.native.js +7 -5
  47. package/dist/cjs/index.native.js.map +1 -1
  48. package/dist/cjs/keyboardAvoidance.cjs +42 -0
  49. package/dist/cjs/keyboardAvoidance.native.js +46 -0
  50. package/dist/cjs/keyboardAvoidance.native.js.map +1 -0
  51. package/dist/cjs/nativeSheet.cjs +68 -55
  52. package/dist/cjs/nativeSheet.native.js +77 -68
  53. package/dist/cjs/nativeSheet.native.js.map +1 -1
  54. package/dist/cjs/setupGestureHandler.cjs +24 -18
  55. package/dist/cjs/setupGestureHandler.native.js +24 -19
  56. package/dist/cjs/setupGestureHandler.native.js.map +1 -1
  57. package/dist/cjs/types.cjs +7 -5
  58. package/dist/cjs/types.native.js +7 -5
  59. package/dist/cjs/types.native.js.map +1 -1
  60. package/dist/cjs/useGestureHandlerPan.cjs +181 -111
  61. package/dist/cjs/useGestureHandlerPan.native.js +183 -115
  62. package/dist/cjs/useGestureHandlerPan.native.js.map +1 -1
  63. package/dist/cjs/useKeyboardControllerSheet.cjs +76 -18
  64. package/dist/cjs/useKeyboardControllerSheet.native.js +100 -82
  65. package/dist/cjs/useKeyboardControllerSheet.native.js.map +1 -1
  66. package/dist/cjs/useSheet.cjs +12 -10
  67. package/dist/cjs/useSheet.native.js +16 -14
  68. package/dist/cjs/useSheet.native.js.map +1 -1
  69. package/dist/cjs/useSheetController.cjs +35 -33
  70. package/dist/cjs/useSheetController.native.js +37 -35
  71. package/dist/cjs/useSheetController.native.js.map +1 -1
  72. package/dist/cjs/useSheetOffscreenSize.cjs +35 -23
  73. package/dist/cjs/useSheetOffscreenSize.native.js +36 -27
  74. package/dist/cjs/useSheetOffscreenSize.native.js.map +1 -1
  75. package/dist/cjs/useSheetOpenState.cjs +28 -25
  76. package/dist/cjs/useSheetOpenState.native.js +39 -37
  77. package/dist/cjs/useSheetOpenState.native.js.map +1 -1
  78. package/dist/cjs/useSheetProviderProps.cjs +129 -81
  79. package/dist/cjs/useSheetProviderProps.native.js +165 -122
  80. package/dist/cjs/useSheetProviderProps.native.js.map +1 -1
  81. package/dist/cjs/useSheetScrollViewGestures.cjs +129 -81
  82. package/dist/cjs/useSheetScrollViewGestures.native.js +128 -79
  83. package/dist/cjs/useSheetScrollViewGestures.native.js.map +1 -1
  84. package/dist/cjs/webViewport.cjs +50 -0
  85. package/dist/cjs/webViewport.native.js +54 -0
  86. package/dist/cjs/webViewport.native.js.map +1 -0
  87. package/dist/esm/GestureDetectorWrapper.mjs +12 -8
  88. package/dist/esm/GestureDetectorWrapper.mjs.map +1 -1
  89. package/dist/esm/GestureDetectorWrapper.native.js +18 -15
  90. package/dist/esm/GestureDetectorWrapper.native.js.map +1 -1
  91. package/dist/esm/GestureSheetContext.native.js +14 -14
  92. package/dist/esm/GestureSheetContext.native.js.map +1 -1
  93. package/dist/esm/Sheet.mjs +70 -70
  94. package/dist/esm/Sheet.mjs.map +1 -1
  95. package/dist/esm/Sheet.native.js +70 -70
  96. package/dist/esm/Sheet.native.js.map +1 -1
  97. package/dist/esm/SheetContext.mjs +2 -2
  98. package/dist/esm/SheetContext.mjs.map +1 -1
  99. package/dist/esm/SheetContext.native.js +2 -2
  100. package/dist/esm/SheetContext.native.js.map +1 -1
  101. package/dist/esm/SheetController.mjs +12 -6
  102. package/dist/esm/SheetController.mjs.map +1 -1
  103. package/dist/esm/SheetController.native.js +18 -12
  104. package/dist/esm/SheetController.native.js.map +1 -1
  105. package/dist/esm/SheetImplementationCustom.mjs +575 -389
  106. package/dist/esm/SheetImplementationCustom.mjs.map +1 -1
  107. package/dist/esm/SheetImplementationCustom.native.js +601 -434
  108. package/dist/esm/SheetImplementationCustom.native.js.map +1 -1
  109. package/dist/esm/SheetScrollView.mjs +165 -104
  110. package/dist/esm/SheetScrollView.mjs.map +1 -1
  111. package/dist/esm/SheetScrollView.native.js +184 -133
  112. package/dist/esm/SheetScrollView.native.js.map +1 -1
  113. package/dist/esm/constants.mjs +4 -4
  114. package/dist/esm/constants.mjs.map +1 -1
  115. package/dist/esm/constants.native.js +4 -4
  116. package/dist/esm/constants.native.js.map +1 -1
  117. package/dist/esm/contexts.mjs +3 -3
  118. package/dist/esm/contexts.mjs.map +1 -1
  119. package/dist/esm/contexts.native.js +3 -3
  120. package/dist/esm/contexts.native.js.map +1 -1
  121. package/dist/esm/createSheet.mjs +130 -133
  122. package/dist/esm/createSheet.mjs.map +1 -1
  123. package/dist/esm/createSheet.native.js +142 -152
  124. package/dist/esm/createSheet.native.js.map +1 -1
  125. package/dist/esm/helpers.mjs +5 -3
  126. package/dist/esm/helpers.mjs.map +1 -1
  127. package/dist/esm/helpers.native.js +5 -3
  128. package/dist/esm/helpers.native.js.map +1 -1
  129. package/dist/esm/index.js +11 -11
  130. package/dist/esm/index.js.map +1 -6
  131. package/dist/esm/keyboardAvoidance.mjs +17 -0
  132. package/dist/esm/keyboardAvoidance.mjs.map +1 -0
  133. package/dist/esm/keyboardAvoidance.native.js +18 -0
  134. package/dist/esm/keyboardAvoidance.native.js.map +1 -0
  135. package/dist/esm/nativeSheet.mjs +49 -38
  136. package/dist/esm/nativeSheet.mjs.map +1 -1
  137. package/dist/esm/nativeSheet.native.js +55 -48
  138. package/dist/esm/nativeSheet.native.js.map +1 -1
  139. package/dist/esm/setupGestureHandler.mjs +12 -8
  140. package/dist/esm/setupGestureHandler.mjs.map +1 -1
  141. package/dist/esm/setupGestureHandler.native.js +12 -9
  142. package/dist/esm/setupGestureHandler.native.js.map +1 -1
  143. package/dist/esm/useGestureHandlerPan.mjs +167 -99
  144. package/dist/esm/useGestureHandlerPan.mjs.map +1 -1
  145. package/dist/esm/useGestureHandlerPan.native.js +168 -102
  146. package/dist/esm/useGestureHandlerPan.native.js.map +1 -1
  147. package/dist/esm/useKeyboardControllerSheet.mjs +65 -9
  148. package/dist/esm/useKeyboardControllerSheet.mjs.map +1 -1
  149. package/dist/esm/useKeyboardControllerSheet.native.js +85 -69
  150. package/dist/esm/useKeyboardControllerSheet.native.js.map +1 -1
  151. package/dist/esm/useSheetController.mjs +11 -11
  152. package/dist/esm/useSheetController.mjs.map +1 -1
  153. package/dist/esm/useSheetController.native.js +11 -11
  154. package/dist/esm/useSheetController.native.js.map +1 -1
  155. package/dist/esm/useSheetOffscreenSize.mjs +23 -13
  156. package/dist/esm/useSheetOffscreenSize.mjs.map +1 -1
  157. package/dist/esm/useSheetOffscreenSize.native.js +24 -17
  158. package/dist/esm/useSheetOffscreenSize.native.js.map +1 -1
  159. package/dist/esm/useSheetOpenState.mjs +14 -13
  160. package/dist/esm/useSheetOpenState.mjs.map +1 -1
  161. package/dist/esm/useSheetOpenState.native.js +17 -17
  162. package/dist/esm/useSheetOpenState.native.js.map +1 -1
  163. package/dist/esm/useSheetProviderProps.mjs +101 -55
  164. package/dist/esm/useSheetProviderProps.mjs.map +1 -1
  165. package/dist/esm/useSheetProviderProps.native.js +137 -96
  166. package/dist/esm/useSheetProviderProps.native.js.map +1 -1
  167. package/dist/esm/useSheetScrollViewGestures.mjs +117 -71
  168. package/dist/esm/useSheetScrollViewGestures.mjs.map +1 -1
  169. package/dist/esm/useSheetScrollViewGestures.native.js +116 -69
  170. package/dist/esm/useSheetScrollViewGestures.native.js.map +1 -1
  171. package/dist/esm/webViewport.mjs +22 -0
  172. package/dist/esm/webViewport.mjs.map +1 -0
  173. package/dist/esm/webViewport.native.js +23 -0
  174. package/dist/esm/webViewport.native.js.map +1 -0
  175. package/dist/jsx/GestureDetectorWrapper.mjs +12 -8
  176. package/dist/jsx/GestureDetectorWrapper.mjs.map +1 -1
  177. package/dist/jsx/GestureDetectorWrapper.native.js +33 -28
  178. package/dist/jsx/GestureDetectorWrapper.native.js.map +1 -1
  179. package/dist/jsx/GestureSheetContext.native.js +29 -27
  180. package/dist/jsx/GestureSheetContext.native.js.map +1 -1
  181. package/dist/jsx/Sheet.mjs +70 -70
  182. package/dist/jsx/Sheet.mjs.map +1 -1
  183. package/dist/jsx/Sheet.native.js +88 -86
  184. package/dist/jsx/Sheet.native.js.map +1 -1
  185. package/dist/jsx/SheetContext.mjs +2 -2
  186. package/dist/jsx/SheetContext.mjs.map +1 -1
  187. package/dist/jsx/SheetContext.native.js +16 -14
  188. package/dist/jsx/SheetContext.native.js.map +1 -1
  189. package/dist/jsx/SheetController.mjs +12 -6
  190. package/dist/jsx/SheetController.mjs.map +1 -1
  191. package/dist/jsx/SheetController.native.js +62 -54
  192. package/dist/jsx/SheetController.native.js.map +1 -1
  193. package/dist/jsx/SheetImplementationCustom.mjs +575 -389
  194. package/dist/jsx/SheetImplementationCustom.mjs.map +1 -1
  195. package/dist/jsx/SheetImplementationCustom.native.js +647 -474
  196. package/dist/jsx/SheetImplementationCustom.native.js.map +1 -1
  197. package/dist/jsx/SheetScrollView.mjs +165 -104
  198. package/dist/jsx/SheetScrollView.mjs.map +1 -1
  199. package/dist/jsx/SheetScrollView.native.js +216 -163
  200. package/dist/jsx/SheetScrollView.native.js.map +1 -1
  201. package/dist/jsx/constants.mjs +4 -4
  202. package/dist/jsx/constants.mjs.map +1 -1
  203. package/dist/jsx/constants.native.js +16 -14
  204. package/dist/jsx/constants.native.js.map +1 -1
  205. package/dist/jsx/contexts.mjs +3 -3
  206. package/dist/jsx/contexts.mjs.map +1 -1
  207. package/dist/jsx/contexts.native.js +29 -27
  208. package/dist/jsx/contexts.native.js.map +1 -1
  209. package/dist/jsx/controller.native.js +14 -12
  210. package/dist/jsx/createSheet.mjs +130 -133
  211. package/dist/jsx/createSheet.mjs.map +1 -1
  212. package/dist/jsx/createSheet.native.js +172 -180
  213. package/dist/jsx/createSheet.native.js.map +1 -1
  214. package/dist/jsx/gestureState.native.js +12 -10
  215. package/dist/jsx/gestureState.native.js.map +1 -1
  216. package/dist/jsx/helpers.mjs +5 -3
  217. package/dist/jsx/helpers.mjs.map +1 -1
  218. package/dist/jsx/helpers.native.js +17 -13
  219. package/dist/jsx/helpers.native.js.map +1 -1
  220. package/dist/jsx/index.js +11 -11
  221. package/dist/jsx/index.js.map +1 -6
  222. package/dist/jsx/index.native.js +7 -5
  223. package/dist/jsx/index.native.js.map +1 -1
  224. package/dist/jsx/keyboardAvoidance.mjs +17 -0
  225. package/dist/jsx/keyboardAvoidance.mjs.map +1 -0
  226. package/dist/jsx/keyboardAvoidance.native.js +46 -0
  227. package/dist/jsx/keyboardAvoidance.native.js.map +1 -0
  228. package/dist/jsx/nativeSheet.mjs +49 -38
  229. package/dist/jsx/nativeSheet.mjs.map +1 -1
  230. package/dist/jsx/nativeSheet.native.js +77 -68
  231. package/dist/jsx/nativeSheet.native.js.map +1 -1
  232. package/dist/jsx/setupGestureHandler.mjs +12 -8
  233. package/dist/jsx/setupGestureHandler.mjs.map +1 -1
  234. package/dist/jsx/setupGestureHandler.native.js +24 -19
  235. package/dist/jsx/setupGestureHandler.native.js.map +1 -1
  236. package/dist/jsx/types.native.js +7 -5
  237. package/dist/jsx/useGestureHandlerPan.mjs +167 -99
  238. package/dist/jsx/useGestureHandlerPan.mjs.map +1 -1
  239. package/dist/jsx/useGestureHandlerPan.native.js +183 -115
  240. package/dist/jsx/useGestureHandlerPan.native.js.map +1 -1
  241. package/dist/jsx/useKeyboardControllerSheet.mjs +65 -9
  242. package/dist/jsx/useKeyboardControllerSheet.mjs.map +1 -1
  243. package/dist/jsx/useKeyboardControllerSheet.native.js +100 -82
  244. package/dist/jsx/useKeyboardControllerSheet.native.js.map +1 -1
  245. package/dist/jsx/useSheet.native.js +16 -14
  246. package/dist/jsx/useSheetController.mjs +11 -11
  247. package/dist/jsx/useSheetController.mjs.map +1 -1
  248. package/dist/jsx/useSheetController.native.js +37 -35
  249. package/dist/jsx/useSheetController.native.js.map +1 -1
  250. package/dist/jsx/useSheetOffscreenSize.mjs +23 -13
  251. package/dist/jsx/useSheetOffscreenSize.mjs.map +1 -1
  252. package/dist/jsx/useSheetOffscreenSize.native.js +36 -27
  253. package/dist/jsx/useSheetOffscreenSize.native.js.map +1 -1
  254. package/dist/jsx/useSheetOpenState.mjs +14 -13
  255. package/dist/jsx/useSheetOpenState.mjs.map +1 -1
  256. package/dist/jsx/useSheetOpenState.native.js +39 -37
  257. package/dist/jsx/useSheetOpenState.native.js.map +1 -1
  258. package/dist/jsx/useSheetProviderProps.mjs +101 -55
  259. package/dist/jsx/useSheetProviderProps.mjs.map +1 -1
  260. package/dist/jsx/useSheetProviderProps.native.js +165 -122
  261. package/dist/jsx/useSheetProviderProps.native.js.map +1 -1
  262. package/dist/jsx/useSheetScrollViewGestures.mjs +117 -71
  263. package/dist/jsx/useSheetScrollViewGestures.mjs.map +1 -1
  264. package/dist/jsx/useSheetScrollViewGestures.native.js +128 -79
  265. package/dist/jsx/useSheetScrollViewGestures.native.js.map +1 -1
  266. package/dist/jsx/webViewport.mjs +22 -0
  267. package/dist/jsx/webViewport.mjs.map +1 -0
  268. package/dist/jsx/webViewport.native.js +54 -0
  269. package/dist/jsx/webViewport.native.js.map +1 -0
  270. package/next.md +78 -0
  271. package/package.json +29 -39
  272. package/setup-gesture-handler/index.cjs +2 -0
  273. package/setup-gesture-handler/index.js +2 -0
  274. package/setup-gesture-handler/index.native.cjs +2 -0
  275. package/setup-gesture-handler/index.native.js +2 -0
  276. package/src/GestureDetectorWrapper.tsx +0 -3
  277. package/src/SheetController.tsx +4 -1
  278. package/src/SheetImplementationCustom.tsx +414 -84
  279. package/src/SheetScrollView.tsx +74 -9
  280. package/src/keyboardAvoidance.ts +30 -0
  281. package/src/nativeSheet.tsx +9 -1
  282. package/src/types.tsx +16 -1
  283. package/src/useGestureHandlerPan.tsx +5 -15
  284. package/src/useKeyboardControllerSheet.ts +106 -10
  285. package/src/useSheetController.tsx +4 -0
  286. package/src/useSheetProviderProps.tsx +17 -0
  287. package/src/useSheetScrollViewGestures.ts +23 -2
  288. package/src/webViewport.ts +52 -0
  289. package/test/keyboardAvoidance.test.ts +53 -0
  290. package/tsconfig.json +57 -0
  291. package/types/GestureDetectorWrapper.d.ts.map +1 -1
  292. package/types/Sheet.d.ts +3 -0
  293. package/types/Sheet.d.ts.map +1 -1
  294. package/types/SheetContext.d.ts +4 -0
  295. package/types/SheetContext.d.ts.map +1 -1
  296. package/types/SheetController.d.ts +1 -1
  297. package/types/SheetController.d.ts.map +1 -1
  298. package/types/SheetImplementationCustom.d.ts +3 -0
  299. package/types/SheetImplementationCustom.d.ts.map +1 -1
  300. package/types/SheetScrollView.d.ts.map +1 -1
  301. package/types/createSheet.d.ts +3 -0
  302. package/types/createSheet.d.ts.map +1 -1
  303. package/types/keyboardAvoidance.d.ts +8 -0
  304. package/types/keyboardAvoidance.d.ts.map +1 -0
  305. package/types/nativeSheet.d.ts.map +1 -1
  306. package/types/types.d.ts +10 -1
  307. package/types/types.d.ts.map +1 -1
  308. package/types/useGestureHandlerPan.d.ts.map +1 -1
  309. package/types/useKeyboardControllerSheet.d.ts +14 -3
  310. package/types/useKeyboardControllerSheet.d.ts.map +1 -1
  311. package/types/useSheetController.d.ts +3 -0
  312. package/types/useSheetController.d.ts.map +1 -1
  313. package/types/useSheetProviderProps.d.ts +4 -0
  314. package/types/useSheetProviderProps.d.ts.map +1 -1
  315. package/types/useSheetScrollViewGestures.d.ts.map +1 -1
  316. package/types/webViewport.d.ts +30 -0
  317. package/types/webViewport.d.ts.map +1 -0
  318. package/dist/cjs/GestureDetectorWrapper.js +0 -29
  319. package/dist/cjs/GestureDetectorWrapper.js.map +0 -6
  320. package/dist/cjs/GestureSheetContext.js +0 -43
  321. package/dist/cjs/GestureSheetContext.js.map +0 -6
  322. package/dist/cjs/Sheet.js +0 -104
  323. package/dist/cjs/Sheet.js.map +0 -6
  324. package/dist/cjs/SheetContext.js +0 -28
  325. package/dist/cjs/SheetContext.js.map +0 -6
  326. package/dist/cjs/SheetController.js +0 -52
  327. package/dist/cjs/SheetController.js.map +0 -6
  328. package/dist/cjs/SheetImplementationCustom.js +0 -393
  329. package/dist/cjs/SheetImplementationCustom.js.map +0 -6
  330. package/dist/cjs/SheetScrollView.js +0 -137
  331. package/dist/cjs/SheetScrollView.js.map +0 -6
  332. package/dist/cjs/constants.js +0 -24
  333. package/dist/cjs/constants.js.map +0 -6
  334. package/dist/cjs/contexts.js +0 -33
  335. package/dist/cjs/contexts.js.map +0 -6
  336. package/dist/cjs/controller.js +0 -23
  337. package/dist/cjs/controller.js.map +0 -6
  338. package/dist/cjs/createSheet.js +0 -152
  339. package/dist/cjs/createSheet.js.map +0 -6
  340. package/dist/cjs/gestureState.js +0 -34
  341. package/dist/cjs/gestureState.js.map +0 -6
  342. package/dist/cjs/helpers.js +0 -26
  343. package/dist/cjs/helpers.js.map +0 -6
  344. package/dist/cjs/index.js +0 -25
  345. package/dist/cjs/index.js.map +0 -6
  346. package/dist/cjs/nativeSheet.js +0 -56
  347. package/dist/cjs/nativeSheet.js.map +0 -6
  348. package/dist/cjs/setupGestureHandler.js +0 -38
  349. package/dist/cjs/setupGestureHandler.js.map +0 -6
  350. package/dist/cjs/types.js +0 -14
  351. package/dist/cjs/types.js.map +0 -6
  352. package/dist/cjs/useGestureHandlerPan.js +0 -126
  353. package/dist/cjs/useGestureHandlerPan.js.map +0 -6
  354. package/dist/cjs/useKeyboardControllerSheet.js +0 -34
  355. package/dist/cjs/useKeyboardControllerSheet.js.map +0 -6
  356. package/dist/cjs/useSheet.js +0 -22
  357. package/dist/cjs/useSheet.js.map +0 -6
  358. package/dist/cjs/useSheetController.js +0 -39
  359. package/dist/cjs/useSheetController.js.map +0 -6
  360. package/dist/cjs/useSheetOffscreenSize.js +0 -43
  361. package/dist/cjs/useSheetOffscreenSize.js.map +0 -6
  362. package/dist/cjs/useSheetOpenState.js +0 -37
  363. package/dist/cjs/useSheetOpenState.js.map +0 -6
  364. package/dist/cjs/useSheetProviderProps.js +0 -130
  365. package/dist/cjs/useSheetProviderProps.js.map +0 -6
  366. package/dist/cjs/useSheetScrollViewGestures.js +0 -102
  367. package/dist/cjs/useSheetScrollViewGestures.js.map +0 -6
  368. package/dist/esm/GestureDetectorWrapper.js +0 -15
  369. package/dist/esm/GestureDetectorWrapper.js.map +0 -6
  370. package/dist/esm/GestureSheetContext.js +0 -28
  371. package/dist/esm/GestureSheetContext.js.map +0 -6
  372. package/dist/esm/Sheet.js +0 -92
  373. package/dist/esm/Sheet.js.map +0 -6
  374. package/dist/esm/SheetContext.js +0 -13
  375. package/dist/esm/SheetContext.js.map +0 -6
  376. package/dist/esm/SheetController.js +0 -31
  377. package/dist/esm/SheetController.js.map +0 -6
  378. package/dist/esm/SheetImplementationCustom.js +0 -395
  379. package/dist/esm/SheetImplementationCustom.js.map +0 -6
  380. package/dist/esm/SheetScrollView.js +0 -122
  381. package/dist/esm/SheetScrollView.js.map +0 -6
  382. package/dist/esm/constants.js +0 -8
  383. package/dist/esm/constants.js.map +0 -6
  384. package/dist/esm/contexts.js +0 -9
  385. package/dist/esm/contexts.js.map +0 -6
  386. package/dist/esm/controller.js +0 -11
  387. package/dist/esm/controller.js.map +0 -6
  388. package/dist/esm/createSheet.js +0 -153
  389. package/dist/esm/createSheet.js.map +0 -6
  390. package/dist/esm/gestureState.js +0 -18
  391. package/dist/esm/gestureState.js.map +0 -6
  392. package/dist/esm/helpers.js +0 -10
  393. package/dist/esm/helpers.js.map +0 -6
  394. package/dist/esm/nativeSheet.js +0 -46
  395. package/dist/esm/nativeSheet.js.map +0 -6
  396. package/dist/esm/setupGestureHandler.js +0 -22
  397. package/dist/esm/setupGestureHandler.js.map +0 -6
  398. package/dist/esm/types.js +0 -1
  399. package/dist/esm/types.js.map +0 -6
  400. package/dist/esm/useGestureHandlerPan.js +0 -111
  401. package/dist/esm/useGestureHandlerPan.js.map +0 -6
  402. package/dist/esm/useKeyboardControllerSheet.js +0 -18
  403. package/dist/esm/useKeyboardControllerSheet.js.map +0 -6
  404. package/dist/esm/useSheet.js +0 -6
  405. package/dist/esm/useSheet.js.map +0 -6
  406. package/dist/esm/useSheetController.js +0 -15
  407. package/dist/esm/useSheetController.js.map +0 -6
  408. package/dist/esm/useSheetOffscreenSize.js +0 -27
  409. package/dist/esm/useSheetOffscreenSize.js.map +0 -6
  410. package/dist/esm/useSheetOpenState.js +0 -22
  411. package/dist/esm/useSheetOpenState.js.map +0 -6
  412. package/dist/esm/useSheetProviderProps.js +0 -109
  413. package/dist/esm/useSheetProviderProps.js.map +0 -6
  414. package/dist/esm/useSheetScrollViewGestures.js +0 -86
  415. package/dist/esm/useSheetScrollViewGestures.js.map +0 -6
  416. package/dist/jsx/GestureDetectorWrapper.js +0 -15
  417. package/dist/jsx/GestureDetectorWrapper.js.map +0 -6
  418. package/dist/jsx/GestureSheetContext.js +0 -28
  419. package/dist/jsx/GestureSheetContext.js.map +0 -6
  420. package/dist/jsx/Sheet.js +0 -92
  421. package/dist/jsx/Sheet.js.map +0 -6
  422. package/dist/jsx/SheetContext.js +0 -13
  423. package/dist/jsx/SheetContext.js.map +0 -6
  424. package/dist/jsx/SheetController.js +0 -31
  425. package/dist/jsx/SheetController.js.map +0 -6
  426. package/dist/jsx/SheetImplementationCustom.js +0 -395
  427. package/dist/jsx/SheetImplementationCustom.js.map +0 -6
  428. package/dist/jsx/SheetScrollView.js +0 -122
  429. package/dist/jsx/SheetScrollView.js.map +0 -6
  430. package/dist/jsx/constants.js +0 -8
  431. package/dist/jsx/constants.js.map +0 -6
  432. package/dist/jsx/contexts.js +0 -9
  433. package/dist/jsx/contexts.js.map +0 -6
  434. package/dist/jsx/controller.js +0 -11
  435. package/dist/jsx/controller.js.map +0 -6
  436. package/dist/jsx/createSheet.js +0 -153
  437. package/dist/jsx/createSheet.js.map +0 -6
  438. package/dist/jsx/gestureState.js +0 -18
  439. package/dist/jsx/gestureState.js.map +0 -6
  440. package/dist/jsx/helpers.js +0 -10
  441. package/dist/jsx/helpers.js.map +0 -6
  442. package/dist/jsx/nativeSheet.js +0 -46
  443. package/dist/jsx/nativeSheet.js.map +0 -6
  444. package/dist/jsx/setupGestureHandler.js +0 -22
  445. package/dist/jsx/setupGestureHandler.js.map +0 -6
  446. package/dist/jsx/types.js +0 -1
  447. package/dist/jsx/types.js.map +0 -6
  448. package/dist/jsx/useGestureHandlerPan.js +0 -111
  449. package/dist/jsx/useGestureHandlerPan.js.map +0 -6
  450. package/dist/jsx/useKeyboardControllerSheet.js +0 -18
  451. package/dist/jsx/useKeyboardControllerSheet.js.map +0 -6
  452. package/dist/jsx/useSheet.js +0 -6
  453. package/dist/jsx/useSheet.js.map +0 -6
  454. package/dist/jsx/useSheetController.js +0 -15
  455. package/dist/jsx/useSheetController.js.map +0 -6
  456. package/dist/jsx/useSheetOffscreenSize.js +0 -27
  457. package/dist/jsx/useSheetOffscreenSize.js.map +0 -6
  458. package/dist/jsx/useSheetOpenState.js +0 -22
  459. package/dist/jsx/useSheetOpenState.js.map +0 -6
  460. package/dist/jsx/useSheetProviderProps.js +0 -109
  461. package/dist/jsx/useSheetProviderProps.js.map +0 -6
  462. package/dist/jsx/useSheetScrollViewGestures.js +0 -86
  463. package/dist/jsx/useSheetScrollViewGestures.js.map +0 -6
  464. package/types/GestureDetectorWrapper.native.d.ts +0 -14
  465. package/types/gestureState.native.d.ts +0 -12
  466. package/types/setupGestureHandler.native.d.ts +0 -41
  467. package/types/useGestureHandlerPan.native.d.ts +0 -33
  468. package/types/useSheetScrollViewGestures.web.d.ts +0 -15
  469. package/types/useSheetScrollViewGestures.web.d.ts.map +0 -1
@@ -10,6 +10,7 @@ import { getGestureHandlerState, isGestureHandlerEnabled } from './gestureState'
10
10
  import { useSheetContext } from './SheetContext'
11
11
  import type { SheetScopedProps } from './types'
12
12
  import { useSheetScrollViewGestures } from './useSheetScrollViewGestures'
13
+ import { getWebKeyboardHeight, MIN_KEYBOARD_HEIGHT } from './webViewport'
13
14
 
14
15
  const SHEET_SCROLL_VIEW_NAME = 'SheetScrollView'
15
16
 
@@ -29,13 +30,66 @@ export const SheetScrollView = React.forwardRef<
29
30
  ) => {
30
31
  const context = useSheetContext(SHEET_SCROLL_VIEW_NAME, __scopeSheet)
31
32
  const gestureContext = useGestureSheetContext()
32
- const { scrollBridge, setHasScrollView } = context
33
+ const { scrollBridge, setHasScrollView, hasFit, screenSize } = context
34
+ const keyboardOccludedHeight = Math.max(0, context.keyboardOccludedHeight || 0)
35
+ // OR a LIVE DOM check: context.isKeyboardVisible (React state) lags the
36
+ // viewport resize, so on the open-transition render this component can re-run
37
+ // with the shrunk consumer maxHeight BEFORE the context flag flips. reading
38
+ // the keyboard height straight from visualViewport closes that race so the
39
+ // height freeze engages on the same render that would otherwise collapse it.
40
+ const isKeyboardVisible =
41
+ context.isKeyboardVisible === true ||
42
+ (isWeb && getWebKeyboardHeight() >= MIN_KEYBOARD_HEIGHT)
33
43
  const [scrollEnabled] = useControllableState({
34
44
  prop: scrollEnabledProp,
35
45
  defaultProp: true,
36
46
  })
37
47
  const scrollRef = React.useRef<RNScrollView | null>(null)
38
48
 
49
+ const [hasScrollableContent, setHasScrollableContent] = useState(true)
50
+ const parentHeight = useRef(0)
51
+ const contentHeight = useRef(0)
52
+ // the sheet's authoritative pre-keyboard frame height (see SheetImpl). a
53
+ // scroll-view-local high-water mark used to live here, but it was unreliable
54
+ // (the ref could read 0 if the view remounted on focus / never laid out while
55
+ // closed), so the height now comes from the sheet, which doesn't remount.
56
+ const frozenFrameHeight = Math.max(0, context.keyboardStableFrameHeight || 0)
57
+
58
+ // with snapPointsMode="fit", Frame is content-sized (flex: 0, flex-basis: auto, height: undefined).
59
+ // a flex: 1 child can't grow inside a content-sized parent, so the ScrollView (and the Frame
60
+ // around it) collapse to 0 height. instead, let the ScrollView size to its content and cap it
61
+ // at the available viewport (screenSize / maxContentSize) so scrolling kicks in for tall content.
62
+ const fitSizingStyle = hasFit
63
+ ? {
64
+ flex: undefined as undefined,
65
+ height: undefined as undefined,
66
+ maxHeight: screenSize || undefined,
67
+ }
68
+ : { flex: 1 }
69
+
70
+ // AUTOFOCUS-ON-OPEN seed (web): the sheet is still reconstructing its
71
+ // pre-keyboard frame baseline and needs THIS scroll view to size to its
72
+ // content so it can measure the true content height. so we apply the stable
73
+ // screen only as a maxHeight cap (UNCLIP from the shrunk consumer maxHeight)
74
+ // and leave height undefined so it stays content-sized.
75
+ const isKeyboardSeeding = context.isKeyboardSeeding === true
76
+
77
+ // when the keyboard is open the sheet stays ANCHORED at the bottom and keeps
78
+ // its full pre-keyboard height — the keyboard overlays its lower part and the
79
+ // keyboardOccludedHeight tail padding (added to the scroll content below) +
80
+ // browser scroll-into-view lift the focused input above the keyboard. so we
81
+ // pin the height to the sheet's authoritative frozenFrameHeight, overriding
82
+ // any consumer maxHeight (on web that's often tied to useWindowDimensions,
83
+ // which SHRINKS when the keyboard opens and would otherwise collapse the
84
+ // sheet). holding the height constant means nothing animates on keyboard
85
+ // open/close — no jump/teleport. applied AFTER {...props} so it wins.
86
+ const keyboardFrozenOverride =
87
+ hasFit && isKeyboardVisible && frozenFrameHeight > 0
88
+ ? isKeyboardSeeding
89
+ ? { maxHeight: frozenFrameHeight }
90
+ : { height: frozenFrameHeight, maxHeight: frozenFrameHeight }
91
+ : null
92
+
39
93
  const panGestureRef = gestureContext?.panGestureRef
40
94
  const { ScrollView: RNGHScrollView } = getGestureHandlerState()
41
95
  const useRNGHScrollView = isGestureHandlerEnabled() && RNGHScrollView && panGestureRef
@@ -73,16 +127,18 @@ export const SheetScrollView = React.forwardRef<
73
127
  }
74
128
  }, [])
75
129
 
76
- const [hasScrollableContent, setHasScrollableContent] = useState(true)
77
- const parentHeight = useRef(0)
78
- const contentHeight = useRef(0)
79
-
80
130
  const updateScrollable = () => {
81
131
  if (parentHeight.current && contentHeight.current) {
82
132
  setHasScrollableContent(contentHeight.current > parentHeight.current)
83
133
  }
84
134
  }
85
135
 
136
+ // track the fit height for the scrollable-content check. the keyboard-freeze
137
+ // height is supplied by the sheet (frozenFrameHeight), not derived here.
138
+ const recordFitHeight = (height: number) => {
139
+ parentHeight.current = height
140
+ }
141
+
86
142
  useEffect(() => {
87
143
  scrollBridge.hasScrollableContent = hasScrollableContent
88
144
  }, [hasScrollableContent])
@@ -108,6 +164,13 @@ export const SheetScrollView = React.forwardRef<
108
164
  }}
109
165
  >
110
166
  {children}
167
+ {keyboardOccludedHeight > 0 && (
168
+ <View
169
+ data-sheet-keyboard-scroll-pad
170
+ height={keyboardOccludedHeight}
171
+ width="100%"
172
+ />
173
+ )}
111
174
  </View>
112
175
  )
113
176
 
@@ -117,12 +180,12 @@ export const SheetScrollView = React.forwardRef<
117
180
  return (
118
181
  <RNGHComponent
119
182
  ref={composeRefs(scrollRef as any, ref)}
120
- style={{ flex: 1 }}
183
+ style={fitSizingStyle}
121
184
  scrollEventThrottle={1}
122
185
  scrollEnabled={scrollEnabled}
123
186
  simultaneousHandlers={[panGestureRef]}
124
187
  onLayout={(e: any) => {
125
- parentHeight.current = Math.ceil(e.nativeEvent.layout.height)
188
+ recordFitHeight(Math.ceil(e.nativeEvent.layout.height))
126
189
  updateScrollable()
127
190
  }}
128
191
  onScroll={(e: any) => {
@@ -160,6 +223,7 @@ export const SheetScrollView = React.forwardRef<
160
223
  keyboardShouldPersistTaps="always"
161
224
  keyboardDismissMode="none"
162
225
  {...props}
226
+ {...keyboardFrozenOverride}
163
227
  >
164
228
  {contentWrapper}
165
229
  </RNGHComponent>
@@ -170,11 +234,11 @@ export const SheetScrollView = React.forwardRef<
170
234
  return (
171
235
  <ScrollView
172
236
  onLayout={(e) => {
173
- parentHeight.current = Math.ceil(e.nativeEvent.layout.height)
237
+ recordFitHeight(Math.ceil(e.nativeEvent.layout.height))
174
238
  updateScrollable()
175
239
  }}
176
240
  ref={composeRefs(scrollRef as any, ref)}
177
- flex={1}
241
+ {...fitSizingStyle}
178
242
  scrollEventThrottle={1}
179
243
  className="_ovs-contain"
180
244
  scrollEnabled={scrollEnabled}
@@ -187,6 +251,7 @@ export const SheetScrollView = React.forwardRef<
187
251
  contentContainerStyle={{ minHeight: '100%' }}
188
252
  {...gestureProps}
189
253
  {...props}
254
+ {...keyboardFrozenOverride}
190
255
  >
191
256
  {contentWrapper}
192
257
  </ScrollView>
@@ -0,0 +1,30 @@
1
+ export function getKeyboardOccludedHeight({
2
+ frameSize,
3
+ isKeyboardVisible,
4
+ keyboardHeight,
5
+ screenSize,
6
+ sheetY,
7
+ }: {
8
+ frameSize: number
9
+ isKeyboardVisible: boolean
10
+ keyboardHeight: number
11
+ screenSize: number
12
+ sheetY: number | undefined
13
+ }) {
14
+ if (
15
+ !isKeyboardVisible ||
16
+ keyboardHeight <= 0 ||
17
+ screenSize <= 0 ||
18
+ frameSize <= 0 ||
19
+ sheetY === undefined ||
20
+ sheetY >= screenSize
21
+ ) {
22
+ return 0
23
+ }
24
+
25
+ const keyboardTop = screenSize - keyboardHeight
26
+ const sheetBottom = sheetY + frameSize
27
+ const occludedHeight = Math.ceil(sheetBottom - keyboardTop)
28
+
29
+ return Math.min(frameSize, Math.max(0, occludedHeight))
30
+ }
@@ -59,7 +59,15 @@ export function setupNativeSheet(
59
59
 
60
60
  return (
61
61
  <>
62
- <SheetProvider setHasScrollView={emptyFn} {...providerProps} onlyShowFrame>
62
+ <SheetProvider
63
+ setHasScrollView={emptyFn}
64
+ keyboardOccludedHeight={0}
65
+ isKeyboardVisible={false}
66
+ keyboardStableFrameHeight={0}
67
+ isKeyboardSeeding={false}
68
+ {...providerProps}
69
+ onlyShowFrame
70
+ >
63
71
  <ModalSheetView ref={ref} onModalDidDismiss={() => setOpenInternal(false)}>
64
72
  <ModalSheetViewMainContent>
65
73
  <View style={{ flex: 1 }}>{props.children}</View>
package/src/types.tsx CHANGED
@@ -75,10 +75,16 @@ export type SheetProps = ScopedProps<
75
75
  zIndex?: number
76
76
  portalProps?: PortalProps
77
77
  /**
78
- * Native-only flag that will make the sheet move up when the mobile keyboard opens so the focused input remains visible
78
+ * Makes the sheet move up when the mobile keyboard opens so the focused input remains visible.
79
+ * Works on native (via keyboard events) and on mobile web (via the VisualViewport API).
79
80
  */
80
81
  moveOnKeyboardChange?: boolean
81
82
  containerComponent?: React.ComponentType<any>
83
+
84
+ /**
85
+ * Called when the sheet open/close animation completes.
86
+ */
87
+ onAnimationComplete?: (info: { open: boolean }) => void
82
88
  },
83
89
  'Sheet'
84
90
  >
@@ -126,6 +132,15 @@ export type ScrollBridge = {
126
132
  isAtTop?: boolean
127
133
  // snap sheet to a specific position (for handoff UP)
128
134
  snapToPosition?: (positionIndex: number) => void
135
+ // re-baseline the pan drag origin to the current animated position. the web
136
+ // scroll-view hook calls this on each transition into pan ownership so a
137
+ // scroll→pan handoff resumes from where the sheet is, not a stale origin.
138
+ startPanDrag?: () => void
139
+ // web only: true while a touch is active on the ScrollView node. The web
140
+ // scroll-view gesture hook owns drag detection for those touches (it calls
141
+ // drag/release on this bridge), so the PanResponder must NOT also grant for
142
+ // them — otherwise two systems drive the animated position and it jitters.
143
+ scrollNodeTouched?: boolean
129
144
  }
130
145
 
131
146
  // keyboard controller sheet types
@@ -122,7 +122,6 @@ export function useGestureHandlerPan(config: GesturePanConfig): GesturePanResult
122
122
 
123
123
  // simultaneousHandlers pattern from react-native-actions-sheet
124
124
  // both gestures run simultaneously, we use blockPan to decide who handles
125
- // console.warn('[RNGH-Pan] CREATING gesture, minY:', minY, 'frameSize:', frameSize)
126
125
  const gesture = Gesture.Pan()
127
126
  .withRef(panGestureRef)
128
127
  // NO manualActivation - let both gestures run via simultaneousHandlers
@@ -148,7 +147,6 @@ export function useGestureHandlerPan(config: GesturePanConfig): GesturePanResult
148
147
  const pos = getCurrentPosition()
149
148
  const atTop = pos <= minY + AT_TOP_THRESHOLD
150
149
  const currentScrollY = scrollBridge.y
151
- // console.warn('[RNGH-Pan] onBegin', { pos, minY, atTop, currentScrollY })
152
150
  gs.startY = pos
153
151
  gs.lastPanTranslationY = 0
154
152
  gs.accumulatedOffset = 0
@@ -171,7 +169,6 @@ export function useGestureHandlerPan(config: GesturePanConfig): GesturePanResult
171
169
  gs.panStarted = true
172
170
  setIsDragging(true)
173
171
 
174
- // console.warn('[RNGH-Pan] onStart', { startY: gs.startY, minY })
175
172
  scrollBridge.initialPosition = gs.startY
176
173
  onStart()
177
174
  })
@@ -195,8 +192,6 @@ export function useGestureHandlerPan(config: GesturePanConfig): GesturePanResult
195
192
  const isCurrentlyAtTop = currentPos <= minY + AT_TOP_THRESHOLD
196
193
  const nodeIsScrolling = scrollY > 0
197
194
 
198
- // console.warn('[RNGH-Pan] onChange', { translationY: translationY.toFixed(1), deltaY: deltaY.toFixed(1), currentPos: currentPos.toFixed(1), minY, isCurrentlyAtTop, isSwipingDown, scrollY, scrollEngaged: gs.scrollEngaged })
199
-
200
195
  // decision matrix (from react-native-actions-sheet pattern)
201
196
  // each frame, decide who handles the movement based on current state
202
197
  //
@@ -229,7 +224,6 @@ export function useGestureHandlerPan(config: GesturePanConfig): GesturePanResult
229
224
  } else if (gs.scrollEngaged && hasScrollableContent) {
230
225
  // scroll WAS > 0 but now is 0 -> handoff from scroll to pan
231
226
  // pan takes over to drag sheet down
232
- // console.warn('[RNGH-Pan] *** HANDOFF FROM SCROLL TO PAN ***')
233
227
  panHandles = true
234
228
  } else {
235
229
  // scroll never engaged OR content not scrollable, just drag sheet down
@@ -249,13 +243,13 @@ export function useGestureHandlerPan(config: GesturePanConfig): GesturePanResult
249
243
  }
250
244
  }
251
245
 
252
- // console.warn('[RNGH-Pan] decision', { panHandles, isCurrentlyAtTop, isSwipingDown, nodeIsScrolling, scrollEngaged: gs.scrollEngaged, hasScrollableContent, currentPos: currentPos.toFixed(1), minY })
253
-
254
246
  if (panHandles) {
255
247
  // pan handles - disable scroll and move sheet
256
- // when not at top: lock scroll to 0 (sheet is being dragged)
257
- // when at top: lock at current position (handoff from scroll to pan)
258
- const lockTo = isCurrentlyAtTop ? undefined : 0
248
+ // when swiping down at top after scroll was engaged: lock at current scroll position
249
+ // (handoff from scroll to pan — preserve scroll offset)
250
+ // otherwise: always lock scroll to 0 (prevents scroll from firing during sheet drag)
251
+ const lockTo =
252
+ isCurrentlyAtTop && isSwipingDown && gs.scrollEngaged ? undefined : 0
259
253
  scrollBridge.setScrollEnabled?.(false, lockTo)
260
254
 
261
255
  // accumulate the delta for position calculation
@@ -276,8 +270,6 @@ export function useGestureHandlerPan(config: GesturePanConfig): GesturePanResult
276
270
  const { velocityY } = event
277
271
  const currentPos = gs.startY + gs.accumulatedOffset
278
272
 
279
- // console.warn('[RNGH-Pan] onEnd', { velocityY, currentPos, accumulatedOffset: gs.accumulatedOffset, scrollY: scrollBridge.y })
280
-
281
273
  // clear scroll lock
282
274
  scrollBridge.scrollLockY = undefined
283
275
 
@@ -315,7 +307,6 @@ export function useGestureHandlerPan(config: GesturePanConfig): GesturePanResult
315
307
  onEnd(closestPoint)
316
308
  })
317
309
  .onFinalize(() => {
318
- // console.warn('[RNGH-Pan] onFinalize', { panStarted: gs.panStarted })
319
310
  // clear scroll lock on finalize too (safety)
320
311
  scrollBridge.scrollLockY = undefined
321
312
  if (gs.panStarted) {
@@ -334,7 +325,6 @@ export function useGestureHandlerPan(config: GesturePanConfig): GesturePanResult
334
325
  // if we have a scroll gesture ref, make pan simultaneous with it
335
326
  // this allows both gestures to run and we decide in onChange who handles it
336
327
  if (scrollGestureRef?.current) {
337
- // console.warn('[RNGH-Pan] adding simultaneousWithExternalGesture for scroll')
338
328
  return gesture.simultaneousWithExternalGesture(scrollGestureRef.current)
339
329
  }
340
330
 
@@ -1,26 +1,122 @@
1
1
  /**
2
- * Web stub for keyboard controller sheet hook.
3
- * Returns no-op values since keyboard-controller is native-only.
2
+ * Web implementation of the keyboard controller sheet hook.
3
+ *
4
+ * Mobile browsers don't expose a keyboard API, but they do resize the
5
+ * VisualViewport when the soft keyboard opens. We derive the keyboard height as
6
+ * `getStableLayoutViewportHeight() - visualViewport.height` (see webViewport —
7
+ * the stable baseline is document.documentElement.clientHeight, NOT innerHeight,
8
+ * which itself shrinks with the keyboard on real iOS Safari) and feed it into the
9
+ * keyboardOccludedHeight scroll padding in SheetImplementationCustom.
10
+ *
11
+ * Without this, a bottom sheet on mobile web stays pinned behind the keyboard:
12
+ * react-native-web's Dimensions tracks the (shrinking) VisualViewport, so any
13
+ * content sized off window dimensions collapses while the sheet's bottom stays
14
+ * occluded. See SheetImplementationCustom's activePositions / keyboardOccludedHeight.
4
15
  */
5
16
 
6
- import { useRef } from 'react'
17
+ import { useCallback, useEffect, useRef, useState } from 'react'
18
+ import { isWeb } from '@tamagui/constants'
7
19
  import type {
8
20
  KeyboardControllerSheetOptions,
9
21
  KeyboardControllerSheetResult,
10
22
  } from './types'
11
-
12
- const noop = () => {}
23
+ import {
24
+ getWebKeyboardHeight,
25
+ isEditableElement,
26
+ MIN_KEYBOARD_HEIGHT,
27
+ } from './webViewport'
13
28
 
14
29
  export function useKeyboardControllerSheet(
15
- _options: KeyboardControllerSheetOptions
30
+ options: KeyboardControllerSheetOptions
16
31
  ): KeyboardControllerSheetResult {
32
+ const { enabled } = options
33
+
34
+ const [keyboardHeight, setKeyboardHeight] = useState(0)
35
+ const [isKeyboardVisible, setIsKeyboardVisible] = useState(false)
36
+
37
+ // action-sheet pattern: pause keyboard hide events during drag so the sheet
38
+ // position doesn't revert mid-gesture when a TextInput blurs.
17
39
  const pauseKeyboardHandler = useRef(false)
40
+ const pendingHide = useRef(false)
41
+ // live mirror of isKeyboardVisible so the listener can read it without
42
+ // re-subscribing on every toggle.
43
+ const isVisibleRef = useRef(false)
44
+ isVisibleRef.current = isKeyboardVisible
45
+
46
+ const dismissKeyboard = useCallback(() => {
47
+ if (typeof document === 'undefined') return
48
+ const active = document.activeElement as HTMLElement | null
49
+ if (isEditableElement(active)) {
50
+ active?.blur?.()
51
+ }
52
+ }, [])
53
+
54
+ const flushPendingHide = useCallback(() => {
55
+ if (pendingHide.current) {
56
+ pendingHide.current = false
57
+ setIsKeyboardVisible(false)
58
+ setKeyboardHeight(0)
59
+ }
60
+ }, [])
61
+
62
+ useEffect(() => {
63
+ if (!isWeb || !enabled) return
64
+ if (typeof window === 'undefined') return
65
+ const vv = window.visualViewport
66
+ if (!vv) return
67
+
68
+ const update = () => {
69
+ const height = getWebKeyboardHeight()
70
+ const tall = height >= MIN_KEYBOARD_HEIGHT
71
+ // require an editable element focused to *show* — this rules out URL-bar
72
+ // collapse and other viewport changes that aren't a keyboard. but stay
73
+ // visible while the viewport remains shrunk even if focus momentarily
74
+ // moves to a non-editable element (e.g. tapping between two inputs fires
75
+ // focusout→focusin), so the sheet doesn't flicker mid-transition.
76
+ const editableFocused = isEditableElement(document.activeElement)
77
+ const visible = tall && (editableFocused || isVisibleRef.current)
78
+
79
+ if (!visible) {
80
+ // suppress hide during an active drag so positions stay frozen; the
81
+ // drag-end flush reconciles the real state.
82
+ if (pauseKeyboardHandler.current && isVisibleRef.current) {
83
+ pendingHide.current = true
84
+ return
85
+ }
86
+ setIsKeyboardVisible(false)
87
+ setKeyboardHeight(0)
88
+ return
89
+ }
90
+
91
+ pendingHide.current = false
92
+ setIsKeyboardVisible(true)
93
+ setKeyboardHeight((prev) => (prev === height ? prev : height))
94
+ }
95
+
96
+ // only react to resize (keyboard height changes). we intentionally do NOT
97
+ // listen to visualViewport 'scroll' — that fires continuously while the
98
+ // sheet content scrolls and would re-derive the keyboard height from a
99
+ // shifting viewport, making the sheet jump.
100
+ vv.addEventListener('resize', update)
101
+ // focus changes flip editable state without necessarily resizing the viewport
102
+ window.addEventListener('focusin', update)
103
+ window.addEventListener('focusout', update)
104
+
105
+ update()
106
+
107
+ return () => {
108
+ vv.removeEventListener('resize', update)
109
+ window.removeEventListener('focusin', update)
110
+ window.removeEventListener('focusout', update)
111
+ }
112
+ }, [enabled])
113
+
18
114
  return {
19
115
  keyboardControllerEnabled: false,
20
- keyboardHeight: 0,
21
- isKeyboardVisible: false,
22
- dismissKeyboard: noop,
116
+ keyboardHeight,
117
+ isKeyboardVisible,
118
+ dismissKeyboard,
23
119
  pauseKeyboardHandler,
24
- flushPendingHide: noop,
120
+ flushPendingHide,
25
121
  }
26
122
  }
@@ -22,6 +22,10 @@ export type SheetControllerContextValue = {
22
22
  // hide without "closing" to prevent re-animation when shown again
23
23
  hidden?: boolean
24
24
  onOpenChange?: React.Dispatch<React.SetStateAction<boolean>> | ((val: boolean) => void)
25
+ // fired by the sheet after its open/close animation finishes. used by
26
+ // Dialog adapt to know when it's safe to tear down adapted children
27
+ // without cutting off the slide-out mid-animation.
28
+ onAnimationComplete?: (state: { open: boolean }) => void
25
29
  // when true, the sheet should skip its open animation (used for adapt handoff)
26
30
  skipNextAnimation?: boolean
27
31
  }
@@ -8,6 +8,23 @@ import type { ScrollBridge, SheetProps } from './types'
8
8
  import type { SheetOpenState } from './useSheetOpenState'
9
9
 
10
10
  export type SheetContextValue = ReturnType<typeof useSheetProviderProps> & {
11
+ keyboardOccludedHeight: number
12
+ // whether the soft keyboard is currently open. distinct from
13
+ // keyboardOccludedHeight (which is 0 once the sheet fits above the keyboard):
14
+ // the fit-mode height freeze must persist for the whole time the keyboard is
15
+ // open, not just while occluded, or it releases and the sheet collapses.
16
+ isKeyboardVisible: boolean
17
+ // the sheet's authoritative pre-keyboard frame height (web). SheetScrollView
18
+ // pins its height to this while the keyboard is open so the frame stays its
19
+ // full size (anchored to the screen bottom) instead of collapsing to a
20
+ // consumer maxHeight that shrank with the viewport. 0 when not applicable.
21
+ keyboardStableFrameHeight: number
22
+ // AUTOFOCUS-ON-OPEN seed phase (web). while reconstructing the pre-keyboard
23
+ // baseline, SheetScrollView must UNCLIP (apply keyboardStableFrameHeight as
24
+ // maxHeight only, not a fixed height) so it sizes to its content and the sheet
25
+ // can measure the true content height. once settled the fixed-height pin
26
+ // applies. false outside the seed window.
27
+ isKeyboardSeeding: boolean
11
28
  setHasScrollView: (val: boolean) => void
12
29
  }
13
30
 
@@ -75,6 +75,10 @@ export function useSheetScrollViewGestures({
75
75
  }
76
76
 
77
77
  scrollBridge.scrollStartY = touch.pageY
78
+ // claim this touch for the scroll-view gesture hook so the PanResponder
79
+ // (which also negotiates this touch via RNW's responder system) defers
80
+ // and doesn't double-drive the sheet position. cleared on touchend.
81
+ scrollBridge.scrollNodeTouched = true
78
82
  }
79
83
 
80
84
  const handleTouchMove = (e: TouchEvent) => {
@@ -115,6 +119,10 @@ export function useSheetScrollViewGestures({
115
119
  if (newOwner === 'pan') {
116
120
  s.panDragOffset = 0
117
121
  s.dys = []
122
+ // re-baseline the pan origin to the sheet's CURRENT position so the
123
+ // offset (reset to 0 here) maps to where it actually is — required for
124
+ // a correct scroll→pan handoff now that the PanResponder defers to us.
125
+ scrollBridge.startPanDrag?.()
118
126
  scrollBridge.setParentDragging(true)
119
127
  disableScroll()
120
128
  } else {
@@ -133,8 +141,13 @@ export function useSheetScrollViewGestures({
133
141
 
134
142
  s.dys.push(dy)
135
143
  if (s.dys.length > 100) s.dys = s.dys.slice(-10)
136
- } else if (s.owner === 'scroll') {
137
- // programmatic scroll for synthetic events
144
+ } else if (s.owner === 'scroll' && !e.isTrusted) {
145
+ // SYNTHETIC events only (tests): dispatched TouchEvents don't trigger the
146
+ // browser's native overflow scroll, so we move scrollTop ourselves. for a
147
+ // REAL touch (e.isTrusted) the browser already scrolls the overflow
148
+ // container natively — doing it again here double-applies the delta and
149
+ // makes scrollTop jitter / snap around. so for real touches we let native
150
+ // scrolling own it and only track the offset via the ScrollView onScroll.
138
151
  const scrollDelta = -dy
139
152
  const maxScrollY = node.scrollHeight - node.clientHeight
140
153
  const newScrollY = Math.max(0, Math.min(maxScrollY, currentScrollY + scrollDelta))
@@ -159,12 +172,20 @@ export function useSheetScrollViewGestures({
159
172
  }
160
173
 
161
174
  scrollBridge.release({ dragAt: s.panDragOffset, vy })
175
+ } else if (s.owner === 'scroll') {
176
+ // gesture ended while scrolling. a pan→scroll handoff only happens once
177
+ // the pane reached the top, so commit the top snap (index 0) and clear
178
+ // the dragging state HERE, on touchend — never mid-gesture (that would
179
+ // fight the live gesture). this replaces the PanResponder's release,
180
+ // which used to fire on touchend before it deferred to this hook.
181
+ scrollBridge.snapToPosition?.(0)
162
182
  }
163
183
 
164
184
  enableScroll()
165
185
  s.owner = 'none'
166
186
  s.panDragOffset = 0
167
187
  s.dys = []
188
+ scrollBridge.scrollNodeTouched = false
168
189
  }
169
190
 
170
191
  node.addEventListener('touchstart', handleTouchStart, {
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Web (mobile-browser) viewport helpers for the Sheet's keyboard handling.
3
+ *
4
+ * On real iOS Safari (verified on-device, iOS 26) the soft keyboard shrinks
5
+ * BOTH `window.visualViewport.height` AND `window.innerHeight` — neither is the
6
+ * stable layout viewport. Measured during a keyboard open: visualViewport
7
+ * 714 -> 404, innerHeight 714 -> 561 (it wobbles), but
8
+ * `document.documentElement.clientHeight` holds rock-steady at 714 the whole
9
+ * time (open, mid-keyboard, and close). So clientHeight IS the stable layout
10
+ * viewport, and we derive everything from it:
11
+ * - soft-keyboard height = clientHeight - visualViewport.height (stays correct
12
+ * even as innerHeight drifts), so the scroll padding clears the input.
13
+ * - the sheet's fit-mode anchor cap (translateY = screenSize - frameSize) reads
14
+ * clientHeight, so it never re-measures against a shrunk value and the frame
15
+ * stays anchored at the bottom.
16
+ */
17
+
18
+ // ignore small viewport changes (URL bar collapse, accessory bars) so they
19
+ // don't read as a full keyboard. a real soft keyboard is well above this.
20
+ export const MIN_KEYBOARD_HEIGHT = 80
21
+
22
+ export function isEditableElement(el: Element | null): boolean {
23
+ if (!el) return false
24
+ const tag = el.tagName
25
+ if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT') return true
26
+ if ((el as HTMLElement).isContentEditable) return true
27
+ return false
28
+ }
29
+
30
+ /**
31
+ * The stable layout-viewport height. document.documentElement.clientHeight is
32
+ * unaffected by the soft keyboard on iOS Safari (unlike innerHeight /
33
+ * visualViewport), so it stays constant while the keyboard animates in/out.
34
+ */
35
+ export function getStableLayoutViewportHeight(): number {
36
+ if (typeof window === 'undefined') return 0
37
+ const ch = typeof document !== 'undefined' ? document.documentElement?.clientHeight : 0
38
+ if (ch && ch > 0) return ch
39
+ // fallback when clientHeight is unavailable (SSR / detached): best effort
40
+ return Math.max(window.innerHeight || 0, window.visualViewport?.height || 0)
41
+ }
42
+
43
+ /**
44
+ * Soft-keyboard height = the occluded region between the (stable) layout
45
+ * viewport bottom and the visual viewport bottom.
46
+ */
47
+ export function getWebKeyboardHeight(): number {
48
+ if (typeof window === 'undefined') return 0
49
+ const vv = window.visualViewport
50
+ if (!vv) return 0
51
+ return Math.max(0, Math.round(getStableLayoutViewportHeight() - vv.height))
52
+ }
@@ -0,0 +1,53 @@
1
+ import { describe, expect, test } from 'vitest'
2
+
3
+ import { getKeyboardOccludedHeight } from '../src/keyboardAvoidance'
4
+
5
+ describe('getKeyboardOccludedHeight', () => {
6
+ const base = {
7
+ frameSize: 700,
8
+ isKeyboardVisible: true,
9
+ keyboardHeight: 300,
10
+ screenSize: 844,
11
+ sheetY: 59,
12
+ }
13
+
14
+ test('returns overflow below the keyboard top after the sheet is clamped', () => {
15
+ expect(getKeyboardOccludedHeight(base)).toBe(215)
16
+ })
17
+
18
+ test('returns zero when the keyboard-adjusted sheet clears the keyboard', () => {
19
+ expect(
20
+ getKeyboardOccludedHeight({
21
+ ...base,
22
+ frameSize: 400,
23
+ sheetY: 144,
24
+ })
25
+ ).toBe(0)
26
+ })
27
+
28
+ test('ignores hidden keyboard and offscreen sheet positions', () => {
29
+ expect(
30
+ getKeyboardOccludedHeight({
31
+ ...base,
32
+ isKeyboardVisible: false,
33
+ })
34
+ ).toBe(0)
35
+ expect(
36
+ getKeyboardOccludedHeight({
37
+ ...base,
38
+ sheetY: base.screenSize,
39
+ })
40
+ ).toBe(0)
41
+ })
42
+
43
+ test('clamps occlusion to the frame height', () => {
44
+ expect(
45
+ getKeyboardOccludedHeight({
46
+ ...base,
47
+ frameSize: 120,
48
+ keyboardHeight: 1000,
49
+ sheetY: 0,
50
+ })
51
+ ).toBe(120)
52
+ })
53
+ })