react-native-reorderable-list 0.16.2 → 0.17.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 (48) hide show
  1. package/README.md +12 -5
  2. package/lib/commonjs/components/NestedReorderableList.js +6 -6
  3. package/lib/commonjs/components/NestedReorderableList.js.map +1 -1
  4. package/lib/commonjs/components/ReorderableList.js +3 -3
  5. package/lib/commonjs/components/ReorderableList.js.map +1 -1
  6. package/lib/commonjs/components/ReorderableListCell.js +20 -18
  7. package/lib/commonjs/components/ReorderableListCell.js.map +1 -1
  8. package/lib/commonjs/components/ReorderableListCore.js +168 -158
  9. package/lib/commonjs/components/ReorderableListCore.js.map +1 -1
  10. package/lib/commonjs/components/ScrollViewContainer.js +13 -12
  11. package/lib/commonjs/components/ScrollViewContainer.js.map +1 -1
  12. package/lib/commonjs/contexts/ReorderableListContext.js.map +1 -1
  13. package/lib/commonjs/index.js.map +1 -1
  14. package/lib/module/components/NestedReorderableList.js +6 -6
  15. package/lib/module/components/NestedReorderableList.js.map +1 -1
  16. package/lib/module/components/ReorderableList.js +3 -3
  17. package/lib/module/components/ReorderableList.js.map +1 -1
  18. package/lib/module/components/ReorderableListCell.js +20 -18
  19. package/lib/module/components/ReorderableListCell.js.map +1 -1
  20. package/lib/module/components/ReorderableListCore.js +168 -158
  21. package/lib/module/components/ReorderableListCore.js.map +1 -1
  22. package/lib/module/components/ScrollViewContainer.js +13 -12
  23. package/lib/module/components/ScrollViewContainer.js.map +1 -1
  24. package/lib/module/contexts/ReorderableListContext.js.map +1 -1
  25. package/lib/module/index.js.map +1 -1
  26. package/lib/typescript/components/ReorderableListCell.d.ts +3 -3
  27. package/lib/typescript/components/ReorderableListCell.d.ts.map +1 -1
  28. package/lib/typescript/components/ReorderableListCore.d.ts +3 -3
  29. package/lib/typescript/components/ReorderableListCore.d.ts.map +1 -1
  30. package/lib/typescript/components/ScrollViewContainer.d.ts.map +1 -1
  31. package/lib/typescript/contexts/ReorderableListContext.d.ts +2 -1
  32. package/lib/typescript/contexts/ReorderableListContext.d.ts.map +1 -1
  33. package/lib/typescript/contexts/ScrollViewContainerContext.d.ts +3 -3
  34. package/lib/typescript/contexts/ScrollViewContainerContext.d.ts.map +1 -1
  35. package/lib/typescript/index.d.ts +2 -2
  36. package/lib/typescript/index.d.ts.map +1 -1
  37. package/lib/typescript/types/props.d.ts +18 -4
  38. package/lib/typescript/types/props.d.ts.map +1 -1
  39. package/package.json +1 -1
  40. package/src/components/NestedReorderableList.tsx +6 -6
  41. package/src/components/ReorderableList.tsx +3 -3
  42. package/src/components/ReorderableListCell.tsx +27 -19
  43. package/src/components/ReorderableListCore.tsx +277 -217
  44. package/src/components/ScrollViewContainer.tsx +27 -14
  45. package/src/contexts/ReorderableListContext.ts +2 -1
  46. package/src/contexts/ScrollViewContainerContext.ts +3 -3
  47. package/src/index.ts +2 -0
  48. package/src/types/props.ts +24 -5
