box-content-preview 3.90.0 → 3.91.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -7
- package/dist/lib/index.css +3 -3
- package/dist/lib/index.js +553 -117
- package/package.json +1 -1
package/dist/lib/index.js
CHANGED
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
* and limitations under the license.
|
|
22
22
|
*/
|
|
23
23
|
import { decode as __WEBPACK_EXTERNAL_MODULE_box_ui_elements_es_utils_keys_d752524f_decode__ } from "box-ui-elements/es/utils/keys";
|
|
24
|
+
import { createPortal as __WEBPACK_EXTERNAL_MODULE_react_dom_7dac9eee_createPortal__ } from "react-dom";
|
|
24
25
|
import * as __WEBPACK_EXTERNAL_MODULE_react__ from "react";
|
|
25
26
|
import { default as __WEBPACK_EXTERNAL_MODULE_axios_default__ } from "axios";
|
|
26
27
|
import { bdlBoxBlue as __WEBPACK_EXTERNAL_MODULE_box_ui_elements_es_styles_variables_c815ce80_bdlBoxBlue__, bdlGray65 as __WEBPACK_EXTERNAL_MODULE_box_ui_elements_es_styles_variables_c815ce80_bdlGray65__, bdlGreenLight as __WEBPACK_EXTERNAL_MODULE_box_ui_elements_es_styles_variables_c815ce80_bdlGreenLight__, bdlGrimace as __WEBPACK_EXTERNAL_MODULE_box_ui_elements_es_styles_variables_c815ce80_bdlGrimace__, bdlWatermelonRed as __WEBPACK_EXTERNAL_MODULE_box_ui_elements_es_styles_variables_c815ce80_bdlWatermelonRed__, bdlYellorange as __WEBPACK_EXTERNAL_MODULE_box_ui_elements_es_styles_variables_c815ce80_bdlYellorange__, bdlYellow as __WEBPACK_EXTERNAL_MODULE_box_ui_elements_es_styles_variables_c815ce80_bdlYellow__, white as __WEBPACK_EXTERNAL_MODULE_box_ui_elements_es_styles_variables_c815ce80_white__ } from "box-ui-elements/es/styles/variables";
|
|
@@ -1017,7 +1018,7 @@ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e =
|
|
|
1017
1018
|
const CLIENT_NAME = "box-content-preview"; // eslint-disable-line no-undef
|
|
1018
1019
|
const CLIENT_NAME_KEY = 'box_client_name';
|
|
1019
1020
|
const CLIENT_VERSION_KEY = 'box_client_version';
|
|
1020
|
-
const CLIENT_VERSION = "3.
|
|
1021
|
+
const CLIENT_VERSION = "3.91.0"; // eslint-disable-line no-undef
|
|
1021
1022
|
const HEADER_CLIENT_NAME = 'X-Box-Client-Name';
|
|
1022
1023
|
const HEADER_CLIENT_VERSION = 'X-Box-Client-Version';
|
|
1023
1024
|
const PROMISE_MAP = {};
|
|
@@ -4487,7 +4488,7 @@ function getPdfjsWorkerSrc() {
|
|
|
4487
4488
|
|
|
4488
4489
|
/***/ },
|
|
4489
4490
|
|
|
4490
|
-
/***/
|
|
4491
|
+
/***/ 2668
|
|
4491
4492
|
(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
4492
4493
|
|
|
4493
4494
|
|
|
@@ -4621,6 +4622,7 @@ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e =
|
|
|
4621
4622
|
/** Visible window: start/end times, pixels-per-second, and the current zoom. */
|
|
4622
4623
|
function createWaveformViewport({
|
|
4623
4624
|
durationSec,
|
|
4625
|
+
gutterPx = 0,
|
|
4624
4626
|
heightPx,
|
|
4625
4627
|
maxZoom,
|
|
4626
4628
|
scrollLeftPx,
|
|
@@ -4630,11 +4632,16 @@ function createWaveformViewport({
|
|
|
4630
4632
|
const zoom = Number.isFinite(zoomLevel) && zoomLevel > 0 ? zoomLevel : constants/* WAVEFORM_ZOOM_MIN */.LW;
|
|
4631
4633
|
const viewDurationSec = durationSec > 0 ? durationSec / zoom : 0; // seconds visible at this zoom
|
|
4632
4634
|
const pixelsPerSecond = viewDurationSec > 0 && widthPx > 0 ? widthPx / viewDurationSec : 0;
|
|
4633
|
-
const
|
|
4634
|
-
const
|
|
4635
|
+
const leadingGutterPx = Number.isFinite(gutterPx) && gutterPx > 0 ? gutterPx : 0;
|
|
4636
|
+
const unclampedStartSec = pixelsPerSecond > 0 ? (scrollLeftPx - leadingGutterPx) / pixelsPerSecond : 0;
|
|
4637
|
+
const gutterDurationSec = pixelsPerSecond > 0 ? leadingGutterPx / pixelsPerSecond : 0;
|
|
4638
|
+
const latestWindowStartSec = leadingGutterPx > 0 ? durationSec + gutterDurationSec - viewDurationSec : Math.max(0, durationSec - viewDurationSec);
|
|
4639
|
+
const earliestWindowStartSec = leadingGutterPx > 0 ? -gutterDurationSec : 0;
|
|
4640
|
+
const startSec = pixelsPerSecond > 0 ? Math.min(latestWindowStartSec, Math.max(earliestWindowStartSec, unclampedStartSec)) : 0;
|
|
4635
4641
|
return {
|
|
4636
4642
|
durationSec,
|
|
4637
4643
|
endSec: startSec + viewDurationSec,
|
|
4644
|
+
gutterPx: leadingGutterPx,
|
|
4638
4645
|
heightPx,
|
|
4639
4646
|
maxZoom,
|
|
4640
4647
|
pixelsPerSecond,
|
|
@@ -4654,7 +4661,7 @@ function getViewportAtScroll(viewport, scrollLeftPx) {
|
|
|
4654
4661
|
|
|
4655
4662
|
/** True when the visible window has not moved — skip a React state update. */
|
|
4656
4663
|
function viewportEquals(prev, next) {
|
|
4657
|
-
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;
|
|
4664
|
+
return !!prev && prev.durationSec === next.durationSec && prev.endSec === next.endSec && prev.gutterPx === next.gutterPx && prev.maxZoom === next.maxZoom && prev.scrollLeftPx === next.scrollLeftPx && prev.startSec === next.startSec && prev.widthPx === next.widthPx && prev.zoomLevel === next.zoomLevel;
|
|
4658
4665
|
}
|
|
4659
4666
|
|
|
4660
4667
|
/** How many CSS pixels from the left of the visible window this time sits. */
|
|
@@ -4701,17 +4708,34 @@ function clampWaveformZoom(zoomLevel, maxZoom = constants/* WAVEFORM_ZOOM_MIN */
|
|
|
4701
4708
|
/** WaveSurfer zoom density. 0 = fit the whole file in the view. */
|
|
4702
4709
|
function getZoomedPixelsPerSecond({
|
|
4703
4710
|
durationSec,
|
|
4711
|
+
isTape = false,
|
|
4704
4712
|
maxZoom = constants/* WAVEFORM_ZOOM_MIN */.LW,
|
|
4705
4713
|
viewWidthPx,
|
|
4706
4714
|
zoomLevel
|
|
4707
4715
|
}) {
|
|
4708
4716
|
const zoom = clampWaveformZoom(zoomLevel, maxZoom);
|
|
4709
|
-
if (
|
|
4717
|
+
if (!(durationSec > 0) || !(viewWidthPx > 0)) {
|
|
4718
|
+
return 0;
|
|
4719
|
+
}
|
|
4720
|
+
if (!isTape && zoom <= constants/* WAVEFORM_ZOOM_MIN */.LW) {
|
|
4710
4721
|
return 0;
|
|
4711
4722
|
}
|
|
4712
4723
|
return viewWidthPx / durationSec * zoom;
|
|
4713
4724
|
}
|
|
4714
4725
|
|
|
4726
|
+
/** Half-view empty space so t=0 and duration can sit under the center pin. */
|
|
4727
|
+
function getTapeGutterPx(widthPx) {
|
|
4728
|
+
return widthPx > 0 ? widthPx / 2 : 0;
|
|
4729
|
+
}
|
|
4730
|
+
|
|
4731
|
+
/** Tape first paint: 10s on screen, or 1× when the file is shorter than that. */
|
|
4732
|
+
function getTapeDefaultZoom(durationSec, maxZoom = constants/* WAVEFORM_ZOOM_MIN */.LW) {
|
|
4733
|
+
if (!(durationSec > 0)) {
|
|
4734
|
+
return constants/* WAVEFORM_ZOOM_MIN */.LW;
|
|
4735
|
+
}
|
|
4736
|
+
return clampWaveformZoom(durationSec / constants/* WAVEFORM_TAPE_DEFAULT_WINDOW_SEC */.Av, maxZoom);
|
|
4737
|
+
}
|
|
4738
|
+
|
|
4715
4739
|
/** Map zoom (1…max) onto the 0–100 slider. */
|
|
4716
4740
|
function sliderValueFromZoom(zoomLevel, maxZoom = constants/* WAVEFORM_ZOOM_MIN */.LW) {
|
|
4717
4741
|
const max = Math.max(constants/* WAVEFORM_ZOOM_MIN */.LW, maxZoom);
|
|
@@ -4732,9 +4756,10 @@ function zoomFromSliderValue(value, maxZoom = constants/* WAVEFORM_ZOOM_MIN */.L
|
|
|
4732
4756
|
return clampWaveformZoom(constants/* WAVEFORM_ZOOM_MIN */.LW + t * (max - constants/* WAVEFORM_ZOOM_MIN */.LW), max);
|
|
4733
4757
|
}
|
|
4734
4758
|
|
|
4735
|
-
/** Max scroll that still shows a full window (no overscroll). */
|
|
4759
|
+
/** Max scroll that still shows a full window (no overscroll). Gutters add empty lead/trail. */
|
|
4736
4760
|
function maxScrollLeft(viewport) {
|
|
4737
|
-
|
|
4761
|
+
const gutterPx = viewport.gutterPx || 0;
|
|
4762
|
+
return Math.max(0, viewport.durationSec * viewport.pixelsPerSecond + 2 * gutterPx - viewport.widthPx);
|
|
4738
4763
|
}
|
|
4739
4764
|
|
|
4740
4765
|
/** Scroll offset that still shows a full window (no overscroll). */
|
|
@@ -4747,7 +4772,7 @@ function clampScrollLeft(scrollLeftPx, viewport) {
|
|
|
4747
4772
|
|
|
4748
4773
|
/** Center this time in the view, clamped so the window still fills the canvas. */
|
|
4749
4774
|
function getCenteredScrollLeft(timeSec, viewport) {
|
|
4750
|
-
return clampScrollLeft(timeSec * viewport.pixelsPerSecond - viewport.widthPx / 2, viewport);
|
|
4775
|
+
return clampScrollLeft(timeSec * viewport.pixelsPerSecond + (viewport.gutterPx || 0) - viewport.widthPx / 2, viewport);
|
|
4751
4776
|
}
|
|
4752
4777
|
|
|
4753
4778
|
/**
|
|
@@ -4755,10 +4780,28 @@ function getCenteredScrollLeft(timeSec, viewport) {
|
|
|
4755
4780
|
* No-op at fit-to-width or when that time is already visible.
|
|
4756
4781
|
*/
|
|
4757
4782
|
function getSeekCameraAction({
|
|
4783
|
+
cameraMode = 'desktop',
|
|
4758
4784
|
timeSec,
|
|
4759
4785
|
viewport
|
|
4760
4786
|
}) {
|
|
4761
|
-
if (
|
|
4787
|
+
if (!(viewport.widthPx > 0) || !(viewport.pixelsPerSecond > 0)) {
|
|
4788
|
+
return {
|
|
4789
|
+
type: 'none'
|
|
4790
|
+
};
|
|
4791
|
+
}
|
|
4792
|
+
if (cameraMode === 'tape') {
|
|
4793
|
+
const scrollLeftPx = getCenteredScrollLeft(timeSec, viewport);
|
|
4794
|
+
if (Math.abs(scrollLeftPx - viewport.scrollLeftPx) < 1) {
|
|
4795
|
+
return {
|
|
4796
|
+
type: 'none'
|
|
4797
|
+
};
|
|
4798
|
+
}
|
|
4799
|
+
return {
|
|
4800
|
+
type: 'jump',
|
|
4801
|
+
scrollLeftPx
|
|
4802
|
+
};
|
|
4803
|
+
}
|
|
4804
|
+
if (viewport.zoomLevel <= constants/* WAVEFORM_ZOOM_MIN */.LW) {
|
|
4762
4805
|
return {
|
|
4763
4806
|
type: 'none'
|
|
4764
4807
|
};
|
|
@@ -4774,6 +4817,23 @@ function getSeekCameraAction({
|
|
|
4774
4817
|
};
|
|
4775
4818
|
}
|
|
4776
4819
|
|
|
4820
|
+
/** Always keep this time under the center pin. Reuses followRight so the camera hook can pin. */
|
|
4821
|
+
function getTapeCameraAction({
|
|
4822
|
+
timeSec,
|
|
4823
|
+
viewport
|
|
4824
|
+
}) {
|
|
4825
|
+
if (!(viewport.widthPx > 0) || !(viewport.pixelsPerSecond > 0)) {
|
|
4826
|
+
return {
|
|
4827
|
+
type: 'none'
|
|
4828
|
+
};
|
|
4829
|
+
}
|
|
4830
|
+
return {
|
|
4831
|
+
isPlayheadPinned: true,
|
|
4832
|
+
scrollLeftPx: getCenteredScrollLeft(timeSec, viewport),
|
|
4833
|
+
type: 'followRight'
|
|
4834
|
+
};
|
|
4835
|
+
}
|
|
4836
|
+
|
|
4777
4837
|
/** Follow inset in CSS px, capped at one third of the view so a narrow player still has room. */
|
|
4778
4838
|
function getFollowInsetPx(widthPx, insetPx = constants/* WAVEFORM_FOLLOW_INSET_PX */.NM) {
|
|
4779
4839
|
if (!(widthPx > 0)) {
|
|
@@ -4791,6 +4851,11 @@ function getPinnedPlayheadLeft(widthPx, insetPx = constants/* WAVEFORM_FOLLOW_IN
|
|
|
4791
4851
|
return `${(widthPx - inset) / widthPx * 100}%`;
|
|
4792
4852
|
}
|
|
4793
4853
|
|
|
4854
|
+
/** CSS left for a playhead locked to the center of the view. */
|
|
4855
|
+
function getTapePinnedPlayheadLeft() {
|
|
4856
|
+
return '50%';
|
|
4857
|
+
}
|
|
4858
|
+
|
|
4794
4859
|
/** CSS left % of the playhead from the left of the visible window. */
|
|
4795
4860
|
function timeLeftPercent(timeSec, durationSec, viewport) {
|
|
4796
4861
|
if (viewport.widthPx > 0 && viewport.pixelsPerSecond > 0) {
|
|
@@ -4805,12 +4870,19 @@ function timeLeftPercent(timeSec, durationSec, viewport) {
|
|
|
4805
4870
|
* Off-screen at play start jumps in; off-screen right while playing keeps following.
|
|
4806
4871
|
*/
|
|
4807
4872
|
function getPlayheadCameraAction({
|
|
4873
|
+
cameraMode = 'desktop',
|
|
4808
4874
|
insetPx = constants/* WAVEFORM_FOLLOW_INSET_PX */.NM,
|
|
4809
4875
|
isPlaying,
|
|
4810
4876
|
playJustStarted,
|
|
4811
4877
|
timeSec,
|
|
4812
4878
|
viewport
|
|
4813
4879
|
}) {
|
|
4880
|
+
if (cameraMode === 'tape') {
|
|
4881
|
+
return getTapeCameraAction({
|
|
4882
|
+
timeSec,
|
|
4883
|
+
viewport
|
|
4884
|
+
});
|
|
4885
|
+
}
|
|
4814
4886
|
if (!isPlaying || viewport.zoomLevel <= constants/* WAVEFORM_ZOOM_MIN */.LW || !(viewport.widthPx > 0) || !(viewport.pixelsPerSecond > 0)) {
|
|
4815
4887
|
return {
|
|
4816
4888
|
type: 'none'
|
|
@@ -4850,6 +4922,46 @@ function getPlayheadCameraAction({
|
|
|
4850
4922
|
type: 'none'
|
|
4851
4923
|
};
|
|
4852
4924
|
}
|
|
4925
|
+
;// ./src/lib/viewers/media/waveform/useTapeWaveform.ts
|
|
4926
|
+
|
|
4927
|
+
|
|
4928
|
+
function isIPadNavigator(tapeNavigator) {
|
|
4929
|
+
return /iPad/i.test(tapeNavigator.userAgent || '') || tapeNavigator.platform === 'MacIntel' && (tapeNavigator.maxTouchPoints || 0) > 1;
|
|
4930
|
+
}
|
|
4931
|
+
function isCoarsePrimaryPointer(tapeWindow) {
|
|
4932
|
+
return typeof tapeWindow.matchMedia === 'function' && tapeWindow.matchMedia(constants/* TAPE_POINTER_MEDIA_QUERY */.Le).matches;
|
|
4933
|
+
}
|
|
4934
|
+
|
|
4935
|
+
/**
|
|
4936
|
+
* Tape vs desktop camera: coarse primary pointer (finger) or iPad
|
|
4937
|
+
* (including iPadOS reporting itself as Mac). Not width, not hasTouch,
|
|
4938
|
+
* not Browser.isMobile().
|
|
4939
|
+
*/
|
|
4940
|
+
function isTapeWaveformInput(tapeWindow = window) {
|
|
4941
|
+
return isCoarsePrimaryPointer(tapeWindow) || isIPadNavigator(tapeWindow.navigator);
|
|
4942
|
+
}
|
|
4943
|
+
|
|
4944
|
+
/** Subscribe to the pointer media query; re-read the iPad heuristic on change. */
|
|
4945
|
+
function useTapeWaveform() {
|
|
4946
|
+
const [isTape, setIsTape] = (0,external_react_.useState)(() => typeof window !== 'undefined' && isTapeWaveformInput(window));
|
|
4947
|
+
(0,external_react_.useEffect)(() => {
|
|
4948
|
+
if (typeof window.matchMedia !== 'function') {
|
|
4949
|
+
setIsTape(isTapeWaveformInput(window));
|
|
4950
|
+
return undefined;
|
|
4951
|
+
}
|
|
4952
|
+
const mediaQuery = window.matchMedia(constants/* TAPE_POINTER_MEDIA_QUERY */.Le);
|
|
4953
|
+
const sync = () => {
|
|
4954
|
+
setIsTape(isTapeWaveformInput(window));
|
|
4955
|
+
};
|
|
4956
|
+
sync();
|
|
4957
|
+
mediaQuery.addEventListener('change', sync);
|
|
4958
|
+
return () => mediaQuery.removeEventListener('change', sync);
|
|
4959
|
+
}, []);
|
|
4960
|
+
return isTape;
|
|
4961
|
+
}
|
|
4962
|
+
// EXTERNAL MODULE: ./node_modules/classnames/index.js
|
|
4963
|
+
var classnames = __webpack_require__(2485);
|
|
4964
|
+
var classnames_default = /*#__PURE__*/__webpack_require__.n(classnames);
|
|
4853
4965
|
// EXTERNAL MODULE: ./src/lib/viewers/controls/media/markers/helpers/useDismissableMarkerSelection.ts
|
|
4854
4966
|
var useDismissableMarkerSelection = __webpack_require__(2378);
|
|
4855
4967
|
// EXTERNAL MODULE: ./src/lib/viewers/controls/media/markers/helpers/buildClusters.ts
|
|
@@ -4869,6 +4981,7 @@ var utils = __webpack_require__(5346);
|
|
|
4869
4981
|
|
|
4870
4982
|
|
|
4871
4983
|
|
|
4984
|
+
|
|
4872
4985
|
const WAVEFORM_MARKER_SIZE_PX = 20;
|
|
4873
4986
|
function hasMappedWindow(viewport) {
|
|
4874
4987
|
return !!viewport && Number.isFinite(viewport.startSec) && viewport.endSec > viewport.startSec;
|
|
@@ -4907,11 +5020,12 @@ function clustersByExactTime(markers, durationSec) {
|
|
|
4907
5020
|
function WaveformCommentMarkers({
|
|
4908
5021
|
commentMarkers,
|
|
4909
5022
|
durationSec,
|
|
5023
|
+
isTape = false,
|
|
4910
5024
|
onCommentMarkerClick,
|
|
4911
5025
|
selectedId: hostSelectedId = null,
|
|
4912
5026
|
viewport = null
|
|
4913
5027
|
}) {
|
|
4914
|
-
const trackRef = (0,external_react_.useRef)(null);
|
|
5028
|
+
const trackRef = (0,external_react_.useRef)(null); // width source for clustering overlapping badges
|
|
4915
5029
|
const {
|
|
4916
5030
|
containerRef,
|
|
4917
5031
|
selectMarker,
|
|
@@ -4920,7 +5034,7 @@ function WaveformCommentMarkers({
|
|
|
4920
5034
|
const [trackWidth, setTrackWidth] = (0,external_react_.useState)(0);
|
|
4921
5035
|
const canShowTrack = durationSec > 0 && commentMarkers.length > 0;
|
|
4922
5036
|
const zoomLevel = viewport?.zoomLevel ?? constants/* WAVEFORM_ZOOM_MIN */.LW;
|
|
4923
|
-
const
|
|
5037
|
+
const alignsMarkersToVisibleWindow = hasMappedWindow(viewport) && (viewport.zoomLevel > constants/* WAVEFORM_ZOOM_MIN */.LW || isTape);
|
|
4924
5038
|
(0,external_react_.useLayoutEffect)(() => {
|
|
4925
5039
|
if (!canShowTrack) {
|
|
4926
5040
|
setTrackWidth(0);
|
|
@@ -4956,7 +5070,10 @@ function WaveformCommentMarkers({
|
|
|
4956
5070
|
}
|
|
4957
5071
|
return /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
4958
5072
|
ref: containerRef,
|
|
4959
|
-
className:
|
|
5073
|
+
className: classnames_default()('bp-WaveformCommentMarkers', {
|
|
5074
|
+
'bp-WaveformCommentMarkers--tape': isTape,
|
|
5075
|
+
'bp-WaveformCommentMarkers--zoomed': alignsMarkersToVisibleWindow
|
|
5076
|
+
}),
|
|
4960
5077
|
"data-testid": "bp-waveform-comment-markers"
|
|
4961
5078
|
}, /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
4962
5079
|
ref: trackRef,
|
|
@@ -4965,7 +5082,10 @@ function WaveformCommentMarkers({
|
|
|
4965
5082
|
const marker = cluster.markers[0];
|
|
4966
5083
|
const isGroup = cluster.markers.length > 1;
|
|
4967
5084
|
const isSelected = cluster.markers.some(entry => entry.id === selectedId);
|
|
4968
|
-
const className =
|
|
5085
|
+
const className = classnames_default()('bp-WaveformCommentMarkers-marker', {
|
|
5086
|
+
'bp-WaveformCommentMarkers-marker--group': isGroup,
|
|
5087
|
+
'bp-WaveformCommentMarkers-marker--selected': isSelected
|
|
5088
|
+
});
|
|
4969
5089
|
const left = `${markerLeftPercent(marker.time, durationSec, viewport)}%`;
|
|
4970
5090
|
if (isGroup) {
|
|
4971
5091
|
return /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
@@ -5003,6 +5123,8 @@ function WaveformCommentMarkers({
|
|
|
5003
5123
|
}));
|
|
5004
5124
|
})));
|
|
5005
5125
|
}
|
|
5126
|
+
;// external "react-dom"
|
|
5127
|
+
|
|
5006
5128
|
;// ./node_modules/wavesurfer.js/dist/wavesurfer.esm.js
|
|
5007
5129
|
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
|
|
5008
5130
|
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;
|
|
@@ -5087,18 +5209,31 @@ function getBufferedProgress(bufferedRange, durationSec) {
|
|
|
5087
5209
|
return clampTo0And1(bufferedRange.end(bufferedRange.length - 1) / durationSec);
|
|
5088
5210
|
}
|
|
5089
5211
|
|
|
5212
|
+
/** Played bars: rest token on desktop, hover-played (brightest) on tape. Tape never uses hover or buffer fills. */
|
|
5213
|
+
function getPlayedWaveformColor(isTape = false) {
|
|
5214
|
+
return isTape ? WAVEFORM_COLOR_HOVER_PLAYED : WAVEFORM_COLOR_PLAYED;
|
|
5215
|
+
}
|
|
5216
|
+
|
|
5090
5217
|
/**
|
|
5091
5218
|
* progressColor paints left of the playhead (clipped by wavesurfer).
|
|
5092
5219
|
* waveColor paints right of the playhead, including buffered vs not-yet-buffered.
|
|
5093
5220
|
*/
|
|
5094
5221
|
function getWaveformFills({
|
|
5095
5222
|
bufferProgress,
|
|
5096
|
-
hoverProgress
|
|
5223
|
+
hoverProgress,
|
|
5224
|
+
isTape = false
|
|
5097
5225
|
}) {
|
|
5098
5226
|
const buffer = clampTo0And1(bufferProgress);
|
|
5227
|
+
const playedColor = getPlayedWaveformColor(isTape);
|
|
5228
|
+
if (isTape) {
|
|
5229
|
+
return {
|
|
5230
|
+
progressColor: playedColor,
|
|
5231
|
+
waveColor: WAVEFORM_COLOR_UNPLAYED
|
|
5232
|
+
};
|
|
5233
|
+
}
|
|
5099
5234
|
if (hoverProgress == null) {
|
|
5100
5235
|
return {
|
|
5101
|
-
progressColor:
|
|
5236
|
+
progressColor: playedColor,
|
|
5102
5237
|
waveColor: gradientStopsFromColorRanges([{
|
|
5103
5238
|
color: WAVEFORM_COLOR_UNPLAYED,
|
|
5104
5239
|
end: buffer,
|
|
@@ -5275,6 +5410,7 @@ function prefersReducedMotion() {
|
|
|
5275
5410
|
* every frame. WaveformView owns WaveSurfer, zoom, and the media rAF loop.
|
|
5276
5411
|
*/
|
|
5277
5412
|
function usePlayheadCamera({
|
|
5413
|
+
cameraMode = 'desktop',
|
|
5278
5414
|
mediaElRef,
|
|
5279
5415
|
onViewportCommit,
|
|
5280
5416
|
playheadRef,
|
|
@@ -5283,6 +5419,8 @@ function usePlayheadCamera({
|
|
|
5283
5419
|
}) {
|
|
5284
5420
|
const onViewportCommitRef = (0,external_react_.useRef)(onViewportCommit);
|
|
5285
5421
|
onViewportCommitRef.current = onViewportCommit;
|
|
5422
|
+
const cameraModeRef = (0,external_react_.useRef)(cameraMode);
|
|
5423
|
+
cameraModeRef.current = cameraMode;
|
|
5286
5424
|
const programmaticScrollRef = (0,external_react_.useRef)(false);
|
|
5287
5425
|
const jumpAnimationRef = (0,external_react_.useRef)(0);
|
|
5288
5426
|
const lastCameraScrollRef = (0,external_react_.useRef)(null);
|
|
@@ -5293,6 +5431,8 @@ function usePlayheadCamera({
|
|
|
5293
5431
|
const scrollSettleTimerRef = (0,external_react_.useRef)(0);
|
|
5294
5432
|
const applyRef = (0,external_react_.useRef)(null);
|
|
5295
5433
|
const isFollowPinned = (0,external_react_.useCallback)(() => isFollowPinnedRef.current, []);
|
|
5434
|
+
const isUserPanning = (0,external_react_.useCallback)(() => userIsScrollingRef.current, []);
|
|
5435
|
+
const isTape = (0,external_react_.useCallback)(() => cameraModeRef.current === 'tape', []);
|
|
5296
5436
|
const cancelJump = (0,external_react_.useCallback)(() => {
|
|
5297
5437
|
if (!jumpAnimationRef.current) {
|
|
5298
5438
|
return;
|
|
@@ -5321,15 +5461,22 @@ function usePlayheadCamera({
|
|
|
5321
5461
|
const onSeek = (0,external_react_.useCallback)(timeSec => {
|
|
5322
5462
|
mediaTimeRef.current = timeSec;
|
|
5323
5463
|
cancelJump();
|
|
5324
|
-
|
|
5325
|
-
|
|
5464
|
+
if (!isTape()) {
|
|
5465
|
+
clearFollowPin();
|
|
5466
|
+
}
|
|
5467
|
+
}, [cancelJump, clearFollowPin, isTape]);
|
|
5326
5468
|
|
|
5327
5469
|
/** Unpin and hold follow so zoom setScroll (slider center or pinch origin) is not stolen. */
|
|
5328
5470
|
const onZoom = (0,external_react_.useCallback)(() => {
|
|
5329
5471
|
cancelJump();
|
|
5472
|
+
if (isTape()) {
|
|
5473
|
+
isFollowPinnedRef.current = true;
|
|
5474
|
+
holdFollowUntilInsetRef.current = false;
|
|
5475
|
+
return;
|
|
5476
|
+
}
|
|
5330
5477
|
isFollowPinnedRef.current = false;
|
|
5331
5478
|
holdFollowUntilInsetRef.current = true;
|
|
5332
|
-
}, [cancelJump]);
|
|
5479
|
+
}, [cancelJump, isTape]);
|
|
5333
5480
|
const applyScrollLeft = (0,external_react_.useCallback)((scrollLeftPx, shouldCommitState) => {
|
|
5334
5481
|
const wavesurfer = wavesurferRef.current;
|
|
5335
5482
|
if (!wavesurfer || !wavesurfer.setScroll) {
|
|
@@ -5357,8 +5504,8 @@ function usePlayheadCamera({
|
|
|
5357
5504
|
if (!playhead || !isPinned || !(viewport.widthPx > 0)) {
|
|
5358
5505
|
return;
|
|
5359
5506
|
}
|
|
5360
|
-
playhead.style.left = getPinnedPlayheadLeft(viewport.widthPx);
|
|
5361
|
-
}, []);
|
|
5507
|
+
playhead.style.left = isTape() ? getTapePinnedPlayheadLeft() : getPinnedPlayheadLeft(viewport.widthPx);
|
|
5508
|
+
}, [isTape]);
|
|
5362
5509
|
const apply = (0,external_react_.useCallback)((timeSec, playJustStarted = false) => {
|
|
5363
5510
|
mediaTimeRef.current = timeSec;
|
|
5364
5511
|
const wavesurfer = wavesurferRef.current;
|
|
@@ -5366,7 +5513,7 @@ function usePlayheadCamera({
|
|
|
5366
5513
|
if (!wavesurfer) {
|
|
5367
5514
|
return;
|
|
5368
5515
|
}
|
|
5369
|
-
if (viewport.zoomLevel <= constants/* WAVEFORM_ZOOM_MIN */.LW) {
|
|
5516
|
+
if (!isTape() && viewport.zoomLevel <= constants/* WAVEFORM_ZOOM_MIN */.LW) {
|
|
5370
5517
|
clearFollowPin();
|
|
5371
5518
|
return;
|
|
5372
5519
|
}
|
|
@@ -5378,12 +5525,13 @@ function usePlayheadCamera({
|
|
|
5378
5525
|
}
|
|
5379
5526
|
const liveViewport = getViewportAtScroll(viewport, getScrollLeft(wavesurfer, viewport.scrollLeftPx));
|
|
5380
5527
|
const action = getPlayheadCameraAction({
|
|
5528
|
+
cameraMode: cameraModeRef.current,
|
|
5381
5529
|
isPlaying: true,
|
|
5382
5530
|
playJustStarted,
|
|
5383
5531
|
timeSec,
|
|
5384
5532
|
viewport: liveViewport
|
|
5385
5533
|
});
|
|
5386
|
-
if (holdFollowUntilInsetRef.current && !playJustStarted) {
|
|
5534
|
+
if (!isTape() && holdFollowUntilInsetRef.current && !playJustStarted) {
|
|
5387
5535
|
if (action.type !== 'none') {
|
|
5388
5536
|
return;
|
|
5389
5537
|
}
|
|
@@ -5415,6 +5563,7 @@ function usePlayheadCamera({
|
|
|
5415
5563
|
const tick = now => {
|
|
5416
5564
|
const t = Math.min(1, (now - start) / constants/* WAVEFORM_PLAYHEAD_JUMP_MS */.Bq);
|
|
5417
5565
|
const liveAction = getPlayheadCameraAction({
|
|
5566
|
+
cameraMode: cameraModeRef.current,
|
|
5418
5567
|
isPlaying: true,
|
|
5419
5568
|
playJustStarted: true,
|
|
5420
5569
|
timeSec: mediaTimeRef.current,
|
|
@@ -5431,7 +5580,7 @@ function usePlayheadCamera({
|
|
|
5431
5580
|
apply(mediaTimeRef.current, false);
|
|
5432
5581
|
};
|
|
5433
5582
|
jumpAnimationRef.current = window.requestAnimationFrame(tick);
|
|
5434
|
-
}, [applyScrollLeft, cancelJump, clearFollowPin, pinFollowPlayhead, playheadRef, viewportRef, wavesurferRef]);
|
|
5583
|
+
}, [applyScrollLeft, cancelJump, clearFollowPin, isTape, pinFollowPlayhead, playheadRef, viewportRef, wavesurferRef]);
|
|
5435
5584
|
applyRef.current = apply;
|
|
5436
5585
|
|
|
5437
5586
|
/**
|
|
@@ -5454,9 +5603,12 @@ function usePlayheadCamera({
|
|
|
5454
5603
|
}
|
|
5455
5604
|
releaseUserPanHold();
|
|
5456
5605
|
cancelJump();
|
|
5457
|
-
|
|
5606
|
+
if (!isTape()) {
|
|
5607
|
+
isFollowPinnedRef.current = false;
|
|
5608
|
+
}
|
|
5458
5609
|
const liveViewport = getViewportAtScroll(viewportRef.current, getScrollLeft(wavesurfer, viewportRef.current.scrollLeftPx));
|
|
5459
5610
|
const action = getSeekCameraAction({
|
|
5611
|
+
cameraMode: cameraModeRef.current,
|
|
5460
5612
|
timeSec,
|
|
5461
5613
|
viewport: liveViewport
|
|
5462
5614
|
});
|
|
@@ -5476,7 +5628,7 @@ function usePlayheadCamera({
|
|
|
5476
5628
|
applyScrollLeft(from + (to - from) * (1 - (1 - t) * (1 - t)), false);
|
|
5477
5629
|
const playhead = playheadRef.current;
|
|
5478
5630
|
if (playhead) {
|
|
5479
|
-
playhead.style.left = timeLeftPercent(mediaTimeRef.current, viewportRef.current.durationSec, viewportRef.current);
|
|
5631
|
+
playhead.style.left = isTape() ? getTapePinnedPlayheadLeft() : timeLeftPercent(mediaTimeRef.current, viewportRef.current.durationSec, viewportRef.current);
|
|
5480
5632
|
}
|
|
5481
5633
|
if (t < 1) {
|
|
5482
5634
|
jumpAnimationRef.current = window.requestAnimationFrame(tick);
|
|
@@ -5486,7 +5638,7 @@ function usePlayheadCamera({
|
|
|
5486
5638
|
applyScrollLeft(to, true);
|
|
5487
5639
|
};
|
|
5488
5640
|
jumpAnimationRef.current = window.requestAnimationFrame(tick);
|
|
5489
|
-
}, [applyScrollLeft, cancelJump, playheadRef, releaseUserPanHold, viewportRef, wavesurferRef]);
|
|
5641
|
+
}, [applyScrollLeft, cancelJump, isTape, playheadRef, releaseUserPanHold, viewportRef, wavesurferRef]);
|
|
5490
5642
|
const handleScroll = (0,external_react_.useCallback)(onUserPan => {
|
|
5491
5643
|
const wavesurfer = wavesurferRef.current;
|
|
5492
5644
|
if (!wavesurfer) {
|
|
@@ -5498,8 +5650,28 @@ function usePlayheadCamera({
|
|
|
5498
5650
|
return;
|
|
5499
5651
|
}
|
|
5500
5652
|
viewportRef.current = getViewportAtScroll(viewportRef.current, scrollLeftPx);
|
|
5501
|
-
const timeSec = readMediaTime();
|
|
5502
5653
|
const playhead = playheadRef.current;
|
|
5654
|
+
if (isTape()) {
|
|
5655
|
+
if (playhead) {
|
|
5656
|
+
playhead.style.left = getTapePinnedPlayheadLeft();
|
|
5657
|
+
}
|
|
5658
|
+
const pinTimeSec = Math.min(viewportRef.current.durationSec, Math.max(0, timeFromPositionPx(viewportRef.current.widthPx / 2, viewportRef.current)));
|
|
5659
|
+
userIsScrollingRef.current = true;
|
|
5660
|
+
window.clearTimeout(scrollSettleTimerRef.current);
|
|
5661
|
+
scrollSettleTimerRef.current = window.setTimeout(() => {
|
|
5662
|
+
userIsScrollingRef.current = false;
|
|
5663
|
+
scrollSettleTimerRef.current = 0;
|
|
5664
|
+
if (!mediaElRef.current || mediaElRef.current.paused) {
|
|
5665
|
+
return;
|
|
5666
|
+
}
|
|
5667
|
+
applyRef.current?.(readMediaTime(), false);
|
|
5668
|
+
}, constants/* WAVEFORM_FOLLOW_SCROLL_SETTLE_MS */.Zs);
|
|
5669
|
+
cancelJump();
|
|
5670
|
+
programmaticScrollRef.current = false;
|
|
5671
|
+
onUserPan(pinTimeSec);
|
|
5672
|
+
return;
|
|
5673
|
+
}
|
|
5674
|
+
const timeSec = readMediaTime();
|
|
5503
5675
|
if (playhead) {
|
|
5504
5676
|
playhead.style.left = timeLeftPercent(timeSec, viewportRef.current.durationSec, viewportRef.current);
|
|
5505
5677
|
}
|
|
@@ -5518,7 +5690,7 @@ function usePlayheadCamera({
|
|
|
5518
5690
|
isFollowPinnedRef.current = false;
|
|
5519
5691
|
programmaticScrollRef.current = false;
|
|
5520
5692
|
onUserPan(timeSec);
|
|
5521
|
-
}, [cancelJump, isUserPan, mediaElRef, playheadRef, readMediaTime, viewportRef, wavesurferRef]);
|
|
5693
|
+
}, [cancelJump, isTape, isUserPan, mediaElRef, playheadRef, readMediaTime, viewportRef, wavesurferRef]);
|
|
5522
5694
|
(0,external_react_.useEffect)(() => () => {
|
|
5523
5695
|
releaseUserPanHold();
|
|
5524
5696
|
cancelJump();
|
|
@@ -5530,6 +5702,7 @@ function usePlayheadCamera({
|
|
|
5530
5702
|
clearFollowPin,
|
|
5531
5703
|
handleScroll,
|
|
5532
5704
|
isFollowPinned,
|
|
5705
|
+
isUserPanning,
|
|
5533
5706
|
onSeek,
|
|
5534
5707
|
onZoom,
|
|
5535
5708
|
releaseUserPanHold,
|
|
@@ -5555,6 +5728,8 @@ function WaveformView_toPrimitive(t, r) { if ("object" != typeof t || !t) return
|
|
|
5555
5728
|
|
|
5556
5729
|
|
|
5557
5730
|
|
|
5731
|
+
|
|
5732
|
+
|
|
5558
5733
|
/** Pointer X in the view and the media time under it; zoom keeps this point fixed. */
|
|
5559
5734
|
|
|
5560
5735
|
/** CSS width × devicePixelRatio, for canvas gradient fills. */
|
|
@@ -5584,6 +5759,25 @@ function disableScrollOverscroll(container) {
|
|
|
5584
5759
|
}
|
|
5585
5760
|
}
|
|
5586
5761
|
|
|
5762
|
+
/** Half-view margins so t=0 and duration can sit under the center pin. */
|
|
5763
|
+
function applyWaveformGutters(wavesurfer, gutterPx) {
|
|
5764
|
+
const wrapper = wavesurfer.getWrapper ? wavesurfer.getWrapper() : null;
|
|
5765
|
+
if (!wrapper || !wrapper.style) {
|
|
5766
|
+
return;
|
|
5767
|
+
}
|
|
5768
|
+
const pad = gutterPx > 0 ? `${gutterPx}px` : '';
|
|
5769
|
+
wrapper.style.marginLeft = pad;
|
|
5770
|
+
wrapper.style.marginRight = pad;
|
|
5771
|
+
// WaveSurfer sets overflow-x:hidden when duration * minPxPerSec <= view width
|
|
5772
|
+
// (tape 1x). Gutters live in these margins, so the scroller must stay pan-able.
|
|
5773
|
+
const scroll = wrapper.parentElement;
|
|
5774
|
+
if (scroll && scroll.style) {
|
|
5775
|
+
const scrollStyle = scroll.style;
|
|
5776
|
+
scrollStyle.overflowX = gutterPx > 0 ? 'auto' : '';
|
|
5777
|
+
scrollStyle.scrollbarWidth = gutterPx > 0 ? 'none' : '';
|
|
5778
|
+
}
|
|
5779
|
+
}
|
|
5780
|
+
|
|
5587
5781
|
/** Tint WaveSurfer's zoomed tiles with played/unplayed/hover/buffer colors. */
|
|
5588
5782
|
function tintZoomedWaveform(wavesurfer, fills, replaceSnapshot = false) {
|
|
5589
5783
|
const wrapper = wavesurfer.getWrapper ? wavesurfer.getWrapper() : null;
|
|
@@ -5597,6 +5791,15 @@ function tintZoomedWaveform(wavesurfer, fills, replaceSnapshot = false) {
|
|
|
5597
5791
|
totalWidthCss: wrapper.clientWidth
|
|
5598
5792
|
});
|
|
5599
5793
|
}
|
|
5794
|
+
|
|
5795
|
+
/** Touch (and the compatibility mouse events Chrome sends after a tap) must not drive hover fills. */
|
|
5796
|
+
function isTouchHoverInput(event) {
|
|
5797
|
+
if (event.pointerType === 'touch') {
|
|
5798
|
+
return true;
|
|
5799
|
+
}
|
|
5800
|
+
const native = event.nativeEvent;
|
|
5801
|
+
return !!native.sourceCapabilities?.firesTouchEvents;
|
|
5802
|
+
}
|
|
5600
5803
|
function touchDistance(touches) {
|
|
5601
5804
|
if (touches.length < 2) {
|
|
5602
5805
|
return 0;
|
|
@@ -5627,11 +5830,14 @@ function zoomOriginAtPointer(pointerX, wavesurfer, durationSec, fallbackWidth) {
|
|
|
5627
5830
|
*/
|
|
5628
5831
|
function WaveformView({
|
|
5629
5832
|
bufferedRange,
|
|
5833
|
+
cameraMode = 'desktop',
|
|
5630
5834
|
currentTime = 0,
|
|
5631
5835
|
durationSec,
|
|
5632
5836
|
height = constants/* WAVEFORM_HEIGHT */.oN,
|
|
5633
5837
|
interactive = true,
|
|
5838
|
+
isPlaying = false,
|
|
5634
5839
|
mediaEl,
|
|
5840
|
+
onPlayPause,
|
|
5635
5841
|
onSeek,
|
|
5636
5842
|
onViewportChange,
|
|
5637
5843
|
onZoomChange,
|
|
@@ -5639,42 +5845,59 @@ function WaveformView({
|
|
|
5639
5845
|
zoomLevel: zoomLevelProp
|
|
5640
5846
|
}) {
|
|
5641
5847
|
// DOM / WaveSurfer
|
|
5642
|
-
const containerRef = (0,external_react_.useRef)(null);
|
|
5643
|
-
const
|
|
5644
|
-
const playheadRef = (0,external_react_.useRef)(null);
|
|
5645
|
-
const
|
|
5646
|
-
const wavesurferRef = (0,external_react_.useRef)(null);
|
|
5848
|
+
const containerRef = (0,external_react_.useRef)(null); // WaveSurfer canvas host
|
|
5849
|
+
const playheadAnimationRef = (0,external_react_.useRef)(0); // animation frame id while the playhead follows playback
|
|
5850
|
+
const playheadRef = (0,external_react_.useRef)(null); // playhead element the camera positions
|
|
5851
|
+
const trackRef = (0,external_react_.useRef)(null); // hover / tap target around the canvas
|
|
5852
|
+
const wavesurferRef = (0,external_react_.useRef)(null); // WaveSurfer instance
|
|
5647
5853
|
|
|
5648
5854
|
// Latest props for WaveSurfer + media listeners that must not re-subscribe each render.
|
|
5649
|
-
const
|
|
5650
|
-
const
|
|
5651
|
-
const
|
|
5652
|
-
const
|
|
5653
|
-
const
|
|
5654
|
-
const
|
|
5655
|
-
const mediaElRef = (0,external_react_.useRef)(mediaEl);
|
|
5656
|
-
const
|
|
5657
|
-
const
|
|
5658
|
-
const
|
|
5855
|
+
const cameraModeRef = (0,external_react_.useRef)(cameraMode); // latest tape/desktop; WaveSurfer create() deps stay empty
|
|
5856
|
+
const currentTimeRef = (0,external_react_.useRef)(currentTime); // latest media time; zoom recenter reads this
|
|
5857
|
+
const durationSecRef = (0,external_react_.useRef)(durationSec); // latest duration; click-to-seek reads this
|
|
5858
|
+
const hasZoomHandlersRef = (0,external_react_.useRef)(false); // parent can zoom; wheel/pinch check this
|
|
5859
|
+
const interactiveRef = (0,external_react_.useRef)(interactive); // latest interactive; WaveSurfer listeners read this
|
|
5860
|
+
const isPlayingRef = (0,external_react_.useRef)(isPlaying); // latest isPlaying; tape tap toggles from this
|
|
5861
|
+
const mediaElRef = (0,external_react_.useRef)(mediaEl); // latest <audio>/<video>; camera + playhead tick read this
|
|
5862
|
+
const onPlayPauseRef = (0,external_react_.useRef)(onPlayPause); // latest play/pause; tape tap must not re-bind
|
|
5863
|
+
const onSeekRef = (0,external_react_.useRef)(onSeek); // latest onSeek; click/scroll handlers must not re-bind
|
|
5864
|
+
const onViewportChangeRef = (0,external_react_.useRef)(onViewportChange); // latest viewport callback; camera commits here
|
|
5865
|
+
const peaksRef = (0,external_react_.useRef)(peaks); // latest peaks; WaveSurfer create() + morph read this
|
|
5866
|
+
|
|
5867
|
+
const displayedPeaksRef = (0,external_react_.useRef)(null); // peaks currently drawn (for morph)
|
|
5868
|
+
const peakTransitionAnimationRef = (0,external_react_.useRef)(0); // animation frame id while peaks morph in
|
|
5659
5869
|
// Zoom / pinch / tile tint (read from pointer + WaveSurfer handlers)
|
|
5660
|
-
const
|
|
5661
|
-
const
|
|
5662
|
-
const
|
|
5663
|
-
const
|
|
5664
|
-
const
|
|
5665
|
-
|
|
5666
|
-
const
|
|
5667
|
-
const
|
|
5668
|
-
const
|
|
5669
|
-
|
|
5670
|
-
|
|
5870
|
+
const applyZoomWindowRef = (0,external_react_.useRef)(null); // latest applyZoomWindow; resize observer calls this
|
|
5871
|
+
const bufferProgressRef = (0,external_react_.useRef)(0); // latest buffer fill; zoomed tile tint reads this
|
|
5872
|
+
const hideScrubTimeChipTimerRef = (0,external_react_.useRef)(0); // hides the tape scrub time chip after scroll settles
|
|
5873
|
+
const hoverProgressRef = (0,external_react_.useRef)(null); // latest hover fill; zoomed tile tint reads this
|
|
5874
|
+
const lastObservedWidthRef = (0,external_react_.useRef)(0); // last ResizeObserver width; skip no-op resizes
|
|
5875
|
+
const liveHeightRef = (0,external_react_.useRef)(height); // canvas height last applied to WaveSurfer
|
|
5876
|
+
const pinchStartRef = (0,external_react_.useRef)(null); // two-finger distance and zoom at pinch start
|
|
5877
|
+
const pointerZoomClearTimerRef = (0,external_react_.useRef)(0); // clears pointerZoomRef after WAVEFORM_ZOOM_DISMISS_MS
|
|
5878
|
+
const pointerZoomRef = (0,external_react_.useRef)(false); // pinch/wheel in progress; skip play/pause and tape recenter
|
|
5879
|
+
const queuedTapeSeekTimeSecRef = (0,external_react_.useRef)(null); // seek time waiting for the next animation frame
|
|
5880
|
+
const suppressNextTapPlayPauseRef = (0,external_react_.useRef)(false); // swallow play/pause after a swipe or pinch
|
|
5881
|
+
const suppressNextTapPlayPauseTimerRef = (0,external_react_.useRef)(0); // clears suppressNextTapPlayPauseRef
|
|
5882
|
+
const suppressViewportSyncRef = (0,external_react_.useRef)(false); // ignore WaveSurfer zoom/scroll while we setOptions
|
|
5883
|
+
const tapeSeekAnimationRef = (0,external_react_.useRef)(0); // coalesces swipe seeks to one seek per animation frame
|
|
5884
|
+
const toggleTapePlaybackRef = (0,external_react_.useRef)(null); // latest tap play/pause; click/pointerup call this
|
|
5885
|
+
const zoomOriginRef = (0,external_react_.useRef)(null); // pointer+time so zoom keeps that point fixed
|
|
5886
|
+
|
|
5887
|
+
cameraModeRef.current = cameraMode;
|
|
5671
5888
|
currentTimeRef.current = currentTime;
|
|
5672
|
-
peaksRef.current = peaks;
|
|
5673
5889
|
durationSecRef.current = durationSec;
|
|
5890
|
+
interactiveRef.current = interactive;
|
|
5891
|
+
isPlayingRef.current = isPlaying;
|
|
5674
5892
|
mediaElRef.current = mediaEl;
|
|
5893
|
+
onPlayPauseRef.current = onPlayPause;
|
|
5894
|
+
onSeekRef.current = onSeek;
|
|
5675
5895
|
onViewportChangeRef.current = onViewportChange;
|
|
5896
|
+
peaksRef.current = peaks;
|
|
5676
5897
|
const [internalZoom, setInternalZoom] = (0,external_react_.useState)(constants/* WAVEFORM_ZOOM_MIN */.LW);
|
|
5677
5898
|
const [hoverProgress, setHoverProgress] = (0,external_react_.useState)(null);
|
|
5899
|
+
const [scrubPreviewTimeSec, setScrubPreviewTimeSec] = (0,external_react_.useState)(null);
|
|
5900
|
+
const [overlayPortalHost, setOverlayPortalHost] = (0,external_react_.useState)(null);
|
|
5678
5901
|
const [canvasWidthPx, setCanvasWidthPx] = (0,external_react_.useState)(0);
|
|
5679
5902
|
const [scrollLeft, setScrollLeft] = (0,external_react_.useState)(0);
|
|
5680
5903
|
const isControlled = typeof zoomLevelProp === 'number';
|
|
@@ -5687,19 +5910,22 @@ function WaveformView({
|
|
|
5687
5910
|
const zoomLevel = clampWaveformZoom(isControlled ? zoomLevelProp : internalZoom, maxZoom);
|
|
5688
5911
|
const zoomRef = (0,external_react_.useRef)(zoomLevel); // latest zoom for WaveSurfer redraw/zoom handlers
|
|
5689
5912
|
zoomRef.current = zoomLevel;
|
|
5690
|
-
const prevZoomRef = (0,external_react_.useRef)(null);
|
|
5913
|
+
const prevZoomRef = (0,external_react_.useRef)(null); // last applied zoom; tape recenters only when this changes
|
|
5914
|
+
const isTape = cameraMode === 'tape';
|
|
5691
5915
|
const isZoomed = zoomLevel > constants/* WAVEFORM_ZOOM_MIN */.LW;
|
|
5916
|
+
const isScrollableWindow = isZoomed || isTape;
|
|
5692
5917
|
const bufferProgress = getBufferedProgress(bufferedRange, durationSec);
|
|
5693
5918
|
bufferProgressRef.current = bufferProgress;
|
|
5694
5919
|
hoverProgressRef.current = hoverProgress;
|
|
5695
5920
|
const viewport = (0,external_react_.useMemo)(() => createWaveformViewport({
|
|
5696
5921
|
durationSec,
|
|
5922
|
+
gutterPx: isTape ? getTapeGutterPx(canvasWidthPx) : 0,
|
|
5697
5923
|
heightPx: height,
|
|
5698
5924
|
maxZoom,
|
|
5699
5925
|
scrollLeftPx: scrollLeft,
|
|
5700
5926
|
widthPx: canvasWidthPx,
|
|
5701
5927
|
zoomLevel
|
|
5702
|
-
}), [canvasWidthPx, durationSec, height, maxZoom, scrollLeft, zoomLevel]);
|
|
5928
|
+
}), [canvasWidthPx, durationSec, height, isTape, maxZoom, scrollLeft, zoomLevel]);
|
|
5703
5929
|
const viewportRef = (0,external_react_.useRef)(viewport); // live scroll window; prefer this over render-state while the camera is moving
|
|
5704
5930
|
const onViewportCommit = (0,external_react_.useCallback)((scrollLeftPx, nextViewport, commitReactState = true) => {
|
|
5705
5931
|
onViewportChangeRef.current?.(nextViewport);
|
|
@@ -5714,20 +5940,45 @@ function WaveformView({
|
|
|
5714
5940
|
clearFollowPin,
|
|
5715
5941
|
handleScroll: handleCameraScroll,
|
|
5716
5942
|
isFollowPinned,
|
|
5943
|
+
isUserPanning,
|
|
5717
5944
|
onSeek: onPlayheadSeek,
|
|
5718
5945
|
onZoom,
|
|
5719
5946
|
releaseUserPanHold,
|
|
5720
5947
|
seekTo
|
|
5721
5948
|
} = usePlayheadCamera({
|
|
5949
|
+
cameraMode,
|
|
5722
5950
|
mediaElRef,
|
|
5723
5951
|
onViewportCommit,
|
|
5724
5952
|
playheadRef,
|
|
5725
5953
|
viewportRef,
|
|
5726
5954
|
wavesurferRef
|
|
5727
5955
|
});
|
|
5956
|
+
const toggleTapePlayback = (0,external_react_.useCallback)(() => {
|
|
5957
|
+
if (!interactiveRef.current) {
|
|
5958
|
+
return;
|
|
5959
|
+
}
|
|
5960
|
+
if (isUserPanning() || pointerZoomRef.current) {
|
|
5961
|
+
return;
|
|
5962
|
+
}
|
|
5963
|
+
if (suppressNextTapPlayPauseRef.current) {
|
|
5964
|
+
suppressNextTapPlayPauseRef.current = false;
|
|
5965
|
+
window.clearTimeout(suppressNextTapPlayPauseTimerRef.current);
|
|
5966
|
+
suppressNextTapPlayPauseTimerRef.current = 0;
|
|
5967
|
+
return;
|
|
5968
|
+
}
|
|
5969
|
+
onPlayPauseRef.current?.(!isPlayingRef.current);
|
|
5970
|
+
suppressNextTapPlayPauseRef.current = true;
|
|
5971
|
+
window.clearTimeout(suppressNextTapPlayPauseTimerRef.current);
|
|
5972
|
+
suppressNextTapPlayPauseTimerRef.current = window.setTimeout(() => {
|
|
5973
|
+
suppressNextTapPlayPauseRef.current = false;
|
|
5974
|
+
suppressNextTapPlayPauseTimerRef.current = 0;
|
|
5975
|
+
}, constants/* WAVEFORM_TAPE_CLICK_SUPPRESS_MS */.fI);
|
|
5976
|
+
}, [isUserPanning]);
|
|
5977
|
+
toggleTapePlaybackRef.current = toggleTapePlayback;
|
|
5728
5978
|
(0,external_react_.useLayoutEffect)(() => {
|
|
5729
5979
|
viewportRef.current = createWaveformViewport({
|
|
5730
5980
|
durationSec: viewport.durationSec,
|
|
5981
|
+
gutterPx: viewport.gutterPx,
|
|
5731
5982
|
heightPx: viewport.heightPx,
|
|
5732
5983
|
maxZoom: viewport.maxZoom,
|
|
5733
5984
|
scrollLeftPx: viewportRef.current.scrollLeftPx,
|
|
@@ -5750,6 +6001,41 @@ function WaveformView({
|
|
|
5750
6001
|
pointerZoomClearTimerRef.current = 0;
|
|
5751
6002
|
}, constants/* WAVEFORM_ZOOM_DISMISS_MS */.m6);
|
|
5752
6003
|
}, []);
|
|
6004
|
+
|
|
6005
|
+
/**
|
|
6006
|
+
* Seek the time under the pin (one seek per frame). Swallow the delayed iOS click;
|
|
6007
|
+
* show the scrub chip until the swipe settles.
|
|
6008
|
+
*/
|
|
6009
|
+
const handleTapeSwipe = (0,external_react_.useCallback)(timeSec => {
|
|
6010
|
+
// Swallow the click WaveSurfer/iOS fires after a swipe or pinch.
|
|
6011
|
+
suppressNextTapPlayPauseRef.current = true;
|
|
6012
|
+
window.clearTimeout(suppressNextTapPlayPauseTimerRef.current);
|
|
6013
|
+
suppressNextTapPlayPauseTimerRef.current = window.setTimeout(() => {
|
|
6014
|
+
suppressNextTapPlayPauseRef.current = false;
|
|
6015
|
+
suppressNextTapPlayPauseTimerRef.current = 0;
|
|
6016
|
+
}, constants/* WAVEFORM_TAPE_CLICK_SUPPRESS_MS */.fI);
|
|
6017
|
+
queuedTapeSeekTimeSecRef.current = timeSec;
|
|
6018
|
+
if (!tapeSeekAnimationRef.current) {
|
|
6019
|
+
// One seek per frame; later scrolls just update the queued time.
|
|
6020
|
+
tapeSeekAnimationRef.current = window.requestAnimationFrame(() => {
|
|
6021
|
+
tapeSeekAnimationRef.current = 0;
|
|
6022
|
+
const next = queuedTapeSeekTimeSecRef.current;
|
|
6023
|
+
queuedTapeSeekTimeSecRef.current = null;
|
|
6024
|
+
if (next != null) {
|
|
6025
|
+
onSeekRef.current?.(next);
|
|
6026
|
+
}
|
|
6027
|
+
});
|
|
6028
|
+
}
|
|
6029
|
+
if (interactiveRef.current) {
|
|
6030
|
+
// Show the time under the pin; hide once scrolling has settled.
|
|
6031
|
+
setScrubPreviewTimeSec(timeSec);
|
|
6032
|
+
window.clearTimeout(hideScrubTimeChipTimerRef.current);
|
|
6033
|
+
hideScrubTimeChipTimerRef.current = window.setTimeout(() => {
|
|
6034
|
+
setScrubPreviewTimeSec(null);
|
|
6035
|
+
hideScrubTimeChipTimerRef.current = 0;
|
|
6036
|
+
}, constants/* WAVEFORM_FOLLOW_SCROLL_SETTLE_MS */.Zs);
|
|
6037
|
+
}
|
|
6038
|
+
}, []);
|
|
5753
6039
|
const syncViewport = (0,external_react_.useCallback)(() => {
|
|
5754
6040
|
const wavesurfer = wavesurferRef.current;
|
|
5755
6041
|
if (!wavesurfer) {
|
|
@@ -5765,14 +6051,16 @@ function WaveformView({
|
|
|
5765
6051
|
if (!playhead) {
|
|
5766
6052
|
return;
|
|
5767
6053
|
}
|
|
5768
|
-
if (
|
|
6054
|
+
if (isTape) {
|
|
6055
|
+
playhead.style.left = getTapePinnedPlayheadLeft();
|
|
6056
|
+
} else if (!isFollowPinned()) {
|
|
5769
6057
|
playhead.style.left = timeLeftPercent(timeSec, durationSecRef.current, viewportRef.current);
|
|
5770
6058
|
}
|
|
5771
6059
|
const wavesurfer = wavesurferRef.current;
|
|
5772
6060
|
if (wavesurfer && wavesurfer.setTime) {
|
|
5773
6061
|
wavesurfer.setTime(timeSec);
|
|
5774
6062
|
}
|
|
5775
|
-
}, [isFollowPinned]);
|
|
6063
|
+
}, [isFollowPinned, isTape]);
|
|
5776
6064
|
|
|
5777
6065
|
// Same zoom-window body as the zoom effect; extracted so resize can call it too.
|
|
5778
6066
|
const applyZoomWindow = (0,external_react_.useCallback)(() => {
|
|
@@ -5784,11 +6072,13 @@ function WaveformView({
|
|
|
5784
6072
|
const viewWidthPx = wavesurfer.getWidth ? wavesurfer.getWidth() : container.clientWidth;
|
|
5785
6073
|
const minPxPerSec = getZoomedPixelsPerSecond({
|
|
5786
6074
|
durationSec,
|
|
6075
|
+
isTape,
|
|
5787
6076
|
maxZoom,
|
|
5788
6077
|
viewWidthPx,
|
|
5789
6078
|
zoomLevel
|
|
5790
6079
|
});
|
|
5791
|
-
const
|
|
6080
|
+
const gutterPx = isTape ? getTapeGutterPx(viewWidthPx) : 0;
|
|
6081
|
+
const origin = isTape ? null : zoomOriginRef.current;
|
|
5792
6082
|
zoomOriginRef.current = null;
|
|
5793
6083
|
const didZoomChange = prevZoomRef.current !== zoomLevel;
|
|
5794
6084
|
if (origin || didZoomChange) {
|
|
@@ -5798,24 +6088,27 @@ function WaveformView({
|
|
|
5798
6088
|
try {
|
|
5799
6089
|
wavesurfer.setOptions(WaveformView_objectSpread({
|
|
5800
6090
|
autoScroll: false,
|
|
6091
|
+
fillParent: !isTape,
|
|
5801
6092
|
minPxPerSec
|
|
5802
|
-
},
|
|
5803
|
-
progressColor:
|
|
6093
|
+
}, isScrollableWindow ? {
|
|
6094
|
+
progressColor: getPlayedWaveformColor(isTape),
|
|
5804
6095
|
waveColor: WAVEFORM_COLOR_UNPLAYED
|
|
5805
6096
|
} : {}));
|
|
6097
|
+
applyWaveformGutters(wavesurfer, gutterPx);
|
|
5806
6098
|
if (minPxPerSec > 0) {
|
|
6099
|
+
const windowViewport = createWaveformViewport({
|
|
6100
|
+
durationSec,
|
|
6101
|
+
gutterPx,
|
|
6102
|
+
heightPx: liveHeightRef.current || height,
|
|
6103
|
+
maxZoom,
|
|
6104
|
+
scrollLeftPx: 0,
|
|
6105
|
+
widthPx: viewWidthPx,
|
|
6106
|
+
zoomLevel
|
|
6107
|
+
});
|
|
5807
6108
|
if (origin) {
|
|
5808
|
-
applyScrollLeft(origin.timeSec * minPxPerSec - origin.pointerX, true);
|
|
5809
|
-
} else if (didZoomChange && !pointerZoomRef.current) {
|
|
5810
|
-
|
|
5811
|
-
durationSec,
|
|
5812
|
-
heightPx: height,
|
|
5813
|
-
maxZoom,
|
|
5814
|
-
scrollLeftPx: 0,
|
|
5815
|
-
widthPx: viewWidthPx,
|
|
5816
|
-
zoomLevel
|
|
5817
|
-
});
|
|
5818
|
-
applyScrollLeft(Math.min(maxScrollLeft(zoomedViewport), Math.max(0, currentTimeRef.current * minPxPerSec - viewWidthPx / 2)), true);
|
|
6109
|
+
applyScrollLeft(origin.timeSec * minPxPerSec + gutterPx - origin.pointerX, true);
|
|
6110
|
+
} else if (didZoomChange && (isTape || !pointerZoomRef.current)) {
|
|
6111
|
+
applyScrollLeft(getCenteredScrollLeft(currentTimeRef.current, windowViewport), true);
|
|
5819
6112
|
}
|
|
5820
6113
|
}
|
|
5821
6114
|
wavesurfer.setTime(currentTimeRef.current);
|
|
@@ -5825,13 +6118,17 @@ function WaveformView({
|
|
|
5825
6118
|
}
|
|
5826
6119
|
syncViewport();
|
|
5827
6120
|
updatePlayheadPosition(currentTimeRef.current);
|
|
5828
|
-
}, [applyScrollLeft, durationSec, height, maxZoom, onZoom, syncViewport, updatePlayheadPosition, zoomLevel]);
|
|
6121
|
+
}, [applyScrollLeft, durationSec, height, isScrollableWindow, isTape, maxZoom, onZoom, syncViewport, updatePlayheadPosition, zoomLevel]);
|
|
5829
6122
|
applyZoomWindowRef.current = applyZoomWindow;
|
|
5830
6123
|
(0,external_react_.useEffect)(() => {
|
|
5831
6124
|
const container = containerRef.current;
|
|
5832
6125
|
if (!container) {
|
|
5833
6126
|
return undefined;
|
|
5834
6127
|
}
|
|
6128
|
+
const measuredHeight = cameraModeRef.current === 'tape' && container.clientHeight > 0 ? Math.round(container.clientHeight) : height;
|
|
6129
|
+
if (cameraModeRef.current === 'tape' && measuredHeight > 0) {
|
|
6130
|
+
liveHeightRef.current = measuredHeight;
|
|
6131
|
+
}
|
|
5835
6132
|
const wavesurfer = w.create({
|
|
5836
6133
|
autoScroll: false,
|
|
5837
6134
|
barGap: constants/* WAVEFORM_BAR_GAP */.Lu,
|
|
@@ -5842,25 +6139,34 @@ function WaveformView({
|
|
|
5842
6139
|
cursorWidth: 0,
|
|
5843
6140
|
duration: durationSecRef.current,
|
|
5844
6141
|
fillParent: true,
|
|
5845
|
-
height,
|
|
6142
|
+
height: measuredHeight,
|
|
5846
6143
|
hideScrollbar: true,
|
|
5847
|
-
|
|
6144
|
+
dragToSeek: false,
|
|
6145
|
+
interact: interactiveRef.current && cameraModeRef.current !== 'tape',
|
|
5848
6146
|
normalize: false,
|
|
5849
6147
|
peaks: toChannels(peaksRef.current),
|
|
5850
|
-
progressColor:
|
|
6148
|
+
progressColor: getPlayedWaveformColor(cameraModeRef.current === 'tape'),
|
|
5851
6149
|
waveColor: WAVEFORM_COLOR_UNPLAYED
|
|
5852
6150
|
});
|
|
5853
6151
|
const unsubscribeClick = wavesurfer.on('click', relativeX => {
|
|
5854
6152
|
if (!interactiveRef.current) {
|
|
5855
6153
|
return;
|
|
5856
6154
|
}
|
|
6155
|
+
if (cameraModeRef.current === 'tape') {
|
|
6156
|
+
toggleTapePlaybackRef.current?.();
|
|
6157
|
+
return;
|
|
6158
|
+
}
|
|
5857
6159
|
onSeekRef.current?.(relativeX * durationSecRef.current);
|
|
5858
6160
|
});
|
|
5859
6161
|
const unsubscribeScroll = wavesurfer.on('scroll', () => {
|
|
5860
6162
|
if (suppressViewportSyncRef.current) {
|
|
5861
6163
|
return;
|
|
5862
6164
|
}
|
|
5863
|
-
|
|
6165
|
+
// User pan: map scroll to the time under the playhead, then tape seeks it.
|
|
6166
|
+
handleCameraScroll(timeSec => {
|
|
6167
|
+
if (cameraModeRef.current === 'tape' && !pointerZoomRef.current) {
|
|
6168
|
+
handleTapeSwipe(timeSec);
|
|
6169
|
+
}
|
|
5864
6170
|
syncViewport();
|
|
5865
6171
|
});
|
|
5866
6172
|
});
|
|
@@ -5871,12 +6177,13 @@ function WaveformView({
|
|
|
5871
6177
|
syncViewport();
|
|
5872
6178
|
});
|
|
5873
6179
|
const unsubscribeRedraw = wavesurfer.on('redrawcomplete', () => {
|
|
5874
|
-
if (!(zoomRef.current > constants/* WAVEFORM_ZOOM_MIN */.LW)) {
|
|
6180
|
+
if (!(zoomRef.current > constants/* WAVEFORM_ZOOM_MIN */.LW) && cameraModeRef.current !== 'tape') {
|
|
5875
6181
|
return;
|
|
5876
6182
|
}
|
|
5877
6183
|
tintZoomedWaveform(wavesurfer, getWaveformFills({
|
|
5878
6184
|
bufferProgress: bufferProgressRef.current,
|
|
5879
|
-
hoverProgress: hoverProgressRef.current
|
|
6185
|
+
hoverProgress: cameraModeRef.current === 'tape' ? null : hoverProgressRef.current,
|
|
6186
|
+
isTape: cameraModeRef.current === 'tape'
|
|
5880
6187
|
}), true);
|
|
5881
6188
|
});
|
|
5882
6189
|
wavesurferRef.current = wavesurfer;
|
|
@@ -5887,6 +6194,9 @@ function WaveformView({
|
|
|
5887
6194
|
return () => {
|
|
5888
6195
|
releaseUserPanHold();
|
|
5889
6196
|
cancelJump();
|
|
6197
|
+
window.clearTimeout(hideScrubTimeChipTimerRef.current);
|
|
6198
|
+
window.clearTimeout(suppressNextTapPlayPauseTimerRef.current);
|
|
6199
|
+
window.cancelAnimationFrame(tapeSeekAnimationRef.current);
|
|
5890
6200
|
window.cancelAnimationFrame(peakTransitionAnimationRef.current);
|
|
5891
6201
|
unsubscribeClick();
|
|
5892
6202
|
unsubscribeScroll();
|
|
@@ -5896,18 +6206,39 @@ function WaveformView({
|
|
|
5896
6206
|
wavesurferRef.current = null;
|
|
5897
6207
|
displayedPeaksRef.current = null;
|
|
5898
6208
|
};
|
|
5899
|
-
}, [cancelJump, handleCameraScroll, height, releaseUserPanHold, syncViewport]);
|
|
6209
|
+
}, [cancelJump, handleCameraScroll, handleTapeSwipe, height, isUserPanning, releaseUserPanHold, syncViewport]);
|
|
5900
6210
|
(0,external_react_.useLayoutEffect)(() => {
|
|
5901
6211
|
const el = containerRef.current;
|
|
5902
6212
|
if (!el) {
|
|
5903
6213
|
return undefined;
|
|
5904
6214
|
}
|
|
5905
6215
|
setCanvasWidthPx(el.clientWidth);
|
|
6216
|
+
lastObservedWidthRef.current = el.clientWidth;
|
|
6217
|
+
const mountedHeight = Math.round(el.clientHeight);
|
|
6218
|
+
if (cameraModeRef.current === 'tape' && mountedHeight > 0) {
|
|
6219
|
+
liveHeightRef.current = mountedHeight;
|
|
6220
|
+
}
|
|
5906
6221
|
const observer = new ResizeObserver(entries => {
|
|
5907
6222
|
entries.forEach(entry => {
|
|
5908
|
-
|
|
6223
|
+
const nextWidth = entry.contentRect.width;
|
|
6224
|
+
const widthChanged = nextWidth !== lastObservedWidthRef.current;
|
|
6225
|
+
lastObservedWidthRef.current = nextWidth;
|
|
6226
|
+
setCanvasWidthPx(nextWidth);
|
|
6227
|
+
const nextHeight = Math.round(entry.contentRect.height);
|
|
6228
|
+
if (cameraModeRef.current === 'tape' && Number.isFinite(nextHeight) && nextHeight > 0 && nextHeight !== liveHeightRef.current) {
|
|
6229
|
+
liveHeightRef.current = nextHeight;
|
|
6230
|
+
const wavesurfer = wavesurferRef.current;
|
|
6231
|
+
if (wavesurfer && wavesurfer.setOptions) {
|
|
6232
|
+
wavesurfer.setOptions({
|
|
6233
|
+
height: nextHeight
|
|
6234
|
+
});
|
|
6235
|
+
}
|
|
6236
|
+
}
|
|
6237
|
+
syncViewport();
|
|
6238
|
+
if (widthChanged) {
|
|
6239
|
+
applyZoomWindowRef.current?.();
|
|
6240
|
+
}
|
|
5909
6241
|
});
|
|
5910
|
-
syncViewport();
|
|
5911
6242
|
});
|
|
5912
6243
|
observer.observe(el);
|
|
5913
6244
|
return () => observer.disconnect();
|
|
@@ -5932,7 +6263,7 @@ function WaveformView({
|
|
|
5932
6263
|
return;
|
|
5933
6264
|
}
|
|
5934
6265
|
wavesurfer.setOptions({
|
|
5935
|
-
interact: interactive
|
|
6266
|
+
interact: interactive && cameraModeRef.current !== 'tape'
|
|
5936
6267
|
});
|
|
5937
6268
|
}, [interactive]);
|
|
5938
6269
|
(0,external_react_.useLayoutEffect)(() => {
|
|
@@ -5963,13 +6294,17 @@ function WaveformView({
|
|
|
5963
6294
|
window.cancelAnimationFrame(playheadAnimationRef.current);
|
|
5964
6295
|
cancelJump();
|
|
5965
6296
|
releaseUserPanHold();
|
|
5966
|
-
|
|
6297
|
+
if (cameraModeRef.current !== 'tape') {
|
|
6298
|
+
clearFollowPin();
|
|
6299
|
+
}
|
|
5967
6300
|
syncViewport();
|
|
5968
6301
|
updatePlayheadPosition(media.currentTime);
|
|
5969
6302
|
};
|
|
5970
6303
|
const handleSeeked = () => {
|
|
5971
6304
|
onPlayheadSeek(media.currentTime);
|
|
5972
|
-
|
|
6305
|
+
if (!isUserPanning()) {
|
|
6306
|
+
seekTo(media.currentTime);
|
|
6307
|
+
}
|
|
5973
6308
|
updatePlayheadPosition(media.currentTime);
|
|
5974
6309
|
};
|
|
5975
6310
|
if (!media.paused) {
|
|
@@ -5988,7 +6323,7 @@ function WaveformView({
|
|
|
5988
6323
|
media.removeEventListener('pause', stopLoop);
|
|
5989
6324
|
media.removeEventListener('seeked', handleSeeked);
|
|
5990
6325
|
};
|
|
5991
|
-
}, [applyPlayheadCamera, cancelJump, clearFollowPin, mediaEl, onPlayheadSeek, releaseUserPanHold, seekTo, syncViewport, updatePlayheadPosition]);
|
|
6326
|
+
}, [applyPlayheadCamera, cancelJump, clearFollowPin, isUserPanning, mediaEl, onPlayheadSeek, releaseUserPanHold, seekTo, syncViewport, updatePlayheadPosition]);
|
|
5992
6327
|
(0,external_react_.useEffect)(() => {
|
|
5993
6328
|
const wavesurfer = wavesurferRef.current;
|
|
5994
6329
|
if (!wavesurfer || !wavesurfer.setOptions || !(durationSec > 0)) {
|
|
@@ -6023,9 +6358,10 @@ function WaveformView({
|
|
|
6023
6358
|
}
|
|
6024
6359
|
const fills = getWaveformFills({
|
|
6025
6360
|
bufferProgress,
|
|
6026
|
-
hoverProgress
|
|
6361
|
+
hoverProgress: isTape ? null : hoverProgress,
|
|
6362
|
+
isTape
|
|
6027
6363
|
});
|
|
6028
|
-
if (
|
|
6364
|
+
if (isScrollableWindow) {
|
|
6029
6365
|
tintZoomedWaveform(wavesurfer, fills);
|
|
6030
6366
|
return;
|
|
6031
6367
|
}
|
|
@@ -6034,7 +6370,7 @@ function WaveformView({
|
|
|
6034
6370
|
waveColor: toCanvasFill(fills.waveColor, devicePixelWidth(canvasWidthPx))
|
|
6035
6371
|
});
|
|
6036
6372
|
wavesurfer.setTime(currentTimeRef.current);
|
|
6037
|
-
}, [bufferProgress, canvasWidthPx, hoverProgress,
|
|
6373
|
+
}, [bufferProgress, canvasWidthPx, hoverProgress, isScrollableWindow, isTape]);
|
|
6038
6374
|
(0,external_react_.useEffect)(() => {
|
|
6039
6375
|
const track = trackRef.current;
|
|
6040
6376
|
if (!track) {
|
|
@@ -6115,7 +6451,7 @@ function WaveformView({
|
|
|
6115
6451
|
};
|
|
6116
6452
|
}, [durationSec, markPointerZoom, setZoomLevel]);
|
|
6117
6453
|
const onHoverMove = (0,external_react_.useCallback)(event => {
|
|
6118
|
-
if (!interactive) {
|
|
6454
|
+
if (!interactive || isTape || isTouchHoverInput(event)) {
|
|
6119
6455
|
return;
|
|
6120
6456
|
}
|
|
6121
6457
|
const rect = event.currentTarget.getBoundingClientRect();
|
|
@@ -6132,19 +6468,48 @@ function WaveformView({
|
|
|
6132
6468
|
return;
|
|
6133
6469
|
}
|
|
6134
6470
|
setHoverProgress(Math.min(1, Math.max(0, pointerX / rect.width)));
|
|
6135
|
-
}, [durationSec, interactive]);
|
|
6471
|
+
}, [durationSec, interactive, isTape]);
|
|
6136
6472
|
const onHoverLeave = (0,external_react_.useCallback)(() => {
|
|
6137
6473
|
setHoverProgress(null);
|
|
6138
6474
|
}, []);
|
|
6475
|
+
const bindOverlayPortalHost = (0,external_react_.useCallback)(node => {
|
|
6476
|
+
const host = node?.parentElement ?? null;
|
|
6477
|
+
setOverlayPortalHost(prev => prev === host ? prev : host);
|
|
6478
|
+
}, []);
|
|
6139
6479
|
const hoverLeft = hoverProgress == null ? null : timeLeftPercent(hoverProgress * durationSec, durationSec, viewportRef.current);
|
|
6480
|
+
const scrubTimeChip = isTape && scrubPreviewTimeSec != null ? /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
6481
|
+
className: "bp-WaveformView-hover bp-WaveformView-hover--tape",
|
|
6482
|
+
"data-testid": "bp-waveform-hover"
|
|
6483
|
+
}, /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
6484
|
+
className: "bp-WaveformView-hoverTime",
|
|
6485
|
+
"data-testid": "bp-waveform-hover-time"
|
|
6486
|
+
}, formatTime(scrubPreviewTimeSec))) : null;
|
|
6140
6487
|
return /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
6141
|
-
|
|
6488
|
+
ref: bindOverlayPortalHost,
|
|
6489
|
+
className: classnames_default()('bp-WaveformView', {
|
|
6490
|
+
'bp-WaveformView--inert': !interactive,
|
|
6491
|
+
'bp-WaveformView--tape': isTape,
|
|
6492
|
+
'bp-WaveformView--zoomed': isZoomed
|
|
6493
|
+
}),
|
|
6142
6494
|
"data-testid": "bp-waveform-view"
|
|
6143
6495
|
}, /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
6144
6496
|
ref: trackRef,
|
|
6145
6497
|
className: "bp-WaveformView-track",
|
|
6146
|
-
onMouseLeave: interactive ? onHoverLeave : undefined,
|
|
6147
|
-
onMouseMove: interactive ? onHoverMove : undefined
|
|
6498
|
+
onMouseLeave: interactive && !isTape ? onHoverLeave : undefined,
|
|
6499
|
+
onMouseMove: interactive && !isTape ? onHoverMove : undefined,
|
|
6500
|
+
onPointerMove: interactive && !isTape ? event => {
|
|
6501
|
+
if (event.pointerType === 'touch') {
|
|
6502
|
+
onHoverLeave();
|
|
6503
|
+
return;
|
|
6504
|
+
}
|
|
6505
|
+
onHoverMove(event);
|
|
6506
|
+
} : undefined,
|
|
6507
|
+
onPointerUp: isTape ? event => {
|
|
6508
|
+
if (event.button > 0) {
|
|
6509
|
+
return;
|
|
6510
|
+
}
|
|
6511
|
+
toggleTapePlaybackRef.current?.();
|
|
6512
|
+
} : undefined
|
|
6148
6513
|
}, /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
6149
6514
|
ref: containerRef,
|
|
6150
6515
|
className: "bp-WaveformView-canvas"
|
|
@@ -6162,12 +6527,9 @@ function WaveformView({
|
|
|
6162
6527
|
}, /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
6163
6528
|
className: "bp-WaveformView-hoverTime",
|
|
6164
6529
|
"data-testid": "bp-waveform-hover-time"
|
|
6165
|
-
}, formatTime(hoverProgress * durationSec)))));
|
|
6530
|
+
}, formatTime(hoverProgress * durationSec)))), scrubTimeChip && overlayPortalHost ? /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_dom_7dac9eee_createPortal__(scrubTimeChip, overlayPortalHost) : null);
|
|
6166
6531
|
}
|
|
6167
6532
|
/* harmony default export */ const waveform_WaveformView = (/*#__PURE__*/external_react_["default"].memo(WaveformView));
|
|
6168
|
-
// EXTERNAL MODULE: ./node_modules/classnames/index.js
|
|
6169
|
-
var classnames = __webpack_require__(2485);
|
|
6170
|
-
var classnames_default = /*#__PURE__*/__webpack_require__.n(classnames);
|
|
6171
6533
|
;// ./src/lib/viewers/controls/icons/IconZoomIn24.tsx
|
|
6172
6534
|
|
|
6173
6535
|
function IconZoomIn24() {
|
|
@@ -6253,11 +6615,14 @@ function WaveformZoomControl({
|
|
|
6253
6615
|
}) {
|
|
6254
6616
|
const [isHovered, setHovered] = (0,external_react_.useState)(false);
|
|
6255
6617
|
const [isFocused, setFocused] = (0,external_react_.useState)(false);
|
|
6256
|
-
const
|
|
6618
|
+
const [isPinned, setPinned] = (0,external_react_.useState)(false);
|
|
6619
|
+
const wasFlyoutOpenOnPointerDownRef = (0,external_react_.useRef)(true); // first tap on + pins the flyout instead of zooming
|
|
6620
|
+
const zoomControlElRef = (0,external_react_.useRef)(null); // root; outside pointerdown unpins the flyout
|
|
6621
|
+
const dismissTimerRef = (0,external_react_.useRef)(0); // delay before hover-close of the flyout
|
|
6257
6622
|
const sliderId = `bp-waveform-zoom-slider${(0,external_react_.useId)()}`;
|
|
6258
6623
|
const zoom = clampWaveformZoom(zoomLevel, maxZoom);
|
|
6259
6624
|
const zoomValue = Math.round(sliderValueFromZoom(zoom, maxZoom));
|
|
6260
|
-
const isOpen = isHovered || isFocused || isRevealed;
|
|
6625
|
+
const isOpen = isHovered || isFocused || isRevealed || isPinned;
|
|
6261
6626
|
const isAtMinZoom = zoomValue <= 0;
|
|
6262
6627
|
const isAtMaxZoom = zoomValue >= constants/* WAVEFORM_ZOOM_SLIDER_MAX */.nh;
|
|
6263
6628
|
const clearDismiss = (0,external_react_.useCallback)(() => {
|
|
@@ -6265,13 +6630,42 @@ function WaveformZoomControl({
|
|
|
6265
6630
|
dismissTimerRef.current = 0;
|
|
6266
6631
|
}, []);
|
|
6267
6632
|
(0,external_react_.useEffect)(() => () => window.clearTimeout(dismissTimerRef.current), []);
|
|
6633
|
+
(0,external_react_.useEffect)(() => {
|
|
6634
|
+
if (!isPinned) {
|
|
6635
|
+
return undefined;
|
|
6636
|
+
}
|
|
6637
|
+
const closeIfOutside = event => {
|
|
6638
|
+
const zoomControlEl = zoomControlElRef.current;
|
|
6639
|
+
if (!zoomControlEl || zoomControlEl.contains(event.target)) {
|
|
6640
|
+
return;
|
|
6641
|
+
}
|
|
6642
|
+
setPinned(false);
|
|
6643
|
+
setFocused(false);
|
|
6644
|
+
setHovered(false);
|
|
6645
|
+
};
|
|
6646
|
+
document.addEventListener('pointerdown', closeIfOutside);
|
|
6647
|
+
return () => document.removeEventListener('pointerdown', closeIfOutside);
|
|
6648
|
+
}, [isPinned]);
|
|
6268
6649
|
const handleSlider = (0,external_react_.useCallback)(newValue => {
|
|
6269
6650
|
onZoomChange(zoomFromSliderValue(newValue, maxZoom));
|
|
6270
6651
|
}, [maxZoom, onZoomChange]);
|
|
6271
6652
|
const handleStep = (0,external_react_.useCallback)(delta => {
|
|
6272
6653
|
onZoomChange(zoomFromSliderValue(zoomValue + delta, maxZoom));
|
|
6273
6654
|
}, [maxZoom, onZoomChange, zoomValue]);
|
|
6655
|
+
const handleZoomInPointerDown = (0,external_react_.useCallback)(() => {
|
|
6656
|
+
wasFlyoutOpenOnPointerDownRef.current = isHovered || isFocused || isRevealed || isPinned;
|
|
6657
|
+
}, [isFocused, isHovered, isPinned, isRevealed]);
|
|
6658
|
+
const handleZoomInClick = (0,external_react_.useCallback)(() => {
|
|
6659
|
+
if (!wasFlyoutOpenOnPointerDownRef.current) {
|
|
6660
|
+
setPinned(true);
|
|
6661
|
+
return;
|
|
6662
|
+
}
|
|
6663
|
+
if (!isAtMaxZoom) {
|
|
6664
|
+
handleStep(constants/* WAVEFORM_ZOOM_BUTTON_STEP */.QD);
|
|
6665
|
+
}
|
|
6666
|
+
}, [handleStep, isAtMaxZoom]);
|
|
6274
6667
|
return /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
6668
|
+
ref: zoomControlElRef,
|
|
6275
6669
|
"aria-label": "Zoom",
|
|
6276
6670
|
className: classnames_default()('bp-WaveformZoomControl', {
|
|
6277
6671
|
'bp-is-open': isOpen
|
|
@@ -6282,6 +6676,7 @@ function WaveformZoomControl({
|
|
|
6282
6676
|
return;
|
|
6283
6677
|
}
|
|
6284
6678
|
setFocused(false);
|
|
6679
|
+
setPinned(false);
|
|
6285
6680
|
},
|
|
6286
6681
|
onFocus: () => {
|
|
6287
6682
|
clearDismiss();
|
|
@@ -6299,15 +6694,12 @@ function WaveformZoomControl({
|
|
|
6299
6694
|
},
|
|
6300
6695
|
role: "group"
|
|
6301
6696
|
}, /*#__PURE__*/external_react_["default"].createElement(MediaToggle/* default */.A, {
|
|
6302
|
-
"aria-disabled": isAtMaxZoom,
|
|
6697
|
+
"aria-disabled": isOpen && isAtMaxZoom,
|
|
6303
6698
|
className: "bp-WaveformZoomControl-button",
|
|
6304
6699
|
"data-resin-target": "waveformZoomIn",
|
|
6305
6700
|
"data-testid": "bp-waveform-zoom-in",
|
|
6306
|
-
onClick:
|
|
6307
|
-
|
|
6308
|
-
handleStep(constants/* WAVEFORM_ZOOM_BUTTON_STEP */.QD);
|
|
6309
|
-
}
|
|
6310
|
-
},
|
|
6701
|
+
onClick: handleZoomInClick,
|
|
6702
|
+
onPointerDown: handleZoomInPointerDown,
|
|
6311
6703
|
title: "Zoom in"
|
|
6312
6704
|
}, /*#__PURE__*/external_react_["default"].createElement(icons_IconZoomIn24, null)), /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
6313
6705
|
"aria-hidden": !isOpen,
|
|
@@ -6361,6 +6753,7 @@ function WaveformZoomControl({
|
|
|
6361
6753
|
|
|
6362
6754
|
|
|
6363
6755
|
|
|
6756
|
+
|
|
6364
6757
|
const PLACEHOLDER_PEAKS = placeholderPeaks();
|
|
6365
6758
|
function MP3ControlsV2({
|
|
6366
6759
|
autoplay,
|
|
@@ -6388,12 +6781,15 @@ function MP3ControlsV2({
|
|
|
6388
6781
|
const [zoomLevel, setZoomLevel] = (0,external_react_.useState)(constants/* WAVEFORM_ZOOM_MIN */.LW);
|
|
6389
6782
|
const [maxZoom, setMaxZoom] = (0,external_react_.useState)(constants/* WAVEFORM_ZOOM_MIN */.LW);
|
|
6390
6783
|
const [isZoomRevealed, setIsZoomRevealed] = (0,external_react_.useState)(false);
|
|
6391
|
-
const zoomRevealTimerRef = (0,external_react_.useRef)(0);
|
|
6784
|
+
const zoomRevealTimerRef = (0,external_react_.useRef)(0); // hides the zoom flyout after WAVEFORM_ZOOM_DISMISS_MS
|
|
6392
6785
|
const hasRealPeaks = !!(peaks && peaks.length);
|
|
6393
6786
|
const waveformPeaks = hasRealPeaks ? peaks : PLACEHOLDER_PEAKS;
|
|
6394
6787
|
const waveformDurationSec = hasWaveformDuration ? durationValue : PLACEHOLDER_DURATION_SEC;
|
|
6395
6788
|
const [playRequested, setPlayRequested] = (0,external_react_.useState)(false);
|
|
6396
6789
|
const [viewport, setViewport] = (0,external_react_.useState)(null);
|
|
6790
|
+
const isTape = useTapeWaveform();
|
|
6791
|
+
const hasAppliedTapeDefaultZoomRef = (0,external_react_.useRef)(false); // ~10s window applied; reset to 1× when leaving tape
|
|
6792
|
+
const userChangedTapeZoomRef = (0,external_react_.useRef)(false); // pinch/wheel zoom; skip re-applying the 10s default
|
|
6397
6793
|
const handleViewportChange = (0,external_react_.useCallback)(next => {
|
|
6398
6794
|
setMaxZoom(prev => prev === next.maxZoom ? prev : next.maxZoom);
|
|
6399
6795
|
setViewport(prev => viewportEquals(prev, next) ? prev : next);
|
|
@@ -6407,12 +6803,33 @@ function MP3ControlsV2({
|
|
|
6407
6803
|
}, constants/* WAVEFORM_ZOOM_DISMISS_MS */.m6);
|
|
6408
6804
|
}, []);
|
|
6409
6805
|
const handleWaveformZoom = (0,external_react_.useCallback)(nextZoom => {
|
|
6806
|
+
userChangedTapeZoomRef.current = true;
|
|
6410
6807
|
setZoomLevel(nextZoom);
|
|
6411
6808
|
revealZoomControl();
|
|
6412
6809
|
}, [revealZoomControl]);
|
|
6413
6810
|
(0,external_react_.useEffect)(() => {
|
|
6414
6811
|
setZoomLevel(prev => clampWaveformZoom(prev, maxZoom));
|
|
6415
6812
|
}, [maxZoom]);
|
|
6813
|
+
(0,external_react_.useEffect)(() => {
|
|
6814
|
+
if (!isTape) {
|
|
6815
|
+
if (hasAppliedTapeDefaultZoomRef.current) {
|
|
6816
|
+
hasAppliedTapeDefaultZoomRef.current = false;
|
|
6817
|
+
userChangedTapeZoomRef.current = false;
|
|
6818
|
+
setZoomLevel(constants/* WAVEFORM_ZOOM_MIN */.LW);
|
|
6819
|
+
}
|
|
6820
|
+
return;
|
|
6821
|
+
}
|
|
6822
|
+
if (!hasWaveformDuration || !hasRealPeaks || !viewport || !(viewport.widthPx > 0)) {
|
|
6823
|
+
return;
|
|
6824
|
+
}
|
|
6825
|
+
if (userChangedTapeZoomRef.current) {
|
|
6826
|
+
hasAppliedTapeDefaultZoomRef.current = true;
|
|
6827
|
+
return;
|
|
6828
|
+
}
|
|
6829
|
+
const nextZoom = getTapeDefaultZoom(durationValue, Math.max(maxZoom, viewport.maxZoom));
|
|
6830
|
+
hasAppliedTapeDefaultZoomRef.current = true;
|
|
6831
|
+
setZoomLevel(prev => prev === nextZoom ? prev : nextZoom);
|
|
6832
|
+
}, [durationValue, hasRealPeaks, hasWaveformDuration, isTape, maxZoom, viewport]);
|
|
6416
6833
|
(0,external_react_.useEffect)(() => () => window.clearTimeout(zoomRevealTimerRef.current), []);
|
|
6417
6834
|
(0,external_react_.useEffect)(() => {
|
|
6418
6835
|
if (isPlaying) {
|
|
@@ -6441,6 +6858,7 @@ function MP3ControlsV2({
|
|
|
6441
6858
|
const showPlayOverlay = !playRequested && !isPlaying;
|
|
6442
6859
|
const hasZoomHandlers = hasRealPeaks && !showPlayOverlay;
|
|
6443
6860
|
const hasZoomControl = hasZoomHandlers && hasMediaMetadata && maxZoom > constants/* WAVEFORM_ZOOM_MIN */.LW;
|
|
6861
|
+
const waveformZoomLevel = isTape || hasZoomHandlers ? zoomLevel : constants/* WAVEFORM_ZOOM_MIN */.LW;
|
|
6444
6862
|
return /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
6445
6863
|
className: "bp-MP3ControlsV2",
|
|
6446
6864
|
"data-testid": "media-controls-wrapper-v2"
|
|
@@ -6450,18 +6868,22 @@ function MP3ControlsV2({
|
|
|
6450
6868
|
className: "bp-MP3ControlsV2-waveform"
|
|
6451
6869
|
}, /*#__PURE__*/external_react_["default"].createElement(waveform_WaveformView, {
|
|
6452
6870
|
bufferedRange: bufferedRange,
|
|
6871
|
+
cameraMode: isTape ? 'tape' : 'desktop',
|
|
6453
6872
|
currentTime: currentTime,
|
|
6454
6873
|
durationSec: waveformDurationSec,
|
|
6455
6874
|
interactive: isWaveformInteractive,
|
|
6875
|
+
isPlaying: isPlaying,
|
|
6456
6876
|
mediaEl: mediaEl,
|
|
6877
|
+
onPlayPause: isWaveformInteractive ? onPlayPause : undefined,
|
|
6457
6878
|
onSeek: isWaveformInteractive ? onTimeChange : undefined,
|
|
6458
6879
|
onViewportChange: hasRealPeaks ? handleViewportChange : undefined,
|
|
6459
6880
|
onZoomChange: hasZoomHandlers ? handleWaveformZoom : undefined,
|
|
6460
6881
|
peaks: waveformPeaks,
|
|
6461
|
-
zoomLevel:
|
|
6882
|
+
zoomLevel: waveformZoomLevel
|
|
6462
6883
|
}), /*#__PURE__*/external_react_["default"].createElement(WaveformCommentMarkers, {
|
|
6463
6884
|
commentMarkers: waveformMarkers,
|
|
6464
6885
|
durationSec: hasWaveformDuration ? durationValue : 0,
|
|
6886
|
+
isTape: isTape,
|
|
6465
6887
|
onCommentMarkerClick: handleCommentMarkerClick,
|
|
6466
6888
|
selectedId: selectedMarkerId,
|
|
6467
6889
|
viewport: viewport
|
|
@@ -6470,7 +6892,7 @@ function MP3ControlsV2({
|
|
|
6470
6892
|
}, /*#__PURE__*/external_react_["default"].createElement(WaveformZoomControl, {
|
|
6471
6893
|
isRevealed: isZoomRevealed,
|
|
6472
6894
|
maxZoom: maxZoom,
|
|
6473
|
-
onZoomChange:
|
|
6895
|
+
onZoomChange: handleWaveformZoom,
|
|
6474
6896
|
zoomLevel: zoomLevel
|
|
6475
6897
|
})), showPlayOverlay && /*#__PURE__*/external_react_["default"].createElement("button", {
|
|
6476
6898
|
className: "bp-MP3ControlsV2-playOverlay"
|
|
@@ -6590,6 +7012,7 @@ function isFpsAvailable(player) {
|
|
|
6590
7012
|
(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
6591
7013
|
|
|
6592
7014
|
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
7015
|
+
/* harmony export */ Av: () => (/* binding */ WAVEFORM_TAPE_DEFAULT_WINDOW_SEC),
|
|
6593
7016
|
/* harmony export */ Bq: () => (/* binding */ WAVEFORM_PLAYHEAD_JUMP_MS),
|
|
6594
7017
|
/* harmony export */ DY: () => (/* binding */ WAVEFORM_BAR_RADIUS),
|
|
6595
7018
|
/* harmony export */ EB: () => (/* binding */ CLIENT_DECODE_MAX_COMPRESSED_BYTES),
|
|
@@ -6597,12 +7020,14 @@ function isFpsAvailable(player) {
|
|
|
6597
7020
|
/* harmony export */ GQ: () => (/* binding */ DURATION_MISMATCH_TOLERANCE_SEC),
|
|
6598
7021
|
/* harmony export */ Kl: () => (/* binding */ WAVEFORM_MIN_VIEW_WINDOW_SEC),
|
|
6599
7022
|
/* harmony export */ LW: () => (/* binding */ WAVEFORM_ZOOM_MIN),
|
|
7023
|
+
/* harmony export */ Le: () => (/* binding */ TAPE_POINTER_MEDIA_QUERY),
|
|
6600
7024
|
/* harmony export */ Lu: () => (/* binding */ WAVEFORM_BAR_GAP),
|
|
6601
7025
|
/* harmony export */ NM: () => (/* binding */ WAVEFORM_FOLLOW_INSET_PX),
|
|
6602
7026
|
/* harmony export */ QD: () => (/* binding */ WAVEFORM_ZOOM_BUTTON_STEP),
|
|
6603
7027
|
/* harmony export */ XS: () => (/* binding */ WAVEFORM_BAR_MIN_HEIGHT),
|
|
6604
7028
|
/* harmony export */ Zs: () => (/* binding */ WAVEFORM_FOLLOW_SCROLL_SETTLE_MS),
|
|
6605
7029
|
/* harmony export */ f3: () => (/* binding */ CLIENT_DECODE_PEAK_COUNT),
|
|
7030
|
+
/* harmony export */ fI: () => (/* binding */ WAVEFORM_TAPE_CLICK_SUPPRESS_MS),
|
|
6606
7031
|
/* harmony export */ i8: () => (/* binding */ PEAK_UNIT_MAX),
|
|
6607
7032
|
/* harmony export */ m6: () => (/* binding */ WAVEFORM_ZOOM_DISMISS_MS),
|
|
6608
7033
|
/* harmony export */ mJ: () => (/* binding */ PEAK_UNIT_MIN),
|
|
@@ -6642,6 +7067,10 @@ const WAVEFORM_ZOOM_MIN = 1;
|
|
|
6642
7067
|
const WAVEFORM_ZOOM_MAX = 24;
|
|
6643
7068
|
/** Visible window never shorter than this. */
|
|
6644
7069
|
const WAVEFORM_MIN_VIEW_WINDOW_SEC = 4;
|
|
7070
|
+
/** Tape (phone/tablet) default: seconds of audio visible in the viewport. */
|
|
7071
|
+
const WAVEFORM_TAPE_DEFAULT_WINDOW_SEC = 10;
|
|
7072
|
+
/** Primary pointer is a finger, not a mouse/trackpad. */
|
|
7073
|
+
const TAPE_POINTER_MEDIA_QUERY = '(hover: none) and (pointer: coarse)';
|
|
6645
7074
|
const WAVEFORM_ZOOM_SLIDER_MAX = 100;
|
|
6646
7075
|
/** One click on zoom in/out moves this many units on the 0–100 slider. */
|
|
6647
7076
|
const WAVEFORM_ZOOM_BUTTON_STEP = 10;
|
|
@@ -6650,6 +7079,8 @@ const WAVEFORM_FOLLOW_INSET_PX = 200;
|
|
|
6650
7079
|
const WAVEFORM_PLAYHEAD_JUMP_MS = 400;
|
|
6651
7080
|
/** After the last user pan, wait this long before the camera may pin again. */
|
|
6652
7081
|
const WAVEFORM_FOLLOW_SCROLL_SETTLE_MS = 150;
|
|
7082
|
+
/** Ignore a WaveSurfer click after a tape swipe (iOS delayed click). Must outlast the scrub-chip hide. */
|
|
7083
|
+
const WAVEFORM_TAPE_CLICK_SUPPRESS_MS = 200;
|
|
6653
7084
|
const WAVEFORM_BAR_GAP = 2;
|
|
6654
7085
|
const WAVEFORM_BAR_WIDTH = 2;
|
|
6655
7086
|
const WAVEFORM_BAR_RADIUS = WAVEFORM_BAR_WIDTH / 2;
|
|
@@ -6701,6 +7132,12 @@ function isWaveformErrorCode(value) {
|
|
|
6701
7132
|
|
|
6702
7133
|
/** Visible slice of the timeline. Emitted whenever zoom, scroll, or width changes. */
|
|
6703
7134
|
|
|
7135
|
+
/** Navigator fields used to detect iPad, including iPadOS reporting itself as Mac. */
|
|
7136
|
+
|
|
7137
|
+
/** Window bits needed to choose tape vs desktop (coarse pointer + iPad). */
|
|
7138
|
+
|
|
7139
|
+
/** Desktop walks then pins near the right inset. Tape keeps the playhead at center. */
|
|
7140
|
+
|
|
6704
7141
|
/** One canvas linear-gradient stop. `offset` is 0–1 along the bar. */
|
|
6705
7142
|
|
|
6706
7143
|
/**
|
|
@@ -23055,7 +23492,7 @@ class Browser {
|
|
|
23055
23492
|
;// ./src/lib/Logger.js
|
|
23056
23493
|
/* eslint-disable no-undef */
|
|
23057
23494
|
const CLIENT_NAME = "box-content-preview";
|
|
23058
|
-
const CLIENT_VERSION = "3.
|
|
23495
|
+
const CLIENT_VERSION = "3.91.0";
|
|
23059
23496
|
/* eslint-enable no-undef */
|
|
23060
23497
|
|
|
23061
23498
|
class Logger {
|
|
@@ -34434,10 +34871,9 @@ class MediaBaseViewer extends viewers_BaseViewer {
|
|
|
34434
34871
|
const template = this.options.representation.content.url_template;
|
|
34435
34872
|
this.mediaEl.addEventListener('error', this.errorHandler);
|
|
34436
34873
|
this.mediaEl.setAttribute('title', this.options.file.name);
|
|
34437
|
-
if (lib_Browser.isIOS()) {
|
|
34438
|
-
// iOS
|
|
34439
|
-
//
|
|
34440
|
-
// https://webkit.org/blog/6784/new-video-policies-for-ios/
|
|
34874
|
+
if (lib_Browser.isIOS() && this.mediaEl.tagName === 'VIDEO') {
|
|
34875
|
+
// Unblocks loadeddata on iOS <video>. Do not set this on <audio>:
|
|
34876
|
+
// after tap-to-open, Safari will start playback.
|
|
34441
34877
|
this.mediaEl.autoplay = true;
|
|
34442
34878
|
}
|
|
34443
34879
|
const contentUrl = this.createContentUrlV2(template);
|
|
@@ -35930,7 +36366,7 @@ class MP3Viewer extends media_MediaBaseViewer {
|
|
|
35930
36366
|
* @return {Promise<{ default: Function }>} MP3ControlsV2 module
|
|
35931
36367
|
*/
|
|
35932
36368
|
importV2Controls() {
|
|
35933
|
-
return Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__,
|
|
36369
|
+
return Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, 2668));
|
|
35934
36370
|
}
|
|
35935
36371
|
|
|
35936
36372
|
/**
|