react-native-gesture-image-viewer 2.4.0 → 2.5.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 (50) hide show
  1. package/README.md +19 -5
  2. package/lib/module/GestureViewer.js +31 -13
  3. package/lib/module/GestureViewer.js.map +1 -1
  4. package/lib/module/GestureViewerManager.js +43 -14
  5. package/lib/module/GestureViewerManager.js.map +1 -1
  6. package/lib/module/index.js.map +1 -1
  7. package/lib/module/itemDimensions.js +86 -0
  8. package/lib/module/itemDimensions.js.map +1 -0
  9. package/lib/module/useGestureViewer.js +244 -32
  10. package/lib/module/useGestureViewer.js.map +1 -1
  11. package/lib/module/useGestureViewerPaging.js +1 -3
  12. package/lib/module/useGestureViewerPaging.js.map +1 -1
  13. package/lib/module/useGestureViewerPaging.web.js +26 -18
  14. package/lib/module/useGestureViewerPaging.web.js.map +1 -1
  15. package/lib/module/utils/index.js +43 -10
  16. package/lib/module/utils/index.js.map +1 -1
  17. package/lib/module/utils/tapZoom.js +51 -13
  18. package/lib/module/utils/tapZoom.js.map +1 -1
  19. package/lib/typescript/src/GestureViewer.d.ts.map +1 -1
  20. package/lib/typescript/src/GestureViewerManager.d.ts +16 -3
  21. package/lib/typescript/src/GestureViewerManager.d.ts.map +1 -1
  22. package/lib/typescript/src/index.d.ts +1 -1
  23. package/lib/typescript/src/index.d.ts.map +1 -1
  24. package/lib/typescript/src/itemDimensions.d.ts +26 -0
  25. package/lib/typescript/src/itemDimensions.d.ts.map +1 -0
  26. package/lib/typescript/src/types.d.ts +29 -0
  27. package/lib/typescript/src/types.d.ts.map +1 -1
  28. package/lib/typescript/src/useGestureViewer.d.ts +3 -2
  29. package/lib/typescript/src/useGestureViewer.d.ts.map +1 -1
  30. package/lib/typescript/src/useGestureViewerPaging.d.ts.map +1 -1
  31. package/lib/typescript/src/useGestureViewerPaging.types.d.ts +2 -0
  32. package/lib/typescript/src/useGestureViewerPaging.types.d.ts.map +1 -1
  33. package/lib/typescript/src/useGestureViewerPaging.web.d.ts +1 -1
  34. package/lib/typescript/src/useGestureViewerPaging.web.d.ts.map +1 -1
  35. package/lib/typescript/src/utils/index.d.ts +7 -3
  36. package/lib/typescript/src/utils/index.d.ts.map +1 -1
  37. package/lib/typescript/src/utils/tapZoom.d.ts +17 -1
  38. package/lib/typescript/src/utils/tapZoom.d.ts.map +1 -1
  39. package/package.json +1 -1
  40. package/src/GestureViewer.tsx +47 -16
  41. package/src/GestureViewerManager.ts +58 -19
  42. package/src/index.tsx +4 -0
  43. package/src/itemDimensions.ts +162 -0
  44. package/src/types.ts +39 -0
  45. package/src/useGestureViewer.ts +352 -36
  46. package/src/useGestureViewerPaging.ts +1 -3
  47. package/src/useGestureViewerPaging.types.ts +2 -0
  48. package/src/useGestureViewerPaging.web.ts +41 -21
  49. package/src/utils/index.ts +86 -27
  50. package/src/utils/tapZoom.ts +66 -13
@@ -1,4 +1,4 @@
1
- import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
1
+ import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
2
2
  import { Platform, type View, useWindowDimensions } from 'react-native';
3
3
  import { Gesture, type GestureType } from 'react-native-gesture-handler';
