box-content-preview 3.86.0 → 3.88.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/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.86.0"; // eslint-disable-line no-undef
1013
+ const CLIENT_VERSION = "3.88.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 = {};
@@ -2135,6 +2135,204 @@ function DurationLabels({
2135
2135
 
2136
2136
  /***/ },
2137
2137
 
2138
+ /***/ 3524
2139
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
2140
+
2141
+
2142
+ // EXPORTS
2143
+ __webpack_require__.d(__webpack_exports__, {
2144
+ A: () => (/* binding */ MarkerAvatar)
2145
+ });
2146
+
2147
+ // EXTERNAL MODULE: external "react"
2148
+ var external_react_ = __webpack_require__(1649);
2149
+ ;// ./src/lib/viewers/controls/media/MarkerAvatar.scss
2150
+ // extracted by mini-css-extract-plugin
2151
+
2152
+ ;// ./src/lib/viewers/controls/media/MarkerAvatar.tsx
2153
+
2154
+
2155
+ const AVATAR_PALETTE = [{
2156
+ bg: '#7fb0ea',
2157
+ fg: '#222'
2158
+ }, {
2159
+ bg: '#003c84',
2160
+ fg: '#fff'
2161
+ }, {
2162
+ bg: '#ffeb7f',
2163
+ fg: '#222'
2164
+ }, {
2165
+ bg: '#92e0c0',
2166
+ fg: '#222'
2167
+ }, {
2168
+ bg: '#fad98d',
2169
+ fg: '#222'
2170
+ }, {
2171
+ bg: '#91c2fd',
2172
+ fg: '#222'
2173
+ }, {
2174
+ bg: '#f69bab',
2175
+ fg: '#222'
2176
+ }, {
2177
+ bg: '#cf9ff6',
2178
+ fg: '#222'
2179
+ }, {
2180
+ bg: '#f8c08c',
2181
+ fg: '#222'
2182
+ }, {
2183
+ bg: '#a392e0',
2184
+ fg: '#222'
2185
+ }];
2186
+ function AnonymousAvatarIcon() {
2187
+ return /*#__PURE__*/external_react_["default"].createElement("svg", {
2188
+ "aria-hidden": "true",
2189
+ className: "bp-MarkerAvatar-anonymousIcon",
2190
+ focusable: "false",
2191
+ viewBox: "0 0 16 16"
2192
+ }, /*#__PURE__*/external_react_["default"].createElement("path", {
2193
+ d: "M8 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6Zm0 1.5c-2.5 0-5 1.25-5 3.75V14h10v-.75c0-2.5-2.5-3.75-5-3.75Z",
2194
+ fill: "currentColor"
2195
+ }));
2196
+ }
2197
+ function MarkerAvatar({
2198
+ avatarUrl,
2199
+ colorIndex = 0,
2200
+ initial,
2201
+ size
2202
+ }) {
2203
+ const safeIndex = Number.isFinite(colorIndex) ? Math.abs(colorIndex) % AVATAR_PALETTE.length : 0;
2204
+ const {
2205
+ bg: bgColor,
2206
+ fg: textColor
2207
+ } = AVATAR_PALETTE[safeIndex];
2208
+ const [imgFailed, setImgFailed] = external_react_["default"].useState(false);
2209
+ const [loadedUrl, setLoadedUrl] = external_react_["default"].useState(null);
2210
+ const imgRef = external_react_["default"].useRef(null);
2211
+ // Keep initial + palette until onLoad (and for cached complete). Shared with video ticks.
2212
+ const showImage = Boolean(avatarUrl) && !imgFailed && loadedUrl === avatarUrl;
2213
+ external_react_["default"].useEffect(() => {
2214
+ setImgFailed(false);
2215
+ }, [avatarUrl]);
2216
+ external_react_["default"].useLayoutEffect(() => {
2217
+ const img = imgRef.current;
2218
+ if (avatarUrl && img?.complete && img.naturalWidth > 0) {
2219
+ setLoadedUrl(avatarUrl);
2220
+ }
2221
+ }, [avatarUrl]);
2222
+ let fallback = /*#__PURE__*/external_react_["default"].createElement(AnonymousAvatarIcon, null);
2223
+ if (initial) {
2224
+ fallback = /*#__PURE__*/external_react_["default"].createElement("span", {
2225
+ className: "bp-MarkerAvatar-initial",
2226
+ style: {
2227
+ color: textColor
2228
+ }
2229
+ }, initial);
2230
+ }
2231
+ const style = {};
2232
+ if (!showImage) {
2233
+ style.backgroundColor = bgColor;
2234
+ }
2235
+ if (size) {
2236
+ style.width = size;
2237
+ style.height = size;
2238
+ }
2239
+ return /*#__PURE__*/external_react_["default"].createElement("span", {
2240
+ className: "bp-MarkerAvatar",
2241
+ style: Object.keys(style).length > 0 ? style : undefined
2242
+ }, avatarUrl && !imgFailed && /*#__PURE__*/external_react_["default"].createElement("img", {
2243
+ ref: imgRef,
2244
+ alt: "",
2245
+ onError: () => {
2246
+ setImgFailed(true);
2247
+ },
2248
+ onLoad: () => {
2249
+ if (avatarUrl) {
2250
+ setLoadedUrl(avatarUrl);
2251
+ }
2252
+ },
2253
+ src: avatarUrl
2254
+ }), !showImage && fallback);
2255
+ }
2256
+
2257
+ /***/ },
2258
+
2259
+ /***/ 9232
2260
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
2261
+
2262
+
2263
+ // EXPORTS
2264
+ __webpack_require__.d(__webpack_exports__, {
2265
+ A: () => (/* binding */ MarkerAvatarStack)
2266
+ });
2267
+
2268
+ // EXTERNAL MODULE: external "react"
2269
+ var external_react_ = __webpack_require__(1649);
2270
+ // EXTERNAL MODULE: ./src/lib/viewers/controls/media/MarkerAvatar.tsx + 1 modules
2271
+ var MarkerAvatar = __webpack_require__(3524);
2272
+ ;// ./src/lib/viewers/controls/media/MarkerAvatarStack.scss
2273
+ // extracted by mini-css-extract-plugin
2274
+
2275
+ ;// ./src/lib/viewers/controls/media/MarkerAvatarStack.tsx
2276
+
2277
+
2278
+
2279
+ const MAX_VISIBLE_AVATARS = 4;
2280
+ function MarkerAvatarStack({
2281
+ markers,
2282
+ onMarkerClick,
2283
+ overlapPx,
2284
+ selectedId,
2285
+ size
2286
+ }) {
2287
+ const hasOverflow = markers.length > MAX_VISIBLE_AVATARS;
2288
+ const visibleMarkers = hasOverflow ? markers.slice(0, MAX_VISIBLE_AVATARS - 1) : markers;
2289
+ const overflowMarkers = hasOverflow ? markers.slice(MAX_VISIBLE_AVATARS - 1) : [];
2290
+ const isOverflowSelected = overflowMarkers.some(marker => marker.id === selectedId);
2291
+ const style = overlapPx != null ? {
2292
+ '--bp-marker-stack-overlap': `-${overlapPx}px`
2293
+ } : undefined;
2294
+ return /*#__PURE__*/external_react_["default"].createElement("span", {
2295
+ className: "bp-MarkerAvatarStack",
2296
+ style: style
2297
+ }, visibleMarkers.map(marker => /*#__PURE__*/external_react_["default"].createElement("button", {
2298
+ key: marker.id,
2299
+ "aria-label": "Comment marker",
2300
+ "aria-pressed": marker.id === selectedId,
2301
+ className: `bp-MarkerAvatarStack-item${marker.id === selectedId ? ' bp-MarkerAvatarStack-item--selected' : ''}`,
2302
+ "data-resin-target": "commentMarkerStackAvatar",
2303
+ onClick: e => {
2304
+ e.stopPropagation();
2305
+ onMarkerClick?.(marker);
2306
+ },
2307
+ type: "button"
2308
+ }, /*#__PURE__*/external_react_["default"].createElement(MarkerAvatar/* default */.A, {
2309
+ avatarUrl: marker.avatarUrl,
2310
+ colorIndex: marker.colorIndex,
2311
+ initial: marker.initial,
2312
+ size: size
2313
+ }))), hasOverflow && /*#__PURE__*/external_react_["default"].createElement("button", {
2314
+ "aria-label": "Comment marker",
2315
+ "aria-pressed": isOverflowSelected,
2316
+ className: `bp-MarkerAvatarStack-item bp-MarkerAvatarStack-overflow${isOverflowSelected ? ' bp-MarkerAvatarStack-item--selected' : ''}`,
2317
+ "data-resin-target": "commentMarkerStackAvatarOverflow",
2318
+ onClick: e => {
2319
+ e.stopPropagation();
2320
+ onMarkerClick?.(markers[MAX_VISIBLE_AVATARS - 1]);
2321
+ },
2322
+ type: "button"
2323
+ }, /*#__PURE__*/external_react_["default"].createElement("span", {
2324
+ className: "bp-MarkerAvatar bp-MarkerAvatarStack-overflowBadge",
2325
+ style: size ? {
2326
+ width: size,
2327
+ height: size
2328
+ } : undefined
2329
+ }, /*#__PURE__*/external_react_["default"].createElement("span", {
2330
+ className: "bp-MarkerAvatar-initial"
2331
+ }, "+", markers.length - (MAX_VISIBLE_AVATARS - 1)))));
2332
+ }
2333
+
2334
+ /***/ },
2335
+
2138
2336
  /***/ 6929
