@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,136 @@
1
+ /**
2
+ * Native implementation of keyboard controller sheet hook.
3
+ *
4
+ * Simplified to just track keyboard state (height, visibility).
5
+ * Position animation is handled by SheetImplementationCustom via
6
+ * keyboard-adjusted positions — matching the react-native-actions-sheet pattern.
7
+ *
8
+ * Uses react-native-keyboard-controller events when available,
9
+ * falls back to basic Keyboard API otherwise.
10
+ */
11
+
12
+ import { useCallback, useEffect, useRef, useState } from 'react'
13
+ import { Keyboard, Platform } from 'react-native'
14
+ import type {
15
+ KeyboardControllerSheetOptions,
16
+ KeyboardControllerSheetResult,
17
+ } from './types'
18
+
19
+ // lazy import state accessors
20
+ let isKeyboardControllerEnabled: () => boolean = () => false
21
+ let getKeyboardControllerState: () => any = () => ({})
22
+
23
+ try {
24
+ const nativeModule = require('@hanzogui/native')
25
+ isKeyboardControllerEnabled = nativeModule.isKeyboardControllerEnabled
26
+ getKeyboardControllerState = nativeModule.getKeyboardControllerState
27
+ } catch {
28
+ // @hanzogui/native not available
29
+ }
30
+
31
+ export function useKeyboardControllerSheet(
32
+ options: KeyboardControllerSheetOptions
33
+ ): KeyboardControllerSheetResult {
34
+ const { enabled } = options
35
+
36
+ const [keyboardHeight, setKeyboardHeight] = useState(0)
37
+ const [isKeyboardVisible, setIsKeyboardVisible] = useState(false)
38
+ const keyboardControllerEnabled = isKeyboardControllerEnabled()
39
+
40
+ // action-sheet pattern: pause keyboard hide events during drag
41
+ // when true, keyboard hide events are ignored so isKeyboardVisible stays true
42
+ // and activePositions don't revert mid-gesture
43
+ const pauseKeyboardHandler = useRef(false)
44
+ // tracks if a keyboard hide event was suppressed while paused
45
+ const pendingHide = useRef(false)
46
+
47
+ // dismiss keyboard helper
48
+ const dismissKeyboard = useCallback(() => {
49
+ Keyboard.dismiss()
50
+ if (keyboardControllerEnabled) {
51
+ try {
52
+ const { KeyboardController } = getKeyboardControllerState()
53
+ KeyboardController?.dismiss?.()
54
+ } catch {
55
+ // ignore errors from keyboard-controller
56
+ }
57
+ }
58
+ }, [keyboardControllerEnabled])
59
+
60
+ // flush any keyboard hide that was suppressed during drag.
61
+ // called when drag ends to reconcile actual keyboard state.
62
+ const flushPendingHide = useCallback(() => {
63
+ if (pendingHide.current) {
64
+ pendingHide.current = false
65
+ setIsKeyboardVisible(false)
66
+ setKeyboardHeight(0)
67
+ }
68
+ }, [])
69
+
70
+ // keyboard-controller event listeners (preferred when available)
71
+ useEffect(() => {
72
+ if (!enabled || !keyboardControllerEnabled) return
73
+
74
+ const { KeyboardEvents } = getKeyboardControllerState()
75
+ if (!KeyboardEvents?.addListener) return
76
+
77
+ const showSub = KeyboardEvents.addListener('keyboardWillShow', (e: any) => {
78
+ const height = e?.height ?? 0
79
+ if (height > 0) {
80
+ setKeyboardHeight(height)
81
+ }
82
+ setIsKeyboardVisible(true)
83
+ })
84
+
85
+ const hideSub = KeyboardEvents.addListener('keyboardWillHide', () => {
86
+ if (pauseKeyboardHandler.current) {
87
+ pendingHide.current = true
88
+ return
89
+ }
90
+ setIsKeyboardVisible(false)
91
+ setKeyboardHeight(0)
92
+ })
93
+
94
+ return () => {
95
+ showSub?.remove?.()
96
+ hideSub?.remove?.()
97
+ }
98
+ }, [enabled, keyboardControllerEnabled])
99
+
100
+ // fallback to basic Keyboard API when keyboard-controller not available
101
+ useEffect(() => {
102
+ if (!enabled) return
103
+ if (keyboardControllerEnabled) return
104
+
105
+ const showEvent = Platform.OS === 'ios' ? 'keyboardWillShow' : 'keyboardDidShow'
106
+ const hideEvent = Platform.OS === 'ios' ? 'keyboardWillHide' : 'keyboardDidHide'
107
+
108
+ const showListener = Keyboard.addListener(showEvent, (e) => {
109
+ setKeyboardHeight(e.endCoordinates.height)
110
+ setIsKeyboardVisible(true)
111
+ })
112
+
113
+ const hideListener = Keyboard.addListener(hideEvent, () => {
114
+ if (pauseKeyboardHandler.current) {
115
+ pendingHide.current = true
116
+ return
117
+ }
118
+ setIsKeyboardVisible(false)
119
+ setKeyboardHeight(0)
120
+ })
121
+
122
+ return () => {
123
+ showListener.remove()
124
+ hideListener.remove()
125
+ }
126
+ }, [enabled, keyboardControllerEnabled])
127
+
128
+ return {
129
+ keyboardControllerEnabled,
130
+ keyboardHeight,
131
+ isKeyboardVisible,
132
+ dismissKeyboard,
133
+ pauseKeyboardHandler,
134
+ flushPendingHide,
135
+ }
136
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Web stub for keyboard controller sheet hook.
3
+ * Returns no-op values since keyboard-controller is native-only.
4
+ */
5
+
6
+ import { useRef } from 'react'
7
+ import type {
8
+ KeyboardControllerSheetOptions,
9
+ KeyboardControllerSheetResult,
10
+ } from './types'
11
+
12
+ const noop = () => {}
13
+
14
+ export function useKeyboardControllerSheet(
15
+ _options: KeyboardControllerSheetOptions
16
+ ): KeyboardControllerSheetResult {
17
+ const pauseKeyboardHandler = useRef(false)
18
+ return {
19
+ keyboardControllerEnabled: false,
20
+ keyboardHeight: 0,
21
+ isKeyboardVisible: false,
22
+ dismissKeyboard: noop,
23
+ pauseKeyboardHandler,
24
+ flushPendingHide: noop,
25
+ }
26
+ }
@@ -0,0 +1,3 @@
1
+ import { useSheetContext } from './SheetContext'
2
+
3
+ export const useSheet = () => useSheetContext('', undefined)
@@ -0,0 +1,27 @@
1
+ import React from 'react'
2
+
3
+ export const useSheetController = () => {
4
+ const controller = React.useContext(SheetControllerContext)
5
+ const isHidden = controller?.hidden
6
+ const isShowingNonSheet = isHidden && controller?.open
7
+ return {
8
+ controller,
9
+ isHidden,
10
+ isShowingNonSheet,
11
+ disableDrag: controller?.disableDrag,
12
+ }
13
+ }
14
+
15
+ export const SheetControllerContext =
16
+ React.createContext<SheetControllerContextValue | null>(null)
17
+
18
+ export type SheetControllerContextValue = {
19
+ id?: string
20
+ disableDrag?: boolean
21
+ open?: boolean
22
+ // hide without "closing" to prevent re-animation when shown again
23
+ hidden?: boolean
24
+ onOpenChange?: React.Dispatch<React.SetStateAction<boolean>> | ((val: boolean) => void)
25
+ // when true, the sheet should skip its open animation (used for adapt handoff)
26
+ skipNextAnimation?: boolean
27
+ }
@@ -0,0 +1,49 @@
1
+ import type { SheetContextValue } from './useSheetProviderProps'
2
+
3
+ export const useSheetOffscreenSize = ({
4
+ snapPoints,
5
+ position,
6
+ screenSize,
7
+ frameSize,
8
+ snapPointsMode,
9
+ }: SheetContextValue) => {
10
+ if (snapPointsMode === 'fit') {
11
+ return 0
12
+ }
13
+
14
+ if (snapPointsMode === 'constant') {
15
+ const maxSize = Number(snapPoints[0])
16
+ const currentSize = Number(snapPoints[position] ?? 0)
17
+ const offscreenSize = maxSize - currentSize
18
+ return offscreenSize
19
+ }
20
+
21
+ if (snapPointsMode === 'percent') {
22
+ const maxPercentOpened = Number(snapPoints[0]) / 100
23
+ const percentOpened = Number(snapPoints[position] ?? 0) / 100
24
+ const percentHidden = maxPercentOpened - percentOpened
25
+ const offscreenSize = percentHidden * screenSize
26
+ return offscreenSize
27
+ }
28
+
29
+ // mixed:
30
+ const maxSnapPoint = snapPoints[0]
31
+ if (maxSnapPoint === 'fit') {
32
+ return 0
33
+ }
34
+
35
+ const maxSize =
36
+ typeof maxSnapPoint === 'string'
37
+ ? (Number(maxSnapPoint.slice(0, -1)) / 100) * screenSize
38
+ : maxSnapPoint
39
+ const currentSnapPoint = snapPoints[position] ?? 0
40
+ const currentSize =
41
+ typeof currentSnapPoint === 'string'
42
+ ? (Number(currentSnapPoint.slice(0, -1)) / 100) * screenSize
43
+ : currentSnapPoint
44
+ const offscreenSize = maxSize - currentSize
45
+ if (Number.isNaN(offscreenSize)) {
46
+ return 0
47
+ }
48
+ return offscreenSize
49
+ }
@@ -0,0 +1,33 @@
1
+ import { useControllableState } from '@hanzogui/use-controllable-state'
2
+
3
+ import type { SheetProps } from './types'
4
+ import { useSheetController } from './useSheetController'
5
+
6
+ export const useSheetOpenState = (props: SheetProps) => {
7
+ const { isHidden, controller } = useSheetController()
8
+
9
+ const onOpenChangeInternal = (val: boolean) => {
10
+ controller?.onOpenChange?.(val)
11
+ props.onOpenChange?.(val)
12
+ }
13
+
14
+ const propVal = props.preferAdaptParentOpenState
15
+ ? (controller?.open ?? props.open)
16
+ : (props.open ?? controller?.open)
17
+
18
+ const [open, setOpen] = useControllableState({
19
+ prop: propVal,
20
+ defaultProp: props.defaultOpen ?? false,
21
+ onChange: onOpenChangeInternal,
22
+ strategy: 'most-recent-wins',
23
+ })
24
+
25
+ return {
26
+ open,
27
+ setOpen,
28
+ isHidden,
29
+ controller,
30
+ }
31
+ }
32
+
33
+ export type SheetOpenState = ReturnType<typeof useSheetOpenState>
@@ -0,0 +1,223 @@
1
+ import React from 'react'
2
+ import type { GuiElement } from '@hanzogui/core'
3
+ import { useConfiguration } from '@hanzogui/core'
4
+ import { useConstant } from '@hanzogui/use-constant'
5
+ import { useControllableState } from '@hanzogui/use-controllable-state'
6
+
7
+ import type { ScrollBridge, SheetProps } from './types'
8
+ import type { SheetOpenState } from './useSheetOpenState'
9
+
10
+ export type SheetContextValue = ReturnType<typeof useSheetProviderProps> & {
11
+ setHasScrollView: (val: boolean) => void
12
+ }
13
+
14
+ export function useSheetProviderProps(
15
+ props: SheetProps,
16
+ state: SheetOpenState,
17
+ options: {
18
+ onOverlayComponent?: (comp: any) => void
19
+ } = {}
20
+ ) {
21
+ const handleRef = React.useRef<GuiElement>(null)
22
+ const contentRef = React.useRef<GuiElement>(null)
23
+ const [frameSize, setFrameSize] = React.useState<number>(0)
24
+ const [maxContentSize, setMaxContentSize] = React.useState<number>(0)
25
+ const snapPointsMode = props.snapPointsMode ?? 'percent'
26
+ const snapPointsProp: (string | number)[] =
27
+ props.snapPoints ??
28
+ (snapPointsMode === 'percent'
29
+ ? [80]
30
+ : snapPointsMode === 'constant'
31
+ ? [256]
32
+ : ['fit'])
33
+ const hasFit = snapPointsProp[0] === 'fit'
34
+
35
+ const snapPoints = React.useMemo(
36
+ () => (props.dismissOnSnapToBottom ? [...snapPointsProp, 0] : snapPointsProp),
37
+
38
+ [JSON.stringify(snapPointsProp), props.dismissOnSnapToBottom]
39
+ )
40
+
41
+ // lets set -1 to be always the "open = false" position
42
+ const [position_, setPositionImmediate] = useControllableState({
43
+ prop: props.position,
44
+ defaultProp: props.defaultPosition || (state.open ? 0 : -1),
45
+ onChange: props.onPositionChange,
46
+ strategy: 'most-recent-wins',
47
+ })
48
+
49
+ const position = state.open === false ? -1 : position_
50
+
51
+ const { open } = state
52
+
53
+ const setPosition = React.useCallback(
54
+ (next: number) => {
55
+ // close on dismissOnSnapToBottom (and set position so it animates)
56
+ if (props.dismissOnSnapToBottom && next === snapPoints.length - 1) {
57
+ state.setOpen(false)
58
+ } else {
59
+ setPositionImmediate(next)
60
+ }
61
+ },
62
+ [props.dismissOnSnapToBottom, snapPoints.length, setPositionImmediate, state.setOpen]
63
+ )
64
+
65
+ if (process.env.NODE_ENV === 'development') {
66
+ if (
67
+ snapPointsMode === 'mixed' &&
68
+ snapPoints.some((p) => {
69
+ if (typeof p === 'string') {
70
+ if (p === 'fit') {
71
+ return false
72
+ }
73
+ if (p.endsWith('%')) {
74
+ const n = Number(p.slice(0, -1))
75
+ return n < 0 || n > 100
76
+ }
77
+ return true
78
+ }
79
+ return typeof p !== 'number' || p < 0
80
+ })
81
+ ) {
82
+ console.warn(
83
+ '⚠️ Invalid snapPoint given, snapPoints must be positive numeric values, string percentages between 0-100%, or "fit" when snapPointsMode is mixed'
84
+ )
85
+ }
86
+ if (snapPointsMode === 'mixed' && snapPoints.indexOf('fit') > 0) {
87
+ console.warn(
88
+ '⚠️ Invalid snapPoint given, "fit" must be the first/largest snap point when snapPointsMode is mixed'
89
+ )
90
+ }
91
+ if (
92
+ snapPointsMode === 'fit' &&
93
+ (snapPoints.length !== (props.dismissOnSnapToBottom ? 2 : 1) ||
94
+ snapPoints[0] !== 'fit')
95
+ ) {
96
+ console.warn(
97
+ '⚠️ Invalid snapPoint given, there are no snap points when snapPointsMode is fit'
98
+ )
99
+ }
100
+ if (
101
+ snapPointsMode === 'constant' &&
102
+ snapPoints.some((p) => typeof p !== 'number' || p < 0)
103
+ ) {
104
+ console.warn(
105
+ '⚠️ Invalid snapPoint given, snapPoints must be positive numeric values when snapPointsMode is constant'
106
+ )
107
+ }
108
+ if (
109
+ snapPointsMode === 'percent' &&
110
+ snapPoints.some((p) => typeof p !== 'number' || p < 0 || p > 100)
111
+ ) {
112
+ console.warn(
113
+ '⚠️ Invalid snapPoint given, snapPoints must be numeric values between 0 and 100 when snapPointsMode is percent'
114
+ )
115
+ }
116
+ }
117
+
118
+ // reset position to fully open on re-open after dismissOnSnapToBottom
119
+ if (open && props.dismissOnSnapToBottom && position === snapPoints.length - 1) {
120
+ setPositionImmediate(0)
121
+ }
122
+
123
+ // open must set position
124
+ const shouldSetPositionOpen = open && position < 0
125
+ React.useEffect(() => {
126
+ if (shouldSetPositionOpen) {
127
+ setPosition(0)
128
+ }
129
+ }, [setPosition, shouldSetPositionOpen])
130
+
131
+ const { animationDriver } = useConfiguration()
132
+ if (!animationDriver) {
133
+ throw new Error(
134
+ process.env.NODE_ENV === 'production'
135
+ ? `❌ 008`
136
+ : 'Must set animations in gui.config.ts'
137
+ )
138
+ }
139
+
140
+ const scrollBridge = useConstant<ScrollBridge>(() => {
141
+ const parentDragListeners = new Set<Function>()
142
+
143
+ const bridge: ScrollBridge = {
144
+ hasScrollableContent: false,
145
+ enabled: false,
146
+ y: 0,
147
+ paneY: 0,
148
+ paneMinY: 0,
149
+ scrollStartY: -1,
150
+ drag: () => {},
151
+ release: () => {},
152
+ scrollLock: false,
153
+ isParentDragging: false,
154
+ onParentDragging: (cb) => {
155
+ parentDragListeners.add(cb)
156
+ return () => {
157
+ parentDragListeners.delete(cb)
158
+ }
159
+ },
160
+ setParentDragging: (val) => {
161
+ if (val !== bridge.isParentDragging) {
162
+ bridge.isParentDragging = val
163
+ parentDragListeners.forEach((cb) => cb(val))
164
+ }
165
+ },
166
+ }
167
+
168
+ return bridge
169
+ })
170
+
171
+ // Handle both new disableRemoveScroll and deprecated forceRemoveScrollEnabled
172
+ let disableRemoveScroll: boolean | undefined
173
+ if (props.disableRemoveScroll !== undefined) {
174
+ // New prop: disableRemoveScroll={true} means RemoveScroll is disabled
175
+ disableRemoveScroll = props.disableRemoveScroll || !open || !props.modal
176
+ } else if (props.forceRemoveScrollEnabled !== undefined) {
177
+ // Deprecated prop: forceRemoveScrollEnabled can override the default
178
+ if (process.env.NODE_ENV === 'development') {
179
+ console.warn(
180
+ '[Sheet] forceRemoveScrollEnabled is deprecated. Use disableRemoveScroll instead.'
181
+ )
182
+ }
183
+ disableRemoveScroll = !props.forceRemoveScrollEnabled
184
+ } else {
185
+ // Default: disabled when not open or not modal
186
+ disableRemoveScroll = !open || !props.modal
187
+ }
188
+
189
+ const maxSnapPoint = snapPoints[0]
190
+ const screenSize =
191
+ snapPointsMode === 'percent'
192
+ ? frameSize / ((typeof maxSnapPoint === 'number' ? maxSnapPoint : 100) / 100)
193
+ : maxContentSize
194
+
195
+ const providerProps = {
196
+ screenSize,
197
+ maxSnapPoint,
198
+ disableRemoveScroll,
199
+ scrollBridge,
200
+ modal: !!props.modal,
201
+ open: state.open,
202
+ setOpen: state.setOpen,
203
+ hidden: !!state.isHidden,
204
+ contentRef,
205
+ handleRef,
206
+ frameSize,
207
+ setFrameSize,
208
+ dismissOnOverlayPress: props.dismissOnOverlayPress ?? true,
209
+ dismissOnSnapToBottom: props.dismissOnSnapToBottom ?? false,
210
+ onOverlayComponent: options.onOverlayComponent,
211
+ scope: props.__scopeSheet,
212
+ hasFit,
213
+ position,
214
+ snapPoints,
215
+ snapPointsMode,
216
+ setMaxContentSize,
217
+ setPosition,
218
+ setPositionImmediate,
219
+ onlyShowFrame: false,
220
+ }
221
+
222
+ return providerProps
223
+ }
@@ -0,0 +1,163 @@
1
+ import { useRef } from 'react'
2
+ import type { GestureResponderEvent, ScrollView as RNScrollView } from 'react-native'
3
+ import type { ScrollBridge } from './types'
4
+
5
+ interface ResponderState {
6
+ lastPageY: number
7
+ dragAt: number
8
+ dys: number[]
9
+ isScrolling: boolean
10
+ isDraggingScrollArea: boolean
11
+ scrollEngaged: boolean
12
+ prevScrollY: number
13
+ handoffOccurred: boolean
14
+ handoffDragOffset: number
15
+ }
16
+
17
+ interface UseSheetScrollViewGesturesProps {
18
+ scrollRef: React.RefObject<RNScrollView | null>
19
+ scrollBridge: ScrollBridge
20
+ hasScrollableContent: boolean
21
+ scrollEnabled: boolean
22
+ setScrollEnabled: (enabled: boolean, lockTo?: number) => void
23
+ }
24
+
25
+ /**
26
+ * Native gesture handling for Sheet ScrollView.
27
+ * Returns responder props for the ScrollView component.
28
+ */
29
+ export function useSheetScrollViewGestures({
30
+ scrollBridge,
31
+ hasScrollableContent,
32
+ scrollEnabled,
33
+ setScrollEnabled,
34
+ }: UseSheetScrollViewGesturesProps) {
35
+ const state = useRef<ResponderState>({
36
+ lastPageY: 0,
37
+ dragAt: 0,
38
+ dys: [],
39
+ isScrolling: false,
40
+ isDraggingScrollArea: false,
41
+ scrollEngaged: false,
42
+ prevScrollY: 0,
43
+ handoffOccurred: false,
44
+ handoffDragOffset: 0,
45
+ })
46
+
47
+ const release = () => {
48
+ const s = state.current
49
+ if (!s.isDraggingScrollArea) return
50
+
51
+ s.isDraggingScrollArea = false
52
+ scrollBridge.scrollStartY = -1
53
+ scrollBridge.scrollLock = false
54
+ s.isScrolling = false
55
+ s.scrollEngaged = false
56
+ s.prevScrollY = 0
57
+ s.handoffOccurred = false
58
+ s.handoffDragOffset = 0
59
+ setScrollEnabled(true)
60
+
61
+ let vy = 0
62
+ if (s.dys.length) {
63
+ const recentDys = s.dys.slice(-10)
64
+ const dist = recentDys.reduce((a, b) => a + b, 0)
65
+ vy = (dist / recentDys.length) * 0.04
66
+ }
67
+ s.dys = []
68
+
69
+ scrollBridge.release({ dragAt: s.dragAt, vy })
70
+ }
71
+
72
+ const onStartShouldSetResponder = () => {
73
+ const s = state.current
74
+ scrollBridge.scrollStartY = -1
75
+ s.isDraggingScrollArea = true
76
+ s.scrollEngaged = scrollBridge.y > 0
77
+ s.prevScrollY = scrollBridge.y
78
+ s.handoffOccurred = false
79
+ s.handoffDragOffset = 0
80
+ return false
81
+ }
82
+
83
+ const onMoveShouldSetResponder = (e: GestureResponderEvent) => {
84
+ if (!scrollEnabled) return false
85
+ const s = state.current
86
+ const { pageY } = e.nativeEvent
87
+ if (s.lastPageY === 0) {
88
+ s.lastPageY = pageY
89
+ return false
90
+ }
91
+ return Math.abs(pageY - s.lastPageY) > 10
92
+ }
93
+
94
+ const onResponderMove = (e: GestureResponderEvent) => {
95
+ const s = state.current
96
+ const { pageY } = e.nativeEvent
97
+
98
+ if (!s.isScrolling && scrollBridge.scrollStartY === -1) {
99
+ scrollBridge.scrollStartY = pageY
100
+ s.lastPageY = pageY
101
+ }
102
+
103
+ const dragAt = pageY - scrollBridge.scrollStartY
104
+ const dy = pageY - s.lastPageY
105
+ s.lastPageY = pageY
106
+ const isDraggingDown = dy > 0
107
+ const isPaneAtTop = scrollBridge.paneY <= scrollBridge.paneMinY + 5
108
+ const currentScrollY = scrollBridge.y
109
+
110
+ if (currentScrollY > 0) s.scrollEngaged = true
111
+
112
+ const wasScrolledNowAtZero =
113
+ s.scrollEngaged && s.prevScrollY > 0 && currentScrollY <= 0
114
+
115
+ if (wasScrolledNowAtZero && !s.handoffOccurred) {
116
+ s.handoffOccurred = true
117
+ s.handoffDragOffset = 0
118
+ }
119
+
120
+ s.prevScrollY = currentScrollY
121
+
122
+ let panHandles = false
123
+ if (!isPaneAtTop) {
124
+ panHandles = isDraggingDown ? currentScrollY <= 0 || !hasScrollableContent : true
125
+ } else if (isDraggingDown) {
126
+ if (currentScrollY > 0 && hasScrollableContent && !s.handoffOccurred) {
127
+ panHandles = false
128
+ } else {
129
+ panHandles = s.handoffOccurred || wasScrolledNowAtZero || currentScrollY <= 0
130
+ }
131
+ } else {
132
+ panHandles = !hasScrollableContent
133
+ if (!panHandles) {
134
+ s.isScrolling = true
135
+ scrollBridge.scrollLock = true
136
+ setScrollEnabled(true)
137
+ return
138
+ }
139
+ }
140
+
141
+ if (panHandles) {
142
+ setScrollEnabled(false)
143
+ let effectiveDragAt = dragAt
144
+ if (s.handoffOccurred) {
145
+ s.handoffDragOffset += dy
146
+ effectiveDragAt = s.handoffDragOffset
147
+ }
148
+ scrollBridge.drag(effectiveDragAt)
149
+ s.dragAt = effectiveDragAt
150
+ s.dys.push(dy)
151
+ if (s.dys.length > 100) s.dys = s.dys.slice(-10)
152
+ } else {
153
+ setScrollEnabled(true)
154
+ }
155
+ }
156
+
157
+ return {
158
+ onResponderRelease: release,
159
+ onStartShouldSetResponder,
160
+ onMoveShouldSetResponder,
161
+ onResponderMove,
162
+ }
163
+ }