zkit-ui 2.0.22 → 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.
@@ -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);
@@ -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.find(anchorKey);
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":"AAEA,MAAM,MAAM,0BAA0B,GAAG,MAAM,GAAG,OAAO,CAAC;AAE1D,MAAM,MAAM,8BAA8B,GAAG,OAAO,GAAG,OAAO,CAAC;AAE/D,MAAM,MAAM,8BAA8B,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;AAE1E,MAAM,MAAM,qCAAqC,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEzE,MAAM,MAAM,gCAAgC,GAAG,KAAK,GAAG,UAAU,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE7G,MAAM,MAAM,iCAAiC,GAAG,KAAK,GAAG,OAAO,CAAC;AAEhE,MAAM,MAAM,yBAAyB,GAAG;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,8BAA8B,GAAG;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,8BAA8B,GAAG;IAC3C,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,8BAA8B,CAAC;IACtC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,iCAAiC,GAAG;IAC9C,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,8BAA8B,CAAC;IACrC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,8BAA8B,CAAC;CACrC,CAAC;AAEF,MAAM,MAAM,+BAA+B,GAAG;IAC5C,MAAM,EAAE,iCAAiC,CAAC;IAC1C,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,iCAAiC,CAAC;CACzC,CAAC;AAEF,MAAM,MAAM,8BAA8B,GAAG;IAC3C,MAAM,EAAE,gCAAgC,CAAC;IACzC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,iCAAiC,GAAG,IAAI,CAAC;CAChD,CAAC;AAEF,MAAM,MAAM,gCAAgC,GAAG;IAC7C,KAAK,EAAE,SAAS,8BAA8B,EAAE,CAAC;IACjD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IACnC,cAAc,CAAC,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,CAAC;IAC7D,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,iCAAiC,KAAK,WAAW,GAAG,IAAI,GAAG,SAAS,CAAC;IAC9G,UAAU,CAAC,EAAE,yBAAyB,GAAG,eAAe,GAAG,IAAI,CAAC;IAChE,eAAe,CAAC,EAAE,8BAA8B,GAAG,IAAI,CAAC;IACxD,SAAS,CAAC,EAAE,8BAA8B,CAAC;IAC3C,eAAe,CAAC,EAAE,8BAA8B,CAAC;IACjD,gBAAgB,CAAC,EAAE,qCAAqC,CAAC;IACzD,KAAK,CAAC,EAAE,0BAA0B,CAAC;IACnC,4DAA4D;IAC5D,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,wEAAwE;IACxE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,+BAA+B,KAAK,IAAI,CAAC;IAC1E,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,8BAA8B,KAAK,IAAI,CAAC;CAC1D,CAAC;AAEF,MAAM,MAAM,+BAA+B,GAAG;IAC5C,IAAI,EAAE,CAAC,OAAO,EAAE,gCAAgC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACnE,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE,gCAAgC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpE,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,MAAM,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,OAAO,CAAC;CACvB,CAAC"}
@@ -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;AAuCjB,qBAAa,2BAA4B,YAAW,+BAA+B;IACjF,OAAO,CAAC,IAAI,CAA4B;IACxC,OAAO,CAAC,QAAQ,CAA4B;IAC5C,OAAO,CAAC,QAAQ,CAA4B;IAC5C,OAAO,CAAC,KAAK,CAA4B;IACzC,OAAO,CAAC,WAAW,CAAkC;IACrD,OAAO,CAAC,OAAO,CAA4B;IAC3C,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,WAAW,CAAoB;IACvC,OAAO,CAAC,KAAK,CAA2C;IACxD,OAAO,CAAC,OAAO,CAAiD;IAChE,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,gBAAgB,CAAmD;IAC3E,OAAO,CAAC,aAAa,CAA4B;IACjD,OAAO,CAAC,wBAAwB,CAAM;IACtC,OAAO,CAAC,QAAQ,CAA4B;IAC5C,OAAO,CAAC,IAAI,CAAuB;IACnC,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,kBAAkB,CAAK;IAC/B,OAAO,CAAC,eAAe,CAAK;IAC5B,OAAO,CAAC,oBAAoB,CAAK;IACjC,OAAO,CAAC,oBAAoB,CAAK;IACjC,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,oBAAoB,CAAM;IAClC,OAAO,CAAC,oBAAoB,CAAM;IAClC,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,cAAc,CAAK;IAErB,IAAI,CAAC,OAAO,EAAE,gCAAgC,GAAG,OAAO,CAAC,IAAI,CAAC;IA+B9D,KAAK,CAAC,MAAM,GAAE,gCAAwC,GAAG,OAAO,CAAC,IAAI,CAAC;IAS5E,OAAO,IAAI,IAAI;IASf,QAAQ,IAAI,MAAM;IAIlB,MAAM,IAAI,OAAO;IAIjB,OAAO,CAAC,KAAK;IAuEb,OAAO,CAAC,kBAAkB;YA6BZ,qBAAqB;YAoCrB,sBAAsB;IAwCpC,OAAO,CAAC,gCAAgC;IAWxC,OAAO,CAAC,WAAW;IAUnB,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,WAAW;IAiBnB,OAAO,CAAC,OAAO;IA4Bf,OAAO,CAAC,mBAAmB;IAM3B,OAAO,CAAC,kBAAkB;IAQ1B,OAAO,CAAC,YAAY;YASN,qBAAqB;YAarB,qBAAqB;YAcrB,qBAAqB;YAKrB,2BAA2B;YAY3B,sBAAsB;IAIpC,OAAO,CAAC,sBAAsB;IAe9B,OAAO,CAAC,oBAAoB;IAU5B,OAAO,CAAC,iBAAiB;IAQzB,OAAO,CAAC,oBAAoB;IAS5B,OAAO,CAAC,uBAAuB;IAM/B,OAAO,CAAC,iBAAiB,CAoBvB;IAEF,OAAO,CAAC,wBAAwB;IAehC,OAAO,CAAC,wBAAwB;IAchC,OAAO,CAAC,iBAAiB,CAmDvB;IAEF,OAAO,CAAC,eAAe,CAkDrB;IAEF,OAAO,CAAC,WAAW,CAcjB;IAEF,OAAO,CAAC,eAAe,CAIrB;IAEF,OAAO,CAAC,gBAAgB,CAEtB;IAEF,OAAO,CAAC,aAAa,CAanB;IAEF,OAAO,CAAC,YAAY,CAQlB;IAEF,OAAO,CAAC,gBAAgB,CAEtB;IAEF,OAAO,CAAC,sBAAsB,CAI5B;IAEF,OAAO,CAAC,wBAAwB,CAO9B;IAEF,OAAO,CAAC,SAAS;IAejB,OAAO,CAAC,oBAAoB;IAc5B,OAAO,CAAC,UAAU;IAoBlB,OAAO,CAAC,WAAW;IAgBnB,OAAO,CAAC,IAAI;IAiBZ,OAAO,CAAC,gBAAgB;IAgBxB,OAAO,CAAC,gBAAgB;IAiBxB,OAAO,CAAC,mBAAmB;IA0B3B,OAAO,CAAC,sBAAsB;IAY9B,OAAO,CAAC,WAAW;IASnB,OAAO,CAAC,yBAAyB;IAUjC,OAAO,CAAC,gBAAgB;IAoBxB,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,eAAe;IASvB,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,mBAAmB;YAQb,mBAAmB;IAiBjC,OAAO,CAAC,kBAAkB;IAO1B,OAAO,CAAC,oBAAoB;IAK5B,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,KAAK;CAGd;AAED,wBAAgB,2BAA2B,IAAI,+BAA+B,CAE7E;AAMD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,WAAW,GAAG,yBAAyB,CAErF"}
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, _d;
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 = ((_c = this.options) === null || _c === void 0 ? void 0 : _c.closeButton) === false;
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 = ((_d = this.options) === null || _d === void 0 ? void 0 : _d.counter) === false || this.items.length <= 1;
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
- if (this.closeButton && !this.closeButton.hidden) {
460
- this.closeButton.style.opacity = '1';
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
- if (this.closeButton) {
468
- this.closeButton.style.opacity = '0';
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 < 280) {
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":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/SliderCaptcha/index.tsx"],"names":[],"mappings":"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"}
@@ -56,6 +56,7 @@ 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
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';
59
60
  const SLIDER_CANCEL_DURATION = 160;
