@ericchen1990/pano-view 3.1.1 → 3.1.3

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/dist/index.mjs CHANGED
@@ -2297,6 +2297,25 @@ function cn(...values) {
2297
2297
 
2298
2298
  // src/audio/howl.ts
2299
2299
  var import_howler = __toESM(require_howler());
2300
+
2301
+ // src/media-activation-event.ts
2302
+ function isMediaActivationEvent(event) {
2303
+ switch (event.type) {
2304
+ case "keydown":
2305
+ return event instanceof KeyboardEvent && event.key !== "Escape";
2306
+ case "pointerdown":
2307
+ return event instanceof PointerEvent && event.pointerType === "mouse";
2308
+ case "pointerup":
2309
+ return event instanceof PointerEvent && event.pointerType !== "mouse";
2310
+ default:
2311
+ return false;
2312
+ }
2313
+ }
2314
+ function isAutoplayPolicyError(error) {
2315
+ return typeof error === "object" && error !== null && "name" in error && error.name === "NotAllowedError";
2316
+ }
2317
+
2318
+ // src/audio/howl.ts
2300
2319
  import_howler.Howler.autoUnlock = true;
2301
2320
  function resumePanoAudio() {
2302
2321
  if (!import_howler.Howler.ctx || import_howler.Howler.ctx.state === "running") {
@@ -2304,6 +2323,9 @@ function resumePanoAudio() {
2304
2323
  }
2305
2324
  return import_howler.Howler.ctx.resume();
2306
2325
  }
2326
+ function isPanoAudioUnlocked() {
2327
+ return !import_howler.Howler.ctx || import_howler.Howler.ctx.state === "running";
2328
+ }
2307
2329
  function sourceList(src) {
2308
2330
  if (src == null) {
2309
2331
  return [];
@@ -2369,7 +2391,10 @@ function createUnlockingHowl({
2369
2391
  blockedNotified = true;
2370
2392
  onPlayError?.(error);
2371
2393
  }
2372
- const retry = () => {
2394
+ const retry = (event) => {
2395
+ if (!isMediaActivationEvent(event)) {
2396
+ return;
2397
+ }
2373
2398
  removeUnlockListeners();
2374
2399
  if (!disposed && isActive() && shouldRetryPlay()) {
2375
2400
  void resumePanoAudio();
@@ -2378,8 +2403,10 @@ function createUnlockingHowl({
2378
2403
  };
2379
2404
  removeUnlockListeners();
2380
2405
  unlockListeners.push({ type: "pointerdown", listener: retry });
2406
+ unlockListeners.push({ type: "pointerup", listener: retry });
2381
2407
  unlockListeners.push({ type: "keydown", listener: retry });
2382
2408
  window.addEventListener("pointerdown", retry, { capture: true });
2409
+ window.addEventListener("pointerup", retry, { capture: true });
2383
2410
  window.addEventListener("keydown", retry, { capture: true });
2384
2411
  }
2385
2412
  });
@@ -3832,7 +3859,7 @@ function hasPanoMediaActivationIntent(host) {
3832
3859
  return host.intents.size > 0;
3833
3860
  }
3834
3861
  function needsMediaGesture() {
3835
- if (typeof navigator !== "undefined" && navigator.userActivation?.hasBeenActive) {
3862
+ if (typeof navigator !== "undefined" && navigator.userActivation?.isActive) {
3836
3863
  return false;
3837
3864
  }
3838
3865
  if (import_howler2.Howler.ctx?.state === "running") {
@@ -7150,34 +7177,91 @@ var PanoViewer = forwardRef2(
7150
7177
  }),
7151
7178
  [bgmHost, videoHost]
7152
7179
  );
7153
- const activateMedia = useCallback6(() => {
7154
- setMediaActivated(true);
7180
+ const runMediaActivation = useCallback6(() => {
7155
7181
  const resume = mediaActivationControls.resumeAudio();
7156
7182
  mediaActivationOptions?.onActivate?.(mediaActivationControls);
7157
7183
  return resume;
7158
7184
  }, [mediaActivationControls, mediaActivationOptions]);
7185
+ const activateMedia = useCallback6(() => {
7186
+ setMediaActivated(true);
7187
+ return runMediaActivation();
7188
+ }, [runMediaActivation]);
7159
7189
  const hasMediaActivationIntent = mediaActivationRevision >= 0 && hasPanoMediaActivationIntent(mediaActivationHost);
7160
7190
  const shouldActivateMedia = mediaActivationOptions !== null && hasMediaActivationIntent && !mediaActivated;
7161
7191
  useEffect13(() => {
7162
7192
  if (!shouldActivateMedia) {
7163
7193
  return;
7164
7194
  }
7165
- if (!needsMediaGesture()) {
7166
- void activateMedia();
7167
- return;
7168
- }
7169
- const handleGesture = () => {
7170
- removeListeners();
7171
- void activateMedia();
7172
- };
7195
+ let cancelled = false;
7196
+ let activating = false;
7173
7197
  const removeListeners = () => {
7174
7198
  window.removeEventListener("pointerdown", handleGesture, true);
7199
+ window.removeEventListener("pointerup", handleGesture, true);
7175
7200
  window.removeEventListener("keydown", handleGesture, true);
7176
7201
  };
7202
+ const completeIfUnlocked = (requestedVideo, videoOk) => {
7203
+ if (cancelled || !isPanoAudioUnlocked()) {
7204
+ return;
7205
+ }
7206
+ if (requestedVideo && videoHost.controller && !videoOk) {
7207
+ return;
7208
+ }
7209
+ removeListeners();
7210
+ setMediaActivated(true);
7211
+ };
7212
+ const tryActivate = () => {
7213
+ if (activating || cancelled) {
7214
+ return;
7215
+ }
7216
+ activating = true;
7217
+ let videoPlay;
7218
+ const controls2 = {
7219
+ resumeAudio: mediaActivationControls.resumeAudio,
7220
+ playVideo: (options) => {
7221
+ const result = mediaActivationControls.playVideo(options);
7222
+ videoPlay = result;
7223
+ return result;
7224
+ },
7225
+ playBackgroundAudio: mediaActivationControls.playBackgroundAudio
7226
+ };
7227
+ try {
7228
+ const resume = controls2.resumeAudio();
7229
+ mediaActivationOptions?.onActivate?.(controls2);
7230
+ const requestedVideo = videoPlay !== void 0;
7231
+ void Promise.all([resume, videoPlay ?? Promise.resolve(true)]).then(
7232
+ ([, videoOk]) => {
7233
+ completeIfUnlocked(requestedVideo, videoOk);
7234
+ },
7235
+ () => {
7236
+ completeIfUnlocked(requestedVideo, false);
7237
+ }
7238
+ );
7239
+ } finally {
7240
+ activating = false;
7241
+ }
7242
+ };
7243
+ const handleGesture = (event) => {
7244
+ if (!isMediaActivationEvent(event)) {
7245
+ return;
7246
+ }
7247
+ tryActivate();
7248
+ };
7177
7249
  window.addEventListener("pointerdown", handleGesture, { capture: true });
7250
+ window.addEventListener("pointerup", handleGesture, { capture: true });
7178
7251
  window.addEventListener("keydown", handleGesture, { capture: true });
7179
- return removeListeners;
7180
- }, [activateMedia, shouldActivateMedia]);
7252
+ if (!needsMediaGesture()) {
7253
+ tryActivate();
7254
+ }
7255
+ return () => {
7256
+ cancelled = true;
7257
+ removeListeners();
7258
+ };
7259
+ }, [
7260
+ mediaActivationControls,
7261
+ mediaActivationOptions,
7262
+ shouldActivateMedia,
7263
+ videoHost
7264
+ ]);
7181
7265
  const fallbackViewRef = useRef13(DEFAULT_VIEW);
7182
7266
  const normalizedMinFov = Math.max(1, Math.min(minFov, maxFov - 1));
7183
7267
  const normalizedMaxFov = Math.min(
@@ -10526,8 +10610,10 @@ function PanoVideo({
10526
10610
  try {
10527
10611
  await video.play();
10528
10612
  } catch (error) {
10529
- blockedRef.current = true;
10530
- onPlaybackStateChangeRef.current?.("blocked");
10613
+ if (isAutoplayPolicyError(error)) {
10614
+ blockedRef.current = true;
10615
+ onPlaybackStateChangeRef.current?.("blocked");
10616
+ }
10531
10617
  onErrorRef.current?.({ source: "video", error });
10532
10618
  emitSnapshot();
10533
10619
  }