react-native-layout-dnd 0.1.0-alpha.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 (340) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +262 -0
  3. package/lib/module/adapters/coordinates.js +135 -0
  4. package/lib/module/adapters/coordinates.js.map +1 -0
  5. package/lib/module/adapters/scroll.js +81 -0
  6. package/lib/module/adapters/scroll.js.map +1 -0
  7. package/lib/module/adapters/virtualizedList.js +69 -0
  8. package/lib/module/adapters/virtualizedList.js.map +1 -0
  9. package/lib/module/components/DndProvider.js +1144 -0
  10. package/lib/module/components/DndProvider.js.map +1 -0
  11. package/lib/module/components/DragHandle.js +65 -0
  12. package/lib/module/components/DragHandle.js.map +1 -0
  13. package/lib/module/components/GridController.js +151 -0
  14. package/lib/module/components/GridController.js.map +1 -0
  15. package/lib/module/components/GridDragHandle.js +15 -0
  16. package/lib/module/components/GridDragHandle.js.map +1 -0
  17. package/lib/module/components/GridZoneView.js +59 -0
  18. package/lib/module/components/GridZoneView.js.map +1 -0
  19. package/lib/module/components/SortableGrid.js +305 -0
  20. package/lib/module/components/SortableGrid.js.map +1 -0
  21. package/lib/module/components/SortableList.js +714 -0
  22. package/lib/module/components/SortableList.js.map +1 -0
  23. package/lib/module/components/dndTypes.js +4 -0
  24. package/lib/module/components/dndTypes.js.map +1 -0
  25. package/lib/module/components/gridTypes.js +4 -0
  26. package/lib/module/components/gridTypes.js.map +1 -0
  27. package/lib/module/components/handleViewProps.js +13 -0
  28. package/lib/module/components/handleViewProps.js.map +1 -0
  29. package/lib/module/contracts.js +4 -0
  30. package/lib/module/contracts.js.map +1 -0
  31. package/lib/module/controller/approval.js +98 -0
  32. package/lib/module/controller/approval.js.map +1 -0
  33. package/lib/module/controller/coordinatorBase.js +93 -0
  34. package/lib/module/controller/coordinatorBase.js.map +1 -0
  35. package/lib/module/controller/dndSession.js +621 -0
  36. package/lib/module/controller/dndSession.js.map +1 -0
  37. package/lib/module/controller/dndState.js +103 -0
  38. package/lib/module/controller/dndState.js.map +1 -0
  39. package/lib/module/controller/gridAdapter.js +191 -0
  40. package/lib/module/controller/gridAdapter.js.map +1 -0
  41. package/lib/module/controller/gridState.js +101 -0
  42. package/lib/module/controller/gridState.js.map +1 -0
  43. package/lib/module/controller/locations.js +48 -0
  44. package/lib/module/controller/locations.js.map +1 -0
  45. package/lib/module/controller/previewPath.js +73 -0
  46. package/lib/module/controller/previewPath.js.map +1 -0
  47. package/lib/module/controller/sessionCore.js +222 -0
  48. package/lib/module/controller/sessionCore.js.map +1 -0
  49. package/lib/module/controller/useDndState.js +9 -0
  50. package/lib/module/controller/useDndState.js.map +1 -0
  51. package/lib/module/controller/useGridState.js +9 -0
  52. package/lib/module/controller/useGridState.js.map +1 -0
  53. package/lib/module/controller/useStoreState.js +15 -0
  54. package/lib/module/controller/useStoreState.js.map +1 -0
  55. package/lib/module/defaults.js +7 -0
  56. package/lib/module/defaults.js.map +1 -0
  57. package/lib/module/diagnostics.js +16 -0
  58. package/lib/module/diagnostics.js.map +1 -0
  59. package/lib/module/engine/gridPlacements.js +54 -0
  60. package/lib/module/engine/gridPlacements.js.map +1 -0
  61. package/lib/module/engine/index.js +19 -0
  62. package/lib/module/engine/index.js.map +1 -0
  63. package/lib/module/engine/layout.js +36 -0
  64. package/lib/module/engine/layout.js.map +1 -0
  65. package/lib/module/engine/layoutMove.js +326 -0
  66. package/lib/module/engine/layoutMove.js.map +1 -0
  67. package/lib/module/engine/layoutState.js +344 -0
  68. package/lib/module/engine/layoutState.js.map +1 -0
  69. package/lib/module/engine/list.js +172 -0
  70. package/lib/module/engine/list.js.map +1 -0
  71. package/lib/module/engine/listIndex.js +125 -0
  72. package/lib/module/engine/listIndex.js.map +1 -0
  73. package/lib/module/engine/move.js +216 -0
  74. package/lib/module/engine/move.js.map +1 -0
  75. package/lib/module/engine/movementPolicy.js +77 -0
  76. package/lib/module/engine/movementPolicy.js.map +1 -0
  77. package/lib/module/engine/orderedTarget.js +71 -0
  78. package/lib/module/engine/orderedTarget.js.map +1 -0
  79. package/lib/module/engine/pack.js +30 -0
  80. package/lib/module/engine/pack.js.map +1 -0
  81. package/lib/module/engine/rectangles.js +12 -0
  82. package/lib/module/engine/rectangles.js.map +1 -0
  83. package/lib/module/engine/sameLayout.js +29 -0
  84. package/lib/module/engine/sameLayout.js.map +1 -0
  85. package/lib/module/engine/search.js +159 -0
  86. package/lib/module/engine/search.js.map +1 -0
  87. package/lib/module/engine/spatial.js +27 -0
  88. package/lib/module/engine/spatial.js.map +1 -0
  89. package/lib/module/engine/spatialAppRotation.js +39 -0
  90. package/lib/module/engine/spatialAppRotation.js.map +1 -0
  91. package/lib/module/engine/spatialExchange.js +164 -0
  92. package/lib/module/engine/spatialExchange.js.map +1 -0
  93. package/lib/module/engine/spatialInsertion.js +135 -0
  94. package/lib/module/engine/spatialInsertion.js.map +1 -0
  95. package/lib/module/engine/spatialPolicy.js +41 -0
  96. package/lib/module/engine/spatialPolicy.js.map +1 -0
  97. package/lib/module/engine/spatialRotation.js +48 -0
  98. package/lib/module/engine/spatialRotation.js.map +1 -0
  99. package/lib/module/engine/validation.js +205 -0
  100. package/lib/module/engine/validation.js.map +1 -0
  101. package/lib/module/gesture/DndGestureGroup.js +268 -0
  102. package/lib/module/gesture/DndGestureGroup.js.map +1 -0
  103. package/lib/module/gesture/DndGestureHost.js +32 -0
  104. package/lib/module/gesture/DndGestureHost.js.map +1 -0
  105. package/lib/module/gesture/gestureConfig.js +81 -0
  106. package/lib/module/gesture/gestureConfig.js.map +1 -0
  107. package/lib/module/gesture/gestureGrouping.js +122 -0
  108. package/lib/module/gesture/gestureGrouping.js.map +1 -0
  109. package/lib/module/gesture/gestureHost.js +106 -0
  110. package/lib/module/gesture/gestureHost.js.map +1 -0
  111. package/lib/module/index.js +23 -0
  112. package/lib/module/index.js.map +1 -0
  113. package/lib/module/package.json +1 -0
  114. package/lib/module/pointer/dndTarget.js +101 -0
  115. package/lib/module/pointer/dndTarget.js.map +1 -0
  116. package/lib/module/pointer/geometry.js +363 -0
  117. package/lib/module/pointer/geometry.js.map +1 -0
  118. package/lib/module/pointer/layoutTarget.js +307 -0
  119. package/lib/module/pointer/layoutTarget.js.map +1 -0
  120. package/lib/module/pointer/listCellMotion.js +99 -0
  121. package/lib/module/pointer/listCellMotion.js.map +1 -0
  122. package/lib/module/pointer/listTarget.js +42 -0
  123. package/lib/module/pointer/listTarget.js.map +1 -0
  124. package/lib/module/pointer/motion.js +37 -0
  125. package/lib/module/pointer/motion.js.map +1 -0
  126. package/lib/module/runtime/dndPresentation.js +81 -0
  127. package/lib/module/runtime/dndPresentation.js.map +1 -0
  128. package/lib/module/runtime/dndRenderStore.js +129 -0
  129. package/lib/module/runtime/dndRenderStore.js.map +1 -0
  130. package/lib/module/runtime/dndRuntime.js +135 -0
  131. package/lib/module/runtime/dndRuntime.js.map +1 -0
  132. package/lib/module/runtime/dndSettlement.js +77 -0
  133. package/lib/module/runtime/dndSettlement.js.map +1 -0
  134. package/lib/module/runtime/gridRuntime.js +37 -0
  135. package/lib/module/runtime/gridRuntime.js.map +1 -0
  136. package/lib/module/types.js +4 -0
  137. package/lib/module/types.js.map +1 -0
  138. package/lib/typescript/package.json +1 -0
  139. package/lib/typescript/src/adapters/coordinates.d.ts +9 -0
  140. package/lib/typescript/src/adapters/coordinates.d.ts.map +1 -0
  141. package/lib/typescript/src/adapters/scroll.d.ts +49 -0
  142. package/lib/typescript/src/adapters/scroll.d.ts.map +1 -0
  143. package/lib/typescript/src/adapters/virtualizedList.d.ts +22 -0
  144. package/lib/typescript/src/adapters/virtualizedList.d.ts.map +1 -0
  145. package/lib/typescript/src/components/DndProvider.d.ts +4 -0
  146. package/lib/typescript/src/components/DndProvider.d.ts.map +1 -0
  147. package/lib/typescript/src/components/DragHandle.d.ts +4 -0
  148. package/lib/typescript/src/components/DragHandle.d.ts.map +1 -0
  149. package/lib/typescript/src/components/GridController.d.ts +21 -0
  150. package/lib/typescript/src/components/GridController.d.ts.map +1 -0
  151. package/lib/typescript/src/components/GridDragHandle.d.ts +8 -0
  152. package/lib/typescript/src/components/GridDragHandle.d.ts.map +1 -0
  153. package/lib/typescript/src/components/GridZoneView.d.ts +8 -0
  154. package/lib/typescript/src/components/GridZoneView.d.ts.map +1 -0
  155. package/lib/typescript/src/components/SortableGrid.d.ts +4 -0
  156. package/lib/typescript/src/components/SortableGrid.d.ts.map +1 -0
  157. package/lib/typescript/src/components/SortableList.d.ts +4 -0
  158. package/lib/typescript/src/components/SortableList.d.ts.map +1 -0
  159. package/lib/typescript/src/components/dndTypes.d.ts +94 -0
  160. package/lib/typescript/src/components/dndTypes.d.ts.map +1 -0
  161. package/lib/typescript/src/components/gridTypes.d.ts +84 -0
  162. package/lib/typescript/src/components/gridTypes.d.ts.map +1 -0
  163. package/lib/typescript/src/components/handleViewProps.d.ts +6 -0
  164. package/lib/typescript/src/components/handleViewProps.d.ts.map +1 -0
  165. package/lib/typescript/src/contracts.d.ts +145 -0
  166. package/lib/typescript/src/contracts.d.ts.map +1 -0
  167. package/lib/typescript/src/controller/approval.d.ts +66 -0
  168. package/lib/typescript/src/controller/approval.d.ts.map +1 -0
  169. package/lib/typescript/src/controller/coordinatorBase.d.ts +37 -0
  170. package/lib/typescript/src/controller/coordinatorBase.d.ts.map +1 -0
  171. package/lib/typescript/src/controller/dndSession.d.ts +152 -0
  172. package/lib/typescript/src/controller/dndSession.d.ts.map +1 -0
  173. package/lib/typescript/src/controller/dndState.d.ts +27 -0
  174. package/lib/typescript/src/controller/dndState.d.ts.map +1 -0
  175. package/lib/typescript/src/controller/gridAdapter.d.ts +44 -0
  176. package/lib/typescript/src/controller/gridAdapter.d.ts.map +1 -0
  177. package/lib/typescript/src/controller/gridState.d.ts +18 -0
  178. package/lib/typescript/src/controller/gridState.d.ts.map +1 -0
  179. package/lib/typescript/src/controller/locations.d.ts +9 -0
  180. package/lib/typescript/src/controller/locations.d.ts.map +1 -0
  181. package/lib/typescript/src/controller/previewPath.d.ts +49 -0
  182. package/lib/typescript/src/controller/previewPath.d.ts.map +1 -0
  183. package/lib/typescript/src/controller/sessionCore.d.ts +106 -0
  184. package/lib/typescript/src/controller/sessionCore.d.ts.map +1 -0
  185. package/lib/typescript/src/controller/useDndState.d.ts +8 -0
  186. package/lib/typescript/src/controller/useDndState.d.ts.map +1 -0
  187. package/lib/typescript/src/controller/useGridState.d.ts +8 -0
  188. package/lib/typescript/src/controller/useGridState.d.ts.map +1 -0
  189. package/lib/typescript/src/controller/useStoreState.d.ts +16 -0
  190. package/lib/typescript/src/controller/useStoreState.d.ts.map +1 -0
  191. package/lib/typescript/src/defaults.d.ts +5 -0
  192. package/lib/typescript/src/defaults.d.ts.map +1 -0
  193. package/lib/typescript/src/diagnostics.d.ts +9 -0
  194. package/lib/typescript/src/diagnostics.d.ts.map +1 -0
  195. package/lib/typescript/src/engine/gridPlacements.d.ts +22 -0
  196. package/lib/typescript/src/engine/gridPlacements.d.ts.map +1 -0
  197. package/lib/typescript/src/engine/index.d.ts +28 -0
  198. package/lib/typescript/src/engine/index.d.ts.map +1 -0
  199. package/lib/typescript/src/engine/layout.d.ts +4 -0
  200. package/lib/typescript/src/engine/layout.d.ts.map +1 -0
  201. package/lib/typescript/src/engine/layoutMove.d.ts +46 -0
  202. package/lib/typescript/src/engine/layoutMove.d.ts.map +1 -0
  203. package/lib/typescript/src/engine/layoutState.d.ts +22 -0
  204. package/lib/typescript/src/engine/layoutState.d.ts.map +1 -0
  205. package/lib/typescript/src/engine/list.d.ts +68 -0
  206. package/lib/typescript/src/engine/list.d.ts.map +1 -0
  207. package/lib/typescript/src/engine/listIndex.d.ts +32 -0
  208. package/lib/typescript/src/engine/listIndex.d.ts.map +1 -0
  209. package/lib/typescript/src/engine/move.d.ts +10 -0
  210. package/lib/typescript/src/engine/move.d.ts.map +1 -0
  211. package/lib/typescript/src/engine/movementPolicy.d.ts +34 -0
  212. package/lib/typescript/src/engine/movementPolicy.d.ts.map +1 -0
  213. package/lib/typescript/src/engine/orderedTarget.d.ts +32 -0
  214. package/lib/typescript/src/engine/orderedTarget.d.ts.map +1 -0
  215. package/lib/typescript/src/engine/pack.d.ts +3 -0
  216. package/lib/typescript/src/engine/pack.d.ts.map +1 -0
  217. package/lib/typescript/src/engine/rectangles.d.ts +9 -0
  218. package/lib/typescript/src/engine/rectangles.d.ts.map +1 -0
  219. package/lib/typescript/src/engine/sameLayout.d.ts +4 -0
  220. package/lib/typescript/src/engine/sameLayout.d.ts.map +1 -0
  221. package/lib/typescript/src/engine/search.d.ts +28 -0
  222. package/lib/typescript/src/engine/search.d.ts.map +1 -0
  223. package/lib/typescript/src/engine/spatial.d.ts +16 -0
  224. package/lib/typescript/src/engine/spatial.d.ts.map +1 -0
  225. package/lib/typescript/src/engine/spatialAppRotation.d.ts +4 -0
  226. package/lib/typescript/src/engine/spatialAppRotation.d.ts.map +1 -0
  227. package/lib/typescript/src/engine/spatialExchange.d.ts +5 -0
  228. package/lib/typescript/src/engine/spatialExchange.d.ts.map +1 -0
  229. package/lib/typescript/src/engine/spatialInsertion.d.ts +5 -0
  230. package/lib/typescript/src/engine/spatialInsertion.d.ts.map +1 -0
  231. package/lib/typescript/src/engine/spatialPolicy.d.ts +9 -0
  232. package/lib/typescript/src/engine/spatialPolicy.d.ts.map +1 -0
  233. package/lib/typescript/src/engine/spatialRotation.d.ts +8 -0
  234. package/lib/typescript/src/engine/spatialRotation.d.ts.map +1 -0
  235. package/lib/typescript/src/engine/validation.d.ts +9 -0
  236. package/lib/typescript/src/engine/validation.d.ts.map +1 -0
  237. package/lib/typescript/src/gesture/DndGestureGroup.d.ts +33 -0
  238. package/lib/typescript/src/gesture/DndGestureGroup.d.ts.map +1 -0
  239. package/lib/typescript/src/gesture/DndGestureHost.d.ts +12 -0
  240. package/lib/typescript/src/gesture/DndGestureHost.d.ts.map +1 -0
  241. package/lib/typescript/src/gesture/gestureConfig.d.ts +15 -0
  242. package/lib/typescript/src/gesture/gestureConfig.d.ts.map +1 -0
  243. package/lib/typescript/src/gesture/gestureGrouping.d.ts +66 -0
  244. package/lib/typescript/src/gesture/gestureGrouping.d.ts.map +1 -0
  245. package/lib/typescript/src/gesture/gestureHost.d.ts +23 -0
  246. package/lib/typescript/src/gesture/gestureHost.d.ts.map +1 -0
  247. package/lib/typescript/src/index.d.ts +38 -0
  248. package/lib/typescript/src/index.d.ts.map +1 -0
  249. package/lib/typescript/src/pointer/dndTarget.d.ts +14 -0
  250. package/lib/typescript/src/pointer/dndTarget.d.ts.map +1 -0
  251. package/lib/typescript/src/pointer/geometry.d.ts +28 -0
  252. package/lib/typescript/src/pointer/geometry.d.ts.map +1 -0
  253. package/lib/typescript/src/pointer/layoutTarget.d.ts +43 -0
  254. package/lib/typescript/src/pointer/layoutTarget.d.ts.map +1 -0
  255. package/lib/typescript/src/pointer/listCellMotion.d.ts +43 -0
  256. package/lib/typescript/src/pointer/listCellMotion.d.ts.map +1 -0
  257. package/lib/typescript/src/pointer/listTarget.d.ts +7 -0
  258. package/lib/typescript/src/pointer/listTarget.d.ts.map +1 -0
  259. package/lib/typescript/src/pointer/motion.d.ts +20 -0
  260. package/lib/typescript/src/pointer/motion.d.ts.map +1 -0
  261. package/lib/typescript/src/runtime/dndPresentation.d.ts +37 -0
  262. package/lib/typescript/src/runtime/dndPresentation.d.ts.map +1 -0
  263. package/lib/typescript/src/runtime/dndRenderStore.d.ts +46 -0
  264. package/lib/typescript/src/runtime/dndRenderStore.d.ts.map +1 -0
  265. package/lib/typescript/src/runtime/dndRuntime.d.ts +138 -0
  266. package/lib/typescript/src/runtime/dndRuntime.d.ts.map +1 -0
  267. package/lib/typescript/src/runtime/dndSettlement.d.ts +18 -0
  268. package/lib/typescript/src/runtime/dndSettlement.d.ts.map +1 -0
  269. package/lib/typescript/src/runtime/gridRuntime.d.ts +54 -0
  270. package/lib/typescript/src/runtime/gridRuntime.d.ts.map +1 -0
  271. package/lib/typescript/src/types.d.ts +180 -0
  272. package/lib/typescript/src/types.d.ts.map +1 -0
  273. package/package.json +136 -0
  274. package/src/adapters/coordinates.ts +181 -0
  275. package/src/adapters/scroll.ts +147 -0
  276. package/src/adapters/virtualizedList.ts +112 -0
  277. package/src/components/DndProvider.tsx +1836 -0
  278. package/src/components/DragHandle.tsx +89 -0
  279. package/src/components/GridController.tsx +213 -0
  280. package/src/components/GridDragHandle.tsx +11 -0
  281. package/src/components/GridZoneView.tsx +57 -0
  282. package/src/components/SortableGrid.tsx +449 -0
  283. package/src/components/SortableList.tsx +1028 -0
  284. package/src/components/dndTypes.ts +102 -0
  285. package/src/components/gridTypes.ts +90 -0
  286. package/src/components/handleViewProps.ts +35 -0
  287. package/src/contracts.ts +149 -0
  288. package/src/controller/approval.ts +179 -0
  289. package/src/controller/coordinatorBase.ts +118 -0
  290. package/src/controller/dndSession.ts +1058 -0
  291. package/src/controller/dndState.ts +198 -0
  292. package/src/controller/gridAdapter.ts +268 -0
  293. package/src/controller/gridState.ts +187 -0
  294. package/src/controller/locations.ts +67 -0
  295. package/src/controller/previewPath.ts +90 -0
  296. package/src/controller/sessionCore.ts +390 -0
  297. package/src/controller/useDndState.ts +26 -0
  298. package/src/controller/useGridState.ts +22 -0
  299. package/src/controller/useStoreState.ts +27 -0
  300. package/src/defaults.ts +4 -0
  301. package/src/diagnostics.ts +23 -0
  302. package/src/engine/gridPlacements.ts +85 -0
  303. package/src/engine/index.ts +99 -0
  304. package/src/engine/layout.ts +29 -0
  305. package/src/engine/layoutMove.ts +401 -0
  306. package/src/engine/layoutState.ts +490 -0
  307. package/src/engine/list.ts +307 -0
  308. package/src/engine/listIndex.ts +174 -0
  309. package/src/engine/move.ts +274 -0
  310. package/src/engine/movementPolicy.ts +151 -0
  311. package/src/engine/orderedTarget.ts +131 -0
  312. package/src/engine/pack.ts +24 -0
  313. package/src/engine/rectangles.ts +18 -0
  314. package/src/engine/sameLayout.ts +50 -0
  315. package/src/engine/search.ts +174 -0
  316. package/src/engine/spatial.ts +36 -0
  317. package/src/engine/spatialAppRotation.ts +53 -0
  318. package/src/engine/spatialExchange.ts +212 -0
  319. package/src/engine/spatialInsertion.ts +157 -0
  320. package/src/engine/spatialPolicy.ts +48 -0
  321. package/src/engine/spatialRotation.ts +56 -0
  322. package/src/engine/validation.ts +358 -0
  323. package/src/gesture/DndGestureGroup.tsx +357 -0
  324. package/src/gesture/DndGestureHost.tsx +50 -0
  325. package/src/gesture/gestureConfig.ts +123 -0
  326. package/src/gesture/gestureGrouping.ts +210 -0
  327. package/src/gesture/gestureHost.tsx +163 -0
  328. package/src/index.ts +162 -0
  329. package/src/pointer/dndTarget.ts +213 -0
  330. package/src/pointer/geometry.ts +584 -0
  331. package/src/pointer/layoutTarget.ts +515 -0
  332. package/src/pointer/listCellMotion.ts +174 -0
  333. package/src/pointer/listTarget.ts +56 -0
  334. package/src/pointer/motion.ts +66 -0
  335. package/src/runtime/dndPresentation.ts +113 -0
  336. package/src/runtime/dndRenderStore.ts +246 -0
  337. package/src/runtime/dndRuntime.ts +311 -0
  338. package/src/runtime/dndSettlement.ts +117 -0
  339. package/src/runtime/gridRuntime.ts +73 -0
  340. package/src/types.ts +189 -0
