react-native-reorderable-list 0.16.1 → 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 +169 -159
  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 +169 -159
  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 +278 -219
  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(() => {
@@ -481,9 +507,8 @@ const ReorderableListCore = <T,>(
481
507
  const reorder = (fromIndex: number, toIndex: number) => {
482
508
  runOnUI(resetSharedValues)();
483
509
 
484
- markCells(fromIndex, toIndex);
485
-
486
510
  if (fromIndex !== toIndex) {
511
+ markCells(fromIndex, toIndex);
487
512
  onReorder({from: fromIndex, to: toIndex});
488
513
  }
489
514
  };
@@ -497,19 +522,19 @@ const ReorderableListCore = <T,>(
497
522
  const index2 = itemDirection ? to : from;
498
523
 
499
524
  const newOffset1 = itemOffset.value[index1];
500
- const newHeight1 = itemHeight.value[index2];
525
+ const newSize1 = itemSize.value[index2];
501
526
  const newOffset2 =
502
527
  itemOffset.value[index2] +
503
- itemHeight.value[index2] -
504
- itemHeight.value[index1];
505
- const newHeight2 = itemHeight.value[index1];
528
+ itemSize.value[index2] -
529
+ itemSize.value[index1];
530
+ const newSize2 = itemSize.value[index1];
506
531
 
507
532
  itemOffset.value[index1] = newOffset1;
508
- itemHeight.value[index1] = newHeight1;
533
+ itemSize.value[index1] = newSize1;
509
534
  itemOffset.value[index2] = newOffset2;
510
- itemHeight.value[index2] = newHeight2;
535
+ itemSize.value[index2] = newSize2;
511
536
  },
512
- [itemOffset, itemHeight],
537
+ [itemOffset, itemSize],
513
538
  );
514
539
 
515
540
  /**
@@ -522,36 +547,38 @@ const ReorderableListCore = <T,>(
522
547
  const computeCurrentIndex = useCallback(() => {
523
548
  'worklet';
524
549
 
525
- if (currentItemDragCenterY.value === null) {
550
+ if (currentItemDragCenterXY.value === null) {
526
551
  return currentIndex.value;
527
552
  }
528
553
 
529
- // apply scroll offset and scroll container translation
530
- const relativeDragCenterY =
531
- flatListScrollOffsetY.value +
532
- scrollViewDragScrollTranslationY.value +
533
- currentItemDragCenterY.value;
554
+ // Apply scroll offset and scroll container translation.
555
+ const relativeDragCenterXY =
556
+ flatListScrollOffsetXY.value +
557
+ scrollViewDragScrollTranslationXY.value +
558
+ currentItemDragCenterXY.value;
534
559
 
535
560
  const currentOffset = itemOffset.value[currentIndex.value];
536
- const currentHeight = itemHeight.value[currentIndex.value];
537
- const currentCenter = currentOffset + currentHeight * 0.5;
561
+ const currentSize = itemSize.value[currentIndex.value];
562
+ const currentCenter = currentOffset + currentSize * 0.5;
538
563
 
539
564
  const max = itemCount.value;
540
565
  const possibleIndex =
541
- relativeDragCenterY < currentCenter
566
+ relativeDragCenterXY < currentCenter
542
567
  ? Math.max(0, currentIndex.value - 1)
543
568
  : Math.min(max - 1, currentIndex.value + 1);
544
569
 
545
570
  if (currentIndex.value !== possibleIndex) {
546
571
  let possibleOffset = itemOffset.value[possibleIndex];
547
572
  if (possibleIndex > currentIndex.value) {
548
- possibleOffset += itemHeight.value[possibleIndex] - currentHeight;
573
+ possibleOffset += itemSize.value[possibleIndex] - currentSize;
549
574
  }
550
575
 
551
- const possibleCenter = possibleOffset + currentHeight * 0.5;
552
- const distanceFromCurrent = Math.abs(relativeDragCenterY - currentCenter);
576
+ const possibleCenter = possibleOffset + currentSize * 0.5;
577
+ const distanceFromCurrent = Math.abs(
578
+ relativeDragCenterXY - currentCenter,
579
+ );
553
580
  const distanceFromPossible = Math.abs(
554
- relativeDragCenterY - possibleCenter,
581
+ relativeDragCenterXY - possibleCenter,
555
582
  );
556
583
 
557
584
  return distanceFromCurrent <= distanceFromPossible
@@ -562,12 +589,12 @@ const ReorderableListCore = <T,>(
562
589
  return currentIndex.value;
563
590
  }, [
564
591
  currentIndex,
565
- currentItemDragCenterY,
592
+ currentItemDragCenterXY,
566
593
  itemCount,
567
594
  itemOffset,
568
- itemHeight,
569
- flatListScrollOffsetY,
570
- scrollViewDragScrollTranslationY,
595
+ itemSize,
596
+ flatListScrollOffsetXY,
597
+ scrollViewDragScrollTranslationXY,
571
598
  ]);
572
599
 
573
600
  const setCurrentIndex = useCallback(() => {
@@ -593,7 +620,7 @@ const ReorderableListCore = <T,>(
593
620
  scaleDefault.value = withTiming(scaleConfig.toValue, scaleConfig);
594
621
  }
595
622
 
596
- // if no custom opacity run the default
623
+ // If no custom opacity run the default.
597
624
  if (!(cellAnimations && 'opacity' in cellAnimations)) {
598
625
  const opacityConfig = OPACITY_ANIMATION_CONFIG_DEFAULT[type];
599
626
  opacityDefault.value = withTiming(opacityConfig.toValue, opacityConfig);
@@ -620,7 +647,7 @@ const ReorderableListCore = <T,>(
620
647
  runOnJS(setActiveIndex)(-1);
621
648
  }
622
649
 
623
- // trigger onDragEnd event
650
+ // Trigger onDragEnd event.
624
651
  let e = {from: draggedIndex.value, to: currentIndex.value};
625
652
  onDragEnd?.(e);
626
653
 
@@ -631,23 +658,23 @@ const ReorderableListCore = <T,>(
631
658
 
632
659
  // they are actually swapped on drag translation
633
660
  const currentItemOffset = itemOffset.value[draggedIndex.value];
634
- const currentItemHeight = itemHeight.value[draggedIndex.value];
661
+ const currentItemSize = itemSize.value[draggedIndex.value];
635
662
  const draggedItemOffset = itemOffset.value[currentIndex.value];
636
- const draggedItemHeight = itemHeight.value[currentIndex.value];
663
+ const draggedItemSize = itemSize.value[currentIndex.value];
637
664
 
638
- const newTopPosition =
665
+ const newPositionXY =
639
666
  currentIndex.value > draggedIndex.value
640
667
  ? draggedItemOffset - currentItemOffset
641
668
  : draggedItemOffset -
642
669
  currentItemOffset +
643
- (draggedItemHeight - currentItemHeight);
670
+ (draggedItemSize - currentItemSize);
644
671
 
645
672
  runDefaultDragAnimations('end');
646
673
 
647
- if (dragY.value !== newTopPosition) {
648
- // animate dragged item to its new position on release
649
- dragY.value = withTiming(
650
- newTopPosition,
674
+ if (dragXY.value !== newPositionXY) {
675
+ // Animate dragged item to its new position on release.
676
+ dragXY.value = withTiming(
677
+ newPositionXY,
651
678
  {
652
679
  duration: animationDurationProp.value,
653
680
  easing: Easing.out(Easing.ease),
@@ -657,9 +684,9 @@ const ReorderableListCore = <T,>(
657
684
  },
658
685
  );
659
686
  } else {
660
- // user might drag and release the item without moving it so,
687
+ // User might drag and release the item without moving it so,
661
688
  // since the animation end callback is not executed in that case
662
- // we need to reset values as the reorder function would do
689
+ // we need to reset values as the reorder function would do.
663
690
  runOnJS(resetSharedValuesAfterAnimations)();
664
691
  }
665
692
  }
@@ -668,28 +695,28 @@ const ReorderableListCore = <T,>(
668
695
 
669
696
  const computeHiddenArea = useCallback(() => {
670
697
  'worklet';
671
- if (!scrollViewScrollOffsetY || !scrollViewHeightY) {
672
- return {top: 0, bottom: 0};
698
+ if (!scrollViewScrollOffsetXY || !scrollViewSize) {
699
+ return {start: 0, end: 0};
673
700
  }
674
701
 
675
702
  // hidden area cannot be negative
676
- const top = Math.max(
703
+ const start = Math.max(
677
704
  0,
678
- scrollViewScrollOffsetY.value - nestedFlatListPositionY.value,
705
+ scrollViewScrollOffsetXY.value - nestedFlatListPositionXY.value,
679
706
  );
680
- const bottom = Math.max(
707
+ const end = Math.max(
681
708
  0,
682
- nestedFlatListPositionY.value +
683
- flatListHeightY.value -
684
- (scrollViewScrollOffsetY.value + scrollViewHeightY.value),
709
+ nestedFlatListPositionXY.value +
710
+ flatListSize.value -
711
+ (scrollViewScrollOffsetXY.value + scrollViewSize.value),
685
712
  );
686
713
 
687
- return {top, bottom};
714
+ return {start, end};
688
715
  }, [
689
- scrollViewScrollOffsetY,
690
- scrollViewHeightY,
691
- nestedFlatListPositionY,
692
- flatListHeightY,
716
+ scrollViewScrollOffsetXY,
717
+ scrollViewSize,
718
+ nestedFlatListPositionXY,
719
+ flatListSize,
693
720
  ]);
694
721
 
695
722
  const computeThresholdArea = useCallback(() => {
@@ -697,43 +724,55 @@ const ReorderableListCore = <T,>(
697
724
 
698
725
  const hiddenArea = computeHiddenArea();
699
726
 
700
- const offsetTop = Math.max(0, autoscrollThresholdOffset?.top || 0);
701
- 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
+ );
702
735
  const threshold = Math.max(0, Math.min(autoscrollThreshold, 0.4));
703
- const visibleHeight =
704
- flatListHeightY.value -
705
- (hiddenArea.top + hiddenArea.bottom) -
706
- (offsetTop + offsetBottom);
736
+ const visibleSize =
737
+ flatListSize.value -
738
+ (hiddenArea.start + hiddenArea.end) -
739
+ (offsetStart + offsetEnd);
707
740
 
708
- const area = visibleHeight * threshold;
709
- const top = area + offsetTop;
710
- const bottom = flatListHeightY.value - area - offsetBottom;
741
+ const area = visibleSize * threshold;
742
+ const start = area + offsetStart;
743
+ const end = flatListSize.value - area - offsetEnd;
711
744
 
712
- return {top, bottom};
745
+ return {start, end};
713
746
  }, [
714
747
  computeHiddenArea,
715
748
  autoscrollThreshold,
716
749
  autoscrollThresholdOffset,
717
- flatListHeightY,
750
+ flatListSize,
718
751
  ]);
719
752
 
720
753
  const computeContainerThresholdArea = useCallback(() => {
721
754
  'worklet';
722
- if (!scrollViewHeightY) {
723
- return {top: -Infinity, bottom: Infinity};
755
+ if (!scrollViewSize) {
756
+ return {start: -Infinity, end: Infinity};
724
757
  }
725
758
 
726
- const offsetTop = Math.max(0, autoscrollThresholdOffset?.top || 0);
727
- 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
+ );
728
767
  const threshold = Math.max(0, Math.min(autoscrollThreshold, 0.4));
729
- const visibleHeight = scrollViewHeightY.value - (offsetTop + offsetBottom);
768
+ const visibleSize = scrollViewSize.value - (offsetStart + offsetEnd);
730
769
 
731
- const area = visibleHeight * threshold;
732
- const top = area + offsetTop;
733
- const bottom = visibleHeight - area - offsetBottom;
770
+ const area = visibleSize * threshold;
771
+ const start = area + offsetStart;
772
+ const end = visibleSize - area - offsetEnd;
734
773
 
735
- return {top, bottom};
736
- }, [autoscrollThreshold, autoscrollThresholdOffset, scrollViewHeightY]);
774
+ return {start, end};
775
+ }, [autoscrollThreshold, autoscrollThresholdOffset, scrollViewSize]);
737
776
 
738
777
  const shouldScrollContainer = useCallback(
739
778
  (y: number) => {
@@ -744,52 +783,56 @@ const ReorderableListCore = <T,>(
744
783
  // We should scroll the container if there's a hidden part of the nested list.
745
784
  // We might have floating errors like 0.0001 which we should ignore.
746
785
  return (
747
- (nestedListHiddenArea.top > 0.01 && y <= containerThresholdArea.top) ||
748
- (nestedListHiddenArea.bottom > 0.01 &&
749
- y >= containerThresholdArea.bottom)
786
+ (nestedListHiddenArea.start > 0.01 &&
787
+ y <= containerThresholdArea.start) ||
788
+ (nestedListHiddenArea.end > 0.01 && y >= containerThresholdArea.end)
750
789
  );
751
790
  },
752
791
  [computeHiddenArea, computeContainerThresholdArea],
753
792
  );
754
793
 
755
- const getRelativeContainerY = useCallback(() => {
794
+ const getRelativeContainerXY = useCallback(() => {
756
795
  'worklet';
757
796
 
758
797
  return (
759
- currentY.value +
760
- nestedFlatListPositionY.value -
761
- scrollViewDragInitialScrollOffsetY.value
798
+ currentXY.value +
799
+ nestedFlatListPositionXY.value -
800
+ scrollViewDragInitialScrollOffsetXY.value
762
801
  );
763
- }, [currentY, nestedFlatListPositionY, scrollViewDragInitialScrollOffsetY]);
802
+ }, [
803
+ currentXY,
804
+ nestedFlatListPositionXY,
805
+ scrollViewDragInitialScrollOffsetXY,
806
+ ]);
764
807
 
765
- const getRelativeListY = useCallback(() => {
808
+ const getRelativeListXY = useCallback(() => {
766
809
  'worklet';
767
810
 
768
- return currentY.value + scrollViewDragScrollTranslationY.value;
769
- }, [currentY, scrollViewDragScrollTranslationY]);
811
+ return currentXY.value + scrollViewDragScrollTranslationXY.value;
812
+ }, [currentXY, scrollViewDragScrollTranslationXY]);
770
813
 
771
814
  const scrollDirection = useCallback(() => {
772
815
  'worklet';
773
816
 
774
- const relativeContainerY = getRelativeContainerY();
775
- if (shouldScrollContainer(relativeContainerY)) {
817
+ const relativeContainerXY = getRelativeContainerXY();
818
+ if (shouldScrollContainer(relativeContainerXY)) {
776
819
  const containerThresholdArea = computeContainerThresholdArea();
777
- if (relativeContainerY <= containerThresholdArea.top) {
820
+ if (relativeContainerXY <= containerThresholdArea.start) {
778
821
  return -1;
779
822
  }
780
823
 
781
- if (relativeContainerY >= containerThresholdArea.bottom) {
824
+ if (relativeContainerXY >= containerThresholdArea.end) {
782
825
  return 1;
783
826
  }
784
827
  } else if (scrollable) {
785
- const relativeListY = getRelativeListY();
828
+ const relativeListXY = getRelativeListXY();
786
829
  const thresholdArea = computeThresholdArea();
787
830
 
788
- if (relativeListY <= thresholdArea.top) {
831
+ if (relativeListXY <= thresholdArea.start) {
789
832
  return -1;
790
833
  }
791
834
 
792
- if (relativeListY >= thresholdArea.bottom) {
835
+ if (relativeListXY >= thresholdArea.end) {
793
836
  return 1;
794
837
  }
795
838
  }
@@ -799,13 +842,13 @@ const ReorderableListCore = <T,>(
799
842
  shouldScrollContainer,
800
843
  computeThresholdArea,
801
844
  computeContainerThresholdArea,
802
- getRelativeContainerY,
803
- getRelativeListY,
845
+ getRelativeContainerXY,
846
+ getRelativeListXY,
804
847
  scrollable,
805
848
  ]);
806
849
 
807
850
  useAnimatedReaction(
808
- () => currentY.value,
851
+ () => currentXY.value,
809
852
  () => {
810
853
  if (
811
854
  state.value === ReorderableListState.DRAGGED ||
@@ -814,11 +857,12 @@ const ReorderableListCore = <T,>(
814
857
  setCurrentIndex();
815
858
 
816
859
  // Trigger autoscroll when:
817
- // 1. Within the threshold area (top or bottom of list)
860
+ // 1. Within the threshold area (start or end of list)
818
861
  // 2. Have dragged in the same direction as the scroll
819
862
  // 3. Not already in autoscroll mode
820
863
  if (dragDirection.value === scrollDirection()) {
821
- // 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).
822
866
  if (state.value !== ReorderableListState.AUTOSCROLL) {
823
867
  state.value = ReorderableListState.AUTOSCROLL;
824
868
  lastAutoscrollTrigger.value = autoscrollTrigger.value;
@@ -844,7 +888,7 @@ const ReorderableListCore = <T,>(
844
888
  autoscrollSpeedScale;
845
889
 
846
890
  if (autoscrollIncrement !== 0) {
847
- let scrollOffset = flatListScrollOffsetY.value;
891
+ let scrollOffset = flatListScrollOffsetXY.value;
848
892
  let listRef =
849
893
  flatListRef as unknown as AnimatedRef<Animated.ScrollView>;
850
894
 
@@ -852,15 +896,21 @@ const ReorderableListCore = <T,>(
852
896
  // this allows to smoothly pass the scroll from the container to the nested list
853
897
  // without any gesture input.
854
898
  if (
855
- scrollViewScrollOffsetY &&
856
- shouldScrollContainer(getRelativeContainerY())
899
+ scrollViewScrollOffsetXY &&
900
+ shouldScrollContainer(getRelativeContainerXY())
857
901
  ) {
858
- scrollOffset = scrollViewScrollOffsetY.value;
902
+ scrollOffset = scrollViewScrollOffsetXY.value;
859
903
  listRef =
860
904
  scrollViewContainerRef as unknown as AnimatedRef<Animated.ScrollView>;
861
905
  }
906
+ const scrollToValue = scrollOffset + autoscrollIncrement;
862
907
 
863
- scrollTo(listRef, 0, scrollOffset + autoscrollIncrement, true);
908
+ scrollTo(
909
+ listRef,
910
+ horizontalProp.value ? scrollToValue : 0,
911
+ horizontalProp.value ? 0 : scrollToValue,
912
+ true,
913
+ );
864
914
  }
865
915
 
866
916
  // when autoscrolling user may not be moving his finger so we need
@@ -872,21 +922,23 @@ const ReorderableListCore = <T,>(
872
922
 
873
923
  // flatlist scroll handler
874
924
  const handleScroll = useAnimatedScrollHandler(e => {
875
- flatListScrollOffsetY.value = e.contentOffset.y;
925
+ flatListScrollOffsetXY.value = horizontalProp.value
926
+ ? e.contentOffset.x
927
+ : e.contentOffset.y;
876
928
 
877
929
  // Checking if the list is not scrollable instead of the scrolling state.
878
930
  // Fixes a bug on iOS where the item is shifted after autoscrolling and then
879
931
  // moving away from the area.
880
932
  if (!currentScrollEnabled.value) {
881
- dragScrollTranslationY.value =
882
- flatListScrollOffsetY.value - dragInitialScrollOffsetY.value;
933
+ dragScrollTranslationXY.value =
934
+ flatListScrollOffsetXY.value - dragInitialScrollOffsetXY.value;
883
935
  }
884
936
 
885
937
  if (state.value === ReorderableListState.AUTOSCROLL) {
886
- dragY.value =
887
- currentTranslationY.value +
888
- dragScrollTranslationY.value +
889
- scrollViewDragScrollTranslationY.value;
938
+ dragXY.value =
939
+ currentTranslationXY.value +
940
+ dragScrollTranslationXY.value +
941
+ scrollViewDragScrollTranslationXY.value;
890
942
 
891
943
  lastAutoscrollTrigger.value = autoscrollTrigger.value;
892
944
  autoscrollTrigger.value = withDelay(
@@ -898,20 +950,21 @@ const ReorderableListCore = <T,>(
898
950
 
899
951
  // container scroll handler
900
952
  useAnimatedReaction(
901
- () => scrollViewScrollOffsetY?.value,
953
+ () => scrollViewScrollOffsetXY?.value,
902
954
  value => {
903
955
  if (value) {
904
956
  // Checking if the list is not scrollable instead of the scrolling state.
905
- // 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
906
958
  // moving away from the area.
907
959
  if (!currentScrollEnabled.value) {
908
- scrollViewDragScrollTranslationY.value =
909
- value - scrollViewDragInitialScrollOffsetY.value;
960
+ scrollViewDragScrollTranslationXY.value =
961
+ value - scrollViewDragInitialScrollOffsetXY.value;
910
962
  }
911
963
 
912
964
  if (state.value === ReorderableListState.AUTOSCROLL) {
913
- dragY.value =
914
- currentTranslationY.value + scrollViewDragScrollTranslationY.value;
965
+ dragXY.value =
966
+ currentTranslationXY.value +
967
+ scrollViewDragScrollTranslationXY.value;
915
968
 
916
969
  lastAutoscrollTrigger.value = autoscrollTrigger.value;
917
970
  autoscrollTrigger.value = withDelay(
@@ -931,21 +984,21 @@ const ReorderableListCore = <T,>(
931
984
  return;
932
985
  }
933
986
 
934
- // allow new drag when item is completely released
987
+ // Allow new drag when item is completely released.
935
988
  if (state.value === ReorderableListState.IDLE) {
936
- // resetting shared values again fixes a flickeing bug in nested lists where
937
- // 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.
938
991
  resetSharedValues();
939
992
 
940
993
  if (shouldUpdateActiveItem) {
941
994
  runOnJS(setActiveIndex)(index);
942
995
  }
943
996
 
944
- dragInitialScrollOffsetY.value = flatListScrollOffsetY.value;
945
- scrollViewDragInitialScrollOffsetY.value =
946
- scrollViewScrollOffsetY?.value || 0;
997
+ dragInitialScrollOffsetXY.value = flatListScrollOffsetXY.value;
998
+ scrollViewDragInitialScrollOffsetXY.value =
999
+ scrollViewScrollOffsetXY?.value || 0;
947
1000
 
948
- draggedHeight.value = itemHeight.value[index];
1001
+ draggedSize.value = itemSize.value[index];
949
1002
  draggedIndex.value = index;
950
1003
  currentIndex.value = index;
951
1004
  state.value = ReorderableListState.DRAGGED;
@@ -961,16 +1014,16 @@ const ReorderableListCore = <T,>(
961
1014
  dragEnabledProp,
962
1015
  resetSharedValues,
963
1016
  shouldUpdateActiveItem,
964
- dragInitialScrollOffsetY,
965
- scrollViewScrollOffsetY,
966
- scrollViewDragInitialScrollOffsetY,
1017
+ dragInitialScrollOffsetXY,
1018
+ scrollViewScrollOffsetXY,
1019
+ scrollViewDragInitialScrollOffsetXY,
967
1020
  setScrollEnabled,
968
1021
  currentIndex,
969
- draggedHeight,
1022
+ draggedSize,
970
1023
  draggedIndex,
971
1024
  state,
972
- flatListScrollOffsetY,
973
- itemHeight,
1025
+ flatListScrollOffsetXY,
1026
+ itemSize,
974
1027
  onDragStart,
975
1028
  runDefaultDragAnimations,
976
1029
  ],
@@ -978,11 +1031,13 @@ const ReorderableListCore = <T,>(
978
1031
 
979
1032
  const handleFlatListLayout = useCallback(
980
1033
  (e: LayoutChangeEvent) => {
981
- flatListHeightY.value = e.nativeEvent.layout.height;
1034
+ flatListSize.value = horizontalProp.value
1035
+ ? e.nativeEvent.layout.width
1036
+ : e.nativeEvent.layout.height;
982
1037
 
983
1038
  // If nested in a scroll container.
984
- if (scrollViewScrollOffsetY) {
985
- // Timeout fixes a bug where measure returns height 0.
1039
+ if (scrollViewScrollOffsetXY) {
1040
+ // Timeout fixes a bug where measure returns width or height 0.
986
1041
  setTimeout(() => {
987
1042
  runOnUI(() => {
988
1043
  const measurement = measure(flatListRef);
@@ -990,11 +1045,15 @@ const ReorderableListCore = <T,>(
990
1045
  return;
991
1046
  }
992
1047
 
1048
+ const pageXY = horizontalProp.value
1049
+ ? measurement.pageX
1050
+ : measurement.pageY;
1051
+
993
1052
  // We need to use pageY because the list might be nested into other views,
994
1053
  // It's important that we take the measurement of the list without any scroll offset
995
1054
  // from the scroll container.
996
- flatListPageY.value =
997
- measurement.pageY + (scrollViewScrollOffsetY?.value || 0);
1055
+ flatListPageXY.value =
1056
+ pageXY + (scrollViewScrollOffsetXY?.value || 0);
998
1057
  })();
999
1058
  }, 100);
1000
1059
  }
@@ -1003,9 +1062,10 @@ const ReorderableListCore = <T,>(
1003
1062
  },
1004
1063
  [
1005
1064
  flatListRef,
1006
- flatListPageY,
1007
- flatListHeightY,
1008
- scrollViewScrollOffsetY,
1065
+ flatListPageXY,
1066
+ flatListSize,
1067
+ horizontalProp,
1068
+ scrollViewScrollOffsetXY,
1009
1069
  onLayout,
1010
1070
  ],
1011
1071
  );
@@ -1024,7 +1084,7 @@ const ReorderableListCore = <T,>(
1024
1084
  );
1025
1085
 
1026
1086
  const combinedGesture = useMemo(() => {
1027
- // 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.
1028
1088
  if (outerScrollGesture && !(Platform.OS === 'android' && scrollable)) {
1029
1089
  return Gesture.Simultaneous(outerScrollGesture, gestureHandler);
1030
1090
  }
@@ -1044,8 +1104,8 @@ const ReorderableListCore = <T,>(
1044
1104
  // forces remount with key change on reorder
1045
1105
  key={createCellKey(cellKey)}
1046
1106
  itemOffset={itemOffset}
1047
- itemHeight={itemHeight}
1048
- dragY={dragY}
1107
+ itemSize={itemSize}
1108
+ dragXY={dragXY}
1049
1109
  draggedIndex={draggedIndex}
1050
1110
  animationDuration={animationDurationProp}
1051
1111
  startDrag={startDrag}
@@ -1065,7 +1125,6 @@ const ReorderableListCore = <T,>(
1065
1125
  onLayout={handleFlatListLayout}
1066
1126
  onScroll={composedScrollHandler}
1067
1127
  scrollEventThrottle={1}
1068
- horizontal={false}
1069
1128
  removeClippedSubviews={false}
1070
1129
  numColumns={1}
1071
1130
  // We force disable scroll or let the component prop control it.