60
61
  const CAPTCHA_ENTER_DURATION = 280;
61
62
  const CAPTCHA_EXIT_DURATION = 220;
@@ -93,6 +94,8 @@ function getSafePositiveNumber(value, fallback) {
93
94
  }
94
95
  let webHorizontalOverscrollLockCount = 0;
95
96
  let webHorizontalOverscrollSnapshots = [];
97
+ let webMiuiDragBackLockCount = 0;
98
+ let webMiuiDragBackSnapshot;
96
99
  function acquireWebHorizontalOverscrollLock() {
97
100
  if (react_native_1.Platform.OS !== 'web')
98
101
  return undefined;
@@ -126,6 +129,53 @@ function acquireWebHorizontalOverscrollLock() {
126
129
  webHorizontalOverscrollSnapshots = [];
127
130
  };
128
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
+ }
129
179
  function resolveWebSliderInteractionStyle(canSlide) {
130
180
  if (react_native_1.Platform.OS !== 'web')
131
181
  return undefined;
@@ -527,7 +577,12 @@ function SliderCaptcha({ visible, onClose, initialChallenge = null, loadChalleng
527
577
  React.useEffect(() => {
528
578
  if (!visible || react_native_1.Platform.OS !== 'web')
529
579
  return;
530
- return acquireWebHorizontalOverscrollLock();
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
+ };
531
586
  }, [visible]);
532
587
  const handleCanvasLayout = React.useCallback((event) => {
533
588
  const nextWidth = event.nativeEvent.layout.width;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zkit-ui",
3
- "version": "2.0.22",
3
+ "version": "2.0.23",
4
4
  "private": false,
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -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 = this.options?.closeButton === false;
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 === false || this.items.length <= 1;
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
- if (this.closeButton && !this.closeButton.hidden) {
346
- this.closeButton.style.opacity = '1';
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
- if (this.closeButton) {
355
- this.closeButton.style.opacity = '0';
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 < 280) {
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
  }
@@ -8,7 +8,7 @@
8
8
  - 弹层展示
9
9
  - 图片缩放与坐标换算
10
10
  - 滑块拖拽与释放触发校验
11
- - Web 端浏览器滚动、侧滑历史返回与 Android 边缘返回冲突规避
11
+ - Web 端浏览器滚动、侧滑历史返回与 Android 边缘返回冲突规避(含小米浏览器原生横滑返回)
12
12
  - `loading / verifying / success / error` 状态反馈
13
13
  - 校验失败后的自动重载
14
14
  - 业务方负责:
@@ -38,6 +38,7 @@ const CANVAS_BORDER_WIDTH = wp(1);
38
38
  const CAPTCHA_LAYER_Z_INDEX = 4000;
39
39
  const SLIDER_THUMB_SIZE = wp(44);
40
40
  const WEB_SLIDER_EDGE_GESTURE_INSET = Platform.OS === 'web' ? wp(16) : 0;
41
+ const MIUI_DRAG_BACK_QUERY_KEY = 'native_drag_back';
41
42
  const SLIDER_CANCEL_DURATION = 160;
42
43
  const CAPTCHA_ENTER_DURATION = 280;
43
44
  const CAPTCHA_EXIT_DURATION = 220;
@@ -165,13 +166,33 @@ type WebDocument = {
165
166
  documentElement?: WebOverscrollTarget;
166
167
  };
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
+
168
182
  type WebOverscrollSnapshot = {
169
183
  previousValue: string;
170
184
  target: WebOverscrollTarget;
171
185
  };
172
186
 
187
+ type WebMiuiDragBackSnapshot = {
188
+ guardedHref: string;
189
+ originalHref: string;
190
+ };
191
+
173
192
  let webHorizontalOverscrollLockCount = 0;
174
193
  let webHorizontalOverscrollSnapshots: WebOverscrollSnapshot[] = [];
194
+ let webMiuiDragBackLockCount = 0;
195
+ let webMiuiDragBackSnapshot: WebMiuiDragBackSnapshot | undefined;
175
196
 
176
197
  function acquireWebHorizontalOverscrollLock() {
177
198
  if (Platform.OS !== 'web') return undefined;
@@ -210,6 +231,55 @@ function acquireWebHorizontalOverscrollLock() {
210
231
  };
211
232
  }
212
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
+
213
283
  function resolveWebSliderInteractionStyle(canSlide: boolean): StyleProp<ViewStyle> {
214
284
  if (Platform.OS !== 'web') return undefined;
215
285
 
@@ -681,7 +751,14 @@ export function SliderCaptcha<TChallenge extends SliderCaptchaChallenge = Slider
681
751
 
682
752
  React.useEffect(() => {
683
753
  if (!visible || Platform.OS !== 'web') return;
684
- return acquireWebHorizontalOverscrollLock();
754
+
755
+ const releaseHorizontalOverscrollLock = acquireWebHorizontalOverscrollLock();
756
+ const releaseMiuiDragBackLock = acquireWebMiuiDragBackLock();
757
+
758
+ return () => {
759
+ releaseMiuiDragBackLock?.();
760
+ releaseHorizontalOverscrollLock?.();
761
+ };
685
762
  }, [visible]);
686
763
 
687
764
  const handleCanvasLayout = React.useCallback((event: LayoutChangeEvent) => {