2139
2337
  (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
2140
2338
 
@@ -3245,6 +3443,75 @@ function VolumeControls({
3245
3443
 
3246
3444
  /***/ },
3247
3445
 
3446
+ /***/ 2400
3447
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
3448
+
3449
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
3450
+ /* harmony export */ A: () => (/* binding */ buildClusters)
3451
+ /* harmony export */ });
3452
+ /* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5346);
3453
+
3454
+
3455
+ /** Max pixel distance between adjacent markers (sorted by time) for them to be grouped into a single cluster. */
3456
+ const CLUSTER_THRESHOLD_PX = 2;
3457
+
3458
+ /** Converts a group of markers into a ClusterData object with computed positions and metadata. */
3459
+ function finalizeCluster(group, durationValue) {
3460
+ const leftPercent = (0,_utils__WEBPACK_IMPORTED_MODULE_0__/* .percent */ .K)(group[0].time, durationValue);
3461
+ const rightPercent = (0,_utils__WEBPACK_IMPORTED_MODULE_0__/* .percent */ .K)(group[group.length - 1].time, durationValue);
3462
+ const isSinglePoint = leftPercent === rightPercent;
3463
+ return {
3464
+ id: group.map(m => m.id).join('|'),
3465
+ isSinglePoint,
3466
+ leftPercent,
3467
+ markers: group,
3468
+ rightPercent
3469
+ };
3470
+ }
3471
+
3472
+ /**
3473
+ * Groups comment markers into clusters based on their pixel proximity on the scrubber track.
3474
+ * Markers are sorted by time, then chained: each marker that is within CLUSTER_THRESHOLD_PX
3475
+ * of its neighbor joins the same cluster. This means distant markers can end up in one cluster
3476
+ * if intermediate markers bridge the gap.
3477
+ */
3478
+ function buildClusters(markers, durationValue, trackWidth, thresholdPx = CLUSTER_THRESHOLD_PX) {
3479
+ if (durationValue <= 0 || markers.length === 0 || trackWidth <= 0) return [];
3480
+ const sorted = [...markers].sort((a, b) => a.time - b.time);
3481
+ const clusters = [];
3482
+ let currentGroup = [sorted[0]];
3483
+ for (let i = 1; i < sorted.length; i += 1) {
3484
+ const prevPx = sorted[i - 1].time / durationValue * trackWidth;
3485
+ const currPx = sorted[i].time / durationValue * trackWidth;
3486
+ if (currPx - prevPx <= thresholdPx) {
3487
+ currentGroup.push(sorted[i]);
3488
+ } else {
3489
+ clusters.push(finalizeCluster(currentGroup, durationValue));
3490
+ currentGroup = [sorted[i]];
3491
+ }
3492
+ }
3493
+ clusters.push(finalizeCluster(currentGroup, durationValue));
3494
+ return clusters;
3495
+ }
3496
+
3497
+ /***/ },
3498
+
3499
+ /***/ 5346
3500
+ (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
3501
+
3502
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
3503
+ /* harmony export */ K: () => (/* binding */ percent)
3504
+ /* harmony export */ });
3505
+ /* unused harmony export round */
3506
+ const round = value => {
3507
+ return +value.toFixed(4);
3508
+ };
3509
+ const percent = (value1, value2) => {
3510
+ return round(value1 / value2 * 100);
3511
+ };
3512
+
3513
+ /***/ },
3514
+
3248
3515
  /***/ 709
3249
3516
  (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
3250
3517
 
@@ -4118,7 +4385,7 @@ function getPdfjsWorkerSrc() {
4118
4385
 
4119
4386
  /***/ },
4120
4387
 
4121
- /***/ 3678
4388
+ /***/ 6180
4122
4389
  (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
4123
4390
 
4124
4391
 
@@ -4283,6 +4550,11 @@ function getViewportAtScroll(viewport, scrollLeftPx) {
4283
4550
  }));
4284
4551
  }
4285
4552
 
4553
+ /** True when the visible window has not moved — skip a React state update. */
4554
+ function viewportEquals(prev, next) {
4555
+ return !!prev && prev.durationSec === next.durationSec && prev.endSec === next.endSec && prev.maxZoom === next.maxZoom && prev.scrollLeftPx === next.scrollLeftPx && prev.startSec === next.startSec && prev.widthPx === next.widthPx && prev.zoomLevel === next.zoomLevel;
4556
+ }
4557
+
4286
4558
  /** How many CSS pixels from the left of the visible window this time sits. */