4
4
  import {
@@ -14,10 +14,23 @@ import { scheduleOnRN } from 'react-native-worklets';
14
14
 
15
15
  import type GestureViewerManager from './GestureViewerManager';
16
16
  import { registry } from './GestureViewerRegistry';
17
+ import {
18
+ type ItemDimensionsRegistry,
19
+ pruneItemDimensionsRegistry,
20
+ registerItemDimensions,
21
+ resolveItemDimensions,
22
+ } from './itemDimensions';
17
23
  import { scheduleInitialScroll } from './scheduleInitialScroll';
18
- import type { GestureViewerProps, TriggerRect } from './types';
24
+ import type { GestureViewerItemDimensions, GestureViewerProps, TriggerRect } from './types';
19
25
  import { useGestureViewerPaging } from './useGestureViewerPaging';
20
- import { createBoundsConstraint, createScrollAction } from './utils';
26
+ import {
27
+ clampIndex,
28
+ clampTranslationToBounds,
29
+ createScrollAction,
30
+ getLoopAdjustedIndex,
31
+ getLoopPhysicalIndex,
32
+ resolveGeometrySyncTranslationMode,
33
+ } from './utils';
21
34
  import { getDismissDistance, shouldDismissByDirection } from './utils/dismiss';
22
35
  import { applyTapZoomAtPoint } from './utils/tapZoom';
23
36
  import { calculateFocalPointTranslation, shouldAcceptFocalPoint } from './utils/zoom';
@@ -33,6 +46,43 @@ type UseGestureViewerProps<ItemT, LC> = Omit<
33
46
  | 'enableSnapMode'
34
47
  >;
35
48
 
49
+ type ViewerPositionSnapshot = Readonly<{
50
+ dataLength: number;
51
+ initialIndex: number;
52
+ pageStride: number;
53
+ usesLoopSentinels: boolean;
54
+ }>;
55
+
56
+ function getViewerPositionChanges(
57
+ previous: ViewerPositionSnapshot | null,
58
+ current: ViewerPositionSnapshot,
59
+ ) {
60
+ return {
61
+ isInitial: previous === null,
62
+ didDataLengthChange: previous !== null && previous.dataLength !== current.dataLength,
63
+ didInitialIndexChange: previous !== null && previous.initialIndex !== current.initialIndex,
64
+ didLoopLayoutChange:
65
+ previous !== null && previous.usesLoopSentinels !== current.usesLoopSentinels,
66
+ didPageStrideChange: previous !== null && previous.pageStride !== current.pageStride,
67
+ };
68
+ }
69
+
70
+ function fitItemDimensions(
71
+ dimensions: GestureViewerItemDimensions | undefined,
72
+ viewport: GestureViewerItemDimensions,
73
+ ): GestureViewerItemDimensions {
74
+ if (!dimensions) {
75
+ return viewport;
76
+ }
77
+
78
+ const fitScale = Math.min(viewport.width / dimensions.width, viewport.height / dimensions.height);
79
+
80
+ return {
81
+ width: dimensions.width * fitScale,
82
+ height: dimensions.height * fitScale,
83
+ };
84
+ }
85
+
36
86
  export const useGestureViewer = <ItemT, LC>({
37
87
  data,
38
88
  initialIndex = 0,
@@ -53,6 +103,8 @@ export const useGestureViewer = <ItemT, LC>({
53
103
  triggerAnimation,
54
104
  autoPlay = false,
55
105
  autoPlayInterval = 3000,
106
+ getItemDimensions,
107
+ getItemKey,
56
108
  }: UseGestureViewerProps<ItemT, LC>) => {
57
109
  const { width: screenWidth, height: screenHeight } = useWindowDimensions();
58
110
  const width = customWidth || screenWidth;
@@ -74,7 +126,11 @@ export const useGestureViewer = <ItemT, LC>({
74
126
  const onAnimationCompleteRef = useRef(triggerAnimation?.onAnimationComplete);
75
127
  const onSingleTapRef = useRef(onSingleTap);
76
128
  const dataRef = useRef(data);
129
+ const getItemDimensionsRef = useRef(getItemDimensions);
130
+ const getItemKeyRef = useRef(getItemKey);
77
131
  const managerRef = useRef(manager);
132
+ const configuredManagerRef = useRef<GestureViewerManager | null>(null);
133
+ const itemDimensionsRef = useRef<ItemDimensionsRegistry<ItemT>>(new Map());
78
134
 
79
135
  const isValidTriggerRect = useCallback((rect: TriggerRect | null): rect is TriggerRect => {
80
136
  return !!rect && rect.width > 0 && rect.height > 0;
@@ -89,6 +145,8 @@ export const useGestureViewer = <ItemT, LC>({
89
145
  const scale = useSharedValue(1);
90
146
  const backdropOpacity = useSharedValue(1);
91
147
  const rotation = useSharedValue(0);
148
+ const contentWidth = useSharedValue(width);
149
+ const contentHeight = useSharedValue(height);
92
150
 
93
151
  const triggerScale = useSharedValue(1);
94
152
  const triggerTranslateX = useSharedValue(0);
@@ -102,7 +160,122 @@ export const useGestureViewer = <ItemT, LC>({
102
160
  const hasActiveFocal = useSharedValue(false);
103
161
 
104
162
  const dataLength = data?.length || 0;
105
- const previousDataLengthRef = useRef(dataLength);
163
+ const usesLoopSentinels = enableLoop && dataLength > 1;
164
+ const pageStride = width + itemSpacing;
165
+ const adjustedInitialIndex = getLoopPhysicalIndex(initialIndex, dataLength, enableLoop);
166
+ // Manager setup can rerender before a deferred list scroll runs, so each consumer tracks
167
+ // the last committed position inputs independently.
168
+ const managerPositionSnapshotRef = useRef<ViewerPositionSnapshot | null>(null);
169
+ const listPositionSnapshotRef = useRef<ViewerPositionSnapshot | null>(null);
170
+ const viewportRef = useRef({ height, width });
171
+ const loopConfigRef = useRef({ dataLength, enableLoop });
172
+ const activeGeometryRef = useRef<{
173
+ contentHeight: number;
174
+ contentWidth: number;
175
+ height: number;
176
+ width: number;
177
+ } | null>(null);
178
+ const activeGeometryIndexRef = useRef<number | null>(null);
179
+
180
+ const syncActiveContentDimensions = useCallback(
181
+ (logicalIndex = pendingIndexRef.current) => {
182
+ const viewport = viewportRef.current;
183
+ const fitted = fitItemDimensions(
184
+ resolveItemDimensions({
185
+ data: dataRef.current,
186
+ getItemDimensions: getItemDimensionsRef.current,
187
+ getItemKey: getItemKeyRef.current,
188
+ index: logicalIndex,
189
+ registry: itemDimensionsRef.current,
190
+ }),
191
+ viewport,
192
+ );
193
+ const nextGeometry = {
194
+ contentHeight: fitted.height,
195
+ contentWidth: fitted.width,
196
+ height: viewport.height,
197
+ width: viewport.width,
198
+ };
199
+ const previousGeometry = activeGeometryRef.current;
200
+ const previousGeometryIndex = activeGeometryIndexRef.current;
201
+
202
+ activeGeometryIndexRef.current = logicalIndex;
203
+
204
+ const currentScale = scale.get();
205
+ const translationMode = resolveGeometrySyncTranslationMode(
206
+ previousGeometryIndex,
207
+ logicalIndex,
208
+ currentScale,
209
+ );
210
+
211
+ if (translationMode === 'reset') {
212
+ // Complete the page-owned reset before the next item's geometry can reuse the old offset.
213
+ translateX.set(0);
214
+ translateY.set(0);
215
+ }
216
+
217
+ if (
218
+ previousGeometry?.contentHeight === nextGeometry.contentHeight &&
219
+ previousGeometry.contentWidth === nextGeometry.contentWidth &&
220
+ previousGeometry.height === nextGeometry.height &&
221
+ previousGeometry.width === nextGeometry.width
222
+ ) {
223
+ return;
224
+ }
225
+
226
+ activeGeometryRef.current = nextGeometry;
227
+
228
+ if (contentWidth.get() !== fitted.width) {
229
+ contentWidth.set(fitted.width);
230
+ }
231
+ if (contentHeight.get() !== fitted.height) {
232
+ contentHeight.set(fitted.height);
233
+ }
234
+
235
+ if (translationMode !== 'constrain') {
236
+ return;
237
+ }
238
+
239
+ const { translateX: constrainedTranslateX, translateY: constrainedTranslateY } =
240
+ clampTranslationToBounds({
241
+ contentHeight: fitted.height,
242
+ contentWidth: fitted.width,
243
+ height: viewport.height,
244
+ scale: currentScale,
245
+ translateX: translateX.get(),
246
+ translateY: translateY.get(),
247
+ width: viewport.width,
248
+ });
249
+
250
+ translateX.set(withTiming(constrainedTranslateX));
251
+ translateY.set(withTiming(constrainedTranslateY));
252
+ },
253
+ [contentHeight, contentWidth, scale, translateX, translateY],
254
+ );
255
+
256
+ const setItemDimensions = useCallback(
257
+ (listIndex: number, item: ItemT, dimensions: GestureViewerItemDimensions) => {
258
+ const { dataLength: currentDataLength, enableLoop: currentEnableLoop } =
259
+ loopConfigRef.current;
260
+ const logicalIndex =
261
+ currentDataLength <= 0
262
+ ? listIndex
263
+ : getLoopAdjustedIndex(listIndex, currentDataLength, currentEnableLoop).realIndex;
264
+ const didUpdateDimensions = registerItemDimensions({
265
+ data: dataRef.current,
266
+ dimensions,
267
+ getItemKey: getItemKeyRef.current,
268
+ index: logicalIndex,
269
+ item,
270
+ registry: itemDimensionsRef.current,
271
+ });
272
+
273
+ if (didUpdateDimensions && logicalIndex === pendingIndexRef.current) {
274
+ syncActiveContentDimensions(logicalIndex);
275
+ }
276
+ },
277
+ [syncActiveContentDimensions],
278
+ );
106
279
 
107
280
  const animationConfig = useMemo(
108
281
  () => ({
@@ -130,26 +303,38 @@ export const useGestureViewer = <ItemT, LC>({
130
303
  ],
131
304
  );
132
305
 
133
- const adjustedInitialIndex = useMemo(() => {
134
- if (enableLoop && dataLength > 1) {
135
- return initialIndex + 1;
136
- }
137
-
138
- return initialIndex;
139
- }, [enableLoop, dataLength, initialIndex]);
140
-
141
- const constrainTranslation = useMemo(
142
- () => createBoundsConstraint({ height, width }),
143
- [width, height],
306
+ const constrainTranslation = useCallback(
307
+ ({
308
+ scale: targetScale,
309
+ translateX: targetTranslateX,
310
+ translateY: targetTranslateY,
311
+ }: {
312
+ translateX: number;
313
+ translateY: number;
314
+ scale: number;
315
+ }) => {
316
+ 'worklet';
317
+
318
+ return clampTranslationToBounds({
319
+ contentHeight: contentHeight.get(),
320
+ contentWidth: contentWidth.get(),
321
+ height,
322
+ scale: targetScale,
323
+ translateX: targetTranslateX,
324
+ translateY: targetTranslateY,
325
+ width,
326
+ });
327
+ },
328
+ [contentHeight, contentWidth, height, width],
144
329
  );
145
330
 
146
331
  const scrollTo = useCallback(
147
332
  (index: number, animated: boolean) => {
148
- const scrollAction = createScrollAction(listRef.current, width + itemSpacing);
333
+ const scrollAction = createScrollAction(listRef.current, pageStride);
149
334
 
150
335
  return scrollAction.scrollTo(index, animated);
151
336
  },
152
- [width, itemSpacing],
337
+ [pageStride],
153
338
  );
154
339
 
155
340
  const resetTransformState = useCallback(() => {
@@ -168,9 +353,14 @@ export const useGestureViewer = <ItemT, LC>({
168
353
  return;
169
354
  }
170
355
 
356
+ if (nextIndex === pendingIndexRef.current) {
357
+ return;
358
+ }
359
+
171
360
  pendingIndexRef.current = nextIndex;
361
+ syncActiveContentDimensions(nextIndex);
172
362
  },
173
- [dataLength],
363
+ [dataLength, syncActiveContentDimensions],
174
364
  );
175
365
 
176
366
  const syncCurrentIndex = useCallback(
@@ -180,6 +370,7 @@ export const useGestureViewer = <ItemT, LC>({
180
370
  }
181
371
 
182
372
  pendingIndexRef.current = nextIndex;
373
+ syncActiveContentDimensions(nextIndex);
183
374
 
184
375
  const managerCurrentIndex = manager.getState().currentIndex;
185
376
 
@@ -191,7 +382,7 @@ export const useGestureViewer = <ItemT, LC>({
191
382
  manager.notifyStateChange();
192
383
  resetTransformState();
193
384
  },
194
- [dataLength, manager, resetTransformState],
385
+ [dataLength, manager, resetTransformState, syncActiveContentDimensions],
195
386
  );
196
387
 
197
388
  const emitZoomChange = useCallback((currentScale: number, prevScale: number | null) => {
@@ -250,37 +441,78 @@ export const useGestureViewer = <ItemT, LC>({
250
441
  }, [id]);
251
442
 
252
443
  useEffect(() => {
253
- pendingIndexRef.current = initialIndex;
444
+ const currentPositionSnapshot = {
445
+ dataLength,
446
+ initialIndex,
447
+ pageStride,
448
+ usesLoopSentinels,
449
+ };
450
+ const { didDataLengthChange, didInitialIndexChange, didLoopLayoutChange } =
451
+ getViewerPositionChanges(managerPositionSnapshotRef.current, currentPositionSnapshot);
452
+
453
+ managerPositionSnapshotRef.current = currentPositionSnapshot;
254
454
 
255
455
  if (!manager) {
456
+ configuredManagerRef.current = null;
256
457
  return;
257
458
  }
258
459
 
460
+ const isNewManager = configuredManagerRef.current !== manager;
461
+ const shouldApplyInitialIndex =
462
+ isNewManager || didInitialIndexChange || didDataLengthChange || didLoopLayoutChange;
463
+ const shouldSyncInitialIndex =
464
+ didInitialIndexChange ||
465
+ didDataLengthChange ||
466
+ didLoopLayoutChange ||
467
+ activeGeometryIndexRef.current !== initialIndex;
468
+
259
469
  manager.setDataLength(dataLength);
260
470
  manager.setEnableHorizontalSwipe(enableHorizontalSwipe);
261
- manager.setCurrentIndex(initialIndex);
262
- manager.setWidth(width + itemSpacing);
471
+ manager.setPagingStride(pageStride);
472
+ manager.setViewportWidth(width);
263
473
  manager.setHeight(height);
264
- manager.setZoomSharedValues(scale, translateX, translateY, maxZoomScale);
474
+ manager.setZoomSharedValues({
475
+ contentHeight,
476
+ contentWidth,
477
+ maxZoomScale,
478
+ scale,
479
+ translateX,
480
+ translateY,
481
+ });
265
482
  manager.setResetTransformCallback(resetTransformState);
266
483
  manager.setRotation(rotation);
267
484
  manager.setEnableLoop(enableLoop);
485
+
486
+ if (shouldApplyInitialIndex) {
487
+ pendingIndexRef.current = initialIndex;
488
+ manager.setCurrentIndex(initialIndex);
489
+
490
+ if (shouldSyncInitialIndex) {
491
+ syncActiveContentDimensions(initialIndex);
492
+ }
493
+ }
494
+
495
+ configuredManagerRef.current = manager;
268
496
  manager.notifyStateChange();
269
497
  }, [
270
498
  dataLength,
271
499
  enableHorizontalSwipe,
272
500
  initialIndex,
273
501
  manager,
502
+ pageStride,
274
503
  width,
275
- itemSpacing,
276
504
  maxZoomScale,
277
505
  enableLoop,
278
506
  scale,
279
507
  height,
508
+ contentWidth,
509
+ contentHeight,
280
510
  resetTransformState,
511
+ syncActiveContentDimensions,
281
512
  translateX,
282
513
  translateY,
283
514
  rotation,
515
+ usesLoopSentinels,
284
516
  ]);
285
517
 
286
518
  useEffect(() => {
@@ -292,10 +524,35 @@ export const useGestureViewer = <ItemT, LC>({
292
524
  }, [manager]);
293
525
 
294
526
  useEffect(() => {
295
- const hasDataLengthChanged = previousDataLengthRef.current !== dataLength;
296
- const hasValidInitialIndex = initialIndex >= 0 && initialIndex < dataLength;
527
+ const currentPositionSnapshot = {
528
+ dataLength,
529
+ initialIndex,
530
+ pageStride,
531
+ usesLoopSentinels,
532
+ };
533
+ const {
534
+ didDataLengthChange,
535
+ didInitialIndexChange,
536
+ didLoopLayoutChange,
537
+ didPageStrideChange,
538
+ isInitial: isInitialPositionRender,
539
+ } = getViewerPositionChanges(listPositionSnapshotRef.current, currentPositionSnapshot);
540
+ const commitPositionSnapshot = () => {
541
+ listPositionSnapshotRef.current = currentPositionSnapshot;
542
+ };
543
+
544
+ const shouldResetToInitialIndex =
545
+ isInitialPositionRender ||
546
+ didInitialIndexChange ||
547
+ didDataLengthChange ||
548
+ didLoopLayoutChange;
549
+ const shouldRealignCurrentIndex = didPageStrideChange && !shouldResetToInitialIndex;
550
+
551
+ if (!shouldResetToInitialIndex && !shouldRealignCurrentIndex) {
552
+ commitPositionSnapshot();
553
+ return;
554
+ }
297
555
 
298
- previousDataLengthRef.current = dataLength;
299
556
  translateY.set(0);
300
557
  translateX.set(0);
301
558
  scale.set(1);
@@ -303,21 +560,44 @@ export const useGestureViewer = <ItemT, LC>({
303
560
  startScale.set(1);
304
561
  rotation.set(0);
305
562
 
306
- if (
307
- !hasValidInitialIndex ||
308
- (!hasDataLengthChanged && adjustedInitialIndex <= 0) ||
309
- !listRef.current
310
- ) {
563
+ if (dataLength === 0 || !listRef.current) {
564
+ commitPositionSnapshot();
565
+ return;
566
+ }
567
+
568
+ if (isInitialPositionRender && adjustedInitialIndex === 0) {
569
+ commitPositionSnapshot();
570
+ return;
571
+ }
572
+
573
+ const logicalIndex = shouldResetToInitialIndex
574
+ ? initialIndex
575
+ : clampIndex(
576
+ managerRef.current?.getState().currentIndex ?? pendingIndexRef.current,
577
+ dataLength,
578
+ );
579
+ const physicalIndex = getLoopPhysicalIndex(logicalIndex, dataLength, enableLoop);
580
+
581
+ if (shouldRealignCurrentIndex) {
582
+ pendingIndexRef.current = logicalIndex;
583
+ syncActiveContentDimensions(logicalIndex);
584
+ }
585
+
586
+ if (shouldRealignCurrentIndex && physicalIndex === 0) {
587
+ commitPositionSnapshot();
311
588
  return;
312
589
  }
313
590
 
314
591
  return scheduleInitialScroll(() => {
315
- scrollTo(adjustedInitialIndex, false);
592
+ scrollTo(physicalIndex, false);
593
+ commitPositionSnapshot();
316
594
  });
317
595
  }, [
318
596
  adjustedInitialIndex,
319
597
  dataLength,
598
+ enableLoop,
320
599
  initialIndex,
600
+ pageStride,
321
601
  translateY,
322
602
  backdropOpacity,
323
603
  translateX,
@@ -325,15 +605,36 @@ export const useGestureViewer = <ItemT, LC>({
325
605
  startScale,
326
606
  rotation,
327
607
  scrollTo,
608
+ syncActiveContentDimensions,
609
+ usesLoopSentinels,
328
610
  ]);
329
611
 
330
612
  useEffect(() => {
331
613
  onAnimationCompleteRef.current = triggerAnimation?.onAnimationComplete;
332
614
  }, [triggerAnimation?.onAnimationComplete]);
333
615
 
334
- useEffect(() => {
616
+ useLayoutEffect(() => {
617
+ // Retained virtualized-cell callbacks read only the most recently committed props.
335
618
  dataRef.current = data;
336
- }, [data]);
619
+ getItemDimensionsRef.current = getItemDimensions;
620
+ getItemKeyRef.current = getItemKey;
621
+ viewportRef.current = { height, width };
622
+ loopConfigRef.current = { dataLength, enableLoop };
623
+ syncActiveContentDimensions();
624
+ }, [
625
+ data,
626
+ dataLength,
627
+ enableLoop,
628
+ getItemDimensions,
629
+ getItemKey,
630
+ height,
631
+ syncActiveContentDimensions,
632
+ width,
633
+ ]);
634
+
635
+ useEffect(() => {
636
+ pruneItemDimensionsRegistry(itemDimensionsRef.current, dataLength);
637
+ }, [dataLength]);
337
638
 
338
639
  useEffect(() => {
339
640
  managerRef.current = manager;
@@ -768,6 +1069,8 @@ export const useGestureViewer = <ItemT, LC>({
768
1069
  .numberOfTaps(2)
769
1070
  .onEnd((event) => {
770
1071
  applyTapZoomAtPoint({
1072
+ contentHeight: contentHeight.get(),
1073
+ contentWidth: contentWidth.get(),
771
1074
  x: event.x,
772
1075
  y: event.y,
773
1076
  width,
@@ -778,7 +1081,17 @@ export const useGestureViewer = <ItemT, LC>({
778
1081
  translateY,
779
1082
  });
780
1083
  }),
781
- [enableDoubleTapZoom, height, maxZoomScale, scale, translateX, translateY, width],
1084
+ [
1085
+ contentHeight,
1086
+ contentWidth,
1087
+ enableDoubleTapZoom,
1088
+ height,
1089
+ maxZoomScale,
1090
+ scale,
1091
+ translateX,
1092
+ translateY,
1093
+ width,
1094
+ ],
782
1095
  );
783
1096
 
784
1097
  const tapGesture = useMemo(
@@ -827,6 +1140,8 @@ export const useGestureViewer = <ItemT, LC>({
827
1140
  adjustedInitialIndex,
828
1141
  autoPlay,
829
1142
  autoPlayInterval,
1143
+ contentHeight,
1144
+ contentWidth,
830
1145
  currentIndex,
831
1146
  dataLength,
832
1147
  enableDoubleTapZoom,
@@ -866,6 +1181,7 @@ export const useGestureViewer = <ItemT, LC>({
866
1181
  onScroll,
867
1182
 
868
1183
  onScrollBeginDrag,
1184
+ setItemDimensions,
869
1185
  zoomGesture,
870
1186
  };
871
1187
  };
@@ -25,12 +25,10 @@ export function useGestureViewerPaging({
25
25
  width,
26
26
  }: UseGestureViewerPagingArgs): UseGestureViewerPagingResult {
27
27
  const [activeListIndex, setActiveListIndex] = useState(adjustedInitialIndex);
28
- const activeResetItemSpacing = adjustedInitialIndex > 0 ? itemSpacing : 0;
29
- const activeResetWidth = adjustedInitialIndex > 0 ? width : 0;
30
28
 
31
29
  useEffect(() => {
32
30
  setActiveListIndex(adjustedInitialIndex);
33
- }, [adjustedInitialIndex, activeResetItemSpacing, activeResetWidth, dataLength]);
31
+ }, [adjustedInitialIndex, dataLength]);
34
32
 
35
33
  useEffect(() => {
36
34
  if (
@@ -8,6 +8,8 @@ export type UseGestureViewerPagingArgs = {
8
8
  adjustedInitialIndex: number;
9
9
  autoPlay: boolean;
10
10
  autoPlayInterval: number;
11
+ contentHeight: SharedValue<number>;
12
+ contentWidth: SharedValue<number>;
11
13
  currentIndex: number;
12
14
  dataLength: number;
13
15
  enableDoubleTapZoom: boolean;