react-native-gesture-image-viewer 2.1.4 → 2.3.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 (56) hide show
  1. package/README.md +6 -1
  2. package/lib/module/GestureTrigger.js +22 -5
  3. package/lib/module/GestureTrigger.js.map +1 -1
  4. package/lib/module/GestureViewer.js +2 -2
  5. package/lib/module/GestureViewer.js.map +1 -1
  6. package/lib/module/GestureViewerManager.js +3 -0
  7. package/lib/module/GestureViewerManager.js.map +1 -1
  8. package/lib/module/GestureViewerRegistry.js +52 -8
  9. package/lib/module/GestureViewerRegistry.js.map +1 -1
  10. package/lib/module/index.js.map +1 -1
  11. package/lib/module/useGestureViewer.js +141 -43
  12. package/lib/module/useGestureViewer.js.map +1 -1
  13. package/lib/module/useGestureViewerEvent.js +15 -1
  14. package/lib/module/useGestureViewerEvent.js.map +1 -1
  15. package/lib/module/useGestureViewerPaging.js +16 -2
  16. package/lib/module/useGestureViewerPaging.js.map +1 -1
  17. package/lib/module/useGestureViewerPaging.web.js +62 -28
  18. package/lib/module/useGestureViewerPaging.web.js.map +1 -1
  19. package/lib/module/utils/dismiss.js +25 -0
  20. package/lib/module/utils/dismiss.js.map +1 -0
  21. package/lib/typescript/src/GestureTrigger.d.ts +9 -3
  22. package/lib/typescript/src/GestureTrigger.d.ts.map +1 -1
  23. package/lib/typescript/src/GestureViewer.d.ts.map +1 -1
  24. package/lib/typescript/src/GestureViewerManager.d.ts +2 -1
  25. package/lib/typescript/src/GestureViewerManager.d.ts.map +1 -1
  26. package/lib/typescript/src/GestureViewerRegistry.d.ts +11 -4
  27. package/lib/typescript/src/GestureViewerRegistry.d.ts.map +1 -1
  28. package/lib/typescript/src/index.d.ts +1 -1
  29. package/lib/typescript/src/index.d.ts.map +1 -1
  30. package/lib/typescript/src/types.d.ts +33 -4
  31. package/lib/typescript/src/types.d.ts.map +1 -1
  32. package/lib/typescript/src/useGestureViewer.d.ts +2 -2
  33. package/lib/typescript/src/useGestureViewer.d.ts.map +1 -1
  34. package/lib/typescript/src/useGestureViewerEvent.d.ts +15 -1
  35. package/lib/typescript/src/useGestureViewerEvent.d.ts.map +1 -1
  36. package/lib/typescript/src/useGestureViewerPaging.d.ts +1 -1
  37. package/lib/typescript/src/useGestureViewerPaging.d.ts.map +1 -1
  38. package/lib/typescript/src/useGestureViewerPaging.types.d.ts +10 -1
  39. package/lib/typescript/src/useGestureViewerPaging.types.d.ts.map +1 -1
  40. package/lib/typescript/src/useGestureViewerPaging.web.d.ts +1 -1
  41. package/lib/typescript/src/useGestureViewerPaging.web.d.ts.map +1 -1
  42. package/lib/typescript/src/utils/dismiss.d.ts +4 -0
  43. package/lib/typescript/src/utils/dismiss.d.ts.map +1 -0
  44. package/package.json +1 -1
  45. package/src/GestureTrigger.tsx +31 -6
  46. package/src/GestureViewer.tsx +4 -2
  47. package/src/GestureViewerManager.ts +4 -0
  48. package/src/GestureViewerRegistry.ts +67 -8
  49. package/src/index.tsx +1 -0
  50. package/src/types.ts +31 -4
  51. package/src/useGestureViewer.ts +219 -81
  52. package/src/useGestureViewerEvent.ts +15 -1
  53. package/src/useGestureViewerPaging.ts +18 -2
  54. package/src/useGestureViewerPaging.types.ts +8 -1
  55. package/src/useGestureViewerPaging.web.ts +77 -33
  56. package/src/utils/dismiss.ts +36 -0
@@ -1,9 +1,10 @@
1
- import { useCallback, useEffect, useRef } from 'react';
1
+ import { useCallback, useEffect, useRef, type MouseEvent } from 'react';
2
2
  import type { NativeScrollEvent, NativeSyntheticEvent } from 'react-native';
