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,311 @@
1
+ import {
2
+ createContext,
3
+ type ReactNode,
4
+ useContext,
5
+ useMemo,
6
+ useSyncExternalStore,
7
+ } from 'react';
8
+ import type { HostInstance } from 'react-native';
9
+ import {
10
+ measure,
11
+ type AnimatedRef,
12
+ type SharedValue,
13
+ } from 'react-native-reanimated';
14
+
15
+ import type { AutoScrollOptions, DragAxis } from '../adapters/scroll';
16
+ import type {
17
+ GridLayoutZone,
18
+ DndItem,
19
+ LayoutPoint,
20
+ LayoutRect,
21
+ ListLayoutZone,
22
+ MeasuredRect,
23
+ } from '../contracts';
24
+ import type { DndSessionSnapshot } from '../controller/dndSession';
25
+ import type { ListLayout } from '../engine/list';
26
+ import type { ListTargetIndex } from '../engine/listIndex';
27
+ import type { PreparedGridTarget } from '../pointer/layoutTarget';
28
+ import type { DndPresentation, DndZonePresentation } from './dndPresentation';
29
+ import type { LayoutValidationIssue } from '../contracts';
30
+ import type { CancelReason } from '../types';
31
+ import type { GridMotionConfig } from '../pointer/motion';
32
+ import type { ListItemRenderArgs } from '../components/dndTypes';
33
+ import type { GestureRelations, ZoneGeometry } from '../components/gridTypes';
34
+ import type { CellGeometry } from './gridRuntime';
35
+ import {
36
+ DndRenderStore,
37
+ type DndZoneSnapshot,
38
+ type RetainSlotsRule,
39
+ } from './dndRenderStore';
40
+
41
+ type UiListRegistration = {
42
+ kind: 'list';
43
+ zoneId: string;
44
+ orientation: 'vertical' | 'horizontal';
45
+ revision: number;
46
+ layoutVersion: number;
47
+ ref: AnimatedRef<HostInstance>;
48
+ offset: SharedValue<number>;
49
+ contentSize: number;
50
+ autoScroll?: AutoScrollOptions;
51
+ targetIndex?: ListTargetIndex;
52
+ };
53
+ type UiGridRegistration = {
54
+ kind: 'grid';
55
+ zoneId: string;
56
+ revision: number;
57
+ layoutVersion: number;
58
+ ref: AnimatedRef<HostInstance>;
59
+ targetGrid?: PreparedGridTarget;
60
+ };
61
+ export type UiZoneRegistration = UiListRegistration | UiGridRegistration;
62
+ export type ListRegistration = Omit<UiListRegistration, 'layoutVersion'> & {
63
+ layout: ListLayout;
64
+ dataIdentity?: readonly DndItem<unknown>[];
65
+ prepareDisplay?(
66
+ zone: ListLayoutZone,
67
+ revision: number,
68
+ ): DndZonePresentation | null;
69
+ renderItem(args: ListItemRenderArgs<unknown>): ReactNode;
70
+ };
71
+ export type GridRegistration = Omit<UiGridRegistration, 'layoutVersion'> & {
72
+ layout: GridLayoutZone;
73
+ geometry: ZoneGeometry;
74
+ cells: CellGeometry;
75
+ pixelRatio: number;
76
+ renderItem(args: ListItemRenderArgs<unknown>): ReactNode;
77
+ };
78
+ export type ZoneRegistration = ListRegistration | GridRegistration;
79
+ export type ListViewport = {
80
+ zoneId: string;
81
+ viewport: MeasuredRect<'screen'>;
82
+ offset: number;
83
+ layoutVersion: number;
84
+ };
85
+ export type DndMotion = {
86
+ token: number;
87
+ /** Provider-owned native recognizer; independent of virtual cell lifetime. */
88
+ handleId: number | null;
89
+ seq: number;
90
+ phase: 'idle' | 'dragging' | 'released';
91
+ itemId: string | null;
92
+ sourceZoneId: string | null;
93
+ revision: number;
94
+ pointer: LayoutPoint;
95
+ origin: LayoutPoint;
96
+ axis: DragAxis;
97
+ activationDelayMs: number;
98
+ configRevision: number;
99
+ grip: LayoutPoint;
100
+ width: number;
101
+ height: number;
102
+ root: LayoutRect;
103
+ zones: ListViewport[];
104
+ visible: boolean;
105
+ };
106
+ export const EMPTY_DND_MOTION: DndMotion = {
107
+ token: 0,
108
+ handleId: null,
109
+ seq: 0,
110
+ phase: 'idle',
111
+ itemId: null,
112
+ sourceZoneId: null,
113
+ revision: 0,
114
+ pointer: { x: 0, y: 0 },
115
+ origin: { x: 0, y: 0 },
116
+ axis: 'both',
117
+ activationDelayMs: 250,
118
+ configRevision: 0,
119
+ grip: { x: 0, y: 0 },
120
+ width: 0,
121
+ height: 0,
122
+ root: { x: 0, y: 0, width: 0, height: 0 },
123
+ zones: [],
124
+ visible: false,
125
+ };
126
+ export type DndRuntime = {
127
+ snapshot: DndSessionSnapshot<unknown>;
128
+ renderStore?: DndRenderStore;
129
+ motion: SharedValue<DndMotion>;
130
+ presentation?: SharedValue<DndPresentation>;
131
+ /** JS view of the presentation most recently scheduled for the UI runtime. */
132
+ presentationSnapshot?(): DndPresentation;
133
+ /** Shared committed revision keeps unchanged cell worklets stable on approval. */
134
+ committedRevision?: SharedValue<number>;
135
+ /** Provider frame owns measurements and semantic dispatch when enabled. */
136
+ frameDriven?: boolean;
137
+ zones: SharedValue<UiZoneRegistration[]>;
138
+ disabled: SharedValue<boolean>;
139
+ token: SharedValue<number>;
140
+ rootRef: AnimatedRef<HostInstance>;
141
+ dragAxis: DragAxis;
142
+ activationDelayMs: number;
143
+ gestureConfigRevision: number;
144
+ animation: Required<GridMotionConfig>;
145
+ begin(state: DndMotion): void;
146
+ move(state: DndMotion): void;
147
+ release(state: DndMotion, cancelled: boolean | CancelReason): void;
148
+ cancel(reason: CancelReason): void;
149
+ registerZone(registration: ZoneRegistration, identity: object): void;
150
+ unregisterZone(zoneId: string, identity: object): void;
151
+ registerHandle(registration: DndHandleRegistration, identity: object): void;
152
+ unregisterHandle(identity: object): void;
153
+ reportIssues(owner: string, issues: LayoutValidationIssue[]): void;
154
+ };
155
+ export type DndHandleRegistration = {
156
+ itemId: string;
157
+ zoneId: string;
158
+ ref: AnimatedRef<HostInstance>;
159
+ sourceRef: AnimatedRef<HostInstance>;
160
+ disabled: boolean;
161
+ gestureRelations?: GestureRelations;
162
+ };
163
+ export const DndRuntimeContext = createContext<DndRuntime | null>(null);
164
+ export const DndItemContext = createContext<{
165
+ itemId: string;
166
+ zoneId: string;
167
+ ref: AnimatedRef<HostInstance>;
168
+ preview?: boolean;
169
+ } | null>(null);
170
+ export function useDndRuntime(): DndRuntime {
171
+ const runtime = useContext(DndRuntimeContext);
172
+ if (!runtime)
173
+ throw new Error(
174
+ 'SortableList, SortableGrid and DragHandle must be inside DndProvider.',
175
+ );
176
+ return runtime;
177
+ }
178
+
179
+ function renderStoreFor(runtime: DndRuntime): DndRenderStore {
180
+ return (
181
+ runtime.renderStore ??
182
+ new DndRenderStore({
183
+ getSnapshot: () => runtime.snapshot,
184
+ subscribe: () => () => {},
185
+ })
186
+ );
187
+ }
188
+
189
+ const inactiveHandleSelection = {
190
+ get: () => false,
191
+ subscribe: (_listener: () => void) => () => {},
192
+ };
193
+
194
+ export function useDndZoneSnapshot(
195
+ runtime: DndRuntime,
196
+ zoneId: string,
197
+ preserveSlots: boolean | RetainSlotsRule = true,
198
+ ): DndZoneSnapshot {
199
+ const selection = useMemo(() => {
200
+ const store = renderStoreFor(runtime);
201
+ // Without shared presentation nothing moves retained slots on the UI
202
+ // runtime, so React must follow the candidate order itself.
203
+ const get = () =>
204
+ store.getZoneSnapshot(
205
+ zoneId,
206
+ runtime.presentation ? preserveSlots : false,
207
+ );
208
+ return {
209
+ get,
210
+ subscribe: (listener: () => void) =>
211
+ store.subscribeSelection(get, listener),
212
+ };
213
+ }, [runtime, zoneId, preserveSlots]);
214
+ return useSyncExternalStore(selection.subscribe, selection.get);
215
+ }
216
+
217
+ export function useDndHandleActive(
218
+ runtime: DndRuntime,
219
+ itemId: string | undefined,
220
+ disabled: boolean,
221
+ ): boolean {
222
+ const selection = useMemo(() => {
223
+ if (!disabled) return inactiveHandleSelection;
224
+ const store = renderStoreFor(runtime);
225
+ const get = () => store.getSnapshot().itemId === itemId;
226
+ return {
227
+ get,
228
+ subscribe: (listener: () => void) =>
229
+ store.subscribeSelection(get, listener),
230
+ };
231
+ }, [runtime, itemId, disabled]);
232
+ return useSyncExternalStore(selection.subscribe, selection.get);
233
+ }
234
+
235
+ /** Public render arguments follow approved previews independently of native slots. */
236
+ export function useDndItemSnapshot(
237
+ runtime: DndRuntime,
238
+ zoneId: string,
239
+ itemId: string,
240
+ ) {
241
+ const selection = useMemo(() => {
242
+ const store = renderStoreFor(runtime);
243
+ const get = () => store.getItemSnapshot(zoneId, itemId);
244
+ return {
245
+ get,
246
+ subscribe: (listener: () => void) =>
247
+ store.subscribeSelection(get, listener),
248
+ };
249
+ }, [runtime, zoneId, itemId]);
250
+ return useSyncExternalStore(selection.subscribe, selection.get);
251
+ }
252
+
253
+ export function measureDndRect(
254
+ ref: AnimatedRef<HostInstance>,
255
+ ): LayoutRect | null {
256
+ 'worklet';
257
+ const result = measure(ref);
258
+ if (
259
+ !result ||
260
+ ![result.pageX, result.pageY, result.width, result.height].every(
261
+ Number.isFinite,
262
+ ) ||
263
+ result.width <= 0 ||
264
+ result.height <= 0
265
+ )
266
+ return null;
267
+ return {
268
+ x: result.pageX,
269
+ y: result.pageY,
270
+ width: result.width,
271
+ height: result.height,
272
+ };
273
+ }
274
+
275
+ export function readListViewports(
276
+ zones: readonly UiZoneRegistration[],
277
+ ): ListViewport[] {
278
+ 'worklet';
279
+ const timestampMs = (
280
+ globalThis as typeof globalThis & { performance: { now(): number } }
281
+ ).performance.now();
282
+ const measured: ListViewport[] = [];
283
+ for (const zone of zones) {
284
+ const rect = measureDndRect(zone.ref);
285
+ const offset = zone.kind === 'grid' ? 0 : zone.offset.get();
286
+ if (rect && Number.isFinite(offset))
287
+ measured.push({
288
+ zoneId: zone.zoneId,
289
+ offset,
290
+ layoutVersion: zone.layoutVersion,
291
+ viewport: {
292
+ source: 'measured',
293
+ space: 'screen',
294
+ rect,
295
+ revision: zone.revision,
296
+ timestampMs,
297
+ },
298
+ });
299
+ }
300
+ return measured;
301
+ }
302
+
303
+ export function pointInRect(point: LayoutPoint, rect: LayoutRect): boolean {
304
+ 'worklet';
305
+ return (
306
+ point.x >= rect.x &&
307
+ point.x <= rect.x + rect.width &&
308
+ point.y >= rect.y &&
309
+ point.y <= rect.y + rect.height
310
+ );
311
+ }
@@ -0,0 +1,117 @@
1
+ import type { LayoutPoint, LayoutRect } from '../contracts';
2
+
3
+ import { isUsableRect } from '../pointer/geometry';
4
+
5
+ type SettlementGeometry = {
6
+ /** Root and viewport use screen coordinates; contentRect excludes scrolling. */
7
+ root: LayoutRect;
8
+ viewport: LayoutRect;
9
+ contentRect: LayoutRect;
10
+ nativeRect: LayoutRect | null;
11
+ scrollOffset: LayoutPoint;
12
+ pixelRatio?: number;
13
+ };
14
+
15
+ function containsPixels(
16
+ outer: LayoutRect,
17
+ inner: LayoutRect,
18
+ pixelRatio: number,
19
+ ): boolean {
20
+ 'worklet';
21
+ return (
22
+ Math.round(inner.x * pixelRatio) >= Math.round(outer.x * pixelRatio) &&
23
+ Math.round(inner.y * pixelRatio) >= Math.round(outer.y * pixelRatio) &&
24
+ Math.round((inner.x + inner.width) * pixelRatio) <=
25
+ Math.round((outer.x + outer.width) * pixelRatio) &&
26
+ Math.round((inner.y + inner.height) * pixelRatio) <=
27
+ Math.round((outer.y + outer.height) * pixelRatio)
28
+ );
29
+ }
30
+
31
+ /** Resolve the committed logical slot without waiting for a native cell. */
32
+ export function settlementTarget({
33
+ root,
34
+ viewport,
35
+ contentRect,
36
+ scrollOffset,
37
+ pixelRatio = 1,
38
+ }: Omit<SettlementGeometry, 'nativeRect'>): LayoutRect | null {
39
+ 'worklet';
40
+ if (
41
+ !isUsableRect(root) ||
42
+ !isUsableRect(viewport) ||
43
+ !isUsableRect(contentRect) ||
44
+ !Number.isFinite(scrollOffset.x) ||
45
+ !Number.isFinite(scrollOffset.y) ||
46
+ !Number.isFinite(pixelRatio) ||
47
+ pixelRatio <= 0
48
+ )
49
+ return null;
50
+ const expected = {
51
+ x: viewport.x + contentRect.x - scrollOffset.x,
52
+ y: viewport.y + contentRect.y - scrollOffset.y,
53
+ width: contentRect.width,
54
+ height: contentRect.height,
55
+ };
56
+ if (
57
+ !isUsableRect(expected) ||
58
+ !containsPixels(viewport, expected, pixelRatio) ||
59
+ !containsPixels(root, expected, pixelRatio)
60
+ )
61
+ return null;
62
+ return { ...expected, x: expected.x - root.x, y: expected.y - root.y };
63
+ }
64
+
65
+ /** Native alignment gates only the final handoff, not the overlay animation. */
66
+ export function settlementDestination({
67
+ root,
68
+ viewport,
69
+ contentRect,
70
+ nativeRect,
71
+ scrollOffset,
72
+ pixelRatio = 1,
73
+ }: SettlementGeometry): LayoutRect | null {
74
+ 'worklet';
75
+ const target = settlementTarget({
76
+ root,
77
+ viewport,
78
+ contentRect,
79
+ scrollOffset,
80
+ pixelRatio,
81
+ });
82
+ if (!target || !isUsableRect(nativeRect)) return null;
83
+ const tolerance = 1 / pixelRatio;
84
+ if (
85
+ Math.abs(nativeRect.x - root.x - target.x) > tolerance ||
86
+ Math.abs(nativeRect.y - root.y - target.y) > tolerance ||
87
+ Math.abs(nativeRect.width - target.width) > tolerance ||
88
+ Math.abs(nativeRect.height - target.height) > tolerance ||
89
+ !containsPixels(viewport, nativeRect, pixelRatio) ||
90
+ !containsPixels(root, nativeRect, pixelRatio)
91
+ )
92
+ return null;
93
+ return {
94
+ x: nativeRect.x - root.x,
95
+ y: nativeRect.y - root.y,
96
+ width: nativeRect.width,
97
+ height: nativeRect.height,
98
+ };
99
+ }
100
+
101
+ /** Both rectangles use root coordinates; progress is the native animation value. */
102
+ export function interpolateSettlementRect(
103
+ from: LayoutRect,
104
+ to: LayoutRect,
105
+ progress: number,
106
+ ): LayoutRect | null {
107
+ 'worklet';
108
+ if (!isUsableRect(from) || !isUsableRect(to) || !Number.isFinite(progress))
109
+ return null;
110
+ const amount = Math.max(0, Math.min(1, progress));
111
+ return {
112
+ x: from.x + (to.x - from.x) * amount,
113
+ y: from.y + (to.y - from.y) * amount,
114
+ width: from.width + (to.width - from.width) * amount,
115
+ height: from.height + (to.height - from.height) * amount,
116
+ };
117
+ }
@@ -0,0 +1,73 @@
1
+ import type { HostInstance } from 'react-native';
2
+ import type { AnimatedRef } from 'react-native-reanimated';
3
+
4
+ import type { GridMovementPolicy } from '../engine/movementPolicy';
5
+ import type { CellSpan, GridZone, ItemLocation } from '../types';
6
+
7
+ import type { ZoneGeometry } from '../components/gridTypes';
8
+
9
+ /**
10
+ * Geometry vocabulary of the grid pointer policy (`pointer/geometry.ts`),
11
+ * shared by the provider's layout targeting. The React runtime of the former
12
+ * grid controller no longer lives here.
13
+ */
14
+
15
+ export type WindowRect = {
16
+ x: number;
17
+ y: number;
18
+ width: number;
19
+ height: number;
20
+ };
21
+ export type CellGeometry = { cellWidth: number; cellHeight: number };
22
+ export type ZoneRegistration = {
23
+ zone: GridZone<undefined>;
24
+ geometry: ZoneGeometry;
25
+ pixelRatio: number;
26
+ ref: AnimatedRef<HostInstance>;
27
+ };
28
+ export type MeasuredZone = Omit<ZoneRegistration, 'ref'> & {
29
+ rect: WindowRect;
30
+ cells: CellGeometry;
31
+ };
32
+ export type UiMotion = {
33
+ movementPolicy?: GridMovementPolicy;
34
+ baseRevision?: number;
35
+ token: number;
36
+ phase: 'idle' | 'dragging' | 'finalizing' | 'settling' | 'handoff';
37
+ itemId: string | null;
38
+ sourceZoneId: string | null;
39
+ seq: number;
40
+ target: ItemLocation | null;
41
+ span: CellSpan;
42
+ x: number;
43
+ y: number;
44
+ width: number;
45
+ height: number;
46
+ gripX: number;
47
+ gripY: number;
48
+ zones: MeasuredZone[];
49
+ outlet: WindowRect;
50
+ validity: 'pending' | 'valid' | 'invalid';
51
+ visible: boolean;
52
+ destination: WindowRect | null;
53
+ };
54
+ export const EMPTY_MOTION: UiMotion = {
55
+ token: 0,
56
+ phase: 'idle',
57
+ itemId: null,
58
+ sourceZoneId: null,
59
+ seq: 0,
60
+ target: null,
61
+ span: { rows: 1, cols: 1 },
62
+ x: 0,
63
+ y: 0,
64
+ width: 0,
65
+ height: 0,
66
+ gripX: 0,
67
+ gripY: 0,
68
+ zones: [],
69
+ outlet: { x: 0, y: 0, width: 0, height: 0 },
70
+ validity: 'pending',
71
+ visible: false,
72
+ destination: null,
73
+ };
package/src/types.ts ADDED
@@ -0,0 +1,189 @@
1
+ import type { MoveProposal, ProposalResponse } from './contracts';
2
+
3
+ import type { GridMovementPolicy } from './engine/movementPolicy';
4
+
5
+ export type CellPosition = { row: number; col: number };
6
+ export type CellSpan = { rows: number; cols: number };
7
+ /** Optional JS diagnostics; durations are not native rendering or GPU timings. */
8
+ export type GridDiagnosticEvent =
9
+ | {
10
+ type: 'timing';
11
+ name:
12
+ 'compute-move' | 'input-validation' | 'candidate-validation' | 'policy';
13
+ durationMs: number;
14
+ sessionId?: string;
15
+ attempts?: number;
16
+ status?: string;
17
+ }
18
+ | {
19
+ type: 'lifecycle';
20
+ name:
21
+ | 'request'
22
+ | 'request-coalesced'
23
+ | 'release'
24
+ | 'proposal'
25
+ | 'response'
26
+ | 'settling'
27
+ | 'end';
28
+ timestampMs: number;
29
+ sessionId: string;
30
+ };
31
+ export type ItemPlacement = 'insert' | 'exchange';
32
+ export type GridItem<T> = {
33
+ id: string;
34
+ span: CellSpan;
35
+ /** Caller-selected spatial behavior. Omitted means exchange, regardless of size. */
36
+ placement?: ItemPlacement;
37
+ data: T;
38
+ };
39
+ export type PositionedItem<T> = GridItem<T> & { position: CellPosition };
40
+
41
+ export type SpatialZone<T> = {
42
+ id: string;
43
+ rows: number;
44
+ columns: number;
45
+ strategy: 'spatial';
46
+ items: PositionedItem<T>[];
47
+ };
48
+ export type OrderedZone<T> = {
49
+ id: string;
50
+ rows: number;
51
+ columns: number;
52
+ strategy: 'ordered';
53
+ itemSpan: CellSpan;
54
+ items: GridItem<T>[];
55
+ };
56
+ export type GridZone<T> = SpatialZone<T> | OrderedZone<T>;
57
+ export type GridValue<T> = {
58
+ zones: GridZone<T>[];
59
+ /** Increment on every external data/layout edit. Omit only for legacy control. */
60
+ revision?: number;
61
+ proposalResponse?: Omit<ProposalResponse, 'baseRevision'> & {
62
+ baseRevision?: number;
63
+ };
64
+ };
65
+
66
+ export type RevisionedGridValue<T> = GridValue<T> & { revision: number };
67
+ export type GridProposal<T> = MoveProposal<
68
+ RevisionedGridValue<T>,
69
+ ItemLocation
70
+ >;
71
+
72
+ export type ValidationCode =
73
+ | 'invalid-structure'
74
+ | 'duplicate-id'
75
+ | 'invalid-dimension'
76
+ | 'invalid-span'
77
+ | 'invalid-placement'
78
+ | 'missing-item-span'
79
+ | 'span-mismatch'
80
+ | 'invalid-position'
81
+ | 'out-of-bounds'
82
+ | 'overlap'
83
+ | 'capacity-exceeded'
84
+ | 'invalid-budget'
85
+ | 'invalid-geometry'
86
+ | 'invalid-configuration';
87
+ export type ValidationIssue = {
88
+ code: ValidationCode;
89
+ zoneId?: string;
90
+ itemId?: string;
91
+ message: string;
92
+ };
93
+ export type ValidationResult =
94
+ { valid: true } | { valid: false; issues: ValidationIssue[] };
95
+ export type ZoneLayoutResult<T> =
96
+ | { valid: true; items: PositionedItem<T>[] }
97
+ | { valid: false; issues: ValidationIssue[] };
98
+ export type PackInput<T> = {
99
+ items: readonly GridItem<T>[];
100
+ rows: number;
101
+ columns: number;
102
+ searchBudget: number;
103
+ };
104
+ export type PackResult<T> =
105
+ | { status: 'ok'; placements: PositionedItem<T>[] }
106
+ | { status: 'impossible' }
107
+ | { status: 'unresolved' }
108
+ | { status: 'invalid'; issues: ValidationIssue[] };
109
+
110
+ export type ItemLocation =
111
+ | { zoneId: string; strategy: 'spatial'; position: CellPosition }
112
+ | { zoneId: string; strategy: 'ordered'; index: number };
113
+
114
+ /** A logical target, after pointer conversion and hysteresis in the controller. */
115
+ export type MoveInput<T> = {
116
+ movementPolicy?: GridMovementPolicy;
117
+ value: GridValue<T>;
118
+ itemId: string;
119
+ to: ItemLocation;
120
+ searchBudget?: number;
121
+ };
122
+ export type MoveResult<T> =
123
+ | {
124
+ status: 'ok';
125
+ value: GridValue<T>;
126
+ from: ItemLocation;
127
+ to: ItemLocation;
128
+ changed: boolean;
129
+ attempts: number;
130
+ }
131
+ | { status: 'impossible' | 'unresolved'; attempts: number }
132
+ | { status: 'invalid'; issues: ValidationIssue[] };
133
+
134
+ export type GridChange = {
135
+ sessionId: string;
136
+ /** Present when the input GridValue supplies a revision (including useGridState). */
137
+ baseRevision?: number;
138
+ itemId: string;
139
+ from: ItemLocation;
140
+ to: ItemLocation;
141
+ };
142
+ export type DragStartEvent = {
143
+ sessionId: string;
144
+ itemId: string;
145
+ sourceZoneId: string;
146
+ };
147
+ export type CanDropArgs<T> = {
148
+ item: GridItem<T>;
149
+ change: GridChange;
150
+ proposedValue: GridValue<T>;
151
+ };
152
+ export type DropDecision =
153
+ { allowed: true } | { allowed: false; reason?: string };
154
+ export type CleanupReason =
155
+ | 'input-changed'
156
+ | 'geometry-changed'
157
+ | 'zone-removed'
158
+ | 'disabled'
159
+ | 'unmounted';
160
+ /** Interruptions include every cancel reason a proposal can meet while it awaits a response. */
161
+ export type ProposalInterruptReason =
162
+ CancelReason | 'response-missing' | 'change-handler-error';
163
+ export type CancelReason =
164
+ | CleanupReason
165
+ | 'outside-zones'
166
+ | 'invalid-target'
167
+ | 'measure-failed'
168
+ | 'policy-rejected'
169
+ | 'search-budget'
170
+ | 'unresolvable'
171
+ | 'gesture-interrupted'
172
+ | 'policy-error'
173
+ | 'start-handler-error';
174
+ export type DragEndEvent = DragStartEvent & {
175
+ cleanupReason?: CleanupReason;
176
+ error?: unknown;
177
+ } & (
178
+ | { outcome: 'unchanged' }
179
+ | {
180
+ outcome: 'cancelled';
181
+ targetZoneId?: string;
182
+ reason: CancelReason;
183
+ policyReason?: string;
184
+ }
185
+ | ({ outcome: 'proposed'; change: GridChange; targetZoneId: string } & (
186
+ | { response: 'accepted' | 'rejected' | 'expired' | 'mismatch' }
187
+ | { response: 'interrupted'; reason: ProposalInterruptReason }
188
+ ))
189
+ );