react-native-gtkx 0.2.0-alpha.2 → 0.3.0-alpha.1

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/README.md +5 -2
  2. package/dist/aliases/index.d.ts +84 -0
  3. package/dist/aliases/index.js +208 -0
  4. package/dist/aliases/index.js.map +1 -0
  5. package/dist/animated/index.d.ts +2 -0
  6. package/dist/animated/index.js +5 -0
  7. package/dist/animated/index.js.map +1 -1
  8. package/dist/animated/types.d.ts +1 -0
  9. package/dist/animated/types.js.map +1 -1
  10. package/dist/animated/value-animation.js +17 -4
  11. package/dist/animated/value-animation.js.map +1 -1
  12. package/dist/apis/host.gtkx.js +9 -12
  13. package/dist/apis/host.gtkx.js.map +1 -1
  14. package/dist/apis/index.d.ts +4 -2
  15. package/dist/apis/index.js +2 -0
  16. package/dist/apis/index.js.map +1 -1
  17. package/dist/apis/keyboard.d.ts +60 -0
  18. package/dist/apis/keyboard.js +63 -0
  19. package/dist/apis/keyboard.js.map +1 -0
  20. package/dist/apis/log-box.d.ts +15 -0
  21. package/dist/apis/log-box.js +46 -0
  22. package/dist/apis/log-box.js.map +1 -0
  23. package/dist/apis/platform.d.ts +18 -1
  24. package/dist/apis/platform.js.map +1 -1
  25. package/dist/common/index.d.ts +0 -1
  26. package/dist/common/index.js +24 -1
  27. package/dist/common/index.js.map +1 -1
  28. package/dist/components/animated.d.ts +70 -6
  29. package/dist/components/animated.js +559 -46
  30. package/dist/components/animated.js.map +1 -1
  31. package/dist/components/driven-size.d.ts +27 -0
  32. package/dist/components/driven-size.js +85 -0
  33. package/dist/components/driven-size.js.map +1 -0
  34. package/dist/components/find-node-handle.d.ts +11 -0
  35. package/dist/components/find-node-handle.js +53 -0
  36. package/dist/components/find-node-handle.js.map +1 -0
  37. package/dist/components/flat-list.d.ts +3 -2
  38. package/dist/components/flat-list.js.map +1 -1
  39. package/dist/components/frame-scheduler.d.ts +16 -0
  40. package/dist/components/frame-scheduler.js +37 -0
  41. package/dist/components/frame-scheduler.js.map +1 -0
  42. package/dist/components/image.d.ts +6 -1
  43. package/dist/components/image.js +15 -4
  44. package/dist/components/image.js.map +1 -1
  45. package/dist/components/index.d.ts +7 -5
  46. package/dist/components/index.js +5 -3
  47. package/dist/components/index.js.map +1 -1
  48. package/dist/components/measure.d.ts +51 -1
  49. package/dist/components/measure.js +101 -2
  50. package/dist/components/measure.js.map +1 -1
  51. package/dist/components/pressable.d.ts +61 -1
  52. package/dist/components/pressable.js +151 -4
  53. package/dist/components/pressable.js.map +1 -1
  54. package/dist/components/rect-store.d.ts +58 -0
  55. package/dist/components/rect-store.js +124 -3
  56. package/dist/components/rect-store.js.map +1 -1
  57. package/dist/components/root.js +6 -1
  58. package/dist/components/root.js.map +1 -1
  59. package/dist/components/scroll-phase.d.ts +35 -0
  60. package/dist/components/scroll-phase.js +26 -0
  61. package/dist/components/scroll-phase.js.map +1 -0
  62. package/dist/components/scroll-view.d.ts +39 -3
  63. package/dist/components/scroll-view.js +378 -43
  64. package/dist/components/scroll-view.js.map +1 -1
  65. package/dist/components/text-input.js +9 -25
  66. package/dist/components/text-input.js.map +1 -1
  67. package/dist/components/text.d.ts +6 -2
  68. package/dist/components/text.js +43 -8
  69. package/dist/components/text.js.map +1 -1
  70. package/dist/components/use-focus.d.ts +27 -0
  71. package/dist/components/use-focus.js +116 -0
  72. package/dist/components/use-focus.js.map +1 -0
  73. package/dist/components/use-layout-child.d.ts +13 -1
  74. package/dist/components/use-layout-child.js +188 -5
  75. package/dist/components/use-layout-child.js.map +1 -1
  76. package/dist/components/view.d.ts +5 -2
  77. package/dist/components/view.js +18 -13
  78. package/dist/components/view.js.map +1 -1
  79. package/dist/components/virtualized-list.d.ts +45 -5
  80. package/dist/components/virtualized-list.js +90 -24
  81. package/dist/components/virtualized-list.js.map +1 -1
  82. package/dist/components/wheel-scroll-session.d.ts +7 -0
  83. package/dist/components/wheel-scroll-session.js +53 -0
  84. package/dist/components/wheel-scroll-session.js.map +1 -0
  85. package/dist/components/widget-retention.d.ts +35 -0
  86. package/dist/components/widget-retention.js +169 -0
  87. package/dist/components/widget-retention.js.map +1 -0
  88. package/dist/contracts.d.ts +4 -0
  89. package/dist/contracts.js.map +1 -1
  90. package/dist/dnd/context.d.ts +69 -0
  91. package/dist/dnd/context.js +149 -0
  92. package/dist/dnd/context.js.map +1 -0
  93. package/dist/dnd/draggable.d.ts +59 -0
  94. package/dist/dnd/draggable.js +149 -0
  95. package/dist/dnd/draggable.js.map +1 -0
  96. package/dist/dnd/droppable.d.ts +24 -0
  97. package/dist/dnd/droppable.js +74 -0
  98. package/dist/dnd/droppable.js.map +1 -0
  99. package/dist/dnd/gtk-controllers.d.ts +39 -0
  100. package/dist/dnd/gtk-controllers.js +110 -0
  101. package/dist/dnd/gtk-controllers.js.map +1 -0
  102. package/dist/dnd/index.d.ts +6 -0
  103. package/dist/dnd/index.js +31 -0
  104. package/dist/dnd/index.js.map +1 -0
  105. package/dist/dnd/order.d.ts +7 -0
  106. package/dist/dnd/order.js +20 -0
  107. package/dist/dnd/order.js.map +1 -0
  108. package/dist/dnd/payload.d.ts +14 -0
  109. package/dist/dnd/payload.js +41 -0
  110. package/dist/dnd/payload.js.map +1 -0
  111. package/dist/dnd/sortable.d.ts +49 -0
  112. package/dist/dnd/sortable.js +307 -0
  113. package/dist/dnd/sortable.js.map +1 -0
  114. package/dist/dnd/types.d.ts +290 -0
  115. package/dist/dnd/types.js +25 -0
  116. package/dist/dnd/types.js.map +1 -0
  117. package/dist/gesture-handler-compat/builder.d.ts +251 -0
  118. package/dist/gesture-handler-compat/builder.js +513 -0
  119. package/dist/gesture-handler-compat/builder.js.map +1 -0
  120. package/dist/gesture-handler-compat/composition.d.ts +23 -0
  121. package/dist/gesture-handler-compat/composition.js +111 -0
  122. package/dist/gesture-handler-compat/composition.js.map +1 -0
  123. package/dist/gesture-handler-compat/deciders.d.ts +3 -0
  124. package/dist/gesture-handler-compat/deciders.js +47 -0
  125. package/dist/gesture-handler-compat/deciders.js.map +1 -0
  126. package/dist/gesture-handler-compat/detector-runtime.d.ts +44 -0
  127. package/dist/gesture-handler-compat/detector-runtime.js +374 -0
  128. package/dist/gesture-handler-compat/detector-runtime.js.map +1 -0
  129. package/dist/gesture-handler-compat/detector.d.ts +22 -0
  130. package/dist/gesture-handler-compat/detector.js +104 -0
  131. package/dist/gesture-handler-compat/detector.js.map +1 -0
  132. package/dist/gesture-handler-compat/fling.d.ts +24 -0
  133. package/dist/gesture-handler-compat/fling.js +123 -0
  134. package/dist/gesture-handler-compat/fling.js.map +1 -0
  135. package/dist/gesture-handler-compat/force-touch.d.ts +13 -0
  136. package/dist/gesture-handler-compat/force-touch.js +40 -0
  137. package/dist/gesture-handler-compat/force-touch.js.map +1 -0
  138. package/dist/gesture-handler-compat/hooks.d.ts +157 -0
  139. package/dist/gesture-handler-compat/hooks.js +268 -0
  140. package/dist/gesture-handler-compat/hooks.js.map +1 -0
  141. package/dist/gesture-handler-compat/hover.d.ts +2 -0
  142. package/dist/gesture-handler-compat/hover.js +22 -0
  143. package/dist/gesture-handler-compat/hover.js.map +1 -0
  144. package/dist/gesture-handler-compat/index.d.ts +98 -0
  145. package/dist/gesture-handler-compat/index.js +255 -0
  146. package/dist/gesture-handler-compat/index.js.map +1 -0
  147. package/dist/gesture-handler-compat/long-press.d.ts +6 -0
  148. package/dist/gesture-handler-compat/long-press.js +21 -0
  149. package/dist/gesture-handler-compat/long-press.js.map +1 -0
  150. package/dist/gesture-handler-compat/manual.d.ts +2 -0
  151. package/dist/gesture-handler-compat/manual.js +18 -0
  152. package/dist/gesture-handler-compat/manual.js.map +1 -0
  153. package/dist/gesture-handler-compat/native.d.ts +7 -0
  154. package/dist/gesture-handler-compat/native.js +34 -0
  155. package/dist/gesture-handler-compat/native.js.map +1 -0
  156. package/dist/gesture-handler-compat/orchestrator.d.ts +77 -0
  157. package/dist/gesture-handler-compat/orchestrator.js +284 -0
  158. package/dist/gesture-handler-compat/orchestrator.js.map +1 -0
  159. package/dist/gesture-handler-compat/pan.d.ts +23 -0
  160. package/dist/gesture-handler-compat/pan.js +116 -0
  161. package/dist/gesture-handler-compat/pan.js.map +1 -0
  162. package/dist/gesture-handler-compat/recognizer.d.ts +268 -0
  163. package/dist/gesture-handler-compat/recognizer.js +1056 -0
  164. package/dist/gesture-handler-compat/recognizer.js.map +1 -0
  165. package/dist/gesture-handler-compat/relations.d.ts +43 -0
  166. package/dist/gesture-handler-compat/relations.js +128 -0
  167. package/dist/gesture-handler-compat/relations.js.map +1 -0
  168. package/dist/gesture-handler-compat/tap.d.ts +6 -0
  169. package/dist/gesture-handler-compat/tap.js +29 -0
  170. package/dist/gesture-handler-compat/tap.js.map +1 -0
  171. package/dist/gesture-handler-compat/touchpad.d.ts +41 -0
  172. package/dist/gesture-handler-compat/touchpad.js +64 -0
  173. package/dist/gesture-handler-compat/touchpad.js.map +1 -0
  174. package/dist/gesture-handler-compat/types.d.ts +441 -0
  175. package/dist/gesture-handler-compat/types.js +167 -0
  176. package/dist/gesture-handler-compat/types.js.map +1 -0
  177. package/dist/gtk/controllers.d.ts +39 -0
  178. package/dist/gtk/controllers.js +92 -0
  179. package/dist/gtk/controllers.js.map +1 -0
  180. package/dist/gtk/index.d.ts +2 -1
  181. package/dist/gtk/index.js +7 -1
  182. package/dist/gtk/index.js.map +1 -1
  183. package/dist/gtkx/bridge/geometry.js +6 -4
  184. package/dist/gtkx/bridge/geometry.js.map +1 -1
  185. package/dist/gtkx/bridge/index.d.ts +5 -3
  186. package/dist/gtkx/bridge/index.js +6 -3
  187. package/dist/gtkx/bridge/index.js.map +1 -1
  188. package/dist/gtkx/bridge/slot-portal.js.map +1 -1
  189. package/dist/gtkx/bridge/use-signal.js +1 -1
  190. package/dist/gtkx/bridge/use-signal.js.map +1 -1
  191. package/dist/gtkx/bridge/view-box.d.ts +56 -0
  192. package/dist/gtkx/bridge/view-box.js +394 -9
  193. package/dist/gtkx/bridge/view-box.js.map +1 -1
  194. package/dist/gtkx/bridge/widget-css.d.ts +17 -0
  195. package/dist/gtkx/bridge/widget-css.js +72 -0
  196. package/dist/gtkx/bridge/widget-css.js.map +1 -0
  197. package/dist/index.d.ts +3 -3
  198. package/dist/index.js +2 -2
  199. package/dist/index.js.map +1 -1
  200. package/dist/layout/driven-size.d.ts +12 -0
  201. package/dist/layout/driven-size.js +70 -0
  202. package/dist/layout/driven-size.js.map +1 -0
  203. package/dist/layout/engine.d.ts +17 -1
  204. package/dist/layout/engine.js +3 -20
  205. package/dist/layout/engine.js.map +1 -1
  206. package/dist/layout/node.d.ts +13 -0
  207. package/dist/layout/node.js +14 -0
  208. package/dist/layout/node.js.map +1 -1
  209. package/dist/layout/yoga.d.ts +3 -2
  210. package/dist/layout/yoga.js +5 -2
  211. package/dist/layout/yoga.js.map +1 -1
  212. package/dist/mcp/data/generated.d.ts +257 -60
  213. package/dist/mcp/data/generated.js +306 -62
  214. package/dist/mcp/data/generated.js.map +1 -1
  215. package/dist/metro/index.d.ts +10 -0
  216. package/dist/metro/index.js +21 -12
  217. package/dist/metro/index.js.map +1 -1
  218. package/dist/navigation/sidebar.d.ts +16 -0
  219. package/dist/navigation/sidebar.js +65 -1
  220. package/dist/navigation/sidebar.js.map +1 -1
  221. package/dist/reanimated-compat/animated-ref.d.ts +32 -0
  222. package/dist/reanimated-compat/animated-ref.js +57 -0
  223. package/dist/reanimated-compat/animated-ref.js.map +1 -0
  224. package/dist/reanimated-compat/animation.d.ts +177 -0
  225. package/dist/reanimated-compat/animation.js +540 -0
  226. package/dist/reanimated-compat/animation.js.map +1 -0
  227. package/dist/reanimated-compat/color.d.ts +28 -0
  228. package/dist/reanimated-compat/color.js +249 -0
  229. package/dist/reanimated-compat/color.js.map +1 -0
  230. package/dist/reanimated-compat/decay.d.ts +39 -0
  231. package/dist/reanimated-compat/decay.js +96 -0
  232. package/dist/reanimated-compat/decay.js.map +1 -0
  233. package/dist/reanimated-compat/easing.d.ts +30 -0
  234. package/dist/reanimated-compat/easing.js +76 -0
  235. package/dist/reanimated-compat/easing.js.map +1 -0
  236. package/dist/reanimated-compat/hooks.d.ts +14 -0
  237. package/dist/reanimated-compat/hooks.js +217 -0
  238. package/dist/reanimated-compat/hooks.js.map +1 -0
  239. package/dist/reanimated-compat/index.d.ts +258 -0
  240. package/dist/reanimated-compat/index.js +464 -0
  241. package/dist/reanimated-compat/index.js.map +1 -0
  242. package/dist/reanimated-compat/interpolation.d.ts +18 -0
  243. package/dist/reanimated-compat/interpolation.js +122 -0
  244. package/dist/reanimated-compat/interpolation.js.map +1 -0
  245. package/dist/reanimated-compat/layout-animation-config.d.ts +43 -0
  246. package/dist/reanimated-compat/layout-animation-config.js +78 -0
  247. package/dist/reanimated-compat/layout-animation-config.js.map +1 -0
  248. package/dist/reanimated-compat/layout-animation-presets.d.ts +117 -0
  249. package/dist/reanimated-compat/layout-animation-presets.js +498 -0
  250. package/dist/reanimated-compat/layout-animation-presets.js.map +1 -0
  251. package/dist/reanimated-compat/layout-animation-runtime.d.ts +21 -0
  252. package/dist/reanimated-compat/layout-animation-runtime.js +311 -0
  253. package/dist/reanimated-compat/layout-animation-runtime.js.map +1 -0
  254. package/dist/reanimated-compat/layout-animation-view.d.ts +27 -0
  255. package/dist/reanimated-compat/layout-animation-view.js +266 -0
  256. package/dist/reanimated-compat/layout-animation-view.js.map +1 -0
  257. package/dist/reanimated-compat/layout-animation.d.ts +171 -0
  258. package/dist/reanimated-compat/layout-animation.js +469 -0
  259. package/dist/reanimated-compat/layout-animation.js.map +1 -0
  260. package/dist/reanimated-compat/layout-transitions.d.ts +83 -0
  261. package/dist/reanimated-compat/layout-transitions.js +350 -0
  262. package/dist/reanimated-compat/layout-transitions.js.map +1 -0
  263. package/dist/reanimated-compat/mutable.d.ts +29 -0
  264. package/dist/reanimated-compat/mutable.js +139 -0
  265. package/dist/reanimated-compat/mutable.js.map +1 -0
  266. package/dist/reanimated-compat/props.d.ts +18 -0
  267. package/dist/reanimated-compat/props.js +111 -0
  268. package/dist/reanimated-compat/props.js.map +1 -0
  269. package/dist/reanimated-compat/scroll-handler.d.ts +119 -0
  270. package/dist/reanimated-compat/scroll-handler.js +274 -0
  271. package/dist/reanimated-compat/scroll-handler.js.map +1 -0
  272. package/dist/reanimated-compat/scroll-offset.d.ts +12 -0
  273. package/dist/reanimated-compat/scroll-offset.js +104 -0
  274. package/dist/reanimated-compat/scroll-offset.js.map +1 -0
  275. package/dist/reanimated-compat/style.d.ts +90 -0
  276. package/dist/reanimated-compat/style.js +452 -0
  277. package/dist/reanimated-compat/style.js.map +1 -0
  278. package/dist/reanimated-compat/test-timers.d.ts +28 -0
  279. package/dist/reanimated-compat/test-timers.js +136 -0
  280. package/dist/reanimated-compat/test-timers.js.map +1 -0
  281. package/dist/reanimated-compat/threads.d.ts +13 -0
  282. package/dist/reanimated-compat/threads.js +41 -0
  283. package/dist/reanimated-compat/threads.js.map +1 -0
  284. package/dist/reanimated-compat/tracking.d.ts +41 -0
  285. package/dist/reanimated-compat/tracking.js +106 -0
  286. package/dist/reanimated-compat/tracking.js.map +1 -0
  287. package/dist/reanimated-compat/updater-animations.d.ts +36 -0
  288. package/dist/reanimated-compat/updater-animations.js +273 -0
  289. package/dist/reanimated-compat/updater-animations.js.map +1 -0
  290. package/dist/responder/system.d.ts +80 -7
  291. package/dist/responder/system.js +143 -23
  292. package/dist/responder/system.js.map +1 -1
  293. package/dist/responder/use-responder.d.ts +11 -0
  294. package/dist/responder/use-responder.js +225 -6
  295. package/dist/responder/use-responder.js.map +1 -1
  296. package/dist/runner/host-dev.js +1 -1
  297. package/dist/runner/host-dev.js.map +1 -1
  298. package/dist/runner/host.js +1 -1
  299. package/dist/runner/host.js.map +1 -1
  300. package/dist/runner/index.js +3 -3
  301. package/dist/runner/index.js.map +1 -1
  302. package/dist/sea/gtkx-config-module.js +1 -1
  303. package/dist/sea/gtkx-config-module.js.map +1 -1
  304. package/dist/style/absolute-insets.d.ts +26 -0
  305. package/dist/style/absolute-insets.js +113 -0
  306. package/dist/style/absolute-insets.js.map +1 -0
  307. package/dist/style/animated-size.d.ts +25 -0
  308. package/dist/style/animated-size.js +225 -0
  309. package/dist/style/animated-size.js.map +1 -0
  310. package/dist/style/colors.d.ts +17 -0
  311. package/dist/style/colors.js +25 -6
  312. package/dist/style/colors.js.map +1 -1
  313. package/dist/style/imperative-css.d.ts +21 -0
  314. package/dist/style/imperative-css.js +63 -0
  315. package/dist/style/imperative-css.js.map +1 -0
  316. package/dist/style/index.d.ts +2 -1
  317. package/dist/style/index.js +2 -1
  318. package/dist/style/index.js.map +1 -1
  319. package/dist/style/split-style.js +5 -0
  320. package/dist/style/split-style.js.map +1 -1
  321. package/dist/testing/index.js.map +1 -1
  322. package/dist/unsupported-export.d.ts +8 -0
  323. package/dist/unsupported-export.js +66 -0
  324. package/dist/unsupported-export.js.map +1 -0
  325. package/dist/vite/index.d.ts +21 -8
  326. package/dist/vite/index.js +127 -82
  327. package/dist/vite/index.js.map +1 -1
  328. package/dist/vitest/index.d.ts +2 -2
  329. package/dist/vitest/index.js.map +1 -1
  330. package/dist/worklets-compat/index.d.ts +4 -0
  331. package/dist/worklets-compat/index.js +28 -0
  332. package/dist/worklets-compat/index.js.map +1 -0
  333. package/dist/worklets-compat/surface.d.ts +110 -0
  334. package/dist/worklets-compat/surface.js +153 -0
  335. package/dist/worklets-compat/surface.js.map +1 -0
  336. package/package.json +25 -9
  337. package/types.d.ts +9 -0
  338. package/dist/common/list.d.ts +0 -82
  339. package/dist/common/list.js +0 -166
  340. package/dist/common/list.js.map +0 -1