@@ -63,9 +63,9 @@ const AnimatedFlatList = Animated.createAnimatedComponent(
63
63
  interface ReorderableListCoreProps<T> extends ReorderableListProps<T> {
64
64
  // Not optional but undefined to force passing the prop.
65
65
  scrollViewContainerRef: RefObject<ScrollView> | undefined;
66
- scrollViewPageY: SharedValue<number> | undefined;
67
- scrollViewHeightY: SharedValue<number> | undefined;
68
- scrollViewScrollOffsetY: SharedValue<number> | undefined;
66
+ scrollViewPageXY: SharedValue<number> | undefined;
67
+ scrollViewSize: SharedValue<number> | undefined;
68
+ scrollViewScrollOffsetXY: SharedValue<number> | undefined;
69
69
  scrollViewScrollEnabledProp: SharedValue<boolean> | undefined;
70
70
  setScrollViewForceDisableScroll:
71
71
  | Dispatch<SetStateAction<boolean>>
@@ -89,9 +89,9 @@ const ReorderableListCore = <T,>(
89
89
  onDragEnd,
90
90
  onIndexChange,
91
91
  scrollViewContainerRef,
92
- scrollViewPageY,
93
- scrollViewHeightY,
94
- scrollViewScrollOffsetY,
92
+ scrollViewPageXY,
93
+ scrollViewSize,
94
+ scrollViewScrollOffsetXY,
95
95
  scrollViewScrollEnabledProp,
96
96
  setScrollViewForceDisableScroll,
97
97
  scrollable,
@@ -121,37 +121,37 @@ const ReorderableListCore = <T,>(
121
121
  const currentScrollEnabled = useSharedValue(scrollEnabled);
122
122
 
123
123
  const gestureState = useSharedValue<State>(State.UNDETERMINED);
124
- const currentY = useSharedValue(0);
125
- const currentTranslationY = useSharedValue(0);
126
- const currentItemDragCenterY = useSharedValue<number | null>(null);
127
- const startItemDragCenterY = useSharedValue<number>(0);
128
- const flatListScrollOffsetY = useSharedValue(0);
129
- const flatListHeightY = useSharedValue(0);
130
- const flatListPageY = useSharedValue(0);
131
- // The scroll y translation of the list since drag start
132
- const dragScrollTranslationY = useSharedValue(0);
133
- // The initial scroll offset y of the list on drag start
134
- const dragInitialScrollOffsetY = useSharedValue(0);
135
- // The scroll y translation of the ScrollViewContainer since drag start
136
- const scrollViewDragScrollTranslationY = useSharedValue(0);
137
- // The initial scroll offset y of the ScrollViewContainer on drag start
138
- const scrollViewDragInitialScrollOffsetY = useSharedValue(0);
139
- const draggedHeight = useSharedValue(0);
124
+ const currentXY = useSharedValue(0);
125
+ const currentTranslationXY = useSharedValue(0);
126
+ const currentItemDragCenterXY = useSharedValue<number | null>(null);
127
+ const startItemDragCenterXY = useSharedValue<number>(0);
128
+ const flatListScrollOffsetXY = useSharedValue(0);
129
+ const flatListSize = useSharedValue(0);
130
+ const flatListPageXY = useSharedValue(0);
131
+ // The scroll x or y translation of the list since drag start
132
+ const dragScrollTranslationXY = useSharedValue(0);
133
+ // The initial scroll offset x or y of the list on drag start
134
+ const dragInitialScrollOffsetXY = useSharedValue(0);
135
+ // The scroll x or y translation of the ScrollViewContainer since drag start
136
+ const scrollViewDragScrollTranslationXY = useSharedValue(0);
137
+ // The initial scroll offset x or y of the ScrollViewContainer on drag start
138
+ const scrollViewDragInitialScrollOffsetXY = useSharedValue(0);
139
+ const draggedSize = useSharedValue(0);
140
140
  const itemOffset = useSharedValue<number[]>([]);
141
- const itemHeight = useSharedValue<number[]>([]);
142
- // We need to track data length since itemOffset and itemHeight might contain more data than we need.
141
+ const itemSize = useSharedValue<number[]>([]);
142
+ // We need to track data length since itemOffset and itemSize might contain more data than we need.
143
143
  // e.g. items are removed from the list, in which case layout data for those items is set to 0.
144
144
  const itemCount = useSharedValue(data.length);
145
145
  const autoscrollTrigger = useSharedValue(-1);
146
146
  const lastAutoscrollTrigger = useSharedValue(-1);
147
- const dragY = useSharedValue(0);
147
+ const dragXY = useSharedValue(0);
148
148
  const currentIndex = useSharedValue(-1);
149
149
  const draggedIndex = useSharedValue(-1);
150
150
  const state = useSharedValue<ReorderableListState>(ReorderableListState.IDLE);
151
151
  const dragEndHandlers = useSharedValue<
152
152
  ((from: number, to: number) => void)[][]
153
153
  >([]);
154
- const startY = useSharedValue(0);
154
+ const startXY = useSharedValue(0);
155
155
  const scaleDefault = useSharedValue(1);
156
156
  const opacityDefault = useSharedValue(1);
157
157
  const dragDirection = useSharedValue(0);
@@ -168,10 +168,11 @@ const ReorderableListCore = <T,>(
168
168
  autoscrollActivationDelta,
169
169
  );
170
170
  const dragEnabledProp = usePropAsSharedValue(dragEnabled ?? true);
171
+ const horizontalProp = usePropAsSharedValue(!!rest.horizontal);
171
172
 
172
173
  // Position of the list relative to the scroll container
173
- const nestedFlatListPositionY = useDerivedValue(
174
- () => flatListPageY.value - (scrollViewPageY?.value || 0),
174
+ const nestedFlatListPositionXY = useDerivedValue(
175
+ () => flatListPageXY.value - (scrollViewPageXY?.value || 0),
175
176
  );
176
177
 
177
178
  useEffect(() => {
@@ -183,14 +184,14 @@ const ReorderableListCore = <T,>(
183
184
  if (data.length < prevItemCount.current) {
184
185
  for (let i = data.length; i < prevItemCount.current; i++) {
185
186
  runOnUI(() => {
186
- itemHeight.value[i] = 0;
187
+ itemSize.value[i] = 0;
187
188
  itemOffset.value[i] = 0;
188
189
  })();
189
190
  }
190
191
  }
191
192
 
192
193
  prevItemCount.current = data.length;
193
- }, [data.length, itemHeight, itemOffset, itemCount]);
194
+ }, [data.length, itemSize, itemOffset, itemCount]);
194
195
 
195
196
  useEffect(() => {
196
197
  if (
@@ -230,12 +231,13 @@ const ReorderableListCore = <T,>(
230
231
 
231
232
  const listContextValue = useMemo(
232
233
  () => ({
233
- draggedHeight,
234
+ draggedSize,
234
235
  currentIndex,
235
236
  draggedIndex,
236
237
  dragEndHandlers,
237
238
  activeIndex,
238
239
  itemLayoutAnimation: itemLayoutAnimationPropRef,
240
+ horizontal: horizontalProp,
239
241
  cellAnimations: {
240
242
  ...cellAnimations,
241
243
  transform:
@@ -249,7 +251,7 @@ const ReorderableListCore = <T,>(
249
251
  },
250
252
  }),
251
253
  [
252
- draggedHeight,
254
+ draggedSize,
253
255
  currentIndex,
254
256
  draggedIndex,
255
257
  dragEndHandlers,
@@ -258,6 +260,7 @@ const ReorderableListCore = <T,>(
258
260
  itemLayoutAnimationPropRef,
259
261
  scaleDefault,
260
262
  opacityDefault,
263
+ horizontalProp,
261
264
  ],
262
265
  );
263
266
 
@@ -272,52 +275,65 @@ const ReorderableListCore = <T,>(
272
275
  (e: GestureUpdateEvent<PanGestureHandlerEventPayload>) => {
273
276
  'worklet';
274
277
 
275
- const direction = e.velocityY > 0 ? 1 : -1;
278
+ const absoluteXY = horizontalProp.value ? e.absoluteX : e.absoluteY;
279
+ const velocityXY = horizontalProp.value ? e.velocityX : e.velocityY;
280
+
281
+ const direction = velocityXY > 0 ? 1 : -1;
276
282
  if (direction !== dragDirection.value) {
277
283
  if (lastDragDirectionPivot.value === null) {
278
- lastDragDirectionPivot.value = e.absoluteY;
284
+ lastDragDirectionPivot.value = absoluteXY;
279
285
  } else if (
280
- Math.abs(e.absoluteY - lastDragDirectionPivot.value) >=
286
+ Math.abs(absoluteXY - lastDragDirectionPivot.value) >=
281
287
  autoscrollActivationDeltaProp.value
282
288
  ) {
283
289
  dragDirection.value = direction;
284
- lastDragDirectionPivot.value = e.absoluteY;
290
+ lastDragDirectionPivot.value = absoluteXY;
285
291
  }
286
292
  }
287
293
  },
288
- [dragDirection, lastDragDirectionPivot, autoscrollActivationDeltaProp],
294
+ [
295
+ dragDirection,
296
+ lastDragDirectionPivot,
297
+ autoscrollActivationDeltaProp,
298
+ horizontalProp,
299
+ ],
289
300
  );
290
301
 
291
- const setCurrentItemDragCenterY = useCallback(
302
+ const setCurrentItemDragCenterXY = useCallback(
292
303
  (e: GestureUpdateEvent<PanGestureHandlerEventPayload>) => {
293
304
  'worklet';
294
305
 
295
- if (currentItemDragCenterY.value === null) {
306
+ const translationXY = horizontalProp.value
307
+ ? e.translationX
308
+ : e.translationY;
309
+
310
+ if (currentItemDragCenterXY.value === null) {
296
311
  if (currentIndex.value >= 0) {
297
- const itemCenter = itemHeight.value[currentIndex.value] * 0.5;
298
- // the y coordinate of the item relative to the list
299
- const itemY =
312
+ const itemCenter = itemSize.value[currentIndex.value] * 0.5;
313
+ // the x or y coordinate of the item relative to the list
314
+ const itemXY =
300
315
  itemOffset.value[currentIndex.value] -
301
- (flatListScrollOffsetY.value +
302
- scrollViewDragScrollTranslationY.value);
316
+ (flatListScrollOffsetXY.value +
317
+ scrollViewDragScrollTranslationXY.value);
303
318
 
304
- const value = itemY + itemCenter + e.translationY;
305
- startItemDragCenterY.value = value;
306
- currentItemDragCenterY.value = value;
319
+ const value = itemXY + itemCenter + translationXY;
320
+ startItemDragCenterXY.value = value;
321
+ currentItemDragCenterXY.value = value;
307
322
  }
308
323
  } else {
309
- currentItemDragCenterY.value =
310
- startItemDragCenterY.value + e.translationY;
324
+ currentItemDragCenterXY.value =
325
+ startItemDragCenterXY.value + translationXY;
311
326
  }
312
327
  },
313
328
  [
314
- currentItemDragCenterY,
329
+ horizontalProp,
330
+ currentItemDragCenterXY,
315
331
  currentIndex,
316
- startItemDragCenterY,
332
+ startItemDragCenterXY,
317
333
  itemOffset,
318
- itemHeight,
319
- flatListScrollOffsetY,
320
- scrollViewDragScrollTranslationY,
334
+ itemSize,
335
+ flatListScrollOffsetXY,
336
+ scrollViewDragScrollTranslationXY,
321
337
  ],
322
338
  );
323
339
 
@@ -329,10 +345,15 @@ const ReorderableListCore = <T,>(
329
345
 
330
346
  // prevent new dragging until item is completely released
331
347
  if (state.value === ReorderableListState.IDLE) {
332
- startY.value = e.y;
333
- currentY.value = e.y;
334
- currentTranslationY.value = e.translationY;
335
- dragY.value = e.translationY;
348
+ const xy = horizontalProp.value ? e.x : e.y;
349
+ const translationXY = horizontalProp.value
350
+ ? e.translationX
351
+ : e.translationY;
352
+
353
+ startXY.value = xy;
354
+ currentXY.value = xy;
355
+ currentTranslationXY.value = translationXY;
356
+ dragXY.value = translationXY;
336
357
  gestureState.value = e.state;
337
358
  }
338
359
  })
@@ -344,14 +365,18 @@ const ReorderableListCore = <T,>(
344
365
  }
345
366
 
346
367
  if (state.value !== ReorderableListState.RELEASED) {
347
- setCurrentItemDragCenterY(e);
348
-
349
- currentY.value = startY.value + e.translationY;
350
- currentTranslationY.value = e.translationY;
351
- dragY.value =
352
- e.translationY +
353
- dragScrollTranslationY.value +
354
- scrollViewDragScrollTranslationY.value;
368
+ setCurrentItemDragCenterXY(e);
369
+
370
+ const translationXY = horizontalProp.value
371
+ ? e.translationX
372
+ : e.translationY;
373
+
374
+ currentXY.value = startXY.value + translationXY;
375
+ currentTranslationXY.value = translationXY;
376
+ dragXY.value =
377
+ translationXY +
378
+ dragScrollTranslationXY.value +
379
+ scrollViewDragScrollTranslationXY.value;
355
380
  gestureState.value = e.state;
356
381
  }
357
382
  })
@@ -368,15 +393,16 @@ const ReorderableListCore = <T,>(
368
393
  [
369
394
  panGesture,
370
395
  state,
371
- startY,
372
- currentY,
373
- currentTranslationY,
374
- dragY,
396
+ startXY,
397
+ currentXY,
398
+ currentTranslationXY,
399
+ dragXY,
375
400
  gestureState,
376
- dragScrollTranslationY,
377
- scrollViewDragScrollTranslationY,
401
+ dragScrollTranslationXY,
402
+ scrollViewDragScrollTranslationXY,
378
403
  setDragDirection,
379
- setCurrentItemDragCenterY,
404
+ setCurrentItemDragCenterXY,
405
+ horizontalProp,
380
406
  ],
381
407
  );
382
408
 
@@ -440,21 +466,21 @@ const ReorderableListCore = <T,>(
440
466
 
441
467
  state.value = ReorderableListState.IDLE;
442
468
  draggedIndex.value = -1;
443
- dragY.value = 0;
444
- dragScrollTranslationY.value = 0;
445
- scrollViewDragScrollTranslationY.value = 0;
469
+ dragXY.value = 0;
470
+ dragScrollTranslationXY.value = 0;
471
+ scrollViewDragScrollTranslationXY.value = 0;
446
472
  dragDirection.value = 0;
447
473
  lastDragDirectionPivot.value = null;
448
- currentItemDragCenterY.value = null;
474
+ currentItemDragCenterXY.value = null;
449
475
  }, [
450
476
  state,
451
477
  draggedIndex,
452
- dragY,
453
- dragScrollTranslationY,
454
- scrollViewDragScrollTranslationY,
478
+ dragXY,
479
+ dragScrollTranslationXY,
480
+ scrollViewDragScrollTranslationXY,
455
481
  dragDirection,
456
482
  lastDragDirectionPivot,
457
- currentItemDragCenterY,
483
+ currentItemDragCenterXY,
458
484
  ]);
459
485
 
460
486
  const resetSharedValuesAfterAnimations = useCallback(() => {
@@ -496,19 +522,19 @@ const ReorderableListCore = <T,>(
496
522
  const index2 = itemDirection ? to : from;
497
523
 
498
524
  const newOffset1 = itemOffset.value[index1];
499
- const newHeight1 = itemHeight.value[index2];
525
+ const newSize1 = itemSize.value[index2];
500
526
  const newOffset2 =
501
527
  itemOffset.value[index2] +
502
- itemHeight.value[index2] -
503
- itemHeight.value[index1];
504
- const newHeight2 = itemHeight.value[index1];
528
+ itemSize.value[index2] -
529
+ itemSize.value[index1];
530
+ const newSize2 = itemSize.value[index1];
505
531
 
506
532
  itemOffset.value[index1] = newOffset1;
507
- itemHeight.value[index1] = newHeight1;
533
+ itemSize.value[index1] = newSize1;
508
534
  itemOffset.value[index2] = newOffset2;
509
- itemHeight.value[index2] = newHeight2;
535
+ itemSize.value[index2] = newSize2;
510
536
  },
511
- [itemOffset, itemHeight],
537
+ [itemOffset, itemSize],
512
538
  );
513
539
 
514
540
  /**
@@ -521,36 +547,38 @@ const ReorderableListCore = <T,>(
521
547
  const computeCurrentIndex = useCallback(() => {
522
548
  'worklet';
523
549
 
524
- if (currentItemDragCenterY.value === null) {
550
+ if (currentItemDragCenterXY.value === null) {
525
551
  return currentIndex.value;
526
552
  }
527
553
 
528
- // apply scroll offset and scroll container translation
529
- const relativeDragCenterY =
530
- flatListScrollOffsetY.value +
531
- scrollViewDragScrollTranslationY.value +
532
- currentItemDragCenterY.value;
554
+ // Apply scroll offset and scroll container translation.
555
+ const relativeDragCenterXY =
556
+ flatListScrollOffsetXY.value +
557
+ scrollViewDragScrollTranslationXY.value +
558
+ currentItemDragCenterXY.value;
533
559
 
534
560
  const currentOffset = itemOffset.value[currentIndex.value];
535
- const currentHeight = itemHeight.value[currentIndex.value];
536
- const currentCenter = currentOffset + currentHeight * 0.5;
561
+ const currentSize = itemSize.value[currentIndex.value];
562
+ const currentCenter = currentOffset + currentSize * 0.5;
537
563
 
538
564
  const max = itemCount.value;
539
565
  const possibleIndex =
540
- relativeDragCenterY < currentCenter
566
+ relativeDragCenterXY < currentCenter
541
567
  ? Math.max(0, currentIndex.value - 1)
542
568
  : Math.min(max - 1, currentIndex.value + 1);
543
569
 
544
570
  if (currentIndex.value !== possibleIndex) {
545
571
  let possibleOffset = itemOffset.value[possibleIndex];
546
572
  if (possibleIndex > currentIndex.value) {
547
- possibleOffset += itemHeight.value[possibleIndex] - currentHeight;
573
+ possibleOffset += itemSize.value[possibleIndex] - currentSize;
548
574
  }
549
575
 
550
- const possibleCenter = possibleOffset + currentHeight * 0.5;
551
- const distanceFromCurrent = Math.abs(relativeDragCenterY - currentCenter);
576
+ const possibleCenter = possibleOffset + currentSize * 0.5;
577
+ const distanceFromCurrent = Math.abs(
578
+ relativeDragCenterXY - currentCenter,
579
+ );
552
580
  const distanceFromPossible = Math.abs(
553
- relativeDragCenterY - possibleCenter,
581
+ relativeDragCenterXY - possibleCenter,
554
582
  );
555
583
 
556
584
  return distanceFromCurrent <= distanceFromPossible
@@ -561,12 +589,12 @@ const ReorderableListCore = <T,>(
561
589
  return currentIndex.value;
562
590
  }, [
563
591
  currentIndex,
564
- currentItemDragCenterY,
592
+ currentItemDragCenterXY,
565
593
  itemCount,
566
594
  itemOffset,
567
- itemHeight,
568
- flatListScrollOffsetY,
569
- scrollViewDragScrollTranslationY,
595
+ itemSize,
596
+ flatListScrollOffsetXY,
597
+ scrollViewDragScrollTranslationXY,
570
598
  ]);
571
599
 
572
600
  const setCurrentIndex = useCallback(() => {
@@ -592,7 +620,7 @@ const ReorderableListCore = <T,>(
592
620
  scaleDefault.value = withTiming(scaleConfig.toValue, scaleConfig);
593
621
  }
594
622
 
595
- // if no custom opacity run the default
623
+ // If no custom opacity run the default.
596
624
  if (!(cellAnimations && 'opacity' in cellAnimations)) {
597
625
  const opacityConfig = OPACITY_ANIMATION_CONFIG_DEFAULT[type];
598
626
  opacityDefault.value = withTiming(opacityConfig.toValue, opacityConfig);
@@ -619,7 +647,7 @@ const ReorderableListCore = <T,>(
619
647
  runOnJS(setActiveIndex)(-1);
620
648
  }
621
649
 
622
- // trigger onDragEnd event
650
+ // Trigger onDragEnd event.
623
651
  let e = {from: draggedIndex.value, to: currentIndex.value};
624
652
  onDragEnd?.(e);
625
653
 
@@ -630,23 +658,23 @@ const ReorderableListCore = <T,>(
630
658
 
631
659
  // they are actually swapped on drag translation
632
660
  const currentItemOffset = itemOffset.value[draggedIndex.value];
633
- const currentItemHeight = itemHeight.value[draggedIndex.value];
661
+ const currentItemSize = itemSize.value[draggedIndex.value];
634
662
  const draggedItemOffset = itemOffset.value[currentIndex.value];
635
- const draggedItemHeight = itemHeight.value[currentIndex.value];
663
+ const draggedItemSize = itemSize.value[currentIndex.value];
636
664
 
637
- const newTopPosition =
665
+ const newPositionXY =
638
666
  currentIndex.value > draggedIndex.value
639
667
  ? draggedItemOffset - currentItemOffset
640
668
  : draggedItemOffset -
641
669
  currentItemOffset +
642
- (draggedItemHeight - currentItemHeight);
670
+ (draggedItemSize - currentItemSize);
643
671
 
644
672
  runDefaultDragAnimations('end');
645
673
 
646
- if (dragY.value !== newTopPosition) {
647
- // animate dragged item to its new position on release
648
- dragY.value = withTiming(
649
- newTopPosition,
674
+ if (dragXY.value !== newPositionXY) {
675
+ // Animate dragged item to its new position on release.
676
+ dragXY.value = withTiming(
677
+ newPositionXY,
650
678
  {
651
679
  duration: animationDurationProp.value,
652
680
  easing: Easing.out(Easing.ease),
@@ -656,9 +684,9 @@ const ReorderableListCore = <T,>(
656
684
  },
657
685
  );
658
686
  } else {
659
- // user might drag and release the item without moving it so,
687
+ // User might drag and release the item without moving it so,
660
688
  // since the animation end callback is not executed in that case
661
- // we need to reset values as the reorder function would do
689
+ // we need to reset values as the reorder function would do.
662
690
  runOnJS(resetSharedValuesAfterAnimations)();
663
691
  }
664
692
  }
@@ -667,28 +695,28 @@ const ReorderableListCore = <T,>(
667
695
 
668
696
  const computeHiddenArea = useCallback(() => {
669
697
  'worklet';
670
- if (!scrollViewScrollOffsetY || !scrollViewHeightY) {
671
- return {top: 0, bottom: 0};
698
+ if (!scrollViewScrollOffsetXY || !scrollViewSize) {
699
+ return {start: 0, end: 0};
672
700
  }
673
701
 
674
702
  // hidden area cannot be negative
675
- const top = Math.max(
703
+ const start = Math.max(
676
704
  0,
677
- scrollViewScrollOffsetY.value - nestedFlatListPositionY.value,
705
+ scrollViewScrollOffsetXY.value - nestedFlatListPositionXY.value,
678
706
  );
679
- const bottom = Math.max(
707
+ const end = Math.max(
680
708
  0,
681
- nestedFlatListPositionY.value +
682
- flatListHeightY.value -
683
- (scrollViewScrollOffsetY.value + scrollViewHeightY.value),
709
+ nestedFlatListPositionXY.value +
710
+ flatListSize.value -
711
+ (scrollViewScrollOffsetXY.value + scrollViewSize.value),
684
712
  );
685
713
 
686
- return {top, bottom};
714
+ return {start, end};
687
715
  }, [
688
- scrollViewScrollOffsetY,
689
- scrollViewHeightY,
690
- nestedFlatListPositionY,
691
- flatListHeightY,
716
+ scrollViewScrollOffsetXY,
717
+ scrollViewSize,
718
+ nestedFlatListPositionXY,
719
+ flatListSize,
692
720
  ]);
693
721
 
694
722
  const computeThresholdArea = useCallback(() => {
@@ -696,43 +724,55 @@ const ReorderableListCore = <T,>(
696
724
 
697
725
  const hiddenArea = computeHiddenArea();
698
726
 
699
- const offsetTop = Math.max(0, autoscrollThresholdOffset?.top || 0);
700
- const offsetBottom = Math.max(0, autoscrollThresholdOffset?.bottom || 0);
727
+ const offsetStart = Math.max(
728
+ 0,
729
+ autoscrollThresholdOffset?.start || autoscrollThresholdOffset?.top || 0,
730
+ );
731
+ const offsetEnd = Math.max(
732
+ 0,
733
+ autoscrollThresholdOffset?.end || autoscrollThresholdOffset?.bottom || 0,
734
+ );
701
735
  const threshold = Math.max(0, Math.min(autoscrollThreshold, 0.4));
702
- const visibleHeight =
703
- flatListHeightY.value -
704
- (hiddenArea.top + hiddenArea.bottom) -
705
- (offsetTop + offsetBottom);
736
+ const visibleSize =
737
+ flatListSize.value -
738
+ (hiddenArea.start + hiddenArea.end) -
739
+ (offsetStart + offsetEnd);
706
740
 
707
- const area = visibleHeight * threshold;
708
- const top = area + offsetTop;
709
- const bottom = flatListHeightY.value - area - offsetBottom;
741
+ const area = visibleSize * threshold;
742
+ const start = area + offsetStart;
743
+ const end = flatListSize.value - area - offsetEnd;
710
744
 
711
- return {top, bottom};
745
+ return {start, end};
712
746
  }, [
713
747
  computeHiddenArea,
714
748
  autoscrollThreshold,
715
749
  autoscrollThresholdOffset,
716
- flatListHeightY,
750
+ flatListSize,
717
751
  ]);
718
752
 
719
753
  const computeContainerThresholdArea = useCallback(() => {
720
754
  'worklet';
721
- if (!scrollViewHeightY) {
722
- return {top: -Infinity, bottom: Infinity};
755
+ if (!scrollViewSize) {
756
+ return {start: -Infinity, end: Infinity};
723
757
  }
724
758
 
725
- const offsetTop = Math.max(0, autoscrollThresholdOffset?.top || 0);
726
- const offsetBottom = Math.max(0, autoscrollThresholdOffset?.bottom || 0);
759
+ const offsetStart = Math.max(
760
+ 0,
761
+ autoscrollThresholdOffset?.start || autoscrollThresholdOffset?.top || 0,
762
+ );
763
+ const offsetEnd = Math.max(
764
+ 0,
765
+ autoscrollThresholdOffset?.end || autoscrollThresholdOffset?.bottom || 0,
766
+ );
727
767
  const threshold = Math.max(0, Math.min(autoscrollThreshold, 0.4));
728
- const visibleHeight = scrollViewHeightY.value - (offsetTop + offsetBottom);
768
+ const visibleSize = scrollViewSize.value - (offsetStart + offsetEnd);
729
769
 
730
- const area = visibleHeight * threshold;
731
- const top = area + offsetTop;
732
- const bottom = visibleHeight - area - offsetBottom;
770
+ const area = visibleSize * threshold;
771
+ const start = area + offsetStart;
772
+ const end = visibleSize - area - offsetEnd;
733
773
 
734
- return {top, bottom};
735
- }, [autoscrollThreshold, autoscrollThresholdOffset, scrollViewHeightY]);
774
+ return {start, end};
775
+ }, [autoscrollThreshold, autoscrollThresholdOffset, scrollViewSize]);
736
776
 
737
777
  const shouldScrollContainer = useCallback(
738
778
  (y: number) => {
@@ -743,52 +783,56 @@ const ReorderableListCore = <T,>(
743
783
  // We should scroll the container if there's a hidden part of the nested list.
744
784
  // We might have floating errors like 0.0001 which we should ignore.
745
785
  return (
746
- (nestedListHiddenArea.top > 0.01 && y <= containerThresholdArea.top) ||
747
- (nestedListHiddenArea.bottom > 0.01 &&
748
- y >= containerThresholdArea.bottom)
786
+ (nestedListHiddenArea.start > 0.01 &&
787
+ y <= containerThresholdArea.start) ||
788
+ (nestedListHiddenArea.end > 0.01 && y >= containerThresholdArea.end)
749
789
  );
750
790
  },
751
791
  [computeHiddenArea, computeContainerThresholdArea],
752
792
  );
753
793
 
754
- const getRelativeContainerY = useCallback(() => {
794
+ const getRelativeContainerXY = useCallback(() => {
755
795
  'worklet';
756
796
 
757
797
  return (
758
- currentY.value +
759
- nestedFlatListPositionY.value -
760
- scrollViewDragInitialScrollOffsetY.value
798
+ currentXY.value +
799
+ nestedFlatListPositionXY.value -
800
+ scrollViewDragInitialScrollOffsetXY.value
761
801
  );
762
- }, [currentY, nestedFlatListPositionY, scrollViewDragInitialScrollOffsetY]);
802
+ }, [
803
+ currentXY,
804
+ nestedFlatListPositionXY,
805
+ scrollViewDragInitialScrollOffsetXY,
806
+ ]);
763
807
 
764
- const getRelativeListY = useCallback(() => {
808
+ const getRelativeListXY = useCallback(() => {
765
809
  'worklet';
766
810
 
767
- return currentY.value + scrollViewDragScrollTranslationY.value;
768
- }, [currentY, scrollViewDragScrollTranslationY]);
811
+ return currentXY.value + scrollViewDragScrollTranslationXY.value;
812
+ }, [currentXY, scrollViewDragScrollTranslationXY]);
769
813
 
770
814
  const scrollDirection = useCallback(() => {
771
815
  'worklet';
772
816
 
773
- const relativeContainerY = getRelativeContainerY();
774
- if (shouldScrollContainer(relativeContainerY)) {
817
+ const relativeContainerXY = getRelativeContainerXY();
818
+ if (shouldScrollContainer(relativeContainerXY)) {
775
819
  const containerThresholdArea = computeContainerThresholdArea();
776
- if (relativeContainerY <= containerThresholdArea.top) {
820
+ if (relativeContainerXY <= containerThresholdArea.start) {
777
821
  return -1;
778
822
  }
779
823
 
780
- if (relativeContainerY >= containerThresholdArea.bottom) {
824
+ if (relativeContainerXY >= containerThresholdArea.end) {
781
825
  return 1;
782
826
  }
783
827
  } else if (scrollable) {
784
- const relativeListY = getRelativeListY();
828
+ const relativeListXY = getRelativeListXY();
785
829
  const thresholdArea = computeThresholdArea();
786
830
 
787
- if (relativeListY <= thresholdArea.top) {
831
+ if (relativeListXY <= thresholdArea.start) {
788
832
  return -1;
789
833
  }
790
834
 
791
- if (relativeListY >= thresholdArea.bottom) {
835
+ if (relativeListXY >= thresholdArea.end) {
792
836
  return 1;
793
837
  }
794
838
  }
@@ -798,13 +842,13 @@ const ReorderableListCore = <T,>(
798
842
  shouldScrollContainer,
799
843
  computeThresholdArea,
800
844
  computeContainerThresholdArea,
801
- getRelativeContainerY,
802
- getRelativeListY,
845
+ getRelativeContainerXY,
846
+ getRelativeListXY,
803
847
  scrollable,
804
848
  ]);
805
849
 
806
850
  useAnimatedReaction(
807
- () => currentY.value,
851
+ () => currentXY.value,
808
852
  () => {
809
853
  if (
810
854
  state.value === ReorderableListState.DRAGGED ||
@@ -813,11 +857,12 @@ const ReorderableListCore = <T,>(
813
857
  setCurrentIndex();
814
858
 
815
859
  // Trigger autoscroll when:
816
- // 1. Within the threshold area (top or bottom of list)
860
+ // 1. Within the threshold area (start or end of list)
817
861
  // 2. Have dragged in the same direction as the scroll
818
862
  // 3. Not already in autoscroll mode
819
863
  if (dragDirection.value === scrollDirection()) {
820
- // When the first two conditions are met and it's already in autoscroll mode, we let it continue (no-op)
864
+ // When the first two conditions are met and it's already in autoscroll mode,
865
+ // we let it continue (no-op).
821
866
  if (state.value !== ReorderableListState.AUTOSCROLL) {
822
867
  state.value = ReorderableListState.AUTOSCROLL;
823
868
  lastAutoscrollTrigger.value = autoscrollTrigger.value;
@@ -843,7 +888,7 @@ const ReorderableListCore = <T,>(
843
888
  autoscrollSpeedScale;
844
889
 
845
890
  if (autoscrollIncrement !== 0) {
846
- let scrollOffset = flatListScrollOffsetY.value;
891
+ let scrollOffset = flatListScrollOffsetXY.value;
847
892
  let listRef =
848
893
  flatListRef as unknown as AnimatedRef<Animated.ScrollView>;
849
894
 
@@ -851,15 +896,21 @@ const ReorderableListCore = <T,>(
851
896
  // this allows to smoothly pass the scroll from the container to the nested list
852
897
  // without any gesture input.
853
898
  if (
854
- scrollViewScrollOffsetY &&
855
- shouldScrollContainer(getRelativeContainerY())
899
+ scrollViewScrollOffsetXY &&
900
+ shouldScrollContainer(getRelativeContainerXY())
856
901
  ) {
857
- scrollOffset = scrollViewScrollOffsetY.value;
902
+ scrollOffset = scrollViewScrollOffsetXY.value;
858
903
  listRef =
859
904
  scrollViewContainerRef as unknown as AnimatedRef<Animated.ScrollView>;
860
905
  }
906
+ const scrollToValue = scrollOffset + autoscrollIncrement;
861
907
 
862
- scrollTo(listRef, 0, scrollOffset + autoscrollIncrement, true);
908
+ scrollTo(
909
+ listRef,
910
+ horizontalProp.value ? scrollToValue : 0,
911
+ horizontalProp.value ? 0 : scrollToValue,
912
+ true,
913
+ );
863
914
  }
864
915
 
865
916
  // when autoscrolling user may not be moving his finger so we need
@@ -871,21 +922,23 @@ const ReorderableListCore = <T,>(
871
922
 
872
923
  // flatlist scroll handler
873
924
  const handleScroll = useAnimatedScrollHandler(e => {
874
- flatListScrollOffsetY.value = e.contentOffset.y;
925
+ flatListScrollOffsetXY.value = horizontalProp.value
926
+ ? e.contentOffset.x
927
+ : e.contentOffset.y;
875
928
 
876
929
  // Checking if the list is not scrollable instead of the scrolling state.
877
930
  // Fixes a bug on iOS where the item is shifted after autoscrolling and then
878
931
  // moving away from the area.
879
932
  if (!currentScrollEnabled.value) {
880
- dragScrollTranslationY.value =
881
- flatListScrollOffsetY.value - dragInitialScrollOffsetY.value;
933
+ dragScrollTranslationXY.value =
934
+ flatListScrollOffsetXY.value - dragInitialScrollOffsetXY.value;
882
935
  }
883
936
 
884
937
  if (state.value === ReorderableListState.AUTOSCROLL) {
885
- dragY.value =
886
- currentTranslationY.value +
887
- dragScrollTranslationY.value +
888
- scrollViewDragScrollTranslationY.value;
938
+ dragXY.value =
939
+ currentTranslationXY.value +
940
+ dragScrollTranslationXY.value +
941
+ scrollViewDragScrollTranslationXY.value;
889
942
 
890
943
  lastAutoscrollTrigger.value = autoscrollTrigger.value;
891
944
  autoscrollTrigger.value = withDelay(
@@ -897,20 +950,21 @@ const ReorderableListCore = <T,>(
897
950
 
898
951
  // container scroll handler
899
952
  useAnimatedReaction(
900
- () => scrollViewScrollOffsetY?.value,
953
+ () => scrollViewScrollOffsetXY?.value,
901
954
  value => {
902
955
  if (value) {
903
956
  // Checking if the list is not scrollable instead of the scrolling state.
904
- // Fixes a bug on iOS where the item is shifted after autoscrolling and then
957
+ // Fixes a bug on iOS where the item is shifted, after autoscrolling and then
905
958
  // moving away from the area.
906
959
  if (!currentScrollEnabled.value) {
907
- scrollViewDragScrollTranslationY.value =
908
- value - scrollViewDragInitialScrollOffsetY.value;
960
+ scrollViewDragScrollTranslationXY.value =
961
+ value - scrollViewDragInitialScrollOffsetXY.value;
909
962
  }
910
963
 
911
964
  if (state.value === ReorderableListState.AUTOSCROLL) {
912
- dragY.value =
913
- currentTranslationY.value + scrollViewDragScrollTranslationY.value;
965
+ dragXY.value =
966
+ currentTranslationXY.value +
967
+ scrollViewDragScrollTranslationXY.value;
914
968
 
915
969
  lastAutoscrollTrigger.value = autoscrollTrigger.value;
916
970
  autoscrollTrigger.value = withDelay(
@@ -930,21 +984,21 @@ const ReorderableListCore = <T,>(
930
984
  return;
931
985
  }
932
986
 
933
- // allow new drag when item is completely released
987
+ // Allow new drag when item is completely released.
934
988
  if (state.value === ReorderableListState.IDLE) {
935
- // resetting shared values again fixes a flickeing bug in nested lists where
936
- // after scrolling the parent list it would offset the new dragged item in another nested list
989
+ // Resetting shared values again fixes a flickeing bug in nested lists where
990
+ // after scrolling the parent list it would offset the new dragged item in another nested list.
937
991
  resetSharedValues();
938
992
 
939
993
  if (shouldUpdateActiveItem) {
940
994
  runOnJS(setActiveIndex)(index);
941
995
  }
942
996
 
943
- dragInitialScrollOffsetY.value = flatListScrollOffsetY.value;
944
- scrollViewDragInitialScrollOffsetY.value =
945
- scrollViewScrollOffsetY?.value || 0;
997
+ dragInitialScrollOffsetXY.value = flatListScrollOffsetXY.value;
998
+ scrollViewDragInitialScrollOffsetXY.value =
999
+ scrollViewScrollOffsetXY?.value || 0;
946
1000
 
947
- draggedHeight.value = itemHeight.value[index];
1001
+ draggedSize.value = itemSize.value[index];
948
1002
  draggedIndex.value = index;
949
1003
  currentIndex.value = index;
950
1004
  state.value = ReorderableListState.DRAGGED;
@@ -960,16 +1014,16 @@ const ReorderableListCore = <T,>(
960
1014
  dragEnabledProp,
961
1015
  resetSharedValues,
962
1016
  shouldUpdateActiveItem,
963
- dragInitialScrollOffsetY,
964
- scrollViewScrollOffsetY,
965
- scrollViewDragInitialScrollOffsetY,
1017
+ dragInitialScrollOffsetXY,
1018
+ scrollViewScrollOffsetXY,
1019
+ scrollViewDragInitialScrollOffsetXY,
966
1020
  setScrollEnabled,
967
1021
  currentIndex,
968
- draggedHeight,
1022
+ draggedSize,
969
1023
  draggedIndex,
970
1024
  state,
971
- flatListScrollOffsetY,
972
- itemHeight,
1025
+ flatListScrollOffsetXY,
1026
+ itemSize,
973
1027
  onDragStart,
974
1028
  runDefaultDragAnimations,
975
1029
  ],
@@ -977,11 +1031,13 @@ const ReorderableListCore = <T,>(
977
1031
 
978
1032
  const handleFlatListLayout = useCallback(
979
1033
  (e: LayoutChangeEvent) => {
980
- flatListHeightY.value = e.nativeEvent.layout.height;
1034
+ flatListSize.value = horizontalProp.value
1035
+ ? e.nativeEvent.layout.width
1036
+ : e.nativeEvent.layout.height;
981
1037
 
982
1038
  // If nested in a scroll container.
983
- if (scrollViewScrollOffsetY) {
984
- // Timeout fixes a bug where measure returns height 0.
1039
+ if (scrollViewScrollOffsetXY) {
1040
+ // Timeout fixes a bug where measure returns width or height 0.
985
1041
  setTimeout(() => {
986
1042
  runOnUI(() => {
987
1043
  const measurement = measure(flatListRef);
@@ -989,11 +1045,15 @@ const ReorderableListCore = <T,>(
989
1045
  return;
990
1046
  }
991
1047
 
1048
+ const pageXY = horizontalProp.value
1049
+ ? measurement.pageX
1050
+ : measurement.pageY;
1051
+
992
1052
  // We need to use pageY because the list might be nested into other views,
993
1053
  // It's important that we take the measurement of the list without any scroll offset
994
1054
  // from the scroll container.
995
- flatListPageY.value =
996
- measurement.pageY + (scrollViewScrollOffsetY?.value || 0);
1055
+ flatListPageXY.value =
1056
+ pageXY + (scrollViewScrollOffsetXY?.value || 0);
997
1057
  })();
998
1058
  }, 100);
999
1059
  }
@@ -1002,9 +1062,10 @@ const ReorderableListCore = <T,>(
1002
1062
  },
1003
1063
  [
1004
1064
  flatListRef,
1005
- flatListPageY,
1006
- flatListHeightY,
1007
- scrollViewScrollOffsetY,
1065
+ flatListPageXY,
1066
+ flatListSize,
1067
+ horizontalProp,
1068
+ scrollViewScrollOffsetXY,
1008
1069
  onLayout,
1009
1070
  ],
1010
1071
  );
@@ -1023,7 +1084,7 @@ const ReorderableListCore = <T,>(
1023
1084
  );
1024
1085
 
1025
1086
  const combinedGesture = useMemo(() => {
1026
- // android is able to handle nested scroll view, but not the full height ones like iOS
1087
+ // Android is able to handle nested scroll view, but not the full size ones like iOS.
1027
1088
  if (outerScrollGesture && !(Platform.OS === 'android' && scrollable)) {
1028
1089
  return Gesture.Simultaneous(outerScrollGesture, gestureHandler);
1029
1090
  }
@@ -1043,8 +1104,8 @@ const ReorderableListCore = <T,>(
1043
1104
  // forces remount with key change on reorder
1044
1105
  key={createCellKey(cellKey)}
1045
1106
  itemOffset={itemOffset}
1046
- itemHeight={itemHeight}
1047
- dragY={dragY}
1107
+ itemSize={itemSize}
1108
+ dragXY={dragXY}
1048
1109
  draggedIndex={draggedIndex}
1049
1110
  animationDuration={animationDurationProp}
1050
1111
  startDrag={startDrag}
@@ -1064,7 +1125,6 @@ const ReorderableListCore = <T,>(
1064
1125
  onLayout={handleFlatListLayout}
1065
1126
  onScroll={composedScrollHandler}
1066
1127
  scrollEventThrottle={1}
1067
- horizontal={false}
1068
1128
  removeClippedSubviews={false}
1069
1129
  numColumns={1}
1070
1130
  // We force disable scroll or let the component prop control it.