zkit-ui 2.0.21 → 2.0.23
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/android/src/main/java/cn/fontree/zkit/ui/preview/NativeImagePreviewSourceViewRegistry.java +13 -0
- package/android/src/main/java/cn/fontree/zkit/ui/preview/NativeImagePreviewViewerOverlayView.java +1 -1
- package/dist/ui/NativeImagePreview/web/types.d.ts +2 -0
- package/dist/ui/NativeImagePreview/web/types.d.ts.map +1 -1
- package/dist/ui/NativeImagePreview/web/viewer.d.ts +5 -0
- package/dist/ui/NativeImagePreview/web/viewer.d.ts.map +1 -1
- package/dist/ui/NativeImagePreview/web/viewer.js +83 -12
- package/dist/ui/SliderCaptcha/index.d.ts.map +1 -1
- package/dist/ui/SliderCaptcha/index.js +123 -3
- package/package.json +1 -1
- package/src/ui/NativeImagePreview/web/types.ts +2 -0
- package/src/ui/NativeImagePreview/web/viewer.ts +86 -11
- package/src/ui/SliderCaptcha/README.md +1 -0
- package/src/ui/SliderCaptcha/index.tsx +174 -3
package/android/src/main/java/cn/fontree/zkit/ui/preview/NativeImagePreviewSourceViewRegistry.java
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
package cn.fontree.zkit.ui.preview;
|
|
2
2
|
|
|
3
|
+
import android.graphics.Rect;
|
|
3
4
|
import android.view.View;
|
|
4
5
|
import android.widget.ImageView;
|
|
5
6
|
|
|
@@ -72,6 +73,18 @@ public final class NativeImagePreviewSourceViewRegistry {
|
|
|
72
73
|
return imageView;
|
|
73
74
|
}
|
|
74
75
|
|
|
76
|
+
@Nullable
|
|
77
|
+
public static synchronized ImageView findVisible(@NonNull String key) {
|
|
78
|
+
ImageView imageView = find(key);
|
|
79
|
+
if (imageView == null) {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
Rect visibleRect = new Rect();
|
|
83
|
+
return imageView.getGlobalVisibleRect(visibleRect) && !visibleRect.isEmpty()
|
|
84
|
+
? imageView
|
|
85
|
+
: null;
|
|
86
|
+
}
|
|
87
|
+
|
|
75
88
|
@Nullable
|
|
76
89
|
private static ImageView resolveMappedViewLocked(@NonNull String key) {
|
|
77
90
|
WeakReference<ImageView> reference = SOURCE_VIEWS.get(key);
|
package/android/src/main/java/cn/fontree/zkit/ui/preview/NativeImagePreviewViewerOverlayView.java
CHANGED
|
@@ -377,7 +377,7 @@ public final class NativeImagePreviewViewerOverlayView extends FrameLayout imple
|
|
|
377
377
|
|
|
378
378
|
NativeImagePreviewMediaItem item = items.get(currentIndex);
|
|
379
379
|
String anchorKey = NativeImagePreviewSharedElementNames.forItem(previewGroupId, item);
|
|
380
|
-
ImageView targetView = NativeImagePreviewSourceViewRegistry.
|
|
380
|
+
ImageView targetView = NativeImagePreviewSourceViewRegistry.findVisible(anchorKey);
|
|
381
381
|
NativeImagePreviewSharedElementState targetState = NativeImagePreviewLayoutSupport.captureImageViewState(targetView);
|
|
382
382
|
NativeImagePreviewSharedElementGeometry targetGeometry = targetState != null
|
|
383
383
|
? targetState.getGeometry()
|
|
@@ -59,7 +59,9 @@ export type NativeImagePreviewWebOpenOptions = {
|
|
|
59
59
|
sourceObjectFit?: NativeImagePreviewWebObjectFit;
|
|
60
60
|
sourceVisibility?: NativeImagePreviewWebSourceVisibility;
|
|
61
61
|
theme?: NativeImagePreviewWebTheme;
|
|
62
|
+
/** Defaults to hidden for images and visible for videos. */
|
|
62
63
|
closeButton?: boolean;
|
|
64
|
+
/** Hidden by default; set to true to show the current item position. */
|
|
63
65
|
counter?: boolean;
|
|
64
66
|
onChange?: (index: number, meta: NativeImagePreviewWebChangeMeta) => void;
|
|
65
67
|
onClose?: (meta: NativeImagePreviewWebCloseMeta) => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/ui/NativeImagePreview/web/types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/ui/NativeImagePreview/web/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -35,6 +35,9 @@ export declare class NativeImagePreviewWebViewer implements NativeImagePreviewWe
|
|
|
35
35
|
private previousHtmlOverflow;
|
|
36
36
|
private viewportWidth;
|
|
37
37
|
private viewportHeight;
|
|
38
|
+
private pendingTapCloseTimer;
|
|
39
|
+
private tapEligible;
|
|
40
|
+
private controlsVisible;
|
|
38
41
|
open(options: NativeImagePreviewWebOpenOptions): Promise<void>;
|
|
39
42
|
close(reason?: NativeImagePreviewWebCloseReason): Promise<void>;
|
|
40
43
|
destroy(): void;
|
|
@@ -48,6 +51,7 @@ export declare class NativeImagePreviewWebViewer implements NativeImagePreviewWe
|
|
|
48
51
|
private showContent;
|
|
49
52
|
private showControls;
|
|
50
53
|
private hideControls;
|
|
54
|
+
private syncCloseButtonVisibility;
|
|
51
55
|
private finishClose;
|
|
52
56
|
private unmount;
|
|
53
57
|
private captureViewportSize;
|
|
@@ -77,6 +81,7 @@ export declare class NativeImagePreviewWebViewer implements NativeImagePreviewWe
|
|
|
77
81
|
private handleVisibilityChange;
|
|
78
82
|
private handleLostPointerCapture;
|
|
79
83
|
private handleTap;
|
|
84
|
+
private cancelPendingTapClose;
|
|
80
85
|
private preparePinchIfNeeded;
|
|
81
86
|
private applyPinch;
|
|
82
87
|
private finishSwipe;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"viewer.d.ts","sourceRoot":"","sources":["../../../../src/ui/NativeImagePreview/web/viewer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAGV,gCAAgC,EAChC,+BAA+B,EAG/B,gCAAgC,EAChC,yBAAyB,EAG1B,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"viewer.d.ts","sourceRoot":"","sources":["../../../../src/ui/NativeImagePreview/web/viewer.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,6 +9,7 @@ const media_1 = require("./media");
|
|
|
9
9
|
const transition_1 = require("./transition");
|
|
10
10
|
const MAX_SCALE = 5;
|
|
11
11
|
const DOUBLE_TAP_SCALE = 2.5;
|
|
12
|
+
const DOUBLE_TAP_TIMEOUT = 280;
|
|
12
13
|
const DRAG_DISMISS_DISTANCE = 72;
|
|
13
14
|
const DRAG_DISMISS_MIN_FLING_DISTANCE = 24;
|
|
14
15
|
const DRAG_DISMISS_VELOCITY = 520;
|
|
@@ -53,14 +54,19 @@ class NativeImagePreviewWebViewer {
|
|
|
53
54
|
this.previousHtmlOverflow = '';
|
|
54
55
|
this.viewportWidth = 1;
|
|
55
56
|
this.viewportHeight = 1;
|
|
57
|
+
this.pendingTapCloseTimer = null;
|
|
58
|
+
this.tapEligible = false;
|
|
59
|
+
this.controlsVisible = false;
|
|
56
60
|
this.handlePointerDown = (event) => {
|
|
57
61
|
if (this.closing || !this.root) {
|
|
58
62
|
return;
|
|
59
63
|
}
|
|
64
|
+
this.cancelPendingTapClose(false);
|
|
60
65
|
const target = event.target;
|
|
61
66
|
if (this.shouldIgnorePointerStart(target, event)) {
|
|
62
67
|
return;
|
|
63
68
|
}
|
|
69
|
+
this.tapEligible = this.pointers.size === 0;
|
|
64
70
|
this.root.setPointerCapture(event.pointerId);
|
|
65
71
|
this.pointers.set(event.pointerId, { id: event.pointerId, x: event.clientX, y: event.clientY });
|
|
66
72
|
this.downX = event.clientX;
|
|
@@ -71,6 +77,10 @@ class NativeImagePreviewWebViewer {
|
|
|
71
77
|
this.dragX = 0;
|
|
72
78
|
this.dragY = 0;
|
|
73
79
|
this.mode = this.pointers.size >= 2 ? 'pinch' : 'none';
|
|
80
|
+
if (this.mode === 'pinch') {
|
|
81
|
+
this.tapEligible = false;
|
|
82
|
+
this.cancelPendingTapClose(true);
|
|
83
|
+
}
|
|
74
84
|
this.preparePinchIfNeeded();
|
|
75
85
|
};
|
|
76
86
|
this.handlePointerMove = (event) => {
|
|
@@ -80,6 +90,7 @@ class NativeImagePreviewWebViewer {
|
|
|
80
90
|
event.preventDefault();
|
|
81
91
|
this.pointers.set(event.pointerId, { id: event.pointerId, x: event.clientX, y: event.clientY });
|
|
82
92
|
if (this.pointers.size >= 2) {
|
|
93
|
+
this.tapEligible = false;
|
|
83
94
|
this.mode = 'pinch';
|
|
84
95
|
this.applyPinch();
|
|
85
96
|
return;
|
|
@@ -95,6 +106,8 @@ class NativeImagePreviewWebViewer {
|
|
|
95
106
|
if (Math.hypot(dx, dy) < MODE_LOCK_DISTANCE) {
|
|
96
107
|
return;
|
|
97
108
|
}
|
|
109
|
+
this.tapEligible = false;
|
|
110
|
+
this.cancelPendingTapClose(true);
|
|
98
111
|
if (state.scale > 1.02) {
|
|
99
112
|
this.mode = 'pan';
|
|
100
113
|
}
|
|
@@ -126,6 +139,10 @@ class NativeImagePreviewWebViewer {
|
|
|
126
139
|
if (!this.pointers.has(event.pointerId)) {
|
|
127
140
|
return;
|
|
128
141
|
}
|
|
142
|
+
if (event.type === 'pointercancel') {
|
|
143
|
+
this.cancelActiveGesture();
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
129
146
|
const finalDx = event.clientX - this.downX;
|
|
130
147
|
const finalDy = event.clientY - this.downY;
|
|
131
148
|
this.pointers.delete(event.pointerId);
|
|
@@ -133,6 +150,7 @@ class NativeImagePreviewWebViewer {
|
|
|
133
150
|
this.root.releasePointerCapture(event.pointerId);
|
|
134
151
|
}
|
|
135
152
|
if (this.pointers.size >= 2) {
|
|
153
|
+
this.tapEligible = false;
|
|
136
154
|
this.preparePinchIfNeeded();
|
|
137
155
|
return;
|
|
138
156
|
}
|
|
@@ -164,9 +182,10 @@ class NativeImagePreviewWebViewer {
|
|
|
164
182
|
this.dragX = finalDx;
|
|
165
183
|
this.finishSwipe(velocityX);
|
|
166
184
|
}
|
|
167
|
-
else if (this.mode === 'none') {
|
|
185
|
+
else if (this.mode === 'none' && this.tapEligible) {
|
|
168
186
|
this.handleTap(event);
|
|
169
187
|
}
|
|
188
|
+
this.tapEligible = false;
|
|
170
189
|
this.mode = 'none';
|
|
171
190
|
this.dragX = 0;
|
|
172
191
|
this.dragY = 0;
|
|
@@ -176,6 +195,8 @@ class NativeImagePreviewWebViewer {
|
|
|
176
195
|
return;
|
|
177
196
|
}
|
|
178
197
|
event.preventDefault();
|
|
198
|
+
this.tapEligible = false;
|
|
199
|
+
this.cancelPendingTapClose(true);
|
|
179
200
|
const state = this.activeState();
|
|
180
201
|
const nextScale = (0, geometry_1.clamp)(state.scale * (event.deltaY > 0 ? 0.92 : 1.08), 1, MAX_SCALE);
|
|
181
202
|
state.scale = nextScale;
|
|
@@ -251,6 +272,8 @@ class NativeImagePreviewWebViewer {
|
|
|
251
272
|
this.slideStates = items.map(() => this.createSlideState());
|
|
252
273
|
this.openState = true;
|
|
253
274
|
this.closing = false;
|
|
275
|
+
this.tapEligible = false;
|
|
276
|
+
this.controlsVisible = false;
|
|
254
277
|
this.captureViewportSize();
|
|
255
278
|
this.lockDocumentScroll();
|
|
256
279
|
this.mount();
|
|
@@ -265,6 +288,8 @@ class NativeImagePreviewWebViewer {
|
|
|
265
288
|
if (!this.openState || this.closing) {
|
|
266
289
|
return;
|
|
267
290
|
}
|
|
291
|
+
this.cancelPendingTapClose(true);
|
|
292
|
+
this.tapEligible = false;
|
|
268
293
|
this.closing = true;
|
|
269
294
|
await this.performCloseTransition(reason);
|
|
270
295
|
this.finishClose(reason);
|
|
@@ -283,7 +308,7 @@ class NativeImagePreviewWebViewer {
|
|
|
283
308
|
return this.openState;
|
|
284
309
|
}
|
|
285
310
|
mount() {
|
|
286
|
-
var _a, _b, _c
|
|
311
|
+
var _a, _b, _c;
|
|
287
312
|
const root = document.createElement('div');
|
|
288
313
|
root.className = `native-image-preview-root native-image-preview-theme-${(_b = (_a = this.options) === null || _a === void 0 ? void 0 : _a.theme) !== null && _b !== void 0 ? _b : 'dark'}`;
|
|
289
314
|
root.tabIndex = -1;
|
|
@@ -313,12 +338,12 @@ class NativeImagePreviewWebViewer {
|
|
|
313
338
|
closeButton.type = 'button';
|
|
314
339
|
closeButton.textContent = '×';
|
|
315
340
|
closeButton.setAttribute('aria-label', 'Close image preview');
|
|
316
|
-
closeButton.hidden =
|
|
341
|
+
closeButton.hidden = true;
|
|
317
342
|
closeButton.style.opacity = '0';
|
|
318
343
|
root.append(closeButton);
|
|
319
344
|
const counter = document.createElement('div');
|
|
320
345
|
counter.className = 'native-image-preview-counter';
|
|
321
|
-
counter.hidden = ((
|
|
346
|
+
counter.hidden = ((_c = this.options) === null || _c === void 0 ? void 0 : _c.counter) !== true || this.items.length <= 1;
|
|
322
347
|
counter.style.opacity = '0';
|
|
323
348
|
root.append(counter);
|
|
324
349
|
this.root = root;
|
|
@@ -327,6 +352,7 @@ class NativeImagePreviewWebViewer {
|
|
|
327
352
|
this.track = track;
|
|
328
353
|
this.closeButton = closeButton;
|
|
329
354
|
this.counter = counter;
|
|
355
|
+
this.syncCloseButtonVisibility();
|
|
330
356
|
root.addEventListener('pointerdown', this.handlePointerDown);
|
|
331
357
|
root.addEventListener('pointermove', this.handlePointerMove);
|
|
332
358
|
root.addEventListener('pointerup', this.handlePointerUp);
|
|
@@ -456,25 +482,36 @@ class NativeImagePreviewWebViewer {
|
|
|
456
482
|
this.applyActiveMediaTransform(false);
|
|
457
483
|
}
|
|
458
484
|
showControls() {
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
}
|
|
485
|
+
this.controlsVisible = true;
|
|
486
|
+
this.syncCloseButtonVisibility();
|
|
462
487
|
if (this.counter && !this.counter.hidden) {
|
|
463
488
|
this.counter.style.opacity = '1';
|
|
464
489
|
}
|
|
465
490
|
}
|
|
466
491
|
hideControls() {
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
}
|
|
492
|
+
this.controlsVisible = false;
|
|
493
|
+
this.syncCloseButtonVisibility();
|
|
470
494
|
if (this.counter) {
|
|
471
495
|
this.counter.style.opacity = '0';
|
|
472
496
|
}
|
|
473
497
|
}
|
|
498
|
+
syncCloseButtonVisibility() {
|
|
499
|
+
var _a, _b;
|
|
500
|
+
if (!this.closeButton) {
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
const configuredVisibility = (_a = this.options) === null || _a === void 0 ? void 0 : _a.closeButton;
|
|
504
|
+
const shouldShow = configuredVisibility !== null && configuredVisibility !== void 0 ? configuredVisibility : ((_b = this.items[this.index]) === null || _b === void 0 ? void 0 : _b.type) === 'video';
|
|
505
|
+
this.closeButton.hidden = !shouldShow;
|
|
506
|
+
this.closeButton.style.opacity = shouldShow && this.controlsVisible ? '1' : '0';
|
|
507
|
+
}
|
|
474
508
|
finishClose(reason) {
|
|
475
509
|
var _a, _b, _c;
|
|
476
510
|
const item = (_a = this.items[this.index]) !== null && _a !== void 0 ? _a : null;
|
|
477
511
|
const index = this.index;
|
|
512
|
+
this.cancelPendingTapClose(true);
|
|
513
|
+
this.tapEligible = false;
|
|
514
|
+
this.controlsVisible = false;
|
|
478
515
|
this.restoreSourceElement();
|
|
479
516
|
this.unlockDocumentScroll();
|
|
480
517
|
this.unmount();
|
|
@@ -489,6 +526,7 @@ class NativeImagePreviewWebViewer {
|
|
|
489
526
|
this.mode = 'none';
|
|
490
527
|
}
|
|
491
528
|
unmount() {
|
|
529
|
+
this.cancelPendingTapClose(true);
|
|
492
530
|
const root = this.root;
|
|
493
531
|
const closeButton = this.closeButton;
|
|
494
532
|
if (!root) {
|
|
@@ -556,7 +594,7 @@ class NativeImagePreviewWebViewer {
|
|
|
556
594
|
}
|
|
557
595
|
await (0, media_1.waitForElementImage)(element);
|
|
558
596
|
const rect = (0, geometry_1.rectFromElement)(element);
|
|
559
|
-
if (!(0, geometry_1.isUsableRect)(rect)) {
|
|
597
|
+
if (!(0, geometry_1.isUsableRect)(rect) || !(0, geometry_1.intersectRects)(rect, this.viewportRect())) {
|
|
560
598
|
return null;
|
|
561
599
|
}
|
|
562
600
|
const size = await this.resolveSharedMediaSize(item);
|
|
@@ -647,8 +685,14 @@ class NativeImagePreviewWebViewer {
|
|
|
647
685
|
}
|
|
648
686
|
handleTap(event) {
|
|
649
687
|
const state = this.activeState();
|
|
688
|
+
const item = this.items[this.index];
|
|
689
|
+
if ((item === null || item === void 0 ? void 0 : item.type) !== 'image') {
|
|
690
|
+
state.lastTapAt = 0;
|
|
691
|
+
return;
|
|
692
|
+
}
|
|
650
693
|
const now = performance.now();
|
|
651
|
-
if (now - state.lastTapAt <
|
|
694
|
+
if (state.lastTapAt > 0 && now - state.lastTapAt < DOUBLE_TAP_TIMEOUT) {
|
|
695
|
+
this.cancelPendingTapClose(false);
|
|
652
696
|
state.scale = state.scale > 1.02 ? 1 : DOUBLE_TAP_SCALE;
|
|
653
697
|
state.translateX = 0;
|
|
654
698
|
state.translateY = 0;
|
|
@@ -658,6 +702,28 @@ class NativeImagePreviewWebViewer {
|
|
|
658
702
|
return;
|
|
659
703
|
}
|
|
660
704
|
state.lastTapAt = now;
|
|
705
|
+
const tapIndex = this.index;
|
|
706
|
+
this.pendingTapCloseTimer = window.setTimeout(() => {
|
|
707
|
+
this.pendingTapCloseTimer = null;
|
|
708
|
+
const tapState = this.slideStates[tapIndex];
|
|
709
|
+
if (tapState) {
|
|
710
|
+
tapState.lastTapAt = 0;
|
|
711
|
+
}
|
|
712
|
+
if (this.openState && !this.closing && this.index === tapIndex) {
|
|
713
|
+
void this.close('backdrop');
|
|
714
|
+
}
|
|
715
|
+
}, DOUBLE_TAP_TIMEOUT);
|
|
716
|
+
}
|
|
717
|
+
cancelPendingTapClose(resetTapState) {
|
|
718
|
+
if (this.pendingTapCloseTimer !== null) {
|
|
719
|
+
window.clearTimeout(this.pendingTapCloseTimer);
|
|
720
|
+
this.pendingTapCloseTimer = null;
|
|
721
|
+
}
|
|
722
|
+
if (resetTapState) {
|
|
723
|
+
this.slideStates.forEach((state) => {
|
|
724
|
+
state.lastTapAt = 0;
|
|
725
|
+
});
|
|
726
|
+
}
|
|
661
727
|
}
|
|
662
728
|
preparePinchIfNeeded() {
|
|
663
729
|
if (this.pointers.size < 2) {
|
|
@@ -709,6 +775,8 @@ class NativeImagePreviewWebViewer {
|
|
|
709
775
|
}
|
|
710
776
|
goTo(nextIndex, reason) {
|
|
711
777
|
var _a, _b;
|
|
778
|
+
this.cancelPendingTapClose(true);
|
|
779
|
+
this.tapEligible = false;
|
|
712
780
|
const clamped = (0, geometry_1.clamp)(nextIndex, 0, this.items.length - 1);
|
|
713
781
|
const previousIndex = this.index;
|
|
714
782
|
this.index = clamped;
|
|
@@ -716,6 +784,7 @@ class NativeImagePreviewWebViewer {
|
|
|
716
784
|
this.resetSlideState(clamped);
|
|
717
785
|
this.updateTrack(true);
|
|
718
786
|
this.updateCounter();
|
|
787
|
+
this.syncCloseButtonVisibility();
|
|
719
788
|
this.pauseInactiveVideos(clamped);
|
|
720
789
|
if (previousIndex !== clamped) {
|
|
721
790
|
this.syncHiddenSourceElement(clamped);
|
|
@@ -755,6 +824,8 @@ class NativeImagePreviewWebViewer {
|
|
|
755
824
|
}
|
|
756
825
|
}
|
|
757
826
|
cancelActiveGesture() {
|
|
827
|
+
this.cancelPendingTapClose(true);
|
|
828
|
+
this.tapEligible = false;
|
|
758
829
|
if (!this.pointers.size && this.mode === 'none' && !this.dragX && !this.dragY) {
|
|
759
830
|
return;
|
|
760
831
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/SliderCaptcha/index.tsx"],"names":[],"mappings":"AAEA,OAAO,EAOL,SAAS,EAGT,SAAS,EAEV,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/SliderCaptcha/index.tsx"],"names":[],"mappings":"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"}
|
|
@@ -55,6 +55,9 @@ const CARD_HORIZONTAL_PADDING = (0, zkit_tools_1.wp)(24);
|
|
|
55
55
|
const CANVAS_BORDER_WIDTH = (0, zkit_tools_1.wp)(1);
|
|
56
56
|
const CAPTCHA_LAYER_Z_INDEX = 4000;
|
|
57
57
|
const SLIDER_THUMB_SIZE = (0, zkit_tools_1.wp)(44);
|
|
58
|
+
const WEB_SLIDER_EDGE_GESTURE_INSET = react_native_1.Platform.OS === 'web' ? (0, zkit_tools_1.wp)(16) : 0;
|
|
59
|
+
const MIUI_DRAG_BACK_QUERY_KEY = 'native_drag_back';
|
|
60
|
+
const SLIDER_CANCEL_DURATION = 160;
|
|
58
61
|
const CAPTCHA_ENTER_DURATION = 280;
|
|
59
62
|
const CAPTCHA_EXIT_DURATION = 220;
|
|
60
63
|
const CAPTCHA_CARD_OFFSET_Y = (0, zkit_tools_1.wp)(18);
|
|
@@ -89,6 +92,100 @@ function getSafePositiveNumber(value, fallback) {
|
|
|
89
92
|
}
|
|
90
93
|
return value;
|
|
91
94
|
}
|
|
95
|
+
let webHorizontalOverscrollLockCount = 0;
|
|
96
|
+
let webHorizontalOverscrollSnapshots = [];
|
|
97
|
+
let webMiuiDragBackLockCount = 0;
|
|
98
|
+
let webMiuiDragBackSnapshot;
|
|
99
|
+
function acquireWebHorizontalOverscrollLock() {
|
|
100
|
+
if (react_native_1.Platform.OS !== 'web')
|
|
101
|
+
return undefined;
|
|
102
|
+
const webDocument = globalThis.document;
|
|
103
|
+
const targets = [webDocument === null || webDocument === void 0 ? void 0 : webDocument.documentElement, webDocument === null || webDocument === void 0 ? void 0 : webDocument.body].filter((target) => Boolean(target));
|
|
104
|
+
if (targets.length === 0)
|
|
105
|
+
return undefined;
|
|
106
|
+
if (webHorizontalOverscrollLockCount === 0) {
|
|
107
|
+
webHorizontalOverscrollSnapshots = targets.map((target) => ({
|
|
108
|
+
previousValue: target.style.overscrollBehaviorX,
|
|
109
|
+
target,
|
|
110
|
+
}));
|
|
111
|
+
}
|
|
112
|
+
webHorizontalOverscrollLockCount += 1;
|
|
113
|
+
targets.forEach((target) => {
|
|
114
|
+
target.style.overscrollBehaviorX = 'none';
|
|
115
|
+
});
|
|
116
|
+
let released = false;
|
|
117
|
+
return () => {
|
|
118
|
+
if (released)
|
|
119
|
+
return;
|
|
120
|
+
released = true;
|
|
121
|
+
webHorizontalOverscrollLockCount = Math.max(webHorizontalOverscrollLockCount - 1, 0);
|
|
122
|
+
if (webHorizontalOverscrollLockCount > 0)
|
|
123
|
+
return;
|
|
124
|
+
webHorizontalOverscrollSnapshots.forEach(({ previousValue, target }) => {
|
|
125
|
+
if (target.style.overscrollBehaviorX === 'none') {
|
|
126
|
+
target.style.overscrollBehaviorX = previousValue;
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
webHorizontalOverscrollSnapshots = [];
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
function acquireWebMiuiDragBackLock() {
|
|
133
|
+
var _a;
|
|
134
|
+
if (react_native_1.Platform.OS !== 'web')
|
|
135
|
+
return undefined;
|
|
136
|
+
const webEnvironment = globalThis;
|
|
137
|
+
const { history: webHistory, location: webLocation, navigator: webNavigator } = webEnvironment;
|
|
138
|
+
if (!webHistory ||
|
|
139
|
+
!webLocation ||
|
|
140
|
+
!/MiuiBrowser/i.test((_a = webNavigator === null || webNavigator === void 0 ? void 0 : webNavigator.userAgent) !== null && _a !== void 0 ? _a : '')) {
|
|
141
|
+
return undefined;
|
|
142
|
+
}
|
|
143
|
+
if (webMiuiDragBackLockCount === 0) {
|
|
144
|
+
try {
|
|
145
|
+
const guardedUrl = new URL(webLocation.href);
|
|
146
|
+
if (guardedUrl.searchParams.get(MIUI_DRAG_BACK_QUERY_KEY) !== '0') {
|
|
147
|
+
const originalHref = webLocation.href;
|
|
148
|
+
guardedUrl.searchParams.set(MIUI_DRAG_BACK_QUERY_KEY, '0');
|
|
149
|
+
const guardedHref = guardedUrl.href;
|
|
150
|
+
webHistory.replaceState(webHistory.state, '', guardedHref);
|
|
151
|
+
webMiuiDragBackSnapshot = { guardedHref, originalHref };
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
// Ignore restricted history/URL environments and retain the standard Web gesture guards.
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
webMiuiDragBackLockCount += 1;
|
|
159
|
+
let released = false;
|
|
160
|
+
return () => {
|
|
161
|
+
if (released)
|
|
162
|
+
return;
|
|
163
|
+
released = true;
|
|
164
|
+
webMiuiDragBackLockCount = Math.max(webMiuiDragBackLockCount - 1, 0);
|
|
165
|
+
if (webMiuiDragBackLockCount > 0)
|
|
166
|
+
return;
|
|
167
|
+
const snapshot = webMiuiDragBackSnapshot;
|
|
168
|
+
webMiuiDragBackSnapshot = undefined;
|
|
169
|
+
if (!snapshot || webLocation.href !== snapshot.guardedHref)
|
|
170
|
+
return;
|
|
171
|
+
try {
|
|
172
|
+
webHistory.replaceState(webHistory.state, '', snapshot.originalHref);
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
// The browser may reject history writes after a route or document lifecycle change.
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
function resolveWebSliderInteractionStyle(canSlide) {
|
|
180
|
+
if (react_native_1.Platform.OS !== 'web')
|
|
181
|
+
return undefined;
|
|
182
|
+
return {
|
|
183
|
+
cursor: canSlide ? 'grab' : 'default',
|
|
184
|
+
overscrollBehaviorX: 'none',
|
|
185
|
+
touchAction: 'none',
|
|
186
|
+
userSelect: 'none',
|
|
187
|
+
};
|
|
188
|
+
}
|
|
92
189
|
const styles = react_native_1.StyleSheet.create({
|
|
93
190
|
modalRoot: {
|
|
94
191
|
...react_native_1.StyleSheet.absoluteFillObject,
|
|
@@ -192,7 +289,7 @@ const styles = react_native_1.StyleSheet.create({
|
|
|
192
289
|
},
|
|
193
290
|
sliderThumb: {
|
|
194
291
|
position: 'absolute',
|
|
195
|
-
left:
|
|
292
|
+
left: WEB_SLIDER_EDGE_GESTURE_INSET,
|
|
196
293
|
width: SLIDER_THUMB_SIZE,
|
|
197
294
|
height: SLIDER_THUMB_SIZE,
|
|
198
295
|
borderRadius: SLIDER_THUMB_SIZE / 2,
|
|
@@ -265,7 +362,7 @@ function SliderCaptcha({ visible, onClose, initialChallenge = null, loadChalleng
|
|
|
265
362
|
const blockDisplayHeight = blockHeight * scale;
|
|
266
363
|
const blockTop = Math.max(0, ((_a = challenge === null || challenge === void 0 ? void 0 : challenge.blockY) !== null && _a !== void 0 ? _a : 0) * scale);
|
|
267
364
|
const maxBlockOffset = Math.max(canvasContentWidth - blockDisplayWidth, 0);
|
|
268
|
-
const maxThumbOffset = Math.max(canvasOuterWidth - SLIDER_THUMB_SIZE, 0);
|
|
365
|
+
const maxThumbOffset = Math.max(canvasOuterWidth - SLIDER_THUMB_SIZE - WEB_SLIDER_EDGE_GESTURE_INSET * 2, 0);
|
|
269
366
|
const blockTranslateRatio = maxThumbOffset > 0 ? maxBlockOffset / maxThumbOffset : 0;
|
|
270
367
|
const isBusy = status === 'loading' || status === 'verifying';
|
|
271
368
|
const canSlide = visible && Boolean(challenge) && !isBusy;
|
|
@@ -292,6 +389,7 @@ function SliderCaptcha({ visible, onClose, initialChallenge = null, loadChalleng
|
|
|
292
389
|
opacity: 0.15,
|
|
293
390
|
radius: (0, zkit_tools_1.wp)(4),
|
|
294
391
|
}), [theme.colors.onSurface]);
|
|
392
|
+
const webSliderInteractionStyle = React.useMemo(() => resolveWebSliderInteractionStyle(canSlide), [canSlide]);
|
|
295
393
|
const requestChallenge = React.useCallback(async (reason) => {
|
|
296
394
|
if (!visibleRef.current)
|
|
297
395
|
return;
|
|
@@ -476,6 +574,16 @@ function SliderCaptcha({ visible, onClose, initialChallenge = null, loadChalleng
|
|
|
476
574
|
});
|
|
477
575
|
return () => subscription.remove();
|
|
478
576
|
}, [onClose, visible]);
|
|
577
|
+
React.useEffect(() => {
|
|
578
|
+
if (!visible || react_native_1.Platform.OS !== 'web')
|
|
579
|
+
return;
|
|
580
|
+
const releaseHorizontalOverscrollLock = acquireWebHorizontalOverscrollLock();
|
|
581
|
+
const releaseMiuiDragBackLock = acquireWebMiuiDragBackLock();
|
|
582
|
+
return () => {
|
|
583
|
+
releaseMiuiDragBackLock === null || releaseMiuiDragBackLock === void 0 ? void 0 : releaseMiuiDragBackLock();
|
|
584
|
+
releaseHorizontalOverscrollLock === null || releaseHorizontalOverscrollLock === void 0 ? void 0 : releaseHorizontalOverscrollLock();
|
|
585
|
+
};
|
|
586
|
+
}, [visible]);
|
|
479
587
|
const handleCanvasLayout = React.useCallback((event) => {
|
|
480
588
|
const nextWidth = event.nativeEvent.layout.width;
|
|
481
589
|
if (!Number.isFinite(nextWidth) || nextWidth <= 0)
|
|
@@ -521,6 +629,14 @@ function SliderCaptcha({ visible, onClose, initialChallenge = null, loadChalleng
|
|
|
521
629
|
const blockAnimatedStyle = (0, react_native_reanimated_1.useAnimatedStyle)(() => ({
|
|
522
630
|
transform: [{ translateX: thumbX.value * blockTranslateRatio }],
|
|
523
631
|
}));
|
|
632
|
+
const cancelCurrentDrag = React.useCallback(() => {
|
|
633
|
+
const startPosition = clamp(thumbStartRef.current, 0, maxThumbOffset);
|
|
634
|
+
thumbXRef.current = startPosition;
|
|
635
|
+
thumbX.value = (0, react_native_reanimated_1.withTiming)(startPosition, {
|
|
636
|
+
duration: SLIDER_CANCEL_DURATION,
|
|
637
|
+
easing: react_native_reanimated_1.Easing.out(react_native_reanimated_1.Easing.cubic),
|
|
638
|
+
});
|
|
639
|
+
}, [maxThumbOffset, thumbX]);
|
|
524
640
|
const panResponder = React.useMemo(() => react_native_1.PanResponder.create({
|
|
525
641
|
onStartShouldSetPanResponder: () => canSlide,
|
|
526
642
|
onMoveShouldSetPanResponder: () => canSlide,
|
|
@@ -537,7 +653,10 @@ function SliderCaptcha({ visible, onClose, initialChallenge = null, loadChalleng
|
|
|
537
653
|
onPanResponderRelease: () => {
|
|
538
654
|
void verifyCurrentChallenge();
|
|
539
655
|
},
|
|
540
|
-
|
|
656
|
+
onPanResponderTerminate: cancelCurrentDrag,
|
|
657
|
+
onPanResponderTerminationRequest: () => false,
|
|
658
|
+
onShouldBlockNativeResponder: () => true,
|
|
659
|
+
}), [canSlide, cancelCurrentDrag, maxThumbOffset, thumbX, verifyCurrentChallenge]);
|
|
541
660
|
if (!mounted)
|
|
542
661
|
return null;
|
|
543
662
|
return ((0, jsx_runtime_1.jsxs)(react_native_1.View, { pointerEvents: "box-none", style: styles.modalRoot, children: [(0, jsx_runtime_1.jsx)(react_native_reanimated_1.default.View, { style: [styles.overlayBackdrop, backdropAnimatedStyle] }), (0, jsx_runtime_1.jsx)(react_native_1.Pressable, { style: styles.overlayPressable, onPress: handleBackdropPress, children: (0, jsx_runtime_1.jsx)(react_native_reanimated_1.default.View, { style: [styles.cardContainer, cardAnimatedStyle], collapsable: false, renderToHardwareTextureAndroid: react_native_1.Platform.OS === 'android', shouldRasterizeIOS: react_native_1.Platform.OS === 'ios', needsOffscreenAlphaCompositing: react_native_1.Platform.OS === 'android', children: (0, jsx_runtime_1.jsxs)(react_native_1.Pressable, { style: [
|
|
@@ -584,6 +703,7 @@ function SliderCaptcha({ visible, onClose, initialChallenge = null, loadChalleng
|
|
|
584
703
|
], children: (0, jsx_runtime_1.jsx)(Text_1.Text, { style: styles.feedbackText, children: feedbackMessage }) })) : null] }), (0, jsx_runtime_1.jsx)(react_native_1.View, { style: [
|
|
585
704
|
styles.sliderTrack,
|
|
586
705
|
{ backgroundColor: theme.colors.secondary, borderColor: theme.colors.border },
|
|
706
|
+
webSliderInteractionStyle,
|
|
587
707
|
], ...panResponder.panHandlers, children: (0, jsx_runtime_1.jsx)(react_native_reanimated_1.default.View, { style: [
|
|
588
708
|
styles.sliderThumb,
|
|
589
709
|
thumbAnimatedStyle,
|
package/package.json
CHANGED
|
@@ -73,7 +73,9 @@ export type NativeImagePreviewWebOpenOptions = {
|
|
|
73
73
|
sourceObjectFit?: NativeImagePreviewWebObjectFit;
|
|
74
74
|
sourceVisibility?: NativeImagePreviewWebSourceVisibility;
|
|
75
75
|
theme?: NativeImagePreviewWebTheme;
|
|
76
|
+
/** Defaults to hidden for images and visible for videos. */
|
|
76
77
|
closeButton?: boolean;
|
|
78
|
+
/** Hidden by default; set to true to show the current item position. */
|
|
77
79
|
counter?: boolean;
|
|
78
80
|
onChange?: (index: number, meta: NativeImagePreviewWebChangeMeta) => void;
|
|
79
81
|
onClose?: (meta: NativeImagePreviewWebCloseMeta) => void;
|
|
@@ -14,6 +14,7 @@ import type {
|
|
|
14
14
|
} from './types';
|
|
15
15
|
import {
|
|
16
16
|
clamp,
|
|
17
|
+
intersectRects,
|
|
17
18
|
isUsableRect,
|
|
18
19
|
normalizeRect,
|
|
19
20
|
rectFromDOMRect,
|
|
@@ -42,6 +43,7 @@ type GestureMode = 'none' | 'pan' | 'pinch' | 'swipe' | 'dismiss';
|
|
|
42
43
|
|
|
43
44
|
const MAX_SCALE = 5;
|
|
44
45
|
const DOUBLE_TAP_SCALE = 2.5;
|
|
46
|
+
const DOUBLE_TAP_TIMEOUT = 280;
|
|
45
47
|
const DRAG_DISMISS_DISTANCE = 72;
|
|
46
48
|
const DRAG_DISMISS_MIN_FLING_DISTANCE = 24;
|
|
47
49
|
const DRAG_DISMISS_VELOCITY = 520;
|
|
@@ -86,6 +88,9 @@ export class NativeImagePreviewWebViewer implements NativeImagePreviewWebControl
|
|
|
86
88
|
private previousHtmlOverflow = '';
|
|
87
89
|
private viewportWidth = 1;
|
|
88
90
|
private viewportHeight = 1;
|
|
91
|
+
private pendingTapCloseTimer: number | null = null;
|
|
92
|
+
private tapEligible = false;
|
|
93
|
+
private controlsVisible = false;
|
|
89
94
|
|
|
90
95
|
async open(options: NativeImagePreviewWebOpenOptions): Promise<void> {
|
|
91
96
|
if (this.openState) {
|
|
@@ -105,6 +110,8 @@ export class NativeImagePreviewWebViewer implements NativeImagePreviewWebControl
|
|
|
105
110
|
this.slideStates = items.map(() => this.createSlideState());
|
|
106
111
|
this.openState = true;
|
|
107
112
|
this.closing = false;
|
|
113
|
+
this.tapEligible = false;
|
|
114
|
+
this.controlsVisible = false;
|
|
108
115
|
this.captureViewportSize();
|
|
109
116
|
|
|
110
117
|
this.lockDocumentScroll();
|
|
@@ -122,6 +129,8 @@ export class NativeImagePreviewWebViewer implements NativeImagePreviewWebControl
|
|
|
122
129
|
if (!this.openState || this.closing) {
|
|
123
130
|
return;
|
|
124
131
|
}
|
|
132
|
+
this.cancelPendingTapClose(true);
|
|
133
|
+
this.tapEligible = false;
|
|
125
134
|
this.closing = true;
|
|
126
135
|
await this.performCloseTransition(reason);
|
|
127
136
|
this.finishClose(reason);
|
|
@@ -180,13 +189,13 @@ export class NativeImagePreviewWebViewer implements NativeImagePreviewWebControl
|
|
|
180
189
|
closeButton.type = 'button';
|
|
181
190
|
closeButton.textContent = '×';
|
|
182
191
|
closeButton.setAttribute('aria-label', 'Close image preview');
|
|
183
|
-
closeButton.hidden =
|
|
192
|
+
closeButton.hidden = true;
|
|
184
193
|
closeButton.style.opacity = '0';
|
|
185
194
|
root.append(closeButton);
|
|
186
195
|
|
|
187
196
|
const counter = document.createElement('div');
|
|
188
197
|
counter.className = 'native-image-preview-counter';
|
|
189
|
-
counter.hidden = this.options?.counter
|
|
198
|
+
counter.hidden = this.options?.counter !== true || this.items.length <= 1;
|
|
190
199
|
counter.style.opacity = '0';
|
|
191
200
|
root.append(counter);
|
|
192
201
|
|
|
@@ -196,6 +205,7 @@ export class NativeImagePreviewWebViewer implements NativeImagePreviewWebControl
|
|
|
196
205
|
this.track = track;
|
|
197
206
|
this.closeButton = closeButton;
|
|
198
207
|
this.counter = counter;
|
|
208
|
+
this.syncCloseButtonVisibility();
|
|
199
209
|
|
|
200
210
|
root.addEventListener('pointerdown', this.handlePointerDown);
|
|
201
211
|
root.addEventListener('pointermove', this.handlePointerMove);
|
|
@@ -342,26 +352,38 @@ export class NativeImagePreviewWebViewer implements NativeImagePreviewWebControl
|
|
|
342
352
|
}
|
|
343
353
|
|
|
344
354
|
private showControls(): void {
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
}
|
|
355
|
+
this.controlsVisible = true;
|
|
356
|
+
this.syncCloseButtonVisibility();
|
|
348
357
|
if (this.counter && !this.counter.hidden) {
|
|
349
358
|
this.counter.style.opacity = '1';
|
|
350
359
|
}
|
|
351
360
|
}
|
|
352
361
|
|
|
353
362
|
private hideControls(): void {
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
}
|
|
363
|
+
this.controlsVisible = false;
|
|
364
|
+
this.syncCloseButtonVisibility();
|
|
357
365
|
if (this.counter) {
|
|
358
366
|
this.counter.style.opacity = '0';
|
|
359
367
|
}
|
|
360
368
|
}
|
|
361
369
|
|
|
370
|
+
private syncCloseButtonVisibility(): void {
|
|
371
|
+
if (!this.closeButton) {
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
const configuredVisibility = this.options?.closeButton;
|
|
375
|
+
const shouldShow = configuredVisibility
|
|
376
|
+
?? this.items[this.index]?.type === 'video';
|
|
377
|
+
this.closeButton.hidden = !shouldShow;
|
|
378
|
+
this.closeButton.style.opacity = shouldShow && this.controlsVisible ? '1' : '0';
|
|
379
|
+
}
|
|
380
|
+
|
|
362
381
|
private finishClose(reason: NativeImagePreviewWebCloseReason): void {
|
|
363
382
|
const item = this.items[this.index] ?? null;
|
|
364
383
|
const index = this.index;
|
|
384
|
+
this.cancelPendingTapClose(true);
|
|
385
|
+
this.tapEligible = false;
|
|
386
|
+
this.controlsVisible = false;
|
|
365
387
|
this.restoreSourceElement();
|
|
366
388
|
this.unlockDocumentScroll();
|
|
367
389
|
this.unmount();
|
|
@@ -377,6 +399,7 @@ export class NativeImagePreviewWebViewer implements NativeImagePreviewWebControl
|
|
|
377
399
|
}
|
|
378
400
|
|
|
379
401
|
private unmount(): void {
|
|
402
|
+
this.cancelPendingTapClose(true);
|
|
380
403
|
const root = this.root;
|
|
381
404
|
const closeButton = this.closeButton;
|
|
382
405
|
if (!root) {
|
|
@@ -447,7 +470,7 @@ export class NativeImagePreviewWebViewer implements NativeImagePreviewWebControl
|
|
|
447
470
|
}
|
|
448
471
|
await waitForElementImage(element);
|
|
449
472
|
const rect = rectFromElement(element);
|
|
450
|
-
if (!isUsableRect(rect)) {
|
|
473
|
+
if (!isUsableRect(rect) || !intersectRects(rect, this.viewportRect())) {
|
|
451
474
|
return null;
|
|
452
475
|
}
|
|
453
476
|
const size = await this.resolveSharedMediaSize(item);
|
|
@@ -527,11 +550,13 @@ export class NativeImagePreviewWebViewer implements NativeImagePreviewWebControl
|
|
|
527
550
|
if (this.closing || !this.root) {
|
|
528
551
|
return;
|
|
529
552
|
}
|
|
553
|
+
this.cancelPendingTapClose(false);
|
|
530
554
|
const target = event.target as HTMLElement | null;
|
|
531
555
|
if (this.shouldIgnorePointerStart(target, event)) {
|
|
532
556
|
return;
|
|
533
557
|
}
|
|
534
558
|
|
|
559
|
+
this.tapEligible = this.pointers.size === 0;
|
|
535
560
|
this.root.setPointerCapture(event.pointerId);
|
|
536
561
|
this.pointers.set(event.pointerId, { id: event.pointerId, x: event.clientX, y: event.clientY });
|
|
537
562
|
this.downX = event.clientX;
|
|
@@ -542,6 +567,10 @@ export class NativeImagePreviewWebViewer implements NativeImagePreviewWebControl
|
|
|
542
567
|
this.dragX = 0;
|
|
543
568
|
this.dragY = 0;
|
|
544
569
|
this.mode = this.pointers.size >= 2 ? 'pinch' : 'none';
|
|
570
|
+
if (this.mode === 'pinch') {
|
|
571
|
+
this.tapEligible = false;
|
|
572
|
+
this.cancelPendingTapClose(true);
|
|
573
|
+
}
|
|
545
574
|
this.preparePinchIfNeeded();
|
|
546
575
|
};
|
|
547
576
|
|
|
@@ -582,6 +611,7 @@ export class NativeImagePreviewWebViewer implements NativeImagePreviewWebControl
|
|
|
582
611
|
this.pointers.set(event.pointerId, { id: event.pointerId, x: event.clientX, y: event.clientY });
|
|
583
612
|
|
|
584
613
|
if (this.pointers.size >= 2) {
|
|
614
|
+
this.tapEligible = false;
|
|
585
615
|
this.mode = 'pinch';
|
|
586
616
|
this.applyPinch();
|
|
587
617
|
return;
|
|
@@ -599,6 +629,8 @@ export class NativeImagePreviewWebViewer implements NativeImagePreviewWebControl
|
|
|
599
629
|
if (Math.hypot(dx, dy) < MODE_LOCK_DISTANCE) {
|
|
600
630
|
return;
|
|
601
631
|
}
|
|
632
|
+
this.tapEligible = false;
|
|
633
|
+
this.cancelPendingTapClose(true);
|
|
602
634
|
if (state.scale > 1.02) {
|
|
603
635
|
this.mode = 'pan';
|
|
604
636
|
} else if (Math.abs(dy) > Math.abs(dx) * 1.15) {
|
|
@@ -631,6 +663,10 @@ export class NativeImagePreviewWebViewer implements NativeImagePreviewWebControl
|
|
|
631
663
|
if (!this.pointers.has(event.pointerId)) {
|
|
632
664
|
return;
|
|
633
665
|
}
|
|
666
|
+
if (event.type === 'pointercancel') {
|
|
667
|
+
this.cancelActiveGesture();
|
|
668
|
+
return;
|
|
669
|
+
}
|
|
634
670
|
const finalDx = event.clientX - this.downX;
|
|
635
671
|
const finalDy = event.clientY - this.downY;
|
|
636
672
|
this.pointers.delete(event.pointerId);
|
|
@@ -638,6 +674,7 @@ export class NativeImagePreviewWebViewer implements NativeImagePreviewWebControl
|
|
|
638
674
|
this.root.releasePointerCapture(event.pointerId);
|
|
639
675
|
}
|
|
640
676
|
if (this.pointers.size >= 2) {
|
|
677
|
+
this.tapEligible = false;
|
|
641
678
|
this.preparePinchIfNeeded();
|
|
642
679
|
return;
|
|
643
680
|
}
|
|
@@ -670,10 +707,11 @@ export class NativeImagePreviewWebViewer implements NativeImagePreviewWebControl
|
|
|
670
707
|
} else if (this.mode === 'swipe') {
|
|
671
708
|
this.dragX = finalDx;
|
|
672
709
|
this.finishSwipe(velocityX);
|
|
673
|
-
} else if (this.mode === 'none') {
|
|
710
|
+
} else if (this.mode === 'none' && this.tapEligible) {
|
|
674
711
|
this.handleTap(event);
|
|
675
712
|
}
|
|
676
713
|
|
|
714
|
+
this.tapEligible = false;
|
|
677
715
|
this.mode = 'none';
|
|
678
716
|
this.dragX = 0;
|
|
679
717
|
this.dragY = 0;
|
|
@@ -684,6 +722,8 @@ export class NativeImagePreviewWebViewer implements NativeImagePreviewWebControl
|
|
|
684
722
|
return;
|
|
685
723
|
}
|
|
686
724
|
event.preventDefault();
|
|
725
|
+
this.tapEligible = false;
|
|
726
|
+
this.cancelPendingTapClose(true);
|
|
687
727
|
const state = this.activeState();
|
|
688
728
|
const nextScale = clamp(state.scale * (event.deltaY > 0 ? 0.92 : 1.08), 1, MAX_SCALE);
|
|
689
729
|
state.scale = nextScale;
|
|
@@ -751,8 +791,15 @@ export class NativeImagePreviewWebViewer implements NativeImagePreviewWebControl
|
|
|
751
791
|
|
|
752
792
|
private handleTap(event: PointerEvent): void {
|
|
753
793
|
const state = this.activeState();
|
|
794
|
+
const item = this.items[this.index];
|
|
795
|
+
if (item?.type !== 'image') {
|
|
796
|
+
state.lastTapAt = 0;
|
|
797
|
+
return;
|
|
798
|
+
}
|
|
799
|
+
|
|
754
800
|
const now = performance.now();
|
|
755
|
-
if (now - state.lastTapAt <
|
|
801
|
+
if (state.lastTapAt > 0 && now - state.lastTapAt < DOUBLE_TAP_TIMEOUT) {
|
|
802
|
+
this.cancelPendingTapClose(false);
|
|
756
803
|
state.scale = state.scale > 1.02 ? 1 : DOUBLE_TAP_SCALE;
|
|
757
804
|
state.translateX = 0;
|
|
758
805
|
state.translateY = 0;
|
|
@@ -762,6 +809,29 @@ export class NativeImagePreviewWebViewer implements NativeImagePreviewWebControl
|
|
|
762
809
|
return;
|
|
763
810
|
}
|
|
764
811
|
state.lastTapAt = now;
|
|
812
|
+
const tapIndex = this.index;
|
|
813
|
+
this.pendingTapCloseTimer = window.setTimeout(() => {
|
|
814
|
+
this.pendingTapCloseTimer = null;
|
|
815
|
+
const tapState = this.slideStates[tapIndex];
|
|
816
|
+
if (tapState) {
|
|
817
|
+
tapState.lastTapAt = 0;
|
|
818
|
+
}
|
|
819
|
+
if (this.openState && !this.closing && this.index === tapIndex) {
|
|
820
|
+
void this.close('backdrop');
|
|
821
|
+
}
|
|
822
|
+
}, DOUBLE_TAP_TIMEOUT);
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
private cancelPendingTapClose(resetTapState: boolean): void {
|
|
826
|
+
if (this.pendingTapCloseTimer !== null) {
|
|
827
|
+
window.clearTimeout(this.pendingTapCloseTimer);
|
|
828
|
+
this.pendingTapCloseTimer = null;
|
|
829
|
+
}
|
|
830
|
+
if (resetTapState) {
|
|
831
|
+
this.slideStates.forEach((state) => {
|
|
832
|
+
state.lastTapAt = 0;
|
|
833
|
+
});
|
|
834
|
+
}
|
|
765
835
|
}
|
|
766
836
|
|
|
767
837
|
private preparePinchIfNeeded(): void {
|
|
@@ -815,6 +885,8 @@ export class NativeImagePreviewWebViewer implements NativeImagePreviewWebControl
|
|
|
815
885
|
}
|
|
816
886
|
|
|
817
887
|
private goTo(nextIndex: number, reason: 'api' | 'swipe'): void {
|
|
888
|
+
this.cancelPendingTapClose(true);
|
|
889
|
+
this.tapEligible = false;
|
|
818
890
|
const clamped = clamp(nextIndex, 0, this.items.length - 1);
|
|
819
891
|
const previousIndex = this.index;
|
|
820
892
|
this.index = clamped;
|
|
@@ -822,6 +894,7 @@ export class NativeImagePreviewWebViewer implements NativeImagePreviewWebControl
|
|
|
822
894
|
this.resetSlideState(clamped);
|
|
823
895
|
this.updateTrack(true);
|
|
824
896
|
this.updateCounter();
|
|
897
|
+
this.syncCloseButtonVisibility();
|
|
825
898
|
this.pauseInactiveVideos(clamped);
|
|
826
899
|
if (previousIndex !== clamped) {
|
|
827
900
|
this.syncHiddenSourceElement(clamped);
|
|
@@ -865,6 +938,8 @@ export class NativeImagePreviewWebViewer implements NativeImagePreviewWebControl
|
|
|
865
938
|
}
|
|
866
939
|
|
|
867
940
|
private cancelActiveGesture(): void {
|
|
941
|
+
this.cancelPendingTapClose(true);
|
|
942
|
+
this.tapEligible = false;
|
|
868
943
|
if (!this.pointers.size && this.mode === 'none' && !this.dragX && !this.dragY) {
|
|
869
944
|
return;
|
|
870
945
|
}
|
|
@@ -37,6 +37,9 @@ const CARD_HORIZONTAL_PADDING = wp(24);
|
|
|
37
37
|
const CANVAS_BORDER_WIDTH = wp(1);
|
|
38
38
|
const CAPTCHA_LAYER_Z_INDEX = 4000;
|
|
39
39
|
const SLIDER_THUMB_SIZE = wp(44);
|
|
40
|
+
const WEB_SLIDER_EDGE_GESTURE_INSET = Platform.OS === 'web' ? wp(16) : 0;
|
|
41
|
+
const MIUI_DRAG_BACK_QUERY_KEY = 'native_drag_back';
|
|
42
|
+
const SLIDER_CANCEL_DURATION = 160;
|
|
40
43
|
const CAPTCHA_ENTER_DURATION = 280;
|
|
41
44
|
const CAPTCHA_EXIT_DURATION = 220;
|
|
42
45
|
const CAPTCHA_CARD_OFFSET_Y = wp(18);
|
|
@@ -152,6 +155,142 @@ function getSafePositiveNumber(value: number | undefined, fallback: number) {
|
|
|
152
155
|
return value;
|
|
153
156
|
}
|
|
154
157
|
|
|
158
|
+
type WebOverscrollTarget = {
|
|
159
|
+
style: {
|
|
160
|
+
overscrollBehaviorX: string;
|
|
161
|
+
};
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
type WebDocument = {
|
|
165
|
+
body?: WebOverscrollTarget;
|
|
166
|
+
documentElement?: WebOverscrollTarget;
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
type WebEnvironment = {
|
|
170
|
+
history?: {
|
|
171
|
+
replaceState: (data: unknown, unused: string, url?: string | null) => void;
|
|
172
|
+
state: unknown;
|
|
173
|
+
};
|
|
174
|
+
location?: {
|
|
175
|
+
href: string;
|
|
176
|
+
};
|
|
177
|
+
navigator?: {
|
|
178
|
+
userAgent?: string;
|
|
179
|
+
};
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
type WebOverscrollSnapshot = {
|
|
183
|
+
previousValue: string;
|
|
184
|
+
target: WebOverscrollTarget;
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
type WebMiuiDragBackSnapshot = {
|
|
188
|
+
guardedHref: string;
|
|
189
|
+
originalHref: string;
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
let webHorizontalOverscrollLockCount = 0;
|
|
193
|
+
let webHorizontalOverscrollSnapshots: WebOverscrollSnapshot[] = [];
|
|
194
|
+
let webMiuiDragBackLockCount = 0;
|
|
195
|
+
let webMiuiDragBackSnapshot: WebMiuiDragBackSnapshot | undefined;
|
|
196
|
+
|
|
197
|
+
function acquireWebHorizontalOverscrollLock() {
|
|
198
|
+
if (Platform.OS !== 'web') return undefined;
|
|
199
|
+
|
|
200
|
+
const webDocument = (globalThis as { document?: WebDocument }).document;
|
|
201
|
+
const targets = [webDocument?.documentElement, webDocument?.body].filter(
|
|
202
|
+
(target): target is WebOverscrollTarget => Boolean(target)
|
|
203
|
+
);
|
|
204
|
+
if (targets.length === 0) return undefined;
|
|
205
|
+
|
|
206
|
+
if (webHorizontalOverscrollLockCount === 0) {
|
|
207
|
+
webHorizontalOverscrollSnapshots = targets.map((target) => ({
|
|
208
|
+
previousValue: target.style.overscrollBehaviorX,
|
|
209
|
+
target,
|
|
210
|
+
}));
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
webHorizontalOverscrollLockCount += 1;
|
|
214
|
+
targets.forEach((target) => {
|
|
215
|
+
target.style.overscrollBehaviorX = 'none';
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
let released = false;
|
|
219
|
+
return () => {
|
|
220
|
+
if (released) return;
|
|
221
|
+
released = true;
|
|
222
|
+
webHorizontalOverscrollLockCount = Math.max(webHorizontalOverscrollLockCount - 1, 0);
|
|
223
|
+
if (webHorizontalOverscrollLockCount > 0) return;
|
|
224
|
+
|
|
225
|
+
webHorizontalOverscrollSnapshots.forEach(({ previousValue, target }) => {
|
|
226
|
+
if (target.style.overscrollBehaviorX === 'none') {
|
|
227
|
+
target.style.overscrollBehaviorX = previousValue;
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
webHorizontalOverscrollSnapshots = [];
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function acquireWebMiuiDragBackLock() {
|
|
235
|
+
if (Platform.OS !== 'web') return undefined;
|
|
236
|
+
|
|
237
|
+
const webEnvironment = globalThis as typeof globalThis & WebEnvironment;
|
|
238
|
+
const { history: webHistory, location: webLocation, navigator: webNavigator } = webEnvironment;
|
|
239
|
+
if (
|
|
240
|
+
!webHistory ||
|
|
241
|
+
!webLocation ||
|
|
242
|
+
!/MiuiBrowser/i.test(webNavigator?.userAgent ?? '')
|
|
243
|
+
) {
|
|
244
|
+
return undefined;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (webMiuiDragBackLockCount === 0) {
|
|
248
|
+
try {
|
|
249
|
+
const guardedUrl = new URL(webLocation.href);
|
|
250
|
+
if (guardedUrl.searchParams.get(MIUI_DRAG_BACK_QUERY_KEY) !== '0') {
|
|
251
|
+
const originalHref = webLocation.href;
|
|
252
|
+
guardedUrl.searchParams.set(MIUI_DRAG_BACK_QUERY_KEY, '0');
|
|
253
|
+
const guardedHref = guardedUrl.href;
|
|
254
|
+
webHistory.replaceState(webHistory.state, '', guardedHref);
|
|
255
|
+
webMiuiDragBackSnapshot = { guardedHref, originalHref };
|
|
256
|
+
}
|
|
257
|
+
} catch {
|
|
258
|
+
// Ignore restricted history/URL environments and retain the standard Web gesture guards.
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
webMiuiDragBackLockCount += 1;
|
|
263
|
+
let released = false;
|
|
264
|
+
|
|
265
|
+
return () => {
|
|
266
|
+
if (released) return;
|
|
267
|
+
released = true;
|
|
268
|
+
webMiuiDragBackLockCount = Math.max(webMiuiDragBackLockCount - 1, 0);
|
|
269
|
+
if (webMiuiDragBackLockCount > 0) return;
|
|
270
|
+
|
|
271
|
+
const snapshot = webMiuiDragBackSnapshot;
|
|
272
|
+
webMiuiDragBackSnapshot = undefined;
|
|
273
|
+
if (!snapshot || webLocation.href !== snapshot.guardedHref) return;
|
|
274
|
+
|
|
275
|
+
try {
|
|
276
|
+
webHistory.replaceState(webHistory.state, '', snapshot.originalHref);
|
|
277
|
+
} catch {
|
|
278
|
+
// The browser may reject history writes after a route or document lifecycle change.
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function resolveWebSliderInteractionStyle(canSlide: boolean): StyleProp<ViewStyle> {
|
|
284
|
+
if (Platform.OS !== 'web') return undefined;
|
|
285
|
+
|
|
286
|
+
return {
|
|
287
|
+
cursor: canSlide ? 'grab' : 'default',
|
|
288
|
+
overscrollBehaviorX: 'none',
|
|
289
|
+
touchAction: 'none',
|
|
290
|
+
userSelect: 'none',
|
|
291
|
+
} as unknown as ViewStyle;
|
|
292
|
+
}
|
|
293
|
+
|
|
155
294
|
const styles = StyleSheet.create({
|
|
156
295
|
modalRoot: {
|
|
157
296
|
...StyleSheet.absoluteFillObject,
|
|
@@ -255,7 +394,7 @@ const styles = StyleSheet.create({
|
|
|
255
394
|
},
|
|
256
395
|
sliderThumb: {
|
|
257
396
|
position: 'absolute',
|
|
258
|
-
left:
|
|
397
|
+
left: WEB_SLIDER_EDGE_GESTURE_INSET,
|
|
259
398
|
width: SLIDER_THUMB_SIZE,
|
|
260
399
|
height: SLIDER_THUMB_SIZE,
|
|
261
400
|
borderRadius: SLIDER_THUMB_SIZE / 2,
|
|
@@ -352,7 +491,10 @@ export function SliderCaptcha<TChallenge extends SliderCaptchaChallenge = Slider
|
|
|
352
491
|
const blockDisplayHeight = blockHeight * scale;
|
|
353
492
|
const blockTop = Math.max(0, (challenge?.blockY ?? 0) * scale);
|
|
354
493
|
const maxBlockOffset = Math.max(canvasContentWidth - blockDisplayWidth, 0);
|
|
355
|
-
const maxThumbOffset = Math.max(
|
|
494
|
+
const maxThumbOffset = Math.max(
|
|
495
|
+
canvasOuterWidth - SLIDER_THUMB_SIZE - WEB_SLIDER_EDGE_GESTURE_INSET * 2,
|
|
496
|
+
0
|
|
497
|
+
);
|
|
356
498
|
const blockTranslateRatio = maxThumbOffset > 0 ? maxBlockOffset / maxThumbOffset : 0;
|
|
357
499
|
const isBusy = status === 'loading' || status === 'verifying';
|
|
358
500
|
const canSlide = visible && Boolean(challenge) && !isBusy;
|
|
@@ -392,6 +534,10 @@ export function SliderCaptcha<TChallenge extends SliderCaptchaChallenge = Slider
|
|
|
392
534
|
}),
|
|
393
535
|
[theme.colors.onSurface]
|
|
394
536
|
);
|
|
537
|
+
const webSliderInteractionStyle = React.useMemo(
|
|
538
|
+
() => resolveWebSliderInteractionStyle(canSlide),
|
|
539
|
+
[canSlide]
|
|
540
|
+
);
|
|
395
541
|
|
|
396
542
|
const requestChallenge = React.useCallback(
|
|
397
543
|
async (reason: SliderCaptchaLoadReason) => {
|
|
@@ -603,6 +749,18 @@ export function SliderCaptcha<TChallenge extends SliderCaptchaChallenge = Slider
|
|
|
603
749
|
return () => subscription.remove();
|
|
604
750
|
}, [onClose, visible]);
|
|
605
751
|
|
|
752
|
+
React.useEffect(() => {
|
|
753
|
+
if (!visible || Platform.OS !== 'web') return;
|
|
754
|
+
|
|
755
|
+
const releaseHorizontalOverscrollLock = acquireWebHorizontalOverscrollLock();
|
|
756
|
+
const releaseMiuiDragBackLock = acquireWebMiuiDragBackLock();
|
|
757
|
+
|
|
758
|
+
return () => {
|
|
759
|
+
releaseMiuiDragBackLock?.();
|
|
760
|
+
releaseHorizontalOverscrollLock?.();
|
|
761
|
+
};
|
|
762
|
+
}, [visible]);
|
|
763
|
+
|
|
606
764
|
const handleCanvasLayout = React.useCallback((event: LayoutChangeEvent) => {
|
|
607
765
|
const nextWidth = event.nativeEvent.layout.width;
|
|
608
766
|
if (!Number.isFinite(nextWidth) || nextWidth <= 0) return;
|
|
@@ -654,6 +812,15 @@ export function SliderCaptcha<TChallenge extends SliderCaptchaChallenge = Slider
|
|
|
654
812
|
transform: [{ translateX: thumbX.value * blockTranslateRatio }],
|
|
655
813
|
}));
|
|
656
814
|
|
|
815
|
+
const cancelCurrentDrag = React.useCallback(() => {
|
|
816
|
+
const startPosition = clamp(thumbStartRef.current, 0, maxThumbOffset);
|
|
817
|
+
thumbXRef.current = startPosition;
|
|
818
|
+
thumbX.value = withTiming(startPosition, {
|
|
819
|
+
duration: SLIDER_CANCEL_DURATION,
|
|
820
|
+
easing: Easing.out(Easing.cubic),
|
|
821
|
+
});
|
|
822
|
+
}, [maxThumbOffset, thumbX]);
|
|
823
|
+
|
|
657
824
|
const panResponder = React.useMemo(
|
|
658
825
|
() =>
|
|
659
826
|
PanResponder.create({
|
|
@@ -672,8 +839,11 @@ export function SliderCaptcha<TChallenge extends SliderCaptchaChallenge = Slider
|
|
|
672
839
|
onPanResponderRelease: () => {
|
|
673
840
|
void verifyCurrentChallenge();
|
|
674
841
|
},
|
|
842
|
+
onPanResponderTerminate: cancelCurrentDrag,
|
|
843
|
+
onPanResponderTerminationRequest: () => false,
|
|
844
|
+
onShouldBlockNativeResponder: () => true,
|
|
675
845
|
}),
|
|
676
|
-
[canSlide, maxThumbOffset, thumbX, verifyCurrentChallenge]
|
|
846
|
+
[canSlide, cancelCurrentDrag, maxThumbOffset, thumbX, verifyCurrentChallenge]
|
|
677
847
|
);
|
|
678
848
|
|
|
679
849
|
if (!mounted) return null;
|
|
@@ -809,6 +979,7 @@ export function SliderCaptcha<TChallenge extends SliderCaptchaChallenge = Slider
|
|
|
809
979
|
style={[
|
|
810
980
|
styles.sliderTrack,
|
|
811
981
|
{ backgroundColor: theme.colors.secondary, borderColor: theme.colors.border },
|
|
982
|
+
webSliderInteractionStyle,
|
|
812
983
|
]}
|
|
813
984
|
{...panResponder.panHandlers}
|
|
814
985
|
>
|