@@ -0,0 +1,1144 @@
1
+ "use strict";
2
+
3
+ import { useCallback, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react';
4
+ import { PixelRatio, StyleSheet } from 'react-native';
5
+ import Animated, { cancelAnimation, scrollTo, useAnimatedRef, useAnimatedStyle, useDerivedValue, useFrameCallback, useSharedValue, withTiming } from 'react-native-reanimated';
6
+ import { runOnUISync, scheduleOnRN, scheduleOnUI } from 'react-native-worklets';
7
+ import { computeAutoScroll } from "../adapters/scroll.js";
8
+ import { createListTargetIndex } from "../engine/listIndex.js";
9
+ import { DndSessionCoordinator } from "../controller/dndSession.js";
10
+ import { sameGestureRelations } from "../gesture/gestureConfig.js";
11
+ import { DEFAULT_ACTIVATION_DELAY_MS, DEFAULT_SEARCH_BUDGET } from "../defaults.js";
12
+ import { resolveGridMovementPolicy, validateGridMovementPolicy } from "../engine/movementPolicy.js";
13
+ import { isPositiveInteger } from "../engine/validation.js";
14
+ import { DEFAULT_GRID_MOTION, resolveGridMotion } from "../pointer/motion.js";
15
+ import { DndItemContext, DndRuntimeContext, EMPTY_DND_MOTION, measureDndRect, pointInRect, readListViewports } from "../runtime/dndRuntime.js";
16
+ import { resolveLayoutTarget, isLayoutTargetVisible, prepareGridTarget } from "../pointer/layoutTarget.js";
17
+ import { itemRect } from "../pointer/geometry.js";
18
+ import { createZonePresentation, EMPTY_DND_PRESENTATION, presentationRect } from "../runtime/dndPresentation.js";
19
+ import { sameLayoutTarget, uiLayoutTarget } from "../pointer/dndTarget.js";
20
+ import { interpolateSettlementRect, settlementDestination, settlementTarget } from "../runtime/dndSettlement.js";
21
+ import { createDndGestureRegistry, DndGestureHost } from "../gesture/DndGestureHost.js";
22
+ import { DndRenderStore } from "../runtime/dndRenderStore.js";
23
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
24
+ function sameHandle(first, second) {
25
+ return first.itemId === second.itemId && first.zoneId === second.zoneId && first.ref === second.ref && first.sourceRef === second.sourceRef && first.disabled === second.disabled && sameGestureRelations(first.gestureRelations, second.gestureRelations);
26
+ }
27
+ function geometryResized(previous, next) {
28
+ 'worklet';
29
+
30
+ return !!previous && (previous.root.width !== next.root.width || previous.root.height !== next.root.height || next.zones.some(measured => {
31
+ const old = previous.zones.find(entry => entry.zoneId === measured.zoneId);
32
+ return old && (old.viewport.rect.width !== measured.viewport.rect.width || old.viewport.rect.height !== measured.viewport.rect.height);
33
+ }));
34
+ }
35
+ function targetEnvironmentChanged(previous, next) {
36
+ 'worklet';
37
+
38
+ return !previous || previous.root.x !== next.root.x || previous.root.y !== next.root.y || previous.root.width !== next.root.width || previous.root.height !== next.root.height || previous.zones.length !== next.zones.length || next.zones.some((zone, index) => {
39
+ const old = previous.zones[index];
40
+ return !old || old.zoneId !== zone.zoneId || old.offset !== zone.offset || old.layoutVersion !== zone.layoutVersion || old.viewport.revision !== zone.viewport.revision || old.viewport.rect.x !== zone.viewport.rect.x || old.viewport.rect.y !== zone.viewport.rect.y || old.viewport.rect.width !== zone.viewport.rect.width || old.viewport.rect.height !== zone.viewport.rect.height;
41
+ });
42
+ }
43
+ function sameUiZone(a, b) {
44
+ return a.kind === b.kind && a.zoneId === b.zoneId && a.revision === b.revision && a.layoutVersion === b.layoutVersion && a.ref === b.ref && (a.kind === 'grid' && b.kind === 'grid' && a.targetGrid === b.targetGrid || b.kind === 'list' && a.kind === 'list' && a.targetIndex === b.targetIndex && a.orientation === b.orientation && a.offset === b.offset && a.contentSize === b.contentSize && a.autoScroll?.enabled === b.autoScroll?.enabled && a.autoScroll?.edgeThreshold === b.autoScroll?.edgeThreshold && a.autoScroll?.maxSpeed === b.autoScroll?.maxSpeed);
45
+ }
46
+
47
+ // Worklets rewrites shared objects into accessors in development. Never share
48
+ // the coordinator's JS snapshot objects themselves with the UI runtime.
49
+ function copyLayoutTarget(target) {
50
+ return target.kind === 'grid' ? {
51
+ ...target,
52
+ position: {
53
+ ...target.position
54
+ }
55
+ } : {
56
+ ...target
57
+ };
58
+ }
59
+
60
+ /** Shared gesture, session and overlay for grid, ScrollView and FlatList zones. */
61
+ export function DndProvider({
62
+ value,
63
+ onChange,
64
+ canDrop,
65
+ onDragStart,
66
+ onDragEnd,
67
+ onDragSettled,
68
+ onValidationError,
69
+ onDiagnostic,
70
+ responseTimeoutMs,
71
+ getGridItemLayout,
72
+ movementPolicy,
73
+ searchBudget,
74
+ disabled = false,
75
+ activation = {
76
+ delayMs: DEFAULT_ACTIVATION_DELAY_MS
77
+ },
78
+ dragAxis = 'both',
79
+ motion: motionConfig,
80
+ renderDragPreview,
81
+ waitForDragPreviewReady = false,
82
+ dragPreviewStyle,
83
+ ref,
84
+ children,
85
+ style,
86
+ onLayout,
87
+ ...viewProps
88
+ }) {
89
+ const pixelRatio = PixelRatio.get();
90
+ const motionOptions = resolveGridMotion(motionConfig);
91
+ const durationMs = motionOptions.valid ? motionOptions.motion.durationMs : DEFAULT_GRID_MOTION.durationMs;
92
+ const reduceMotion = motionOptions.valid ? motionOptions.motion.reduceMotion : DEFAULT_GRID_MOTION.reduceMotion;
93
+ const animation = useMemo(() => ({
94
+ durationMs,
95
+ reduceMotion
96
+ }), [durationMs, reduceMotion]);
97
+ const configValid = Number.isSafeInteger(activation?.delayMs) && activation.delayMs >= 0 && ['both', 'x', 'y'].includes(dragAxis) && (canDrop === undefined || typeof canDrop === 'function') && motionOptions.valid;
98
+ const currentCanDrop = useRef(canDrop);
99
+ const policyRevision = useRef(0);
100
+ const committedValue = useRef(value);
101
+ const currentVisibility = useRef(() => true);
102
+ const checkDrop = useCallback(proposal => currentVisibility.current(proposal) ? currentCanDrop.current ? currentCanDrop.current(proposal) : {
103
+ allowed: true
104
+ } : {
105
+ allowed: false,
106
+ reason: 'clipped-target'
107
+ }, []);
108
+ const [registryInvalid, setRegistryInvalid] = useState(false);
109
+ const preview = useRef(null);
110
+ // `onDragEnd` is the coordinator's. `onDragSettled` repeats the event once
111
+ // the retained preview of that session has finished settling (finishPreview),
112
+ // or at once when no preview is retained; a new session or unmount flushes it.
113
+ const currentDragEnd = useRef(onDragEnd);
114
+ currentDragEnd.current = onDragEnd;
115
+ const currentDragSettled = useRef(onDragSettled);
116
+ currentDragSettled.current = onDragSettled;
117
+ const pendingSettled = useRef([]);
118
+ const reportSettled = useCallback(event => {
119
+ try {
120
+ currentDragSettled.current?.(event);
121
+ } catch (error) {
122
+ console.error('[LayoutDnD] onDragSettled callback failed', error);
123
+ }
124
+ }, []);
125
+ const flushSettled = useCallback(() => {
126
+ const queued = pendingSettled.current;
127
+ if (queued.length === 0) return;
128
+ pendingSettled.current = [];
129
+ for (const event of queued) reportSettled(event);
130
+ }, [reportSettled]);
131
+ const endSession = useCallback(event => {
132
+ const deferred = preview.current?.sessionId === event.sessionId;
133
+ if (deferred) pendingSettled.current.push(event);
134
+ try {
135
+ currentDragEnd.current?.(event);
136
+ } finally {
137
+ if (!deferred) reportSettled(event);
138
+ }
139
+ }, [reportSettled]);
140
+ const [coordinator] = useState(() => new DndSessionCoordinator({
141
+ value,
142
+ onChange,
143
+ canDrop: checkDrop,
144
+ onDragStart,
145
+ onDragEnd: endSession,
146
+ onValidationError,
147
+ onDiagnostic,
148
+ responseTimeoutMs,
149
+ getGridItemLayout,
150
+ movementPolicy,
151
+ searchBudget,
152
+ disabled: disabled || !configValid
153
+ }));
154
+ const [renderStore] = useState(() => new DndRenderStore(coordinator));
155
+ const snapshot = useSyncExternalStore(renderStore.subscribeProvider, renderStore.getProviderSnapshot);
156
+ const motion = useSharedValue(EMPTY_DND_MOTION);
157
+ const nativeRevision = useSharedValue(snapshot.value?.revision ?? 0);
158
+ const presentation = useSharedValue(EMPTY_DND_PRESENTATION);
159
+ const appliedPresentationGeneration = useSharedValue(0);
160
+ const presentationGeneration = useRef(0);
161
+ const settlement = useSharedValue(null);
162
+ const settleProgress = useSharedValue(0);
163
+ const pendingMove = useSharedValue(null);
164
+ const settlingToken = useRef(null);
165
+ const settlingRevision = useRef(null);
166
+ const refreshSettlement = useRef(() => {});
167
+ const targetSession = useSharedValue({
168
+ token: 0,
169
+ policyRevision: 0,
170
+ gridItems: {}
171
+ });
172
+ const sentTarget = useSharedValue({
173
+ state: null,
174
+ target: null,
175
+ policyRevision: -1
176
+ });
177
+ const zones = useSharedValue([]);
178
+ const publishedZones = useRef([]);
179
+ const uiDisabled = useSharedValue(disabled || !configValid);
180
+ const uiEnabled = useDerivedValue(() => !uiDisabled.get());
181
+ // JS reads of a shared value block on the UI runtime whenever the UI has
182
+ // written it since the last read. Motion changes every frame; these numbers
183
+ // change only at activation, release and cleanup, so JS reads stay cached.
184
+ const uiDragToken = useDerivedValue(() => {
185
+ const state = motion.get();
186
+ return state.phase === 'dragging' ? state.token : -1;
187
+ });
188
+ const uiActiveHandle = useDerivedValue(() => {
189
+ const state = motion.get();
190
+ return state.phase === 'idle' || state.handleId === null ? -1 : state.handleId;
191
+ });
192
+ const token = useSharedValue(0);
193
+ const rootRef = useAnimatedRef();
194
+ const handles = useRef(new Map());
195
+ const nextHandleId = useRef(0);
196
+ const [gestureRegistry] = useState(createDndGestureRegistry);
197
+ const registry = useRef(new Map());
198
+ const issues = useRef(new Map());
199
+ const observer = useRef(onValidationError);
200
+ const mounted = useRef(true);
201
+ const handlePublication = useRef({
202
+ queued: false,
203
+ generation: 0,
204
+ prune: false
205
+ }).current;
206
+ const currentConfig = useRef({
207
+ dragAxis,
208
+ delayMs: activation?.delayMs
209
+ });
210
+ const policyValid = validateGridMovementPolicy(movementPolicy).valid;
211
+ const nativeSettingsKey = JSON.stringify([searchBudget === undefined ? DEFAULT_SEARCH_BUDGET : isPositiveInteger(searchBudget) ? searchBudget : null, responseTimeoutMs === undefined ? 2000 : isPositiveInteger(responseTimeoutMs) ? responseTimeoutMs : null, policyValid ? resolveGridMovementPolicy(movementPolicy) : null]);
212
+ const committedNativeSettings = useRef({
213
+ key: nativeSettingsKey,
214
+ mapper: getGridItemLayout,
215
+ revision: 0
216
+ });
217
+ const gestureConfigRevision = committedNativeSettings.current.key === nativeSettingsKey && committedNativeSettings.current.mapper === getGridItemLayout ? committedNativeSettings.current.revision : committedNativeSettings.current.revision + 1;
218
+ const bridge = useRef({
219
+ token: 0,
220
+ sessionId: null,
221
+ state: null,
222
+ policyRevision: 0
223
+ });
224
+ const [retainedPreview, setRetainedPreview] = useState(null);
225
+ // Readiness belongs to the session, not to pointer requests or target
226
+ // validity. The default preview needs no application acknowledgement.
227
+ const [readyPreviewSessionId, setReadyPreviewSessionId] = useState(null);
228
+ const previewReady = !waitForDragPreviewReady || !renderDragPreview || readyPreviewSessionId === snapshot.sessionId;
229
+ const handlePreviewReady = useCallback(() => {
230
+ const current = coordinator.getSnapshot();
231
+ if (!mounted.current || current.sessionId === null) return;
232
+ setReadyPreviewSessionId(current.sessionId);
233
+ }, [coordinator]);
234
+ useImperativeHandle(ref, () => ({
235
+ invalidateGeometry: () => coordinator.cancel('geometry-changed')
236
+ }), [coordinator]);
237
+ const rootLayout = useRef(null);
238
+ const presentationCache = useRef(new Map());
239
+ const lastPresentation = useRef(EMPTY_DND_PRESENTATION);
240
+ const presentationSnapshot = useCallback(() => lastPresentation.current, []);
241
+ const prepareReleaseRef = useRef(undefined);
242
+ const publishPresentation = useCallback(() => {
243
+ const current = coordinator.getSnapshot();
244
+ const display = current.displayValue;
245
+ const next = {
246
+ token: bridge.current.token,
247
+ revision: current.value?.revision ?? 0,
248
+ zones: {},
249
+ ...((current.phase === 'dragging' || current.phase === 'awaiting-response') && current.validity === 'valid' && current.target ? {
250
+ releaseTarget: {
251
+ target: copyLayoutTarget(current.target),
252
+ policyRevision: policyRevision.current,
253
+ ...(current.phase === 'awaiting-response' ? {
254
+ releasedSeq: current.seq
255
+ } : {})
256
+ }
257
+ } : {})
258
+ };
259
+ // Idle cells already own committed geometry. Sending every rect again for
260
+ // each newly measured virtual cell copies the entire list onto UI.
261
+ if (display && (current.phase !== 'idle' || preview.current !== null)) for (const registration of registry.current.values()) {
262
+ if (registration.revision !== current.value?.revision || registration.kind === 'list' && registration.dataIdentity && registration.dataIdentity !== current.value?.items) continue;
263
+ const zone = display.zones.find(entry => entry.id === registration.zoneId);
264
+ if (!zone) continue;
265
+ const prepare = registration.kind === 'list' ? registration.prepareDisplay : undefined;
266
+ const cached = presentationCache.current.get(zone.id);
267
+ let result = null;
268
+ if (cached?.zone === zone && cached.layout === registration.layout && cached.geometryKey === registration.geometryKey && cached.prepare === prepare) {
269
+ result = cached.result;
270
+ } else if (registration.kind === 'list' && zone.kind === 'list') {
271
+ result = registration.prepareDisplay?.(zone, display.revision) ?? null;
272
+ } else if (registration.kind === 'grid' && zone.kind === 'grid') {
273
+ result = createZonePresentation(zone.placements.map(placement => [placement.itemId, itemRect(placement.position, placement.span, registration.geometry, registration.cells)]), cached?.result);
274
+ }
275
+ if (result) {
276
+ next.zones[`#${zone.id}`] = result;
277
+ presentationCache.current.set(zone.id, {
278
+ zone,
279
+ layout: registration.layout,
280
+ geometryKey: registration.geometryKey,
281
+ prepare,
282
+ result
283
+ });
284
+ }
285
+ }
286
+ const previous = lastPresentation.current;
287
+ for (const zoneId of presentationCache.current.keys()) {
288
+ if (!next.zones[`#${zoneId}`]) presentationCache.current.delete(zoneId);
289
+ }
290
+ if (previous.token === next.token && previous.revision === next.revision && previous.releaseTarget?.policyRevision === next.releaseTarget?.policyRevision && previous.releaseTarget?.releasedSeq === next.releaseTarget?.releasedSeq && sameLayoutTarget(previous.releaseTarget?.target ?? null, next.releaseTarget?.target ?? null) && Object.keys(previous.zones).length === Object.keys(next.zones).length && Object.keys(next.zones).every(key => previous.zones[key] === next.zones[key])) return;
291
+ lastPresentation.current = next;
292
+ const generation = ++presentationGeneration.current;
293
+ const animateRelease = current.phase === 'awaiting-response' ? prepareReleaseRef.current : undefined;
294
+ const applyPresentation = () => {
295
+ 'worklet';
296
+
297
+ const state = motion.get();
298
+ if (state.token === next.token && generation >= appliedPresentationGeneration.get()) {
299
+ appliedPresentationGeneration.set(generation);
300
+ presentation.set(next);
301
+ if (state.phase === 'released') animateRelease?.(state);
302
+ }
303
+ };
304
+ // A final validated target must reach UI before React's synchronous commit
305
+ // work delays the normal worklet microtask batch. This only shares geometry;
306
+ // animation and native measurement still run on subsequent UI frames.
307
+ if (animateRelease) runOnUISync(applyPresentation);else scheduleOnUI(applyPresentation);
308
+ }, [coordinator, motion, presentation, appliedPresentationGeneration]);
309
+ useLayoutEffect(() => coordinator.subscribe(publishPresentation), [coordinator, publishPresentation]);
310
+ const publishHandles = useCallback(() => {
311
+ if (!mounted.current || handlePublication.queued) return;
312
+ handlePublication.queued = true;
313
+ const generation = handlePublication.generation;
314
+ globalThis.queueMicrotask(() => {
315
+ if (!mounted.current || handlePublication.generation !== generation) return;
316
+ handlePublication.queued = false;
317
+ if (handlePublication.prune) {
318
+ handlePublication.prune = false;
319
+ // UI activation precedes its queued JS begin. Read the native owner
320
+ // once for the whole commit, keeping that recognizer through eviction.
321
+ let activeHandle;
322
+ for (const [identity, owner] of handles.current) {
323
+ if (owner.mounted) continue;
324
+ activeHandle ??= uiActiveHandle.get();
325
+ if (activeHandle !== owner.id) handles.current.delete(identity);
326
+ }
327
+ }
328
+ gestureRegistry.setOwners(Array.from(handles.current.values()));
329
+ });
330
+ }, [gestureRegistry, handlePublication, uiActiveHandle]);
331
+ const registerHandle = useCallback((registration, identity) => {
332
+ const previous = handles.current.get(identity);
333
+ const same = !!previous && sameHandle(previous.registration, registration);
334
+ if (previous?.mounted && same) return;
335
+ handles.current.set(identity, {
336
+ id: previous?.id ?? ++nextHandleId.current,
337
+ identity,
338
+ // A cleanup/setup pair in one commit can reuse the same native owner.
339
+ registration: same ? previous.registration : registration,
340
+ mounted: true
341
+ });
342
+ publishHandles();
343
+ refreshSettlement.current();
344
+ }, [publishHandles]);
345
+ const unregisterHandle = useCallback(identity => {
346
+ const previous = handles.current.get(identity);
347
+ if (!previous || !previous.mounted) return;
348
+ handles.current.set(identity, {
349
+ ...previous,
350
+ mounted: false
351
+ });
352
+ handlePublication.prune = true;
353
+ publishHandles();
354
+ }, [handlePublication, publishHandles]);
355
+ const reportIssues = useCallback((owner, next) => {
356
+ const key = JSON.stringify(next);
357
+ const old = issues.current.get(owner);
358
+ if (next.length) issues.current.set(owner, key);else issues.current.delete(owner);
359
+ if (!mounted.current) return;
360
+ setRegistryInvalid(issues.current.size > 0);
361
+ if (next.length && old !== key) {
362
+ coordinator.cancel('disabled');
363
+ try {
364
+ observer.current?.(next);
365
+ } catch (error) {
366
+ console.error('[LayoutDnD] Validation callback failed', error);
367
+ }
368
+ }
369
+ }, [coordinator]);
370
+ useLayoutEffect(() => {
371
+ mounted.current = true;
372
+ if (currentCanDrop.current !== canDrop || committedValue.current !== value) policyRevision.current++;
373
+ committedValue.current = value;
374
+ currentCanDrop.current = canDrop;
375
+ const nextPolicyRevision = policyRevision.current;
376
+ scheduleOnUI(() => {
377
+ const current = targetSession.get();
378
+ if (current.policyRevision !== nextPolicyRevision) targetSession.set({
379
+ ...current,
380
+ policyRevision: nextPolicyRevision
381
+ });
382
+ });
383
+ observer.current = onValidationError;
384
+ if (currentConfig.current.dragAxis !== dragAxis || currentConfig.current.delayMs !== activation?.delayMs) coordinator.cancel('input-changed');
385
+ currentConfig.current = {
386
+ dragAxis,
387
+ delayMs: activation?.delayMs
388
+ };
389
+ committedNativeSettings.current = {
390
+ key: nativeSettingsKey,
391
+ mapper: getGridItemLayout,
392
+ revision: gestureConfigRevision
393
+ };
394
+ coordinator.commit({
395
+ value,
396
+ onChange,
397
+ canDrop: checkDrop,
398
+ onDragStart,
399
+ onDragEnd: endSession,
400
+ onValidationError,
401
+ onDiagnostic,
402
+ responseTimeoutMs,
403
+ getGridItemLayout,
404
+ movementPolicy,
405
+ searchBudget,
406
+ disabled: disabled || !configValid || registryInvalid || issues.current.size > 0
407
+ });
408
+ nativeRevision.set(coordinator.getSnapshot().value?.revision ?? 0);
409
+ uiDisabled.set(coordinator.getSnapshot().disabled);
410
+ reportIssues('provider-config', configValid ? [] : [{
411
+ code: 'invalid-configuration',
412
+ message: 'Drag axis, activation delay or motion configuration is invalid.'
413
+ }]);
414
+ });
415
+ const registeredByZone = useCallback(() => new Map(Array.from(registry.current.values()).map(entry => [entry.zoneId, entry])), []);
416
+ const publishZones = useCallback(() => {
417
+ const needsTargets = coordinator.getSnapshot().phase !== 'idle' || preview.current !== null;
418
+ const entries = Array.from(registry.current.values());
419
+ const unique = entries.filter((entry, index) => entries.findIndex(other => other.zoneId === entry.zoneId) === index);
420
+ const next = unique.map(entry => entry.kind === 'list' ? {
421
+ kind: 'list',
422
+ orientation: entry.orientation,
423
+ zoneId: entry.zoneId,
424
+ revision: entry.revision,
425
+ layoutVersion: entry.layoutVersion,
426
+ ref: entry.ref,
427
+ offset: entry.offset,
428
+ contentSize: entry.contentSize,
429
+ autoScroll: entry.autoScroll,
430
+ targetIndex: needsTargets ? entry.targetIndex : undefined
431
+ } : {
432
+ kind: 'grid',
433
+ zoneId: entry.zoneId,
434
+ revision: entry.revision,
435
+ layoutVersion: entry.layoutVersion,
436
+ ref: entry.ref,
437
+ targetGrid: needsTargets ? entry.targetGrid : undefined
438
+ });
439
+ if (next.length !== publishedZones.current.length || next.some((entry, index) => !sameUiZone(entry, publishedZones.current[index]))) {
440
+ publishedZones.current = next;
441
+ zones.set(next);
442
+ }
443
+ reportIssues('duplicate-zones', entries.length === unique.length ? [] : [{
444
+ code: 'duplicate-id',
445
+ message: 'Each zone can have only one mounted sortable component.'
446
+ }]);
447
+ }, [coordinator, zones, reportIssues]);
448
+ const registerZone = useCallback((entry, identity) => {
449
+ const previous = registry.current.get(identity);
450
+ const geometryKey = entry.kind === 'grid' ? JSON.stringify([entry.geometry, entry.cells, entry.pixelRatio]) : null;
451
+ if (previous && previous.geometryKey !== geometryKey) {
452
+ const active = coordinator.getSnapshot();
453
+ if (active.sourceZoneId === entry.zoneId || active.targetZoneId === entry.zoneId) coordinator.cancel('geometry-changed');
454
+ }
455
+ const layoutVersion = (previous?.layoutVersion ?? 0) + Number(previous?.layout !== entry.layout || previous?.geometryKey !== geometryKey);
456
+ registry.current.set(identity, {
457
+ ...entry,
458
+ identity,
459
+ geometryKey,
460
+ layoutVersion,
461
+ ...(entry.kind === 'list' ? {
462
+ targetIndex: previous?.kind === 'list' && previous.layout === entry.layout ? previous.targetIndex : createListTargetIndex(entry.layout, previous?.kind === 'list' ? previous.targetIndex : undefined)
463
+ } : {
464
+ targetGrid: prepareGridTarget({
465
+ ...entry,
466
+ layoutVersion
467
+ })
468
+ })
469
+ });
470
+ publishZones();
471
+ publishPresentation();
472
+ refreshSettlement.current();
473
+ }, [coordinator, publishZones, publishPresentation]);
474
+ const unregisterZone = useCallback((zoneId, identity) => {
475
+ if (!registry.current.delete(identity)) return;
476
+ publishZones();
477
+ const current = coordinator.getSnapshot();
478
+ if (current.sourceZoneId === zoneId || current.targetZoneId === zoneId) coordinator.cancel('zone-removed');
479
+ }, [coordinator, publishZones]);
480
+ const cancel = useCallback(reason => coordinator.cancel(reason), [coordinator]);
481
+ const targetFor = useCallback(state => {
482
+ const current = coordinator.getSnapshot();
483
+ return resolveLayoutTarget(state, registeredByZone(), current.gridItemLayouts, current.movementPolicy, current.target);
484
+ }, [coordinator, registeredByZone]);
485
+ currentVisibility.current = proposal => {
486
+ const state = bridge.current.state;
487
+ return !!state && isLayoutTargetVisible(state, registeredByZone(), proposal.to, coordinator.getSnapshot().gridItemLayouts);
488
+ };
489
+ const begin = useCallback(state => {
490
+ if (!mounted.current) return;
491
+ const latest = motion.get();
492
+ if (latest.token !== state.token || latest.handleId !== state.handleId) return;
493
+ if (bridge.current.sessionId && bridge.current.token === state.token) return;
494
+ const owner = state.handleId === null ? undefined : Array.from(handles.current.values()).find(entry => entry.id === state.handleId);
495
+ const validOwner = state.handleId === null || !!owner && !owner.registration.disabled && owner.registration.itemId === state.itemId && owner.registration.zoneId === state.sourceZoneId;
496
+ const source = registeredByZone().get(state.sourceZoneId ?? '');
497
+ const measurement = state.zones.find(entry => entry.zoneId === state.sourceZoneId);
498
+ flushSettled();
499
+ const id = validOwner && state.axis === currentConfig.current.dragAxis && state.activationDelayMs === currentConfig.current.delayMs && state.configRevision === committedNativeSettings.current.revision && source && measurement?.layoutVersion === source.layoutVersion && measurement.viewport.revision === state.revision && state.itemId ? coordinator.start(state.itemId, state.revision) : null;
500
+ if (!id) {
501
+ if (owner && !owner.mounted) {
502
+ handles.current.delete(owner.identity);
503
+ publishHandles();
504
+ }
505
+ const previousToken = bridge.current.token;
506
+ const idlePresentation = lastPresentation.current;
507
+ const idleGeneration = presentationGeneration.current;
508
+ scheduleOnUI(() => {
509
+ if (motion.get().token === state.token) {
510
+ motion.set({
511
+ ...EMPTY_DND_MOTION,
512
+ token: previousToken
513
+ });
514
+ if (idlePresentation.token === previousToken) {
515
+ appliedPresentationGeneration.set(idleGeneration);
516
+ presentation.set(idlePresentation);
517
+ }
518
+ }
519
+ });
520
+ return;
521
+ }
522
+ bridge.current = {
523
+ token: state.token,
524
+ sessionId: id,
525
+ state,
526
+ policyRevision: policyRevision.current
527
+ };
528
+ preview.current = {
529
+ token: state.token,
530
+ item: coordinator.getSnapshot().value.items.find(item => item.id === state.itemId),
531
+ sessionId: id,
532
+ sourceZoneId: state.sourceZoneId,
533
+ render: source.renderItem,
534
+ index: source.kind === 'list' ? source.layout.entries.find(entry => entry.itemId === state.itemId)?.index ?? 0 : source.layout.placements.findIndex(entry => entry.itemId === state.itemId),
535
+ width: state.width,
536
+ height: state.height
537
+ };
538
+ setRetainedPreview(preview.current);
539
+ publishZones();
540
+ const initial = targetFor(state);
541
+ // A zone measured before its registered layout reached the UI has no
542
+ // position to offer yet; the first pointer packet supplies it.
543
+ if (initial.target !== null || !initial.stale) coordinator.requestTarget(id, state.seq, initial.target);
544
+ const current = coordinator.getSnapshot();
545
+ const gridItems = {};
546
+ for (const [zoneId, recipe] of current.gridItemLayouts) gridItems[`#${zoneId}`] = recipe;
547
+ const prepared = {
548
+ token: state.token,
549
+ policyRevision: policyRevision.current,
550
+ gridItems,
551
+ movementPolicy: current.movementPolicy
552
+ };
553
+ const target = current.target ? copyLayoutTarget(current.target) : null;
554
+ scheduleOnUI(() => {
555
+ if (motion.get().token !== state.token) return;
556
+ targetSession.set(prepared);
557
+ sentTarget.set({
558
+ state,
559
+ target,
560
+ policyRevision: prepared.policyRevision
561
+ });
562
+ });
563
+ publishPresentation();
564
+ }, [coordinator, motion, presentation, appliedPresentationGeneration, publishHandles, registeredByZone, targetFor, targetSession, sentTarget, publishPresentation, publishZones, flushSettled]);
565
+ const move = useCallback(state => {
566
+ try {
567
+ const active = bridge.current;
568
+ if (!mounted.current || active.token !== state.token || !active.sessionId) return;
569
+ // A queued move can reach JS after the finger has already lifted.
570
+ // Release validates its own final geometry; rendering this old preview
571
+ // first only delays that validation behind another React commit.
572
+ if (uiDragToken.get() !== state.token) return;
573
+ if (!Number.isSafeInteger(state.seq) || active.state && state.seq <= active.state.seq) return;
574
+ if (geometryResized(active.state, state)) {
575
+ coordinator.cancel('geometry-changed');
576
+ return;
577
+ }
578
+ const resolved = targetFor(state);
579
+ // The UI measured this zone before the layout version registered by
580
+ // the last candidate reached it. Publishing an outside target here
581
+ // would revert and re-apply the preview once per target change; keep
582
+ // the current target until a packet with the new version arrives.
583
+ if (resolved.target === null && resolved.stale) return;
584
+ const refresh = targetEnvironmentChanged(active.state, state) || active.policyRevision !== policyRevision.current;
585
+ active.state = state;
586
+ active.policyRevision = policyRevision.current;
587
+ coordinator.requestTarget(active.sessionId, state.seq, resolved.target, {
588
+ refresh
589
+ });
590
+ } finally {
591
+ const {
592
+ token: completedToken,
593
+ seq
594
+ } = state;
595
+ scheduleOnUI(() => {
596
+ const pending = pendingMove.get();
597
+ if (pending?.token === completedToken && pending.seq === seq) pendingMove.set(null);
598
+ });
599
+ }
600
+ }, [coordinator, targetFor, pendingMove, uiDragToken]);
601
+ const release = useCallback((state, cancelled) => {
602
+ const active = bridge.current;
603
+ if (!mounted.current || active.token !== state.token || !active.sessionId) return;
604
+ if (cancelled) {
605
+ active.state = state;
606
+ coordinator.cancel(typeof cancelled === 'string' ? cancelled : 'gesture-interrupted');
607
+ return;
608
+ }
609
+ if (geometryResized(active.state, state)) {
610
+ active.state = state;
611
+ coordinator.cancel('geometry-changed');
612
+ return;
613
+ }
614
+ let finalState = state;
615
+ const registrations = registeredByZone();
616
+ const measurementsChanged = state.zones.some(measured => {
617
+ const current = registrations.get(measured.zoneId);
618
+ return current?.revision === state.revision && current.layoutVersion !== measured.layoutVersion;
619
+ });
620
+ if (measurementsChanged) {
621
+ // A native size event may commit after onDeactivate captured viewports,
622
+ // but before its queued RN release runs. Refresh that one snapshot;
623
+ // accepting the old layout version would bypass final target validation.
624
+ const measureZones = Array.from(registrations.values(), entry => entry.kind === 'list' ? {
625
+ kind: 'list',
626
+ zoneId: entry.zoneId,
627
+ orientation: entry.orientation,
628
+ revision: entry.revision,
629
+ layoutVersion: entry.layoutVersion,
630
+ ref: entry.ref,
631
+ offset: entry.offset,
632
+ contentSize: entry.contentSize
633
+ } : {
634
+ kind: 'grid',
635
+ zoneId: entry.zoneId,
636
+ revision: entry.revision,
637
+ layoutVersion: entry.layoutVersion,
638
+ ref: entry.ref
639
+ });
640
+ const refreshed = runOnUISync(() => {
641
+ 'worklet';
642
+
643
+ const root = measureDndRect(rootRef);
644
+ if (!root) return null;
645
+ const next = {
646
+ ...state,
647
+ root,
648
+ zones: readListViewports(measureZones)
649
+ };
650
+ const native = motion.get();
651
+ if (native.token === state.token && native.phase === 'released' && native.seq === state.seq) motion.set(next);
652
+ return next;
653
+ });
654
+ if (!refreshed) {
655
+ coordinator.cancel('measure-failed');
656
+ return;
657
+ }
658
+ if (geometryResized(state, refreshed) || geometryResized(active.state, refreshed)) {
659
+ coordinator.cancel('geometry-changed');
660
+ return;
661
+ }
662
+ finalState = refreshed;
663
+ }
664
+ active.state = finalState;
665
+ const final = targetFor(finalState);
666
+ // Release keeps the target the user saw when only the layout version
667
+ // published to the UI lags behind; the engine validates the index.
668
+ coordinator.release(active.sessionId, finalState.seq, final.target === null && final.stale ? coordinator.getSnapshot().target : final.target);
669
+ }, [coordinator, targetFor, registeredByZone, motion, rootRef]);
670
+ const prepareRelease = useCallback(state => {
671
+ 'worklet';
672
+
673
+ if (durationMs <= 0 || uiDisabled.get() || settlement.get() || geometryResized(motion.get(), state)) return;
674
+ const approved = presentation.get();
675
+ const releaseTarget = approved.releaseTarget;
676
+ const prepared = targetSession.get();
677
+ const registered = zones.get();
678
+ // Continue the already validated preview immediately on UI. Final
679
+ // policy checks and asynchronous approval still gate the handoff.
680
+ if (releaseTarget && state.itemId !== null && approved.token === state.token && approved.revision === state.revision && prepared.token === state.token && releaseTarget.policyRevision === prepared.policyRevision && (releaseTarget.releasedSeq === state.seq || sameLayoutTarget(releaseTarget.target, uiLayoutTarget(state, registered, prepared, releaseTarget.target)))) {
681
+ const zone = registered.find(entry => entry.zoneId === releaseTarget.target.zoneId);
682
+ const contentRect = presentationRect(approved, releaseTarget.target.zoneId, state.itemId);
683
+ if (zone && contentRect) {
684
+ const next = {
685
+ token: state.token,
686
+ itemId: state.itemId,
687
+ revision: state.revision,
688
+ from: {
689
+ x: state.pointer.x - state.grip.x - state.root.x,
690
+ y: state.pointer.y - state.grip.y - state.root.y,
691
+ width: state.width,
692
+ height: state.height
693
+ },
694
+ destination: null,
695
+ zone,
696
+ contentRect,
697
+ itemRef: null,
698
+ startedAt: null,
699
+ animationStartedAt: null,
700
+ animating: false,
701
+ done: false,
702
+ committed: false
703
+ };
704
+ settlement.set(next);
705
+ }
706
+ }
707
+ }, [durationMs, uiDisabled, settlement, presentation, targetSession, zones, motion]);
708
+ useLayoutEffect(() => {
709
+ prepareReleaseRef.current = prepareRelease;
710
+ }, [prepareRelease]);
711
+ const gestureRuntime = useMemo(() => ({
712
+ motion,
713
+ frameDriven: true,
714
+ token,
715
+ zones,
716
+ disabled: uiDisabled,
717
+ enabled: uiEnabled,
718
+ rootRef,
719
+ begin,
720
+ move,
721
+ release,
722
+ prepareRelease,
723
+ dragAxis,
724
+ revision: nativeRevision,
725
+ activationDelayMs: configValid ? activation.delayMs : 0,
726
+ gestureConfigRevision
727
+ }), [motion, token, zones, uiDisabled, uiEnabled, rootRef, begin, move, release, prepareRelease, dragAxis, nativeRevision, configValid, activation?.delayMs, gestureConfigRevision]);
728
+ const finishPreview = useCallback(finishedToken => {
729
+ if (bridge.current.token !== finishedToken) return;
730
+ const native = motion.get();
731
+ if (native.phase !== 'idle' && native.token !== finishedToken) return;
732
+ bridge.current.sessionId = null;
733
+ settlingToken.current = null;
734
+ settlingRevision.current = null;
735
+ preview.current = null;
736
+ setRetainedPreview(null);
737
+ publishZones();
738
+ publishPresentation();
739
+ let removed = false;
740
+ for (const [identity, owner] of handles.current) {
741
+ if (!owner.mounted) {
742
+ handles.current.delete(identity);
743
+ removed = true;
744
+ }
745
+ }
746
+ if (removed) publishHandles();
747
+ flushSettled();
748
+ }, [motion, publishHandles, publishZones, publishPresentation, flushSettled]);
749
+ refreshSettlement.current = () => {
750
+ const retained = preview.current;
751
+ const current = coordinator.getSnapshot();
752
+ if (!retained || settlingToken.current !== retained.token || current.phase !== 'idle') return;
753
+ const zone = current.value?.zones.find(entry => entry.kind === 'list' ? entry.itemIds.includes(retained.item.id) : entry.placements.some(item => item.itemId === retained.item.id));
754
+ const registration = zone && Array.from(registry.current.values()).find(entry => entry.zoneId === zone.id && entry.revision === current.value?.revision);
755
+ let contentRect = null;
756
+ if (registration?.kind === 'list' && zone?.kind === 'list') {
757
+ contentRect = registration.layout.entries.find(entry => entry.itemId === retained.item.id)?.rect ?? null;
758
+ } else if (registration?.kind === 'grid' && zone?.kind === 'grid') {
759
+ const placement = zone.placements.find(entry => entry.itemId === retained.item.id);
760
+ if (placement) contentRect = itemRect(placement.position, placement.span, registration.geometry, registration.cells);
761
+ }
762
+ const uiZone = publishedZones.current.find(entry => entry.zoneId === zone?.id) ?? null;
763
+ const owner = Array.from(handles.current.values()).find(entry => entry.mounted && entry.registration.itemId === retained.item.id && entry.registration.zoneId === zone?.id);
764
+ const itemRef = owner?.registration.sourceRef ?? null;
765
+ const ownerToken = retained.token;
766
+ scheduleOnUI(() => {
767
+ const work = settlement.get();
768
+ if (work?.token === ownerToken) {
769
+ settlement.set({
770
+ ...work,
771
+ zone: uiZone,
772
+ contentRect,
773
+ itemRef
774
+ });
775
+ }
776
+ });
777
+ };
778
+ useFrameCallback(useCallback(info => {
779
+ 'worklet';
780
+
781
+ const state = motion.get();
782
+ const work = settlement.get();
783
+ if (work && work.token === state.token) {
784
+ const startedAt = work.startedAt ?? info.timestamp;
785
+ if (work.startedAt === null) settlement.set({
786
+ ...work,
787
+ startedAt
788
+ });
789
+ const root = measureDndRect(rootRef);
790
+ const viewport = work.zone ? measureDndRect(work.zone.ref) : null;
791
+ const nativeRect = work.itemRef ? measureDndRect(work.itemRef) : null;
792
+ const offset = work.zone?.kind === 'list' ? work.zone.offset.get() : 0;
793
+ const geometry = root && viewport && work.contentRect && work.zone?.revision === work.revision ? {
794
+ root,
795
+ viewport,
796
+ contentRect: work.contentRect,
797
+ nativeRect,
798
+ scrollOffset: work.zone.kind === 'list' && work.zone.orientation === 'horizontal' ? {
799
+ x: offset,
800
+ y: 0
801
+ } : {
802
+ x: 0,
803
+ y: offset
804
+ },
805
+ pixelRatio
806
+ } : null;
807
+ const destination = geometry ? settlementTarget(geometry) : null;
808
+ const ready = geometry ? settlementDestination(geometry) : null;
809
+ if (work.committed && (geometry && !destination || root && (root.width !== state.root.width || root.height !== state.root.height) || info.timestamp - startedAt > (work.animating ? durationMs + 750 : 750))) {
810
+ cancelAnimation(settleProgress);
811
+ settlement.set(null);
812
+ motion.set({
813
+ ...EMPTY_DND_MOTION,
814
+ token: work.token
815
+ });
816
+ scheduleOnRN(finishPreview, work.token);
817
+ } else if (destination && !work.animating) {
818
+ settlement.set({
819
+ ...work,
820
+ startedAt,
821
+ animationStartedAt: info.timestamp,
822
+ destination,
823
+ animating: true
824
+ });
825
+ settleProgress.set(0);
826
+ settleProgress.set(withTiming(1, {
827
+ duration: durationMs,
828
+ reduceMotion: reduceMotion
829
+ }, finished => {
830
+ const latest = settlement.get();
831
+ if (finished && latest?.token === work.token) settlement.set({
832
+ ...latest,
833
+ done: true
834
+ });
835
+ }));
836
+ } else if (destination && work.animating && work.destination && (Math.abs(destination.x - work.destination.x) > 1 / pixelRatio || Math.abs(destination.y - work.destination.y) > 1 / pixelRatio || Math.abs(destination.width - work.destination.width) > 1 / pixelRatio || Math.abs(destination.height - work.destination.height) > 1 / pixelRatio)) {
837
+ const progress = settleProgress.get();
838
+ const from = interpolateSettlementRect(work.from, work.destination, progress) ?? work.from;
839
+ cancelAnimation(settleProgress);
840
+ settlement.set({
841
+ ...work,
842
+ startedAt,
843
+ from,
844
+ destination,
845
+ done: false,
846
+ animationStartedAt: work.done ? info.timestamp : work.animationStartedAt
847
+ });
848
+ settleProgress.set(0);
849
+ settleProgress.set(withTiming(1, {
850
+ duration: work.done ? durationMs : Math.max(0, durationMs - (info.timestamp - (work.animationStartedAt ?? startedAt))),
851
+ reduceMotion: reduceMotion
852
+ }, finished => {
853
+ const latest = settlement.get();
854
+ if (finished && latest?.token === work.token) settlement.set({
855
+ ...latest,
856
+ done: true
857
+ });
858
+ }));
859
+ } else if (work.committed && ready && work.done) {
860
+ cancelAnimation(settleProgress);
861
+ settlement.set(null);
862
+ motion.set({
863
+ ...EMPTY_DND_MOTION,
864
+ token: work.token
865
+ });
866
+ scheduleOnRN(finishPreview, work.token);
867
+ }
868
+ return;
869
+ }
870
+ if (state.phase !== 'dragging' || uiDisabled.get()) return;
871
+ const registered = zones.get();
872
+ // Gesture events update the pointer only. One frame owns native geometry,
873
+ // target lookup, and auto-scroll, including a stationary pointer scrolling.
874
+ const root = measureDndRect(rootRef);
875
+ const measured = root ? readListViewports(registered) : [];
876
+ let next = {
877
+ ...state,
878
+ root: root ?? state.root,
879
+ zones: measured
880
+ };
881
+ if (targetEnvironmentChanged(state, next)) {
882
+ next = {
883
+ ...next,
884
+ seq: state.seq + 1
885
+ };
886
+ motion.set(next);
887
+ }
888
+ const prepared = targetSession.get();
889
+ if (prepared.token === state.token) {
890
+ const sent = sentTarget.get();
891
+ const target = uiLayoutTarget(next, registered, prepared, sent.target);
892
+ if (pendingMove.get()?.token !== next.token && (!sent.state || sent.state.token !== next.token || !sameLayoutTarget(sent.target, target) || targetEnvironmentChanged(sent.state, next) || sent.policyRevision !== prepared.policyRevision)) {
893
+ if (sent.state && next.seq <= sent.state.seq) {
894
+ next = {
895
+ ...next,
896
+ seq: sent.state.seq + 1
897
+ };
898
+ motion.set(next);
899
+ }
900
+ sentTarget.set({
901
+ state: next,
902
+ target,
903
+ policyRevision: prepared.policyRevision
904
+ });
905
+ pendingMove.set({
906
+ token: next.token,
907
+ seq: next.seq
908
+ });
909
+ scheduleOnRN(move, next);
910
+ }
911
+ }
912
+ if (!root) return;
913
+ if (!pointInRect(state.pointer, root)) return;
914
+ for (const viewport of measured) {
915
+ if (!pointInRect(state.pointer, viewport.viewport.rect)) continue;
916
+ const list = registered.find(entry => entry.zoneId === viewport.zoneId);
917
+ if (!list || list.kind !== 'list') break;
918
+ const vertical = list.orientation === 'vertical';
919
+ const result = computeAutoScroll({
920
+ pointer: vertical ? state.pointer.y : state.pointer.x,
921
+ viewportStart: vertical ? viewport.viewport.rect.y : viewport.viewport.rect.x,
922
+ viewportSize: vertical ? viewport.viewport.rect.height : viewport.viewport.rect.width,
923
+ offset: viewport.offset,
924
+ contentSize: list.contentSize,
925
+ deltaTimeMs: info.timeSincePreviousFrame ?? 0,
926
+ options: list.autoScroll
927
+ });
928
+ if (result.valid && result.velocity !== 0) scrollTo(list.ref, vertical ? 0 : result.offset, vertical ? result.offset : 0, false);
929
+ break;
930
+ }
931
+ }, [motion, settlement, rootRef, settleProgress, durationMs, reduceMotion, pixelRatio, finishPreview, uiDisabled, zones, targetSession, sentTarget, pendingMove, move]));
932
+ useLayoutEffect(() => {
933
+ const active = bridge.current;
934
+ if (snapshot.phase === 'idle') {
935
+ const previousToken = active.token;
936
+ const native = motion.get();
937
+ const retained = preview.current;
938
+ active.sessionId = null;
939
+ if (retained && native.visible && native.token === previousToken && durationMs > 0 && !snapshot.disabled && (settlingRevision.current === null || settlingRevision.current === snapshot.value?.revision)) {
940
+ if (settlingToken.current !== previousToken) {
941
+ settlingToken.current = previousToken;
942
+ settlingRevision.current = snapshot.value?.revision ?? native.revision;
943
+ const next = {
944
+ token: previousToken,
945
+ itemId: retained.item.id,
946
+ revision: snapshot.value?.revision ?? native.revision,
947
+ from: {
948
+ x: native.pointer.x - native.grip.x - native.root.x,
949
+ y: native.pointer.y - native.grip.y - native.root.y,
950
+ width: native.width,
951
+ height: native.height
952
+ },
953
+ destination: null,
954
+ zone: null,
955
+ contentRect: null,
956
+ itemRef: null,
957
+ startedAt: null,
958
+ animationStartedAt: null,
959
+ animating: false,
960
+ done: false,
961
+ committed: true
962
+ };
963
+ scheduleOnUI(() => {
964
+ if (motion.get().token !== previousToken) return;
965
+ motion.set({
966
+ ...motion.get(),
967
+ phase: 'released'
968
+ });
969
+ const current = settlement.get();
970
+ settlement.set(current?.token === previousToken && !current.committed ? {
971
+ ...current,
972
+ committed: true,
973
+ revision: next.revision,
974
+ startedAt: null,
975
+ zone: null,
976
+ contentRect: null,
977
+ itemRef: null
978
+ } : next);
979
+ });
980
+ }
981
+ refreshSettlement.current();
982
+ } else {
983
+ finishPreview(previousToken);
984
+ scheduleOnUI(() => {
985
+ if (motion.get().token !== previousToken) return;
986
+ cancelAnimation(settleProgress);
987
+ settlement.set(null);
988
+ motion.set({
989
+ ...EMPTY_DND_MOTION,
990
+ token: previousToken
991
+ });
992
+ });
993
+ }
994
+ } else if (previewReady) {
995
+ const activeToken = active.token;
996
+ scheduleOnUI(() => {
997
+ const state = motion.get();
998
+ if (state.token === activeToken && state.phase !== 'idle' && !state.visible) motion.set({
999
+ ...state,
1000
+ visible: true
1001
+ });
1002
+ });
1003
+ }
1004
+ }, [motion, snapshot, durationMs, settlement, settleProgress, finishPreview, previewReady]);
1005
+ useLayoutEffect(() => {
1006
+ mounted.current = true;
1007
+ // Child layout effects may register before the Provider is reactivated.
1008
+ publishHandles();
1009
+ return () => {
1010
+ mounted.current = false;
1011
+ handlePublication.generation++;
1012
+ handlePublication.queued = false;
1013
+ coordinator.dispose();
1014
+ flushSettled();
1015
+ scheduleOnUI(() => {
1016
+ cancelAnimation(settleProgress);
1017
+ settlement.set(null);
1018
+ motion.set(EMPTY_DND_MOTION);
1019
+ });
1020
+ };
1021
+ }, [coordinator, flushSettled, handlePublication, motion, publishHandles, settlement, settleProgress]);
1022
+ const overlayStyle = useAnimatedStyle(() => {
1023
+ const state = motion.get();
1024
+ const work = settlement.get();
1025
+ const destination = work?.destination;
1026
+ const rect = work && destination ? interpolateSettlementRect(work.from, destination, settleProgress.get()) : null;
1027
+ const x = rect?.x ?? state.pointer.x - state.grip.x - state.root.x;
1028
+ const y = rect?.y ?? state.pointer.y - state.grip.y - state.root.y;
1029
+ const width = rect?.width ?? state.width;
1030
+ const height = rect?.height ?? state.height;
1031
+ return {
1032
+ opacity: state.visible ? 1 : 0,
1033
+ width: state.width,
1034
+ height: state.height,
1035
+ transform: [{
1036
+ translateX: x + (width - state.width) / 2
1037
+ }, {
1038
+ translateY: y + (height - state.height) / 2
1039
+ }, {
1040
+ scaleX: state.width > 0 ? width / state.width : 1
1041
+ }, {
1042
+ scaleY: state.height > 0 ? height / state.height : 1
1043
+ }]
1044
+ };
1045
+ });
1046
+ const activeItem = snapshot.value?.items.find(item => item.id === (snapshot.itemId ?? retainedPreview?.item.id));
1047
+ const content = retainedPreview;
1048
+ const previewSessionId = snapshot.sessionId ?? content?.sessionId;
1049
+ const previewSourceZoneId = snapshot.sourceZoneId ?? content?.sourceZoneId;
1050
+ const runtime = useMemo(() => ({
1051
+ get snapshot() {
1052
+ return renderStore.getSnapshot();
1053
+ },
1054
+ renderStore,
1055
+ committedRevision: nativeRevision,
1056
+ motion,
1057
+ presentation,
1058
+ presentationSnapshot,
1059
+ zones,
1060
+ disabled: uiDisabled,
1061
+ token,
1062
+ rootRef,
1063
+ dragAxis,
1064
+ activationDelayMs: configValid ? activation.delayMs : 0,
1065
+ gestureConfigRevision,
1066
+ animation,
1067
+ begin,
1068
+ move,
1069
+ release,
1070
+ cancel,
1071
+ registerZone,
1072
+ unregisterZone,
1073
+ registerHandle,
1074
+ unregisterHandle,
1075
+ reportIssues
1076
+ }), [renderStore, nativeRevision, motion, presentation, presentationSnapshot, zones, uiDisabled, token, rootRef, dragAxis, configValid, activation?.delayMs, gestureConfigRevision, animation, begin, move, release, cancel, registerZone, unregisterZone, registerHandle, unregisterHandle, reportIssues]);
1077
+ return /*#__PURE__*/_jsx(DndRuntimeContext, {
1078
+ value: runtime,
1079
+ children: /*#__PURE__*/_jsx(DndGestureHost, {
1080
+ registry: gestureRegistry,
1081
+ runtime: gestureRuntime,
1082
+ children: /*#__PURE__*/_jsxs(Animated.View, {
1083
+ ...viewProps,
1084
+ ref: rootRef,
1085
+ collapsable: false,
1086
+ style: [styles.root, style],
1087
+ onLayout: event => {
1088
+ const {
1089
+ width,
1090
+ height
1091
+ } = event.nativeEvent.layout;
1092
+ if (rootLayout.current && (rootLayout.current.width !== width || rootLayout.current.height !== height)) coordinator.cancel('geometry-changed');
1093
+ rootLayout.current = {
1094
+ width,
1095
+ height
1096
+ };
1097
+ onLayout?.(event);
1098
+ },
1099
+ children: [children, activeItem && content && previewSessionId && previewSourceZoneId && /*#__PURE__*/_jsx(DndItemContext, {
1100
+ value: {
1101
+ itemId: activeItem.id,
1102
+ zoneId: previewSourceZoneId,
1103
+ ref: rootRef,
1104
+ preview: true
1105
+ },
1106
+ children: /*#__PURE__*/_jsx(Animated.View, {
1107
+ pointerEvents: "none",
1108
+ style: [styles.preview, overlayStyle, dragPreviewStyle],
1109
+ children: renderDragPreview ? renderDragPreview({
1110
+ item: activeItem,
1111
+ index: content.index,
1112
+ zoneId: previewSourceZoneId,
1113
+ isDragging: true,
1114
+ sessionId: previewSessionId,
1115
+ targetZoneId: snapshot.targetZoneId,
1116
+ validity: snapshot.validity,
1117
+ width: content.width,
1118
+ height: content.height,
1119
+ onReady: handlePreviewReady
1120
+ }) : content.render({
1121
+ item: activeItem,
1122
+ index: content.index,
1123
+ zoneId: previewSourceZoneId,
1124
+ isDragging: true
1125
+ })
1126
+ })
1127
+ })]
1128
+ })
1129
+ })
1130
+ });
1131
+ }
1132
+ const styles = StyleSheet.create({
1133
+ root: {
1134
+ position: 'relative'
1135
+ },
1136
+ preview: {
1137
+ position: 'absolute',
1138
+ left: 0,
1139
+ top: 0,
1140
+ zIndex: 1000,
1141
+ elevation: 16
1142
+ }
1143
+ });
1144
+ //# sourceMappingURL=DndProvider.js.map