4287
4559
  function positionPxFromTime(timeSec, viewport) {
4288
4560
  return (timeSec - viewport.startSec) * viewport.pixelsPerSecond;
@@ -4371,6 +4643,35 @@ function clampScrollLeft(scrollLeftPx, viewport) {
4371
4643
  return Math.min(maxScrollLeft(viewport), Math.max(0, scrollLeftPx));
4372
4644
  }
4373
4645
 
4646
+ /** Center this time in the view, clamped so the window still fills the canvas. */
4647
+ function getCenteredScrollLeft(timeSec, viewport) {
4648
+ return clampScrollLeft(timeSec * viewport.pixelsPerSecond - viewport.widthPx / 2, viewport);
4649
+ }
4650
+
4651
+ /**
4652
+ * Host/media seek while zoomed: jump so the time (and its comment avatar) is on screen.
4653
+ * No-op at fit-to-width or when that time is already visible.
4654
+ */
4655
+ function getSeekCameraAction({
4656
+ timeSec,
4657
+ viewport
4658
+ }) {
4659
+ if (viewport.zoomLevel <= constants/* WAVEFORM_ZOOM_MIN */.LW || !(viewport.widthPx > 0) || !(viewport.pixelsPerSecond > 0)) {
4660
+ return {
4661
+ type: 'none'
4662
+ };
4663
+ }
4664
+ if (isTimeInView(timeSec, viewport)) {
4665
+ return {
4666
+ type: 'none'
4667
+ };
4668
+ }
4669
+ return {
4670
+ type: 'jump',
4671
+ scrollLeftPx: getCenteredScrollLeft(timeSec, viewport)
4672
+ };
4673
+ }
4674
+
4374
4675
  /** Follow inset in CSS px, capped at one third of the view so a narrow player still has room. */
4375
4676
  function getFollowInsetPx(widthPx, insetPx = constants/* WAVEFORM_FOLLOW_INSET_PX */.NM) {
4376
4677
  if (!(widthPx > 0)) {
@@ -4447,6 +4748,198 @@ function getPlayheadCameraAction({
4447
4748
  type: 'none'
4448
4749
  };
4449
4750
  }
4751
+ // EXTERNAL MODULE: ./src/lib/viewers/controls/media/buildClusters.ts
4752
+ var buildClusters = __webpack_require__(2400);
4753
+ // EXTERNAL MODULE: ./src/lib/viewers/controls/media/MarkerAvatar.tsx + 1 modules
4754
+ var MarkerAvatar = __webpack_require__(3524);
4755
+ // EXTERNAL MODULE: ./src/lib/viewers/controls/media/MarkerAvatarStack.tsx + 1 modules
4756
+ var MarkerAvatarStack = __webpack_require__(9232);
4757
+ // EXTERNAL MODULE: ./src/lib/viewers/controls/media/utils.ts
4758
+ var utils = __webpack_require__(5346);
4759
+ ;// ./src/lib/viewers/media/waveform/WaveformCommentMarkers.scss
4760
+ // extracted by mini-css-extract-plugin
4761
+
4762
+ ;// ./src/lib/viewers/media/waveform/WaveformCommentMarkers.tsx
4763
+
4764
+
4765
+
4766
+
4767
+
4768
+
4769
+
4770
+ const WAVEFORM_MARKER_SIZE_PX = 20;
4771
+ function hasMappedWindow(viewport) {
4772
+ return !!viewport && Number.isFinite(viewport.startSec) && viewport.endSec > viewport.startSec;
4773
+ }
4774
+ function markerLeftPercent(time, durationSec, viewport) {
4775
+ const mapped = hasMappedWindow(viewport);
4776
+ const origin = mapped ? viewport.startSec : 0;
4777
+ const span = mapped ? viewport.endSec - viewport.startSec : durationSec;
4778
+ return (0,utils/* percent */.K)(time - origin, span);
4779
+ }
4780
+
4781
+ /** Width is unknown until layout. Still place badges, and stack exact same timestamps. */
4782
+ function clustersByExactTime(markers, durationSec) {
4783
+ const sorted = [...markers].sort((a, b) => a.time - b.time);
4784
+ const groups = [];
4785
+ sorted.forEach(marker => {
4786
+ const last = groups[groups.length - 1];
4787
+ if (last && last[last.length - 1].time === marker.time) {
4788
+ last.push(marker);
4789
+ } else {
4790
+ groups.push([marker]);
4791
+ }
4792
+ });
4793
+ return groups.map(group => {
4794
+ const leftPercent = (0,utils/* percent */.K)(group[0].time, durationSec);
4795
+ const rightPercent = (0,utils/* percent */.K)(group[group.length - 1].time, durationSec);
4796
+ return {
4797
+ id: group.map(m => m.id).join('|'),
4798
+ isSinglePoint: leftPercent === rightPercent,
4799
+ leftPercent,
4800
+ markers: group,
4801
+ rightPercent
4802
+ };
4803
+ });
4804
+ }
4805
+ function WaveformCommentMarkers({
4806
+ commentMarkers,
4807
+ durationSec,
4808
+ onCommentMarkerClick,
4809
+ selectedId: hostSelectedId = null,
4810
+ viewport = null
4811
+ }) {
4812
+ const overlayRef = (0,external_react_.useRef)(null);
4813
+ const trackRef = (0,external_react_.useRef)(null);
4814
+ const dismissedIdRef = (0,external_react_.useRef)(null);
4815
+ const [trackWidth, setTrackWidth] = (0,external_react_.useState)(0);
4816
+ const [optimisticSelectedId, setOptimisticSelectedId] = (0,external_react_.useState)(null);
4817
+ const [isSelectionDismissed, setIsSelectionDismissed] = (0,external_react_.useState)(false);
4818
+ const selectedId = optimisticSelectedId ?? (isSelectionDismissed ? null : hostSelectedId);
4819
+ const canShowTrack = durationSec > 0 && commentMarkers.length > 0;
4820
+ const zoomLevel = viewport?.zoomLevel ?? constants/* WAVEFORM_ZOOM_MIN */.LW;
4821
+ const isZoomed = hasMappedWindow(viewport) && viewport.zoomLevel > constants/* WAVEFORM_ZOOM_MIN */.LW;
4822
+ (0,external_react_.useEffect)(() => {
4823
+ setOptimisticSelectedId(null);
4824
+ // Host ack of the dismissed id must not bring the ring back.
4825
+ if (dismissedIdRef.current && hostSelectedId === dismissedIdRef.current) {
4826
+ return;
4827
+ }
4828
+ dismissedIdRef.current = null;
4829
+ setIsSelectionDismissed(false);
4830
+ }, [hostSelectedId]);
4831
+ (0,external_react_.useLayoutEffect)(() => {
4832
+ if (!canShowTrack) {
4833
+ setTrackWidth(0);
4834
+ return undefined;
4835
+ }
4836
+ const el = trackRef.current;
4837
+ if (!el) {
4838
+ return undefined;
4839
+ }
4840
+ setTrackWidth(el.clientWidth);
4841
+ const observer = new ResizeObserver(entries => {
4842
+ entries.forEach(entry => {
4843
+ setTrackWidth(entry.contentRect.width);
4844
+ });
4845
+ });
4846
+ observer.observe(el);
4847
+ return () => observer.disconnect();
4848
+ }, [canShowTrack]);
4849
+ const clusters = (0,external_react_.useMemo)(() => {
4850
+ const clusterWidth = trackWidth * Math.max(constants/* WAVEFORM_ZOOM_MIN */.LW, zoomLevel);
4851
+ if (clusterWidth <= 0) {
4852
+ return clustersByExactTime(commentMarkers, durationSec);
4853
+ }
4854
+ return (0,buildClusters/* default */.A)(commentMarkers, durationSec, clusterWidth, WAVEFORM_MARKER_SIZE_PX);
4855
+ }, [commentMarkers, durationSec, trackWidth, zoomLevel]);
4856
+ const handleMarkerClick = (0,external_react_.useCallback)((marker, event) => {
4857
+ event?.stopPropagation();
4858
+ dismissedIdRef.current = null;
4859
+ setIsSelectionDismissed(false);
4860
+ setOptimisticSelectedId(marker.id);
4861
+ onCommentMarkerClick?.(marker);
4862
+ }, [onCommentMarkerClick]);
4863
+ (0,external_react_.useEffect)(() => {
4864
+ if (!selectedId) {
4865
+ return undefined;
4866
+ }
4867
+ const isEventInsideSelectedBadge = target => {
4868
+ if (!(target instanceof Element) || !overlayRef.current) {
4869
+ return false;
4870
+ }
4871
+ const selected = overlayRef.current.querySelector('.bp-WaveformCommentMarkers-marker--selected, .bp-MarkerAvatarStack-item--selected');
4872
+ return Boolean(selected && selected.contains(target));
4873
+ };
4874
+ const onDocumentPointerDown = event => {
4875
+ if (isEventInsideSelectedBadge(event.target)) {
4876
+ return;
4877
+ }
4878
+ dismissedIdRef.current = selectedId;
4879
+ setOptimisticSelectedId(null);
4880
+ setIsSelectionDismissed(true);
4881
+ const active = document.activeElement;
4882
+ if (active instanceof HTMLElement && overlayRef.current?.contains(active)) {
4883
+ active.blur();
4884
+ }
4885
+ };
4886
+ document.addEventListener('pointerdown', onDocumentPointerDown, true);
4887
+ return () => {
4888
+ document.removeEventListener('pointerdown', onDocumentPointerDown, true);
4889
+ };
4890
+ }, [selectedId]);
4891
+ if (!(durationSec > 0) || commentMarkers.length === 0) {
4892
+ return null;
4893
+ }
4894
+ return /*#__PURE__*/external_react_["default"].createElement("div", {
4895
+ ref: overlayRef,
4896
+ className: `bp-WaveformCommentMarkers${isZoomed ? ' bp-WaveformCommentMarkers--zoomed' : ''}`,
4897
+ "data-testid": "bp-waveform-comment-markers"
4898
+ }, /*#__PURE__*/external_react_["default"].createElement("div", {
4899
+ ref: trackRef,
4900
+ className: "bp-WaveformCommentMarkers-track"
4901
+ }, clusters.map(cluster => {
4902
+ const marker = cluster.markers[0];
4903
+ const isGroup = cluster.markers.length > 1;
4904
+ const isSelected = cluster.markers.some(entry => entry.id === selectedId);
4905
+ const className = `bp-WaveformCommentMarkers-marker${isSelected ? ' bp-WaveformCommentMarkers-marker--selected' : ''}${isGroup ? ' bp-WaveformCommentMarkers-marker--group' : ''}`;
4906
+ const left = `${markerLeftPercent(marker.time, durationSec, viewport)}%`;
4907
+ if (isGroup) {
4908
+ return /*#__PURE__*/external_react_["default"].createElement("div", {
4909
+ key: cluster.id,
4910
+ className: className,
4911
+ "data-testid": "bp-waveform-comment-marker",
4912
+ style: {
4913
+ left
4914
+ }
4915
+ }, /*#__PURE__*/external_react_["default"].createElement(MarkerAvatarStack/* default */.A, {
4916
+ markers: cluster.markers,
4917
+ onMarkerClick: handleMarkerClick,
4918
+ overlapPx: WAVEFORM_MARKER_SIZE_PX / 2,
4919
+ selectedId: selectedId,
4920
+ size: WAVEFORM_MARKER_SIZE_PX
4921
+ }));
4922
+ }
4923
+ return /*#__PURE__*/external_react_["default"].createElement("button", {
4924
+ key: cluster.id,
4925
+ "aria-label": "Comment marker",
4926
+ "aria-pressed": isSelected,
4927
+ className: className,
4928
+ "data-resin-target": "commentMarker",
4929
+ "data-testid": "bp-waveform-comment-marker",
4930
+ onClick: event => handleMarkerClick(marker, event),
4931
+ style: {
4932
+ left
4933
+ },
4934
+ type: "button"
4935
+ }, /*#__PURE__*/external_react_["default"].createElement(MarkerAvatar/* default */.A, {
4936
+ avatarUrl: marker.avatarUrl,
4937
+ colorIndex: marker.colorIndex,
4938
+ initial: marker.initial,
4939
+ size: WAVEFORM_MARKER_SIZE_PX
4940
+ }));
4941
+ })));
4942
+ }
4450
4943
  ;// ./node_modules/wavesurfer.js/dist/wavesurfer.esm.js
4451
4944
  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
4452
4945
  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;
@@ -4792,9 +5285,9 @@ function usePlayheadCamera({
4792
5285
  }
4793
5286
  programmaticScrollRef.current = false;
4794
5287
  });
4795
- if (shouldCommitState) {
4796
- onViewportCommitRef.current(appliedScrollLeft, viewportRef.current);
4797
- }
5288
+ // Overlay always gets the live window. React scroll state only when not pinned,
5289
+ // so WaveformView does not re-render every follow frame.
5290
+ onViewportCommitRef.current(appliedScrollLeft, viewportRef.current, shouldCommitState);
4798
5291
  }, [viewportRef, wavesurferRef]);
