box-content-preview 3.95.0 → 3.97.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
  [![Mergify Status](https://img.shields.io/endpoint.svg?url=https://gh.mergify.io/badges/box/box-content-preview&style=flat)](https://mergify.io)
3
3
  [![Styled With Prettier](https://img.shields.io/badge/styled_with-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier)
4
4
  [![build status](https://img.shields.io/travis/box/box-content-preview/master.svg?style=flat-square)](https://travis-ci.org/box/box-content-preview)
5
- [![version](https://img.shields.io/badge/version-v3.95.0-blue.svg?style=flat-square)](https://github.com/box/box-content-preview)
5
+ [![version](https://img.shields.io/badge/version-v3.97.0-blue.svg?style=flat-square)](https://github.com/box/box-content-preview)
6
6
  [![npm version](https://img.shields.io/npm/v/box-ui-elements.svg?style=flat-square)](https://www.npmjs.com/package/box-ui-elements)
7
7
 
8
8
  # [Box Content Preview](https://developer.box.com/docs/box-content-preview)
@@ -22,11 +22,11 @@ We encourage all users to update their applications to utilize modern browsers f
22
22
 
23
23
  ## Current Version
24
24
 
25
- - Version: v3.95.0
25
+ - Version: v3.97.0
26
26
  - Locale: en-US
27
27
 
28
- https://cdn01.boxcdn.net/platform/preview/3.95.0/en-US/preview.js
29
- https://cdn01.boxcdn.net/platform/preview/3.95.0/en-US/preview.css
28
+ https://cdn01.boxcdn.net/platform/preview/3.97.0/en-US/preview.js
29
+ https://cdn01.boxcdn.net/platform/preview/3.97.0/en-US/preview.css
30
30
 
31
31
  ## Supported Locales
32
32
 
@@ -52,10 +52,10 @@ You can self-host the Box Content Preview library or reference the versions avai
52
52
  <title>Box Content Preview Demo</title>
53
53
 
54
54
  <!-- Latest version of Preview SDK for your locale -->
55
- <script src="https://cdn01.boxcdn.net/platform/preview/3.95.0/en-US/preview.js"></script>
55
+ <script src="https://cdn01.boxcdn.net/platform/preview/3.97.0/en-US/preview.js"></script>
56
56
  <link
57
57
  rel="stylesheet"
58
- href="https://cdn01.boxcdn.net/platform/preview/3.95.0/en-US/preview.css"
58
+ href="https://cdn01.boxcdn.net/platform/preview/3.97.0/en-US/preview.css"
59
59
  />
60
60
  </head>
61
61
  <body>
@@ -76,7 +76,7 @@ To self-host the Box Content Preview library, follow these steps:
76
76
 
77
77
  1. Either fork the repo and check out the version you want to host or download the specific version as a zip:
78
78
 
79
- - Check out a specific version with `git checkout v3.95.0`
79
+ - Check out a specific version with `git checkout v3.97.0`
80
80
  - Download a specific version as a zip from https://github.com/box/box-content-preview/releases
81
81
 
82
82
  2. Install dependencies and build the library with `yarn install && yarn build:i18n && yarn build:prod`
@@ -61,6 +61,7 @@
61
61
  .bp-MarkerAvatarStack{position:absolute;bottom:calc(100% + 4px);left:50%;display:flex;align-items:center;transform:translateX(-50%)}.bp-MarkerAvatarStack-item{position:relative;flex-shrink:0;box-sizing:content-box;width:20px;height:20px;padding:0;background:none;border:0;border-radius:50%;outline:none;overflow:visible;cursor:pointer;appearance:none;transition:margin 150ms}.bp-MarkerAvatarStack-item:focus,.bp-MarkerAvatarStack-item:focus-visible{outline:none}.bp-MarkerAvatarStack-item:not(:first-child){margin-left:var(--bp-marker-stack-overlap, -10px)}.bp-MarkerAvatarStack-item .bp-MarkerAvatar{position:absolute;top:50%;bottom:auto;left:50%;display:block;transform:translate(-50%, -50%);transform-origin:center center}.bp-MarkerAvatarStack-item:hover,.bp-MarkerAvatarStack-item:focus-visible{z-index:3}:is(.bp-WaveformCommentMarkers-marker--group,.bp-TimeControlsV2-marker--group,.bp-MarkerCluster):is(:hover,:has(.bp-MarkerAvatarStack-item:focus-visible)) .bp-MarkerAvatarStack-item:not(:first-child){margin-left:2px}.bp-MarkerAvatarStack-overflow{cursor:pointer}.bp-MarkerAvatarStack-overflowBadge{background-color:#383838;color:#fff}.bp-MarkerAvatarStack-overflowBadge .bp-MarkerAvatar-initial{color:#fff}
62
62
  .bp-WaveformCommentMarkers{position:absolute;top:-2px;right:0;left:0;z-index:4;box-sizing:border-box;height:24px;padding:0 60px;overflow:visible;pointer-events:auto}.bp-WaveformCommentMarkers--zoomed,.bp-WaveformCommentMarkers--tape{padding:0;overflow:clip visible}.bp-WaveformCommentMarkers--tape{top:auto;bottom:100%;margin-bottom:12px}.bp-WaveformCommentMarkers-track{position:relative;width:100%;height:100%;overflow:visible}.bp-WaveformCommentMarkers--zoomed .bp-WaveformCommentMarkers-track,.bp-WaveformCommentMarkers--tape .bp-WaveformCommentMarkers-track{overflow:clip visible}.bp-WaveformCommentMarkers-marker{position:absolute;top:50%;z-index:1;display:flex;align-items:center;justify-content:center;width:auto;height:auto;padding:0;background:none;border:0;border-radius:50%;transform:translate(-50%, -50%);cursor:pointer;appearance:none;pointer-events:auto;overflow:visible;outline:none;transition:box-shadow 150ms}.bp-WaveformCommentMarkers-marker:focus,.bp-WaveformCommentMarkers-marker:focus-visible{outline:none}.bp-WaveformCommentMarkers-marker .bp-MarkerAvatar{overflow:visible;isolation:isolate;cursor:pointer}.bp-WaveformCommentMarkers-marker .bp-MarkerAvatar img{cursor:pointer}.bp-WaveformCommentMarkers-marker .bp-MarkerAvatar::after{position:absolute;z-index:1;inset:0;background:#000;border-radius:50%;opacity:.4;pointer-events:none;content:"";transition:opacity 150ms}.bp-WaveformCommentMarkers-marker>.bp-MarkerAvatar{position:relative;bottom:auto;left:auto;transform:none;transform-origin:center center}.bp-WaveformCommentMarkers-marker .bp-MarkerAvatar:not(.bp-MarkerAvatarStack-overflowBadge),.bp-WaveformCommentMarkers-marker .bp-MarkerAvatarStack .bp-MarkerAvatar:not(.bp-MarkerAvatarStack-overflowBadge){background-color:#000}.bp-WaveformCommentMarkers-marker .bp-MarkerAvatarStack{position:relative;bottom:auto;left:auto;transform:none}.bp-WaveformCommentMarkers-marker--group{width:auto}.bp-WaveformView:hover~.bp-WaveformCommentMarkers .bp-MarkerAvatar::after,.bp-WaveformCommentMarkers:hover .bp-MarkerAvatar::after,.bp-WaveformCommentMarkers:has(:focus-visible) .bp-MarkerAvatar::after,.bp-WaveformCommentMarkers-marker:not(.bp-WaveformCommentMarkers-marker--group).bp-WaveformCommentMarkers-marker--selected .bp-MarkerAvatar::after,.bp-WaveformCommentMarkers .bp-MarkerAvatarStack-item--selected .bp-MarkerAvatar::after{opacity:0}.bp-WaveformCommentMarkers-marker--selected{z-index:3}.bp-WaveformCommentMarkers-marker:hover,.bp-WaveformCommentMarkers-marker:focus-within{z-index:4}.bp-WaveformCommentMarkers .bp-MarkerAvatarStack-item{cursor:pointer;transition:margin 150ms}.bp-WaveformCommentMarkers .bp-MarkerAvatarStack-item:hover,.bp-WaveformCommentMarkers .bp-MarkerAvatarStack-item:focus-visible{z-index:3}@media(prefers-reduced-motion: reduce){.bp-WaveformCommentMarkers-marker,.bp-WaveformCommentMarkers .bp-MarkerAvatarStack-item,.bp-WaveformCommentMarkers-marker .bp-MarkerAvatar::after{transition:none}}
63
63
  .bp-WaveformGeneratingIndicator{display:flex;gap:4px;align-items:center;height:48px;padding:8px 16px 8px 12px;pointer-events:none}.bp-WaveformGeneratingIndicator-bars{display:flex;flex:0 0 24px;align-items:center;justify-content:center;width:24px;height:24px}.bp-WaveformGeneratingIndicator-bar{width:2px;height:10px;background:rgba(255,255,255,.3);border-radius:6px;animation:bp-WaveformGeneratingIndicator-pulse .66s ease-in-out infinite}.bp-WaveformGeneratingIndicator-bar:nth-child(2){margin-left:2px;animation-delay:.1s}.bp-WaveformGeneratingIndicator-bar:last-child{margin-left:2px;animation-delay:.2s}.bp-WaveformGeneratingIndicator-label{color:#fff;font-weight:normal;font-size:14px;line-height:22px;white-space:nowrap}@keyframes bp-WaveformGeneratingIndicator-pulse{0%,80%,100%{background:rgba(255,255,255,.3);transform:scaleY(1.2)}40%{background:#fff;transform:scaleY(1.6)}}@media(prefers-reduced-motion: reduce){.bp-WaveformGeneratingIndicator-bar{animation:none;background:#fff;transform:none}}
64
+ .bp-WaveformShuttle{position:absolute;top:48px;left:50%;z-index:6;display:flex;gap:4px;align-items:center;height:48px;padding:8px 16px;color:#fff;background:rgba(255,255,255,.1);border-radius:24px;box-shadow:0 2px 12px rgba(0,0,0,.08);transform:translateX(-50%);backdrop-filter:blur(60px);pointer-events:none;-webkit-user-select:none;user-select:none}.bp-WaveformShuttle-glyph{display:block;flex:0 0 auto;width:19px;height:11px}.bp-WaveformShuttle.bp-is-reverse .bp-WaveformShuttle-glyph{transform:scaleX(-1)}.bp-WaveformShuttle-rate{font-weight:500;font-size:14px;line-height:22px;white-space:nowrap}
64
65
  .bp-WaveformRange{position:absolute;inset:0;z-index:2;pointer-events:none}.bp-WaveformRange-region{position:absolute;top:50%;box-sizing:border-box;height:150px;pointer-events:none;background:rgba(255,255,255,.1);border:1px solid rgba(255,255,255,.4);border-radius:10px;box-shadow:0 0 0 1px #222;transform:translateY(-50%);transition:border-width 100ms ease,border-color 100ms ease}.bp-WaveformRange--highlight .bp-WaveformRange-region,.bp-WaveformRange:has(.bp-WaveformRange-handle:hover) .bp-WaveformRange-region,.bp-WaveformRange:has(.bp-WaveformRange-handle--dragging) .bp-WaveformRange-region{border-width:2px;border-color:#fff}.bp-WaveformRange-handle{position:absolute;top:50%;z-index:1;width:24px;height:150px;pointer-events:auto;cursor:ew-resize;touch-action:none;transform:translate(-50%, -50%)}.bp-WaveformRange-handle--end{z-index:2}.bp-WaveformRange-handleGrip{position:absolute;top:50%;left:50%;width:8px;height:20px;background:#fff;border:1px solid #222;border-radius:4px;box-shadow:0 1px 4px rgba(0,0,0,.4);opacity:0;pointer-events:none;transform:translate(-50%, -50%) scale(0.5);transition:opacity 100ms ease-in,transform 100ms ease-in}.bp-WaveformRange-handle:hover .bp-WaveformRange-handleGrip,.bp-WaveformRange-handle:focus-visible .bp-WaveformRange-handleGrip,.bp-WaveformRange-handle--dragging .bp-WaveformRange-handleGrip{opacity:1;transform:translate(-50%, -50%) scale(1);transition:opacity 150ms ease-out,transform 150ms ease-out}.bp-WaveformRange-comment{position:absolute;top:calc(50% - 75px);z-index:5;display:inline-flex;gap:8px;align-items:center;justify-content:center;box-sizing:border-box;height:48px;padding:8px 14px;color:rgba(255,255,255,.8);font-weight:normal;font-size:14px;font-family:Lato,Arial,sans-serif;line-height:22px;letter-spacing:.1px;white-space:nowrap;background:rgba(0,0,0,.8);border:0;backdrop-filter:blur(12px);border-radius:46px;box-shadow:0 2px 4px 0 rgba(0,0,0,.12);transform:translate(-50%, calc(-100% - 36px));cursor:pointer;appearance:none;pointer-events:auto}.bp-WaveformRange-commentIcon{display:block;flex:0 0 auto;width:20px;height:20px}.bp-WaveformView--tape .bp-WaveformRange-comment{top:calc(50% - (100% + 10px) / 2)}.bp-WaveformRange-tooltip{position:absolute;top:100%;z-index:3;margin-top:4px;pointer-events:none;transform:translateX(-50%)}.bp-WaveformRange-tooltipTime{padding:4px 10px;color:#fff;font-weight:normal;font-size:14px;font-family:Lato,Arial,sans-serif;line-height:20px;letter-spacing:.3px;white-space:nowrap;background:rgba(34,34,34,.92);border:1px solid rgba(255,255,255,.18);border-radius:8px}@media(prefers-reduced-motion: reduce){.bp-WaveformRange-region,.bp-WaveformRange-handleGrip{transition:none}}
65
66
  .bp-WaveformView{box-sizing:border-box;width:100%;height:206px;min-height:206px;padding:0 60px;overflow:visible;background:none;-webkit-tap-highlight-color:transparent}.bp-WaveformView.bp-WaveformView--zoomed,.bp-WaveformView.bp-WaveformView--tape{padding:0;touch-action:none}.bp-WaveformView.bp-WaveformView--zoomed .bp-WaveformView-canvas,.bp-WaveformView.bp-WaveformView--tape .bp-WaveformView-canvas{overflow:hidden;mask-image:linear-gradient(to right, transparent, #000 92px, #000 calc(100% - 92px), transparent)}.bp-WaveformView.bp-WaveformView--zoomed .bp-WaveformView-canvas>*::part(scroll),.bp-WaveformView.bp-WaveformView--tape .bp-WaveformView-canvas>*::part(scroll){overscroll-behavior-x:none}.bp-WaveformView.bp-WaveformView--tape{flex:1 1 auto;height:100%;min-height:0}.bp-WaveformView.bp-WaveformView--tape .bp-WaveformView-canvas{height:100%}.bp-WaveformView.bp-WaveformView--tape .bp-WaveformView-canvas>*::part(scroll){scrollbar-width:none}.bp-WaveformView.bp-WaveformView--tape .bp-WaveformView-playhead,.bp-WaveformView.bp-WaveformView--tape .bp-WaveformRange-region,.bp-WaveformView.bp-WaveformView--tape .bp-WaveformRange-handle{height:calc(100% + 10px)}.bp-WaveformView-track{position:relative;display:flex;align-items:center;width:100%;height:100%;cursor:pointer}.bp-WaveformView-canvas{z-index:0;width:100%;height:140px}.bp-WaveformView-playhead{position:absolute;top:50%;left:0;z-index:1;width:2px;height:150px;pointer-events:none;background:linear-gradient(#2487ff, #006bed);border-radius:1px;box-shadow:0 0 0 1px #222,0 0 10px 0 rgba(36,135,255,.3);transform:translate(-50%, -50%)}.bp-WaveformView-hover{position:absolute;top:100%;z-index:2;margin-top:4px;pointer-events:none;transform:translateX(-50%)}.bp-WaveformView-hover--tape{top:-24px;left:50%;z-index:5;margin-top:0;transform:translate(-50%, -50%)}.bp-WaveformView-hoverTime{padding:4px 10px;color:#fff;font-weight:normal;font-size:14px;font-family:Lato,Arial,sans-serif;line-height:20px;letter-spacing:.3px;white-space:nowrap;background:rgba(34,34,34,.92);border:1px solid rgba(255,255,255,.18);border-radius:8px}.bp-WaveformView--inert{pointer-events:none}.bp-WaveformView--inert .bp-WaveformView-track{cursor:default}.bp-WaveformView--inert .bp-WaveformRange-handle,.bp-WaveformView--inert .bp-WaveformRange-comment{pointer-events:none;cursor:default}.bp-WaveformView:not(:hover) .bp-WaveformRange:not(.bp-WaveformRange--persist){opacity:.4}
66
67
  .bp-SliderControl{outline:0;position:relative;cursor:pointer}.bp-SliderControl:focus:not(:disabled){box-shadow:inset 0 0 0 1px rgba(211,211,211,.5),0 1px 2px rgba(0,0,0,.1)}.bp-SliderControl:focus-visible:not(:disabled){box-shadow:inset 0 0 0 1px rgba(211,211,211,.5),0 1px 2px rgba(0,0,0,.1)}.bp-SliderControl:focus:not(:focus-visible){box-shadow:none}.bp-SliderControl-thumb{position:absolute;top:calc(50% - 6px);width:12px;height:12px;margin-left:-6px;background:#0061d5;border:0;border-radius:12px;cursor:pointer}.bp-SliderControl-track{position:absolute;inset:0;height:3px;margin:auto 3px;background:transparent linear-gradient(#fff, #fff) no-repeat center border-box}
package/dist/lib/index.js CHANGED
@@ -314,6 +314,7 @@ class PreviewError extends Error {
314
314
  /* harmony export */ Ci: () => (/* binding */ CLASS_BOX_PREVIEW_VIDEO_PRELOAD_PLAY_OVERLAY),
315
315
  /* harmony export */ D4: () => (/* binding */ CLASS_ANNOTATIONS_VIDEO_FTUX_CURSOR_SEEN),
316
316
  /* harmony export */ EP: () => (/* binding */ ORIGINAL_REP_NAME),
317
+ /* harmony export */ Ed: () => (/* binding */ BLUEPRINT_MIGRATION_SUPPORTING_UI),
317
318
  /* harmony export */ Ev: () => (/* binding */ BROWSERS),
318
319
  /* harmony export */ FD: () => (/* binding */ SELECTOR_BOX_PREVIEW_LOGO_DEFAULT),
319
320
  /* harmony export */ GA: () => (/* binding */ ANNOTATOR_EVENT),
@@ -337,6 +338,7 @@ class PreviewError extends Error {
337
338
  /* harmony export */ Mi: () => (/* binding */ PDFJS_CSS_UNITS),
338
339
  /* harmony export */ Mj: () => (/* binding */ CLASS_BOX_PREVIEW_THUMBNAILS_CLOSE_ACTIVE),
339
340
  /* harmony export */ N7: () => (/* binding */ DISCOVERABILITY_ATTRIBUTE),
341
+ /* harmony export */ OQ: () => (/* binding */ BLUEPRINT_MIGRATION_CONTROLS_BAR),
340
342
  /* harmony export */ OW: () => (/* binding */ PRELOAD_REP_NAME),
341
343
  /* harmony export */ Oo: () => (/* binding */ CLASS_ANNOTATIONS_CREATE_REGION),
342
344
  /* harmony export */ P8: () => (/* binding */ CLASS_BOX_PREVIEW_HAS_HEADER),
@@ -367,9 +369,11 @@ class PreviewError extends Error {
367
369
  /* harmony export */ bE: () => (/* binding */ SELECTOR_BOX_PREVIEW_CONTENT),
368
370
  /* harmony export */ br: () => (/* binding */ FILE_OPTION_FILE_VERSION_ID),
369
371
  /* harmony export */ c6: () => (/* binding */ PRELOAD_PAGED_REP_NAME),
372
+ /* harmony export */ cA: () => (/* binding */ BLUEPRINT_MIGRATION_ARCHIVE),
370
373
  /* harmony export */ cP: () => (/* binding */ CLASS_BOX_PREVIEW_PRELOAD_WRAPPER_VIDEO),
371
374
  /* harmony export */ cR: () => (/* binding */ TEXT_STATIC_ASSETS_VERSION),
372
375
  /* harmony export */ cZ: () => (/* binding */ CLASS_ANNOTATIONS_DISCOVERABLE),
376
+ /* harmony export */ dR: () => (/* binding */ BLUEPRINT_MIGRATION_MEDIA_CONTROLS),
373
377
  /* harmony export */ eA: () => (/* binding */ SUBTITLES_OFF),
374
378
  /* harmony export */ eF: () => (/* binding */ CLASS_BOX_PREVIEW_PRELOAD_CONTENT),
375
379
  /* harmony export */ eM: () => (/* binding */ CLASS_BOX_PREVIEW_HAS_NAVIGATION),
@@ -525,6 +529,13 @@ const X_REP_HINT_VIDEO_MP4 = '[mp4]';
525
529
  const X_REP_HINT_WAVEFORM = '[waveform]';
526
530
  const AI_TRANSCRIPTION_FOR_VIDEO_SUBTITLES = 'aiTranscriptionForVideoSubtitles';
527
531
  const AUDIO_PLAYER_V2 = 'audioPlayerV2.enabled';
532
+
533
+ // One per wave of the Blueprint migration. Each is reported as its own metric dimension so a
534
+ // dashboard can compare a wave's timings with its flag on against the same wave with it off.
535
+ const BLUEPRINT_MIGRATION_ARCHIVE = 'blueprintMigrationArchive.enabled';
536
+ const BLUEPRINT_MIGRATION_CONTROLS_BAR = 'blueprintMigrationControlsBar.enabled';
537
+ const BLUEPRINT_MIGRATION_MEDIA_CONTROLS = 'blueprintMigrationMediaControls.enabled';
538
+ const BLUEPRINT_MIGRATION_SUPPORTING_UI = 'blueprintMigrationSupportingUi.enabled';
528
539
  const PDFJS_CSS_UNITS = 96.0 / 72.0; // Should match CSS_UNITS in pdf_viewer.js
529
540
  const PDFJS_MAX_AUTO_SCALE = 1.25; // Should match MAX_AUTO_SCALE in pdf_viewer.js
530
541
  const PDFJS_WIDTH_PADDING_PX = 40; // Should match SCROLLBAR_PADDING in pdf_viewer.js
@@ -1018,7 +1029,7 @@ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e =
1018
1029
  const CLIENT_NAME = "box-content-preview"; // eslint-disable-line no-undef
1019
1030
  const CLIENT_NAME_KEY = 'box_client_name';
1020
1031
  const CLIENT_VERSION_KEY = 'box_client_version';
1021
- const CLIENT_VERSION = "3.95.0"; // eslint-disable-line no-undef
1032
+ const CLIENT_VERSION = "3.97.0"; // eslint-disable-line no-undef
1022
1033
  const HEADER_CLIENT_NAME = 'X-Box-Client-Name';
1023
1034
  const HEADER_CLIENT_VERSION = 'X-Box-Client-Version';
1024
1035
  const PROMISE_MAP = {};
@@ -4609,7 +4620,7 @@ function getPdfjsWorkerSrc() {
4609
4620
 
4610
4621
  /***/ },
4611
4622
 
4612
- /***/ 8862
4623
+ /***/ 2460
4613
4624
  (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
4614
4625
 
4615
4626
 
@@ -4735,43 +4746,8 @@ function morphPeaks(from, to, elapsedMs) {
4735
4746
  }
4736
4747
  // EXTERNAL MODULE: ./src/lib/viewers/media/waveform/viewport.ts
4737
4748
  var waveform_viewport = __webpack_require__(772);
4738
- ;// ./src/lib/viewers/media/waveform/useTapeWaveform.ts
4739
-
4740
-
4741
- function isIPadNavigator(tapeNavigator) {
4742
- return /iPad/i.test(tapeNavigator.userAgent || '') || tapeNavigator.platform === 'MacIntel' && (tapeNavigator.maxTouchPoints || 0) > 1;
4743
- }
4744
- function isCoarsePrimaryPointer(tapeWindow) {
4745
- return typeof tapeWindow.matchMedia === 'function' && tapeWindow.matchMedia(constants/* TAPE_POINTER_MEDIA_QUERY */.Le).matches;
4746
- }
4747
-
4748
- /**
4749
- * Tape vs desktop camera: coarse primary pointer (finger) or iPad
4750
- * (including iPadOS reporting itself as Mac). Not width, not hasTouch,
4751
- * not Browser.isMobile().
4752
- */
4753
- function isTapeWaveformInput(tapeWindow = window) {
4754
- return isCoarsePrimaryPointer(tapeWindow) || isIPadNavigator(tapeWindow.navigator);
4755
- }
4756
-
4757
- /** Subscribe to the pointer media query; re-read the iPad heuristic on change. */
4758
- function useTapeWaveform() {
4759
- const [isTape, setIsTape] = (0,external_react_.useState)(() => typeof window !== 'undefined' && isTapeWaveformInput(window));
4760
- (0,external_react_.useEffect)(() => {
4761
- if (typeof window.matchMedia !== 'function') {
4762
- setIsTape(isTapeWaveformInput(window));
4763
- return undefined;
4764
- }
4765
- const mediaQuery = window.matchMedia(constants/* TAPE_POINTER_MEDIA_QUERY */.Le);
4766
- const sync = () => {
4767
- setIsTape(isTapeWaveformInput(window));
4768
- };
4769
- sync();
4770
- mediaQuery.addEventListener('change', sync);
4771
- return () => mediaQuery.removeEventListener('change', sync);
4772
- }, []);
4773
- return isTape;
4774
- }
4749
+ // EXTERNAL MODULE: ./src/lib/viewers/media/waveform/useTapeWaveform.ts
4750
+ var useTapeWaveform = __webpack_require__(7308);
4775
4751
  // EXTERNAL MODULE: ./node_modules/classnames/index.js
4776
4752
  var classnames = __webpack_require__(2485);
4777
4753
  var classnames_default = /*#__PURE__*/__webpack_require__.n(classnames);
@@ -4962,14 +4938,62 @@ function WaveformGeneratingIndicator() {
4962
4938
  className: "bp-WaveformGeneratingIndicator-label"
4963
4939
  }, label));
4964
4940
  }
4941
+ ;// ./src/lib/viewers/controls/icons/IconShuttleForward.tsx
4942
+ function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
4943
+
4944
+ function IconShuttleForward(props) {
4945
+ return /*#__PURE__*/external_react_.createElement("svg", _extends({
4946
+ "data-testid": "IconShuttleForward",
4947
+ focusable: false,
4948
+ height: 11,
4949
+ viewBox: "35.57 37.51 37.79 21.24",
4950
+ width: 19
4951
+ }, props), /*#__PURE__*/external_react_.createElement("path", {
4952
+ d: "M35.5684 56.7422V39.502C35.5684 38.8275 35.7415 38.3262 36.0879 37.998C36.4342 37.6699 36.8398 37.5059 37.3047 37.5059C37.7331 37.5059 38.1523 37.6289 38.5625 37.875L53.0137 46.2832C53.5423 46.5931 53.9206 46.8848 54.1484 47.1582C54.3854 47.4316 54.5039 47.7552 54.5039 48.1289C54.5039 48.5026 54.3854 48.8262 54.1484 49.0996C53.9206 49.373 53.5423 49.6647 53.0137 49.9746L38.5625 58.3828C38.1523 58.6289 37.7331 58.752 37.3047 58.752C36.8398 58.752 36.4342 58.5879 36.0879 58.2598C35.7415 57.9316 35.5684 57.4258 35.5684 56.7422Z",
4953
+ fill: "currentColor"
4954
+ }), /*#__PURE__*/external_react_.createElement("path", {
4955
+ d: "M54.4219 56.7422V39.502C54.4219 38.8275 54.5905 38.3262 54.9277 37.998C55.2741 37.6699 55.6842 37.5059 56.1582 37.5059C56.5866 37.5059 57.0059 37.6289 57.416 37.875L71.8672 46.2832C72.3958 46.5931 72.7741 46.8848 73.002 47.1582C73.2389 47.4316 73.3574 47.7552 73.3574 48.1289C73.3574 48.5026 73.2389 48.8262 73.002 49.0996C72.7741 49.373 72.3958 49.6647 71.8672 49.9746L57.416 58.3828C57.0059 58.6289 56.5866 58.752 56.1582 58.752C55.6842 58.752 55.2741 58.5879 54.9277 58.2598C54.5905 57.9316 54.4219 57.4258 54.4219 56.7422Z",
4956
+ fill: "currentColor"
4957
+ }));
4958
+ }
4959
+ /* harmony default export */ const icons_IconShuttleForward = (IconShuttleForward);
4960
+ // EXTERNAL MODULE: ./src/lib/util.js + 1 modules
4961
+ var util = __webpack_require__(4410);
4962
+ ;// ./src/lib/viewers/media/waveform/WaveformShuttleIndicator.scss
4963
+ // extracted by mini-css-extract-plugin
4964
+
4965
+ ;// ./src/lib/viewers/media/waveform/WaveformShuttleIndicator.tsx
4966
+
4967
+
4968
+
4969
+
4970
+
4971
+ function WaveformShuttleIndicator({
4972
+ direction,
4973
+ rate
4974
+ }) {
4975
+ const isReverse = direction === 'reverse';
4976
+ const label = (0,util/* replacePlaceholders */.Lb)(isReverse ? "Scanning backward at {1}x" : "Scanning forward at {1}x", [String(rate)]);
4977
+ return /*#__PURE__*/external_react_["default"].createElement("div", {
4978
+ "aria-label": label,
4979
+ className: classnames_default()('bp-WaveformShuttle', {
4980
+ 'bp-is-reverse': isReverse
4981
+ }),
4982
+ "data-testid": "bp-waveform-shuttle",
4983
+ role: "status"
4984
+ }, /*#__PURE__*/external_react_["default"].createElement(icons_IconShuttleForward, {
4985
+ "aria-hidden": "true",
4986
+ className: "bp-WaveformShuttle-glyph"
4987
+ }), /*#__PURE__*/external_react_["default"].createElement("span", {
4988
+ className: "bp-WaveformShuttle-rate"
4989
+ }, `${rate}x`));
4990
+ }
4965
4991
  ;// external "react-dom"
4966
4992
 
4967
4993
  ;// ./node_modules/wavesurfer.js/dist/wavesurfer.esm.js
4968
4994
  function t(t,e,i,n){return new(i||(i=Promise))((function(s,r){function o(t){try{l(n.next(t))}catch(t){r(t)}}function a(t){try{l(n.throw(t))}catch(t){r(t)}}function l(t){var e;t.done?s(t.value):(e=t.value,e instanceof i?e:new i((function(t){t(e)}))).then(o,a)}l((n=n.apply(t,e||[])).next())}))}"function"==typeof SuppressedError&&SuppressedError;class e{constructor(){this.listeners={}}on(t,e,i){if(this.listeners[t]||(this.listeners[t]=new Set),null==i?void 0:i.once){const i=(...n)=>{this.un(t,i),e(...n)};return this.listeners[t].add(i),()=>this.un(t,i)}return this.listeners[t].add(e),()=>this.un(t,e)}un(t,e){var i;null===(i=this.listeners[t])||void 0===i||i.delete(e)}once(t,e){return this.on(t,e,{once:!0})}unAll(){this.listeners={}}emit(t,...e){this.listeners[t]&&this.listeners[t].forEach((t=>t(...e)))}}const i={decode:function(e,i){return t(this,void 0,void 0,(function*(){const t=new AudioContext({sampleRate:i});try{return yield t.decodeAudioData(e)}finally{"closed"!==t.state&&(yield t.close().catch((()=>{})))}}))},createBuffer:function(t,e){if(!t||0===t.length)throw new Error("channelData must be a non-empty array");if(e<=0)throw new Error("duration must be greater than 0");if("number"==typeof t[0]&&(t=[t]),!t[0]||0===t[0].length)throw new Error("channelData must contain non-empty channel arrays");!function(t){const e=t[0];if(e.some((t=>t>1||t<-1))){const i=e.length;let n=0;for(let t=0;t<i;t++){const i=Math.abs(e[t]);i>n&&(n=i)}for(const e of t)for(let t=0;t<i;t++)e[t]/=n}}(t);const i=t.map((t=>t instanceof Float32Array?t:Float32Array.from(t)));return{duration:e,length:i[0].length,sampleRate:i[0].length/e,numberOfChannels:i.length,getChannelData:t=>{const e=i[t];if(!e)throw new Error(`Channel ${t} not found`);return e},copyFromChannel:AudioBuffer.prototype.copyFromChannel,copyToChannel:AudioBuffer.prototype.copyToChannel}}};function n(t,e){const i=e.xmlns?document.createElementNS(e.xmlns,t):document.createElement(t);for(const[t,s]of Object.entries(e))if("children"===t&&s)for(const[t,e]of Object.entries(s))e instanceof Node?i.appendChild(e):"string"==typeof e?i.appendChild(document.createTextNode(e)):i.appendChild(n(t,e));else"style"===t?Object.assign(i.style,s):"textContent"===t?i.textContent=s:i.setAttribute(t,s.toString());return i}function s(t,e,i){const s=n(t,e||{});return null==i||i.appendChild(s),s}function r(t){return t instanceof HTMLElement||"object"==typeof t&&null!==t&&t.nodeType===Node.ELEMENT_NODE&&"object"==typeof t.style}var o=Object.freeze({__proto__:null,createElement:s,default:s,isHTMLElement:r});const a={fetchBlob:function(e,i,n){return t(this,void 0,void 0,(function*(){var s;const r=yield fetch(e,n);if(r.status>=400)throw new Error(`Failed to fetch ${e}: ${r.status} (${r.statusText})`);return function(e,i,n){t(this,void 0,void 0,(function*(){var t;if(!e.body||!e.headers)return;const s=e.body.getReader(),r=Number(e.headers.get("Content-Length"))||0;let o=0;const a=()=>{s.cancel()};if(n){if(n.aborted)return void s.cancel();n.addEventListener("abort",a,{once:!0})}try{for(;;){const e=yield s.read();if(e.done)break;if(o+=(null===(t=e.value)||void 0===t?void 0:t.length)||0,r>0){const t=Math.round(o/r*100);i(t)}}}catch(t){if(t instanceof DOMException&&"AbortError"===t.name)return;console.warn("Progress tracking error:",t)}finally{n&&n.removeEventListener("abort",a)}}))}(r.clone(),i,null!==(s=null==n?void 0:n.signal)&&void 0!==s?s:void 0),r.blob()}))}};function l(t){let e=t;const i=new Set;return{get value(){return e},set(t){Object.is(e,t)||(e=t,i.forEach((t=>t(e))))},update(t){this.set(t(e))},subscribe:t=>(i.add(t),()=>i.delete(t))}}function h(t,e){const i=l(t());return e.forEach((e=>e.subscribe((()=>{const e=t();Object.is(i.value,e)||i.set(e)})))),{get value(){return i.value},subscribe:t=>i.subscribe(t)}}function c(t,e){let i;const n=()=>{i&&(i(),i=void 0),i=t()},s=e.map((t=>t.subscribe(n)));return n(),()=>{i&&(i(),i=void 0),s.forEach((t=>t()))}}class u extends e{get isPlayingSignal(){return this._isPlaying}get currentTimeSignal(){return this._currentTime}get durationSignal(){return this._duration}get volumeSignal(){return this._volume}get mutedSignal(){return this._muted}get playbackRateSignal(){return this._playbackRate}get seekingSignal(){return this._seeking}constructor(t){super(),this.isExternalMedia=!1,this._ownBlobUrl=null,this.reactiveMediaEventCleanups=[],t.media?(this.media=t.media,this.isExternalMedia=!0):this.media=document.createElement("audio"),this._isPlaying=l(!1),this._currentTime=l(0),this._duration=l(0),this._volume=l(this.media.volume),this._muted=l(this.media.muted),this._playbackRate=l(this.media.playbackRate||1),this._seeking=l(!1),this.setupReactiveMediaEvents(),t.mediaControls&&(this.media.controls=!0),t.autoplay&&(this.media.autoplay=!0),null!=t.playbackRate&&this.onMediaEvent("canplay",(()=>{null!=t.playbackRate&&(this.media.playbackRate=t.playbackRate)}),{once:!0})}setupReactiveMediaEvents(){this.reactiveMediaEventCleanups.push(this.onMediaEvent("play",(()=>{this._isPlaying.set(!0)}))),this.reactiveMediaEventCleanups.push(this.onMediaEvent("pause",(()=>{this._isPlaying.set(!1)}))),this.reactiveMediaEventCleanups.push(this.onMediaEvent("ended",(()=>{this._isPlaying.set(!1)}))),this.reactiveMediaEventCleanups.push(this.onMediaEvent("timeupdate",(()=>{this._currentTime.set(this.media.currentTime)}))),this.reactiveMediaEventCleanups.push(this.onMediaEvent("durationchange",(()=>{this._duration.set(this.media.duration||0)}))),this.reactiveMediaEventCleanups.push(this.onMediaEvent("loadedmetadata",(()=>{this._duration.set(this.media.duration||0)}))),this.reactiveMediaEventCleanups.push(this.onMediaEvent("seeking",(()=>{this._seeking.set(!0)}))),this.reactiveMediaEventCleanups.push(this.onMediaEvent("seeked",(()=>{this._seeking.set(!1)}))),this.reactiveMediaEventCleanups.push(this.onMediaEvent("volumechange",(()=>{this._volume.set(this.media.volume),this._muted.set(this.media.muted)}))),this.reactiveMediaEventCleanups.push(this.onMediaEvent("ratechange",(()=>{this._playbackRate.set(this.media.playbackRate)})))}onMediaEvent(t,e,i){return this.media.addEventListener(t,e,i),()=>this.media.removeEventListener(t,e,i)}getSrc(){return this.media.currentSrc||this.media.src||""}revokeSrc(){this._ownBlobUrl&&(URL.revokeObjectURL(this._ownBlobUrl),this._ownBlobUrl=null)}canPlayType(t){return""!==this.media.canPlayType(t)}setSrc(t,e){const i=this.getSrc();if(t&&i===t)return;this.revokeSrc();const n=e instanceof Blob&&(this.canPlayType(e.type)||!t)?URL.createObjectURL(e):t;if(n!==t&&(this._ownBlobUrl=n),i&&this.media.removeAttribute("src"),n||t)try{this.media.src=n}catch(e){this.media.src=t}}destroy(){this.reactiveMediaEventCleanups.forEach((t=>t())),this.reactiveMediaEventCleanups=[],this.revokeSrc(),this.unAll(),this.isExternalMedia||(this.media.pause(),this.media.removeAttribute("src"),this.media.load(),this.media.remove())}setMediaElement(t){this.reactiveMediaEventCleanups.forEach((t=>t())),this.reactiveMediaEventCleanups=[],this.media=t,this.setupReactiveMediaEvents()}play(){return t(this,void 0,void 0,(function*(){try{return yield this.media.play()}catch(t){if(t instanceof DOMException&&"AbortError"===t.name)return;throw t}}))}pause(){this.media.pause()}isPlaying(){return!this.media.paused&&!this.media.ended}setTime(t){this.media.currentTime=Math.max(0,Math.min(t,this.getDuration()))}getDuration(){return this.media.duration}getCurrentTime(){return this.media.currentTime}getVolume(){return this.media.volume}setVolume(t){this.media.volume=t}getMuted(){return this.media.muted}setMuted(t){this.media.muted=t}getPlaybackRate(){return this.media.playbackRate}isSeeking(){return this.media.seeking}setPlaybackRate(t,e){null!=e&&(this.media.preservesPitch=e),this.media.playbackRate=t}getMediaElement(){return this.media}setSinkId(t){return this.media.setSinkId(t)}}function d({maxTop:t,maxBottom:e,halfHeight:i,vScale:n,barMinHeight:s=0,barAlign:r}){let o=Math.round(t*i*n);let a=o+Math.round(e*i*n)||1;return a<s&&(a=s,r||(o=a/2)),{topHeight:o,totalHeight:a}}function p({barAlign:t,halfHeight:e,topHeight:i,totalHeight:n,canvasHeight:s}){return"top"===t?0:"bottom"===t?s-n:e-i}function m(t,e,i){const n=e-t.left,s=i-t.top;return[n/t.width,s/t.height]}function g(t){return Boolean(t.barWidth||t.barGap||t.barAlign)}function f(t,e){if(!g(e))return t;const i=e.barWidth||.5,n=i+(e.barGap||i/2);return 0===n?t:Math.floor(t/n)*n}function v({scrollLeft:t,totalWidth:e,numCanvases:i}){if(0===e)return[0];const n=t/e,s=Math.floor(n*i);return[s-1,s,s+1]}function b(t){const e=t._cleanup;"function"==typeof e&&e()}function y(t){const e=l({scrollLeft:t.scrollLeft,scrollWidth:t.scrollWidth,clientWidth:t.clientWidth}),i=h((()=>function(t){const{scrollLeft:e,scrollWidth:i,clientWidth:n}=t;if(0===i)return{startX:0,endX:1};const s=e/i,r=(e+n)/i;return{startX:Math.max(0,Math.min(1,s)),endX:Math.max(0,Math.min(1,r))}}(e.value)),[e]),n=h((()=>function(t){return{left:t.scrollLeft,right:t.scrollLeft+t.clientWidth}}(e.value)),[e]),s=()=>{e.set({scrollLeft:t.scrollLeft,scrollWidth:t.scrollWidth,clientWidth:t.clientWidth})};t.addEventListener("scroll",s,{passive:!0});return{scrollData:e,percentages:i,bounds:n,cleanup:()=>{t.removeEventListener("scroll",s),b(e)}}}class C extends e{constructor(t,e){super(),this.timeouts=[],this.isScrollable=!1,this.audioData=null,this.resizeObserver=null,this.lastContainerWidth=0,this.isDragging=!1,this.subscriptions=[],this.unsubscribeOnScroll=[],this.dragStream=null,this.scrollStream=null,this.containerInlinePadding=0,this.onClickWrapper=t=>{const e=this.wrapper.getBoundingClientRect(),[i,n]=m(e,t.clientX,t.clientY);this.emit("click",i,n)},this.onDblClickWrapper=t=>{const e=this.wrapper.getBoundingClientRect(),[i,n]=m(e,t.clientX,t.clientY);this.emit("dblclick",i,n)},this.subscriptions=[],this.options=t;const i=this.parentFromOptionsContainer(t.container);this.parent=i;const[n,s]=this.initHtml();i.appendChild(n),this.container=n,this.scrollContainer=s.querySelector(".scroll"),this.wrapper=s.querySelector(".wrapper"),this.canvasWrapper=s.querySelector(".canvases"),this.progressWrapper=s.querySelector(".progress"),this.cursor=s.querySelector(".cursor"),this.calculateInlinePadding(),e&&s.appendChild(e),this.initEvents()}parentFromOptionsContainer(t){let e;if("string"==typeof t?e=document.querySelector(t):r(t)&&(e=t),!e)throw new Error("Container not found");return e}initEvents(){this.wrapper.addEventListener("click",this.onClickWrapper),this.wrapper.addEventListener("dblclick",this.onDblClickWrapper),!0!==this.options.dragToSeek&&"object"!=typeof this.options.dragToSeek||this.initDrag(),this.scrollStream=y(this.scrollContainer);const t=c((()=>{const{startX:t,endX:e}=this.scrollStream.percentages.value,{left:i,right:n}=this.scrollStream.bounds.value;this.emit("scroll",t,e,i,n)}),[this.scrollStream.percentages,this.scrollStream.bounds]);if(this.subscriptions.push(t),"function"==typeof ResizeObserver){const t=this.createDelay(100);this.resizeObserver=new ResizeObserver((()=>{t().then((()=>this.onContainerResize())).catch((()=>{}))})),this.resizeObserver.observe(this.scrollContainer)}}onContainerResize(){const t=this.parent.clientWidth;this.calculateInlinePadding(),t===this.lastContainerWidth&&"auto"!==this.options.height||(this.lastContainerWidth=t,this.reRender(),this.emit("resize"))}initDrag(){if(this.dragStream)return;this.dragStream=function(t,e={}){const{threshold:i=3,mouseButton:n=0,touchDelay:s=100}=e,r=l(null),o=new Map,a=matchMedia("(pointer: coarse)").matches;let h=()=>{};const c=e=>{if(e.button!==n)return;if(o.has(e.pointerId))return;if(o.set(e.pointerId,e),o.size>1)return;const l=e.pointerId;let c=e.clientX,u=e.clientY,d=!1;const p=Date.now(),m=t.getBoundingClientRect(),{left:g,top:f}=m,v=t=>{if(t.pointerId!==l)return;if(t.defaultPrevented||o.size>1)return;if(a&&Date.now()-p<s)return;const e=t.clientX,n=t.clientY,h=e-c,m=n-u;(d||Math.abs(h)>i||Math.abs(m)>i)&&(t.preventDefault(),t.stopPropagation(),d||(r.set({type:"start",x:c-g,y:u-f}),d=!0),r.set({type:"move",x:e-g,y:n-f,deltaX:h,deltaY:m}),c=e,u=n)},b=t=>{if(o.delete(t.pointerId)){if(t.pointerId===l&&d){const e=t.clientX,i=t.clientY;r.set({type:"end",x:e-g,y:i-f})}0===o.size&&h()}},y=t=>{t.relatedTarget&&t.relatedTarget!==document.documentElement||b(t)},C=t=>{d&&(t.stopPropagation(),t.preventDefault())},S=t=>{t.defaultPrevented||o.size>1||d&&t.preventDefault()};document.addEventListener("pointermove",v),document.addEventListener("pointerup",b),document.addEventListener("pointerout",y),document.addEventListener("pointercancel",y),document.addEventListener("touchmove",S,{passive:!1}),document.addEventListener("click",C,{capture:!0}),h=()=>{document.removeEventListener("pointermove",v),document.removeEventListener("pointerup",b),document.removeEventListener("pointerout",y),document.removeEventListener("pointercancel",y),document.removeEventListener("touchmove",S),setTimeout((()=>{document.removeEventListener("click",C,{capture:!0})}),10)}};return t.addEventListener("pointerdown",c),{signal:r,cleanup:()=>{h(),t.removeEventListener("pointerdown",c),o.clear(),b(r)}}}(this.wrapper);const t=c((()=>{const t=this.dragStream.signal.value;if(!t)return;const e=this.wrapper.getBoundingClientRect().width,i=(n=t.x/e)<0?0:n>1?1:n;var n;"start"===t.type?(this.isDragging=!0,this.emit("dragstart",i)):"move"===t.type?this.emit("drag",i):"end"===t.type&&(this.isDragging=!1,this.emit("dragend",i))}),[this.dragStream.signal]);this.subscriptions.push(t)}calculateInlinePadding(){const{paddingLeft:t,paddingRight:e}=getComputedStyle(this.scrollContainer),i=parseFloat(t)+parseFloat(e);this.containerInlinePadding=Number.isNaN(i)?0:i}initHtml(){const t=document.createElement("div"),e=t.attachShadow({mode:"open"}),i=this.options.cspNonce&&"string"==typeof this.options.cspNonce?this.options.cspNonce.replace(/"/g,""):"";return e.innerHTML=`\n <style${i?` nonce="${i}"`:""}>\n :host {\n user-select: none;\n min-width: 1px;\n }\n :host audio {\n display: block;\n width: 100%;\n }\n :host .scroll {\n overflow-x: auto;\n overflow-y: hidden;\n width: 100%;\n position: relative;\n }\n :host .noScrollbar {\n scrollbar-color: transparent;\n scrollbar-width: none;\n }\n :host .noScrollbar::-webkit-scrollbar {\n display: none;\n -webkit-appearance: none;\n }\n :host .wrapper {\n position: relative;\n overflow: visible;\n z-index: 2;\n }\n :host .canvases {\n min-height: ${this.getHeight(this.options.height,this.options.splitChannels)}px;\n pointer-events: none;\n }\n :host .canvases > div {\n position: relative;\n }\n :host canvas {\n display: block;\n position: absolute;\n top: 0;\n image-rendering: pixelated;\n }\n :host .progress {\n pointer-events: none;\n position: absolute;\n z-index: 2;\n top: 0;\n left: 0;\n width: 0;\n height: 100%;\n overflow: hidden;\n }\n :host .progress > div {\n position: relative;\n }\n :host .cursor {\n pointer-events: none;\n position: absolute;\n z-index: 5;\n top: 0;\n left: 0;\n height: 100%;\n border-radius: 2px;\n }\n </style>\n\n <div class="scroll" part="scroll">\n <div class="wrapper" part="wrapper">\n <div class="canvases" part="canvases"></div>\n <div class="progress" part="progress"></div>\n <div class="cursor" part="cursor"></div>\n </div>\n </div>\n `,[t,e]}setOptions(t){var e;if(this.options.container!==t.container){const e=this.parentFromOptionsContainer(t.container);e.appendChild(this.container),this.parent=e}!0===t.dragToSeek||"object"==typeof this.options.dragToSeek?this.initDrag():(null===(e=this.dragStream)||void 0===e||e.cleanup(),this.dragStream=null),this.options=t,this.reRender()}getWrapper(){return this.wrapper}getWidth(){return this.scrollContainer.clientWidth-this.containerInlinePadding}getScroll(){return this.scrollContainer.scrollLeft}setScroll(t){this.scrollContainer.scrollLeft=t}setScrollPercentage(t){const{scrollWidth:e}=this.scrollContainer,i=e*t;this.setScroll(i)}destroy(){var t;this.wrapper.removeEventListener("click",this.onClickWrapper),this.wrapper.removeEventListener("dblclick",this.onDblClickWrapper),this.timeouts.forEach((t=>t())),this.timeouts=[],this.subscriptions.forEach((t=>t())),this.container.remove(),this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null),null===(t=this.unsubscribeOnScroll)||void 0===t||t.forEach((t=>t())),this.unsubscribeOnScroll=[],this.dragStream&&(this.dragStream.cleanup(),this.dragStream=null),this.scrollStream&&(this.scrollStream.cleanup(),this.scrollStream=null)}createDelay(t=10){let e,i;const n=()=>{e&&(clearTimeout(e),e=void 0),i&&(i(),i=void 0)};return this.timeouts.push(n),()=>new Promise(((s,r)=>{n(),i=r,e=setTimeout((()=>{e=void 0,i=void 0,s()}),t)}))}getHeight(t,e){var i;const n=(null===(i=this.audioData)||void 0===i?void 0:i.numberOfChannels)||1;return function({optionsHeight:t,optionsSplitChannels:e,parentHeight:i,numberOfChannels:n,defaultHeight:s=128}){if(null==t)return s;const r=Number(t);if(!isNaN(r))return r;if("auto"===t){const t=i||s;return(null==e?void 0:e.every((t=>!t.overlay)))?t/n:t}return s}({optionsHeight:t,optionsSplitChannels:e,parentHeight:this.parent.clientHeight,numberOfChannels:n,defaultHeight:128})}convertColorValues(t,e){return function(t,e,i){if(!Array.isArray(t))return t||"";if(0===t.length)return"#999";if(t.length<2)return t[0]||"";const n=document.createElement("canvas"),s=n.getContext("2d");if(!s)return t[0]||"";const r=i||n.height*e,o=s.createLinearGradient(0,0,0,r),a=1/(t.length-1);return t.forEach(((t,e)=>{o.addColorStop(e*a,t)})),o}(t,this.getPixelRatio(),null==e?void 0:e.canvas.height)}getPixelRatio(){return t=window.devicePixelRatio,Math.max(1,t||1);// removed by dead control flow
4969
4995
  var t; }renderBarWaveform(t,e,i,n){const{width:s,height:r}=i.canvas,{halfHeight:o,barWidth:a,barRadius:l,barIndexScale:h,barSpacing:c,barMinHeight:u}=function({width:t,height:e,length:i,options:n,pixelRatio:s}){const r=e/2,o=n.barWidth?n.barWidth*s:1,a=n.barGap?n.barGap*s:n.barWidth?o/2:0,l=o+a||1;return{halfHeight:r,barWidth:o,barGap:a,barRadius:n.barRadius||0,barMinHeight:n.barMinHeight?n.barMinHeight*s:0,barIndexScale:i>0?t/l/i:0,barSpacing:l}}({width:s,height:r,length:(t[0]||[]).length,options:e,pixelRatio:this.getPixelRatio()}),m=function({channelData:t,barIndexScale:e,barSpacing:i,barWidth:n,halfHeight:s,vScale:r,canvasHeight:o,barAlign:a,barMinHeight:l}){const h=t[0]||[],c=t[1]||h,u=h.length,m=[];let g=0,f=0,v=0;for(let t=0;t<=u;t++){const u=Math.round(t*e);if(u>g){const{topHeight:t,totalHeight:e}=d({maxTop:f,maxBottom:v,halfHeight:s,vScale:r,barMinHeight:l,barAlign:a}),h=p({barAlign:a,halfHeight:s,topHeight:t,totalHeight:e,canvasHeight:o});m.push({x:g*i,y:h,width:n,height:e}),g=u,f=0,v=0}const b=Math.abs(h[t]||0),y=Math.abs(c[t]||0);b>f&&(f=b),y>v&&(v=y)}return m}({channelData:t,barIndexScale:h,barSpacing:c,barWidth:a,halfHeight:o,vScale:n,canvasHeight:r,barAlign:e.barAlign,barMinHeight:u});i.beginPath();for(const t of m)l&&"roundRect"in i?i.roundRect(t.x,t.y,t.width,t.height,l):i.rect(t.x,t.y,t.width,t.height);i.fill(),i.closePath()}renderLineWaveform(t,e,i,n){const{width:s,height:r}=i.canvas,o=function({channelData:t,width:e,height:i,vScale:n}){const s=i/2,r=t[0]||[];return[r,t[1]||r].map(((t,i)=>{const r=t.length,o=r?e/r:0,a=s,l=0===i?-1:1,h=[{x:0,y:a}];let c=0,u=0;for(let e=0;e<=r;e++){const i=Math.round(e*o);if(i>c){const t=a+(Math.round(u*s*n)||1)*l;h.push({x:c,y:t}),c=i,u=0}const r=Math.abs(t[e]||0);r>u&&(u=r)}return h.push({x:c,y:a}),h}))}({channelData:t,width:s,height:r,vScale:n});i.beginPath();for(const t of o)if(t.length){i.moveTo(t[0].x,t[0].y);for(let e=1;e<t.length;e++){const n=t[e];i.lineTo(n.x,n.y)}}i.fill(),i.closePath()}renderWaveform(t,e,i){if(i.fillStyle=this.convertColorValues(e.waveColor,i),e.renderFunction)return void e.renderFunction(t,i);const n=function({channelData:t,barHeight:e,normalize:i,maxPeak:n}){var s;const r=e||1;if(!i)return r;const o=t[0];if(!o||0===o.length)return r;let a=null!=n?n:0;if(!n)for(let t=0;t<o.length;t++){const e=null!==(s=o[t])&&void 0!==s?s:0,i=Math.abs(e);i>a&&(a=i)}return a?r/a:r}({channelData:t,barHeight:e.barHeight,normalize:e.normalize,maxPeak:e.maxPeak});g(e)?this.renderBarWaveform(t,e,i,n):this.renderLineWaveform(t,e,i,n)}renderSingleCanvas(t,e,i,n,s,r,o){const a=this.getPixelRatio(),l=document.createElement("canvas");l.width=Math.round(i*a),l.height=Math.round(n*a),l.style.width=`${i}px`,l.style.height=`${n}px`,l.style.left=`${Math.round(s)}px`,r.appendChild(l);const h=l.getContext("2d");if(e.renderFunction?(h.fillStyle=this.convertColorValues(e.waveColor,h),e.renderFunction(t,h)):this.renderWaveform(t,e,h),l.width>0&&l.height>0){const t=l.cloneNode(),i=t.getContext("2d");i.drawImage(l,0,0),i.globalCompositeOperation="source-in",i.fillStyle=this.convertColorValues(e.progressColor,i),i.fillRect(0,0,l.width,l.height),o.appendChild(t)}}renderMultiCanvas(t,e,i,n,s,r){const o=this.getPixelRatio(),{clientWidth:a}=this.scrollContainer,l=i/o,h=function({clientWidth:t,totalWidth:e,options:i}){return f(Math.min(8e3,t,e),i)}({clientWidth:a,totalWidth:l,options:e});let c={};if(0===h)return;const u=i=>{if(i<0||i>=d)return;if(c[i])return;c[i]=!0;const o=i*h;let a=Math.min(l-o,h);if(a=f(a,e),a<=0)return;const u=function({channelData:t,offset:e,clampedWidth:i,totalWidth:n}){return t.map((t=>{const s=Math.floor(e/n*t.length),r=Math.floor((e+i)/n*t.length);return t.slice(s,r)}))}({channelData:t,offset:o,clampedWidth:a,totalWidth:l});this.renderSingleCanvas(u,e,a,n,o,s,r)},d=Math.ceil(l/h);if(!this.isScrollable){for(let t=0;t<d;t++)u(t);return}if(v({scrollLeft:this.scrollContainer.scrollLeft,totalWidth:l,numCanvases:d}).forEach((t=>u(t))),d>1){const t=this.on("scroll",(()=>{const{scrollLeft:t}=this.scrollContainer;Object.keys(c).length>10&&(s.innerHTML="",r.innerHTML="",c={}),v({scrollLeft:t,totalWidth:l,numCanvases:d}).forEach((t=>u(t)))}));this.unsubscribeOnScroll.push(t)}}renderChannel(t,e,i,n){var{overlay:s}=e,r=function(t,e){var i={};for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&e.indexOf(n)<0&&(i[n]=t[n]);if(null!=t&&"function"==typeof Object.getOwnPropertySymbols){var s=0;for(n=Object.getOwnPropertySymbols(t);s<n.length;s++)e.indexOf(n[s])<0&&Object.prototype.propertyIsEnumerable.call(t,n[s])&&(i[n[s]]=t[n[s]])}return i}(e,["overlay"]);const o=document.createElement("div"),a=this.getHeight(r.height,r.splitChannels);o.style.height=`${a}px`,s&&n>0&&(o.style.marginTop=`-${a}px`),this.canvasWrapper.style.minHeight=`${a}px`,this.canvasWrapper.appendChild(o);const l=o.cloneNode();this.progressWrapper.appendChild(l),this.renderMultiCanvas(t,r,i,a,o,l)}render(e){return t(this,void 0,void 0,(function*(){var t;this.timeouts.forEach((t=>t())),this.timeouts=[],this.unsubscribeOnScroll.forEach((t=>t())),this.unsubscribeOnScroll=[],this.canvasWrapper.innerHTML="",this.progressWrapper.innerHTML="",null!=this.options.width&&(this.scrollContainer.style.width="number"==typeof this.options.width?`${this.options.width}px`:this.options.width);const i=this.getPixelRatio(),n=this.scrollContainer.clientWidth-this.containerInlinePadding,{scrollWidth:s,isScrollable:r,useParentWidth:o,width:a}=function({duration:t,minPxPerSec:e=0,parentWidth:i,fillParent:n,pixelRatio:s}){const r=Math.ceil(t*e),o=r>i,a=Boolean(n&&!o);return{scrollWidth:r,isScrollable:o,useParentWidth:a,width:(a?i:r)*s}}({duration:e.duration,minPxPerSec:this.options.minPxPerSec||0,parentWidth:n,fillParent:this.options.fillParent,pixelRatio:i});if(this.isScrollable=r,this.wrapper.style.width=o?"100%":`${s}px`,this.scrollContainer.style.overflowX=this.isScrollable?"auto":"hidden",this.scrollContainer.classList.toggle("noScrollbar",!!this.options.hideScrollbar),this.cursor.style.backgroundColor=`${this.options.cursorColor||this.options.progressColor}`,this.cursor.style.width=`${this.options.cursorWidth}px`,this.audioData=e,this.emit("render"),this.options.splitChannels)for(let i=0;i<e.numberOfChannels;i++){const n=Object.assign(Object.assign({},this.options),null===(t=this.options.splitChannels)||void 0===t?void 0:t[i]);this.renderChannel([e.getChannelData(i)],n,a,i)}else{const t=[e.getChannelData(0)];e.numberOfChannels>1&&t.push(e.getChannelData(1)),this.renderChannel(t,this.options,a,0)}Promise.resolve().then((()=>this.emit("rendered")))}))}reRender(){if(this.unsubscribeOnScroll.forEach((t=>t())),this.unsubscribeOnScroll=[],!this.audioData)return;const{scrollWidth:t}=this.scrollContainer,{right:e}=this.progressWrapper.getBoundingClientRect();if(this.render(this.audioData),!this.isScrollable&&this.scrollContainer.scrollLeft)this.scrollContainer.scrollLeft=0;else if(this.isScrollable&&t!==this.scrollContainer.scrollWidth){const{right:t}=this.progressWrapper.getBoundingClientRect(),i=function(t){const e=2*t;return(e<0?Math.floor(e):Math.ceil(e))/2}(t-e);this.scrollContainer.scrollLeft+=i}}zoom(t){this.options.minPxPerSec=t,this.reRender()}scrollIntoView(t,e=!1){var i;const{scrollLeft:n,scrollWidth:s,clientWidth:r}=this.scrollContainer,o=t*s,a=n,l=n+r,h=r/2;if(this.isDragging){const t=30;o+t>l?this.scrollContainer.scrollLeft+=t:o-t<a&&(this.scrollContainer.scrollLeft-=t)}else{(o<a||o>l)&&(this.scrollContainer.scrollLeft=o-(this.options.autoCenter?h:0));const t=o-n-h;if(e&&this.options.autoCenter&&t>0){const e=null===(i=this.audioData)||void 0===i?void 0:i.duration;if(void 0===e||e<=0)return void(this.scrollContainer.scrollLeft+=t);const n=s/e;this.scrollContainer.scrollLeft+=n<=600?Math.min(t,10):t}}}renderProgress(t,e){if(isNaN(t))return;const i=100*t;this.canvasWrapper.style.clipPath=`polygon(${i}% 0%, 100% 0%, 100% 100%, ${i}% 100%)`,this.progressWrapper.style.width=`${i}%`,this.cursor.style.left=`${i}%`,this.cursor.style.transform=this.options.cursorWidth?`translateX(-${t*this.options.cursorWidth}px)`:"",this.isScrollable&&this.options.autoScroll&&this.audioData&&this.audioData.duration>0&&this.scrollIntoView(t,e)}exportImage(e,i,n){return t(this,void 0,void 0,(function*(){const t=this.canvasWrapper.querySelectorAll("canvas");if(!t.length)throw new Error("No waveform data");if("dataURL"===n){const n=Array.from(t).map((t=>t.toDataURL(e,i)));return Promise.resolve(n)}return Promise.all(Array.from(t).map((t=>new Promise(((n,s)=>{t.toBlob((t=>{t?n(t):s(new Error("Could not export image"))}),e,i)})))))}))}}class S extends e{constructor(){super(...arguments),this.animationFrameId=null,this.isRunning=!1}start(){if(this.isRunning)return;this.isRunning=!0;const t=()=>{this.isRunning&&(this.emit("tick"),this.animationFrameId=requestAnimationFrame(t))};t()}stop(){this.isRunning=!1,null!==this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null)}destroy(){this.stop(),this.unAll()}}class E extends e{constructor(t){super(),this.bufferNode=null,this.playStartTime=0,this.playbackPosition=0,this._muted=!1,this._playbackRate=1,this._duration=void 0,this.buffer=null,this.currentSrc="",this.paused=!0,this.crossOrigin=null,this.seeking=!1,this.autoplay=!1,this.addEventListener=this.on,this.removeEventListener=this.un,this._destroyed=!1,function(){const t=globalThis.navigator;if(null==t?void 0:t.audioSession)try{t.audioSession.type="playback"}catch(t){console.warn("Setting navigator.audioSession.type failed:",t)}}(),this.audioContext=t||new AudioContext,this.gainNode=this.audioContext.createGain(),this.gainNode.connect(this.audioContext.destination)}load(){return t(this,void 0,void 0,(function*(){}))}remove(){this.destroy()}destroy(){if(!this._destroyed){if(this._destroyed=!0,this.currentSrc="",this.bufferNode){this.bufferNode.onended=null;try{this.bufferNode.stop()}catch(t){}this.bufferNode.disconnect(),this.bufferNode=null}this.gainNode.disconnect(),"function"==typeof this.audioContext.close&&Promise.resolve(this.audioContext.close.call(this.audioContext)).catch((()=>{})),this.buffer=null,this.unAll()}}get src(){return this.currentSrc}set src(t){if(this.currentSrc=t,this._duration=void 0,!t)return this.buffer=null,void this.emit("emptied");fetch(t).then((e=>{if(e.status>=400)throw new Error(`Failed to fetch ${t}: ${e.status} (${e.statusText})`);return e.arrayBuffer()})).then((e=>this.currentSrc!==t?null:this.audioContext.decodeAudioData(e))).then((e=>{this.currentSrc===t&&(this.buffer=e,this.emit("loadedmetadata"),this.emit("canplay"),this.autoplay&&this.play())})).catch((t=>{console.error("WebAudioPlayer load error:",t)}))}_play(){if(!this.paused)return;this.paused=!1,this.bufferNode&&(this.bufferNode.onended=null,this.bufferNode.disconnect()),this.bufferNode=this.audioContext.createBufferSource(),this.buffer&&(this.bufferNode.buffer=this.buffer),this.bufferNode.playbackRate.value=this._playbackRate,this.bufferNode.connect(this.gainNode);let t=this.playbackPosition;(t>=this.duration||t<0)&&(t=0,this.playbackPosition=0),this.bufferNode.start(this.audioContext.currentTime,t),this.playStartTime=this.audioContext.currentTime,this.bufferNode.onended=()=>{!this.paused&&this.duration-this.currentTime<.01&&(this.pause(),this.emit("ended"))}}_pause(){if(this.paused=!0,this.bufferNode){this.bufferNode.onended=null;try{this.bufferNode.stop()}catch(t){}}this.playbackPosition+=(this.audioContext.currentTime-this.playStartTime)*this._playbackRate}play(){return t(this,void 0,void 0,(function*(){this.paused&&(this._play(),this.emit("play"))}))}pause(){this.paused||(this._pause(),this.emit("pause"))}stopAt(t){const e=(t-this.currentTime)/this._playbackRate,i=this.bufferNode;null==i||i.stop(this.audioContext.currentTime+e),null==i||i.addEventListener("ended",(()=>{i===this.bufferNode&&(this.bufferNode=null,this.pause(),this.playbackPosition=Math.min(t,this.duration),this.emit("timeupdate"))}),{once:!0})}setSinkId(e){return t(this,void 0,void 0,(function*(){return this.audioContext.setSinkId(e)}))}get playbackRate(){return this._playbackRate}set playbackRate(t){const e=!this.paused;e&&this._pause(),this._playbackRate=t,e&&this._play(),this.bufferNode&&(this.bufferNode.playbackRate.value=t)}get currentTime(){return this.paused?this.playbackPosition:this.playbackPosition+(this.audioContext.currentTime-this.playStartTime)*this._playbackRate}set currentTime(t){const e=!this.paused;e&&this._pause(),this.playbackPosition=t,e&&this._play(),this.emit("seeking"),this.emit("timeupdate")}get duration(){var t,e;return null!==(t=this._duration)&&void 0!==t?t:(null===(e=this.buffer)||void 0===e?void 0:e.duration)||0}set duration(t){this._duration=t}get volume(){return this.gainNode.gain.value}set volume(t){this.gainNode.gain.value=t,this.emit("volumechange")}get muted(){return this._muted}set muted(t){this._muted!==t&&(this._muted=t,this._muted?this.gainNode.disconnect():this.gainNode.connect(this.audioContext.destination))}canPlayType(t){return/^(audio|video)\//.test(t)}getGainNode(){return this.gainNode}getChannelData(){const t=[];if(!this.buffer)return t;const e=this.buffer.numberOfChannels;for(let i=0;i<e;i++)t.push(this.buffer.getChannelData(i));return t}removeAttribute(t){switch(t){case"src":this.src="";break;case"playbackRate":this.playbackRate=0;break;case"currentTime":this.currentTime=0;break;case"duration":this.duration=0;break;case"volume":this.volume=0;break;case"muted":this.muted=!1}}}const P={waveColor:"#999",progressColor:"#555",cursorWidth:1,minPxPerSec:0,fillParent:!0,interact:!0,dragToSeek:!1,autoScroll:!0,autoCenter:!0,sampleRate:8e3};class w extends u{static create(t){return new w(t)}getState(){return this.wavesurferState}getRenderer(){return this.renderer}constructor(t){const e=t.media||("WebAudio"===t.backend?new E:void 0);super({media:e,mediaControls:t.mediaControls,autoplay:t.autoplay,playbackRate:t.audioRate}),this.plugins=[],this.decodedData=null,this.stopAtPosition=null,this.subscriptions=[],this.mediaSubscriptions=[],this.abortController=null,this._isDestroyed=!1,this._loadVersion=0,this.reactiveCleanups=[],this.options=Object.assign({},P,t);const{state:i,actions:n}=function(t){var e,i,n,s,r,o;const a=null!==(e=null==t?void 0:t.currentTime)&&void 0!==e?e:l(0),c=null!==(i=null==t?void 0:t.duration)&&void 0!==i?i:l(0),u=null!==(n=null==t?void 0:t.isPlaying)&&void 0!==n?n:l(!1),d=null!==(s=null==t?void 0:t.isSeeking)&&void 0!==s?s:l(!1),p=null!==(r=null==t?void 0:t.volume)&&void 0!==r?r:l(1),m=null!==(o=null==t?void 0:t.playbackRate)&&void 0!==o?o:l(1),g=l(null),f=l(null),v=l(""),b=l(0),y=l(0),C=h((()=>!u.value),[u]),S=h((()=>null!==g.value),[g]),E=h((()=>S.value&&c.value>0),[S,c]),P=h((()=>a.value),[a]),w=h((()=>c.value>0?a.value/c.value:0),[a,c]);return{state:{currentTime:a,duration:c,isPlaying:u,isPaused:C,isSeeking:d,volume:p,playbackRate:m,audioBuffer:g,peaks:f,url:v,zoom:b,scrollPosition:y,canPlay:S,isReady:E,progress:P,progressPercent:w},actions:{setCurrentTime:t=>{const e=Math.max(0,Math.min(c.value||1/0,t));a.set(e)},setDuration:t=>{c.set(Math.max(0,t))},setPlaying:t=>{u.set(t)},setSeeking:t=>{d.set(t)},setVolume:t=>{const e=Math.max(0,Math.min(1,t));p.set(e)},setPlaybackRate:t=>{const e=Math.max(.1,Math.min(16,t));m.set(e)},setAudioBuffer:t=>{g.set(t),t&&c.set(t.duration)},setPeaks:t=>{f.set(t)},setUrl:t=>{v.set(t)},setZoom:t=>{b.set(Math.max(0,t))},setScrollPosition:t=>{y.set(Math.max(0,t))}}}}({isPlaying:this.isPlayingSignal,currentTime:this.currentTimeSignal,duration:this.durationSignal,volume:this.volumeSignal,playbackRate:this.playbackRateSignal,isSeeking:this.seekingSignal});this.wavesurferState=i,this.wavesurferActions=n,this.timer=new S;const s=e?void 0:this.getMediaElement();this.renderer=new C(this.options,s),this.initPlayerEvents(),this.initRendererEvents(),this.initTimerEvents(),this.initReactiveState(),this.initPlugins();const r=this.options.url||this.getSrc()||"";Promise.resolve().then((()=>{this.emit("init");const{peaks:t,duration:e}=this.options;(r||t&&e)&&this.load(r,t,e).catch((()=>{}))}))}updateProgress(t=this.getCurrentTime()){return this.renderer.renderProgress(t/this.getDuration(),this.isPlaying()),t}initTimerEvents(){this.subscriptions.push(this.timer.on("tick",(()=>{if(!this.isSeeking()){const t=this.updateProgress();if(this.emit("timeupdate",t),this.emit("audioprocess",t),null!=this.stopAtPosition&&this.isPlaying()&&t>=this.stopAtPosition){const t=this.stopAtPosition;this.pause(),this.setTime(t)}}})))}initReactiveState(){this.reactiveCleanups.push(function(t,e){const i=[];i.push(c((()=>{const i=t.isPlaying.value;e.emit(i?"play":"pause")}),[t.isPlaying])),i.push(c((()=>{const i=t.currentTime.value;e.emit("timeupdate",i),t.isPlaying.value&&e.emit("audioprocess",i)}),[t.currentTime,t.isPlaying])),i.push(c((()=>{t.isSeeking.value&&e.emit("seeking",t.currentTime.value)}),[t.isSeeking,t.currentTime]));let n=!1;i.push(c((()=>{t.isReady.value&&!n&&(n=!0,e.emit("ready",t.duration.value))}),[t.isReady,t.duration])),i.push(c((()=>{null===t.audioBuffer.value&&(n=!1)}),[t.audioBuffer]));let s=!1;return i.push(c((()=>{const i=t.isPlaying.value,n=t.currentTime.value,r=t.duration.value,o=r>0&&n>=r;s&&!i&&o&&e.emit("finish"),s=i&&o}),[t.isPlaying,t.currentTime,t.duration])),i.push(c((()=>{const i=t.zoom.value;i>0&&e.emit("zoom",i)}),[t.zoom])),()=>{i.forEach((t=>t()))}}(this.wavesurferState,{emit:this.emit.bind(this)}))}initPlayerEvents(){this.isPlaying()&&(this.emit("play"),this.timer.start()),this.mediaSubscriptions.push(this.onMediaEvent("timeupdate",(()=>{const t=this.updateProgress();this.emit("timeupdate",t)})),this.onMediaEvent("play",(()=>{this.emit("play"),this.timer.start()})),this.onMediaEvent("pause",(()=>{this.emit("pause"),this.timer.stop(),this.stopAtPosition=null})),this.onMediaEvent("emptied",(()=>{this.timer.stop(),this.stopAtPosition=null})),this.onMediaEvent("ended",(()=>{this.emit("timeupdate",this.getDuration()),this.emit("finish"),this.stopAtPosition=null})),this.onMediaEvent("seeking",(()=>{this.emit("seeking",this.getCurrentTime())})),this.onMediaEvent("error",(()=>{var t;this.emit("error",null!==(t=this.getMediaElement().error)&&void 0!==t?t:new Error("Media error")),this.stopAtPosition=null})))}initRendererEvents(){this.subscriptions.push(this.renderer.on("click",((t,e)=>{this.options.interact&&(this.seekTo(t),this.emit("interaction",t*this.getDuration()),this.emit("click",t,e))})),this.renderer.on("dblclick",((t,e)=>{this.emit("dblclick",t,e)})),this.renderer.on("scroll",((t,e,i,n)=>{const s=this.getDuration();this.emit("scroll",t*s,e*s,i,n)})),this.renderer.on("render",(()=>{this.emit("redraw")})),this.renderer.on("rendered",(()=>{this.emit("redrawcomplete")})),this.renderer.on("dragstart",(t=>{this.emit("dragstart",t)})),this.renderer.on("dragend",(t=>{this.emit("dragend",t)})),this.renderer.on("resize",(()=>{this.emit("resize")})));{let t;const e=this.renderer.on("drag",(e=>{var i;if(!this.options.interact)return;this.renderer.renderProgress(e),clearTimeout(t);let n=0;const s=this.options.dragToSeek;this.isPlaying()?n=0:!0===s?n=200:s&&"object"==typeof s&&(n=null!==(i=s.debounceTime)&&void 0!==i?i:200),t=setTimeout((()=>{this.seekTo(e)}),n),this.emit("interaction",e*this.getDuration()),this.emit("drag",e)}));this.subscriptions.push((()=>{clearTimeout(t),e()}))}}initPlugins(){var t;(null===(t=this.options.plugins)||void 0===t?void 0:t.length)&&this.options.plugins.forEach((t=>{this.registerPlugin(t)}))}unsubscribePlayerEvents(){this.mediaSubscriptions.forEach((t=>t())),this.mediaSubscriptions=[]}setOptions(t){this.options=Object.assign({},this.options,t),t.duration&&!t.peaks&&(this.decodedData=i.createBuffer(this.exportPeaks(),t.duration)),t.peaks&&t.duration&&(this.decodedData=i.createBuffer(t.peaks,t.duration)),this.renderer.setOptions(this.options),t.audioRate&&this.setPlaybackRate(t.audioRate),null!=t.mediaControls&&(this.getMediaElement().controls=t.mediaControls)}registerPlugin(t){if(this.plugins.includes(t))return t;t._init(this),this.plugins.push(t);const e=t.once("destroy",(()=>{this.plugins=this.plugins.filter((e=>e!==t)),this.subscriptions=this.subscriptions.filter((t=>t!==e))}));return this.subscriptions.push(e),t}unregisterPlugin(t){this.plugins=this.plugins.filter((e=>e!==t)),t.destroy()}getWrapper(){return this.renderer.getWrapper()}getWidth(){return this.renderer.getWidth()}getScroll(){return this.renderer.getScroll()}setScroll(t){return this.renderer.setScroll(t)}setScrollTime(t){const e=t/this.getDuration();this.renderer.setScrollPercentage(e)}getActivePlugins(){return this.plugins}loadAudio(e,n,s,r){return t(this,void 0,void 0,(function*(){var t;const o=++this._loadVersion;if(this._isDestroyed=!1,this.emit("load",e),!this.options.media&&this.isPlaying()&&this.pause(),this.decodedData=null,this.stopAtPosition=null,null===(t=this.abortController)||void 0===t||t.abort(),this.abortController=null,!n&&!s){const t=this.options.fetchParams||{};window.AbortController&&!t.signal&&(this.abortController=new AbortController,t.signal=this.abortController.signal);const i=t=>this.emit("loading",t);if(n=yield a.fetchBlob(e,i,t),this._isDestroyed||o!==this._loadVersion)return;const s=this.options.blobMimeType;s&&(n=new Blob([n],{type:s}))}if(this._isDestroyed||o!==this._loadVersion)return;this.setSrc(e,n);const l=yield new Promise((t=>{const e=r||this.getDuration();e?t(e):this.mediaSubscriptions.push(this.onMediaEvent("loadedmetadata",(()=>t(this.getDuration())),{once:!0}))}));if(!this._isDestroyed&&o===this._loadVersion){if(!e&&!n){const t=this.getMediaElement();t instanceof E&&(t.duration=l)}if(s)this.decodedData=i.createBuffer(s,l||0);else if(n){const t=yield n.arrayBuffer();if(this._isDestroyed||o!==this._loadVersion)return;this.decodedData=yield i.decode(t,this.options.sampleRate)}this._isDestroyed||o!==this._loadVersion||(this.decodedData&&(this.emit("decode",this.getDuration()),this.renderer.render(this.decodedData)),this.emit("ready",this.getDuration()))}}))}load(e,i,n){return t(this,void 0,void 0,(function*(){try{return yield this.loadAudio(e,void 0,i,n)}catch(t){throw this.emit("error",t),t}}))}loadBlob(e,i,n){return t(this,void 0,void 0,(function*(){try{return yield this.loadAudio("",e,i,n)}catch(t){throw this.emit("error",t),t}}))}zoom(t){if(!this.decodedData)throw new Error("No audio loaded");this.renderer.zoom(t),this.emit("zoom",t)}getDecodedData(){return this.decodedData}exportPeaks({channels:t=2,maxLength:e=8e3,precision:i=1e4}={}){if(!this.decodedData)throw new Error("The audio has not been decoded yet");const n=Math.min(t,this.decodedData.numberOfChannels),s=[];for(let t=0;t<n;t++){const n=this.decodedData.getChannelData(t),r=[],o=n.length/e;for(let t=0;t<e;t++){const e=n.slice(Math.floor(t*o),Math.ceil((t+1)*o));let s=0;for(let t=0;t<e.length;t++){const i=e[t];Math.abs(i)>Math.abs(s)&&(s=i)}r.push(Math.round(s*i)/i)}s.push(r)}return s}getDuration(){let t=super.getDuration()||0;return 0!==t&&t!==1/0||!this.decodedData||(t=this.decodedData.duration),t}toggleInteraction(t){this.options.interact=t}setTime(t){this.stopAtPosition=null,super.setTime(t),this.updateProgress(t),this.emit("timeupdate",t)}seekTo(t){const e=this.getDuration()*t;this.setTime(e)}play(e,i){const n=Object.create(null,{play:{get:()=>super.play}});return t(this,void 0,void 0,(function*(){null!=e&&this.setTime(e);const t=yield n.play.call(this);return null!=i&&(this.media instanceof E?this.media.stopAt(i):this.stopAtPosition=i),t}))}playPause(){return t(this,void 0,void 0,(function*(){return this.isPlaying()?this.pause():this.play()}))}stop(){this.pause(),this.setTime(0)}skip(t){this.setTime(this.getCurrentTime()+t)}empty(){this.load("",[[0]],.001)}setMediaElement(t){this.unsubscribePlayerEvents(),super.setMediaElement(t),this.initPlayerEvents()}exportImage(){return t(this,arguments,void 0,(function*(t="image/png",e=1,i="dataURL"){return this.renderer.exportImage(t,e,i)}))}destroy(){var t;this._isDestroyed=!0,this.emit("destroy"),null===(t=this.abortController)||void 0===t||t.abort(),this.plugins.forEach((t=>t.destroy())),this.subscriptions.forEach((t=>t())),this.unsubscribePlayerEvents(),this.reactiveCleanups.forEach((t=>t())),this.reactiveCleanups=[],this.timer.destroy(),this.renderer.destroy(),super.destroy()}}w.BasePlugin=class extends e{constructor(t){super(),this.subscriptions=[],this.isDestroyed=!1,this.options=t}onInit(){}_init(t){this.isDestroyed&&(this.subscriptions=[],this.isDestroyed=!1),this.wavesurfer=t,this.onInit()}destroy(){this.emit("destroy"),this.subscriptions.forEach((t=>t())),this.subscriptions=[],this.isDestroyed=!0,this.wavesurfer=void 0}},w.dom=o;
4970
4996
 
4971
- // EXTERNAL MODULE: ./src/lib/util.js + 1 modules
4972
- var util = __webpack_require__(4410);
4973
4997
  ;// ./src/lib/viewers/media/waveform/colors.ts
4974
4998
  /**
4975
4999
  * Figma Audio Player waveform tokens as opaque fills.
@@ -5606,10 +5630,10 @@ function usePlayheadCamera({
5606
5630
  };
5607
5631
  }
5608
5632
  ;// ./src/lib/viewers/controls/icons/IconComment24.tsx
5609
- function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
5633
+ function IconComment24_extends() { return IconComment24_extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, IconComment24_extends.apply(null, arguments); }
5610
5634
 
5611
5635
  function IconComment24(props) {
5612
- return /*#__PURE__*/external_react_.createElement("svg", _extends({
5636
+ return /*#__PURE__*/external_react_.createElement("svg", IconComment24_extends({
5613
5637
  "data-testid": "IconComment24",
5614
5638
  fill: "none",
5615
5639
  focusable: false,
@@ -5676,6 +5700,7 @@ const WaveformRangeSelection = /*#__PURE__*/(0,external_react_.forwardRef)(funct
5676
5700
  onPreviewChange,
5677
5701
  onRangeChange,
5678
5702
  range,
5703
+ readOnly = false,
5679
5704
  viewport
5680
5705
  }, ref) {
5681
5706
  const rootRef = (0,external_react_.useRef)(null);
@@ -5706,7 +5731,7 @@ const WaveformRangeSelection = /*#__PURE__*/(0,external_react_.forwardRef)(funct
5706
5731
  const durationMs = (0,waveform_range/* durationMsFromSec */.uH)(durationSec);
5707
5732
  const displayed = dragRange ?? (0,waveform_range/* resolveRange */.Ss)(range, durationMs);
5708
5733
  displayedRef.current = displayed;
5709
- const showCommentButton = Boolean(onDragCreate) && displayed.startMs !== displayed.endMs && activeHandle == null;
5734
+ const showCommentButton = !readOnly && Boolean(onDragCreate) && displayed.startMs !== displayed.endMs && activeHandle == null;
5710
5735
  const syncPositions = (0,external_react_.useCallback)((next, nextViewport, nextDurationSec) => {
5711
5736
  displayedRef.current = next;
5712
5737
  const collapsed = next.startMs === next.endMs;
@@ -5810,7 +5835,7 @@ const WaveformRangeSelection = /*#__PURE__*/(0,external_react_.forwardRef)(funct
5810
5835
  });
5811
5836
  }, [currentTimeSec, syncPositions]);
5812
5837
  const startDrag = (0,external_react_.useCallback)((handle, event) => {
5813
- if (!interactive || event.button > 1 || event.ctrlKey || event.metaKey) {
5838
+ if (readOnly || !interactive || event.button > 1 || event.ctrlKey || event.metaKey) {
5814
5839
  return;
5815
5840
  }
5816
5841
  event.preventDefault();
@@ -5834,7 +5859,7 @@ const WaveformRangeSelection = /*#__PURE__*/(0,external_react_.forwardRef)(funct
5834
5859
  endMs: (0,waveform_range/* isRangeCollapsed */.BT)(rangeRef.current) ? null : resolved.endMs,
5835
5860
  startMs: resolved.startMs
5836
5861
  });
5837
- }, [interactive]);
5862
+ }, [interactive, readOnly]);
5838
5863
  const onHandlePointerDown = (0,external_react_.useCallback)(event => {
5839
5864
  const root = rootRef.current;
5840
5865
  if (!root) {
@@ -5919,12 +5944,13 @@ const WaveformRangeSelection = /*#__PURE__*/(0,external_react_.forwardRef)(funct
5919
5944
  className: `bp-WaveformRange${keepHighlight ? ' bp-WaveformRange--persist' : ''}${highlight ? ' bp-WaveformRange--highlight' : ''}`,
5920
5945
  "data-collapsed": collapsed ? 'true' : 'false',
5921
5946
  "data-highlighted": highlight ? 'true' : 'false',
5947
+ "data-readonly": readOnly ? 'true' : 'false',
5922
5948
  "data-testid": "bp-waveform-range"
5923
5949
  }, /*#__PURE__*/external_react_["default"].createElement("div", {
5924
5950
  ref: regionRef,
5925
5951
  className: "bp-WaveformRange-region",
5926
5952
  "data-testid": "bp-waveform-range-region"
5927
- }), /*#__PURE__*/external_react_["default"].createElement("div", {
5953
+ }), !readOnly && /*#__PURE__*/external_react_["default"].createElement("div", {
5928
5954
  ref: startHandleRef,
5929
5955
  className: `bp-WaveformRange-handle bp-WaveformRange-handle--start${activeHandle === 'start' ? ' bp-WaveformRange-handle--dragging' : ''}`,
5930
5956
  "data-testid": "bp-waveform-range-handle-start",
@@ -5932,7 +5958,7 @@ const WaveformRangeSelection = /*#__PURE__*/(0,external_react_.forwardRef)(funct
5932
5958
  onPointerDown: onHandlePointerDown
5933
5959
  }, /*#__PURE__*/external_react_["default"].createElement("div", {
5934
5960
  className: "bp-WaveformRange-handleGrip"
5935
- })), /*#__PURE__*/external_react_["default"].createElement("div", {
5961
+ })), !readOnly && /*#__PURE__*/external_react_["default"].createElement("div", {
5936
5962
  ref: endHandleRef,
5937
5963
  className: `bp-WaveformRange-handle bp-WaveformRange-handle--end${activeHandle === 'end' ? ' bp-WaveformRange-handle--dragging' : ''}`,
5938
5964
  "data-testid": "bp-waveform-range-handle-end",
@@ -6129,6 +6155,7 @@ function WaveformView({
6129
6155
  onZoomChange,
6130
6156
  peaks,
6131
6157
  range = null,
6158
+ rangeReadOnly = false,
6132
6159
  zoomLevel: zoomLevelProp
6133
6160
  }) {
6134
6161
  // DOM / WaveSurfer
@@ -6945,6 +6972,7 @@ function WaveformView({
6945
6972
  }, []);
6946
6973
  const hoverLeft = isRangeDragging || hoverProgress == null ? null : (0,waveform_viewport/* timeLeftPercent */.Mu)(hoverProgress * durationSec, durationSec, viewportRef.current);
6947
6974
  const overlayRange = createRange ?? range;
6975
+ const isOverlayReadOnly = rangeReadOnly && createRange == null;
6948
6976
  const showRangeOverlay = Boolean(overlayRange) && (isRangeDragging || !isPlaying || !(0,waveform_range/* isRangeCollapsed */.BT)(overlayRange));
6949
6977
  const scrubTimeChip = isTape && scrubPreviewTimeSec != null ? /*#__PURE__*/external_react_["default"].createElement("div", {
6950
6978
  className: "bp-WaveformView-hover bp-WaveformView-hover--tape",
@@ -6993,14 +7021,15 @@ function WaveformView({
6993
7021
  currentTimeSec: currentTime,
6994
7022
  durationSec: durationSec,
6995
7023
  getPlayheadSec: getPlayheadSec,
6996
- interactive: interactive,
7024
+ interactive: interactive && !isOverlayReadOnly,
6997
7025
  isHighlighted: isRangeDragging || isRangeHovered,
6998
7026
  keepHighlight: true,
6999
7027
  onDragChange: handleRangeDragChange,
7000
- onDragCreate: interactive && !isRangeDragging ? onRangeDragCreate : undefined,
7028
+ onDragCreate: interactive && !isRangeDragging && !isOverlayReadOnly ? onRangeDragCreate : undefined,
7001
7029
  onPreviewChange: setPreviewRange,
7002
- onRangeChange: interactive ? onRangeChange : undefined,
7030
+ onRangeChange: interactive && !isOverlayReadOnly ? onRangeChange : undefined,
7003
7031
  range: overlayRange,
7032
+ readOnly: isOverlayReadOnly,
7004
7033
  viewport: viewport
7005
7034
  }), hoverLeft != null && hoverProgress != null && !isRangeDragging && /*#__PURE__*/external_react_["default"].createElement("div", {
7006
7035
  className: "bp-WaveformView-hover",
@@ -7249,12 +7278,14 @@ function WaveformZoomControl({
7249
7278
 
7250
7279
 
7251
7280
 
7281
+
7252
7282
  const PLACEHOLDER_PEAKS = placeholderPeaks();
7253
7283
  function MP3ControlsV2({
7254
7284
  autoplay,
7255
7285
  bufferedRange,
7256
7286
  commentMarkers,
7257
7287
  commentRangeDraft = null,
7288
+ commentRangeReadOnly = null,
7258
7289
  currentTime,
7259
7290
  durationTime,
7260
7291
  hasStartedPlayback = false,
@@ -7278,6 +7309,8 @@ function MP3ControlsV2({
7278
7309
  peaks,
7279
7310
  playNext,
7280
7311
  rate,
7312
+ shuttleDirection = null,
7313
+ shuttleRate = 0,
7281
7314
  volume
7282
7315
  }) {
7283
7316
  const durationValue = typeof durationTime === 'number' && isFinite_default()(durationTime) ? durationTime : 0;
@@ -7293,7 +7326,7 @@ function MP3ControlsV2({
7293
7326
  const waveformDurationSec = hasWaveformDuration ? durationValue : PLACEHOLDER_DURATION_SEC;
7294
7327
  const [playRequested, setPlayRequested] = (0,external_react_.useState)(hasStartedPlayback);
7295
7328
  const [viewport, setViewport] = (0,external_react_.useState)(null);
7296
- const isTape = useTapeWaveform();
7329
+ const isTape = (0,useTapeWaveform/* default */.Ay)();
7297
7330
  const hasAppliedTapeDefaultZoomRef = (0,external_react_.useRef)(false); // ~10s window applied; reset to 1× when leaving tape
7298
7331
  const lastKeyboardZoomStepRef = (0,external_react_.useRef)(0); // last +/− step applied; skip re-step when maxZoom retriggers the effect
7299
7332
  const userChangedTapeZoomRef = (0,external_react_.useRef)(false); // pinch/wheel zoom; skip re-applying the 10s default
@@ -7362,6 +7395,8 @@ function MP3ControlsV2({
7362
7395
  // Overlay unmounts on click; without this, focus lands on body and Space is lost.
7363
7396
  mediaEl?.closest('.bp-media-container')?.focus();
7364
7397
  }, [mediaEl, onPlayPause]);
7398
+ const waveformRange = commentRangeDraft ?? commentRangeReadOnly;
7399
+ const isRangeReadOnly = commentRangeDraft == null && commentRangeReadOnly != null;
7365
7400
  const waveformMarkers = (0,external_react_.useMemo)(() => commentMarkers || [], [commentMarkers]);
7366
7401
  const selectedMarkerId = (0,external_react_.useMemo)(() => waveformMarkers.find(marker => marker.isSelected)?.id ?? null, [waveformMarkers]);
7367
7402
  const handleCommentMarkerClick = (0,external_react_.useCallback)(marker => {
@@ -7380,6 +7415,7 @@ function MP3ControlsV2({
7380
7415
  const hasZoomHandlers = hasRealPeaks && !showPlayOverlay;
7381
7416
  const hasZoomControl = hasZoomHandlers && hasMediaMetadata && maxZoom > constants/* WAVEFORM_ZOOM_MIN */.LW;
7382
7417
  const showGeneratingWaveformIndicator = isGeneratingWaveform && !hasRealPeaks;
7418
+ const showShuttle = !isTape && !!shuttleDirection && shuttleRate > 0;
7383
7419
  const waveformZoomLevel = isTape || hasZoomHandlers ? zoomLevel : constants/* WAVEFORM_ZOOM_MIN */.LW;
7384
7420
  return /*#__PURE__*/external_react_["default"].createElement("div", {
7385
7421
  className: "bp-MP3ControlsV2",
@@ -7405,7 +7441,8 @@ function MP3ControlsV2({
7405
7441
  onViewportChange: hasRealPeaks ? handleViewportChange : undefined,
7406
7442
  onZoomChange: hasZoomHandlers ? handleWaveformZoom : undefined,
7407
7443
  peaks: waveformPeaks,
7408
- range: commentRangeDraft,
7444
+ range: waveformRange,
7445
+ rangeReadOnly: isRangeReadOnly,
7409
7446
  zoomLevel: waveformZoomLevel
7410
7447
  }), /*#__PURE__*/external_react_["default"].createElement(WaveformCommentMarkers, {
7411
7448
  commentMarkers: waveformMarkers,
@@ -7414,7 +7451,10 @@ function MP3ControlsV2({
7414
7451
  onCommentMarkerClick: handleCommentMarkerClick,
7415
7452
  selectedId: selectedMarkerId,
7416
7453
  viewport: viewport
7417
- })), (showGeneratingWaveformIndicator || hasZoomControl) && /*#__PURE__*/external_react_["default"].createElement("div", {
7454
+ })), showShuttle && shuttleDirection && /*#__PURE__*/external_react_["default"].createElement(WaveformShuttleIndicator, {
7455
+ direction: shuttleDirection,
7456
+ rate: shuttleRate
7457
+ }), (showGeneratingWaveformIndicator || hasZoomControl) && /*#__PURE__*/external_react_["default"].createElement("div", {
7418
7458
  className: "bp-MP3ControlsV2-waveformZoom"
7419
7459
  }, showGeneratingWaveformIndicator ? /*#__PURE__*/external_react_["default"].createElement(WaveformGeneratingIndicator, null) : /*#__PURE__*/external_react_["default"].createElement(WaveformZoomControl, {
7420
7460
  isRevealed: isZoomRevealed,
@@ -7695,6 +7735,8 @@ function isWaveformErrorCode(value) {
7695
7735
 
7696
7736
  /** Desktop walks then pins near the right inset. Tape keeps the playhead at center. */
7697
7737
 
7738
+ /** J scans backward, L scans forward. Absent when shuttle is off. */
7739
+
7698
7740
  /** One canvas linear-gradient stop. `offset` is 0–1 along the bar. */
7699
7741
 
7700
7742
  /**
@@ -8437,6 +8479,55 @@ function rangeProgress(range, durationMs) {
8437
8479
 
8438
8480
  /***/ },
8439
8481
 
8482
+ /***/ 7308
8483
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
8484
+
8485
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
8486
+ /* harmony export */ Ay: () => (/* binding */ useTapeWaveform),
8487
+ /* harmony export */ MQ: () => (/* binding */ isTapeWaveformInput)
8488
+ /* harmony export */ });
8489
+ /* unused harmony exports isIPadNavigator, isCoarsePrimaryPointer */
8490
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1649);
8491
+ /* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(4929);
8492
+
8493
+
8494
+ function isIPadNavigator(tapeNavigator) {
8495
+ return /iPad/i.test(tapeNavigator.userAgent || '') || tapeNavigator.platform === 'MacIntel' && (tapeNavigator.maxTouchPoints || 0) > 1;
8496
+ }
8497
+ function isCoarsePrimaryPointer(tapeWindow) {
8498
+ return typeof tapeWindow.matchMedia === 'function' && tapeWindow.matchMedia(_constants__WEBPACK_IMPORTED_MODULE_1__/* .TAPE_POINTER_MEDIA_QUERY */ .Le).matches;
8499
+ }
8500
+
8501
+ /**
8502
+ * Tape vs desktop camera: coarse primary pointer (finger) or iPad
8503
+ * (including iPadOS reporting itself as Mac). Not width, not hasTouch,
8504
+ * not Browser.isMobile().
8505
+ */
8506
+ function isTapeWaveformInput(tapeWindow = window) {
8507
+ return isCoarsePrimaryPointer(tapeWindow) || isIPadNavigator(tapeWindow.navigator);
8508
+ }
8509
+
8510
+ /** Subscribe to the pointer media query; re-read the iPad heuristic on change. */
8511
+ function useTapeWaveform() {
8512
+ const [isTape, setIsTape] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(() => typeof window !== 'undefined' && isTapeWaveformInput(window));
8513
+ (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
8514
+ if (typeof window.matchMedia !== 'function') {
8515
+ setIsTape(isTapeWaveformInput(window));
8516
+ return undefined;
8517
+ }
8518
+ const mediaQuery = window.matchMedia(_constants__WEBPACK_IMPORTED_MODULE_1__/* .TAPE_POINTER_MEDIA_QUERY */ .Le);
8519
+ const sync = () => {
8520
+ setIsTape(isTapeWaveformInput(window));
8521
+ };
8522
+ sync();
8523
+ mediaQuery.addEventListener('change', sync);
8524
+ return () => mediaQuery.removeEventListener('change', sync);
8525
+ }, []);
8526
+ return isTape;
8527
+ }
8528
+
8529
+ /***/ },
8530
+
8440
8531
  /***/ 1053
8441
8532
  (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
8442
8533
 
@@ -24650,7 +24741,7 @@ class Browser {
24650
24741
  ;// ./src/lib/Logger.js
24651
24742
  /* eslint-disable no-undef */
24652
24743
  const CLIENT_NAME = "box-content-preview";
24653
- const CLIENT_VERSION = "3.95.0";
24744
+ const CLIENT_VERSION = "3.97.0";
24654
24745
  /* eslint-enable no-undef */
24655
24746
 
24656
24747
  class Logger {
@@ -33876,6 +33967,27 @@ class TextLoader extends viewers_AssetLoader {
33876
33967
  }
33877
33968
  }
33878
33969
  /* harmony default export */ const text_TextLoader = (new TextLoader());
33970
+ ;// ./src/lib/viewers/controls/media/markers/helpers/commentMarkerRange.ts
33971
+ /**
33972
+ * Turn a host comment marker into the waveform range for a read-only span.
33973
+ * `comment_markers` uses seconds (`time` is the start, `endTime` the end); the
33974
+ * waveform draws `{ startMs, endMs }`. A point comment, or a span whose end is
33975
+ * not after the start, has no range, so the viewer only seeks.
33976
+ */
33977
+ function commentMarkerRange(marker) {
33978
+ if (!marker || !Number.isFinite(marker.time) || marker.endTime == null || !Number.isFinite(marker.endTime)) {
33979
+ return null;
33980
+ }
33981
+ const startMs = Math.round(marker.time * 1000);
33982
+ const endMs = Math.round(marker.endTime * 1000);
33983
+ if (!(endMs > startMs)) {
33984
+ return null;
33985
+ }
33986
+ return {
33987
+ endMs,
33988
+ startMs
33989
+ };
33990
+ }
33879
33991
  ;// ./src/lib/viewers/controls/media/types.ts
33880
33992
  /**
33881
33993
  * Draft range drawn on the waveform. Sidebar sends `comment_range_draft`
@@ -37431,6 +37543,8 @@ var waveform_constants = __webpack_require__(4929);
37431
37543
  var createWaveformLoader = __webpack_require__(4971);
37432
37544
  // EXTERNAL MODULE: ./src/lib/viewers/media/waveform/range.ts
37433
37545
  var range = __webpack_require__(4253);
37546
+ // EXTERNAL MODULE: ./src/lib/viewers/media/waveform/useTapeWaveform.ts
37547
+ var useTapeWaveform = __webpack_require__(7308);
37434
37548
  // EXTERNAL MODULE: ./src/lib/viewers/media/waveform/validateWaveformPayload.ts
37435
37549
  var validateWaveformPayload = __webpack_require__(1053);
37436
37550
  ;// ./src/lib/viewers/media/MP3.scss
@@ -37454,6 +37568,8 @@ function MP3Viewer_toPrimitive(t, r) { if ("object" != typeof t || !t) return t;
37454
37568
 
37455
37569
 
37456
37570
 
37571
+
37572
+
37457
37573
  const CSS_CLASS_MP3 = 'bp-media-mp3';
37458
37574
  const AUDIO_V2_SHUTTLE_RATES = [2, 4, 8, 16];
37459
37575
  const AUDIO_V2_SHUTTLE_TICK_MS = 50;
@@ -37551,6 +37667,7 @@ class MP3Viewer extends media_MediaBaseViewer {
37551
37667
  if (selected) {
37552
37668
  if (selected.id !== this.hostSelectedMarkerId) {
37553
37669
  this.hostSelectedMarkerId = selected.id;
37670
+ this.commentRangeReadOnly = commentMarkerRange(selected);
37554
37671
  if (Number.isFinite(selected.time)) {
37555
37672
  this.pendingHostSelectedSeek = selected;
37556
37673
  this.applyPendingHostSelectedSeek();
@@ -37559,6 +37676,7 @@ class MP3Viewer extends media_MediaBaseViewer {
37559
37676
  } else if (this.hostSelectedMarkerId && !markers.some(marker => marker.id === this.hostSelectedMarkerId)) {
37560
37677
  this.hostSelectedMarkerId = null;
37561
37678
  this.pendingHostSelectedSeek = null;
37679
+ this.commentRangeReadOnly = null;
37562
37680
  }
37563
37681
  this.renderUI();
37564
37682
  });
@@ -37628,21 +37746,19 @@ class MP3Viewer extends media_MediaBaseViewer {
37628
37746
  this.isCommentRangeDragging = !!isDragging;
37629
37747
  });
37630
37748
  MP3Viewer_defineProperty(this, "handleCommentRangeClear", () => {
37631
- if (!this.commentRangeDraft || this.commentRangeDraft.endMs == null) {
37749
+ const clearedDraftRange = this.clearOpenCommentRangeDraft();
37750
+ const clearedReadOnlyRange = this.commentRangeReadOnly != null;
37751
+ this.commentRangeReadOnly = null;
37752
+ if (!clearedDraftRange && !clearedReadOnlyRange) {
37632
37753
  return;
37633
37754
  }
37634
- const notifyHost = this.isCommentRangeTimestampActive;
37635
- this.commentRangeDraft = null;
37636
- this.isCommentRangeTimestampActive = false;
37637
- if (notifyHost) {
37638
- this.emit(EVENT_COMMENT_RANGE_DRAFT_DISMISS);
37639
- }
37640
37755
  this.syncCommentRangeLoop();
37641
37756
  this.renderUI();
37642
37757
  });
37643
37758
  MP3Viewer_defineProperty(this, "handleCommentMarkerClick", marker => {
37644
37759
  this.exitShuttle();
37645
37760
  this.hostSelectedMarkerId = marker.id;
37761
+ this.commentRangeReadOnly = commentMarkerRange(marker);
37646
37762
  this.pendingHostSelectedSeek = marker;
37647
37763
  if (this.mediaEl) {
37648
37764
  this.mediaEl.pause();
@@ -37698,6 +37814,7 @@ class MP3Viewer extends media_MediaBaseViewer {
37698
37814
  this.mediaEl.setAttribute('preload', 'auto');
37699
37815
  this.commentMarkers = [];
37700
37816
  this.commentRangeDraft = null;
37817
+ this.commentRangeReadOnly = null;
37701
37818
  this.hostSelectedMarkerId = null;
37702
37819
  this.isCommentRangeDragging = false;
37703
37820
  this.isCommentRangeTimestampActive = false;
@@ -37840,6 +37957,9 @@ class MP3Viewer extends media_MediaBaseViewer {
37840
37957
  this.handlePlayRequest();
37841
37958
  }
37842
37959
  shuttle(direction) {
37960
+ if ((0,useTapeWaveform/* isTapeWaveformInput */.MQ)()) {
37961
+ return;
37962
+ }
37843
37963
  const sameDirection = this.shuttleDirection === direction;
37844
37964
  const rate = nextShuttleRate(this.shuttleRate, sameDirection);
37845
37965
  if (direction === 'forward') {
@@ -37866,6 +37986,7 @@ class MP3Viewer extends media_MediaBaseViewer {
37866
37986
  }).catch(() => {});
37867
37987
  }
37868
37988
  this.scheduleCommentRangeLoopWrap(true);
37989
+ this.renderUI();
37869
37990
  }
37870
37991
  startReverseShuttle(rate) {
37871
37992
  this.stopReverseShuttle();
@@ -37885,6 +38006,7 @@ class MP3Viewer extends media_MediaBaseViewer {
37885
38006
  this.exitShuttle();
37886
38007
  }
37887
38008
  }, AUDIO_V2_SHUTTLE_TICK_MS);
38009
+ this.renderUI();
37888
38010
  }
37889
38011
  stopReverseShuttle() {
37890
38012
  if (this.reverseShuttleTimer) {
@@ -37988,7 +38110,7 @@ class MP3Viewer extends media_MediaBaseViewer {
37988
38110
  * @return {Promise<{ default: Function }>} MP3ControlsV2 module
37989
38111
  */
37990
38112
  importV2Controls() {
37991
- return Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, 8862));
38113
+ return Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, 2460));
37992
38114
  }
37993
38115
 
37994
38116
  /**
@@ -38015,6 +38137,7 @@ class MP3Viewer extends media_MediaBaseViewer {
38015
38137
  this.removeListener(EVENT_COMMENT_RANGE_DRAFT, this.handleCommentRangeDraft);
38016
38138
  this.removeListener(EVENT_COMMENT_RANGE_DRAFT_CLEAR, this.handleCommentRangeDraftClear);
38017
38139
  this.commentRangeDraft = null;
38140
+ this.commentRangeReadOnly = null;
38018
38141
  this.isCommentRangeDragging = false;
38019
38142
  this.isCommentRangeTimestampActive = false;
38020
38143
  this.stopReverseShuttle();
@@ -38031,6 +38154,7 @@ class MP3Viewer extends media_MediaBaseViewer {
38031
38154
  if (this.isAudioPlayerV2) {
38032
38155
  // A file-version switch is a clear, not a resync of the previous draft.
38033
38156
  this.commentRangeDraft = null;
38157
+ this.commentRangeReadOnly = null;
38034
38158
  this.isCommentRangeDragging = false;
38035
38159
  this.isCommentRangeTimestampActive = false;
38036
38160
  this.syncCommentRangeLoop();
@@ -38455,30 +38579,52 @@ class MP3Viewer extends media_MediaBaseViewer {
38455
38579
  }
38456
38580
  this.pendingHostSelectedSeek = null;
38457
38581
  this.exitShuttle();
38458
- this.handleCommentRangeClear();
38582
+ this.clearOpenCommentRangeDraft();
38583
+ this.commentRangeReadOnly = commentMarkerRange(marker);
38459
38584
  this.mediaEl.pause();
38460
38585
  if (this.mediaEl.currentTime !== marker.time) {
38461
38586
  this.mediaEl.currentTime = marker.time;
38462
38587
  }
38588
+ this.syncCommentRangeLoop();
38463
38589
  }
38464
38590
 
38465
38591
  /**
38466
- * Seconds of the open draft span, or null when collapsed / absent.
38467
- * Collapsed drafts (`endMs: null`) do not confine playback.
38592
+ * Seconds of the span that confines playback, or null when collapsed / absent.
38593
+ * A composer draft wins over a viewed comment range. Collapsed drafts do not confine playback.
38468
38594
  *
38469
38595
  * @return {{endSec: number, startSec: number}|null}
38470
38596
  */
38471
38597
  getOpenCommentRangeSeconds() {
38472
- const draft = this.commentRangeDraft;
38473
- if ((0,range/* isRangeCollapsed */.BT)(draft) || !Number.isFinite(draft.startMs) || !Number.isFinite(draft.endMs)) {
38598
+ // An open composer draft owns playback. A viewed comment range does otherwise.
38599
+ const source = this.commentRangeDraft != null ? this.commentRangeDraft : this.commentRangeReadOnly;
38600
+ if ((0,range/* isRangeCollapsed */.BT)(source) || !Number.isFinite(source.startMs) || !Number.isFinite(source.endMs)) {
38474
38601
  return null;
38475
38602
  }
38476
38603
  return {
38477
- endSec: draft.endMs / 1000,
38478
- startSec: draft.startMs / 1000
38604
+ endSec: source.endMs / 1000,
38605
+ startSec: source.startMs / 1000
38479
38606
  };
38480
38607
  }
38481
38608
 
38609
+ /**
38610
+ * Drop an open composer draft. A collapsed timestamp is left alone.
38611
+ * Does not clear a viewed comment range.
38612
+ *
38613
+ * @return {boolean} whether an open draft was cleared
38614
+ */
38615
+ clearOpenCommentRangeDraft() {
38616
+ if (!this.commentRangeDraft || this.commentRangeDraft.endMs == null) {
38617
+ return false;
38618
+ }
38619
+ const notifyHost = this.isCommentRangeTimestampActive;
38620
+ this.commentRangeDraft = null;
38621
+ this.isCommentRangeTimestampActive = false;
38622
+ if (notifyHost) {
38623
+ this.emit(EVENT_COMMENT_RANGE_DRAFT_DISMISS);
38624
+ }
38625
+ return true;
38626
+ }
38627
+
38482
38628
  /**
38483
38629
  * Keep a seek inside the open draft. Waveform click-outside and host
38484
38630
  * comment seeks dismiss first, then seek; clamp does not apply then.
@@ -38648,6 +38794,7 @@ class MP3Viewer extends media_MediaBaseViewer {
38648
38794
  this.controls.render(/*#__PURE__*/external_react_["default"].createElement(Mp3ControlsV2, MP3Viewer_extends({}, sharedProps, {
38649
38795
  commentMarkers: this.commentMarkers || [],
38650
38796
  commentRangeDraft: this.commentRangeDraft || null,
38797
+ commentRangeReadOnly: this.commentRangeReadOnly || null,
38651
38798
  hasStartedPlayback: !!this.userRequestedPlay,
38652
38799
  isGeneratingWaveform: this.isGeneratingWaveform(),
38653
38800
  keyboardVolumeStep: this.keyboardVolumeStep,
@@ -38660,7 +38807,9 @@ class MP3Viewer extends media_MediaBaseViewer {
38660
38807
  onCommentRangeDragCreate: this.handleCommentRangeDragCreate,
38661
38808
  onPlayNextChange: this.setPlayNext,
38662
38809
  peaks: this.waveformPeaks,
38663
- playNext: this.isPlayNextEnabled()
38810
+ playNext: this.isPlayNextEnabled(),
38811
+ shuttleDirection: this.shuttleDirection,
38812
+ shuttleRate: this.shuttleRate
38664
38813
  })));
38665
38814
  return;
38666
38815
  }
@@ -56121,11 +56270,18 @@ class Preview extends (events_default()) {
56121
56270
  loadFromCache() {
56122
56271
  // Log cache hit
56123
56272
  this.logger.setCached();
56124
-
56125
- // Finally load the viewer
56126
- this.loadViewer();
56127
56273
  const needsVideoReps = this.isVideoFileByExtension() && !this.hasPlayableVideoReps(this.file);
56128
- if (!this.options.skipServerUpdate || needsVideoReps) {
56274
+ const needsTranscriptionRep = isFeatureEnabled(this.options.features, constants/* AI_TRANSCRIPTION_FOR_VIDEO_SUBTITLES */.Iu) && this.isVideoFileByExtension() && !this.hasTranscriptionRep(this.file);
56275
+ // Captions are optional — do not treat a missing extracted_text rep like missing
56276
+ // dash/mp4. skipServerUpdate still skips this refresh; default reopen already
56277
+ // calls loadFromServer() because skipServerUpdate is false.
56278
+ const needsServerRefresh = !this.options.skipServerUpdate || needsVideoReps || needsTranscriptionRep;
56279
+
56280
+ // Play from cache immediately. Default reopen still refreshes file info in the
56281
+ // background; handleFileInfoResponse then updates the live viewer if extracted_text
56282
+ // arrived. A failed captions-only refresh must not uncache or destroy playback.
56283
+ this.loadViewer();
56284
+ if (needsServerRefresh) {
56129
56285
  this.loadFromServer();
56130
56286
  }
56131
56287
  }
@@ -56156,7 +56312,14 @@ class Preview extends (events_default()) {
56156
56312
  const fileInfoUrl = (0,util/* appendQueryParams */.Ne)(getURL(this.file.id, fileVersionId, apiHost), params);
56157
56313
  this.api.get(fileInfoUrl, {
56158
56314
  headers: this.getRequestHeaders()
56159
- }).then(this.handleFileInfoResponse).catch(this.handleFetchError);
56315
+ }).then(this.handleFileInfoResponse).catch(err => {
56316
+ // Captions are optional. If a cache-hit viewer is already playing dash/mp4,
56317
+ // a failed background file-info refresh must not uncache or triggerError.
56318
+ if (this.viewer && this.hasPlayableVideoReps(this.file)) {
56319
+ return;
56320
+ }
56321
+ this.handleFetchError(err);
56322
+ });
56160
56323
  }
56161
56324
 
56162
56325
  /**
@@ -56247,6 +56410,7 @@ class Preview extends (events_default()) {
56247
56410
  if (this.isVideoFileByExtension() && !this.hasPlayableVideoReps(file)) {
56248
56411
  throw new PreviewError/* default */.A(lib_events/* ERROR_CODE */.bo.ACCOUNT, "This preview didn’t load because your account is unable to preview this file type. Please try to open or download the file to view.");
56249
56412
  }
56413
+ const needsTranscriptionReload = this.canUseDash() && isFeatureEnabled(this.options.features, constants/* AI_TRANSCRIPTION_FOR_VIDEO_SUBTITLES */.Iu) && this.isVideoFileByExtension() && !this.hasTranscriptionRep(cachedFile) && this.hasTranscriptionRep(file);
56250
56414
 
56251
56415
  // Should load viewer for first time if:
56252
56416
  // - File isn't cached OR
@@ -56260,6 +56424,18 @@ class Preview extends (events_default()) {
56260
56424
  } else if (cachedFile.file_version.sha1 !== file.file_version.sha1 || isFileWatermarked) {
56261
56425
  this.logger.setCacheStale(); // Log that cache is stale
56262
56426
  this.reload(true); // Reload viewer without fetching updated file info from server
56427
+ } else if (needsTranscriptionReload) {
56428
+ // Cache was valid but lacked extracted_text (e.g. prefetch without the hint).
56429
+ // Server refresh now has the rep — update the already-playing viewer so
56430
+ // loadTranscription can attach captions. Only call it after loadeddata;
56431
+ // calling earlier duplicates the Auto-generated Shaka track and can throw
56432
+ // if UI is not ready. If loadeddata has not fired, the handler uses this file.
56433
+ if (this.viewer) {
56434
+ this.viewer.options.file = this.file;
56435
+ if (this.viewer.isLoaded() && typeof this.viewer.loadTranscription === 'function') {
56436
+ this.viewer.loadTranscription();
56437
+ }
56438
+ }
56263
56439
  }
56264
56440
  } catch (err) {
56265
56441
  const error = err instanceof PreviewError/* default */.A ? err : new PreviewError/* default */.A(lib_events/* ERROR_CODE */.bo.LOAD_VIEWER, "This preview didn’t load. Please try to open or download the file to view.", {}, err.message);
@@ -56380,6 +56556,31 @@ class Preview extends (events_default()) {
56380
56556
  });
56381
56557
  }
56382
56558
 
56559
+ /**
56560
+ * Returns true if file has an extracted_text transcription rep with a content URL.
56561
+ *
56562
+ * @private
56563
+ * @param {Object} file - File object
56564
+ * @return {boolean}
56565
+ */
56566
+ hasTranscriptionRep(file) {
56567
+ if (!file?.representations?.entries) {
56568
+ return false;
56569
+ }
56570
+ const extractedText = getRepresentation(file, 'extracted_text');
56571
+ return !!extractedText?.content?.url_template;
56572
+ }
56573
+
56574
+ /**
56575
+ * Returns true when Dash playback is available and not disabled.
56576
+ *
56577
+ * @private
56578
+ * @return {boolean}
56579
+ */
56580
+ canUseDash() {
56581
+ return lib_Browser.canPlayDash() && !this.disabledViewers.Dash;
56582
+ }
56583
+
56383
56584
  /**
56384
56585
  * Returns true if file has playable video representations (dash or mp4).
56385
56586
  *
@@ -56834,7 +57035,7 @@ class Preview extends (events_default()) {
56834
57035
  previewMode,
56835
57036
  sharedLinkAuth
56836
57037
  } = this.options || {};
56837
- this.emit(name, Preview_objectSpread(Preview_objectSpread({}, payload), {}, {
57038
+ this.emit(name, Preview_objectSpread(Preview_objectSpread(Preview_objectSpread({}, payload), this.getBlueprintMigrationTags()), {}, {
56838
57039
  access_pattern: accessPattern,
56839
57040
  client_name: clientName,
56840
57041
  content_type: (0,util/* getProp */.GT)(this.viewer, 'options.viewer.NAME', ''),
@@ -56852,6 +57053,26 @@ class Preview extends (events_default()) {
56852
57053
  }, getClientLogDetails()));
56853
57054
  }
56854
57055
 
57056
+ /**
57057
+ * Returns the state of each Blueprint migration wave for this preview session. Every metric
57058
+ * and error carries all four, including the waves that are off, so the flag-off side of a
57059
+ * rollout is measured the same way as the flag-on side rather than inferred from its absence.
57060
+ *
57061
+ * @private
57062
+ * @return {Object} Blueprint migration dimensions
57063
+ */
57064
+ getBlueprintMigrationTags() {
57065
+ const {
57066
+ features
57067
+ } = this.options || {};
57068
+ return {
57069
+ blueprint_archive: isFeatureEnabled(features, constants/* BLUEPRINT_MIGRATION_ARCHIVE */.cA),
57070
+ blueprint_controls_bar: isFeatureEnabled(features, constants/* BLUEPRINT_MIGRATION_CONTROLS_BAR */.OQ),
57071
+ blueprint_media_controls: isFeatureEnabled(features, constants/* BLUEPRINT_MIGRATION_MEDIA_CONTROLS */.dR),
57072
+ blueprint_supporting_ui: isFeatureEnabled(features, constants/* BLUEPRINT_MIGRATION_SUPPORTING_UI */.Ed)
57073
+ };
57074
+ }
57075
+
56855
57076
  /**
56856
57077
  * Returns the prefetch/preload dimensions for this preview session. Only attached to
56857
57078
  * the load event, preview_preload_outcome counter, and preview_error — exactly one
@@ -56875,7 +57096,7 @@ class Preview extends (events_default()) {
56875
57096
  * @return {Object} Headers
56876
57097
  */
56877
57098
  getRequestHeaders(token) {
56878
- const isDash = lib_Browser.canPlayDash() && !this.disabledViewers.Dash;
57099
+ const isDash = this.canUseDash();
56879
57100
  let videoHint = isDash ? constants/* X_REP_HINT_VIDEO_DASH */.yF : constants/* X_REP_HINT_VIDEO_MP4 */.Zg;
56880
57101
  if (isDash && isFeatureEnabled(this.options.features, constants/* AI_TRANSCRIPTION_FOR_VIDEO_SUBTITLES */.Iu)) {
56881
57102
  videoHint += constants/* X_REP_HINT_VIDEO_DASH_EXTRACTED_TEXT */.xU;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "box-content-preview",
3
- "version": "3.95.0",
3
+ "version": "3.97.0",
4
4
  "description": "Box Content Preview UI Element",
5
5
  "author": "Box (https://www.box.com/)",
6
6
  "license": "SEE LICENSE IN LICENSE",