react-native-gesture-image-viewer 2.2.0 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -1
- package/lib/module/GestureViewer.js +2 -2
- package/lib/module/GestureViewer.js.map +1 -1
- package/lib/module/GestureViewerManager.js +27 -23
- package/lib/module/GestureViewerManager.js.map +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/useGestureViewer.js +156 -106
- package/lib/module/useGestureViewer.js.map +1 -1
- package/lib/module/useGestureViewerEvent.js +15 -1
- package/lib/module/useGestureViewerEvent.js.map +1 -1
- package/lib/module/useGestureViewerPaging.js +1 -1
- package/lib/module/useGestureViewerPaging.js.map +1 -1
- package/lib/module/useGestureViewerPaging.web.js +47 -26
- package/lib/module/useGestureViewerPaging.web.js.map +1 -1
- package/lib/module/utils/dismiss.js +25 -0
- package/lib/module/utils/dismiss.js.map +1 -0
- package/lib/module/utils/tapZoom.js +6 -6
- package/lib/module/utils/tapZoom.js.map +1 -1
- package/lib/typescript/src/GestureViewer.d.ts.map +1 -1
- package/lib/typescript/src/GestureViewerManager.d.ts +2 -1
- package/lib/typescript/src/GestureViewerManager.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +1 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +33 -4
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/lib/typescript/src/useGestureViewer.d.ts +2 -2
- package/lib/typescript/src/useGestureViewer.d.ts.map +1 -1
- package/lib/typescript/src/useGestureViewerEvent.d.ts +15 -1
- package/lib/typescript/src/useGestureViewerEvent.d.ts.map +1 -1
- package/lib/typescript/src/useGestureViewerPaging.types.d.ts +9 -1
- package/lib/typescript/src/useGestureViewerPaging.types.d.ts.map +1 -1
- package/lib/typescript/src/useGestureViewerPaging.web.d.ts +1 -1
- package/lib/typescript/src/useGestureViewerPaging.web.d.ts.map +1 -1
- package/lib/typescript/src/utils/dismiss.d.ts +4 -0
- package/lib/typescript/src/utils/dismiss.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/GestureViewer.tsx +4 -2
- package/src/GestureViewerManager.ts +31 -25
- package/src/index.tsx +1 -0
- package/src/types.ts +31 -4
- package/src/useGestureViewer.ts +239 -157
- package/src/useGestureViewerEvent.ts +15 -1
- package/src/useGestureViewerPaging.ts +1 -1
- package/src/useGestureViewerPaging.types.ts +7 -1
- package/src/useGestureViewerPaging.web.ts +56 -32
- package/src/utils/dismiss.ts +36 -0
- package/src/utils/tapZoom.ts +6 -6
|
@@ -86,6 +86,10 @@ class GestureViewerManager {
|
|
|
86
86
|
this.emitEvent('rotationChange', { rotation, previousRotation });
|
|
87
87
|
};
|
|
88
88
|
|
|
89
|
+
emitTap = (data: GestureViewerEventData['tap']) => {
|
|
90
|
+
this.emitEvent('tap', data);
|
|
91
|
+
};
|
|
92
|
+
|
|
89
93
|
getState(): GestureViewerState {
|
|
90
94
|
return {
|
|
91
95
|
currentIndex: this.currentIndex,
|
|
@@ -154,32 +158,34 @@ class GestureViewerManager {
|
|
|
154
158
|
rotate = (angle: 0 | 90 | 180 | 270 | 360 = 90, clockwise = true) => {
|
|
155
159
|
const MAX_ANGLE = 360;
|
|
156
160
|
|
|
161
|
+
const currentRotation = this.rotation?.get();
|
|
162
|
+
|
|
157
163
|
if (
|
|
158
|
-
|
|
164
|
+
currentRotation === undefined ||
|
|
159
165
|
angle < 0 ||
|
|
160
166
|
angle > MAX_ANGLE ||
|
|
161
|
-
(angle !== 0 &&
|
|
167
|
+
(angle !== 0 && currentRotation % angle !== 0 && angle !== 360)
|
|
162
168
|
) {
|
|
163
169
|
return;
|
|
164
170
|
}
|
|
165
171
|
|
|
166
172
|
if (angle === 0) {
|
|
167
|
-
const nextAngle = Math.floor(
|
|
173
|
+
const nextAngle = Math.floor(currentRotation / MAX_ANGLE) * MAX_ANGLE;
|
|
168
174
|
|
|
169
|
-
this.rotation
|
|
175
|
+
this.rotation?.set(withTiming(clockwise ? nextAngle : nextAngle - MAX_ANGLE));
|
|
170
176
|
return;
|
|
171
177
|
}
|
|
172
178
|
|
|
173
179
|
if (angle === 360) {
|
|
174
|
-
this.rotation
|
|
175
|
-
clockwise ?
|
|
180
|
+
this.rotation?.set(
|
|
181
|
+
withTiming(clockwise ? currentRotation + MAX_ANGLE : currentRotation - MAX_ANGLE),
|
|
176
182
|
);
|
|
177
183
|
return;
|
|
178
184
|
}
|
|
179
185
|
|
|
180
|
-
const nextAngle = clockwise ?
|
|
186
|
+
const nextAngle = clockwise ? currentRotation + angle : currentRotation - angle;
|
|
181
187
|
|
|
182
|
-
this.rotation
|
|
188
|
+
this.rotation?.set(withTiming(nextAngle));
|
|
183
189
|
};
|
|
184
190
|
|
|
185
191
|
zoomIn = (multiplier = 0.25) => {
|
|
@@ -193,21 +199,21 @@ class GestureViewerManager {
|
|
|
193
199
|
return;
|
|
194
200
|
}
|
|
195
201
|
|
|
196
|
-
const nextScale = Math.min(this.scale.
|
|
202
|
+
const nextScale = Math.min(this.scale.get() * (1 + multiplier), this.maxZoomScale);
|
|
197
203
|
|
|
198
|
-
this.scale.
|
|
204
|
+
this.scale.set(withTiming(nextScale));
|
|
199
205
|
|
|
200
206
|
const { translateX, translateY } = createBoundsConstraint({
|
|
201
207
|
width: this.width,
|
|
202
208
|
height: this.height,
|
|
203
209
|
})({
|
|
204
|
-
translateX: this.translateX.
|
|
205
|
-
translateY: this.translateY.
|
|
210
|
+
translateX: this.translateX.get(),
|
|
211
|
+
translateY: this.translateY.get(),
|
|
206
212
|
scale: nextScale,
|
|
207
213
|
});
|
|
208
214
|
|
|
209
|
-
this.translateX.
|
|
210
|
-
this.translateY.
|
|
215
|
+
this.translateX.set(withTiming(translateX));
|
|
216
|
+
this.translateY.set(withTiming(translateY));
|
|
211
217
|
};
|
|
212
218
|
|
|
213
219
|
zoomOut = (multiplier = 0.25) => {
|
|
@@ -221,13 +227,13 @@ class GestureViewerManager {
|
|
|
221
227
|
return;
|
|
222
228
|
}
|
|
223
229
|
|
|
224
|
-
const nextScale = Math.max(this.scale.
|
|
230
|
+
const nextScale = Math.max(this.scale.get() / (1 + multiplier), 1);
|
|
225
231
|
|
|
226
|
-
this.scale.
|
|
232
|
+
this.scale.set(withTiming(nextScale));
|
|
227
233
|
|
|
228
234
|
if (nextScale === 1) {
|
|
229
|
-
this.translateX.
|
|
230
|
-
this.translateY.
|
|
235
|
+
this.translateX.set(withTiming(0));
|
|
236
|
+
this.translateY.set(withTiming(0));
|
|
231
237
|
return;
|
|
232
238
|
}
|
|
233
239
|
|
|
@@ -235,13 +241,13 @@ class GestureViewerManager {
|
|
|
235
241
|
width: this.width,
|
|
236
242
|
height: this.height,
|
|
237
243
|
})({
|
|
238
|
-
translateX: this.translateX.
|
|
239
|
-
translateY: this.translateY.
|
|
244
|
+
translateX: this.translateX.get(),
|
|
245
|
+
translateY: this.translateY.get(),
|
|
240
246
|
scale: nextScale,
|
|
241
247
|
});
|
|
242
248
|
|
|
243
|
-
this.translateX.
|
|
244
|
-
this.translateY.
|
|
249
|
+
this.translateX.set(withTiming(translateX));
|
|
250
|
+
this.translateY.set(withTiming(translateY));
|
|
245
251
|
};
|
|
246
252
|
|
|
247
253
|
resetZoom = (scale = 1) => {
|
|
@@ -255,9 +261,9 @@ class GestureViewerManager {
|
|
|
255
261
|
return;
|
|
256
262
|
}
|
|
257
263
|
|
|
258
|
-
this.scale.
|
|
259
|
-
this.translateX.
|
|
260
|
-
this.translateY.
|
|
264
|
+
this.scale.set(withTiming(scale));
|
|
265
|
+
this.translateX.set(withTiming(0));
|
|
266
|
+
this.translateY.set(withTiming(0));
|
|
261
267
|
};
|
|
262
268
|
|
|
263
269
|
goToIndex = (index: number) => {
|
package/src/index.tsx
CHANGED
|
@@ -8,6 +8,7 @@ export type {
|
|
|
8
8
|
GestureViewerEventType,
|
|
9
9
|
GestureViewerProps,
|
|
10
10
|
GestureViewerState,
|
|
11
|
+
GestureViewerSingleTapEvent,
|
|
11
12
|
} from './types';
|
|
12
13
|
export { useGestureViewerController } from './useGestureViewerController';
|
|
13
14
|
export { useGestureViewerEvent } from './useGestureViewerEvent';
|
package/src/types.ts
CHANGED
|
@@ -75,6 +75,15 @@ export type TriggerRect = {
|
|
|
75
75
|
height: number;
|
|
76
76
|
};
|
|
77
77
|
|
|
78
|
+
export type GestureViewerSingleTapEvent<ItemT> = {
|
|
79
|
+
x: number;
|
|
80
|
+
y: number;
|
|
81
|
+
index: number;
|
|
82
|
+
item: ItemT;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export type GestureViewerDismissDirection = 'down' | 'up' | 'both';
|
|
86
|
+
|
|
78
87
|
export interface TriggerAnimationConfig extends WithTimingConfig {
|
|
79
88
|
/**
|
|
80
89
|
* Animation duration in milliseconds
|
|
@@ -121,9 +130,18 @@ export interface GestureViewerProps<ItemT, LC> {
|
|
|
121
130
|
* A callback function that is called to render the item.
|
|
122
131
|
*/
|
|
123
132
|
renderItem: (item: ItemT, index: number) => React.ReactElement;
|
|
133
|
+
/**
|
|
134
|
+
* A callback function that is called when a single tap is confirmed on the viewer content.
|
|
135
|
+
* @remarks
|
|
136
|
+
* - The callback runs only after the tap is resolved as a single tap, so it may be slightly delayed when double-tap zoom is enabled.
|
|
137
|
+
* - It is not called for swipe, pinch, dismiss, or double-tap zoom gestures.
|
|
138
|
+
* - Prefer this callback over overlaying a pressable in `renderContainer` for fullscreen tap handling.
|
|
139
|
+
*/
|
|
140
|
+
onSingleTap?: (event: GestureViewerSingleTapEvent<ItemT>) => void;
|
|
124
141
|
/**
|
|
125
142
|
* A callback function that is called to render the container.
|
|
126
143
|
* @remarks Useful for composing additional UI (e.g., close button, toolbars) around the viewer.
|
|
144
|
+
* Prefer `onSingleTap` for fullscreen tap handling instead of overlaying a pressable over the viewer content.
|
|
127
145
|
* The second argument provides control helpers such as `dismiss()` to close the viewer.
|
|
128
146
|
*
|
|
129
147
|
* @param children - The viewer content to be rendered inside your container.
|
|
@@ -183,8 +201,8 @@ export interface GestureViewerProps<ItemT, LC> {
|
|
|
183
201
|
*/
|
|
184
202
|
autoPlayInterval?: number;
|
|
185
203
|
/**
|
|
186
|
-
* Dismiss gesture options.
|
|
187
|
-
* @remarks Useful for closing modals with
|
|
204
|
+
* Dismiss gesture options.
|
|
205
|
+
* @remarks Useful for closing modals with configurable vertical swipe gestures.
|
|
188
206
|
*/
|
|
189
207
|
dismiss?: {
|
|
190
208
|
/**
|
|
@@ -192,6 +210,12 @@ export interface GestureViewerProps<ItemT, LC> {
|
|
|
192
210
|
* @defaultValue true
|
|
193
211
|
*/
|
|
194
212
|
enabled?: boolean;
|
|
213
|
+
/**
|
|
214
|
+
* Controls which vertical swipe direction can trigger `onDismiss`.
|
|
215
|
+
* @remarks Use `down` for backward-compatible behavior, `up` for upward-only dismiss, or `both` for either direction.
|
|
216
|
+
* @defaultValue 'down'
|
|
217
|
+
*/
|
|
218
|
+
direction?: GestureViewerDismissDirection;
|
|
195
219
|
/**
|
|
196
220
|
* `threshold` controls when `onDismiss` is called by applying a threshold value during vertical gestures.
|
|
197
221
|
* @defaultValue 80
|
|
@@ -203,7 +227,7 @@ export interface GestureViewerProps<ItemT, LC> {
|
|
|
203
227
|
*/
|
|
204
228
|
resistance?: number;
|
|
205
229
|
/**
|
|
206
|
-
* By default, the background `opacity` gradually decreases
|
|
230
|
+
* By default, the background `opacity` gradually decreases as you drag in the configured dismiss direction.
|
|
207
231
|
* @remarks When `false`, this animation is disabled.
|
|
208
232
|
* @defaultValue true
|
|
209
233
|
*/
|
|
@@ -425,11 +449,14 @@ export type GestureViewerState = {
|
|
|
425
449
|
readonly totalCount: number;
|
|
426
450
|
};
|
|
427
451
|
|
|
428
|
-
export type GestureViewerEventType = 'zoomChange' | 'rotationChange';
|
|
452
|
+
export type GestureViewerEventType = 'zoomChange' | 'rotationChange' | 'tap';
|
|
453
|
+
|
|
454
|
+
export type SingleTapEventData = { kind: 'single'; x: number; y: number; index: number };
|
|
429
455
|
|
|
430
456
|
export type GestureViewerEventData = {
|
|
431
457
|
zoomChange: { scale: number; previousScale: number | null };
|
|
432
458
|
rotationChange: { rotation: number; previousRotation: number | null };
|
|
459
|
+
tap: SingleTapEventData;
|
|
433
460
|
};
|
|
434
461
|
|
|
435
462
|
export type GestureViewerEventCallback<T extends GestureViewerEventType> = (
|