box-content-preview 3.84.0 → 3.86.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.84.0-blue.svg?style=flat-square)](https://github.com/box/box-content-preview)
5
+ [![version](https://img.shields.io/badge/version-v3.86.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.84.0
25
+ - Version: v3.86.0
26
26
  - Locale: en-US
27
27
 
28
- https://cdn01.boxcdn.net/platform/preview/3.84.0/en-US/preview.js
29
- https://cdn01.boxcdn.net/platform/preview/3.84.0/en-US/preview.css
28
+ https://cdn01.boxcdn.net/platform/preview/3.86.0/en-US/preview.js
29
+ https://cdn01.boxcdn.net/platform/preview/3.86.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.84.0/en-US/preview.js"></script>
55
+ <script src="https://cdn01.boxcdn.net/platform/preview/3.86.0/en-US/preview.js"></script>
56
56
  <link
57
57
  rel="stylesheet"
58
- href="https://cdn01.boxcdn.net/platform/preview/3.84.0/en-US/preview.css"
58
+ href="https://cdn01.boxcdn.net/platform/preview/3.86.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.84.0`
79
+ - Check out a specific version with `git checkout v3.86.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`
@@ -71,7 +71,7 @@
71
71
  .bp-VideoControls{display:flex;flex-direction:column;width:100%;background-image:linear-gradient(to top, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 100%);padding:40px 20px 8px}.bp-VideoControls .bp-FullscreenToggle{width:36px;height:40px}.bp-VideoControls-bar{display:flex;padding:0 10px 5px;display:grid;align-items:center}.bp-VideoControls-bar.bp-VideoControls-bar--two-groups{justify-content:flex-end}.bp-VideoControls-bar.bp-VideoControls-bar--two-groups .bp-VideoControls-group--play-pause{position:absolute;left:50%;transform:translateX(-50%)}.bp-VideoControls-bar.bp-VideoControls-bar--three-groups{grid-template-columns:repeat(3, 1fr)}.bp-VideoControls-bar.bp-VideoControls-bar--three-groups.bp-VideoControls-bar--narrow-video{grid-template-columns:repeat(2, 1fr)}.bp-VideoControls-bar.bp-VideoControls-bar--three-groups .bp-VideoControls-group--annotations{justify-self:flex-start}.bp-VideoControls-bar.bp-VideoControls-bar--three-groups .bp-VideoControls-group--play-pause{justify-self:center}.bp-VideoControls-bar.bp-VideoControls-bar--three-groups .bp-VideoControls-group--media-controls{justify-self:flex-end}.bp-VideoControls-group{display:flex;align-items:center}.bp-VideoControls-settings{position:relative}.bp-VideoControls-settings .bp-SettingsFlyout{right:15px}.bp-VideoControls-settings .bp-SettingsToggle-button{width:36px;height:40px}
72
72
  .bp-FilmstripV2{position:absolute;bottom:calc(100% + 12px);padding:12px;padding-bottom:8px;background:#fff;border-radius:16px;box-shadow:0 2px 8px rgba(0,0,0,.15);visibility:hidden}.bp-FilmstripV2.bp-is-shown{visibility:visible}.bp-FilmstripV2-frame{position:relative;display:flex;align-items:center;justify-content:center;overflow:hidden;border-radius:10px}.bp-FilmstripV2-frameImage{position:absolute;top:0;left:0;overflow:hidden;background-repeat:no-repeat;transform-origin:top left}.bp-FilmstripV2-frame .bp-crawler{position:relative;z-index:1}.bp-FilmstripV2-time{margin-top:8px;color:#000;font-size:13px;line-height:20px;text-align:center}
73
73
  .bp-MarkerAvatar{position:absolute;bottom:calc(100% + 4px);left:50%;width:12px;height:12px;overflow:hidden;border:0;border-radius:50%;outline:2px solid rgba(0,0,0,.5);box-shadow:0 0 0 0 #fff;transform:translate(-50%, 0);transform-origin:bottom center;transition:transform 150ms,box-shadow 150ms,outline 150ms}.bp-MarkerAvatar img{position:absolute;top:0;left:0;width:100%;height:100%;object-fit:cover;object-position:center}.bp-MarkerAvatar-initial{display:grid;width:100%;height:100%;font-weight:bold;font-size:7px;line-height:1;text-align:center;text-transform:uppercase;place-items:center}.bp-MarkerAvatar-anonymousIcon{width:100%;height:100%;color:#222}
74
- .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;padding:0;background:none;border:0;cursor:pointer;transition:margin 150ms}.bp-MarkerAvatarStack-item:not(:first-child){margin-left:-6px}.bp-MarkerAvatarStack-item .bp-MarkerAvatar{position:relative;bottom:auto;left:auto;display:block;transform:none}.bp-MarkerAvatarStack-item:hover,.bp-MarkerAvatarStack-item:focus-visible{z-index:1}.bp-MarkerAvatarStack-item:hover .bp-MarkerAvatar,.bp-MarkerAvatarStack-item:focus-visible .bp-MarkerAvatar{outline:0 solid transparent;box-shadow:0 0 0 2px #fff}.bp-TimeControlsV2-marker--group:hover .bp-MarkerAvatarStack-item:not(:first-child),.bp-TimeControlsV2-marker--group:focus-visible .bp-MarkerAvatarStack-item:not(:first-child),.bp-MarkerCluster:hover .bp-MarkerAvatarStack-item:not(:first-child),.bp-MarkerCluster:focus-within .bp-MarkerAvatarStack-item:not(:first-child){margin-left:2px}.bp-MarkerAvatarStack-overflow{cursor:pointer}.bp-MarkerAvatarStack-overflowBadge{background-color:#6f6f6f}
74
+ .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;padding:0;background:none;border:0;cursor:pointer;transition:margin 150ms}.bp-MarkerAvatarStack-item:not(:first-child){margin-left:var(--bp-marker-stack-overlap, -6px)}.bp-MarkerAvatarStack-item .bp-MarkerAvatar{position:relative;bottom:auto;left:auto;display:block;transform:none}.bp-MarkerAvatarStack-item:hover,.bp-MarkerAvatarStack-item:focus-visible{z-index:1}.bp-MarkerAvatarStack-item:hover .bp-MarkerAvatar,.bp-MarkerAvatarStack-item:focus-visible .bp-MarkerAvatar{outline:0 solid transparent;box-shadow:0 0 0 2px #fff}.bp-TimeControlsV2-marker--group:hover .bp-MarkerAvatarStack-item:not(:first-child),.bp-TimeControlsV2-marker--group:focus-visible .bp-MarkerAvatarStack-item:not(:first-child),.bp-MarkerCluster:hover .bp-MarkerAvatarStack-item:not(:first-child),.bp-MarkerCluster:focus-within .bp-MarkerAvatarStack-item:not(:first-child){margin-left:2px}.bp-MarkerAvatarStack-overflow{cursor:pointer}.bp-MarkerAvatarStack-overflowBadge{background-color:#6f6f6f}
75
75
  .bp-MarkerCluster{position:absolute;top:50%;z-index:1;height:8px;transform:translate(-2px, -50%);transition:transform 150ms}.bp-MarkerCluster:hover,.bp-MarkerCluster:focus-within{z-index:2;transform:translate(-2px, -50%) scale(1.5)}.bp-MarkerCluster:hover .bp-MarkerCluster-tick,.bp-MarkerCluster:focus-within .bp-MarkerCluster-tick{transform:none}.bp-MarkerCluster-tick{display:block;width:100%;height:100%;padding:0;background:#6f6f6f;border:1px solid #fff;border-radius:2px;cursor:pointer;transition:transform 150ms}
76
76
  .bp-TimeControlsV2{position:relative;margin-right:10px;margin-left:10px}.bp-TimeControlsV2-scrubber{position:relative}.bp-TimeControlsV2-slider{height:20px}.bp-TimeControlsV2-slider .bp-SliderControl-track{height:6px;margin:auto 0;border-radius:5px;backface-visibility:hidden;mask-image:var(--bp-track-mask, none)}.bp-TimeControlsV2-slider .bp-SliderControl-thumb{top:50%;z-index:3;width:3px;height:16px;margin-left:-1.5px;background:#fff;border:0;border-radius:2px;transform:translateY(-50%);cursor:ew-resize}.bp-TimeControlsV2-marker{position:absolute;top:50%;z-index:1;width:2px;height:8px;padding:0;background:#fff;border:0;border-radius:2px;transform:translate(-50%, -50%);cursor:pointer;transition:transform 150ms}.bp-TimeControlsV2-marker:hover,.bp-TimeControlsV2-marker:focus-visible{z-index:2;transform:translate(-50%, -50%) scale(1.7)}.bp-TimeControlsV2-marker:hover>.bp-MarkerAvatar,.bp-TimeControlsV2-marker:focus-visible>.bp-MarkerAvatar{outline:0 solid transparent;box-shadow:0 0 0 2px #fff;transform:translate(-50%, calc(5px / 1.7))}.bp-TimeControlsV2-marker:focus-visible{outline:2px solid #fff;outline-offset:2px}.bp-TimeControlsV2-marker--group:hover,.bp-TimeControlsV2-marker--group:focus-visible{transform:translate(-50%, -50%) scale(1.5)}
77
77
  .bp-VideoFullscreenButton{position:absolute;display:flex;align-items:center;justify-content:center;width:48px;height:48px;padding:0;color:#fff;background:rgba(0,0,0,.6);border:none;border-radius:50%;box-shadow:0 2px 12px 0 rgba(0,0,0,.8);cursor:pointer;backdrop-filter:blur(60px);pointer-events:auto}.bp-VideoFullscreenButton svg{width:20px;height:20px}
package/dist/lib/index.js CHANGED
@@ -1010,7 +1010,7 @@ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e =
1010
1010
  const CLIENT_NAME = "box-content-preview"; // eslint-disable-line no-undef
1011
1011
  const CLIENT_NAME_KEY = 'box_client_name';
1012
1012
  const CLIENT_VERSION_KEY = 'box_client_version';
1013
- const CLIENT_VERSION = "3.84.0"; // eslint-disable-line no-undef
1013
+ const CLIENT_VERSION = "3.86.0"; // eslint-disable-line no-undef
1014
1014
  const HEADER_CLIENT_NAME = 'X-Box-Client-Name';
1015
1015
  const HEADER_CLIENT_VERSION = 'X-Box-Client-Version';
1016
1016
  const PROMISE_MAP = {};
@@ -4118,7 +4118,7 @@ function getPdfjsWorkerSrc() {
4118
4118
 
4119
4119
  /***/ },
4120
4120
 
4121
- /***/ 3845
4121
+ /***/ 3678
4122
4122
  (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
4123
4123
 
4124
4124
 
@@ -4249,6 +4249,7 @@ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object
4249
4249
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
4250
4250
  function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
4251
4251
 
4252
+ /** Visible window: start/end times, pixels-per-second, and the current zoom. */
4252
4253
  function createWaveformViewport({
4253
4254
  durationSec,
4254
4255
  heightPx,
@@ -4356,6 +4357,96 @@ function zoomFromSliderValue(value, maxZoom = constants/* WAVEFORM_ZOOM_MIN */.L
4356
4357
  const t = Math.min(constants/* WAVEFORM_ZOOM_SLIDER_MAX */.nh, Math.max(0, value)) / constants/* WAVEFORM_ZOOM_SLIDER_MAX */.nh;
4357
4358
  return clampWaveformZoom(constants/* WAVEFORM_ZOOM_MIN */.LW + t * (max - constants/* WAVEFORM_ZOOM_MIN */.LW), max);
4358
4359
  }
4360
+
4361
+ /** Max scroll that still shows a full window (no overscroll). */
4362
+ function maxScrollLeft(viewport) {
4363
+ return Math.max(0, viewport.durationSec * viewport.pixelsPerSecond - viewport.widthPx);
4364
+ }
4365
+
4366
+ /** Scroll offset that still shows a full window (no overscroll). */
4367
+ function clampScrollLeft(scrollLeftPx, viewport) {
4368
+ if (!Number.isFinite(scrollLeftPx)) {
4369
+ return 0;
4370
+ }
4371
+ return Math.min(maxScrollLeft(viewport), Math.max(0, scrollLeftPx));
4372
+ }
4373
+
4374
+ /** Follow inset in CSS px, capped at one third of the view so a narrow player still has room. */
4375
+ function getFollowInsetPx(widthPx, insetPx = constants/* WAVEFORM_FOLLOW_INSET_PX */.NM) {
4376
+ if (!(widthPx > 0)) {
4377
+ return 0;
4378
+ }
4379
+ return Math.min(Math.max(0, insetPx), widthPx / 3);
4380
+ }
4381
+
4382
+ /** CSS left for a playhead pinned to the follow inset. */
4383
+ function getPinnedPlayheadLeft(widthPx, insetPx = constants/* WAVEFORM_FOLLOW_INSET_PX */.NM) {
4384
+ const inset = getFollowInsetPx(widthPx, insetPx);
4385
+ if (!(widthPx > 0)) {
4386
+ return '0%';
4387
+ }
4388
+ return `${(widthPx - inset) / widthPx * 100}%`;
4389
+ }
4390
+
4391
+ /** CSS left % of the playhead from the left of the visible window. */
4392
+ function timeLeftPercent(timeSec, durationSec, viewport) {
4393
+ if (viewport.widthPx > 0 && viewport.pixelsPerSecond > 0) {
4394
+ return `${positionPxFromTime(timeSec, viewport) / viewport.widthPx * 100}%`;
4395
+ }
4396
+ const progress = durationSec > 0 ? Math.min(1, Math.max(0, timeSec / durationSec)) : 0;
4397
+ return `${progress * 100}%`;
4398
+ }
4399
+
4400
+ /**
4401
+ * Walk across the view until the playhead nears the right edge, then follow.
4402
+ * Off-screen at play start jumps in; off-screen right while playing keeps following.
4403
+ */
4404
+ function getPlayheadCameraAction({
4405
+ insetPx = constants/* WAVEFORM_FOLLOW_INSET_PX */.NM,
4406
+ isPlaying,
4407
+ playJustStarted,
4408
+ timeSec,
4409
+ viewport
4410
+ }) {
4411
+ if (!isPlaying || viewport.zoomLevel <= constants/* WAVEFORM_ZOOM_MIN */.LW || !(viewport.widthPx > 0) || !(viewport.pixelsPerSecond > 0)) {
4412
+ return {
4413
+ type: 'none'
4414
+ };
4415
+ }
4416
+ const inset = getFollowInsetPx(viewport.widthPx, insetPx);
4417
+ const viewX = positionPxFromTime(timeSec, viewport);
4418
+ const playheadCanvasX = timeSec * viewport.pixelsPerSecond;
4419
+ const followX = viewport.widthPx - inset;
4420
+ if (viewX < 0) {
4421
+ if (!playJustStarted) {
4422
+ return {
4423
+ type: 'none'
4424
+ };
4425
+ }
4426
+ return {
4427
+ type: 'jump',
4428
+ scrollLeftPx: clampScrollLeft(playheadCanvasX - inset, viewport)
4429
+ };
4430
+ }
4431
+ if (viewX >= followX) {
4432
+ const unclampedScroll = playheadCanvasX - followX;
4433
+ const scrollLeftPx = clampScrollLeft(unclampedScroll, viewport);
4434
+ if (playJustStarted && viewX > viewport.widthPx) {
4435
+ return {
4436
+ type: 'jump',
4437
+ scrollLeftPx
4438
+ };
4439
+ }
4440
+ return {
4441
+ type: 'followRight',
4442
+ isPlayheadPinned: unclampedScroll <= maxScrollLeft(viewport),
4443
+ scrollLeftPx
4444
+ };
4445
+ }
4446
+ return {
4447
+ type: 'none'
4448
+ };
4449
+ }
4359
4450
  ;// ./node_modules/wavesurfer.js/dist/wavesurfer.esm.js
4360
4451
  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
4361
4452
  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;
@@ -4612,6 +4703,241 @@ function tintWaveformTiles({
4612
4703
  });
4613
4704
  });
4614
4705
  }
4706
+ ;// ./src/lib/viewers/media/waveform/usePlayheadCamera.ts
4707
+
4708
+
4709
+
4710
+
4711
+ function getScrollLeft(wavesurfer, fallback = 0) {
4712
+ return wavesurfer && wavesurfer.getScroll ? wavesurfer.getScroll() : fallback;
4713
+ }
4714
+ function prefersReducedMotion() {
4715
+ return typeof window !== 'undefined' && typeof window.matchMedia === 'function' && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
4716
+ }
4717
+ /**
4718
+ * Pin/follow vs user pan. Refs, not state: rAF and WaveSurfer `scroll` read these
4719
+ * every frame. WaveformView owns WaveSurfer, zoom, and the media rAF loop.
4720
+ */
4721
+ function usePlayheadCamera({
4722
+ mediaElRef,
4723
+ onViewportCommit,
4724
+ playheadRef,
4725
+ viewportRef,
4726
+ wavesurferRef
4727
+ }) {
4728
+ const onViewportCommitRef = (0,external_react_.useRef)(onViewportCommit);
4729
+ onViewportCommitRef.current = onViewportCommit;
4730
+ const programmaticScrollRef = (0,external_react_.useRef)(false);
4731
+ const jumpAnimationRef = (0,external_react_.useRef)(0);
4732
+ const lastCameraScrollRef = (0,external_react_.useRef)(null);
4733
+ const mediaTimeRef = (0,external_react_.useRef)(0);
4734
+ const isFollowPinnedRef = (0,external_react_.useRef)(false);
4735
+ const userIsScrollingRef = (0,external_react_.useRef)(false);
4736
+ const holdFollowUntilInsetRef = (0,external_react_.useRef)(false);
4737
+ const scrollSettleTimerRef = (0,external_react_.useRef)(0);
4738
+ const applyRef = (0,external_react_.useRef)(null);
4739
+ const isFollowPinned = (0,external_react_.useCallback)(() => isFollowPinnedRef.current, []);
4740
+ const cancelJump = (0,external_react_.useCallback)(() => {
4741
+ if (!jumpAnimationRef.current) {
4742
+ return;
4743
+ }
4744
+ window.cancelAnimationFrame(jumpAnimationRef.current);
4745
+ jumpAnimationRef.current = 0;
4746
+ }, []);
4747
+ const clearFollowPin = (0,external_react_.useCallback)(() => {
4748
+ isFollowPinnedRef.current = false;
4749
+ programmaticScrollRef.current = false;
4750
+ }, []);
4751
+ const releaseUserPanHold = (0,external_react_.useCallback)(() => {
4752
+ window.clearTimeout(scrollSettleTimerRef.current);
4753
+ scrollSettleTimerRef.current = 0;
4754
+ userIsScrollingRef.current = false;
4755
+ holdFollowUntilInsetRef.current = false;
4756
+ }, []);
4757
+ const readMediaTime = (0,external_react_.useCallback)(() => {
4758
+ const live = mediaElRef.current?.currentTime;
4759
+ if (typeof live === 'number' && Number.isFinite(live)) {
4760
+ mediaTimeRef.current = live;
4761
+ return live;
4762
+ }
4763
+ return mediaTimeRef.current;
4764
+ }, [mediaElRef]);
4765
+ const onSeek = (0,external_react_.useCallback)(timeSec => {
4766
+ mediaTimeRef.current = timeSec;
4767
+ cancelJump();
4768
+ clearFollowPin();
4769
+ }, [cancelJump, clearFollowPin]);
4770
+
4771
+ /** Unpin and hold follow so zoom setScroll (slider center or pinch origin) is not stolen. */
4772
+ const onZoom = (0,external_react_.useCallback)(() => {
4773
+ cancelJump();
4774
+ isFollowPinnedRef.current = false;
4775
+ holdFollowUntilInsetRef.current = true;
4776
+ }, [cancelJump]);
4777
+ const applyScrollLeft = (0,external_react_.useCallback)((scrollLeftPx, shouldCommitState) => {
4778
+ const wavesurfer = wavesurferRef.current;
4779
+ if (!wavesurfer || !wavesurfer.setScroll) {
4780
+ return;
4781
+ }
4782
+ programmaticScrollRef.current = true;
4783
+ lastCameraScrollRef.current = scrollLeftPx;
4784
+ wavesurfer.setScroll(scrollLeftPx);
4785
+ const appliedScrollLeft = getScrollLeft(wavesurfer, scrollLeftPx);
4786
+ lastCameraScrollRef.current = appliedScrollLeft;
4787
+ viewportRef.current = getViewportAtScroll(viewportRef.current, appliedScrollLeft);
4788
+ window.requestAnimationFrame(() => {
4789
+ // Keep the flag through delayed `scroll` while the camera is driving.
4790
+ if (jumpAnimationRef.current || isFollowPinnedRef.current) {
4791
+ return;
4792
+ }
4793
+ programmaticScrollRef.current = false;
4794
+ });
4795
+ if (shouldCommitState) {
4796
+ onViewportCommitRef.current(appliedScrollLeft, viewportRef.current);
4797
+ }
4798
+ }, [viewportRef, wavesurferRef]);
4799
+ const pinFollowPlayhead = (0,external_react_.useCallback)((playhead, viewport, isPinned) => {
4800
+ isFollowPinnedRef.current = isPinned;
4801
+ if (!playhead || !isPinned || !(viewport.widthPx > 0)) {
4802
+ return;
4803
+ }
4804
+ playhead.style.left = getPinnedPlayheadLeft(viewport.widthPx);
4805
+ }, []);
4806
+ const apply = (0,external_react_.useCallback)((timeSec, playJustStarted = false) => {
4807
+ mediaTimeRef.current = timeSec;
4808
+ const wavesurfer = wavesurferRef.current;
4809
+ const viewport = viewportRef.current;
4810
+ if (!wavesurfer) {
4811
+ return;
4812
+ }
4813
+ if (viewport.zoomLevel <= constants/* WAVEFORM_ZOOM_MIN */.LW) {
4814
+ clearFollowPin();
4815
+ return;
4816
+ }
4817
+ if (userIsScrollingRef.current && !playJustStarted) {
4818
+ return;
4819
+ }
4820
+ if (jumpAnimationRef.current && !playJustStarted) {
4821
+ return;
4822
+ }
4823
+ const liveViewport = getViewportAtScroll(viewport, getScrollLeft(wavesurfer, viewport.scrollLeftPx));
4824
+ const action = getPlayheadCameraAction({
4825
+ isPlaying: true,
4826
+ playJustStarted,
4827
+ timeSec,
4828
+ viewport: liveViewport
4829
+ });
4830
+ if (holdFollowUntilInsetRef.current && !playJustStarted) {
4831
+ if (action.type !== 'none') {
4832
+ return;
4833
+ }
4834
+ holdFollowUntilInsetRef.current = false;
4835
+ }
4836
+ if (action.type === 'none') {
4837
+ if (isFollowPinnedRef.current) {
4838
+ isFollowPinnedRef.current = false;
4839
+ applyScrollLeft(liveViewport.scrollLeftPx, true);
4840
+ }
4841
+ programmaticScrollRef.current = false;
4842
+ return;
4843
+ }
4844
+ cancelJump();
4845
+ if (action.type === 'followRight') {
4846
+ pinFollowPlayhead(playheadRef.current, liveViewport, action.isPlayheadPinned);
4847
+ applyScrollLeft(action.scrollLeftPx, !action.isPlayheadPinned);
4848
+ return;
4849
+ }
4850
+ isFollowPinnedRef.current = false;
4851
+ const from = getScrollLeft(wavesurfer, liveViewport.scrollLeftPx);
4852
+ if (prefersReducedMotion() || typeof window.requestAnimationFrame !== 'function') {
4853
+ applyScrollLeft(action.scrollLeftPx, true);
4854
+ apply(timeSec, false);
4855
+ return;
4856
+ }
4857
+ programmaticScrollRef.current = true;
4858
+ const start = (0,util/* getCurrentTimeMs */.RU)();
4859
+ const tick = now => {
4860
+ const t = Math.min(1, (now - start) / constants/* WAVEFORM_PLAYHEAD_JUMP_MS */.Bq);
4861
+ const liveAction = getPlayheadCameraAction({
4862
+ isPlaying: true,
4863
+ playJustStarted: true,
4864
+ timeSec: mediaTimeRef.current,
4865
+ viewport: getViewportAtScroll(viewportRef.current, getScrollLeft(wavesurfer, from))
4866
+ });
4867
+ const to = liveAction.type === 'none' ? action.scrollLeftPx : liveAction.scrollLeftPx;
4868
+ applyScrollLeft(from + (to - from) * (1 - (1 - t) * (1 - t)), false);
4869
+ if (t < 1) {
4870
+ jumpAnimationRef.current = window.requestAnimationFrame(tick);
4871
+ return;
4872
+ }
4873
+ jumpAnimationRef.current = 0;
4874
+ applyScrollLeft(to, true);
4875
+ apply(mediaTimeRef.current, false);
4876
+ };
4877
+ jumpAnimationRef.current = window.requestAnimationFrame(tick);
4878
+ }, [applyScrollLeft, cancelJump, clearFollowPin, pinFollowPlayhead, playheadRef, viewportRef, wavesurferRef]);
4879
+ applyRef.current = apply;
4880
+
4881
+ /**
4882
+ * Camera-owned: jumping; matching follow scroll; unpinned programmatic; clamp-to-max.
4883
+ * User pan: pinned and |scroll - lastCamera| > 1, or any non-programmatic scroll while not jumping.
4884
+ */
4885
+ const isUserPan = (0,external_react_.useCallback)(scrollLeftPx => {
4886
+ const isCameraOwnedScroll = programmaticScrollRef.current || jumpAnimationRef.current !== 0;
4887
+ const lastCameraScroll = lastCameraScrollRef.current;
4888
+ const maxScroll = maxScrollLeft(viewportRef.current);
4889
+ const isClampedToMax = lastCameraScroll != null && scrollLeftPx >= maxScroll - 1 && lastCameraScroll >= maxScroll - 1;
4890
+ const isFollowCameraScroll = isFollowPinnedRef.current && lastCameraScroll != null && Math.abs(scrollLeftPx - lastCameraScroll) <= 1;
4891
+ return !(isCameraOwnedScroll && (jumpAnimationRef.current !== 0 || isFollowCameraScroll || isClampedToMax || !isFollowPinnedRef.current));
4892
+ }, [viewportRef]);
4893
+ const handleScroll = (0,external_react_.useCallback)(onUserPan => {
4894
+ const wavesurfer = wavesurferRef.current;
4895
+ if (!wavesurfer) {
4896
+ return;
4897
+ }
4898
+ const scrollLeftPx = getScrollLeft(wavesurfer);
4899
+ if (!isUserPan(scrollLeftPx)) {
4900
+ viewportRef.current = getViewportAtScroll(viewportRef.current, scrollLeftPx);
4901
+ return;
4902
+ }
4903
+ viewportRef.current = getViewportAtScroll(viewportRef.current, scrollLeftPx);
4904
+ const timeSec = readMediaTime();
4905
+ const playhead = playheadRef.current;
4906
+ if (playhead) {
4907
+ playhead.style.left = timeLeftPercent(timeSec, viewportRef.current.durationSec, viewportRef.current);
4908
+ }
4909
+ userIsScrollingRef.current = true;
4910
+ holdFollowUntilInsetRef.current = true;
4911
+ window.clearTimeout(scrollSettleTimerRef.current);
4912
+ scrollSettleTimerRef.current = window.setTimeout(() => {
4913
+ userIsScrollingRef.current = false;
4914
+ scrollSettleTimerRef.current = 0;
4915
+ if (!mediaElRef.current || mediaElRef.current.paused) {
4916
+ return;
4917
+ }
4918
+ applyRef.current?.(readMediaTime(), false);
4919
+ }, constants/* WAVEFORM_FOLLOW_SCROLL_SETTLE_MS */.Zs);
4920
+ cancelJump();
4921
+ isFollowPinnedRef.current = false;
4922
+ programmaticScrollRef.current = false;
4923
+ onUserPan(timeSec);
4924
+ }, [cancelJump, isUserPan, mediaElRef, playheadRef, readMediaTime, viewportRef, wavesurferRef]);
4925
+ (0,external_react_.useEffect)(() => () => {
4926
+ releaseUserPanHold();
4927
+ cancelJump();
4928
+ }, [cancelJump, releaseUserPanHold]);
4929
+ return {
4930
+ apply,
4931
+ applyScrollLeft,
4932
+ cancelJump,
4933
+ clearFollowPin,
4934
+ handleScroll,
4935
+ isFollowPinned,
4936
+ onSeek,
4937
+ onZoom,
4938
+ releaseUserPanHold
4939
+ };
4940
+ }
4615
4941
  ;// ./src/lib/viewers/media/waveform/WaveformView.scss
4616
4942
  // extracted by mini-css-extract-plugin
4617
4943
 
@@ -4630,6 +4956,7 @@ function WaveformView_toPrimitive(t, r) { if ("object" != typeof t || !t) return
4630
4956
 
4631
4957
 
4632
4958
 
4959
+
4633
4960
  /** Pointer X in the view and the media time under it; zoom keeps this point fixed. */
4634
4961
 
4635
4962
  /** CSS width × devicePixelRatio, for canvas gradient fills. */
@@ -4637,21 +4964,12 @@ function devicePixelWidth(widthCssPx) {
4637
4964
  const pixelRatio = typeof window !== 'undefined' ? window.devicePixelRatio || 1 : 1;
4638
4965
  return widthCssPx * pixelRatio;
4639
4966
  }
4640
- function prefersReducedMotion() {
4967
+ function WaveformView_prefersReducedMotion() {
4641
4968
  return typeof window !== 'undefined' && typeof window.matchMedia === 'function' && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
4642
4969
  }
4643
- function getScrollLeft(wavesurfer, fallback = 0) {
4970
+ function WaveformView_getScrollLeft(wavesurfer, fallback = 0) {
4644
4971
  return wavesurfer && wavesurfer.getScroll ? wavesurfer.getScroll() : fallback;
4645
4972
  }
4646
-
4647
- /** CSS left % of the playhead from the left of the visible window. */
4648
- function timeLeftPercent(timeSec, durationSec, viewport) {
4649
- if (viewport.widthPx > 0 && viewport.pixelsPerSecond > 0) {
4650
- return `${positionPxFromTime(timeSec, viewport) / viewport.widthPx * 100}%`;
4651
- }
4652
- const progress = durationSec > 0 ? Math.min(1, Math.max(0, timeSec / durationSec)) : 0;
4653
- return `${progress * 100}%`;
4654
- }
4655
4973
  function applyPeaks(wavesurfer, peaks, durationSec) {
4656
4974
  if (!wavesurfer.load) {
4657
4975
  return;
@@ -4693,7 +5011,7 @@ function zoomOriginAtPointer(pointerX, wavesurfer, durationSec, fallbackWidth) {
4693
5011
  }
4694
5012
  return {
4695
5013
  pointerX,
4696
- timeSec: (getScrollLeft(wavesurfer) + pointerX) / fullWidth * durationSec
5014
+ timeSec: (WaveformView_getScrollLeft(wavesurfer) + pointerX) / fullWidth * durationSec
4697
5015
  };
4698
5016
  }
4699
5017
 
@@ -4713,30 +5031,37 @@ function WaveformView({
4713
5031
  peaks,
4714
5032
  zoomLevel: zoomLevelProp
4715
5033
  }) {
5034
+ // DOM / WaveSurfer
4716
5035
  const containerRef = (0,external_react_.useRef)(null);
4717
5036
  const trackRef = (0,external_react_.useRef)(null);
4718
5037
  const playheadRef = (0,external_react_.useRef)(null);
4719
5038
  const playheadAnimationRef = (0,external_react_.useRef)(0);
4720
5039
  const wavesurferRef = (0,external_react_.useRef)(null);
5040
+
5041
+ // Latest props for WaveSurfer + media listeners that must not re-subscribe each render.
4721
5042
  const onSeekRef = (0,external_react_.useRef)(onSeek);
4722
5043
  const interactiveRef = (0,external_react_.useRef)(interactive);
4723
5044
  const hasZoomHandlersRef = (0,external_react_.useRef)(false);
4724
5045
  const currentTimeRef = (0,external_react_.useRef)(currentTime);
4725
5046
  const peaksRef = (0,external_react_.useRef)(peaks);
5047
+ const durationSecRef = (0,external_react_.useRef)(durationSec);
5048
+ const mediaElRef = (0,external_react_.useRef)(mediaEl);
5049
+ const onViewportChangeRef = (0,external_react_.useRef)(onViewportChange);
4726
5050
  const displayedPeaksRef = (0,external_react_.useRef)(null);
4727
5051
  const peakTransitionAnimationRef = (0,external_react_.useRef)(0);
4728
- const durationSecRef = (0,external_react_.useRef)(durationSec);
5052
+ // Zoom / pinch / tile tint (read from pointer + WaveSurfer handlers)
4729
5053
  const zoomOriginRef = (0,external_react_.useRef)(null);
4730
5054
  const pinchStartRef = (0,external_react_.useRef)(null);
5055
+ const pointerZoomRef = (0,external_react_.useRef)(false);
5056
+ const pointerZoomClearTimerRef = (0,external_react_.useRef)(0);
4731
5057
  const bufferProgressRef = (0,external_react_.useRef)(0);
4732
5058
  const hoverProgressRef = (0,external_react_.useRef)(null);
4733
- const programmaticScrollRef = (0,external_react_.useRef)(false);
4734
- const onViewportChangeRef = (0,external_react_.useRef)(onViewportChange);
4735
5059
  onSeekRef.current = onSeek;
4736
5060
  interactiveRef.current = interactive;
4737
5061
  currentTimeRef.current = currentTime;
4738
5062
  peaksRef.current = peaks;
4739
5063
  durationSecRef.current = durationSec;
5064
+ mediaElRef.current = mediaEl;
4740
5065
  onViewportChangeRef.current = onViewportChange;
4741
5066
  const [internalZoom, setInternalZoom] = (0,external_react_.useState)(constants/* WAVEFORM_ZOOM_MIN */.LW);
4742
5067
  const [hoverProgress, setHoverProgress] = (0,external_react_.useState)(null);
@@ -4750,7 +5075,7 @@ function WaveformView({
4750
5075
  });
4751
5076
  hasZoomHandlersRef.current = maxZoom > constants/* WAVEFORM_ZOOM_MIN */.LW && (typeof onZoomChange === 'function' || typeof zoomLevelProp !== 'number');
4752
5077
  const zoomLevel = clampWaveformZoom(isControlled ? zoomLevelProp : internalZoom, maxZoom);
4753
- const zoomRef = (0,external_react_.useRef)(zoomLevel);
5078
+ const zoomRef = (0,external_react_.useRef)(zoomLevel); // latest zoom for WaveSurfer redraw/zoom handlers
4754
5079
  zoomRef.current = zoomLevel;
4755
5080
  const prevZoomRef = (0,external_react_.useRef)(null);
4756
5081
  const isZoomed = zoomLevel > constants/* WAVEFORM_ZOOM_MIN */.LW;
@@ -4765,8 +5090,38 @@ function WaveformView({
4765
5090
  widthPx: canvasWidthPx,
4766
5091
  zoomLevel
4767
5092
  }), [canvasWidthPx, durationSec, height, maxZoom, scrollLeft, zoomLevel]);
4768
- const viewportRef = (0,external_react_.useRef)(viewport);
4769
- viewportRef.current = viewport;
5093
+ const viewportRef = (0,external_react_.useRef)(viewport); // live scroll window; prefer this over render-state while the camera is moving
5094
+ const onViewportCommit = (0,external_react_.useCallback)((scrollLeftPx, nextViewport) => {
5095
+ onViewportChangeRef.current?.(nextViewport);
5096
+ setScrollLeft(scrollLeftPx);
5097
+ }, []);
5098
+ const {
5099
+ apply: applyPlayheadCamera,
5100
+ applyScrollLeft,
5101
+ cancelJump,
5102
+ clearFollowPin,
5103
+ handleScroll: handleCameraScroll,
5104
+ isFollowPinned,
5105
+ onSeek: onPlayheadSeek,
5106
+ onZoom,
5107
+ releaseUserPanHold
5108
+ } = usePlayheadCamera({
5109
+ mediaElRef,
5110
+ onViewportCommit,
5111
+ playheadRef,
5112
+ viewportRef,
5113
+ wavesurferRef
5114
+ });
5115
+ (0,external_react_.useLayoutEffect)(() => {
5116
+ viewportRef.current = createWaveformViewport({
5117
+ durationSec: viewport.durationSec,
5118
+ heightPx: viewport.heightPx,
5119
+ maxZoom: viewport.maxZoom,
5120
+ scrollLeftPx: viewportRef.current.scrollLeftPx,
5121
+ widthPx: viewport.widthPx,
5122
+ zoomLevel: viewport.zoomLevel
5123
+ });
5124
+ }, [viewport]);
4770
5125
  const setZoomLevel = (0,external_react_.useCallback)(nextZoom => {
4771
5126
  const zoom = clampWaveformZoom(nextZoom, maxZoom);
4772
5127
  if (!isControlled) {
@@ -4774,12 +5129,20 @@ function WaveformView({
4774
5129
  }
4775
5130
  onZoomChange?.(zoom);
4776
5131
  }, [isControlled, maxZoom, onZoomChange]);
5132
+ const markPointerZoom = (0,external_react_.useCallback)(() => {
5133
+ pointerZoomRef.current = true;
5134
+ window.clearTimeout(pointerZoomClearTimerRef.current);
5135
+ pointerZoomClearTimerRef.current = window.setTimeout(() => {
5136
+ pointerZoomRef.current = false;
5137
+ pointerZoomClearTimerRef.current = 0;
5138
+ }, constants/* WAVEFORM_ZOOM_DISMISS_MS */.m6);
5139
+ }, []);
4777
5140
  const syncViewport = (0,external_react_.useCallback)(() => {
4778
5141
  const wavesurfer = wavesurferRef.current;
4779
5142
  if (!wavesurfer) {
4780
5143
  return;
4781
5144
  }
4782
- const scrollLeftPx = getScrollLeft(wavesurfer);
5145
+ const scrollLeftPx = WaveformView_getScrollLeft(wavesurfer);
4783
5146
  viewportRef.current = getViewportAtScroll(viewportRef.current, scrollLeftPx);
4784
5147
  onViewportChangeRef.current?.(viewportRef.current);
4785
5148
  setScrollLeft(scrollLeftPx);
@@ -4789,29 +5152,14 @@ function WaveformView({
4789
5152
  if (!playhead) {
4790
5153
  return;
4791
5154
  }
4792
- playhead.style.left = timeLeftPercent(timeSec, durationSecRef.current, viewportRef.current);
5155
+ if (!isFollowPinned()) {
5156
+ playhead.style.left = timeLeftPercent(timeSec, durationSecRef.current, viewportRef.current);
5157
+ }
4793
5158
  const wavesurfer = wavesurferRef.current;
4794
5159
  if (wavesurfer && wavesurfer.setTime) {
4795
5160
  wavesurfer.setTime(timeSec);
4796
5161
  }
4797
- }, []);
4798
- const applyScrollLeft = (0,external_react_.useCallback)((scrollLeftPx, shouldCommitState) => {
4799
- const wavesurfer = wavesurferRef.current;
4800
- if (!wavesurfer || !wavesurfer.setScroll) {
4801
- return;
4802
- }
4803
- programmaticScrollRef.current = true;
4804
- wavesurfer.setScroll(scrollLeftPx);
4805
- viewportRef.current = getViewportAtScroll(viewportRef.current, getScrollLeft(wavesurfer, scrollLeftPx));
4806
- window.requestAnimationFrame(() => {
4807
- // Keep the flag through delayed `scroll` after a zoom setScroll.
4808
- programmaticScrollRef.current = false;
4809
- });
4810
- if (shouldCommitState) {
4811
- onViewportChangeRef.current?.(viewportRef.current);
4812
- setScrollLeft(getScrollLeft(wavesurfer, scrollLeftPx));
4813
- }
4814
- }, []);
5162
+ }, [isFollowPinned]);
4815
5163
  (0,external_react_.useEffect)(() => {
4816
5164
  const container = containerRef.current;
4817
5165
  if (!container) {
@@ -4842,11 +5190,9 @@ function WaveformView({
4842
5190
  onSeekRef.current?.(relativeX * durationSecRef.current);
4843
5191
  });
4844
5192
  const unsubscribeScroll = wavesurfer.on('scroll', () => {
4845
- if (programmaticScrollRef.current) {
4846
- viewportRef.current = getViewportAtScroll(viewportRef.current, getScrollLeft(wavesurfer));
4847
- return;
4848
- }
4849
- syncViewport();
5193
+ handleCameraScroll(() => {
5194
+ syncViewport();
5195
+ });
4850
5196
  });
4851
5197
  const unsubscribeZoom = wavesurfer.on('zoom', () => {
4852
5198
  syncViewport();
@@ -4864,6 +5210,8 @@ function WaveformView({
4864
5210
  displayedPeaksRef.current = peaksRef.current;
4865
5211
  syncViewport();
4866
5212
  return () => {
5213
+ releaseUserPanHold();
5214
+ cancelJump();
4867
5215
  window.cancelAnimationFrame(peakTransitionAnimationRef.current);
4868
5216
  unsubscribeClick();
4869
5217
  unsubscribeScroll();
@@ -4873,7 +5221,7 @@ function WaveformView({
4873
5221
  wavesurferRef.current = null;
4874
5222
  displayedPeaksRef.current = null;
4875
5223
  };
4876
- }, [height, syncViewport]);
5224
+ }, [cancelJump, handleCameraScroll, height, releaseUserPanHold, syncViewport]);
4877
5225
  (0,external_react_.useLayoutEffect)(() => {
4878
5226
  const el = containerRef.current;
4879
5227
  if (!el) {
@@ -4935,23 +5283,30 @@ function WaveformView({
4935
5283
  zoomOriginRef.current = null;
4936
5284
  const didZoomChange = prevZoomRef.current !== zoomLevel;
4937
5285
  prevZoomRef.current = zoomLevel;
5286
+ if (origin || didZoomChange) {
5287
+ onZoom();
5288
+ }
4938
5289
  if (minPxPerSec > 0) {
4939
5290
  if (origin) {
4940
5291
  applyScrollLeft(origin.timeSec * minPxPerSec - origin.pointerX, true);
4941
- } else if (didZoomChange) {
4942
- const maxScroll = Math.max(0, durationSec * minPxPerSec - viewWidthPx);
4943
- applyScrollLeft(Math.min(maxScroll, Math.max(0, currentTimeRef.current * minPxPerSec - viewWidthPx / 2)), true);
5292
+ } else if (didZoomChange && !pointerZoomRef.current) {
5293
+ const zoomedViewport = createWaveformViewport({
5294
+ durationSec,
5295
+ heightPx: height,
5296
+ maxZoom,
5297
+ scrollLeftPx: 0,
5298
+ widthPx: viewWidthPx,
5299
+ zoomLevel
5300
+ });
5301
+ applyScrollLeft(Math.min(maxScrollLeft(zoomedViewport), Math.max(0, currentTimeRef.current * minPxPerSec - viewWidthPx / 2)), true);
4944
5302
  }
4945
5303
  }
4946
5304
  wavesurfer.setTime(currentTimeRef.current);
4947
5305
  syncViewport();
4948
- }, [applyScrollLeft, durationSec, maxZoom, syncViewport, zoomLevel]);
5306
+ updatePlayheadPosition(currentTimeRef.current);
5307
+ }, [applyScrollLeft, durationSec, height, maxZoom, onZoom, syncViewport, updatePlayheadPosition, zoomLevel]);
4949
5308
  (0,external_react_.useLayoutEffect)(() => {
4950
- if (mediaEl && !mediaEl.paused) {
4951
- updatePlayheadPosition(mediaEl.currentTime);
4952
- return;
4953
- }
4954
- updatePlayheadPosition(currentTime);
5309
+ updatePlayheadPosition(mediaEl ? mediaEl.currentTime : currentTime);
4955
5310
  }, [currentTime, durationSec, mediaEl, updatePlayheadPosition, viewport]);
4956
5311
  (0,external_react_.useEffect)(() => {
4957
5312
  const media = mediaEl;
@@ -4961,18 +5316,26 @@ function WaveformView({
4961
5316
  const tick = () => {
4962
5317
  if (!media.paused) {
4963
5318
  updatePlayheadPosition(media.currentTime);
5319
+ applyPlayheadCamera(media.currentTime, false);
4964
5320
  }
4965
5321
  playheadAnimationRef.current = window.requestAnimationFrame(tick);
4966
5322
  };
4967
5323
  const startLoop = () => {
4968
5324
  window.cancelAnimationFrame(playheadAnimationRef.current);
5325
+ releaseUserPanHold();
5326
+ applyPlayheadCamera(media.currentTime, true);
4969
5327
  playheadAnimationRef.current = window.requestAnimationFrame(tick);
4970
5328
  };
4971
5329
  const stopLoop = () => {
4972
5330
  window.cancelAnimationFrame(playheadAnimationRef.current);
5331
+ cancelJump();
5332
+ releaseUserPanHold();
5333
+ clearFollowPin();
5334
+ syncViewport();
4973
5335
  updatePlayheadPosition(media.currentTime);
4974
5336
  };
4975
5337
  const handleSeeked = () => {
5338
+ onPlayheadSeek(media.currentTime);
4976
5339
  updatePlayheadPosition(media.currentTime);
4977
5340
  };
4978
5341
  if (!media.paused) {
@@ -4984,12 +5347,14 @@ function WaveformView({
4984
5347
  media.addEventListener('seeked', handleSeeked);
4985
5348
  return () => {
4986
5349
  window.cancelAnimationFrame(playheadAnimationRef.current);
5350
+ cancelJump();
5351
+ releaseUserPanHold();
4987
5352
  media.removeEventListener('play', startLoop);
4988
5353
  media.removeEventListener('playing', startLoop);
4989
5354
  media.removeEventListener('pause', stopLoop);
4990
5355
  media.removeEventListener('seeked', handleSeeked);
4991
5356
  };
4992
- }, [mediaEl, updatePlayheadPosition]);
5357
+ }, [applyPlayheadCamera, cancelJump, clearFollowPin, mediaEl, onPlayheadSeek, releaseUserPanHold, syncViewport, updatePlayheadPosition]);
4993
5358
  (0,external_react_.useEffect)(() => {
4994
5359
  const wavesurfer = wavesurferRef.current;
4995
5360
  if (!wavesurfer || !wavesurfer.setOptions || !(durationSec > 0)) {
@@ -4997,7 +5362,7 @@ function WaveformView({
4997
5362
  }
4998
5363
  window.cancelAnimationFrame(peakTransitionAnimationRef.current);
4999
5364
  const fromPeaks = displayedPeaksRef.current;
5000
- if (!fromPeaks || fromPeaks === peaks || prefersReducedMotion()) {
5365
+ if (!fromPeaks || fromPeaks === peaks || WaveformView_prefersReducedMotion()) {
5001
5366
  displayedPeaksRef.current = peaks;
5002
5367
  applyPeaks(wavesurfer, peaks, durationSec);
5003
5368
  return undefined;
@@ -5046,6 +5411,7 @@ function WaveformView({
5046
5411
  const captureZoomOrigin = clientX => {
5047
5412
  const rect = track.getBoundingClientRect();
5048
5413
  zoomOriginRef.current = zoomOriginAtPointer(clientX - rect.left, wavesurferRef.current, durationSec, rect.width);
5414
+ markPointerZoom();
5049
5415
  };
5050
5416
 
5051
5417
  /** Zoom origin at the midpoint of a two-finger pinch. */
@@ -5077,6 +5443,7 @@ function WaveformView({
5077
5443
  distance: touchDistance(event.touches),
5078
5444
  zoom: zoomRef.current
5079
5445
  };
5446
+ markPointerZoom();
5080
5447
  };
5081
5448
  const onTouchMove = event => {
5082
5449
  const pinch = pinchStartRef.current;
@@ -5085,6 +5452,7 @@ function WaveformView({
5085
5452
  }
5086
5453
  event.preventDefault();
5087
5454
  zoomOriginRef.current = zoomOriginFromPinch(event.touches);
5455
+ markPointerZoom();
5088
5456
  setZoomLevel(pinch.zoom * (touchDistance(event.touches) / pinch.distance));
5089
5457
  };
5090
5458
  const onTouchEnd = event => {
@@ -5104,13 +5472,14 @@ function WaveformView({
5104
5472
  track.addEventListener('touchend', onTouchEnd);
5105
5473
  track.addEventListener('touchcancel', onTouchEnd);
5106
5474
  return () => {
5475
+ window.clearTimeout(pointerZoomClearTimerRef.current);
5107
5476
  track.removeEventListener('wheel', onZoomWheel);
5108
5477
  track.removeEventListener('touchstart', onTouchStart);
5109
5478
  track.removeEventListener('touchmove', onTouchMove);
5110
5479
  track.removeEventListener('touchend', onTouchEnd);
5111
5480
  track.removeEventListener('touchcancel', onTouchEnd);
5112
5481
  };
5113
- }, [durationSec, setZoomLevel]);
5482
+ }, [durationSec, markPointerZoom, setZoomLevel]);
5114
5483
  const onHoverMove = (0,external_react_.useCallback)(event => {
5115
5484
  if (!interactive) {
5116
5485
  return;
@@ -5512,6 +5881,7 @@ function isFpsAvailable(player) {
5512
5881
  (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
5513
5882
 
5514
5883
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
5884
+ /* harmony export */ Bq: () => (/* binding */ WAVEFORM_PLAYHEAD_JUMP_MS),
5515
5885
  /* harmony export */ DY: () => (/* binding */ WAVEFORM_BAR_RADIUS),
5516
5886
  /* harmony export */ EB: () => (/* binding */ CLIENT_DECODE_MAX_COMPRESSED_BYTES),
5517
5887
  /* harmony export */ FY: () => (/* binding */ MAX_PEAK_COUNT),
@@ -5519,7 +5889,9 @@ function isFpsAvailable(player) {
5519
5889
  /* harmony export */ Kl: () => (/* binding */ WAVEFORM_MIN_VIEW_WINDOW_SEC),
5520
5890
  /* harmony export */ LW: () => (/* binding */ WAVEFORM_ZOOM_MIN),
5521
5891
  /* harmony export */ Lu: () => (/* binding */ WAVEFORM_BAR_GAP),
5892
+ /* harmony export */ NM: () => (/* binding */ WAVEFORM_FOLLOW_INSET_PX),
5522
5893
  /* harmony export */ XS: () => (/* binding */ WAVEFORM_BAR_MIN_HEIGHT),
5894
+ /* harmony export */ Zs: () => (/* binding */ WAVEFORM_FOLLOW_SCROLL_SETTLE_MS),
5523
5895
  /* harmony export */ f3: () => (/* binding */ CLIENT_DECODE_PEAK_COUNT),
5524
5896
  /* harmony export */ i8: () => (/* binding */ PEAK_UNIT_MAX),
5525
5897
  /* harmony export */ m6: () => (/* binding */ WAVEFORM_ZOOM_DISMISS_MS),
@@ -5562,6 +5934,10 @@ const WAVEFORM_ZOOM_MAX = 24;
5562
5934
  const WAVEFORM_MIN_VIEW_WINDOW_SEC = 4;
5563
5935
  const WAVEFORM_ZOOM_SLIDER_MAX = 100;
5564
5936
  const WAVEFORM_ZOOM_DISMISS_MS = 250;
5937
+ const WAVEFORM_FOLLOW_INSET_PX = 200;
5938
+ const WAVEFORM_PLAYHEAD_JUMP_MS = 400;
5939
+ /** After the last user pan, wait this long before the camera may pin again. */
5940
+ const WAVEFORM_FOLLOW_SCROLL_SETTLE_MS = 150;
5565
5941
  const WAVEFORM_BAR_GAP = 2;
5566
5942
  const WAVEFORM_BAR_WIDTH = 2;
5567
5943
  const WAVEFORM_BAR_RADIUS = WAVEFORM_BAR_WIDTH / 2;
@@ -21945,7 +22321,7 @@ class Browser {
21945
22321
  ;// ./src/lib/Logger.js
21946
22322
  /* eslint-disable no-undef */
21947
22323
  const CLIENT_NAME = "box-content-preview";
21948
- const CLIENT_VERSION = "3.84.0";
22324
+ const CLIENT_VERSION = "3.86.0";
21949
22325
  /* eslint-enable no-undef */
21950
22326
 
21951
22327
  class Logger {
@@ -34752,7 +35128,7 @@ class MP3Viewer extends media_MediaBaseViewer {
34752
35128
  * @return {Promise<{ default: Function }>} MP3ControlsV2 module
34753
35129
  */
34754
35130
  importV2Controls() {
34755
- return Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, 3845));
35131
+ return Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, 3678));
34756
35132
  }
34757
35133
 
34758
35134
  /**
@@ -36659,7 +37035,7 @@ function finalizeCluster(group, durationValue) {
36659
37035
  * of its neighbor joins the same cluster. This means distant markers can end up in one cluster
36660
37036
  * if intermediate markers bridge the gap.
36661
37037
  */
36662
- function buildClusters(markers, durationValue, trackWidth) {
37038
+ function buildClusters(markers, durationValue, trackWidth, thresholdPx = CLUSTER_THRESHOLD_PX) {
36663
37039
  if (durationValue <= 0 || markers.length === 0 || trackWidth <= 0) return [];
36664
37040
  const sorted = [...markers].sort((a, b) => a.time - b.time);
36665
37041
  const clusters = [];
@@ -36667,7 +37043,7 @@ function buildClusters(markers, durationValue, trackWidth) {
36667
37043
  for (let i = 1; i < sorted.length; i += 1) {
36668
37044
  const prevPx = sorted[i - 1].time / durationValue * trackWidth;
36669
37045
  const currPx = sorted[i].time / durationValue * trackWidth;
36670
- if (currPx - prevPx <= CLUSTER_THRESHOLD_PX) {
37046
+ if (currPx - prevPx <= thresholdPx) {
36671
37047
  currentGroup.push(sorted[i]);
36672
37048
  } else {
36673
37049
  clusters.push(finalizeCluster(currentGroup, durationValue));
@@ -36808,7 +37184,8 @@ function AnonymousAvatarIcon() {
36808
37184
  function MarkerAvatar({
36809
37185
  avatarUrl,
36810
37186
  colorIndex = 0,
36811
- initial
37187
+ initial,
37188
+ size
36812
37189
  }) {
36813
37190
  const safeIndex = Number.isFinite(colorIndex) ? Math.abs(colorIndex) % AVATAR_PALETTE.length : 0;
36814
37191
  const {
@@ -36832,11 +37209,17 @@ function MarkerAvatar({
36832
37209
  }
36833
37210
  }, initial);
36834
37211
  }
37212
+ const style = {};
37213
+ if (!showImage) {
37214
+ style.backgroundColor = bgColor;
37215
+ }
37216
+ if (size) {
37217
+ style.width = size;
37218
+ style.height = size;
37219
+ }
36835
37220
  return /*#__PURE__*/external_react_["default"].createElement("span", {
36836
37221
  className: "bp-MarkerAvatar",
36837
- style: !showImage ? {
36838
- backgroundColor: bgColor
36839
- } : undefined
37222
+ style: Object.keys(style).length > 0 ? style : undefined
36840
37223
  }, avatar);
36841
37224
  }
36842
37225
  ;// ./src/lib/viewers/controls/media/MarkerAvatarStack.scss
@@ -36849,15 +37232,26 @@ function MarkerAvatar({
36849
37232
  const MAX_VISIBLE_AVATARS = 4;
36850
37233
  function MarkerAvatarStack({
36851
37234
  markers,
36852
- onMarkerClick
37235
+ onMarkerClick,
37236
+ overlapPx,
37237
+ selectedId,
37238
+ size
36853
37239
  }) {
36854
37240
  const hasOverflow = markers.length > MAX_VISIBLE_AVATARS;
36855
37241
  const visibleMarkers = hasOverflow ? markers.slice(0, MAX_VISIBLE_AVATARS - 1) : markers;
37242
+ const overflowMarkers = hasOverflow ? markers.slice(MAX_VISIBLE_AVATARS - 1) : [];
37243
+ const isOverflowSelected = overflowMarkers.some(marker => marker.id === selectedId);
37244
+ const style = overlapPx != null ? {
37245
+ '--bp-marker-stack-overlap': `-${overlapPx}px`
37246
+ } : undefined;
36856
37247
  return /*#__PURE__*/external_react_["default"].createElement("span", {
36857
- className: "bp-MarkerAvatarStack"
37248
+ className: "bp-MarkerAvatarStack",
37249
+ style: style
36858
37250
  }, visibleMarkers.map(marker => /*#__PURE__*/external_react_["default"].createElement("button", {
36859
37251
  key: marker.id,
36860
- className: "bp-MarkerAvatarStack-item",
37252
+ "aria-label": "Comment marker",
37253
+ "aria-pressed": marker.id === selectedId,
37254
+ className: `bp-MarkerAvatarStack-item${marker.id === selectedId ? ' bp-MarkerAvatarStack-item--selected' : ''}`,
36861
37255
  "data-resin-target": "commentMarkerStackAvatar",
36862
37256
  onClick: e => {
36863
37257
  e.stopPropagation();
@@ -36867,9 +37261,12 @@ function MarkerAvatarStack({
36867
37261
  }, /*#__PURE__*/external_react_["default"].createElement(MarkerAvatar, {
36868
37262
  avatarUrl: marker.avatarUrl,
36869
37263
  colorIndex: marker.colorIndex,
36870
- initial: marker.initial
37264
+ initial: marker.initial,
37265
+ size: size
36871
37266
  }))), hasOverflow && /*#__PURE__*/external_react_["default"].createElement("button", {
36872
- className: "bp-MarkerAvatarStack-item bp-MarkerAvatarStack-overflow",
37267
+ "aria-label": "Comment marker",
37268
+ "aria-pressed": isOverflowSelected,
37269
+ className: `bp-MarkerAvatarStack-item bp-MarkerAvatarStack-overflow${isOverflowSelected ? ' bp-MarkerAvatarStack-item--selected' : ''}`,
36873
37270
  "data-resin-target": "commentMarkerStackAvatarOverflow",
36874
37271
  onClick: e => {
36875
37272
  e.stopPropagation();
@@ -36877,7 +37274,11 @@ function MarkerAvatarStack({
36877
37274
  },
36878
37275
  type: "button"
36879
37276
  }, /*#__PURE__*/external_react_["default"].createElement("span", {
36880
- className: "bp-MarkerAvatar bp-MarkerAvatarStack-overflowBadge"
37277
+ className: "bp-MarkerAvatar bp-MarkerAvatarStack-overflowBadge",
37278
+ style: size ? {
37279
+ width: size,
37280
+ height: size
37281
+ } : undefined
36881
37282
  }, /*#__PURE__*/external_react_["default"].createElement("span", {
36882
37283
  className: "bp-MarkerAvatar-initial"
36883
37284
  }, "+", markers.length - (MAX_VISIBLE_AVATARS - 1)))));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "box-content-preview",
3
- "version": "3.84.0",
3
+ "version": "3.86.0",
4
4
  "description": "Box Content Preview UI Element",
5
5
  "author": "Box (https://www.box.com/)",
6
6
  "license": "SEE LICENSE IN LICENSE",