4799
5292
  const pinFollowPlayhead = (0,external_react_.useCallback)((playhead, viewport, isPinned) => {
4800
5293
  isFollowPinnedRef.current = isPinned;
@@ -4890,6 +5383,47 @@ function usePlayheadCamera({
4890
5383
  const isFollowCameraScroll = isFollowPinnedRef.current && lastCameraScroll != null && Math.abs(scrollLeftPx - lastCameraScroll) <= 1;
4891
5384
  return !(isCameraOwnedScroll && (jumpAnimationRef.current !== 0 || isFollowCameraScroll || isClampedToMax || !isFollowPinnedRef.current));
4892
5385
  }, [viewportRef]);
5386
+ const seekTo = (0,external_react_.useCallback)(timeSec => {
5387
+ mediaTimeRef.current = timeSec;
5388
+ const wavesurfer = wavesurferRef.current;
5389
+ if (!wavesurfer) {
5390
+ return;
5391
+ }
5392
+ releaseUserPanHold();
5393
+ cancelJump();
5394
+ isFollowPinnedRef.current = false;
5395
+ const liveViewport = getViewportAtScroll(viewportRef.current, getScrollLeft(wavesurfer, viewportRef.current.scrollLeftPx));
5396
+ const action = getSeekCameraAction({
5397
+ timeSec,
5398
+ viewport: liveViewport
5399
+ });
5400
+ if (action.type !== 'jump') {
5401
+ return;
5402
+ }
5403
+ const from = liveViewport.scrollLeftPx;
5404
+ const to = action.scrollLeftPx;
5405
+ if (prefersReducedMotion() || typeof window.requestAnimationFrame !== 'function' || from === to) {
5406
+ applyScrollLeft(to, true);
5407
+ return;
5408
+ }
5409
+ programmaticScrollRef.current = true;
5410
+ const start = (0,util/* getCurrentTimeMs */.RU)();
5411
+ const tick = now => {
5412
+ const t = Math.min(1, (now - start) / constants/* WAVEFORM_PLAYHEAD_JUMP_MS */.Bq);
5413
+ applyScrollLeft(from + (to - from) * (1 - (1 - t) * (1 - t)), false);
5414
+ const playhead = playheadRef.current;
5415
+ if (playhead) {
5416
+ playhead.style.left = timeLeftPercent(mediaTimeRef.current, viewportRef.current.durationSec, viewportRef.current);
5417
+ }
5418
+ if (t < 1) {
5419
+ jumpAnimationRef.current = window.requestAnimationFrame(tick);
5420
+ return;
5421
+ }
5422
+ jumpAnimationRef.current = 0;
5423
+ applyScrollLeft(to, true);
5424
+ };
5425
+ jumpAnimationRef.current = window.requestAnimationFrame(tick);
5426
+ }, [applyScrollLeft, cancelJump, playheadRef, releaseUserPanHold, viewportRef, wavesurferRef]);
4893
5427
  const handleScroll = (0,external_react_.useCallback)(onUserPan => {
4894
5428
  const wavesurfer = wavesurferRef.current;
4895
5429
  if (!wavesurfer) {
@@ -4935,7 +5469,8 @@ function usePlayheadCamera({
4935
5469
  isFollowPinned,
4936
5470
  onSeek,
4937
5471
  onZoom,
4938
- releaseUserPanHold
5472
+ releaseUserPanHold,
5473
+ seekTo
4939
5474
  };
4940
5475
  }
4941
5476
  ;// ./src/lib/viewers/media/waveform/WaveformView.scss
@@ -4977,6 +5512,15 @@ function applyPeaks(wavesurfer, peaks, durationSec) {
4977
5512
  wavesurfer.load('', toChannels(peaks), durationSec);
4978
5513
  }
4979
5514
 
5515
+ /** Stop the zoomed waveform from bouncing on trackpad overscroll. WaveSurfer's scroller is inside a shadow root, so SCSS uses `::part(scroll)` while zoomed and this sets the same property as soon as WaveSurfer exists. */
5516
+ function disableScrollOverscroll(container) {
5517
+ const host = container.firstElementChild;
5518
+ const scroll = host instanceof HTMLElement ? host.shadowRoot?.querySelector('.scroll') : null;
5519
+ if (scroll instanceof HTMLElement) {
5520
+ scroll.style.overscrollBehaviorX = 'none';
5521
+ }
5522
+ }
5523
+
4980
5524
  /** Tint WaveSurfer's zoomed tiles with played/unplayed/hover/buffer colors. */
4981
5525
  function tintZoomedWaveform(wavesurfer, fills, replaceSnapshot = false) {
4982
5526
  const wrapper = wavesurfer.getWrapper ? wavesurfer.getWrapper() : null;
@@ -5054,6 +5598,9 @@ function WaveformView({
5054
5598
  const pinchStartRef = (0,external_react_.useRef)(null);
5055
5599
  const pointerZoomRef = (0,external_react_.useRef)(false);
5056
5600
  const pointerZoomClearTimerRef = (0,external_react_.useRef)(0);
5601
+ const applyZoomWindowRef = (0,external_react_.useRef)(null);
5602
+ // WaveSurfer `setOptions` fires zoom/scroll before we apply the intended scroll.
5603
+ const suppressViewportSyncRef = (0,external_react_.useRef)(false);
5057
5604
  const bufferProgressRef = (0,external_react_.useRef)(0);
5058
5605
  const hoverProgressRef = (0,external_react_.useRef)(null);
5059
5606
  onSeekRef.current = onSeek;
@@ -5091,9 +5638,11 @@ function WaveformView({
5091
5638
  zoomLevel
5092
5639
  }), [canvasWidthPx, durationSec, height, maxZoom, scrollLeft, zoomLevel]);
5093
5640
  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) => {
5641
+ const onViewportCommit = (0,external_react_.useCallback)((scrollLeftPx, nextViewport, commitReactState = true) => {
5095
5642
  onViewportChangeRef.current?.(nextViewport);
5096
- setScrollLeft(scrollLeftPx);
5643
+ if (commitReactState) {
5644
+ setScrollLeft(scrollLeftPx);
5645
+ }
5097
5646
  }, []);
5098
5647
  const {
5099
5648
  apply: applyPlayheadCamera,
@@ -5104,7 +5653,8 @@ function WaveformView({
5104
5653
  isFollowPinned,
5105
5654
  onSeek: onPlayheadSeek,
5106
5655
  onZoom,
5107
- releaseUserPanHold
5656
+ releaseUserPanHold,
5657
+ seekTo
5108
5658
  } = usePlayheadCamera({
5109
5659
  mediaElRef,
5110
5660
  onViewportCommit,
@@ -5160,6 +5710,60 @@ function WaveformView({
5160
5710
  wavesurfer.setTime(timeSec);
5161
5711
  }
5162
5712
  }, [isFollowPinned]);
5713
+
5714
+ // Same zoom-window body as the zoom effect; extracted so resize can call it too.
5715
+ const applyZoomWindow = (0,external_react_.useCallback)(() => {
5716
+ const wavesurfer = wavesurferRef.current;
5717
+ const container = containerRef.current;
5718
+ if (!wavesurfer || !wavesurfer.setOptions || !container) {
5719
+ return;
5720
+ }
5721
+ const viewWidthPx = wavesurfer.getWidth ? wavesurfer.getWidth() : container.clientWidth;
5722
+ const minPxPerSec = getZoomedPixelsPerSecond({
5723
+ durationSec,
5724
+ maxZoom,
5725
+ viewWidthPx,
5726
+ zoomLevel
5727
+ });
5728
+ const origin = zoomOriginRef.current;
5729
+ zoomOriginRef.current = null;
5730
+ const didZoomChange = prevZoomRef.current !== zoomLevel;
5731
+ if (origin || didZoomChange) {
5732
+ onZoom();
5733
+ }
5734
+ suppressViewportSyncRef.current = true;
5735
+ try {
5736
+ wavesurfer.setOptions(WaveformView_objectSpread({
5737
+ autoScroll: false,
5738
+ minPxPerSec
5739
+ }, zoomLevel > constants/* WAVEFORM_ZOOM_MIN */.LW ? {
5740
+ progressColor: WAVEFORM_COLOR_PLAYED,
5741
+ waveColor: WAVEFORM_COLOR_UNPLAYED
5742
+ } : {}));
5743
+ if (minPxPerSec > 0) {
5744
+ if (origin) {
5745
+ applyScrollLeft(origin.timeSec * minPxPerSec - origin.pointerX, true);
5746
+ } else if (didZoomChange && !pointerZoomRef.current) {
5747
+ const zoomedViewport = createWaveformViewport({
5748
+ durationSec,
5749
+ heightPx: height,
5750
+ maxZoom,
5751
+ scrollLeftPx: 0,
5752
+ widthPx: viewWidthPx,
5753
+ zoomLevel
5754
+ });
5755
+ applyScrollLeft(Math.min(maxScrollLeft(zoomedViewport), Math.max(0, currentTimeRef.current * minPxPerSec - viewWidthPx / 2)), true);
5756
+ }
5757
+ }
5758
+ wavesurfer.setTime(currentTimeRef.current);
5759
+ } finally {
5760
+ suppressViewportSyncRef.current = false;
5761
+ prevZoomRef.current = zoomLevel;
5762
+ }
5763
+ syncViewport();
5764
+ updatePlayheadPosition(currentTimeRef.current);
5765
+ }, [applyScrollLeft, durationSec, height, maxZoom, onZoom, syncViewport, updatePlayheadPosition, zoomLevel]);
5766
+ applyZoomWindowRef.current = applyZoomWindow;
5163
5767
  (0,external_react_.useEffect)(() => {
5164
5768
  const container = containerRef.current;
5165
5769
  if (!container) {
@@ -5190,11 +5794,17 @@ function WaveformView({
5190
5794
  onSeekRef.current?.(relativeX * durationSecRef.current);
5191
5795
  });
5192
5796
  const unsubscribeScroll = wavesurfer.on('scroll', () => {
5797
+ if (suppressViewportSyncRef.current) {
5798
+ return;
5799
+ }
5193
5800
  handleCameraScroll(() => {
5194
5801
  syncViewport();
5195
5802
  });
5196
5803
  });
5197
5804
  const unsubscribeZoom = wavesurfer.on('zoom', () => {
5805
+ if (suppressViewportSyncRef.current) {
5806
+ return;
5807
+ }
5198
5808
  syncViewport();
5199
5809
  });
5200
5810
  const unsubscribeRedraw = wavesurfer.on('redrawcomplete', () => {
@@ -5208,7 +5818,9 @@ function WaveformView({
5208
5818
  });
5209
5819
  wavesurferRef.current = wavesurfer;
5210
5820
  displayedPeaksRef.current = peaksRef.current;
5821
+ disableScrollOverscroll(container);
5211
5822
  syncViewport();
5823
+ applyZoomWindowRef.current?.();
5212
5824
  return () => {
5213
5825
  releaseUserPanHold();
5214
5826
  cancelJump();
@@ -5248,7 +5860,8 @@ function WaveformView({
5248
5860
  }
5249
5861
  }, [internalZoom, isControlled, maxZoom, zoomLevelProp]);
5250
5862
  (0,external_react_.useEffect)(() => {
5251
- onViewportChange?.(viewport);
5863
+ // Follow skips React scrollLeft; emit the layout-refreshed live window instead.
5864
+ onViewportChange?.(viewportRef.current);
5252
5865
  }, [onViewportChange, viewport]);
5253
5866
  (0,external_react_.useEffect)(() => {
5254
5867
  const wavesurfer = wavesurferRef.current;
@@ -5259,52 +5872,9 @@ function WaveformView({
5259
5872
  interact: interactive
5260
5873
  });
5261
5874
  }, [interactive]);
5262
- (0,external_react_.useEffect)(() => {
5263
- const wavesurfer = wavesurferRef.current;
5264
- const container = containerRef.current;
5265
- if (!wavesurfer || !wavesurfer.setOptions || !container) {
5266
- return;
5267
- }
5268
- const viewWidthPx = wavesurfer.getWidth ? wavesurfer.getWidth() : container.clientWidth;
5269
- const minPxPerSec = getZoomedPixelsPerSecond({
5270
- durationSec,
5271
- maxZoom,
5272
- viewWidthPx,
5273
- zoomLevel
5274
- });
5275
- wavesurfer.setOptions(WaveformView_objectSpread({
5276
- autoScroll: false,
5277
- minPxPerSec
5278
- }, zoomLevel > constants/* WAVEFORM_ZOOM_MIN */.LW ? {
5279
- progressColor: WAVEFORM_COLOR_PLAYED,
5280
- waveColor: WAVEFORM_COLOR_UNPLAYED
5281
- } : {}));
5282
- const origin = zoomOriginRef.current;
5283
- zoomOriginRef.current = null;
5284
- const didZoomChange = prevZoomRef.current !== zoomLevel;
5285
- prevZoomRef.current = zoomLevel;
5286
- if (origin || didZoomChange) {
5287
- onZoom();
5288
- }
5289
- if (minPxPerSec > 0) {
5290
- if (origin) {
5291
- applyScrollLeft(origin.timeSec * minPxPerSec - origin.pointerX, 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);
5302
- }
5303
- }
5304
- wavesurfer.setTime(currentTimeRef.current);
5305
- syncViewport();
5306
- updatePlayheadPosition(currentTimeRef.current);
5307
- }, [applyScrollLeft, durationSec, height, maxZoom, onZoom, syncViewport, updatePlayheadPosition, zoomLevel]);
5875
+ (0,external_react_.useLayoutEffect)(() => {
5876
+ applyZoomWindow();
5877
+ }, [applyZoomWindow]);
5308
5878
  (0,external_react_.useLayoutEffect)(() => {
5309
5879
  updatePlayheadPosition(mediaEl ? mediaEl.currentTime : currentTime);
5310
5880
  }, [currentTime, durationSec, mediaEl, updatePlayheadPosition, viewport]);
@@ -5336,6 +5906,7 @@ function WaveformView({
5336
5906
  };
5337
5907
  const handleSeeked = () => {
5338
5908
  onPlayheadSeek(media.currentTime);
5909
+ seekTo(media.currentTime);
5339
5910
  updatePlayheadPosition(media.currentTime);
5340
5911
  };
5341
5912
  if (!media.paused) {
@@ -5354,7 +5925,7 @@ function WaveformView({
5354
5925
  media.removeEventListener('pause', stopLoop);
5355
5926
  media.removeEventListener('seeked', handleSeeked);
5356
5927
  };
5357
- }, [applyPlayheadCamera, cancelJump, clearFollowPin, mediaEl, onPlayheadSeek, releaseUserPanHold, syncViewport, updatePlayheadPosition]);
5928
+ }, [applyPlayheadCamera, cancelJump, clearFollowPin, mediaEl, onPlayheadSeek, releaseUserPanHold, seekTo, syncViewport, updatePlayheadPosition]);
5358
5929
  (0,external_react_.useEffect)(() => {
5359
5930
  const wavesurfer = wavesurferRef.current;
5360
5931
  if (!wavesurfer || !wavesurfer.setOptions || !(durationSec > 0)) {
@@ -5530,27 +6101,70 @@ function WaveformView({
5530
6101
  "data-testid": "bp-waveform-hover-time"
5531
6102
  }, formatTime(hoverProgress * durationSec)))));
5532
6103
  }
6104
+ /* harmony default export */ const waveform_WaveformView = (/*#__PURE__*/external_react_["default"].memo(WaveformView));
5533
6105
  // EXTERNAL MODULE: ./node_modules/classnames/index.js
5534
6106
  var classnames = __webpack_require__(2485);
5535
6107
  var classnames_default = /*#__PURE__*/__webpack_require__.n(classnames);
5536
- ;// ./src/lib/viewers/controls/icons/IconZoom24.tsx
6108
+ ;// ./src/lib/viewers/controls/icons/IconZoomIn24.tsx
5537
6109
 
5538
- function IconZoom24() {
6110
+ function IconZoomIn24() {
5539
6111
  return /*#__PURE__*/external_react_.createElement("svg", {
5540
6112
  focusable: false,
5541
6113
  height: 24,
5542
6114
  viewBox: "0 0 24 24",
5543
6115
  width: 24
5544
- }, /*#__PURE__*/external_react_.createElement("path", {
5545
- d: "M2 12h20M6 8l-4 4 4 4M18 8l4 4-4 4",
6116
+ }, /*#__PURE__*/external_react_.createElement("circle", {
6117
+ cx: "10",
6118
+ cy: "10",
6119
+ fill: "none",
6120
+ r: "6.25",
6121
+ stroke: "currentColor",
6122
+ strokeWidth: "1.75"
6123
+ }), /*#__PURE__*/external_react_.createElement("path", {
6124
+ d: "M14.5 14.5 20 20",
5546
6125
  fill: "none",
5547
6126
  stroke: "currentColor",
5548
6127
  strokeLinecap: "round",
5549
- strokeLinejoin: "round",
5550
- strokeWidth: "2"
6128
+ strokeWidth: "1.75"
6129
+ }), /*#__PURE__*/external_react_.createElement("path", {
6130
+ d: "M10 7.25v5.5M7.25 10h5.5",
6131
+ fill: "none",
6132
+ stroke: "currentColor",
6133
+ strokeLinecap: "round",
6134
+ strokeWidth: "1.75"
5551
6135
  }));
5552
6136
  }
5553
- /* harmony default export */ const icons_IconZoom24 = (IconZoom24);
6137
+ /* harmony default export */ const icons_IconZoomIn24 = (IconZoomIn24);
6138
+ ;// ./src/lib/viewers/controls/icons/IconZoomOut24.tsx
6139
+
6140
+ function IconZoomOut24() {
6141
+ return /*#__PURE__*/external_react_.createElement("svg", {
6142
+ focusable: false,
6143
+ height: 24,
6144
+ viewBox: "0 0 24 24",
6145
+ width: 24
6146
+ }, /*#__PURE__*/external_react_.createElement("circle", {
6147
+ cx: "10",
6148
+ cy: "10",
6149
+ fill: "none",
6150
+ r: "6.25",
6151
+ stroke: "currentColor",
6152
+ strokeWidth: "1.75"
6153
+ }), /*#__PURE__*/external_react_.createElement("path", {
6154
+ d: "M14.5 14.5 20 20",
6155
+ fill: "none",
6156
+ stroke: "currentColor",
6157
+ strokeLinecap: "round",
6158
+ strokeWidth: "1.75"
6159
+ }), /*#__PURE__*/external_react_.createElement("path", {
6160
+ d: "M7.25 10h5.5",
6161
+ fill: "none",
6162
+ stroke: "currentColor",
6163
+ strokeLinecap: "round",
6164
+ strokeWidth: "1.75"
6165
+ }));
6166
+ }
6167
+ /* harmony default export */ const icons_IconZoomOut24 = (IconZoomOut24);
5554
6168
  // EXTERNAL MODULE: ./src/lib/viewers/controls/media/MediaToggle.tsx
5555
6169
  var MediaToggle = __webpack_require__(8997);
5556
6170
  // EXTERNAL MODULE: ./src/lib/viewers/controls/slider/SliderControl.tsx + 1 modules
@@ -5567,6 +6181,7 @@ var SliderControl = __webpack_require__(4937);
5567
6181
 
5568
6182
 
5569
6183
 
6184
+
5570
6185
  function WaveformZoomControl({
5571
6186
  isRevealed = false,
5572
6187
  maxZoom,
@@ -5576,39 +6191,25 @@ function WaveformZoomControl({
5576
6191
  const [isHovered, setHovered] = (0,external_react_.useState)(false);
5577
6192
  const [isFocused, setFocused] = (0,external_react_.useState)(false);
5578
6193
  const dismissTimerRef = (0,external_react_.useRef)(0);
5579
- const flyoutRef = (0,external_react_.useRef)(null);
5580
- const shouldFocusSliderRef = (0,external_react_.useRef)(false);
5581
6194
  const sliderId = `bp-waveform-zoom-slider${(0,external_react_.useId)()}`;
5582
6195
  const zoom = clampWaveformZoom(zoomLevel, maxZoom);
5583
6196
  const zoomValue = Math.round(sliderValueFromZoom(zoom, maxZoom));
5584
6197
  const isOpen = isHovered || isFocused || isRevealed;
6198
+ const isAtMinZoom = zoomValue <= 0;
6199
+ const isAtMaxZoom = zoomValue >= constants/* WAVEFORM_ZOOM_SLIDER_MAX */.nh;
5585
6200
  const clearDismiss = (0,external_react_.useCallback)(() => {
5586
6201
  window.clearTimeout(dismissTimerRef.current);
5587
6202
  dismissTimerRef.current = 0;
5588
6203
  }, []);
5589
6204
  (0,external_react_.useEffect)(() => () => window.clearTimeout(dismissTimerRef.current), []);
5590
- (0,external_react_.useLayoutEffect)(() => {
5591
- if (!isOpen || !shouldFocusSliderRef.current) {
5592
- return;
5593
- }
5594
- shouldFocusSliderRef.current = false;
5595
- flyoutRef.current?.querySelector('[role="slider"]')?.focus();
5596
- }, [isOpen]);
5597
6205
  const handleSlider = (0,external_react_.useCallback)(newValue => {
5598
6206
  onZoomChange(zoomFromSliderValue(newValue, maxZoom));
5599
6207
  }, [maxZoom, onZoomChange]);
5600
- const handleToggleClick = (0,external_react_.useCallback)(() => {
5601
- clearDismiss();
5602
- if (isOpen) {
5603
- shouldFocusSliderRef.current = false;
5604
- setFocused(false);
5605
- setHovered(false);
5606
- return;
5607
- }
5608
- shouldFocusSliderRef.current = true;
5609
- setFocused(true);
5610
- }, [clearDismiss, isOpen]);
6208
+ const handleStep = (0,external_react_.useCallback)(delta => {
6209
+ onZoomChange(zoomFromSliderValue(zoomValue + delta, maxZoom));
6210
+ }, [maxZoom, onZoomChange, zoomValue]);
5611
6211
  return /*#__PURE__*/external_react_["default"].createElement("div", {
6212
+ "aria-label": "Zoom",
5612
6213
  className: classnames_default()('bp-WaveformZoomControl', {
5613
6214
  'bp-is-open': isOpen
5614
6215
  }),
@@ -5632,14 +6233,37 @@ function WaveformZoomControl({
5632
6233
  dismissTimerRef.current = window.setTimeout(() => {
5633
6234
  setHovered(false);
5634
6235
  }, constants/* WAVEFORM_ZOOM_DISMISS_MS */.m6);
5635
- }
5636
- }, /*#__PURE__*/external_react_["default"].createElement("div", {
5637
- ref: flyoutRef,
6236
+ },
6237
+ role: "group"
6238
+ }, /*#__PURE__*/external_react_["default"].createElement(MediaToggle/* default */.A, {
6239
+ "aria-disabled": isAtMaxZoom,
6240
+ className: "bp-WaveformZoomControl-button",
6241
+ "data-resin-target": "waveformZoomIn",
6242
+ "data-testid": "bp-waveform-zoom-in",
6243
+ onClick: () => {
6244
+ if (!isAtMaxZoom) {
6245
+ handleStep(constants/* WAVEFORM_ZOOM_BUTTON_STEP */.QD);
6246
+ }
6247
+ },
6248
+ title: "Zoom in"
6249
+ }, /*#__PURE__*/external_react_["default"].createElement(icons_IconZoomIn24, null)), /*#__PURE__*/external_react_["default"].createElement("div", {
5638
6250
  "aria-hidden": !isOpen,
5639
6251
  className: classnames_default()('bp-WaveformZoomControl-flyout', {
5640
6252
  'bp-is-open': isOpen
5641
6253
  })
5642
- }, /*#__PURE__*/external_react_["default"].createElement(SliderControl/* default */.A, {
6254
+ }, /*#__PURE__*/external_react_["default"].createElement(MediaToggle/* default */.A, {
6255
+ "aria-disabled": isAtMinZoom,
6256
+ className: "bp-WaveformZoomControl-button",
6257
+ "data-resin-target": "waveformZoomOut",
6258
+ "data-testid": "bp-waveform-zoom-out",
6259
+ onClick: () => {
6260
+ if (!isAtMinZoom) {
6261
+ handleStep(-constants/* WAVEFORM_ZOOM_BUTTON_STEP */.QD);
6262
+ }
6263
+ },
6264
+ tabIndex: isOpen ? 0 : -1,
6265
+ title: "Zoom out"
6266
+ }, /*#__PURE__*/external_react_["default"].createElement(icons_IconZoomOut24, null)), /*#__PURE__*/external_react_["default"].createElement(SliderControl/* default */.A, {
5643
6267
  "aria-hidden": !isOpen,
5644
6268
  className: "bp-WaveformZoomControl-slider",
5645
6269
  "data-resin-target": "waveformZoomSlider",
@@ -5654,14 +6278,7 @@ function WaveformZoomControl({
5654
6278
  tabIndex: isOpen ? 0 : -1,
5655
6279
  title: "Zoom Slider",
5656
6280
  value: zoomValue
5657
- })), /*#__PURE__*/external_react_["default"].createElement(MediaToggle/* default */.A, {
5658
- "aria-controls": sliderId,
5659
- "aria-expanded": isOpen,
5660
- className: "bp-WaveformZoomControl-toggle",
5661
- "data-resin-target": "waveformZoom",
5662
- onClick: handleToggleClick,
5663
- title: "Zoom"
5664
- }, /*#__PURE__*/external_react_["default"].createElement(icons_IconZoom24, null)));
6281
+ })));
5665
6282
  }
5666
6283
  ;// ./src/lib/viewers/media/MP3ControlsV2.scss
5667
6284
  // extracted by mini-css-extract-plugin
@@ -5680,15 +6297,18 @@ function WaveformZoomControl({
5680
6297
 
5681
6298
 
5682
6299
 
6300
+
5683
6301
  const PLACEHOLDER_PEAKS = placeholderPeaks();
5684
6302
  function MP3ControlsV2({
5685
6303
  autoplay,
5686
6304
  bufferedRange,
6305
+ commentMarkers,
5687
6306
  currentTime,
5688
6307
  durationTime,
5689
6308
  isPlaying,
5690
6309
  mediaEl,
5691
6310
  onAutoplayChange,
6311
+ onCommentMarkerClick,
5692
6312
  onMuteChange,
5693
6313
  onPlayPause,
5694
6314
  onRateChange,
@@ -5708,8 +6328,10 @@ function MP3ControlsV2({
5708
6328
  const hasMetadata = durationValue > 0;
5709
6329
  const waveformDurationSec = hasMetadata ? durationValue : PLACEHOLDER_DURATION_SEC;
5710
6330
  const [playRequested, setPlayRequested] = (0,external_react_.useState)(false);
5711
- const handleViewportChange = (0,external_react_.useCallback)(viewport => {
5712
- setMaxZoom(viewport.maxZoom);
6331
+ const [viewport, setViewport] = (0,external_react_.useState)(null);
6332
+ const handleViewportChange = (0,external_react_.useCallback)(next => {
6333
+ setMaxZoom(prev => prev === next.maxZoom ? prev : next.maxZoom);
6334
+ setViewport(prev => viewportEquals(prev, next) ? prev : next);
5713
6335
  }, []);
5714
6336
  const revealZoomControl = (0,external_react_.useCallback)(() => {
5715
6337
  setIsZoomRevealed(true);
@@ -5735,7 +6357,20 @@ function MP3ControlsV2({
5735
6357
  const handlePlayOverlayClick = (0,external_react_.useCallback)(() => {
5736
6358
  setPlayRequested(true);
5737
6359
  onPlayPause(true);
5738
- }, [onPlayPause]);
6360
+ // Overlay unmounts on click; without this, focus lands on body and Space is lost.
6361
+ mediaEl?.closest('.bp-media-container')?.focus();
6362
+ }, [mediaEl, onPlayPause]);
6363
+ const waveformMarkers = (0,external_react_.useMemo)(() => commentMarkers || [], [commentMarkers]);
6364
+ const selectedMarkerId = (0,external_react_.useMemo)(() => waveformMarkers.find(marker => marker.isSelected)?.id ?? null, [waveformMarkers]);
6365
+ const handleCommentMarkerClick = (0,external_react_.useCallback)(marker => {
6366
+ setPlayRequested(true);
6367
+ onPlayPause(false);
6368
+ if (onCommentMarkerClick) {
6369
+ onCommentMarkerClick(marker);
6370
+ return;
6371
+ }
6372
+ onTimeChange(marker.time);
6373
+ }, [onCommentMarkerClick, onPlayPause, onTimeChange]);
5739
6374
  const isWaveformInteractive = playRequested && hasMetadata;
5740
6375
  const isWaitingToPlay = playRequested && !hasMetadata;
5741
6376
  const showPlayOverlay = !playRequested && !isPlaying;
@@ -5746,7 +6381,9 @@ function MP3ControlsV2({
5746
6381
  "data-testid": "media-controls-wrapper-v2"
5747
6382
  }, /*#__PURE__*/external_react_["default"].createElement("div", {
5748
6383
  className: "bp-MP3ControlsV2-stage"
5749
- }, /*#__PURE__*/external_react_["default"].createElement(WaveformView, {
6384
+ }, /*#__PURE__*/external_react_["default"].createElement("div", {
6385
+ className: "bp-MP3ControlsV2-waveform"
6386
+ }, /*#__PURE__*/external_react_["default"].createElement(waveform_WaveformView, {
5750
6387
  bufferedRange: bufferedRange,
5751
6388
  currentTime: currentTime,
5752
6389
  durationSec: waveformDurationSec,
@@ -5757,7 +6394,13 @@ function MP3ControlsV2({
5757
6394
  onZoomChange: hasZoomHandlers ? handleWaveformZoom : undefined,
5758
6395
  peaks: waveformPeaks,
5759
6396
  zoomLevel: hasZoomHandlers ? zoomLevel : constants/* WAVEFORM_ZOOM_MIN */.LW
5760
- }), hasZoomControl && /*#__PURE__*/external_react_["default"].createElement("div", {
6397
+ }), /*#__PURE__*/external_react_["default"].createElement(WaveformCommentMarkers, {
6398
+ commentMarkers: waveformMarkers,
6399
+ durationSec: hasMetadata ? durationValue : 0,
6400
+ onCommentMarkerClick: handleCommentMarkerClick,
6401
+ selectedId: selectedMarkerId,
6402
+ viewport: viewport
6403
+ })), hasZoomControl && /*#__PURE__*/external_react_["default"].createElement("div", {
5761
6404
  className: "bp-MP3ControlsV2-waveformZoom"
5762
6405
  }, /*#__PURE__*/external_react_["default"].createElement(WaveformZoomControl, {
5763
6406
  isRevealed: isZoomRevealed,
@@ -5774,6 +6417,7 @@ function MP3ControlsV2({
5774
6417
  },
5775
6418
  "data-testid": "bp-MP3ControlsV2-play-overlay",
5776
6419
  onClick: handlePlayOverlayClick,
6420
+ onMouseDown: event => event.preventDefault(),
5777
6421
  title: "Play",
5778
6422
  type: "button"
5779
6423
  }), isWaitingToPlay && /*#__PURE__*/external_react_["default"].createElement("div", {
@@ -5890,6 +6534,7 @@ function isFpsAvailable(player) {
5890
6534
  /* harmony export */ LW: () => (/* binding */ WAVEFORM_ZOOM_MIN),
5891
6535
  /* harmony export */ Lu: () => (/* binding */ WAVEFORM_BAR_GAP),
5892
6536
  /* harmony export */ NM: () => (/* binding */ WAVEFORM_FOLLOW_INSET_PX),
6537
+ /* harmony export */ QD: () => (/* binding */ WAVEFORM_ZOOM_BUTTON_STEP),
5893
6538
  /* harmony export */ XS: () => (/* binding */ WAVEFORM_BAR_MIN_HEIGHT),
5894
6539
  /* harmony export */ Zs: () => (/* binding */ WAVEFORM_FOLLOW_SCROLL_SETTLE_MS),
5895
6540
  /* harmony export */ f3: () => (/* binding */ CLIENT_DECODE_PEAK_COUNT),
@@ -5933,6 +6578,8 @@ const WAVEFORM_ZOOM_MAX = 24;
5933
6578
  /** Visible window never shorter than this. */
5934
6579
  const WAVEFORM_MIN_VIEW_WINDOW_SEC = 4;
5935
6580
  const WAVEFORM_ZOOM_SLIDER_MAX = 100;
6581
+ /** One click on zoom in/out moves this many units on the 0–100 slider. */
6582
+ const WAVEFORM_ZOOM_BUTTON_STEP = 10;
5936
6583
  const WAVEFORM_ZOOM_DISMISS_MS = 250;
5937
6584
  const WAVEFORM_FOLLOW_INSET_PX = 200;
5938
6585
  const WAVEFORM_PLAYHEAD_JUMP_MS = 400;
@@ -22321,7 +22968,7 @@ class Browser {
22321
22968
  ;// ./src/lib/Logger.js
22322
22969
  /* eslint-disable no-undef */
22323
22970
  const CLIENT_NAME = "box-content-preview";
22324
- const CLIENT_VERSION = "3.86.0";
22971
+ const CLIENT_VERSION = "3.88.0";
22325
22972
  /* eslint-enable no-undef */
22326
22973
 
22327
22974
  class Logger {
@@ -35041,6 +35688,49 @@ class MP3Viewer extends media_MediaBaseViewer {
35041
35688
  this.startClientWaveformDecode();
35042
35689
  }
35043
35690
  });
35691
+ /**
35692
+ * Honor the requested play/pause state. The play button passes the next state;
35693
+ * comment markers pass false so a click always pauses instead of toggling.
35694
+ *
35695
+ * @param {boolean} shouldPlay
35696
+ * @return {void}
35697
+ */
35698
+ MP3Viewer_defineProperty(this, "handlePlayPause", shouldPlay => {
35699
+ if (shouldPlay) {
35700
+ this.handlePlayRequest();
35701
+ return;
35702
+ }
35703
+ this.pause(undefined, true);
35704
+ });
35705
+ MP3Viewer_defineProperty(this, "handleCommentMarkersUpdated", (markers = []) => {
35706
+ this.commentMarkers = markers;
35707
+ const selected = markers.find(marker => marker.isSelected);
35708
+ const selectedId = selected ? selected.id : null;
35709
+ if (selectedId !== this.hostSelectedMarkerId) {
35710
+ this.hostSelectedMarkerId = selectedId;
35711
+ if (selected && Number.isFinite(selected.time)) {
35712
+ this.pendingHostSelectedSeek = selected;
35713
+ this.applyPendingHostSelectedSeek();
35714
+ } else {
35715
+ this.pendingHostSelectedSeek = null;
35716
+ }
35717
+ }
35718
+ this.renderUI();
35719
+ });
35720
+ MP3Viewer_defineProperty(this, "handleCommentMarkerClick", marker => {
35721
+ this.hostSelectedMarkerId = marker.id;
35722
+ this.pendingHostSelectedSeek = null;
35723
+ if (this.mediaEl) {
35724
+ this.mediaEl.pause();
35725
+ this.mediaEl.currentTime = marker.time;
35726
+ }
35727
+ // Overlay paints the ring from click optimism until the host re-emits selected.
35728
+ this.emit('comment_marker_select', {
35729
+ id: marker.id,
35730
+ time: marker.time
35731
+ });
35732
+ this.renderUI();
35733
+ });
35044
35734
  /**
35045
35735
  * Auto-play was prevented, pause the audio
35046
35736
  *
@@ -35075,6 +35765,7 @@ class MP3Viewer extends media_MediaBaseViewer {
35075
35765
  // Audio element
35076
35766
  this.mediaEl = this.mediaContainerEl.appendChild(document.createElement('audio'));
35077
35767
  this.mediaEl.setAttribute('preload', 'auto');
35768
+ this.commentMarkers = [];
35078
35769
  }
35079
35770
 
35080
35771
  /**
@@ -35128,7 +35819,7 @@ class MP3Viewer extends media_MediaBaseViewer {
35128
35819
  * @return {Promise<{ default: Function }>} MP3ControlsV2 module
35129
35820
  */
35130
35821
  importV2Controls() {
35131
- return Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, 3678));
35822
+ return Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, 6180));
35132
35823
  }
35133
35824
 
35134
35825
  /**
@@ -35150,6 +35841,7 @@ class MP3Viewer extends media_MediaBaseViewer {
35150
35841
  * @inheritdoc
35151
35842
  */
35152
35843
  destroy() {
35844
+ this.removeListener('comment_markers', this.handleCommentMarkersUpdated);
35153
35845
  this.abortClientWaveformDecode();
35154
35846
  super.destroy();
35155
35847
  }
@@ -35201,6 +35893,7 @@ class MP3Viewer extends media_MediaBaseViewer {
35201
35893
  if (!this.isAudioPlayerV2) {
35202
35894
  return;
35203
35895
  }
35896
+ this.applyPendingHostSelectedSeek();
35204
35897
 
35205
35898
  // Play first so Safari has a user gesture before AudioContext is created.
35206
35899
  if (this.userRequestedPlay) {
@@ -35337,9 +36030,30 @@ class MP3Viewer extends media_MediaBaseViewer {
35337
36030
  containerEl: this.mediaContainerEl
35338
36031
  });
35339
36032
  }
36033
+ if (this.isAudioPlayerV2) {
36034
+ this.removeListener('comment_markers', this.handleCommentMarkersUpdated);
36035
+ this.addListener('comment_markers', this.handleCommentMarkersUpdated);
36036
+ }
35340
36037
  this.renderUI();
35341
36038
  }
35342
-
36039
+ /**
36040
+ * Seek+pause to a host-selected comment (feed / deeplink). Audio-only; video does not
36041
+ * seek on comment_markers. No-ops until duration is known. Skips currentTime if the
36042
+ * element is already there so a feed seek does not fire a second `seeked`.
36043
+ *
36044
+ * @return {void}
36045
+ */
36046
+ applyPendingHostSelectedSeek() {
36047
+ const marker = this.pendingHostSelectedSeek;
36048
+ if (!marker || !this.mediaEl || !(this.mediaEl.duration > 0) || !Number.isFinite(marker.time)) {
36049
+ return;
36050
+ }
36051
+ this.pendingHostSelectedSeek = null;
36052
+ this.mediaEl.pause();
36053
+ if (this.mediaEl.currentTime !== marker.time) {
36054
+ this.mediaEl.currentTime = marker.time;
36055
+ }
36056
+ }
35343
36057
  /**
35344
36058
  * @inheritdoc
35345
36059
  */
@@ -35356,7 +36070,7 @@ class MP3Viewer extends media_MediaBaseViewer {
35356
36070
  movePlayback: this.movePlayback,
35357
36071
  onAutoplayChange: this.setAutoplay,
35358
36072
  onMuteChange: this.toggleMute,
35359
- onPlayPause: this.isAudioPlayerV2 ? this.handlePlayRequest : this.togglePlay,
36073
+ onPlayPause: this.isAudioPlayerV2 ? this.handlePlayPause : this.togglePlay,
35360
36074
  onRateChange: this.setRate,
35361
36075
  onTimeChange: this.handleTimeupdateFromMediaControls,
35362
36076
  onVolumeChange: this.setVolume,
@@ -35374,7 +36088,9 @@ class MP3Viewer extends media_MediaBaseViewer {
35374
36088
  }
35375
36089
  const Mp3ControlsV2 = this.MP3ControlsV2;
35376
36090
  this.controls.render(/*#__PURE__*/external_react_["default"].createElement(Mp3ControlsV2, MP3Viewer_extends({}, sharedProps, {
36091
+ commentMarkers: this.commentMarkers || [],
35377
36092
  mediaEl: this.mediaEl,
36093
+ onCommentMarkerClick: this.handleCommentMarkerClick,
35378
36094
  peaks: this.waveformPeaks
35379
36095
  })));
35380
36096
  return;
@@ -37002,57 +37718,8 @@ function VideoControls({
37002
37718
  }
37003
37719
  // EXTERNAL MODULE: ./src/lib/viewers/controls/media/TimestampControl.tsx + 1 modules
37004
37720
  var TimestampControl = __webpack_require__(3904);
37005
- ;// ./src/lib/viewers/controls/media/utils.ts
37006
- const utils_round = value => {
37007
- return +value.toFixed(4);
37008
- };
37009
- const utils_percent = (value1, value2) => {
37010
- return utils_round(value1 / value2 * 100);
37011
- };
37012
- ;// ./src/lib/viewers/controls/media/buildClusters.ts
37013
-
37014
-
37015
- /** Max pixel distance between adjacent markers (sorted by time) for them to be grouped into a single cluster. */
37016
- const CLUSTER_THRESHOLD_PX = 2;
37017
-
37018
- /** Converts a group of markers into a ClusterData object with computed positions and metadata. */
37019
- function finalizeCluster(group, durationValue) {
37020
- const leftPercent = utils_percent(group[0].time, durationValue);
37021
- const rightPercent = utils_percent(group[group.length - 1].time, durationValue);
37022
- const isSinglePoint = leftPercent === rightPercent;
37023
- return {
37024
- id: group.map(m => m.id).join('|'),
37025
- isSinglePoint,
37026
- leftPercent,
37027
- markers: group,
37028
- rightPercent
37029
- };
37030
- }
37031
-
37032
- /**
37033
- * Groups comment markers into clusters based on their pixel proximity on the scrubber track.
37034
- * Markers are sorted by time, then chained: each marker that is within CLUSTER_THRESHOLD_PX
37035
- * of its neighbor joins the same cluster. This means distant markers can end up in one cluster
37036
- * if intermediate markers bridge the gap.
37037
- */
37038
- function buildClusters(markers, durationValue, trackWidth, thresholdPx = CLUSTER_THRESHOLD_PX) {
37039
- if (durationValue <= 0 || markers.length === 0 || trackWidth <= 0) return [];
37040
- const sorted = [...markers].sort((a, b) => a.time - b.time);
37041
- const clusters = [];
37042
- let currentGroup = [sorted[0]];
37043
- for (let i = 1; i < sorted.length; i += 1) {
37044
- const prevPx = sorted[i - 1].time / durationValue * trackWidth;
37045
- const currPx = sorted[i].time / durationValue * trackWidth;
37046
- if (currPx - prevPx <= thresholdPx) {
37047
- currentGroup.push(sorted[i]);
37048
- } else {
37049
- clusters.push(finalizeCluster(currentGroup, durationValue));
37050
- currentGroup = [sorted[i]];
37051
- }
37052
- }
37053
- clusters.push(finalizeCluster(currentGroup, durationValue));
37054
- return clusters;
37055
- }
37721
+ // EXTERNAL MODULE: ./src/lib/viewers/controls/media/buildClusters.ts
37722
+ var buildClusters = __webpack_require__(2400);
37056
37723
  // EXTERNAL MODULE: ./src/lib/viewers/media/formatTimecode.ts
37057
37724
  var formatTimecode = __webpack_require__(4179);
37058
37725
  ;// ./src/lib/viewers/controls/media/FilmstripV2.scss
@@ -37133,156 +37800,8 @@ function FilmstripV2({
37133
37800
  "data-testid": "bp-FilmstripV2-time"
37134
37801
  }, fps ? (0,formatTimecode/* default */.A)(time, fps) : (0,DurationLabels/* formatTime */.f)(time)));
37135
37802
  }
37136
- ;// ./src/lib/viewers/controls/media/MarkerAvatar.scss
37137
- // extracted by mini-css-extract-plugin
37138
-
37139
- ;// ./src/lib/viewers/controls/media/MarkerAvatar.tsx
37140
-
37141
-
37142
- const AVATAR_PALETTE = [{
37143
- bg: '#7fb0ea',
37144
- fg: '#222'
37145
- }, {
37146
- bg: '#003c84',
37147
- fg: '#fff'
37148
- }, {
37149
- bg: '#ffeb7f',
37150
- fg: '#222'
37151
- }, {
37152
- bg: '#92e0c0',
37153
- fg: '#222'
37154
- }, {
37155
- bg: '#fad98d',
37156
- fg: '#222'
37157
- }, {
37158
- bg: '#91c2fd',
37159
- fg: '#222'
37160
- }, {
37161
- bg: '#f69bab',
37162
- fg: '#222'
37163
- }, {
37164
- bg: '#cf9ff6',
37165
- fg: '#222'
37166
- }, {
37167
- bg: '#f8c08c',
37168
- fg: '#222'
37169
- }, {
37170
- bg: '#a392e0',
37171
- fg: '#222'
37172
- }];
37173
- function AnonymousAvatarIcon() {
37174
- return /*#__PURE__*/external_react_["default"].createElement("svg", {
37175
- "aria-hidden": "true",
37176
- className: "bp-MarkerAvatar-anonymousIcon",
37177
- focusable: "false",
37178
- viewBox: "0 0 16 16"
37179
- }, /*#__PURE__*/external_react_["default"].createElement("path", {
37180
- d: "M8 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6Zm0 1.5c-2.5 0-5 1.25-5 3.75V14h10v-.75c0-2.5-2.5-3.75-5-3.75Z",
37181
- fill: "currentColor"
37182
- }));
37183
- }
37184
- function MarkerAvatar({
37185
- avatarUrl,
37186
- colorIndex = 0,
37187
- initial,
37188
- size
37189
- }) {
37190
- const safeIndex = Number.isFinite(colorIndex) ? Math.abs(colorIndex) % AVATAR_PALETTE.length : 0;
37191
- const {
37192
- bg: bgColor,
37193
- fg: textColor
37194
- } = AVATAR_PALETTE[safeIndex];
37195
- const [imgFailed, setImgFailed] = external_react_["default"].useState(false);
37196
- const showImage = Boolean(avatarUrl) && !imgFailed;
37197
- let avatar = /*#__PURE__*/external_react_["default"].createElement(AnonymousAvatarIcon, null);
37198
- if (showImage) {
37199
- avatar = /*#__PURE__*/external_react_["default"].createElement("img", {
37200
- alt: "",
37201
- onError: () => setImgFailed(true),
37202
- src: avatarUrl
37203
- });
37204
- } else if (initial) {
37205
- avatar = /*#__PURE__*/external_react_["default"].createElement("span", {
37206
- className: "bp-MarkerAvatar-initial",
37207
- style: {
37208
- color: textColor
37209
- }
37210
- }, initial);
37211
- }
37212
- const style = {};
37213
- if (!showImage) {
37214
- style.backgroundColor = bgColor;
37215
- }
37216
- if (size) {
37217
- style.width = size;
37218
- style.height = size;
37219
- }
37220
- return /*#__PURE__*/external_react_["default"].createElement("span", {
37221
- className: "bp-MarkerAvatar",
37222
- style: Object.keys(style).length > 0 ? style : undefined
37223
- }, avatar);
37224
- }
37225
- ;// ./src/lib/viewers/controls/media/MarkerAvatarStack.scss
37226
- // extracted by mini-css-extract-plugin
37227
-
37228
- ;// ./src/lib/viewers/controls/media/MarkerAvatarStack.tsx
37229
-
37230
-
37231
-
37232
- const MAX_VISIBLE_AVATARS = 4;
37233
- function MarkerAvatarStack({
37234
- markers,
37235
- onMarkerClick,
37236
- overlapPx,
37237
- selectedId,
37238
- size
37239
- }) {
37240
- const hasOverflow = markers.length > MAX_VISIBLE_AVATARS;
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;
37247
- return /*#__PURE__*/external_react_["default"].createElement("span", {
37248
- className: "bp-MarkerAvatarStack",
37249
- style: style
37250
- }, visibleMarkers.map(marker => /*#__PURE__*/external_react_["default"].createElement("button", {
37251
- key: marker.id,
37252
- "aria-label": "Comment marker",
37253
- "aria-pressed": marker.id === selectedId,
37254
- className: `bp-MarkerAvatarStack-item${marker.id === selectedId ? ' bp-MarkerAvatarStack-item--selected' : ''}`,
37255
- "data-resin-target": "commentMarkerStackAvatar",
37256
- onClick: e => {
37257
- e.stopPropagation();
37258
- onMarkerClick?.(marker);
37259
- },
37260
- type: "button"
37261
- }, /*#__PURE__*/external_react_["default"].createElement(MarkerAvatar, {
37262
- avatarUrl: marker.avatarUrl,
37263
- colorIndex: marker.colorIndex,
37264
- initial: marker.initial,
37265
- size: size
37266
- }))), hasOverflow && /*#__PURE__*/external_react_["default"].createElement("button", {
37267
- "aria-label": "Comment marker",
37268
- "aria-pressed": isOverflowSelected,
37269
- className: `bp-MarkerAvatarStack-item bp-MarkerAvatarStack-overflow${isOverflowSelected ? ' bp-MarkerAvatarStack-item--selected' : ''}`,
37270
- "data-resin-target": "commentMarkerStackAvatarOverflow",
37271
- onClick: e => {
37272
- e.stopPropagation();
37273
- onMarkerClick?.(markers[MAX_VISIBLE_AVATARS - 1]);
37274
- },
37275
- type: "button"
37276
- }, /*#__PURE__*/external_react_["default"].createElement("span", {
37277
- className: "bp-MarkerAvatar bp-MarkerAvatarStack-overflowBadge",
37278
- style: size ? {
37279
- width: size,
37280
- height: size
37281
- } : undefined
37282
- }, /*#__PURE__*/external_react_["default"].createElement("span", {
37283
- className: "bp-MarkerAvatar-initial"
37284
- }, "+", markers.length - (MAX_VISIBLE_AVATARS - 1)))));
37285
- }
37803
+ // EXTERNAL MODULE: ./src/lib/viewers/controls/media/MarkerAvatarStack.tsx + 1 modules
37804
+ var MarkerAvatarStack = __webpack_require__(9232);
37286
37805
  ;// ./src/lib/viewers/controls/media/MarkerCluster.scss
37287
37806
  // extracted by mini-css-extract-plugin
37288
37807
 
@@ -37316,11 +37835,13 @@ function MarkerCluster({
37316
37835
  onMarkerClick?.(markers[0]);
37317
37836
  },
37318
37837
  type: "button"
37319
- }), /*#__PURE__*/external_react_["default"].createElement(MarkerAvatarStack, {
37838
+ }), /*#__PURE__*/external_react_["default"].createElement(MarkerAvatarStack/* default */.A, {
37320
37839
  markers: markers,
37321
37840
  onMarkerClick: onMarkerClick
37322
37841
  }));
37323
37842
  }
37843
+ // EXTERNAL MODULE: ./src/lib/viewers/controls/media/MarkerAvatar.tsx + 1 modules
37844
+ var MarkerAvatar = __webpack_require__(3524);
37324
37845
  ;// ./src/lib/viewers/controls/media/MarkerTick.tsx
37325
37846
 
37326
37847
 
@@ -37344,15 +37865,17 @@ function MarkerTick({
37344
37865
  left: `${position}%`
37345
37866
  },
37346
37867
  type: "button"
37347
- }, isGroup ? /*#__PURE__*/external_react_["default"].createElement(MarkerAvatarStack, {
37868
+ }, isGroup ? /*#__PURE__*/external_react_["default"].createElement(MarkerAvatarStack/* default */.A, {
37348
37869
  markers: markers,
37349
37870
  onMarkerClick: onMarkerClick
37350
- }) : /*#__PURE__*/external_react_["default"].createElement(MarkerAvatar, {
37871
+ }) : /*#__PURE__*/external_react_["default"].createElement(MarkerAvatar/* default */.A, {
37351
37872
  avatarUrl: markers[0].avatarUrl,
37352
37873
  colorIndex: markers[0].colorIndex,
37353
37874
  initial: markers[0].initial
37354
37875
  }));
37355
37876
  }
37877
+ // EXTERNAL MODULE: ./src/lib/viewers/controls/media/utils.ts
37878
+ var utils = __webpack_require__(5346);
37356
37879
  ;// ./src/lib/viewers/controls/media/TimeControlsV2.scss
37357
37880
  // extracted by mini-css-extract-plugin
37358
37881
 
@@ -37390,9 +37913,9 @@ function TimeControlsV2({
37390
37913
  const scrubberRef = external_react_["default"].useRef(null);
37391
37914
  const currentValue = isFinite_default()(currentTime) ? currentTime : 0;
37392
37915
  const durationValue = isFinite_default()(durationTime) ? durationTime : 0;
37393
- const currentPercentage = utils_percent(currentValue, durationValue);
37916
+ const currentPercentage = (0,utils/* percent */.K)(currentValue, durationValue);
37394
37917
  const bufferedAmount = bufferedRange && bufferedRange.length ? bufferedRange.end(bufferedRange.length - 1) : 0;
37395
- const bufferedPercentage = utils_percent(bufferedAmount, durationValue);
37918
+ const bufferedPercentage = (0,utils/* percent */.K)(bufferedAmount, durationValue);
37396
37919
  external_react_["default"].useLayoutEffect(() => {
37397
37920
  const el = scrubberRef.current;
37398
37921
  if (!el) return undefined;
@@ -37405,7 +37928,7 @@ function TimeControlsV2({
37405
37928
  observer.observe(el);
37406
37929
  return () => observer.disconnect();
37407
37930
  }, []);
37408
- const clusters = external_react_["default"].useMemo(() => buildClusters(commentMarkers, durationValue, trackWidth), [commentMarkers, durationValue, trackWidth]);
37931
+ const clusters = external_react_["default"].useMemo(() => (0,buildClusters/* default */.A)(commentMarkers, durationValue, trackWidth), [commentMarkers, durationValue, trackWidth]);
37409
37932
  const trackMask = external_react_["default"].useMemo(() => {
37410
37933
  if (durationValue <= 0 || clusters.length === 0) return undefined;
37411
37934
  const HALF_GAP = 2;