@@ -0,0 +1,307 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // `Sortable`, `SortableItem`, `useSortable` and `useSortableList` — the
3
+ // drag-to-reorder list, which is the shape most apps actually reach for.
4
+ //
5
+ // The reorder is LIVE: crossing another row moves the dragged row into its
6
+ // place immediately, so the list rearranges under the drag icon. That is
7
+ // upstream's behaviour too — its `onMove` fires as rows cross, not at the
8
+ // end — minus the spring, because here the rows are laid out by Yoga rather
9
+ // than transformed.
10
+ //
11
+ // The component owns the order, exactly as upstream requires ("do NOT update
12
+ // external state in `onMove`"). An app reads the settled order from
13
+ // `onDrop`'s `allPositions`.
14
+ import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, } from "react";
15
+ import { ScrollView } from "../components/scroll-view";
16
+ import { View } from "../components/view";
17
+ import { DraggableContext, DraggableHandle } from "./draggable";
18
+ import { DragSourceControllers, DropTargetControllers } from "./gtk-controllers";
19
+ import { listToObject } from "./order";
20
+ import { nextDraggableId } from "./payload";
21
+ import { ScrollDirection, SortableDirection, } from "./types";
22
+ // Upstream exports these from the same entry point as the components, so
23
+ // they are re-exported here rather than moved; the implementations live in
24
+ // ./order, which imports nothing from GTK.
25
+ export { clamp, listToObject, objectMove } from "./order";
26
+ const SortableContext = createContext(null);
27
+ const keyOf = (item, index, extractor) => extractor?.(item, index) ?? item.id;
28
+ /** The order state, shared by `useSortableList` and `Sortable`. */
29
+ const useOrder = (data, itemKeyExtractor) => {
30
+ // Lazy initial state, not a ref: stable for the list's lifetime, and a ref
31
+ // may not be read during render.
32
+ const [scope] = useState(() => `sortable-${nextDraggableId()}`);
33
+ const incoming = useMemo(() => data.map((item, index) => keyOf(item, index, itemKeyExtractor)), [data, itemKeyExtractor]);
34
+ const [order, setOrder] = useState(incoming);
35
+ // The list owns the ORDER; the app owns the SET. Adding or removing an item
36
+ // has to reach the order without discarding a reorder the user already
37
+ // made — so new ids go to the end, departed ids drop out, and a pure
38
+ // reorder of `data` by the app is ignored (upstream's contract too: the
39
+ // component owns the order).
40
+ //
41
+ // Adjusted DURING RENDER rather than in an effect. React documents this as
42
+ // the way to derive state from changed props, and it matters here: an
43
+ // effect would paint one frame in the stale order every time the app
44
+ // appends an item.
45
+ const signature = incoming.join(" ");
46
+ const [seenSignature, setSeenSignature] = useState(signature);
47
+ if (seenSignature !== signature) {
48
+ setSeenSignature(signature);
49
+ const known = new Set(incoming);
50
+ const next = [
51
+ ...order.filter((id) => known.has(id)),
52
+ ...incoming.filter((id) => !order.includes(id)),
53
+ ];
54
+ if (next.length !== order.length ||
55
+ next.some((id, index) => id !== order[index])) {
56
+ setOrder(next);
57
+ }
58
+ }
59
+ const items = useMemo(() => {
60
+ const byId = new Map();
61
+ data.forEach((item, index) => {
62
+ byId.set(keyOf(item, index, itemKeyExtractor), item);
63
+ });
64
+ return order
65
+ .map((id) => byId.get(id))
66
+ .filter((item) => item !== undefined);
67
+ }, [order, data, itemKeyExtractor]);
68
+ return { scope, order, setOrder, items };
69
+ };
70
+ /** The `SharedValue`-shaped boxes upstream hands to `renderItem`. Real,
71
+ * readable and writable here — just not animated. See `SharedValueLike`. */
72
+ const useSharedBoxes = (order) => {
73
+ // Rebuilt when the order changes rather than mutated in place. Upstream's
74
+ // box keeps its identity and changes its `.value`; here the identity tracks
75
+ // the value, which is the closest thing available without a mutable cell
76
+ // React allows to be written during a render. The practical difference is
77
+ // that an app using `positions` as an effect dependency re-runs on a
78
+ // reorder — which is what it wanted from a SharedValue anyway.
79
+ const positions = useMemo(() => ({
80
+ value: listToObject(order),
81
+ }), [order]);
82
+ // These three this platform never writes: there is no UI-thread scroll
83
+ // position, no autoscroll during a drag (see docs/research/drag-and-drop.md)
84
+ // and no measured row heights, because Yoga lays rows out at their natural
85
+ // height. Stable, so forwarding them is free.
86
+ const idle = useMemo(() => ({
87
+ scrollY: { value: 0 },
88
+ autoScroll: { value: ScrollDirection.None },
89
+ itemHeights: { value: {} },
90
+ }), []);
91
+ const itemsCount = order.length;
92
+ return useMemo(() => ({
93
+ positions,
94
+ ...idle,
95
+ plumbing: () => ({
96
+ positions,
97
+ lowerBound: idle.scrollY,
98
+ autoScrollDirection: idle.autoScroll,
99
+ itemHeights: idle.itemHeights,
100
+ itemsCount,
101
+ isDynamicHeight: false,
102
+ }),
103
+ }), [positions, idle, itemsCount]);
104
+ };
105
+ /**
106
+ * Owns the order of a sortable list, for an app rendering its own container.
107
+ *
108
+ * **The order half only.** Upstream's rows get their drag wiring through the
109
+ * props `getItemProps` hands them; here it travels in context, which only
110
+ * `Sortable` provides — so rows still have to be inside a `Sortable`, and a
111
+ * `SortableItem` outside one throws rather than quietly not dragging. This
112
+ * hook is for reading the order and the `SharedValueLike` boxes, which is
113
+ * what most callers of it actually want.
114
+ */
115
+ export const useSortableList = (options) => {
116
+ const { order, items } = useOrder(options.data, options.itemKeyExtractor);
117
+ const boxes = useSharedBoxes(order);
118
+ const dropProviderRef = useRef(null);
119
+ const noop = useCallback(() => { }, []);
120
+ return {
121
+ positions: boxes.positions,
122
+ scrollY: boxes.scrollY,
123
+ autoScroll: boxes.autoScroll,
124
+ itemHeights: boxes.itemHeights,
125
+ dropProviderRef,
126
+ handleScroll: noop,
127
+ handleScrollEnd: noop,
128
+ contentHeight: 0,
129
+ isDynamicHeight: false,
130
+ items,
131
+ getItemProps: boxes.plumbing,
132
+ };
133
+ };
134
+ /**
135
+ * A list whose rows reorder by dragging.
136
+ *
137
+ * ```tsx
138
+ * <Sortable
139
+ * data={tasks}
140
+ * onDrop={(id, position, all) => save(all)}
141
+ * renderItem={({ item, id, ...rest }) => (
142
+ * <SortableItem key={id} id={id} data={item} {...rest}>
143
+ * <View style={styles.row}>
144
+ * <Text>{item.title}</Text>
145
+ * <SortableItem.Handle>
146
+ * <Text>⠿</Text>
147
+ * </SortableItem.Handle>
148
+ * </View>
149
+ * </SortableItem>
150
+ * )}
151
+ * />
152
+ * ```
153
+ *
154
+ * The rows carry a real GTK drag icon — a picture of the row itself, lifted
155
+ * at the point it was grabbed — and the list rearranges live underneath it.
156
+ */
157
+ export const Sortable = ({ data, renderItem, itemKeyExtractor, style, contentContainerStyle, testID, direction = SortableDirection.Vertical, onMove, onDragStart, onDrop, onDragging, }) => {
158
+ const { scope, order, setOrder, items } = useOrder(data, itemKeyExtractor);
159
+ const boxes = useSharedBoxes(order);
160
+ // The order as it was when the drag began, so a cancelled drag puts the
161
+ // list back rather than leaving it wherever the pointer happened to be.
162
+ const beforeDrag = useRef(null);
163
+ // The drag callbacks below run from GTK signals, long after any commit, so
164
+ // reading the order through a ref updated in an effect is both current and
165
+ // free of the stale-closure problem `useCallback` would otherwise have.
166
+ const orderRef = useRef(order);
167
+ useEffect(() => {
168
+ orderRef.current = order;
169
+ }, [order]);
170
+ const beginDrag = useCallback((draggedId) => {
171
+ beforeDrag.current = orderRef.current;
172
+ onDragStart?.(draggedId, orderRef.current.indexOf(draggedId));
173
+ }, [onDragStart]);
174
+ const moveOnto = useCallback((draggedId, targetId) => {
175
+ setOrder((current) => {
176
+ const from = current.indexOf(draggedId);
177
+ const to = current.indexOf(targetId);
178
+ if (from === -1 || to === -1 || from === to) {
179
+ return current;
180
+ }
181
+ const next = [...current];
182
+ next.splice(from, 1);
183
+ next.splice(to, 0, draggedId);
184
+ onMove?.(draggedId, from, to);
185
+ return next;
186
+ });
187
+ }, [setOrder, onMove]);
188
+ const endDrag = useCallback((draggedId, cancelled) => {
189
+ const restore = beforeDrag.current;
190
+ beforeDrag.current = null;
191
+ if (cancelled) {
192
+ if (restore) {
193
+ setOrder(() => restore);
194
+ }
195
+ return;
196
+ }
197
+ const settled = orderRef.current;
198
+ onDrop?.(draggedId, settled.indexOf(draggedId), listToObject(settled));
199
+ }, [setOrder, onDrop]);
200
+ const contextValue = useMemo(() => ({ scope, moveOnto, beginDrag, endDrag, onDragging }), [scope, moveOnto, beginDrag, endDrag, onDragging]);
201
+ if (direction === SortableDirection.Horizontal) {
202
+ // Loud rather than silent: a horizontal list that lays out vertically is
203
+ // a bug report waiting to happen. See docs/research/drag-and-drop.md for
204
+ // why the horizontal surface is deferred rather than approximated.
205
+ throw new Error("react-native-gtkx/dnd: SortableDirection.Horizontal is not implemented on Linux");
206
+ }
207
+ return (_jsx(SortableContext.Provider, { value: contextValue, children: _jsx(ScrollView, { style: style,
208
+ // No `alignItems: "stretch"` override here any more. It used to be
209
+ // needed because this platform's ScrollView content container
210
+ // defaulted to `flex-start`, which shrank every row to its intrinsic
211
+ // width and collapsed the `flex: 1` text column inside it. That
212
+ // default was a parity bug — RN's content container is a plain
213
+ // `View`, whose default is `stretch` — and it is fixed at the source
214
+ // now (components/scroll-view.tsx), so a `Sortable` gets full-width
215
+ // rows the same way any other RN list does.
216
+ contentContainerStyle: contentContainerStyle, testID: testID, children: items.map((item, index) => renderItem({
217
+ item,
218
+ index,
219
+ id: keyOf(item, index, itemKeyExtractor),
220
+ direction,
221
+ ...boxes.plumbing(),
222
+ })) }) }));
223
+ };
224
+ /**
225
+ * The reorder half of the module, as a hook, for a row that owns its own
226
+ * view. Render `children` inside that view.
227
+ */
228
+ export const useSortable = (options) => {
229
+ const { id, onDragging } = options;
230
+ const list = useContext(SortableContext);
231
+ if (list === null) {
232
+ // Loudly, because a silent no-op is the worst failure mode this repo has
233
+ // met: docs/research/gestures.md records `Animated.View` accepting the
234
+ // responder props and ignoring them, which compiled, ran, and did
235
+ // nothing. Unlike upstream — where a row gets its wiring through the
236
+ // props `getItemProps` hands it — the wiring here is in context, so a row
237
+ // outside its list has no drag at all rather than a degraded one.
238
+ throw new Error("react-native-gtkx/dnd: SortableItem/useSortable must be inside a Sortable");
239
+ }
240
+ const [isMoving, setIsMoving] = useState(false);
241
+ const [hasHandle, setHasHandle] = useState(false);
242
+ const registerHandle = useCallback((registered) => {
243
+ setHasHandle(registered);
244
+ }, []);
245
+ // Same reasoning as draggable.tsx: a handle registers one commit late, so
246
+ // the row's own copy waits for it rather than briefly mounting a second
247
+ // drag source.
248
+ const [mounted, setMounted] = useState(false);
249
+ // eslint-disable-next-line react-hooks/set-state-in-effect
250
+ useEffect(() => setMounted(true), []);
251
+ // Same list only — and INCLUDING this row itself. Refusing the self-drop
252
+ // looks right and is wrong: because the reorder happens live on `::enter`,
253
+ // by the time the pointer settles it is over the DRAGGED row, so a row that
254
+ // refuses its own payload leaves GDK with no target, cancels the drag, and
255
+ // the list snaps back to where it started. Accepting is also the honest
256
+ // reading: dropping a row on its own current position means "leave it
257
+ // here", which is a completed drag, not an abandoned one.
258
+ const accepts = useCallback((payload) => payload.scope === list.scope, [list]);
259
+ const dragControllers = (_jsx(DragSourceControllers, { payload: { scope: list.scope, id }, onDragBegin: () => {
260
+ setIsMoving(true);
261
+ list.beginDrag(id);
262
+ }, onDragEnd: (dropped) => {
263
+ setIsMoving(false);
264
+ list.endDrag(id, !dropped);
265
+ } }));
266
+ const dropControllers = (_jsx(DropTargetControllers, { accepts: accepts,
267
+ // The reorder happens HERE, not on drop: crossing this row is what
268
+ // moves the dragged row into its place, so the list rearranges under
269
+ // the drag icon the way upstream's animated gaps do.
270
+ onEnter: (payload) => list.moveOnto(payload.id, id), onMotion: (payload, _x, y) => {
271
+ list.onDragging?.(payload.id, id, y);
272
+ onDragging?.(payload.id, id, y);
273
+ },
274
+ // Nothing left to do: the order is already right, and `drag-end` on the
275
+ // source is what settles it.
276
+ onDrop: () => { } }));
277
+ return {
278
+ animatedStyle: undefined,
279
+ isMoving,
280
+ hasHandle,
281
+ registerHandle,
282
+ dragControllers,
283
+ children: (_jsxs(_Fragment, { children: [mounted && !hasHandle ? dragControllers : null, dropControllers] })),
284
+ };
285
+ };
286
+ /** One row of a {@link Sortable}. Both a drag source and a drop target: the
287
+ * row you drag onto is the position the dragged row takes. */
288
+ export const SortableItem = ({ id, data, children, style, animatedStyle, testID, onMove, onDragStart, onDrop, onDragging, }) => {
289
+ const sortable = useSortable({
290
+ id,
291
+ data,
292
+ onMove,
293
+ onDragStart,
294
+ onDrop,
295
+ onDragging,
296
+ });
297
+ // `SortableItem.Handle` is `Draggable.Handle`: the same context carries the
298
+ // drag source to whichever view claims it, so one implementation serves
299
+ // both components.
300
+ const handleContext = useMemo(() => ({
301
+ source: sortable.dragControllers,
302
+ registerHandle: sortable.registerHandle,
303
+ }), [sortable.dragControllers, sortable.registerHandle]);
304
+ return (_jsx(View, { style: animatedStyle ? [style, animatedStyle] : style, testID: testID, children: _jsxs(DraggableContext.Provider, { value: handleContext, children: [sortable.children, children] }) }));
305
+ };
306
+ SortableItem.Handle = DraggableHandle;
307
+ //# sourceMappingURL=sortable.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sortable.js","sourceRoot":"","sources":["../../src/dnd/sortable.tsx"],"names":[],"mappings":"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","sourcesContent":["// `Sortable`, `SortableItem`, `useSortable` and `useSortableList` — the\n// drag-to-reorder list, which is the shape most apps actually reach for.\n//\n// The reorder is LIVE: crossing another row moves the dragged row into its\n// place immediately, so the list rearranges under the drag icon. That is\n// upstream's behaviour too — its `onMove` fires as rows cross, not at the\n// end — minus the spring, because here the rows are laid out by Yoga rather\n// than transformed.\n//\n// The component owns the order, exactly as upstream requires (\"do NOT update\n// external state in `onMove`\"). An app reads the settled order from\n// `onDrop`'s `allPositions`.\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from \"react\"\nimport { ScrollView } from \"../components/scroll-view\"\nimport { View } from \"../components/view\"\nimport { DraggableContext, DraggableHandle } from \"./draggable\"\nimport { DragSourceControllers, DropTargetControllers } from \"./gtk-controllers\"\nimport { listToObject } from \"./order\"\nimport { nextDraggableId, type DragPayload } from \"./payload\"\nimport {\n ScrollDirection,\n SortableDirection,\n type SharedValueLike,\n type SortableData,\n type SortableItemPlumbing,\n type SortableItemProps,\n type SortableProps,\n type UseSortableListOptions,\n type UseSortableListReturn,\n type UseSortableOptions,\n type UseSortableReturn,\n} from \"./types\"\n\n// Upstream exports these from the same entry point as the components, so\n// they are re-exported here rather than moved; the implementations live in\n// ./order, which imports nothing from GTK.\nexport { clamp, listToObject, objectMove } from \"./order\"\n\n// --- the list ---------------------------------------------------------------\n\ntype SortableContextValue = {\n /** Namespaces this list's payloads, so dragging a row does not light up\n * every `Droppable` on the screen. */\n scope: string\n /** Called by a row when the dragged row crosses it. */\n moveOnto: (draggedId: string, targetId: string) => void\n beginDrag: (draggedId: string) => void\n endDrag: (draggedId: string, cancelled: boolean) => void\n onDragging?: (id: string, overItemId: string | null, y: number) => void\n}\n\nconst SortableContext = createContext<SortableContextValue | null>(null)\n\nconst keyOf = <TData extends SortableData>(\n item: TData,\n index: number,\n extractor?: (item: TData, index: number) => string,\n): string => extractor?.(item, index) ?? item.id\n\n/** The order state, shared by `useSortableList` and `Sortable`. */\nconst useOrder = <TData extends SortableData>(\n data: TData[],\n itemKeyExtractor?: (item: TData, index: number) => string,\n) => {\n // Lazy initial state, not a ref: stable for the list's lifetime, and a ref\n // may not be read during render.\n const [scope] = useState(() => `sortable-${nextDraggableId()}`)\n\n const incoming = useMemo(\n () => data.map((item, index) => keyOf(item, index, itemKeyExtractor)),\n [data, itemKeyExtractor],\n )\n const [order, setOrder] = useState<string[]>(incoming)\n\n // The list owns the ORDER; the app owns the SET. Adding or removing an item\n // has to reach the order without discarding a reorder the user already\n // made — so new ids go to the end, departed ids drop out, and a pure\n // reorder of `data` by the app is ignored (upstream's contract too: the\n // component owns the order).\n //\n // Adjusted DURING RENDER rather than in an effect. React documents this as\n // the way to derive state from changed props, and it matters here: an\n // effect would paint one frame in the stale order every time the app\n // appends an item.\n const signature = incoming.join(\" \")\n const [seenSignature, setSeenSignature] = useState(signature)\n if (seenSignature !== signature) {\n setSeenSignature(signature)\n const known = new Set(incoming)\n const next = [\n ...order.filter((id) => known.has(id)),\n ...incoming.filter((id) => !order.includes(id)),\n ]\n if (\n next.length !== order.length ||\n next.some((id, index) => id !== order[index])\n ) {\n setOrder(next)\n }\n }\n\n const items = useMemo(() => {\n const byId = new Map<string, TData>()\n data.forEach((item, index) => {\n byId.set(keyOf(item, index, itemKeyExtractor), item)\n })\n return order\n .map((id) => byId.get(id))\n .filter((item): item is TData => item !== undefined)\n }, [order, data, itemKeyExtractor])\n\n return { scope, order, setOrder, items }\n}\n\n/** The `SharedValue`-shaped boxes upstream hands to `renderItem`. Real,\n * readable and writable here — just not animated. See `SharedValueLike`. */\nconst useSharedBoxes = (order: string[]) => {\n // Rebuilt when the order changes rather than mutated in place. Upstream's\n // box keeps its identity and changes its `.value`; here the identity tracks\n // the value, which is the closest thing available without a mutable cell\n // React allows to be written during a render. The practical difference is\n // that an app using `positions` as an effect dependency re-runs on a\n // reorder — which is what it wanted from a SharedValue anyway.\n const positions = useMemo(\n (): SharedValueLike<Record<string, number>> => ({\n value: listToObject(order),\n }),\n [order],\n )\n // These three this platform never writes: there is no UI-thread scroll\n // position, no autoscroll during a drag (see docs/research/drag-and-drop.md)\n // and no measured row heights, because Yoga lays rows out at their natural\n // height. Stable, so forwarding them is free.\n const idle = useMemo(\n () => ({\n scrollY: { value: 0 },\n autoScroll: { value: ScrollDirection.None as ScrollDirection },\n itemHeights: { value: {} as Record<string, number> },\n }),\n [],\n )\n\n const itemsCount = order.length\n\n return useMemo(\n () => ({\n positions,\n ...idle,\n plumbing: (): SortableItemPlumbing => ({\n positions,\n lowerBound: idle.scrollY,\n autoScrollDirection: idle.autoScroll,\n itemHeights: idle.itemHeights,\n itemsCount,\n isDynamicHeight: false,\n }),\n }),\n [positions, idle, itemsCount],\n )\n}\n\n/**\n * Owns the order of a sortable list, for an app rendering its own container.\n *\n * **The order half only.** Upstream's rows get their drag wiring through the\n * props `getItemProps` hands them; here it travels in context, which only\n * `Sortable` provides — so rows still have to be inside a `Sortable`, and a\n * `SortableItem` outside one throws rather than quietly not dragging. This\n * hook is for reading the order and the `SharedValueLike` boxes, which is\n * what most callers of it actually want.\n */\nexport const useSortableList = <TData extends SortableData>(\n options: UseSortableListOptions<TData>,\n): UseSortableListReturn<TData> => {\n const { order, items } = useOrder(options.data, options.itemKeyExtractor)\n const boxes = useSharedBoxes(order)\n const dropProviderRef = useRef(null)\n const noop = useCallback(() => {}, [])\n\n return {\n positions: boxes.positions,\n scrollY: boxes.scrollY,\n autoScroll: boxes.autoScroll,\n itemHeights: boxes.itemHeights,\n dropProviderRef,\n handleScroll: noop,\n handleScrollEnd: noop,\n contentHeight: 0,\n isDynamicHeight: false,\n items,\n getItemProps: boxes.plumbing,\n }\n}\n\n/**\n * A list whose rows reorder by dragging.\n *\n * ```tsx\n * <Sortable\n * data={tasks}\n * onDrop={(id, position, all) => save(all)}\n * renderItem={({ item, id, ...rest }) => (\n * <SortableItem key={id} id={id} data={item} {...rest}>\n * <View style={styles.row}>\n * <Text>{item.title}</Text>\n * <SortableItem.Handle>\n * <Text>⠿</Text>\n * </SortableItem.Handle>\n * </View>\n * </SortableItem>\n * )}\n * />\n * ```\n *\n * The rows carry a real GTK drag icon — a picture of the row itself, lifted\n * at the point it was grabbed — and the list rearranges live underneath it.\n */\nexport const Sortable = <TData extends SortableData>({\n data,\n renderItem,\n itemKeyExtractor,\n style,\n contentContainerStyle,\n testID,\n direction = SortableDirection.Vertical,\n onMove,\n onDragStart,\n onDrop,\n onDragging,\n}: SortableProps<TData>): ReactNode => {\n const { scope, order, setOrder, items } = useOrder(data, itemKeyExtractor)\n const boxes = useSharedBoxes(order)\n\n // The order as it was when the drag began, so a cancelled drag puts the\n // list back rather than leaving it wherever the pointer happened to be.\n const beforeDrag = useRef<string[] | null>(null)\n // The drag callbacks below run from GTK signals, long after any commit, so\n // reading the order through a ref updated in an effect is both current and\n // free of the stale-closure problem `useCallback` would otherwise have.\n const orderRef = useRef(order)\n useEffect(() => {\n orderRef.current = order\n }, [order])\n\n const beginDrag = useCallback(\n (draggedId: string) => {\n beforeDrag.current = orderRef.current\n onDragStart?.(draggedId, orderRef.current.indexOf(draggedId))\n },\n [onDragStart],\n )\n\n const moveOnto = useCallback(\n (draggedId: string, targetId: string) => {\n setOrder((current) => {\n const from = current.indexOf(draggedId)\n const to = current.indexOf(targetId)\n if (from === -1 || to === -1 || from === to) {\n return current\n }\n const next = [...current]\n next.splice(from, 1)\n next.splice(to, 0, draggedId)\n onMove?.(draggedId, from, to)\n return next\n })\n },\n [setOrder, onMove],\n )\n\n const endDrag = useCallback(\n (draggedId: string, cancelled: boolean) => {\n const restore = beforeDrag.current\n beforeDrag.current = null\n if (cancelled) {\n if (restore) {\n setOrder(() => restore)\n }\n return\n }\n const settled = orderRef.current\n onDrop?.(draggedId, settled.indexOf(draggedId), listToObject(settled))\n },\n [setOrder, onDrop],\n )\n\n const contextValue = useMemo<SortableContextValue>(\n () => ({ scope, moveOnto, beginDrag, endDrag, onDragging }),\n [scope, moveOnto, beginDrag, endDrag, onDragging],\n )\n\n if (direction === SortableDirection.Horizontal) {\n // Loud rather than silent: a horizontal list that lays out vertically is\n // a bug report waiting to happen. See docs/research/drag-and-drop.md for\n // why the horizontal surface is deferred rather than approximated.\n throw new Error(\n \"react-native-gtkx/dnd: SortableDirection.Horizontal is not implemented on Linux\",\n )\n }\n\n return (\n <SortableContext.Provider value={contextValue}>\n <ScrollView\n style={style}\n // No `alignItems: \"stretch\"` override here any more. It used to be\n // needed because this platform's ScrollView content container\n // defaulted to `flex-start`, which shrank every row to its intrinsic\n // width and collapsed the `flex: 1` text column inside it. That\n // default was a parity bug — RN's content container is a plain\n // `View`, whose default is `stretch` — and it is fixed at the source\n // now (components/scroll-view.tsx), so a `Sortable` gets full-width\n // rows the same way any other RN list does.\n contentContainerStyle={contentContainerStyle}\n testID={testID}\n >\n {items.map((item, index) =>\n renderItem({\n item,\n index,\n id: keyOf(item, index, itemKeyExtractor),\n direction,\n ...boxes.plumbing(),\n }),\n )}\n </ScrollView>\n </SortableContext.Provider>\n )\n}\n\n/**\n * The reorder half of the module, as a hook, for a row that owns its own\n * view. Render `children` inside that view.\n */\nexport const useSortable = <TData,>(\n options: UseSortableOptions<TData>,\n): UseSortableReturn => {\n const { id, onDragging } = options\n const list = useContext(SortableContext)\n if (list === null) {\n // Loudly, because a silent no-op is the worst failure mode this repo has\n // met: docs/research/gestures.md records `Animated.View` accepting the\n // responder props and ignoring them, which compiled, ran, and did\n // nothing. Unlike upstream — where a row gets its wiring through the\n // props `getItemProps` hands it — the wiring here is in context, so a row\n // outside its list has no drag at all rather than a degraded one.\n throw new Error(\n \"react-native-gtkx/dnd: SortableItem/useSortable must be inside a Sortable\",\n )\n }\n const [isMoving, setIsMoving] = useState(false)\n const [hasHandle, setHasHandle] = useState(false)\n\n const registerHandle = useCallback((registered: boolean) => {\n setHasHandle(registered)\n }, [])\n\n // Same reasoning as draggable.tsx: a handle registers one commit late, so\n // the row's own copy waits for it rather than briefly mounting a second\n // drag source.\n const [mounted, setMounted] = useState(false)\n // eslint-disable-next-line react-hooks/set-state-in-effect\n useEffect(() => setMounted(true), [])\n\n // Same list only — and INCLUDING this row itself. Refusing the self-drop\n // looks right and is wrong: because the reorder happens live on `::enter`,\n // by the time the pointer settles it is over the DRAGGED row, so a row that\n // refuses its own payload leaves GDK with no target, cancels the drag, and\n // the list snaps back to where it started. Accepting is also the honest\n // reading: dropping a row on its own current position means \"leave it\n // here\", which is a completed drag, not an abandoned one.\n const accepts = useCallback(\n (payload: DragPayload) => payload.scope === list.scope,\n [list],\n )\n\n const dragControllers = (\n <DragSourceControllers\n payload={{ scope: list.scope, id }}\n onDragBegin={() => {\n setIsMoving(true)\n list.beginDrag(id)\n }}\n onDragEnd={(dropped) => {\n setIsMoving(false)\n list.endDrag(id, !dropped)\n }}\n />\n )\n\n const dropControllers = (\n <DropTargetControllers\n accepts={accepts}\n // The reorder happens HERE, not on drop: crossing this row is what\n // moves the dragged row into its place, so the list rearranges under\n // the drag icon the way upstream's animated gaps do.\n onEnter={(payload) => list.moveOnto(payload.id, id)}\n onMotion={(payload, _x, y) => {\n list.onDragging?.(payload.id, id, y)\n onDragging?.(payload.id, id, y)\n }}\n // Nothing left to do: the order is already right, and `drag-end` on the\n // source is what settles it.\n onDrop={() => {}}\n />\n )\n\n return {\n animatedStyle: undefined,\n isMoving,\n hasHandle,\n registerHandle,\n dragControllers,\n children: (\n <>\n {mounted && !hasHandle ? dragControllers : null}\n {dropControllers}\n </>\n ),\n }\n}\n\n/** One row of a {@link Sortable}. Both a drag source and a drop target: the\n * row you drag onto is the position the dragged row takes. */\nexport const SortableItem = <TData,>({\n id,\n data,\n children,\n style,\n animatedStyle,\n testID,\n onMove,\n onDragStart,\n onDrop,\n onDragging,\n}: SortableItemProps<TData>): ReactNode => {\n const sortable = useSortable<TData>({\n id,\n data,\n onMove,\n onDragStart,\n onDrop,\n onDragging,\n } as UseSortableOptions<TData>)\n\n // `SortableItem.Handle` is `Draggable.Handle`: the same context carries the\n // drag source to whichever view claims it, so one implementation serves\n // both components.\n const handleContext = useMemo(\n () => ({\n source: sortable.dragControllers,\n registerHandle: sortable.registerHandle,\n }),\n [sortable.dragControllers, sortable.registerHandle],\n )\n\n return (\n <View\n style={animatedStyle ? [style, animatedStyle] : style}\n testID={testID}\n >\n <DraggableContext.Provider value={handleContext}>\n {sortable.children}\n {children}\n </DraggableContext.Provider>\n </View>\n )\n}\n\nSortableItem.Handle = DraggableHandle\n"]}
@@ -0,0 +1,290 @@
1
+ import type { ReactNode, RefObject } from "react";
2
+ import type { StyleProp } from "../contracts";
3
+ /**
4
+ * What `SharedValue<T>` degrades to here.
5
+ *
6
+ * Reanimated's `SharedValue<T>` is `{ value: T }` plus the worklet plumbing
7
+ * that makes writes cross to the UI thread. There is no UI thread on this
8
+ * platform, so this is the same box without the crossing: **reads and
9
+ * writes both work**, they just do not drive an animation.
10
+ *
11
+ * That matters more than it looks. `positions`, `lowerBound`,
12
+ * `autoScrollDirection` and `itemHeights` appear in
13
+ * `SortableRenderItemProps` — public API an app forwards with `{...rest}`
14
+ * and, occasionally, reads. Typing them as an opaque token would break the
15
+ * reads; typing them as this keeps them working.
16
+ */
17
+ export type SharedValueLike<T> = {
18
+ value: T;
19
+ };
20
+ export declare enum DraggableState {
21
+ IDLE = "IDLE",
22
+ DRAGGING = "DRAGGING",
23
+ DROPPED = "DROPPED"
24
+ }
25
+ export type AnimationFunction = (toValue: number) => number;
26
+ export type CollisionAlgorithm = "center" | "intersect" | "contain";
27
+ export interface UseDraggableOptions<TData = unknown> {
28
+ data: TData;
29
+ draggableId?: string;
30
+ dragDisabled?: boolean;
31
+ onDragStart?: (data: TData) => void;
32
+ onDragEnd?: (data: TData) => void;
33
+ onDragging?: (payload: {
34
+ x: number;
35
+ y: number;
36
+ tx: number;
37
+ ty: number;
38
+ itemData: TData;
39
+ }) => void;
40
+ onStateChange?: (state: DraggableState) => void;
41
+ /**
42
+ * Accepted and ignored. Upstream uses it to tell a tap from a drag; GDK
43
+ * already does that with `gtk-dnd-drag-threshold` before it starts a drag
44
+ * at all, so honouring it would only make dragging feel slower.
45
+ */
46
+ preDragDelay?: number;
47
+ /**
48
+ * Accepted and ignored. GDK hit-tests the pointer against the real widget
49
+ * tree; of the three upstream algorithms `"center"` is closest, since the
50
+ * drag icon is carried at the point it was grabbed.
51
+ */
52
+ collisionAlgorithm?: CollisionAlgorithm;
53
+ /** Unsupported: the compositor carries the drag icon and nothing here can
54
+ * constrain its path. Kept in the type so a shared file still compiles
55
+ * for iOS and Android. */
56
+ dragAxis?: "x" | "y" | "both";
57
+ /** Unsupported, same reason as `dragAxis`. */
58
+ dragBoundsRef?: RefObject<unknown>;
59
+ /** Unsupported: there is no return animation, because the view never
60
+ * left — GDK drew a picture of it instead. */
61
+ animationFunction?: AnimationFunction;
62
+ }
63
+ export interface UseDraggableReturn {
64
+ /** Spread onto the view that should be draggable. Upstream's name for it
65
+ * is `animatedViewProps`; the props are a `style` and the drag
66
+ * controllers, which on this platform are React children rather than a
67
+ * style. */
68
+ animatedViewProps: {
69
+ style?: StyleProp;
70
+ children: ReactNode;
71
+ };
72
+ state: DraggableState;
73
+ hasHandle: boolean;
74
+ registerHandle: (registered: boolean) => void;
75
+ }
76
+ export interface DraggableProps<TData = unknown> extends UseDraggableOptions<TData> {
77
+ style?: StyleProp;
78
+ children: ReactNode;
79
+ testID?: string;
80
+ }
81
+ export interface DraggableHandleProps {
82
+ children: ReactNode;
83
+ style?: StyleProp;
84
+ testID?: string;
85
+ }
86
+ export type DropAlignment = "center" | "top-left" | "top-center" | "top-right" | "center-left" | "center-right" | "bottom-left" | "bottom-center" | "bottom-right";
87
+ export interface DropOffset {
88
+ x: number;
89
+ y: number;
90
+ }
91
+ export interface UseDroppableOptions<TData = unknown> {
92
+ onDrop: (data: TData) => void;
93
+ dropDisabled?: boolean;
94
+ onActiveChange?: (isActive: boolean) => void;
95
+ activeStyle?: StyleProp;
96
+ droppableId?: string;
97
+ /** How many draggables this zone accepts. When it is full GDK is told to
98
+ * REFUSE the drop, so the pointer shows the no-drop cursor — upstream
99
+ * silently skips the slot instead. */
100
+ capacity?: number;
101
+ /** Unsupported: both of these place the dragged view inside the zone
102
+ * after the drop, and the view never moved. */
103
+ dropAlignment?: DropAlignment;
104
+ dropOffset?: DropOffset;
105
+ }
106
+ export interface UseDroppableReturn {
107
+ viewProps: {
108
+ style?: StyleProp;
109
+ children: ReactNode;
110
+ };
111
+ isActive: boolean;
112
+ activeStyle?: StyleProp;
113
+ }
114
+ export interface DroppableProps<TData = unknown> extends UseDroppableOptions<TData> {
115
+ style?: StyleProp;
116
+ children: ReactNode;
117
+ testID?: string;
118
+ }
119
+ export interface DroppedItemsMap<TData = unknown> {
120
+ [draggableId: string]: {
121
+ droppableId: string;
122
+ data: TData;
123
+ };
124
+ }
125
+ export interface DropProviderProps {
126
+ children: ReactNode;
127
+ onDroppedItemsUpdate?: (droppedItems: DroppedItemsMap) => void;
128
+ onDragStart?: (data: unknown) => void;
129
+ onDragEnd?: (data: unknown) => void;
130
+ onDragging?: (payload: {
131
+ x: number;
132
+ y: number;
133
+ tx: number;
134
+ ty: number;
135
+ itemData: unknown;
136
+ }) => void;
137
+ /** Accepted and ignored: there is no layout pass to complete, because
138
+ * nothing caches a slot rectangle. See `requestPositionUpdate`. */
139
+ onLayoutUpdateComplete?: () => void;
140
+ style?: StyleProp;
141
+ testID?: string;
142
+ ref?: RefObject<DropProviderRef | null>;
143
+ }
144
+ export interface DropProviderRef {
145
+ /**
146
+ * A no-op **because GDK re-hit-tests on every motion**. Upstream needs it
147
+ * to refresh cached slot rectangles after a scroll or a relayout; there
148
+ * are no cached rectangles here, so calling it is harmless and
149
+ * unnecessary. Kept so an app that calls it after a list update compiles.
150
+ */
151
+ requestPositionUpdate: () => void;
152
+ getDroppedItems: () => DroppedItemsMap;
153
+ }
154
+ export interface SortableData {
155
+ id: string;
156
+ }
157
+ export declare enum ScrollDirection {
158
+ None = "none",
159
+ Up = "up",
160
+ Down = "down"
161
+ }
162
+ export declare enum HorizontalScrollDirection {
163
+ None = "none",
164
+ Left = "left",
165
+ Right = "right"
166
+ }
167
+ export declare enum SortableDirection {
168
+ Vertical = "vertical",
169
+ Horizontal = "horizontal"
170
+ }
171
+ /** The plumbing `Sortable` hands `renderItem` and `renderItem` hands
172
+ * `SortableItem` — opaque in upstream's own examples, which destructure
173
+ * `item`/`index`/`id` and spread the rest. */
174
+ export interface SortableItemPlumbing {
175
+ positions: SharedValueLike<Record<string, number>>;
176
+ lowerBound: SharedValueLike<number>;
177
+ autoScrollDirection: SharedValueLike<ScrollDirection>;
178
+ itemHeights: SharedValueLike<Record<string, number>>;
179
+ itemsCount: number;
180
+ /** Accepted and ignored: Yoga lays rows out at their natural height, so
181
+ * a height hint has nothing to correct. */
182
+ itemHeight?: number;
183
+ /** Accepted and ignored, same reason. */
184
+ estimatedItemHeight?: number;
185
+ /**
186
+ * Accepted and ignored. Upstream needs the container's height to know
187
+ * when a dragged row has reached an edge and autoscroll should start;
188
+ * there is no autoscroll here (docs/research/drag-and-drop.md), and the
189
+ * rows are in flow layout inside a real `ScrollView` that already knows
190
+ * its own size.
191
+ *
192
+ * Kept because upstream's own example app passes it on every
193
+ * `SortableItem` — a mirror that drops it turns a literal port into an
194
+ * edit, which is the one thing this module exists to avoid.
195
+ */
196
+ containerHeight?: number;
197
+ /** Accepted and ignored, same reason. */
198
+ isDynamicHeight?: boolean;
199
+ scheduleHeightUpdate?: (id: string, height: number) => void;
200
+ }
201
+ export interface SortableCallbacks {
202
+ onMove?: (id: string, from: number, to: number) => void;
203
+ onDragStart?: (id: string, position: number) => void;
204
+ onDrop?: (id: string, position: number, allPositions?: Record<string, number>) => void;
205
+ onDragging?: (id: string, overItemId: string | null, yPosition: number) => void;
206
+ }
207
+ export interface UseSortableOptions<TData = unknown> extends SortableCallbacks, SortableItemPlumbing {
208
+ id: string;
209
+ data?: TData;
210
+ }
211
+ export interface UseSortableReturn {
212
+ /** Upstream returns a Reanimated style here. This platform reorders by
213
+ * re-rendering, so the row needs no transform — the field stays for
214
+ * spread compatibility. */
215
+ animatedStyle: StyleProp;
216
+ isMoving: boolean;
217
+ hasHandle: boolean;
218
+ registerHandle: (registered: boolean) => void;
219
+ /** Everything the row's view must contain: the drop target always, and the
220
+ * drag source unless a handle has claimed it. */
221
+ children: ReactNode;
222
+ /** The drag source on its own, for a caller placing its own handle. */
223
+ dragControllers: ReactNode;
224
+ }
225
+ export interface SortableItemProps<TData = unknown> extends Partial<SortableItemPlumbing>, SortableCallbacks {
226
+ id: string;
227
+ data?: TData;
228
+ children: ReactNode;
229
+ style?: StyleProp;
230
+ /** Accepted for spread compatibility; upstream's own transform style. */
231
+ animatedStyle?: StyleProp;
232
+ direction?: SortableDirection;
233
+ testID?: string;
234
+ }
235
+ export interface SortableRenderItemProps<TData extends SortableData> extends SortableItemPlumbing {
236
+ item: TData;
237
+ index: number;
238
+ id: string;
239
+ direction?: SortableDirection;
240
+ }
241
+ export interface SortableProps<TData extends SortableData> extends SortableCallbacks {
242
+ data: TData[];
243
+ renderItem: (props: SortableRenderItemProps<TData>) => ReactNode;
244
+ itemKeyExtractor?: (item: TData, index: number) => string;
245
+ style?: StyleProp;
246
+ contentContainerStyle?: StyleProp;
247
+ testID?: string;
248
+ /** Accepted and ignored — see `SortableItemPlumbing`. */
249
+ itemHeight?: number | number[] | ((item: TData, index: number) => number);
250
+ /** Accepted and ignored. */
251
+ estimatedItemHeight?: number;
252
+ /** Accepted and ignored. */
253
+ enableDynamicHeights?: boolean;
254
+ /** Accepted and ignored. */
255
+ useFlatList?: boolean;
256
+ /** Accepted and ignored. */
257
+ onHeightsMeasured?: (heights: Record<string, number>) => void;
258
+ /** `SortableDirection.Horizontal` is not implemented — see
259
+ * docs/research/drag-and-drop.md. Passing it throws, rather than
260
+ * silently laying out vertically. */
261
+ direction?: SortableDirection;
262
+ }
263
+ export interface SortableHandleProps {
264
+ children: ReactNode;
265
+ style?: StyleProp;
266
+ testID?: string;
267
+ }
268
+ export interface UseSortableListOptions<TData extends SortableData> {
269
+ data: TData[];
270
+ itemKeyExtractor?: (item: TData, index: number) => string;
271
+ itemHeight?: number | number[] | ((item: TData, index: number) => number);
272
+ enableDynamicHeights?: boolean;
273
+ estimatedItemHeight?: number;
274
+ onHeightsMeasured?: (heights: Record<string, number>) => void;
275
+ }
276
+ export interface UseSortableListReturn<TData extends SortableData> {
277
+ positions: SharedValueLike<Record<string, number>>;
278
+ scrollY: SharedValueLike<number>;
279
+ autoScroll: SharedValueLike<ScrollDirection>;
280
+ itemHeights: SharedValueLike<Record<string, number>>;
281
+ dropProviderRef: RefObject<DropProviderRef | null>;
282
+ handleScroll: () => void;
283
+ handleScrollEnd: () => void;
284
+ contentHeight: number;
285
+ isDynamicHeight: boolean;
286
+ /** The current order, which this hook owns — upstream keeps the same
287
+ * contract ("do NOT update external state in `onMove`"). */
288
+ items: TData[];
289
+ getItemProps: (item: TData, index: number) => SortableItemPlumbing;
290
+ }