3
3
 
4
4
  import type {
5
5
  UseGestureViewerPagingArgs,
6
6
  UseGestureViewerPagingResult,
7
+ WebClickTarget,
7
8
  } from './useGestureViewerPaging.types';
8
9
  import { applyTapZoomAtPoint } from './utils/tapZoom';
9
10
  import {
@@ -35,6 +36,7 @@ export function useGestureViewerPaging({
35
36
  enableHorizontalSwipe,
36
37
  enableLoop,
37
38
  height,
39
+ onSingleTap,
38
40
  isRotated,
39
41
  isZoomed,
40
42
  itemSpacing,
@@ -43,10 +45,13 @@ export function useGestureViewerPaging({
43
45
  scale,
44
46
  scrollTo,
45
47
  syncCurrentIndex,
48
+ syncPendingIndex,
46
49
  translateX,
47
50
  translateY,
48
51
  width,
49
52
  }: UseGestureViewerPagingArgs): UseGestureViewerPagingResult {
53
+ const webSingleTapTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
54
+
50
55
  const webScrollRuntimeRef = useRef<WebScrollRuntime>({
51
56
  actor: 'idle',
52
57
  isAutoplayPausedByUser: false,
@@ -58,6 +63,13 @@ export function useGestureViewerPaging({
58
63
  resumeAutoplayTimer: null,
59
64
  });
60
65
 
66
+ const clearWebSingleTapTimer = useCallback(() => {
67
+ if (webSingleTapTimerRef.current) {
68
+ clearTimeout(webSingleTapTimerRef.current);
69
+ webSingleTapTimerRef.current = null;
70
+ }
71
+ }, []);
72
+
61
73
  const clearWebSettleTimer = useCallback(() => {
62
74
  const runtime = webScrollRuntimeRef.current;
63
75
 
@@ -231,10 +243,11 @@ export function useGestureViewerPaging({
231
243
 
232
244
  useEffect(() => {
233
245
  return () => {
246
+ clearWebSingleTapTimer();
234
247
  clearWebSettleTimer();
235
248
  clearWebAutoplayResumeTimer();
236
249
  };
237
- }, [clearWebAutoplayResumeTimer, clearWebSettleTimer]);
250
+ }, [clearWebAutoplayResumeTimer, clearWebSettleTimer, clearWebSingleTapTimer]);
238
251
 
239
252
  useEffect(() => {
240
253
  if (
@@ -302,15 +315,34 @@ export function useGestureViewerPaging({
302
315
  return;
303
316
  }
304
317
 
318
+ const offsetX = event.nativeEvent.contentOffset.x;
319
+ const runtime = webScrollRuntimeRef.current;
320
+ const pendingState = resolveWebScrollFinalState({
321
+ dataLength,
322
+ enableLoop,
323
+ lastSettledPhysicalIndex: runtime.lastSettledPhysicalIndex,
324
+ offsetX,
325
+ pageWidth: width + itemSpacing,
326
+ });
327
+
328
+ if (pendingState) {
329
+ syncPendingIndex(pendingState.logicalIndex);
330
+ }
331
+
305
332
  syncProgrammaticActorFromManager();
306
333
  beginWebUserInteraction();
307
- scheduleWebScrollSettle(event.nativeEvent.contentOffset.x);
334
+ scheduleWebScrollSettle(offsetX);
308
335
  },
309
336
  [
310
337
  beginWebUserInteraction,
338
+ dataLength,
311
339
  enableHorizontalSwipe,
340
+ enableLoop,
341
+ itemSpacing,
312
342
  scheduleWebScrollSettle,
343
+ syncPendingIndex,
313
344
  syncProgrammaticActorFromManager,
345
+ width,
314
346
  ],
315
347
  );
316
348
 
@@ -331,50 +363,62 @@ export function useGestureViewerPaging({
331
363
  manager?.handleScrollBeginDrag();
332
364
  }, [beginWebUserInteraction, clearWebSettleTimer, manager]);
333
365
 
334
- const onWebDoubleClick = useCallback(
335
- (event: any) => {
336
- if (!enableDoubleTapZoom || event?.nativeEvent?.detail !== 2) {
366
+ const onWebClick = useCallback(
367
+ (event: MouseEvent<WebClickTarget>) => {
368
+ const detail = event.detail;
369
+ const rect = event.currentTarget.getBoundingClientRect();
370
+ const resolvedX = event.clientX - rect.left;
371
+ const resolvedY = event.clientY - rect.top;
372
+
373
+ if (!enableDoubleTapZoom) {
374
+ if (!onSingleTap) {
375
+ return;
376
+ }
377
+
378
+ clearWebSingleTapTimer();
379
+ onSingleTap(resolvedX, resolvedY);
337
380
  return;
338
381
  }
339
382
 
340
- pauseWebAutoplayWithoutPagingInteraction();
341
- scheduleWebAutoplayResume();
383
+ if (detail === 2) {
384
+ clearWebSingleTapTimer();
342
385
 
343
- const nativeEvent = event?.nativeEvent;
344
- const eventTarget = event?.currentTarget ?? nativeEvent?.currentTarget ?? nativeEvent?.target;
345
- let locationX = nativeEvent?.locationX;
346
- let locationY = nativeEvent?.locationY;
386
+ pauseWebAutoplayWithoutPagingInteraction();
387
+ scheduleWebAutoplayResume();
347
388
 
348
- if (
349
- (!Number.isFinite(locationX) || !Number.isFinite(locationY)) &&
350
- typeof eventTarget?.getBoundingClientRect === 'function' &&
351
- Number.isFinite(nativeEvent?.clientX) &&
352
- Number.isFinite(nativeEvent?.clientY)
353
- ) {
354
- const rect = eventTarget.getBoundingClientRect();
389
+ applyTapZoomAtPoint({
390
+ x: resolvedX,
391
+ y: resolvedY,
392
+ width,
393
+ height,
394
+ maxZoomScale,
395
+ scale,
396
+ translateX,
397
+ translateY,
398
+ });
399
+ return;
400
+ }
355
401
 
356
- locationX = nativeEvent.clientX - rect.left;
357
- locationY = nativeEvent.clientY - rect.top;
402
+ if (detail !== 1 || !onSingleTap) {
403
+ return;
358
404
  }
359
405
 
360
- applyTapZoomAtPoint({
361
- x: Number.isFinite(locationX) ? locationX : width / 2,
362
- y: Number.isFinite(locationY) ? locationY : height / 2,
363
- width,
364
- height,
365
- maxZoomScale,
366
- scale,
367
- translateX,
368
- translateY,
369
- });
406
+ clearWebSingleTapTimer();
407
+
408
+ webSingleTapTimerRef.current = setTimeout(() => {
409
+ onSingleTap(resolvedX, resolvedY);
410
+ webSingleTapTimerRef.current = null;
411
+ }, 250);
370
412
  },
371
413
  [
414
+ clearWebSingleTapTimer,
372
415
  enableDoubleTapZoom,
373
416
  height,
374
417
  maxZoomScale,
418
+ onSingleTap,
375
419
  pauseWebAutoplayWithoutPagingInteraction,
376
- scheduleWebAutoplayResume,
377
420
  scale,
421
+ scheduleWebAutoplayResume,
378
422
  translateX,
379
423
  translateY,
380
424
  width,
@@ -385,6 +429,6 @@ export function useGestureViewerPaging({
385
429
  onMomentumScrollEnd,
386
430
  onScroll,
387
431
  onScrollBeginDrag,
388
- onWebDoubleClick,
432
+ onWebClick,
389
433
  };
390
434
  }
@@ -0,0 +1,36 @@
1
+ import type { GestureViewerDismissDirection } from '../types';
2
+
3
+ export const shouldDismissByDirection = (
4
+ translationY: number,
5
+ threshold: number,
6
+ direction: GestureViewerDismissDirection,
7
+ ): boolean => {
8
+ 'worklet';
9
+
10
+ if (direction === 'up') {
11
+ return translationY < -threshold;
12
+ }
13
+
14
+ if (direction === 'both') {
15
+ return Math.abs(translationY) > threshold;
16
+ }
17
+
18
+ return translationY > threshold;
19
+ };
20
+
21
+ export const getDismissDistance = (
22
+ translationY: number,
23
+ direction: GestureViewerDismissDirection,
24
+ ): number => {
25
+ 'worklet';
26
+
27
+ if (direction === 'up') {
28
+ return Math.max(-translationY, 0);
29
+ }
30
+
31
+ if (direction === 'both') {
32
+ return Math.abs(translationY);
33
+ }
34
+
35
+ return Math.max(translationY, 0);
36
+ };