box-content-preview 3.90.0 → 3.92.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 +4 -3
- package/dist/lib/index.js +1606 -167
- 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.92.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 = {};
|
|
@@ -2915,10 +2916,10 @@ function TimestampControl({
|
|
|
2915
2916
|
|
|
2916
2917
|
// EXPORTS
|
|
2917
2918
|
__webpack_require__.d(__webpack_exports__, {
|
|
2918
|
-
|
|
2919
|
+
Ay: () => (/* binding */ VolumeControls)
|
|
2919
2920
|
});
|
|
2920
2921
|
|
|
2921
|
-
// UNUSED EXPORTS: getIcon
|
|
2922
|
+
// UNUSED EXPORTS: VOLUME_FLYOUT_DISMISS_MS, getIcon
|
|
2922
2923
|
|
|
2923
2924
|
// EXTERNAL MODULE: external "react"
|
|
2924
2925
|
var external_react_ = __webpack_require__(1649);
|
|
@@ -2980,12 +2981,26 @@ function IconVolumeMuted24(props) {
|
|
|
2980
2981
|
var MediaToggle = __webpack_require__(8997);
|
|
2981
2982
|
;// ./src/lib/viewers/controls/hooks/useAttention.ts
|
|
2982
2983
|
|
|
2984
|
+
/** True when focus/hover is moving to a descendant, not leaving the host. */
|
|
2985
|
+
function isRelatedTargetInside(event) {
|
|
2986
|
+
return event.currentTarget.contains(event.relatedTarget);
|
|
2987
|
+
}
|
|
2983
2988
|
function useAttention() {
|
|
2984
2989
|
const [isFocused, setFocused] = external_react_.useState(false);
|
|
2985
2990
|
const [isHovered, setHovered] = external_react_.useState(false);
|
|
2986
|
-
const handleBlur =
|
|
2991
|
+
const handleBlur = event => {
|
|
2992
|
+
if (isRelatedTargetInside(event)) {
|
|
2993
|
+
return;
|
|
2994
|
+
}
|
|
2995
|
+
setFocused(false);
|
|
2996
|
+
};
|
|
2987
2997
|
const handleFocus = () => setFocused(true);
|
|
2988
|
-
const handleMouseOut =
|
|
2998
|
+
const handleMouseOut = event => {
|
|
2999
|
+
if (isRelatedTargetInside(event)) {
|
|
3000
|
+
return;
|
|
3001
|
+
}
|
|
3002
|
+
setHovered(false);
|
|
3003
|
+
};
|
|
2989
3004
|
const handleMouseOver = () => setHovered(true);
|
|
2990
3005
|
return [isFocused || isHovered, {
|
|
2991
3006
|
onBlur: handleBlur,
|
|
@@ -3022,7 +3037,7 @@ var util = __webpack_require__(4410);
|
|
|
3022
3037
|
// extracted by mini-css-extract-plugin
|
|
3023
3038
|
|
|
3024
3039
|
;// ./src/lib/viewers/controls/slider/VolumeSliderControl.tsx
|
|
3025
|
-
const _excluded = ["className", "max", "min", "onMove", "onUpdate", "step", "title", "value", "onMouseOver"];
|
|
3040
|
+
const _excluded = ["className", "max", "min", "onMove", "onUpdate", "step", "title", "value", "onMouseOver", "tabIndex"];
|
|
3026
3041
|
function VolumeSliderControl_extends() { return VolumeSliderControl_extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, VolumeSliderControl_extends.apply(null, arguments); }
|
|
3027
3042
|
function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
|
|
3028
3043
|
function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
|
|
@@ -3048,7 +3063,8 @@ function VolumeSliderControl(_ref) {
|
|
|
3048
3063
|
step = 1,
|
|
3049
3064
|
title,
|
|
3050
3065
|
value,
|
|
3051
|
-
onMouseOver
|
|
3066
|
+
onMouseOver,
|
|
3067
|
+
tabIndex = 0
|
|
3052
3068
|
} = _ref,
|
|
3053
3069
|
rest = _objectWithoutProperties(_ref, _excluded);
|
|
3054
3070
|
const [isScrubbing, setIsScrubbing] = external_react_["default"].useState(false);
|
|
@@ -3159,33 +3175,29 @@ function VolumeSliderControl(_ref) {
|
|
|
3159
3175
|
className: "bp-VolumeVerticalSliderControl-track-container"
|
|
3160
3176
|
}, /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
3161
3177
|
ref: sliderElRef,
|
|
3162
|
-
className: "bp-VolumeVerticalSliderControl-track-background",
|
|
3163
|
-
onMouseDown: handleMouseDown,
|
|
3164
|
-
role: "button",
|
|
3165
|
-
tabIndex: 0
|
|
3166
|
-
}, /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
3167
3178
|
"aria-label": title,
|
|
3168
3179
|
"aria-valuemax": max,
|
|
3169
3180
|
"aria-valuemin": min,
|
|
3170
3181
|
"aria-valuenow": value,
|
|
3171
|
-
className: "bp-VolumeVerticalSliderControl-track",
|
|
3182
|
+
className: "bp-VolumeVerticalSliderControl-track-background",
|
|
3172
3183
|
"data-resin-target": "volumeSlider",
|
|
3173
3184
|
"data-testid": "bp-volume-slider-control-track",
|
|
3174
|
-
onFocus:
|
|
3185
|
+
onFocus: (noop_default()),
|
|
3175
3186
|
onKeyDown: handleKeydown,
|
|
3176
3187
|
onMouseDown: handleMouseDown,
|
|
3177
3188
|
onMouseMove: handleMouseMove,
|
|
3178
3189
|
onMouseOver: onMouseOver,
|
|
3179
3190
|
onTouchStart: handleTouchStart,
|
|
3180
3191
|
role: "slider",
|
|
3192
|
+
tabIndex: tabIndex
|
|
3193
|
+
}, /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
3194
|
+
className: "bp-VolumeVerticalSliderControl-track",
|
|
3181
3195
|
style: {
|
|
3182
3196
|
height: `${heightValueBasedOnVolume / max * 100}%`
|
|
3183
|
-
}
|
|
3184
|
-
tabIndex: 0
|
|
3197
|
+
}
|
|
3185
3198
|
}))));
|
|
3186
3199
|
}
|
|
3187
3200
|
;// ./src/lib/viewers/controls/media/VolumeControls.tsx
|
|
3188
|
-
function VolumeControls_extends() { return VolumeControls_extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, VolumeControls_extends.apply(null, arguments); }
|
|
3189
3201
|
|
|
3190
3202
|
|
|
3191
3203
|
|
|
@@ -3196,6 +3208,9 @@ function VolumeControls_extends() { return VolumeControls_extends = Object.assig
|
|
|
3196
3208
|
|
|
3197
3209
|
|
|
3198
3210
|
|
|
3211
|
+
|
|
3212
|
+
/** Keyboard volume keeps the flyout open longer than the 200ms max-width transition. */
|
|
3213
|
+
const VOLUME_FLYOUT_DISMISS_MS = 1000;
|
|
3199
3214
|
function getIcon(volume) {
|
|
3200
3215
|
let Icon = icons_IconVolumeMuted24;
|
|
3201
3216
|
if (volume >= 0.66) {
|
|
@@ -3208,16 +3223,32 @@ function getIcon(volume) {
|
|
|
3208
3223
|
return Icon;
|
|
3209
3224
|
}
|
|
3210
3225
|
function VolumeControls({
|
|
3226
|
+
keyboardVolumeStep = 0,
|
|
3211
3227
|
onMuteChange,
|
|
3212
3228
|
onVolumeChange,
|
|
3213
3229
|
volume = 1
|
|
3214
3230
|
}) {
|
|
3215
3231
|
const [isActive, handlers] = useAttention();
|
|
3232
|
+
const [isRevealed, setIsRevealed] = (0,external_react_.useState)(false);
|
|
3233
|
+
const revealTimerRef = (0,external_react_.useRef)(0);
|
|
3216
3234
|
const isMuted = !volume;
|
|
3217
3235
|
const Icon = isMuted ? icons_IconVolumeMuted24 : getIcon(volume);
|
|
3218
3236
|
const title = isMuted ? "Unmute" : "Mute";
|
|
3219
3237
|
const value = Math.round(volume * 100);
|
|
3220
|
-
const
|
|
3238
|
+
const isOpen = isActive || isRevealed;
|
|
3239
|
+
(0,external_react_.useEffect)(() => {
|
|
3240
|
+
if (!keyboardVolumeStep) {
|
|
3241
|
+
return;
|
|
3242
|
+
}
|
|
3243
|
+
setIsRevealed(true);
|
|
3244
|
+
window.clearTimeout(revealTimerRef.current);
|
|
3245
|
+
revealTimerRef.current = window.setTimeout(() => {
|
|
3246
|
+
setIsRevealed(false);
|
|
3247
|
+
revealTimerRef.current = 0;
|
|
3248
|
+
}, VOLUME_FLYOUT_DISMISS_MS);
|
|
3249
|
+
}, [keyboardVolumeStep]);
|
|
3250
|
+
(0,external_react_.useEffect)(() => () => window.clearTimeout(revealTimerRef.current), []);
|
|
3251
|
+
const handleVolume = (0,external_react_.useCallback)(newValue => {
|
|
3221
3252
|
const newValueToUse = newValue <= 5 ? 0 : newValue;
|
|
3222
3253
|
// make sure the value is always between 0 and 1 since the value passed in could be
|
|
3223
3254
|
// greater than 100 if the user drags the mouse above the top of the sider when adjusting the volume
|
|
@@ -3227,27 +3258,39 @@ function VolumeControls({
|
|
|
3227
3258
|
return /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
3228
3259
|
className: "bp-VolumeControls",
|
|
3229
3260
|
"data-testid": "bp-volume-controls",
|
|
3230
|
-
onBlur:
|
|
3261
|
+
onBlur: event => {
|
|
3262
|
+
handlers.onBlur(event);
|
|
3263
|
+
if (event.currentTarget.contains(event.relatedTarget)) {
|
|
3264
|
+
return;
|
|
3265
|
+
}
|
|
3266
|
+
window.clearTimeout(revealTimerRef.current);
|
|
3267
|
+
revealTimerRef.current = 0;
|
|
3268
|
+
setIsRevealed(false);
|
|
3269
|
+
},
|
|
3231
3270
|
onFocus: handlers.onFocus,
|
|
3232
3271
|
onMouseOut: handlers.onMouseOut,
|
|
3233
3272
|
onMouseOver: handlers.onMouseOver
|
|
3234
|
-
}, /*#__PURE__*/external_react_["default"].createElement(MediaToggle/* default */.A,
|
|
3273
|
+
}, /*#__PURE__*/external_react_["default"].createElement(MediaToggle/* default */.A, {
|
|
3235
3274
|
className: "bp-VolumeControls-toggle",
|
|
3236
3275
|
"data-resin-target": "volumeToggle",
|
|
3237
3276
|
onClick: () => onMuteChange(!isMuted),
|
|
3238
3277
|
title: title
|
|
3239
|
-
},
|
|
3278
|
+
}, /*#__PURE__*/external_react_["default"].createElement(Icon, null)), /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
3279
|
+
"aria-hidden": !isOpen,
|
|
3240
3280
|
className: classnames_default()('bp-VolumeControls-flyout', {
|
|
3241
|
-
'bp-is-open':
|
|
3281
|
+
'bp-is-open': isOpen
|
|
3242
3282
|
})
|
|
3243
|
-
}, /*#__PURE__*/external_react_["default"].createElement(VolumeSliderControl,
|
|
3283
|
+
}, /*#__PURE__*/external_react_["default"].createElement(VolumeSliderControl, {
|
|
3284
|
+
"aria-hidden": !isOpen,
|
|
3244
3285
|
className: "bp-VolumeControls-slider",
|
|
3245
3286
|
max: 100,
|
|
3287
|
+
onMouseOver: handlers.onMouseOver,
|
|
3246
3288
|
onUpdate: handleVolume,
|
|
3247
3289
|
step: 1,
|
|
3290
|
+
tabIndex: isOpen ? 0 : -1,
|
|
3248
3291
|
title: "Volume Slider",
|
|
3249
3292
|
value: value
|
|
3250
|
-
}
|
|
3293
|
+
})));
|
|
3251
3294
|
}
|
|
3252
3295
|
|
|
3253
3296
|
/***/ },
|
|
@@ -4487,7 +4530,7 @@ function getPdfjsWorkerSrc() {
|
|
|
4487
4530
|
|
|
4488
4531
|
/***/ },
|
|
4489
4532
|
|
|
4490
|
-
/***/
|
|
4533
|
+
/***/ 7450
|
|
4491
4534
|
(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
4492
4535
|
|
|
4493
4536
|
|
|
@@ -4621,6 +4664,7 @@ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e =
|
|
|
4621
4664
|
/** Visible window: start/end times, pixels-per-second, and the current zoom. */
|
|
4622
4665
|
function createWaveformViewport({
|
|
4623
4666
|
durationSec,
|
|
4667
|
+
gutterPx = 0,
|
|
4624
4668
|
heightPx,
|
|
4625
4669
|
maxZoom,
|
|
4626
4670
|
scrollLeftPx,
|
|
@@ -4630,11 +4674,16 @@ function createWaveformViewport({
|
|
|
4630
4674
|
const zoom = Number.isFinite(zoomLevel) && zoomLevel > 0 ? zoomLevel : constants/* WAVEFORM_ZOOM_MIN */.LW;
|
|
4631
4675
|
const viewDurationSec = durationSec > 0 ? durationSec / zoom : 0; // seconds visible at this zoom
|
|
4632
4676
|
const pixelsPerSecond = viewDurationSec > 0 && widthPx > 0 ? widthPx / viewDurationSec : 0;
|
|
4633
|
-
const
|
|
4634
|
-
const
|
|
4677
|
+
const leadingGutterPx = Number.isFinite(gutterPx) && gutterPx > 0 ? gutterPx : 0;
|
|
4678
|
+
const unclampedStartSec = pixelsPerSecond > 0 ? (scrollLeftPx - leadingGutterPx) / pixelsPerSecond : 0;
|
|
4679
|
+
const gutterDurationSec = pixelsPerSecond > 0 ? leadingGutterPx / pixelsPerSecond : 0;
|
|
4680
|
+
const latestWindowStartSec = leadingGutterPx > 0 ? durationSec + gutterDurationSec - viewDurationSec : Math.max(0, durationSec - viewDurationSec);
|
|
4681
|
+
const earliestWindowStartSec = leadingGutterPx > 0 ? -gutterDurationSec : 0;
|
|
4682
|
+
const startSec = pixelsPerSecond > 0 ? Math.min(latestWindowStartSec, Math.max(earliestWindowStartSec, unclampedStartSec)) : 0;
|
|
4635
4683
|
return {
|
|
4636
4684
|
durationSec,
|
|
4637
4685
|
endSec: startSec + viewDurationSec,
|
|
4686
|
+
gutterPx: leadingGutterPx,
|
|
4638
4687
|
heightPx,
|
|
4639
4688
|
maxZoom,
|
|
4640
4689
|
pixelsPerSecond,
|
|
@@ -4654,7 +4703,7 @@ function getViewportAtScroll(viewport, scrollLeftPx) {
|
|
|
4654
4703
|
|
|
4655
4704
|
/** True when the visible window has not moved — skip a React state update. */
|
|
4656
4705
|
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;
|
|
4706
|
+
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
4707
|
}
|
|
4659
4708
|
|
|
4660
4709
|
/** How many CSS pixels from the left of the visible window this time sits. */
|
|
@@ -4701,17 +4750,34 @@ function clampWaveformZoom(zoomLevel, maxZoom = constants/* WAVEFORM_ZOOM_MIN */
|
|
|
4701
4750
|
/** WaveSurfer zoom density. 0 = fit the whole file in the view. */
|
|
4702
4751
|
function getZoomedPixelsPerSecond({
|
|
4703
4752
|
durationSec,
|
|
4753
|
+
isTape = false,
|
|
4704
4754
|
maxZoom = constants/* WAVEFORM_ZOOM_MIN */.LW,
|
|
4705
4755
|
viewWidthPx,
|
|
4706
4756
|
zoomLevel
|
|
4707
4757
|
}) {
|
|
4708
4758
|
const zoom = clampWaveformZoom(zoomLevel, maxZoom);
|
|
4709
|
-
if (
|
|
4759
|
+
if (!(durationSec > 0) || !(viewWidthPx > 0)) {
|
|
4760
|
+
return 0;
|
|
4761
|
+
}
|
|
4762
|
+
if (!isTape && zoom <= constants/* WAVEFORM_ZOOM_MIN */.LW) {
|
|
4710
4763
|
return 0;
|
|
4711
4764
|
}
|
|
4712
4765
|
return viewWidthPx / durationSec * zoom;
|
|
4713
4766
|
}
|
|
4714
4767
|
|
|
4768
|
+
/** Half-view empty space so t=0 and duration can sit under the center pin. */
|
|
4769
|
+
function getTapeGutterPx(widthPx) {
|
|
4770
|
+
return widthPx > 0 ? widthPx / 2 : 0;
|
|
4771
|
+
}
|
|
4772
|
+
|
|
4773
|
+
/** Tape first paint: 10s on screen, or 1× when the file is shorter than that. */
|
|
4774
|
+
function getTapeDefaultZoom(durationSec, maxZoom = constants/* WAVEFORM_ZOOM_MIN */.LW) {
|
|
4775
|
+
if (!(durationSec > 0)) {
|
|
4776
|
+
return constants/* WAVEFORM_ZOOM_MIN */.LW;
|
|
4777
|
+
}
|
|
4778
|
+
return clampWaveformZoom(durationSec / constants/* WAVEFORM_TAPE_DEFAULT_WINDOW_SEC */.Av, maxZoom);
|
|
4779
|
+
}
|
|
4780
|
+
|
|
4715
4781
|
/** Map zoom (1…max) onto the 0–100 slider. */
|
|
4716
4782
|
function sliderValueFromZoom(zoomLevel, maxZoom = constants/* WAVEFORM_ZOOM_MIN */.LW) {
|
|
4717
4783
|
const max = Math.max(constants/* WAVEFORM_ZOOM_MIN */.LW, maxZoom);
|
|
@@ -4732,9 +4798,15 @@ function zoomFromSliderValue(value, maxZoom = constants/* WAVEFORM_ZOOM_MIN */.L
|
|
|
4732
4798
|
return clampWaveformZoom(constants/* WAVEFORM_ZOOM_MIN */.LW + t * (max - constants/* WAVEFORM_ZOOM_MIN */.LW), max);
|
|
4733
4799
|
}
|
|
4734
4800
|
|
|
4735
|
-
/**
|
|
4801
|
+
/** One zoom-in/out button step on the 0–100 slider, mapped back to zoom. */
|
|
4802
|
+
function stepWaveformZoom(zoomLevel, maxZoom, sliderDelta) {
|
|
4803
|
+
return zoomFromSliderValue(Math.round(sliderValueFromZoom(zoomLevel, maxZoom)) + sliderDelta, maxZoom);
|
|
4804
|
+
}
|
|
4805
|
+
|
|
4806
|
+
/** Max scroll that still shows a full window (no overscroll). Gutters add empty lead/trail. */
|
|
4736
4807
|
function maxScrollLeft(viewport) {
|
|
4737
|
-
|
|
4808
|
+
const gutterPx = viewport.gutterPx || 0;
|
|
4809
|
+
return Math.max(0, viewport.durationSec * viewport.pixelsPerSecond + 2 * gutterPx - viewport.widthPx);
|
|
4738
4810
|
}
|
|
4739
4811
|
|
|
4740
4812
|
/** Scroll offset that still shows a full window (no overscroll). */
|
|
@@ -4747,7 +4819,7 @@ function clampScrollLeft(scrollLeftPx, viewport) {
|
|
|
4747
4819
|
|
|
4748
4820
|
/** Center this time in the view, clamped so the window still fills the canvas. */
|
|
4749
4821
|
function getCenteredScrollLeft(timeSec, viewport) {
|
|
4750
|
-
return clampScrollLeft(timeSec * viewport.pixelsPerSecond - viewport.widthPx / 2, viewport);
|
|
4822
|
+
return clampScrollLeft(timeSec * viewport.pixelsPerSecond + (viewport.gutterPx || 0) - viewport.widthPx / 2, viewport);
|
|
4751
4823
|
}
|
|
4752
4824
|
|
|
4753
4825
|
/**
|
|
@@ -4755,10 +4827,28 @@ function getCenteredScrollLeft(timeSec, viewport) {
|
|
|
4755
4827
|
* No-op at fit-to-width or when that time is already visible.
|
|
4756
4828
|
*/
|
|
4757
4829
|
function getSeekCameraAction({
|
|
4830
|
+
cameraMode = 'desktop',
|
|
4758
4831
|
timeSec,
|
|
4759
4832
|
viewport
|
|
4760
4833
|
}) {
|
|
4761
|
-
if (
|
|
4834
|
+
if (!(viewport.widthPx > 0) || !(viewport.pixelsPerSecond > 0)) {
|
|
4835
|
+
return {
|
|
4836
|
+
type: 'none'
|
|
4837
|
+
};
|
|
4838
|
+
}
|
|
4839
|
+
if (cameraMode === 'tape') {
|
|
4840
|
+
const scrollLeftPx = getCenteredScrollLeft(timeSec, viewport);
|
|
4841
|
+
if (Math.abs(scrollLeftPx - viewport.scrollLeftPx) < 1) {
|
|
4842
|
+
return {
|
|
4843
|
+
type: 'none'
|
|
4844
|
+
};
|
|
4845
|
+
}
|
|
4846
|
+
return {
|
|
4847
|
+
type: 'jump',
|
|
4848
|
+
scrollLeftPx
|
|
4849
|
+
};
|
|
4850
|
+
}
|
|
4851
|
+
if (viewport.zoomLevel <= constants/* WAVEFORM_ZOOM_MIN */.LW) {
|
|
4762
4852
|
return {
|
|
4763
4853
|
type: 'none'
|
|
4764
4854
|
};
|
|
@@ -4774,6 +4864,23 @@ function getSeekCameraAction({
|
|
|
4774
4864
|
};
|
|
4775
4865
|
}
|
|
4776
4866
|
|
|
4867
|
+
/** Always keep this time under the center pin. Reuses followRight so the camera hook can pin. */
|
|
4868
|
+
function getTapeCameraAction({
|
|
4869
|
+
timeSec,
|
|
4870
|
+
viewport
|
|
4871
|
+
}) {
|
|
4872
|
+
if (!(viewport.widthPx > 0) || !(viewport.pixelsPerSecond > 0)) {
|
|
4873
|
+
return {
|
|
4874
|
+
type: 'none'
|
|
4875
|
+
};
|
|
4876
|
+
}
|
|
4877
|
+
return {
|
|
4878
|
+
isPlayheadPinned: true,
|
|
4879
|
+
scrollLeftPx: getCenteredScrollLeft(timeSec, viewport),
|
|
4880
|
+
type: 'followRight'
|
|
4881
|
+
};
|
|
4882
|
+
}
|
|
4883
|
+
|
|
4777
4884
|
/** Follow inset in CSS px, capped at one third of the view so a narrow player still has room. */
|
|
4778
4885
|
function getFollowInsetPx(widthPx, insetPx = constants/* WAVEFORM_FOLLOW_INSET_PX */.NM) {
|
|
4779
4886
|
if (!(widthPx > 0)) {
|
|
@@ -4791,6 +4898,11 @@ function getPinnedPlayheadLeft(widthPx, insetPx = constants/* WAVEFORM_FOLLOW_IN
|
|
|
4791
4898
|
return `${(widthPx - inset) / widthPx * 100}%`;
|
|
4792
4899
|
}
|
|
4793
4900
|
|
|
4901
|
+
/** CSS left for a playhead locked to the center of the view. */
|
|
4902
|
+
function getTapePinnedPlayheadLeft() {
|
|
4903
|
+
return '50%';
|
|
4904
|
+
}
|
|
4905
|
+
|
|
4794
4906
|
/** CSS left % of the playhead from the left of the visible window. */
|
|
4795
4907
|
function timeLeftPercent(timeSec, durationSec, viewport) {
|
|
4796
4908
|
if (viewport.widthPx > 0 && viewport.pixelsPerSecond > 0) {
|
|
@@ -4805,12 +4917,19 @@ function timeLeftPercent(timeSec, durationSec, viewport) {
|
|
|
4805
4917
|
* Off-screen at play start jumps in; off-screen right while playing keeps following.
|
|
4806
4918
|
*/
|
|
4807
4919
|
function getPlayheadCameraAction({
|
|
4920
|
+
cameraMode = 'desktop',
|
|
4808
4921
|
insetPx = constants/* WAVEFORM_FOLLOW_INSET_PX */.NM,
|
|
4809
4922
|
isPlaying,
|
|
4810
4923
|
playJustStarted,
|
|
4811
4924
|
timeSec,
|
|
4812
4925
|
viewport
|
|
4813
4926
|
}) {
|
|
4927
|
+
if (cameraMode === 'tape') {
|
|
4928
|
+
return getTapeCameraAction({
|
|
4929
|
+
timeSec,
|
|
4930
|
+
viewport
|
|
4931
|
+
});
|
|
4932
|
+
}
|
|
4814
4933
|
if (!isPlaying || viewport.zoomLevel <= constants/* WAVEFORM_ZOOM_MIN */.LW || !(viewport.widthPx > 0) || !(viewport.pixelsPerSecond > 0)) {
|
|
4815
4934
|
return {
|
|
4816
4935
|
type: 'none'
|
|
@@ -4850,6 +4969,46 @@ function getPlayheadCameraAction({
|
|
|
4850
4969
|
type: 'none'
|
|
4851
4970
|
};
|
|
4852
4971
|
}
|
|
4972
|
+
;// ./src/lib/viewers/media/waveform/useTapeWaveform.ts
|
|
4973
|
+
|
|
4974
|
+
|
|
4975
|
+
function isIPadNavigator(tapeNavigator) {
|
|
4976
|
+
return /iPad/i.test(tapeNavigator.userAgent || '') || tapeNavigator.platform === 'MacIntel' && (tapeNavigator.maxTouchPoints || 0) > 1;
|
|
4977
|
+
}
|
|
4978
|
+
function isCoarsePrimaryPointer(tapeWindow) {
|
|
4979
|
+
return typeof tapeWindow.matchMedia === 'function' && tapeWindow.matchMedia(constants/* TAPE_POINTER_MEDIA_QUERY */.Le).matches;
|
|
4980
|
+
}
|
|
4981
|
+
|
|
4982
|
+
/**
|
|
4983
|
+
* Tape vs desktop camera: coarse primary pointer (finger) or iPad
|
|
4984
|
+
* (including iPadOS reporting itself as Mac). Not width, not hasTouch,
|
|
4985
|
+
* not Browser.isMobile().
|
|
4986
|
+
*/
|
|
4987
|
+
function isTapeWaveformInput(tapeWindow = window) {
|
|
4988
|
+
return isCoarsePrimaryPointer(tapeWindow) || isIPadNavigator(tapeWindow.navigator);
|
|
4989
|
+
}
|
|
4990
|
+
|
|
4991
|
+
/** Subscribe to the pointer media query; re-read the iPad heuristic on change. */
|
|
4992
|
+
function useTapeWaveform() {
|
|
4993
|
+
const [isTape, setIsTape] = (0,external_react_.useState)(() => typeof window !== 'undefined' && isTapeWaveformInput(window));
|
|
4994
|
+
(0,external_react_.useEffect)(() => {
|
|
4995
|
+
if (typeof window.matchMedia !== 'function') {
|
|
4996
|
+
setIsTape(isTapeWaveformInput(window));
|
|
4997
|
+
return undefined;
|
|
4998
|
+
}
|
|
4999
|
+
const mediaQuery = window.matchMedia(constants/* TAPE_POINTER_MEDIA_QUERY */.Le);
|
|
5000
|
+
const sync = () => {
|
|
5001
|
+
setIsTape(isTapeWaveformInput(window));
|
|
5002
|
+
};
|
|
5003
|
+
sync();
|
|
5004
|
+
mediaQuery.addEventListener('change', sync);
|
|
5005
|
+
return () => mediaQuery.removeEventListener('change', sync);
|
|
5006
|
+
}, []);
|
|
5007
|
+
return isTape;
|
|
5008
|
+
}
|
|
5009
|
+
// EXTERNAL MODULE: ./node_modules/classnames/index.js
|
|
5010
|
+
var classnames = __webpack_require__(2485);
|
|
5011
|
+
var classnames_default = /*#__PURE__*/__webpack_require__.n(classnames);
|
|
4853
5012
|
// EXTERNAL MODULE: ./src/lib/viewers/controls/media/markers/helpers/useDismissableMarkerSelection.ts
|
|
4854
5013
|
var useDismissableMarkerSelection = __webpack_require__(2378);
|
|
4855
5014
|
// EXTERNAL MODULE: ./src/lib/viewers/controls/media/markers/helpers/buildClusters.ts
|
|
@@ -4869,6 +5028,7 @@ var utils = __webpack_require__(5346);
|
|
|
4869
5028
|
|
|
4870
5029
|
|
|
4871
5030
|
|
|
5031
|
+
|
|
4872
5032
|
const WAVEFORM_MARKER_SIZE_PX = 20;
|
|
4873
5033
|
function hasMappedWindow(viewport) {
|
|
4874
5034
|
return !!viewport && Number.isFinite(viewport.startSec) && viewport.endSec > viewport.startSec;
|
|
@@ -4907,11 +5067,12 @@ function clustersByExactTime(markers, durationSec) {
|
|
|
4907
5067
|
function WaveformCommentMarkers({
|
|
4908
5068
|
commentMarkers,
|
|
4909
5069
|
durationSec,
|
|
5070
|
+
isTape = false,
|
|
4910
5071
|
onCommentMarkerClick,
|
|
4911
5072
|
selectedId: hostSelectedId = null,
|
|
4912
5073
|
viewport = null
|
|
4913
5074
|
}) {
|
|
4914
|
-
const trackRef = (0,external_react_.useRef)(null);
|
|
5075
|
+
const trackRef = (0,external_react_.useRef)(null); // width source for clustering overlapping badges
|
|
4915
5076
|
const {
|
|
4916
5077
|
containerRef,
|
|
4917
5078
|
selectMarker,
|
|
@@ -4920,7 +5081,7 @@ function WaveformCommentMarkers({
|
|
|
4920
5081
|
const [trackWidth, setTrackWidth] = (0,external_react_.useState)(0);
|
|
4921
5082
|
const canShowTrack = durationSec > 0 && commentMarkers.length > 0;
|
|
4922
5083
|
const zoomLevel = viewport?.zoomLevel ?? constants/* WAVEFORM_ZOOM_MIN */.LW;
|
|
4923
|
-
const
|
|
5084
|
+
const alignsMarkersToVisibleWindow = hasMappedWindow(viewport) && (viewport.zoomLevel > constants/* WAVEFORM_ZOOM_MIN */.LW || isTape);
|
|
4924
5085
|
(0,external_react_.useLayoutEffect)(() => {
|
|
4925
5086
|
if (!canShowTrack) {
|
|
4926
5087
|
setTrackWidth(0);
|
|
@@ -4956,7 +5117,10 @@ function WaveformCommentMarkers({
|
|
|
4956
5117
|
}
|
|
4957
5118
|
return /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
4958
5119
|
ref: containerRef,
|
|
4959
|
-
className:
|
|
5120
|
+
className: classnames_default()('bp-WaveformCommentMarkers', {
|
|
5121
|
+
'bp-WaveformCommentMarkers--tape': isTape,
|
|
5122
|
+
'bp-WaveformCommentMarkers--zoomed': alignsMarkersToVisibleWindow
|
|
5123
|
+
}),
|
|
4960
5124
|
"data-testid": "bp-waveform-comment-markers"
|
|
4961
5125
|
}, /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
4962
5126
|
ref: trackRef,
|
|
@@ -4965,7 +5129,10 @@ function WaveformCommentMarkers({
|
|
|
4965
5129
|
const marker = cluster.markers[0];
|
|
4966
5130
|
const isGroup = cluster.markers.length > 1;
|
|
4967
5131
|
const isSelected = cluster.markers.some(entry => entry.id === selectedId);
|
|
4968
|
-
const className =
|
|
5132
|
+
const className = classnames_default()('bp-WaveformCommentMarkers-marker', {
|
|
5133
|
+
'bp-WaveformCommentMarkers-marker--group': isGroup,
|
|
5134
|
+
'bp-WaveformCommentMarkers-marker--selected': isSelected
|
|
5135
|
+
});
|
|
4969
5136
|
const left = `${markerLeftPercent(marker.time, durationSec, viewport)}%`;
|
|
4970
5137
|
if (isGroup) {
|
|
4971
5138
|
return /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
@@ -5003,6 +5170,8 @@ function WaveformCommentMarkers({
|
|
|
5003
5170
|
}));
|
|
5004
5171
|
})));
|
|
5005
5172
|
}
|
|
5173
|
+
;// external "react-dom"
|
|
5174
|
+
|
|
5006
5175
|
;// ./node_modules/wavesurfer.js/dist/wavesurfer.esm.js
|
|
5007
5176
|
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
5177
|
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 +5256,86 @@ function getBufferedProgress(bufferedRange, durationSec) {
|
|
|
5087
5256
|
return clampTo0And1(bufferedRange.end(bufferedRange.length - 1) / durationSec);
|
|
5088
5257
|
}
|
|
5089
5258
|
|
|
5259
|
+
/** Played bars: rest token on desktop, hover-played (brightest) on tape. Tape never uses hover or buffer fills. */
|
|
5260
|
+
function getPlayedWaveformColor(isTape = false) {
|
|
5261
|
+
return isTape ? WAVEFORM_COLOR_HOVER_PLAYED : WAVEFORM_COLOR_PLAYED;
|
|
5262
|
+
}
|
|
5263
|
+
function rangeFills({
|
|
5264
|
+
buffer,
|
|
5265
|
+
hover,
|
|
5266
|
+
rangeEnd,
|
|
5267
|
+
rangeStart
|
|
5268
|
+
}) {
|
|
5269
|
+
const start = clampTo0And1(rangeStart);
|
|
5270
|
+
const end = clampTo0And1(rangeEnd);
|
|
5271
|
+
const hoverInside = hover != null && hover > start && hover < end;
|
|
5272
|
+
const outsideAfter = [{
|
|
5273
|
+
color: WAVEFORM_COLOR_UNPLAYED,
|
|
5274
|
+
end: Math.max(end, buffer),
|
|
5275
|
+
start: end
|
|
5276
|
+
}, {
|
|
5277
|
+
color: WAVEFORM_COLOR_BUFFER,
|
|
5278
|
+
end: 1,
|
|
5279
|
+
start: Math.max(end, buffer)
|
|
5280
|
+
}];
|
|
5281
|
+
const ranges = hoverInside ? [{
|
|
5282
|
+
color: WAVEFORM_COLOR_UNPLAYED,
|
|
5283
|
+
end: start,
|
|
5284
|
+
start: 0
|
|
5285
|
+
}, {
|
|
5286
|
+
color: WAVEFORM_COLOR_HOVER_PLAYED,
|
|
5287
|
+
end: hover,
|
|
5288
|
+
start
|
|
5289
|
+
}, {
|
|
5290
|
+
color: WAVEFORM_COLOR_HOVER_AREA,
|
|
5291
|
+
end,
|
|
5292
|
+
start: hover
|
|
5293
|
+
}, ...outsideAfter] : [{
|
|
5294
|
+
color: WAVEFORM_COLOR_UNPLAYED,
|
|
5295
|
+
end: start,
|
|
5296
|
+
start: 0
|
|
5297
|
+
}, {
|
|
5298
|
+
color: WAVEFORM_COLOR_PLAYED,
|
|
5299
|
+
end,
|
|
5300
|
+
start
|
|
5301
|
+
}, ...outsideAfter];
|
|
5302
|
+
const fill = gradientStopsFromColorRanges(ranges);
|
|
5303
|
+
return {
|
|
5304
|
+
progressColor: fill,
|
|
5305
|
+
waveColor: fill
|
|
5306
|
+
};
|
|
5307
|
+
}
|
|
5308
|
+
|
|
5090
5309
|
/**
|
|
5091
5310
|
* progressColor paints left of the playhead (clipped by wavesurfer).
|
|
5092
5311
|
* waveColor paints right of the playhead, including buffered vs not-yet-buffered.
|
|
5312
|
+
* An open comment range replaces the played/unplayed split with in-range / out-of-range.
|
|
5093
5313
|
*/
|
|
5094
5314
|
function getWaveformFills({
|
|
5095
5315
|
bufferProgress,
|
|
5096
|
-
hoverProgress
|
|
5316
|
+
hoverProgress,
|
|
5317
|
+
isTape = false,
|
|
5318
|
+
rangeProgress
|
|
5097
5319
|
}) {
|
|
5098
5320
|
const buffer = clampTo0And1(bufferProgress);
|
|
5321
|
+
const playedColor = getPlayedWaveformColor(isTape);
|
|
5322
|
+
if (isTape) {
|
|
5323
|
+
return {
|
|
5324
|
+
progressColor: playedColor,
|
|
5325
|
+
waveColor: WAVEFORM_COLOR_UNPLAYED
|
|
5326
|
+
};
|
|
5327
|
+
}
|
|
5328
|
+
if (rangeProgress && rangeProgress.end > rangeProgress.start) {
|
|
5329
|
+
return rangeFills({
|
|
5330
|
+
buffer,
|
|
5331
|
+
hover: hoverProgress == null ? null : clampTo0And1(hoverProgress),
|
|
5332
|
+
rangeEnd: rangeProgress.end,
|
|
5333
|
+
rangeStart: rangeProgress.start
|
|
5334
|
+
});
|
|
5335
|
+
}
|
|
5099
5336
|
if (hoverProgress == null) {
|
|
5100
5337
|
return {
|
|
5101
|
-
progressColor:
|
|
5338
|
+
progressColor: playedColor,
|
|
5102
5339
|
waveColor: gradientStopsFromColorRanges([{
|
|
5103
5340
|
color: WAVEFORM_COLOR_UNPLAYED,
|
|
5104
5341
|
end: buffer,
|
|
@@ -5259,6 +5496,200 @@ function tintWaveformTiles({
|
|
|
5259
5496
|
});
|
|
5260
5497
|
});
|
|
5261
5498
|
}
|
|
5499
|
+
;// ./src/lib/viewers/media/waveform/range.ts
|
|
5500
|
+
|
|
5501
|
+
|
|
5502
|
+
function clampToRange(value, min, max) {
|
|
5503
|
+
if (!Number.isFinite(value)) {
|
|
5504
|
+
return min;
|
|
5505
|
+
}
|
|
5506
|
+
return Math.min(max, Math.max(min, value));
|
|
5507
|
+
}
|
|
5508
|
+
|
|
5509
|
+
/** Integer ms in `[0, durationMs]`. */
|
|
5510
|
+
function clampTimeMs(timeMs, durationMs) {
|
|
5511
|
+
const duration = Math.max(0, durationMs);
|
|
5512
|
+
return Math.round(clampToRange(timeMs, 0, duration));
|
|
5513
|
+
}
|
|
5514
|
+
function durationMsFromSec(durationSec) {
|
|
5515
|
+
if (!Number.isFinite(durationSec) || durationSec <= 0) {
|
|
5516
|
+
return 0;
|
|
5517
|
+
}
|
|
5518
|
+
return Math.round(durationSec * 1000);
|
|
5519
|
+
}
|
|
5520
|
+
function isRangeCollapsed(range) {
|
|
5521
|
+
return !range || range.endMs == null || range.endMs <= range.startMs;
|
|
5522
|
+
}
|
|
5523
|
+
|
|
5524
|
+
/** Clamp both edges onto the file. Collapsed drafts stay a point. */
|
|
5525
|
+
function resolveRange(range, durationMs) {
|
|
5526
|
+
const startMs = clampTimeMs(range.startMs, durationMs);
|
|
5527
|
+
if (range.endMs == null) {
|
|
5528
|
+
return {
|
|
5529
|
+
endMs: startMs,
|
|
5530
|
+
startMs
|
|
5531
|
+
};
|
|
5532
|
+
}
|
|
5533
|
+
const endMs = clampTimeMs(range.endMs, durationMs);
|
|
5534
|
+
if (endMs <= startMs) {
|
|
5535
|
+
return {
|
|
5536
|
+
endMs: startMs,
|
|
5537
|
+
startMs
|
|
5538
|
+
};
|
|
5539
|
+
}
|
|
5540
|
+
return {
|
|
5541
|
+
endMs,
|
|
5542
|
+
startMs
|
|
5543
|
+
};
|
|
5544
|
+
}
|
|
5545
|
+
|
|
5546
|
+
/**
|
|
5547
|
+
* Which handle should receive this pointer. Overlapping hit areas (collapsed or
|
|
5548
|
+
* a span narrower than the 24px target) split at the midpoint so each edge stays reachable.
|
|
5549
|
+
*/
|
|
5550
|
+
function pickRangeHandle({
|
|
5551
|
+
endX,
|
|
5552
|
+
pointerX,
|
|
5553
|
+
startX
|
|
5554
|
+
}) {
|
|
5555
|
+
const mid = (startX + endX) / 2;
|
|
5556
|
+
if (!Number.isFinite(mid)) {
|
|
5557
|
+
return 'end';
|
|
5558
|
+
}
|
|
5559
|
+
return pointerX < mid ? 'start' : 'end';
|
|
5560
|
+
}
|
|
5561
|
+
|
|
5562
|
+
/** Screen x of a handle. Collapsed drafts sit 1px left/right of the playhead, not on it. */
|
|
5563
|
+
function visualRangeHandlePx({
|
|
5564
|
+
handle,
|
|
5565
|
+
range,
|
|
5566
|
+
viewport
|
|
5567
|
+
}) {
|
|
5568
|
+
const timeSec = (handle === 'start' ? range.startMs : range.endMs) / 1000;
|
|
5569
|
+
const x = positionPxFromTime(timeSec, viewport);
|
|
5570
|
+
if (range.startMs !== range.endMs) {
|
|
5571
|
+
return x;
|
|
5572
|
+
}
|
|
5573
|
+
return handle === 'start' ? x - constants/* WAVEFORM_RANGE_COLLAPSED_OFFSET_PX */.BG : x + constants/* WAVEFORM_RANGE_COLLAPSED_OFFSET_PX */.BG;
|
|
5574
|
+
}
|
|
5575
|
+
|
|
5576
|
+
/** True when the pointer is over the range rectangle or its handle hit targets. */
|
|
5577
|
+
function isPointerOverRange({
|
|
5578
|
+
pointerX,
|
|
5579
|
+
range,
|
|
5580
|
+
viewport
|
|
5581
|
+
}) {
|
|
5582
|
+
const resolved = resolveRange(range, durationMsFromSec(viewport.durationSec));
|
|
5583
|
+
const startX = visualRangeHandlePx({
|
|
5584
|
+
handle: 'start',
|
|
5585
|
+
range: resolved,
|
|
5586
|
+
viewport
|
|
5587
|
+
});
|
|
5588
|
+
const endX = visualRangeHandlePx({
|
|
5589
|
+
handle: 'end',
|
|
5590
|
+
range: resolved,
|
|
5591
|
+
viewport
|
|
5592
|
+
});
|
|
5593
|
+
const pad = constants/* WAVEFORM_RANGE_HIT_AREA_PX */.r0 / 2;
|
|
5594
|
+
return pointerX >= Math.min(startX, endX) - pad && pointerX <= Math.max(startX, endX) + pad;
|
|
5595
|
+
}
|
|
5596
|
+
|
|
5597
|
+
/** Snap to the playhead when the pointer is within `WAVEFORM_RANGE_SNAP_PX`. */
|
|
5598
|
+
function snapTimeMs({
|
|
5599
|
+
pixelsPerSecond,
|
|
5600
|
+
playheadMs,
|
|
5601
|
+
timeMs
|
|
5602
|
+
}) {
|
|
5603
|
+
if (!(pixelsPerSecond > 0) || !Number.isFinite(playheadMs)) {
|
|
5604
|
+
return timeMs;
|
|
5605
|
+
}
|
|
5606
|
+
const deltaPx = Math.abs(timeMs - playheadMs) / 1000 * pixelsPerSecond;
|
|
5607
|
+
if (deltaPx <= constants/* WAVEFORM_RANGE_SNAP_PX */.IQ) {
|
|
5608
|
+
return Math.round(playheadMs);
|
|
5609
|
+
}
|
|
5610
|
+
return timeMs;
|
|
5611
|
+
}
|
|
5612
|
+
|
|
5613
|
+
/**
|
|
5614
|
+
* Move one edge. Crossing the other edge swaps roles so a collapsed pair can
|
|
5615
|
+
* expand in either direction. Enforces `[0, duration]` and the minimum span
|
|
5616
|
+
* once the drag has actually opened a range. An already-open range stays a
|
|
5617
|
+
* span — snapping one edge onto the other clamps to the minimum duration.
|
|
5618
|
+
*/
|
|
5619
|
+
function dragRangeHandle({
|
|
5620
|
+
durationMs,
|
|
5621
|
+
handle,
|
|
5622
|
+
pointerMs,
|
|
5623
|
+
range
|
|
5624
|
+
}) {
|
|
5625
|
+
const duration = Math.max(0, durationMs);
|
|
5626
|
+
const pointer = clampTimeMs(pointerMs, duration);
|
|
5627
|
+
let {
|
|
5628
|
+
startMs,
|
|
5629
|
+
endMs
|
|
5630
|
+
} = range;
|
|
5631
|
+
let nextHandle = handle;
|
|
5632
|
+
if (handle === 'start') {
|
|
5633
|
+
if (pointer > endMs) {
|
|
5634
|
+
startMs = endMs;
|
|
5635
|
+
endMs = pointer;
|
|
5636
|
+
nextHandle = 'end';
|
|
5637
|
+
} else {
|
|
5638
|
+
startMs = pointer;
|
|
5639
|
+
}
|
|
5640
|
+
} else if (pointer < startMs) {
|
|
5641
|
+
endMs = startMs;
|
|
5642
|
+
startMs = pointer;
|
|
5643
|
+
nextHandle = 'start';
|
|
5644
|
+
} else {
|
|
5645
|
+
endMs = pointer;
|
|
5646
|
+
}
|
|
5647
|
+
const wasOpen = range.startMs !== range.endMs;
|
|
5648
|
+
const opened = wasOpen || startMs !== endMs;
|
|
5649
|
+
if (opened && endMs - startMs < constants/* WAVEFORM_RANGE_MIN_DURATION_MS */.bX) {
|
|
5650
|
+
if (nextHandle === 'end') {
|
|
5651
|
+
endMs = clampTimeMs(startMs + constants/* WAVEFORM_RANGE_MIN_DURATION_MS */.bX, duration);
|
|
5652
|
+
if (endMs - startMs < constants/* WAVEFORM_RANGE_MIN_DURATION_MS */.bX) {
|
|
5653
|
+
startMs = clampTimeMs(endMs - constants/* WAVEFORM_RANGE_MIN_DURATION_MS */.bX, duration);
|
|
5654
|
+
}
|
|
5655
|
+
} else {
|
|
5656
|
+
startMs = clampTimeMs(endMs - constants/* WAVEFORM_RANGE_MIN_DURATION_MS */.bX, duration);
|
|
5657
|
+
if (endMs - startMs < constants/* WAVEFORM_RANGE_MIN_DURATION_MS */.bX) {
|
|
5658
|
+
endMs = clampTimeMs(startMs + constants/* WAVEFORM_RANGE_MIN_DURATION_MS */.bX, duration);
|
|
5659
|
+
}
|
|
5660
|
+
}
|
|
5661
|
+
}
|
|
5662
|
+
return {
|
|
5663
|
+
handle: nextHandle,
|
|
5664
|
+
range: {
|
|
5665
|
+
endMs,
|
|
5666
|
+
startMs
|
|
5667
|
+
}
|
|
5668
|
+
};
|
|
5669
|
+
}
|
|
5670
|
+
function pointerTimeMs(pointerX, viewport) {
|
|
5671
|
+
return Math.round(timeFromPositionPx(pointerX, viewport) * 1000);
|
|
5672
|
+
}
|
|
5673
|
+
|
|
5674
|
+
/** Sidebar payload after mouseup. Null when the draft is still a single timestamp. */
|
|
5675
|
+
function commitRangeChange(range) {
|
|
5676
|
+
if (range.endMs <= range.startMs) {
|
|
5677
|
+
return null;
|
|
5678
|
+
}
|
|
5679
|
+
return {
|
|
5680
|
+
endMs: range.endMs,
|
|
5681
|
+
startMs: range.startMs
|
|
5682
|
+
};
|
|
5683
|
+
}
|
|
5684
|
+
function rangeProgress(range, durationMs) {
|
|
5685
|
+
if (!(durationMs > 0) || range.endMs <= range.startMs) {
|
|
5686
|
+
return null;
|
|
5687
|
+
}
|
|
5688
|
+
return {
|
|
5689
|
+
end: range.endMs / durationMs,
|
|
5690
|
+
start: range.startMs / durationMs
|
|
5691
|
+
};
|
|
5692
|
+
}
|
|
5262
5693
|
;// ./src/lib/viewers/media/waveform/usePlayheadCamera.ts
|
|
5263
5694
|
|
|
5264
5695
|
|
|
@@ -5275,6 +5706,7 @@ function prefersReducedMotion() {
|
|
|
5275
5706
|
* every frame. WaveformView owns WaveSurfer, zoom, and the media rAF loop.
|
|
5276
5707
|
*/
|
|
5277
5708
|
function usePlayheadCamera({
|
|
5709
|
+
cameraMode = 'desktop',
|
|
5278
5710
|
mediaElRef,
|
|
5279
5711
|
onViewportCommit,
|
|
5280
5712
|
playheadRef,
|
|
@@ -5283,6 +5715,8 @@ function usePlayheadCamera({
|
|
|
5283
5715
|
}) {
|
|
5284
5716
|
const onViewportCommitRef = (0,external_react_.useRef)(onViewportCommit);
|
|
5285
5717
|
onViewportCommitRef.current = onViewportCommit;
|
|
5718
|
+
const cameraModeRef = (0,external_react_.useRef)(cameraMode);
|
|
5719
|
+
cameraModeRef.current = cameraMode;
|
|
5286
5720
|
const programmaticScrollRef = (0,external_react_.useRef)(false);
|
|
5287
5721
|
const jumpAnimationRef = (0,external_react_.useRef)(0);
|
|
5288
5722
|
const lastCameraScrollRef = (0,external_react_.useRef)(null);
|
|
@@ -5293,6 +5727,8 @@ function usePlayheadCamera({
|
|
|
5293
5727
|
const scrollSettleTimerRef = (0,external_react_.useRef)(0);
|
|
5294
5728
|
const applyRef = (0,external_react_.useRef)(null);
|
|
5295
5729
|
const isFollowPinned = (0,external_react_.useCallback)(() => isFollowPinnedRef.current, []);
|
|
5730
|
+
const isUserPanning = (0,external_react_.useCallback)(() => userIsScrollingRef.current, []);
|
|
5731
|
+
const isTape = (0,external_react_.useCallback)(() => cameraModeRef.current === 'tape', []);
|
|
5296
5732
|
const cancelJump = (0,external_react_.useCallback)(() => {
|
|
5297
5733
|
if (!jumpAnimationRef.current) {
|
|
5298
5734
|
return;
|
|
@@ -5321,15 +5757,22 @@ function usePlayheadCamera({
|
|
|
5321
5757
|
const onSeek = (0,external_react_.useCallback)(timeSec => {
|
|
5322
5758
|
mediaTimeRef.current = timeSec;
|
|
5323
5759
|
cancelJump();
|
|
5324
|
-
|
|
5325
|
-
|
|
5760
|
+
if (!isTape()) {
|
|
5761
|
+
clearFollowPin();
|
|
5762
|
+
}
|
|
5763
|
+
}, [cancelJump, clearFollowPin, isTape]);
|
|
5326
5764
|
|
|
5327
5765
|
/** Unpin and hold follow so zoom setScroll (slider center or pinch origin) is not stolen. */
|
|
5328
5766
|
const onZoom = (0,external_react_.useCallback)(() => {
|
|
5329
5767
|
cancelJump();
|
|
5768
|
+
if (isTape()) {
|
|
5769
|
+
isFollowPinnedRef.current = true;
|
|
5770
|
+
holdFollowUntilInsetRef.current = false;
|
|
5771
|
+
return;
|
|
5772
|
+
}
|
|
5330
5773
|
isFollowPinnedRef.current = false;
|
|
5331
5774
|
holdFollowUntilInsetRef.current = true;
|
|
5332
|
-
}, [cancelJump]);
|
|
5775
|
+
}, [cancelJump, isTape]);
|
|
5333
5776
|
const applyScrollLeft = (0,external_react_.useCallback)((scrollLeftPx, shouldCommitState) => {
|
|
5334
5777
|
const wavesurfer = wavesurferRef.current;
|
|
5335
5778
|
if (!wavesurfer || !wavesurfer.setScroll) {
|
|
@@ -5357,8 +5800,8 @@ function usePlayheadCamera({
|
|
|
5357
5800
|
if (!playhead || !isPinned || !(viewport.widthPx > 0)) {
|
|
5358
5801
|
return;
|
|
5359
5802
|
}
|
|
5360
|
-
playhead.style.left = getPinnedPlayheadLeft(viewport.widthPx);
|
|
5361
|
-
}, []);
|
|
5803
|
+
playhead.style.left = isTape() ? getTapePinnedPlayheadLeft() : getPinnedPlayheadLeft(viewport.widthPx);
|
|
5804
|
+
}, [isTape]);
|
|
5362
5805
|
const apply = (0,external_react_.useCallback)((timeSec, playJustStarted = false) => {
|
|
5363
5806
|
mediaTimeRef.current = timeSec;
|
|
5364
5807
|
const wavesurfer = wavesurferRef.current;
|
|
@@ -5366,7 +5809,7 @@ function usePlayheadCamera({
|
|
|
5366
5809
|
if (!wavesurfer) {
|
|
5367
5810
|
return;
|
|
5368
5811
|
}
|
|
5369
|
-
if (viewport.zoomLevel <= constants/* WAVEFORM_ZOOM_MIN */.LW) {
|
|
5812
|
+
if (!isTape() && viewport.zoomLevel <= constants/* WAVEFORM_ZOOM_MIN */.LW) {
|
|
5370
5813
|
clearFollowPin();
|
|
5371
5814
|
return;
|
|
5372
5815
|
}
|
|
@@ -5378,12 +5821,13 @@ function usePlayheadCamera({
|
|
|
5378
5821
|
}
|
|
5379
5822
|
const liveViewport = getViewportAtScroll(viewport, getScrollLeft(wavesurfer, viewport.scrollLeftPx));
|
|
5380
5823
|
const action = getPlayheadCameraAction({
|
|
5824
|
+
cameraMode: cameraModeRef.current,
|
|
5381
5825
|
isPlaying: true,
|
|
5382
5826
|
playJustStarted,
|
|
5383
5827
|
timeSec,
|
|
5384
5828
|
viewport: liveViewport
|
|
5385
5829
|
});
|
|
5386
|
-
if (holdFollowUntilInsetRef.current && !playJustStarted) {
|
|
5830
|
+
if (!isTape() && holdFollowUntilInsetRef.current && !playJustStarted) {
|
|
5387
5831
|
if (action.type !== 'none') {
|
|
5388
5832
|
return;
|
|
5389
5833
|
}
|
|
@@ -5415,6 +5859,7 @@ function usePlayheadCamera({
|
|
|
5415
5859
|
const tick = now => {
|
|
5416
5860
|
const t = Math.min(1, (now - start) / constants/* WAVEFORM_PLAYHEAD_JUMP_MS */.Bq);
|
|
5417
5861
|
const liveAction = getPlayheadCameraAction({
|
|
5862
|
+
cameraMode: cameraModeRef.current,
|
|
5418
5863
|
isPlaying: true,
|
|
5419
5864
|
playJustStarted: true,
|
|
5420
5865
|
timeSec: mediaTimeRef.current,
|
|
@@ -5431,7 +5876,7 @@ function usePlayheadCamera({
|
|
|
5431
5876
|
apply(mediaTimeRef.current, false);
|
|
5432
5877
|
};
|
|
5433
5878
|
jumpAnimationRef.current = window.requestAnimationFrame(tick);
|
|
5434
|
-
}, [applyScrollLeft, cancelJump, clearFollowPin, pinFollowPlayhead, playheadRef, viewportRef, wavesurferRef]);
|
|
5879
|
+
}, [applyScrollLeft, cancelJump, clearFollowPin, isTape, pinFollowPlayhead, playheadRef, viewportRef, wavesurferRef]);
|
|
5435
5880
|
applyRef.current = apply;
|
|
5436
5881
|
|
|
5437
5882
|
/**
|
|
@@ -5454,9 +5899,12 @@ function usePlayheadCamera({
|
|
|
5454
5899
|
}
|
|
5455
5900
|
releaseUserPanHold();
|
|
5456
5901
|
cancelJump();
|
|
5457
|
-
|
|
5902
|
+
if (!isTape()) {
|
|
5903
|
+
isFollowPinnedRef.current = false;
|
|
5904
|
+
}
|
|
5458
5905
|
const liveViewport = getViewportAtScroll(viewportRef.current, getScrollLeft(wavesurfer, viewportRef.current.scrollLeftPx));
|
|
5459
5906
|
const action = getSeekCameraAction({
|
|
5907
|
+
cameraMode: cameraModeRef.current,
|
|
5460
5908
|
timeSec,
|
|
5461
5909
|
viewport: liveViewport
|
|
5462
5910
|
});
|
|
@@ -5476,7 +5924,7 @@ function usePlayheadCamera({
|
|
|
5476
5924
|
applyScrollLeft(from + (to - from) * (1 - (1 - t) * (1 - t)), false);
|
|
5477
5925
|
const playhead = playheadRef.current;
|
|
5478
5926
|
if (playhead) {
|
|
5479
|
-
playhead.style.left = timeLeftPercent(mediaTimeRef.current, viewportRef.current.durationSec, viewportRef.current);
|
|
5927
|
+
playhead.style.left = isTape() ? getTapePinnedPlayheadLeft() : timeLeftPercent(mediaTimeRef.current, viewportRef.current.durationSec, viewportRef.current);
|
|
5480
5928
|
}
|
|
5481
5929
|
if (t < 1) {
|
|
5482
5930
|
jumpAnimationRef.current = window.requestAnimationFrame(tick);
|
|
@@ -5486,7 +5934,7 @@ function usePlayheadCamera({
|
|
|
5486
5934
|
applyScrollLeft(to, true);
|
|
5487
5935
|
};
|
|
5488
5936
|
jumpAnimationRef.current = window.requestAnimationFrame(tick);
|
|
5489
|
-
}, [applyScrollLeft, cancelJump, playheadRef, releaseUserPanHold, viewportRef, wavesurferRef]);
|
|
5937
|
+
}, [applyScrollLeft, cancelJump, isTape, playheadRef, releaseUserPanHold, viewportRef, wavesurferRef]);
|
|
5490
5938
|
const handleScroll = (0,external_react_.useCallback)(onUserPan => {
|
|
5491
5939
|
const wavesurfer = wavesurferRef.current;
|
|
5492
5940
|
if (!wavesurfer) {
|
|
@@ -5498,8 +5946,28 @@ function usePlayheadCamera({
|
|
|
5498
5946
|
return;
|
|
5499
5947
|
}
|
|
5500
5948
|
viewportRef.current = getViewportAtScroll(viewportRef.current, scrollLeftPx);
|
|
5501
|
-
const timeSec = readMediaTime();
|
|
5502
5949
|
const playhead = playheadRef.current;
|
|
5950
|
+
if (isTape()) {
|
|
5951
|
+
if (playhead) {
|
|
5952
|
+
playhead.style.left = getTapePinnedPlayheadLeft();
|
|
5953
|
+
}
|
|
5954
|
+
const pinTimeSec = Math.min(viewportRef.current.durationSec, Math.max(0, timeFromPositionPx(viewportRef.current.widthPx / 2, viewportRef.current)));
|
|
5955
|
+
userIsScrollingRef.current = true;
|
|
5956
|
+
window.clearTimeout(scrollSettleTimerRef.current);
|
|
5957
|
+
scrollSettleTimerRef.current = window.setTimeout(() => {
|
|
5958
|
+
userIsScrollingRef.current = false;
|
|
5959
|
+
scrollSettleTimerRef.current = 0;
|
|
5960
|
+
if (!mediaElRef.current || mediaElRef.current.paused) {
|
|
5961
|
+
return;
|
|
5962
|
+
}
|
|
5963
|
+
applyRef.current?.(readMediaTime(), false);
|
|
5964
|
+
}, constants/* WAVEFORM_FOLLOW_SCROLL_SETTLE_MS */.Zs);
|
|
5965
|
+
cancelJump();
|
|
5966
|
+
programmaticScrollRef.current = false;
|
|
5967
|
+
onUserPan(pinTimeSec);
|
|
5968
|
+
return;
|
|
5969
|
+
}
|
|
5970
|
+
const timeSec = readMediaTime();
|
|
5503
5971
|
if (playhead) {
|
|
5504
5972
|
playhead.style.left = timeLeftPercent(timeSec, viewportRef.current.durationSec, viewportRef.current);
|
|
5505
5973
|
}
|
|
@@ -5518,7 +5986,7 @@ function usePlayheadCamera({
|
|
|
5518
5986
|
isFollowPinnedRef.current = false;
|
|
5519
5987
|
programmaticScrollRef.current = false;
|
|
5520
5988
|
onUserPan(timeSec);
|
|
5521
|
-
}, [cancelJump, isUserPan, mediaElRef, playheadRef, readMediaTime, viewportRef, wavesurferRef]);
|
|
5989
|
+
}, [cancelJump, isTape, isUserPan, mediaElRef, playheadRef, readMediaTime, viewportRef, wavesurferRef]);
|
|
5522
5990
|
(0,external_react_.useEffect)(() => () => {
|
|
5523
5991
|
releaseUserPanHold();
|
|
5524
5992
|
cancelJump();
|
|
@@ -5530,12 +5998,314 @@ function usePlayheadCamera({
|
|
|
5530
5998
|
clearFollowPin,
|
|
5531
5999
|
handleScroll,
|
|
5532
6000
|
isFollowPinned,
|
|
6001
|
+
isUserPanning,
|
|
5533
6002
|
onSeek,
|
|
5534
6003
|
onZoom,
|
|
5535
6004
|
releaseUserPanHold,
|
|
5536
6005
|
seekTo
|
|
5537
6006
|
};
|
|
5538
6007
|
}
|
|
6008
|
+
;// ./src/lib/viewers/media/waveform/WaveformRangeSelection.scss
|
|
6009
|
+
// extracted by mini-css-extract-plugin
|
|
6010
|
+
|
|
6011
|
+
;// ./src/lib/viewers/media/waveform/WaveformRangeSelection.tsx
|
|
6012
|
+
|
|
6013
|
+
|
|
6014
|
+
|
|
6015
|
+
|
|
6016
|
+
|
|
6017
|
+
|
|
6018
|
+
function offsetLeftCss(base, offsetPx) {
|
|
6019
|
+
if (!offsetPx) {
|
|
6020
|
+
return base;
|
|
6021
|
+
}
|
|
6022
|
+
const op = offsetPx < 0 ? '-' : '+';
|
|
6023
|
+
return `calc(${base} ${op} ${Math.abs(offsetPx)}px)`;
|
|
6024
|
+
}
|
|
6025
|
+
function applyHandleLeft(el, timeSec, durationSec, viewport, collapsedOffsetPx = 0) {
|
|
6026
|
+
if (!el) {
|
|
6027
|
+
return;
|
|
6028
|
+
}
|
|
6029
|
+
el.style.left = offsetLeftCss(timeLeftPercent(timeSec, durationSec, viewport), collapsedOffsetPx);
|
|
6030
|
+
}
|
|
6031
|
+
function applyRegion(el, startSec, endSec, durationSec, viewport, collapsed) {
|
|
6032
|
+
if (!el) {
|
|
6033
|
+
return;
|
|
6034
|
+
}
|
|
6035
|
+
const start = timeLeftPercent(startSec, durationSec, viewport);
|
|
6036
|
+
const halfLine = constants/* WAVEFORM_RANGE_HANDLE_LINE_PX */.h1 / 2;
|
|
6037
|
+
if (collapsed) {
|
|
6038
|
+
const extentPx = constants/* WAVEFORM_RANGE_COLLAPSED_OFFSET_PX */.BG + halfLine;
|
|
6039
|
+
el.style.left = offsetLeftCss(start, -extentPx);
|
|
6040
|
+
el.style.width = `${extentPx * 2}px`;
|
|
6041
|
+
return;
|
|
6042
|
+
}
|
|
6043
|
+
const end = timeLeftPercent(endSec, durationSec, viewport);
|
|
6044
|
+
el.style.left = offsetLeftCss(start, -halfLine);
|
|
6045
|
+
el.style.width = `calc(${end} - ${start} + ${constants/* WAVEFORM_RANGE_HANDLE_LINE_PX */.h1}px)`;
|
|
6046
|
+
}
|
|
6047
|
+
const WaveformRangeSelection = /*#__PURE__*/(0,external_react_.forwardRef)(function WaveformRangeSelection({
|
|
6048
|
+
currentTimeSec = 0,
|
|
6049
|
+
durationSec,
|
|
6050
|
+
getPlayheadSec,
|
|
6051
|
+
interactive = true,
|
|
6052
|
+
isHighlighted = false,
|
|
6053
|
+
keepHighlight = true,
|
|
6054
|
+
onDragChange,
|
|
6055
|
+
onPreviewChange,
|
|
6056
|
+
onRangeChange,
|
|
6057
|
+
range,
|
|
6058
|
+
viewport
|
|
6059
|
+
}, ref) {
|
|
6060
|
+
const rootRef = (0,external_react_.useRef)(null);
|
|
6061
|
+
const regionRef = (0,external_react_.useRef)(null);
|
|
6062
|
+
const startHandleRef = (0,external_react_.useRef)(null);
|
|
6063
|
+
const endHandleRef = (0,external_react_.useRef)(null);
|
|
6064
|
+
const tooltipRef = (0,external_react_.useRef)(null);
|
|
6065
|
+
const dragRef = (0,external_react_.useRef)(null);
|
|
6066
|
+
const rangeRef = (0,external_react_.useRef)(range);
|
|
6067
|
+
const displayedRef = (0,external_react_.useRef)(resolveRange(range, durationMsFromSec(durationSec)));
|
|
6068
|
+
const viewportRef = (0,external_react_.useRef)(viewport);
|
|
6069
|
+
const durationSecRef = (0,external_react_.useRef)(durationSec);
|
|
6070
|
+
const onDragChangeRef = (0,external_react_.useRef)(onDragChange);
|
|
6071
|
+
const onPreviewChangeRef = (0,external_react_.useRef)(onPreviewChange);
|
|
6072
|
+
const onRangeChangeRef = (0,external_react_.useRef)(onRangeChange);
|
|
6073
|
+
const getPlayheadSecRef = (0,external_react_.useRef)(getPlayheadSec);
|
|
6074
|
+
const [dragRange, setDragRange] = (0,external_react_.useState)(null);
|
|
6075
|
+
const [activeHandle, setActiveHandle] = (0,external_react_.useState)(null);
|
|
6076
|
+
const activeHandleRef = (0,external_react_.useRef)(null);
|
|
6077
|
+
rangeRef.current = range;
|
|
6078
|
+
durationSecRef.current = durationSec;
|
|
6079
|
+
onDragChangeRef.current = onDragChange;
|
|
6080
|
+
onPreviewChangeRef.current = onPreviewChange;
|
|
6081
|
+
onRangeChangeRef.current = onRangeChange;
|
|
6082
|
+
getPlayheadSecRef.current = getPlayheadSec;
|
|
6083
|
+
activeHandleRef.current = activeHandle;
|
|
6084
|
+
const durationMs = durationMsFromSec(durationSec);
|
|
6085
|
+
const displayed = dragRange ?? resolveRange(range, durationMs);
|
|
6086
|
+
displayedRef.current = displayed;
|
|
6087
|
+
const syncPositions = (0,external_react_.useCallback)((next, nextViewport, nextDurationSec) => {
|
|
6088
|
+
displayedRef.current = next;
|
|
6089
|
+
const collapsed = next.startMs === next.endMs;
|
|
6090
|
+
applyRegion(regionRef.current, next.startMs / 1000, next.endMs / 1000, nextDurationSec, nextViewport, collapsed);
|
|
6091
|
+
applyHandleLeft(startHandleRef.current, next.startMs / 1000, nextDurationSec, nextViewport, collapsed ? -constants/* WAVEFORM_RANGE_COLLAPSED_OFFSET_PX */.BG : 0);
|
|
6092
|
+
applyHandleLeft(endHandleRef.current, next.endMs / 1000, nextDurationSec, nextViewport, collapsed ? constants/* WAVEFORM_RANGE_COLLAPSED_OFFSET_PX */.BG : 0);
|
|
6093
|
+
const tooltip = tooltipRef.current;
|
|
6094
|
+
if (tooltip) {
|
|
6095
|
+
const tooltipHandle = activeHandleRef.current ?? 'end';
|
|
6096
|
+
const tooltipMs = tooltipHandle === 'start' ? next.startMs : next.endMs;
|
|
6097
|
+
tooltip.style.left = timeLeftPercent(tooltipMs / 1000, nextDurationSec, nextViewport);
|
|
6098
|
+
}
|
|
6099
|
+
}, []);
|
|
6100
|
+
(0,external_react_.useImperativeHandle)(ref, () => ({
|
|
6101
|
+
applyViewport: nextViewport => {
|
|
6102
|
+
viewportRef.current = nextViewport;
|
|
6103
|
+
syncPositions(displayedRef.current, nextViewport, durationSecRef.current);
|
|
6104
|
+
}
|
|
6105
|
+
}), [syncPositions]);
|
|
6106
|
+
(0,external_react_.useLayoutEffect)(() => {
|
|
6107
|
+
syncPositions(displayedRef.current, viewportRef.current, durationSec);
|
|
6108
|
+
}, [activeHandle, displayed.endMs, displayed.startMs, durationSec, syncPositions]);
|
|
6109
|
+
(0,external_react_.useLayoutEffect)(() => {
|
|
6110
|
+
const next = createWaveformViewport({
|
|
6111
|
+
durationSec: viewport.durationSec,
|
|
6112
|
+
heightPx: viewport.heightPx,
|
|
6113
|
+
maxZoom: viewport.maxZoom,
|
|
6114
|
+
scrollLeftPx: viewportRef.current.scrollLeftPx,
|
|
6115
|
+
widthPx: viewport.widthPx,
|
|
6116
|
+
zoomLevel: viewport.zoomLevel
|
|
6117
|
+
});
|
|
6118
|
+
viewportRef.current = next;
|
|
6119
|
+
syncPositions(displayedRef.current, next, durationSecRef.current);
|
|
6120
|
+
}, [syncPositions, viewport.durationSec, viewport.heightPx, viewport.maxZoom, viewport.widthPx, viewport.zoomLevel]);
|
|
6121
|
+
const endDrag = (0,external_react_.useCallback)(event => {
|
|
6122
|
+
const drag = dragRef.current;
|
|
6123
|
+
if (!drag || event.pointerId && drag.pointerId !== event.pointerId) {
|
|
6124
|
+
return;
|
|
6125
|
+
}
|
|
6126
|
+
[startHandleRef.current, endHandleRef.current].forEach(handleEl => {
|
|
6127
|
+
if (handleEl && handleEl.hasPointerCapture(event.pointerId)) {
|
|
6128
|
+
handleEl.releasePointerCapture(event.pointerId);
|
|
6129
|
+
}
|
|
6130
|
+
});
|
|
6131
|
+
dragRef.current = null;
|
|
6132
|
+
setActiveHandle(null);
|
|
6133
|
+
setDragRange(null);
|
|
6134
|
+
onDragChangeRef.current?.(false);
|
|
6135
|
+
const didChange = drag.range.startMs !== drag.originRange.startMs || drag.range.endMs !== drag.originRange.endMs;
|
|
6136
|
+
if (!didChange) {
|
|
6137
|
+
return;
|
|
6138
|
+
}
|
|
6139
|
+
const committed = commitRangeChange(drag.range);
|
|
6140
|
+
if (committed) {
|
|
6141
|
+
onRangeChangeRef.current?.(committed);
|
|
6142
|
+
}
|
|
6143
|
+
}, []);
|
|
6144
|
+
const moveDrag = (0,external_react_.useCallback)(event => {
|
|
6145
|
+
const drag = dragRef.current;
|
|
6146
|
+
if (!drag || event.pointerId && drag.pointerId !== event.pointerId) {
|
|
6147
|
+
return;
|
|
6148
|
+
}
|
|
6149
|
+
const root = rootRef.current;
|
|
6150
|
+
if (!root) {
|
|
6151
|
+
return;
|
|
6152
|
+
}
|
|
6153
|
+
const rect = root.getBoundingClientRect();
|
|
6154
|
+
const pointerX = event.clientX - rect.left;
|
|
6155
|
+
const vp = viewportRef.current;
|
|
6156
|
+
const duration = durationMsFromSec(durationSecRef.current);
|
|
6157
|
+
const playheadSec = getPlayheadSecRef.current?.() ?? currentTimeSec;
|
|
6158
|
+
const pointerMs = snapTimeMs({
|
|
6159
|
+
pixelsPerSecond: vp.pixelsPerSecond,
|
|
6160
|
+
playheadMs: playheadSec * 1000,
|
|
6161
|
+
timeMs: pointerTimeMs(pointerX, vp)
|
|
6162
|
+
});
|
|
6163
|
+
if (drag.originMs === drag.range.startMs && drag.originMs === drag.range.endMs && pointerMs === drag.originMs) {
|
|
6164
|
+
return;
|
|
6165
|
+
}
|
|
6166
|
+
const next = dragRangeHandle({
|
|
6167
|
+
durationMs: duration,
|
|
6168
|
+
handle: drag.handle,
|
|
6169
|
+
pointerMs,
|
|
6170
|
+
range: {
|
|
6171
|
+
endMs: drag.range.endMs,
|
|
6172
|
+
startMs: drag.range.startMs
|
|
6173
|
+
}
|
|
6174
|
+
});
|
|
6175
|
+
drag.handle = next.handle;
|
|
6176
|
+
drag.range = next.range;
|
|
6177
|
+
setActiveHandle(next.handle);
|
|
6178
|
+
setDragRange(next.range);
|
|
6179
|
+
syncPositions(next.range, vp, durationSecRef.current);
|
|
6180
|
+
onPreviewChangeRef.current?.({
|
|
6181
|
+
endMs: next.range.endMs,
|
|
6182
|
+
startMs: next.range.startMs
|
|
6183
|
+
});
|
|
6184
|
+
}, [currentTimeSec, syncPositions]);
|
|
6185
|
+
const startDrag = (0,external_react_.useCallback)((handle, event) => {
|
|
6186
|
+
if (!interactive || event.button > 1 || event.ctrlKey || event.metaKey) {
|
|
6187
|
+
return;
|
|
6188
|
+
}
|
|
6189
|
+
event.preventDefault();
|
|
6190
|
+
event.stopPropagation();
|
|
6191
|
+
const resolved = resolveRange(rangeRef.current, durationMsFromSec(durationSecRef.current));
|
|
6192
|
+
dragRef.current = {
|
|
6193
|
+
handle,
|
|
6194
|
+
originMs: handle === 'start' ? resolved.startMs : resolved.endMs,
|
|
6195
|
+
originRange: {
|
|
6196
|
+
endMs: resolved.endMs,
|
|
6197
|
+
startMs: resolved.startMs
|
|
6198
|
+
},
|
|
6199
|
+
pointerId: event.pointerId,
|
|
6200
|
+
range: resolved
|
|
6201
|
+
};
|
|
6202
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
6203
|
+
setActiveHandle(handle);
|
|
6204
|
+
setDragRange(resolved);
|
|
6205
|
+
onDragChangeRef.current?.(true);
|
|
6206
|
+
onPreviewChangeRef.current?.({
|
|
6207
|
+
endMs: isRangeCollapsed(rangeRef.current) ? null : resolved.endMs,
|
|
6208
|
+
startMs: resolved.startMs
|
|
6209
|
+
});
|
|
6210
|
+
}, [interactive]);
|
|
6211
|
+
const onHandlePointerDown = (0,external_react_.useCallback)(event => {
|
|
6212
|
+
const root = rootRef.current;
|
|
6213
|
+
if (!root) {
|
|
6214
|
+
return;
|
|
6215
|
+
}
|
|
6216
|
+
const rect = root.getBoundingClientRect();
|
|
6217
|
+
const pointerX = event.clientX - rect.left;
|
|
6218
|
+
const vp = viewportRef.current;
|
|
6219
|
+
const resolved = resolveRange(rangeRef.current, durationMsFromSec(durationSecRef.current));
|
|
6220
|
+
const handle = pickRangeHandle({
|
|
6221
|
+
endX: visualRangeHandlePx({
|
|
6222
|
+
handle: 'end',
|
|
6223
|
+
range: resolved,
|
|
6224
|
+
viewport: vp
|
|
6225
|
+
}),
|
|
6226
|
+
pointerX,
|
|
6227
|
+
startX: visualRangeHandlePx({
|
|
6228
|
+
handle: 'start',
|
|
6229
|
+
range: resolved,
|
|
6230
|
+
viewport: vp
|
|
6231
|
+
})
|
|
6232
|
+
});
|
|
6233
|
+
startDrag(handle, event);
|
|
6234
|
+
}, [startDrag]);
|
|
6235
|
+
(0,external_react_.useEffect)(() => {
|
|
6236
|
+
const onMove = event => {
|
|
6237
|
+
if (!dragRef.current) {
|
|
6238
|
+
return;
|
|
6239
|
+
}
|
|
6240
|
+
event.preventDefault();
|
|
6241
|
+
moveDrag(event);
|
|
6242
|
+
};
|
|
6243
|
+
const onUp = event => {
|
|
6244
|
+
if (!dragRef.current) {
|
|
6245
|
+
return;
|
|
6246
|
+
}
|
|
6247
|
+
endDrag(event);
|
|
6248
|
+
};
|
|
6249
|
+
window.addEventListener('pointermove', onMove);
|
|
6250
|
+
window.addEventListener('pointerup', onUp);
|
|
6251
|
+
window.addEventListener('pointercancel', onUp);
|
|
6252
|
+
return () => {
|
|
6253
|
+
window.removeEventListener('pointermove', onMove);
|
|
6254
|
+
window.removeEventListener('pointerup', onUp);
|
|
6255
|
+
window.removeEventListener('pointercancel', onUp);
|
|
6256
|
+
};
|
|
6257
|
+
}, [endDrag, moveDrag]);
|
|
6258
|
+
(0,external_react_.useEffect)(() => {
|
|
6259
|
+
return () => {
|
|
6260
|
+
if (!dragRef.current) {
|
|
6261
|
+
return;
|
|
6262
|
+
}
|
|
6263
|
+
dragRef.current = null;
|
|
6264
|
+
onDragChangeRef.current?.(false);
|
|
6265
|
+
};
|
|
6266
|
+
}, []);
|
|
6267
|
+
if (!(durationSec > 0) || !(durationMs >= 0)) {
|
|
6268
|
+
return null;
|
|
6269
|
+
}
|
|
6270
|
+
const tooltipHandle = activeHandle ?? 'end';
|
|
6271
|
+
const tooltipMs = tooltipHandle === 'start' ? displayed.startMs : displayed.endMs;
|
|
6272
|
+
const collapsed = displayed.startMs === displayed.endMs;
|
|
6273
|
+
const highlight = isHighlighted || collapsed;
|
|
6274
|
+
return /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
6275
|
+
ref: rootRef,
|
|
6276
|
+
className: `bp-WaveformRange${keepHighlight ? ' bp-WaveformRange--persist' : ''}${highlight ? ' bp-WaveformRange--highlight' : ''}`,
|
|
6277
|
+
"data-collapsed": collapsed ? 'true' : 'false',
|
|
6278
|
+
"data-highlighted": highlight ? 'true' : 'false',
|
|
6279
|
+
"data-testid": "bp-waveform-range"
|
|
6280
|
+
}, /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
6281
|
+
ref: regionRef,
|
|
6282
|
+
className: "bp-WaveformRange-region",
|
|
6283
|
+
"data-testid": "bp-waveform-range-region"
|
|
6284
|
+
}), /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
6285
|
+
ref: startHandleRef,
|
|
6286
|
+
className: `bp-WaveformRange-handle bp-WaveformRange-handle--start${activeHandle === 'start' ? ' bp-WaveformRange-handle--dragging' : ''}`,
|
|
6287
|
+
"data-testid": "bp-waveform-range-handle-start",
|
|
6288
|
+
onMouseMove: event => event.stopPropagation(),
|
|
6289
|
+
onPointerDown: onHandlePointerDown
|
|
6290
|
+
}, /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
6291
|
+
className: "bp-WaveformRange-handleGrip"
|
|
6292
|
+
})), /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
6293
|
+
ref: endHandleRef,
|
|
6294
|
+
className: `bp-WaveformRange-handle bp-WaveformRange-handle--end${activeHandle === 'end' ? ' bp-WaveformRange-handle--dragging' : ''}`,
|
|
6295
|
+
"data-testid": "bp-waveform-range-handle-end",
|
|
6296
|
+
onMouseMove: event => event.stopPropagation(),
|
|
6297
|
+
onPointerDown: onHandlePointerDown
|
|
6298
|
+
}, /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
6299
|
+
className: "bp-WaveformRange-handleGrip"
|
|
6300
|
+
})), activeHandle && /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
6301
|
+
ref: tooltipRef,
|
|
6302
|
+
className: "bp-WaveformRange-tooltip",
|
|
6303
|
+
"data-testid": "bp-waveform-range-tooltip"
|
|
6304
|
+
}, /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
6305
|
+
className: "bp-WaveformRange-tooltipTime"
|
|
6306
|
+
}, formatTime(tooltipMs / 1000))));
|
|
6307
|
+
});
|
|
6308
|
+
/* harmony default export */ const waveform_WaveformRangeSelection = (/*#__PURE__*/external_react_["default"].memo(WaveformRangeSelection));
|
|
5539
6309
|
;// ./src/lib/viewers/media/waveform/WaveformView.scss
|
|
5540
6310
|
// extracted by mini-css-extract-plugin
|
|
5541
6311
|
|
|
@@ -5555,6 +6325,10 @@ function WaveformView_toPrimitive(t, r) { if ("object" != typeof t || !t) return
|
|
|
5555
6325
|
|
|
5556
6326
|
|
|
5557
6327
|
|
|
6328
|
+
|
|
6329
|
+
|
|
6330
|
+
|
|
6331
|
+
|
|
5558
6332
|
/** Pointer X in the view and the media time under it; zoom keeps this point fixed. */
|
|
5559
6333
|
|
|
5560
6334
|
/** CSS width × devicePixelRatio, for canvas gradient fills. */
|
|
@@ -5584,6 +6358,25 @@ function disableScrollOverscroll(container) {
|
|
|
5584
6358
|
}
|
|
5585
6359
|
}
|
|
5586
6360
|
|
|
6361
|
+
/** Half-view margins so t=0 and duration can sit under the center pin. */
|
|
6362
|
+
function applyWaveformGutters(wavesurfer, gutterPx) {
|
|
6363
|
+
const wrapper = wavesurfer.getWrapper ? wavesurfer.getWrapper() : null;
|
|
6364
|
+
if (!wrapper || !wrapper.style) {
|
|
6365
|
+
return;
|
|
6366
|
+
}
|
|
6367
|
+
const pad = gutterPx > 0 ? `${gutterPx}px` : '';
|
|
6368
|
+
wrapper.style.marginLeft = pad;
|
|
6369
|
+
wrapper.style.marginRight = pad;
|
|
6370
|
+
// WaveSurfer sets overflow-x:hidden when duration * minPxPerSec <= view width
|
|
6371
|
+
// (tape 1x). Gutters live in these margins, so the scroller must stay pan-able.
|
|
6372
|
+
const scroll = wrapper.parentElement;
|
|
6373
|
+
if (scroll && scroll.style) {
|
|
6374
|
+
const scrollStyle = scroll.style;
|
|
6375
|
+
scrollStyle.overflowX = gutterPx > 0 ? 'auto' : '';
|
|
6376
|
+
scrollStyle.scrollbarWidth = gutterPx > 0 ? 'none' : '';
|
|
6377
|
+
}
|
|
6378
|
+
}
|
|
6379
|
+
|
|
5587
6380
|
/** Tint WaveSurfer's zoomed tiles with played/unplayed/hover/buffer colors. */
|
|
5588
6381
|
function tintZoomedWaveform(wavesurfer, fills, replaceSnapshot = false) {
|
|
5589
6382
|
const wrapper = wavesurfer.getWrapper ? wavesurfer.getWrapper() : null;
|
|
@@ -5597,6 +6390,15 @@ function tintZoomedWaveform(wavesurfer, fills, replaceSnapshot = false) {
|
|
|
5597
6390
|
totalWidthCss: wrapper.clientWidth
|
|
5598
6391
|
});
|
|
5599
6392
|
}
|
|
6393
|
+
|
|
6394
|
+
/** Touch (and the compatibility mouse events Chrome sends after a tap) must not drive hover fills. */
|
|
6395
|
+
function isTouchHoverInput(event) {
|
|
6396
|
+
if (event.pointerType === 'touch') {
|
|
6397
|
+
return true;
|
|
6398
|
+
}
|
|
6399
|
+
const native = event.nativeEvent;
|
|
6400
|
+
return !!native.sourceCapabilities?.firesTouchEvents;
|
|
6401
|
+
}
|
|
5600
6402
|
function touchDistance(touches) {
|
|
5601
6403
|
if (touches.length < 2) {
|
|
5602
6404
|
return 0;
|
|
@@ -5627,56 +6429,87 @@ function zoomOriginAtPointer(pointerX, wavesurfer, durationSec, fallbackWidth) {
|
|
|
5627
6429
|
*/
|
|
5628
6430
|
function WaveformView({
|
|
5629
6431
|
bufferedRange,
|
|
6432
|
+
cameraMode = 'desktop',
|
|
5630
6433
|
currentTime = 0,
|
|
5631
6434
|
durationSec,
|
|
5632
6435
|
height = constants/* WAVEFORM_HEIGHT */.oN,
|
|
5633
6436
|
interactive = true,
|
|
6437
|
+
isPlaying = false,
|
|
5634
6438
|
mediaEl,
|
|
6439
|
+
onPlayPause,
|
|
6440
|
+
onRangeChange,
|
|
6441
|
+
onRangeDragChange,
|
|
5635
6442
|
onSeek,
|
|
5636
6443
|
onViewportChange,
|
|
5637
6444
|
onZoomChange,
|
|
5638
6445
|
peaks,
|
|
6446
|
+
range = null,
|
|
5639
6447
|
zoomLevel: zoomLevelProp
|
|
5640
6448
|
}) {
|
|
5641
6449
|
// 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);
|
|
6450
|
+
const containerRef = (0,external_react_.useRef)(null); // WaveSurfer canvas host
|
|
6451
|
+
const playheadAnimationRef = (0,external_react_.useRef)(0); // animation frame id while the playhead follows playback
|
|
6452
|
+
const playheadRef = (0,external_react_.useRef)(null); // playhead element the camera positions
|
|
6453
|
+
const trackRef = (0,external_react_.useRef)(null); // hover / tap target around the canvas
|
|
6454
|
+
const wavesurferRef = (0,external_react_.useRef)(null); // WaveSurfer instance
|
|
6455
|
+
const rangeLayerRef = (0,external_react_.useRef)(null);
|
|
5647
6456
|
|
|
5648
6457
|
// 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
|
|
6458
|
+
const cameraModeRef = (0,external_react_.useRef)(cameraMode); // latest tape/desktop; WaveSurfer create() deps stay empty
|
|
6459
|
+
const currentTimeRef = (0,external_react_.useRef)(currentTime); // latest media time; zoom recenter reads this
|
|
6460
|
+
const durationSecRef = (0,external_react_.useRef)(durationSec); // latest duration; click-to-seek reads this
|
|
6461
|
+
const hasZoomHandlersRef = (0,external_react_.useRef)(false); // parent can zoom; wheel/pinch check this
|
|
6462
|
+
const interactiveRef = (0,external_react_.useRef)(interactive); // latest interactive; WaveSurfer listeners read this
|
|
6463
|
+
const isPlayingRef = (0,external_react_.useRef)(isPlaying); // latest isPlaying; tape tap toggles from this
|
|
6464
|
+
const mediaElRef = (0,external_react_.useRef)(mediaEl); // latest <audio>/<video>; camera + playhead tick read this
|
|
6465
|
+
const onPlayPauseRef = (0,external_react_.useRef)(onPlayPause); // latest play/pause; tape tap must not re-bind
|
|
6466
|
+
const onSeekRef = (0,external_react_.useRef)(onSeek); // latest onSeek; click/scroll handlers must not re-bind
|
|
6467
|
+
const onViewportChangeRef = (0,external_react_.useRef)(onViewportChange); // latest viewport callback; camera commits here
|
|
6468
|
+
const peaksRef = (0,external_react_.useRef)(peaks); // latest peaks; WaveSurfer create() + morph read this
|
|
6469
|
+
|
|
6470
|
+
const displayedPeaksRef = (0,external_react_.useRef)(null); // peaks currently drawn (for morph)
|
|
6471
|
+
const peakTransitionAnimationRef = (0,external_react_.useRef)(0); // animation frame id while peaks morph in
|
|
5659
6472
|
// 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
|
-
|
|
6473
|
+
const applyZoomWindowRef = (0,external_react_.useRef)(null); // latest applyZoomWindow; resize observer calls this
|
|
6474
|
+
const bufferProgressRef = (0,external_react_.useRef)(0); // latest buffer fill; zoomed tile tint reads this
|
|
6475
|
+
const hideScrubTimeChipTimerRef = (0,external_react_.useRef)(0); // hides the tape scrub time chip after scroll settles
|
|
6476
|
+
const hoverProgressRef = (0,external_react_.useRef)(null); // latest hover fill; zoomed tile tint reads this
|
|
6477
|
+
const lastObservedWidthRef = (0,external_react_.useRef)(0); // last ResizeObserver width; skip no-op resizes
|
|
6478
|
+
const liveHeightRef = (0,external_react_.useRef)(height); // canvas height last applied to WaveSurfer
|
|
6479
|
+
const pinchStartRef = (0,external_react_.useRef)(null); // two-finger distance and zoom at pinch start
|
|
6480
|
+
const pointerZoomClearTimerRef = (0,external_react_.useRef)(0); // clears pointerZoomRef after WAVEFORM_ZOOM_DISMISS_MS
|
|
6481
|
+
const pointerZoomRef = (0,external_react_.useRef)(false); // pinch/wheel in progress; skip play/pause and tape recenter
|
|
6482
|
+
const queuedTapeSeekTimeSecRef = (0,external_react_.useRef)(null); // seek time waiting for the next animation frame
|
|
6483
|
+
const rangeProgressRef = (0,external_react_.useRef)(null); // latest range progress; zoomed tile tint reads this
|
|
6484
|
+
const suppressNextTapPlayPauseRef = (0,external_react_.useRef)(false); // swallow play/pause after a swipe or pinch
|
|
6485
|
+
const suppressNextTapPlayPauseTimerRef = (0,external_react_.useRef)(0); // clears suppressNextTapPlayPauseRef
|
|
6486
|
+
const suppressViewportSyncRef = (0,external_react_.useRef)(false); // ignore WaveSurfer zoom/scroll while we setOptions
|
|
6487
|
+
const tapeSeekAnimationRef = (0,external_react_.useRef)(0); // coalesces swipe seeks to one seek per animation frame
|
|
6488
|
+
const toggleTapePlaybackRef = (0,external_react_.useRef)(null); // latest tap play/pause; click/pointerup call this
|
|
6489
|
+
const zoomOriginRef = (0,external_react_.useRef)(null); // pointer+time so zoom keeps that point fixed
|
|
6490
|
+
|
|
6491
|
+
cameraModeRef.current = cameraMode;
|
|
5671
6492
|
currentTimeRef.current = currentTime;
|
|
5672
|
-
peaksRef.current = peaks;
|
|
5673
6493
|
durationSecRef.current = durationSec;
|
|
6494
|
+
interactiveRef.current = interactive;
|
|
6495
|
+
isPlayingRef.current = isPlaying;
|
|
5674
6496
|
mediaElRef.current = mediaEl;
|
|
6497
|
+
onPlayPauseRef.current = onPlayPause;
|
|
6498
|
+
onSeekRef.current = onSeek;
|
|
5675
6499
|
onViewportChangeRef.current = onViewportChange;
|
|
6500
|
+
peaksRef.current = peaks;
|
|
5676
6501
|
const [internalZoom, setInternalZoom] = (0,external_react_.useState)(constants/* WAVEFORM_ZOOM_MIN */.LW);
|
|
5677
6502
|
const [hoverProgress, setHoverProgress] = (0,external_react_.useState)(null);
|
|
6503
|
+
const [scrubPreviewTimeSec, setScrubPreviewTimeSec] = (0,external_react_.useState)(null);
|
|
6504
|
+
const [overlayPortalHost, setOverlayPortalHost] = (0,external_react_.useState)(null);
|
|
5678
6505
|
const [canvasWidthPx, setCanvasWidthPx] = (0,external_react_.useState)(0);
|
|
5679
6506
|
const [scrollLeft, setScrollLeft] = (0,external_react_.useState)(0);
|
|
6507
|
+
const [previewRange, setPreviewRange] = (0,external_react_.useState)(null);
|
|
6508
|
+
const [isRangeDragging, setIsRangeDragging] = (0,external_react_.useState)(false);
|
|
6509
|
+
const isRangeDraggingRef = (0,external_react_.useRef)(false);
|
|
6510
|
+
const skipNextSeekRef = (0,external_react_.useRef)(false);
|
|
6511
|
+
const lastSetTimeSecRef = (0,external_react_.useRef)(null);
|
|
6512
|
+
const [isRangeHovered, setIsRangeHovered] = (0,external_react_.useState)(false);
|
|
5680
6513
|
const isControlled = typeof zoomLevelProp === 'number';
|
|
5681
6514
|
const maxZoom = getWaveformZoomMax({
|
|
5682
6515
|
durationSec,
|
|
@@ -5687,21 +6520,41 @@ function WaveformView({
|
|
|
5687
6520
|
const zoomLevel = clampWaveformZoom(isControlled ? zoomLevelProp : internalZoom, maxZoom);
|
|
5688
6521
|
const zoomRef = (0,external_react_.useRef)(zoomLevel); // latest zoom for WaveSurfer redraw/zoom handlers
|
|
5689
6522
|
zoomRef.current = zoomLevel;
|
|
5690
|
-
const prevZoomRef = (0,external_react_.useRef)(null);
|
|
6523
|
+
const prevZoomRef = (0,external_react_.useRef)(null); // last applied zoom; tape recenters only when this changes
|
|
6524
|
+
const isTape = cameraMode === 'tape';
|
|
5691
6525
|
const isZoomed = zoomLevel > constants/* WAVEFORM_ZOOM_MIN */.LW;
|
|
6526
|
+
const isScrollableWindow = isZoomed || isTape;
|
|
5692
6527
|
const bufferProgress = getBufferedProgress(bufferedRange, durationSec);
|
|
5693
6528
|
bufferProgressRef.current = bufferProgress;
|
|
5694
|
-
hoverProgressRef.current = hoverProgress;
|
|
6529
|
+
hoverProgressRef.current = isRangeDragging ? null : hoverProgress;
|
|
6530
|
+
const activeRange = isRangeDragging ? previewRange ?? range : range;
|
|
6531
|
+
const activeRangeRef = (0,external_react_.useRef)(activeRange);
|
|
6532
|
+
activeRangeRef.current = activeRange;
|
|
6533
|
+
const durationMs = durationMsFromSec(durationSec);
|
|
6534
|
+
const rangeStartMs = activeRange?.startMs;
|
|
6535
|
+
const rangeEndMs = activeRange?.endMs;
|
|
6536
|
+
const activeRangeProgress = (0,external_react_.useMemo)(() => {
|
|
6537
|
+
if (rangeStartMs == null || !Number.isFinite(rangeStartMs)) {
|
|
6538
|
+
return null;
|
|
6539
|
+
}
|
|
6540
|
+
return rangeProgress(resolveRange({
|
|
6541
|
+
endMs: rangeEndMs ?? null,
|
|
6542
|
+
startMs: rangeStartMs
|
|
6543
|
+
}, durationMs), durationMs);
|
|
6544
|
+
}, [durationMs, rangeEndMs, rangeStartMs]);
|
|
6545
|
+
rangeProgressRef.current = activeRangeProgress;
|
|
5695
6546
|
const viewport = (0,external_react_.useMemo)(() => createWaveformViewport({
|
|
5696
6547
|
durationSec,
|
|
6548
|
+
gutterPx: isTape ? getTapeGutterPx(canvasWidthPx) : 0,
|
|
5697
6549
|
heightPx: height,
|
|
5698
6550
|
maxZoom,
|
|
5699
6551
|
scrollLeftPx: scrollLeft,
|
|
5700
6552
|
widthPx: canvasWidthPx,
|
|
5701
6553
|
zoomLevel
|
|
5702
|
-
}), [canvasWidthPx, durationSec, height, maxZoom, scrollLeft, zoomLevel]);
|
|
6554
|
+
}), [canvasWidthPx, durationSec, height, isTape, maxZoom, scrollLeft, zoomLevel]);
|
|
5703
6555
|
const viewportRef = (0,external_react_.useRef)(viewport); // live scroll window; prefer this over render-state while the camera is moving
|
|
5704
6556
|
const onViewportCommit = (0,external_react_.useCallback)((scrollLeftPx, nextViewport, commitReactState = true) => {
|
|
6557
|
+
rangeLayerRef.current?.applyViewport(nextViewport);
|
|
5705
6558
|
onViewportChangeRef.current?.(nextViewport);
|
|
5706
6559
|
if (commitReactState) {
|
|
5707
6560
|
setScrollLeft(scrollLeftPx);
|
|
@@ -5714,20 +6567,45 @@ function WaveformView({
|
|
|
5714
6567
|
clearFollowPin,
|
|
5715
6568
|
handleScroll: handleCameraScroll,
|
|
5716
6569
|
isFollowPinned,
|
|
6570
|
+
isUserPanning,
|
|
5717
6571
|
onSeek: onPlayheadSeek,
|
|
5718
6572
|
onZoom,
|
|
5719
6573
|
releaseUserPanHold,
|
|
5720
6574
|
seekTo
|
|
5721
6575
|
} = usePlayheadCamera({
|
|
6576
|
+
cameraMode,
|
|
5722
6577
|
mediaElRef,
|
|
5723
6578
|
onViewportCommit,
|
|
5724
6579
|
playheadRef,
|
|
5725
6580
|
viewportRef,
|
|
5726
6581
|
wavesurferRef
|
|
5727
6582
|
});
|
|
6583
|
+
const toggleTapePlayback = (0,external_react_.useCallback)(() => {
|
|
6584
|
+
if (!interactiveRef.current) {
|
|
6585
|
+
return;
|
|
6586
|
+
}
|
|
6587
|
+
if (isUserPanning() || pointerZoomRef.current) {
|
|
6588
|
+
return;
|
|
6589
|
+
}
|
|
6590
|
+
if (suppressNextTapPlayPauseRef.current) {
|
|
6591
|
+
suppressNextTapPlayPauseRef.current = false;
|
|
6592
|
+
window.clearTimeout(suppressNextTapPlayPauseTimerRef.current);
|
|
6593
|
+
suppressNextTapPlayPauseTimerRef.current = 0;
|
|
6594
|
+
return;
|
|
6595
|
+
}
|
|
6596
|
+
onPlayPauseRef.current?.(!isPlayingRef.current);
|
|
6597
|
+
suppressNextTapPlayPauseRef.current = true;
|
|
6598
|
+
window.clearTimeout(suppressNextTapPlayPauseTimerRef.current);
|
|
6599
|
+
suppressNextTapPlayPauseTimerRef.current = window.setTimeout(() => {
|
|
6600
|
+
suppressNextTapPlayPauseRef.current = false;
|
|
6601
|
+
suppressNextTapPlayPauseTimerRef.current = 0;
|
|
6602
|
+
}, constants/* WAVEFORM_TAPE_CLICK_SUPPRESS_MS */.fI);
|
|
6603
|
+
}, [isUserPanning]);
|
|
6604
|
+
toggleTapePlaybackRef.current = toggleTapePlayback;
|
|
5728
6605
|
(0,external_react_.useLayoutEffect)(() => {
|
|
5729
6606
|
viewportRef.current = createWaveformViewport({
|
|
5730
6607
|
durationSec: viewport.durationSec,
|
|
6608
|
+
gutterPx: viewport.gutterPx,
|
|
5731
6609
|
heightPx: viewport.heightPx,
|
|
5732
6610
|
maxZoom: viewport.maxZoom,
|
|
5733
6611
|
scrollLeftPx: viewportRef.current.scrollLeftPx,
|
|
@@ -5750,6 +6628,41 @@ function WaveformView({
|
|
|
5750
6628
|
pointerZoomClearTimerRef.current = 0;
|
|
5751
6629
|
}, constants/* WAVEFORM_ZOOM_DISMISS_MS */.m6);
|
|
5752
6630
|
}, []);
|
|
6631
|
+
|
|
6632
|
+
/**
|
|
6633
|
+
* Seek the time under the pin (one seek per frame). Swallow the delayed iOS click;
|
|
6634
|
+
* show the scrub chip until the swipe settles.
|
|
6635
|
+
*/
|
|
6636
|
+
const handleTapeSwipe = (0,external_react_.useCallback)(timeSec => {
|
|
6637
|
+
// Swallow the click WaveSurfer/iOS fires after a swipe or pinch.
|
|
6638
|
+
suppressNextTapPlayPauseRef.current = true;
|
|
6639
|
+
window.clearTimeout(suppressNextTapPlayPauseTimerRef.current);
|
|
6640
|
+
suppressNextTapPlayPauseTimerRef.current = window.setTimeout(() => {
|
|
6641
|
+
suppressNextTapPlayPauseRef.current = false;
|
|
6642
|
+
suppressNextTapPlayPauseTimerRef.current = 0;
|
|
6643
|
+
}, constants/* WAVEFORM_TAPE_CLICK_SUPPRESS_MS */.fI);
|
|
6644
|
+
queuedTapeSeekTimeSecRef.current = timeSec;
|
|
6645
|
+
if (!tapeSeekAnimationRef.current) {
|
|
6646
|
+
// One seek per frame; later scrolls just update the queued time.
|
|
6647
|
+
tapeSeekAnimationRef.current = window.requestAnimationFrame(() => {
|
|
6648
|
+
tapeSeekAnimationRef.current = 0;
|
|
6649
|
+
const next = queuedTapeSeekTimeSecRef.current;
|
|
6650
|
+
queuedTapeSeekTimeSecRef.current = null;
|
|
6651
|
+
if (next != null) {
|
|
6652
|
+
onSeekRef.current?.(next);
|
|
6653
|
+
}
|
|
6654
|
+
});
|
|
6655
|
+
}
|
|
6656
|
+
if (interactiveRef.current) {
|
|
6657
|
+
// Show the time under the pin; hide once scrolling has settled.
|
|
6658
|
+
setScrubPreviewTimeSec(timeSec);
|
|
6659
|
+
window.clearTimeout(hideScrubTimeChipTimerRef.current);
|
|
6660
|
+
hideScrubTimeChipTimerRef.current = window.setTimeout(() => {
|
|
6661
|
+
setScrubPreviewTimeSec(null);
|
|
6662
|
+
hideScrubTimeChipTimerRef.current = 0;
|
|
6663
|
+
}, constants/* WAVEFORM_FOLLOW_SCROLL_SETTLE_MS */.Zs);
|
|
6664
|
+
}
|
|
6665
|
+
}, []);
|
|
5753
6666
|
const syncViewport = (0,external_react_.useCallback)(() => {
|
|
5754
6667
|
const wavesurfer = wavesurferRef.current;
|
|
5755
6668
|
if (!wavesurfer) {
|
|
@@ -5757,6 +6670,7 @@ function WaveformView({
|
|
|
5757
6670
|
}
|
|
5758
6671
|
const scrollLeftPx = WaveformView_getScrollLeft(wavesurfer);
|
|
5759
6672
|
viewportRef.current = getViewportAtScroll(viewportRef.current, scrollLeftPx);
|
|
6673
|
+
rangeLayerRef.current?.applyViewport(viewportRef.current);
|
|
5760
6674
|
onViewportChangeRef.current?.(viewportRef.current);
|
|
5761
6675
|
setScrollLeft(scrollLeftPx);
|
|
5762
6676
|
}, []);
|
|
@@ -5765,14 +6679,18 @@ function WaveformView({
|
|
|
5765
6679
|
if (!playhead) {
|
|
5766
6680
|
return;
|
|
5767
6681
|
}
|
|
5768
|
-
if (
|
|
6682
|
+
if (isTape) {
|
|
6683
|
+
playhead.style.left = getTapePinnedPlayheadLeft();
|
|
6684
|
+
} else if (!isFollowPinned()) {
|
|
5769
6685
|
playhead.style.left = timeLeftPercent(timeSec, durationSecRef.current, viewportRef.current);
|
|
5770
6686
|
}
|
|
6687
|
+
rangeLayerRef.current?.applyViewport(viewportRef.current);
|
|
5771
6688
|
const wavesurfer = wavesurferRef.current;
|
|
5772
|
-
if (wavesurfer && wavesurfer.setTime) {
|
|
6689
|
+
if (wavesurfer && wavesurfer.setTime && lastSetTimeSecRef.current !== timeSec) {
|
|
6690
|
+
lastSetTimeSecRef.current = timeSec;
|
|
5773
6691
|
wavesurfer.setTime(timeSec);
|
|
5774
6692
|
}
|
|
5775
|
-
}, [isFollowPinned]);
|
|
6693
|
+
}, [isFollowPinned, isTape]);
|
|
5776
6694
|
|
|
5777
6695
|
// Same zoom-window body as the zoom effect; extracted so resize can call it too.
|
|
5778
6696
|
const applyZoomWindow = (0,external_react_.useCallback)(() => {
|
|
@@ -5784,11 +6702,13 @@ function WaveformView({
|
|
|
5784
6702
|
const viewWidthPx = wavesurfer.getWidth ? wavesurfer.getWidth() : container.clientWidth;
|
|
5785
6703
|
const minPxPerSec = getZoomedPixelsPerSecond({
|
|
5786
6704
|
durationSec,
|
|
6705
|
+
isTape,
|
|
5787
6706
|
maxZoom,
|
|
5788
6707
|
viewWidthPx,
|
|
5789
6708
|
zoomLevel
|
|
5790
6709
|
});
|
|
5791
|
-
const
|
|
6710
|
+
const gutterPx = isTape ? getTapeGutterPx(viewWidthPx) : 0;
|
|
6711
|
+
const origin = isTape ? null : zoomOriginRef.current;
|
|
5792
6712
|
zoomOriginRef.current = null;
|
|
5793
6713
|
const didZoomChange = prevZoomRef.current !== zoomLevel;
|
|
5794
6714
|
if (origin || didZoomChange) {
|
|
@@ -5798,26 +6718,30 @@ function WaveformView({
|
|
|
5798
6718
|
try {
|
|
5799
6719
|
wavesurfer.setOptions(WaveformView_objectSpread({
|
|
5800
6720
|
autoScroll: false,
|
|
6721
|
+
fillParent: !isTape,
|
|
5801
6722
|
minPxPerSec
|
|
5802
|
-
},
|
|
5803
|
-
progressColor:
|
|
6723
|
+
}, isScrollableWindow ? {
|
|
6724
|
+
progressColor: getPlayedWaveformColor(isTape),
|
|
5804
6725
|
waveColor: WAVEFORM_COLOR_UNPLAYED
|
|
5805
6726
|
} : {}));
|
|
6727
|
+
applyWaveformGutters(wavesurfer, gutterPx);
|
|
5806
6728
|
if (minPxPerSec > 0) {
|
|
6729
|
+
const windowViewport = createWaveformViewport({
|
|
6730
|
+
durationSec,
|
|
6731
|
+
gutterPx,
|
|
6732
|
+
heightPx: liveHeightRef.current || height,
|
|
6733
|
+
maxZoom,
|
|
6734
|
+
scrollLeftPx: 0,
|
|
6735
|
+
widthPx: viewWidthPx,
|
|
6736
|
+
zoomLevel
|
|
6737
|
+
});
|
|
5807
6738
|
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);
|
|
6739
|
+
applyScrollLeft(origin.timeSec * minPxPerSec + gutterPx - origin.pointerX, true);
|
|
6740
|
+
} else if (didZoomChange && (isTape || !pointerZoomRef.current)) {
|
|
6741
|
+
applyScrollLeft(getCenteredScrollLeft(currentTimeRef.current, windowViewport), true);
|
|
5819
6742
|
}
|
|
5820
6743
|
}
|
|
6744
|
+
lastSetTimeSecRef.current = currentTimeRef.current;
|
|
5821
6745
|
wavesurfer.setTime(currentTimeRef.current);
|
|
5822
6746
|
} finally {
|
|
5823
6747
|
suppressViewportSyncRef.current = false;
|
|
@@ -5825,13 +6749,17 @@ function WaveformView({
|
|
|
5825
6749
|
}
|
|
5826
6750
|
syncViewport();
|
|
5827
6751
|
updatePlayheadPosition(currentTimeRef.current);
|
|
5828
|
-
}, [applyScrollLeft, durationSec, height, maxZoom, onZoom, syncViewport, updatePlayheadPosition, zoomLevel]);
|
|
6752
|
+
}, [applyScrollLeft, durationSec, height, isScrollableWindow, isTape, maxZoom, onZoom, syncViewport, updatePlayheadPosition, zoomLevel]);
|
|
5829
6753
|
applyZoomWindowRef.current = applyZoomWindow;
|
|
5830
6754
|
(0,external_react_.useEffect)(() => {
|
|
5831
6755
|
const container = containerRef.current;
|
|
5832
6756
|
if (!container) {
|
|
5833
6757
|
return undefined;
|
|
5834
6758
|
}
|
|
6759
|
+
const measuredHeight = cameraModeRef.current === 'tape' && container.clientHeight > 0 ? Math.round(container.clientHeight) : height;
|
|
6760
|
+
if (cameraModeRef.current === 'tape' && measuredHeight > 0) {
|
|
6761
|
+
liveHeightRef.current = measuredHeight;
|
|
6762
|
+
}
|
|
5835
6763
|
const wavesurfer = w.create({
|
|
5836
6764
|
autoScroll: false,
|
|
5837
6765
|
barGap: constants/* WAVEFORM_BAR_GAP */.Lu,
|
|
@@ -5842,16 +6770,25 @@ function WaveformView({
|
|
|
5842
6770
|
cursorWidth: 0,
|
|
5843
6771
|
duration: durationSecRef.current,
|
|
5844
6772
|
fillParent: true,
|
|
5845
|
-
height,
|
|
6773
|
+
height: measuredHeight,
|
|
5846
6774
|
hideScrollbar: true,
|
|
5847
|
-
|
|
6775
|
+
dragToSeek: false,
|
|
6776
|
+
interact: interactiveRef.current && cameraModeRef.current !== 'tape',
|
|
5848
6777
|
normalize: false,
|
|
5849
6778
|
peaks: toChannels(peaksRef.current),
|
|
5850
|
-
progressColor:
|
|
6779
|
+
progressColor: getPlayedWaveformColor(cameraModeRef.current === 'tape'),
|
|
5851
6780
|
waveColor: WAVEFORM_COLOR_UNPLAYED
|
|
5852
6781
|
});
|
|
5853
6782
|
const unsubscribeClick = wavesurfer.on('click', relativeX => {
|
|
5854
|
-
if (
|
|
6783
|
+
if (skipNextSeekRef.current) {
|
|
6784
|
+
skipNextSeekRef.current = false;
|
|
6785
|
+
return;
|
|
6786
|
+
}
|
|
6787
|
+
if (!interactiveRef.current || isRangeDraggingRef.current) {
|
|
6788
|
+
return;
|
|
6789
|
+
}
|
|
6790
|
+
if (cameraModeRef.current === 'tape') {
|
|
6791
|
+
toggleTapePlaybackRef.current?.();
|
|
5855
6792
|
return;
|
|
5856
6793
|
}
|
|
5857
6794
|
onSeekRef.current?.(relativeX * durationSecRef.current);
|
|
@@ -5860,9 +6797,14 @@ function WaveformView({
|
|
|
5860
6797
|
if (suppressViewportSyncRef.current) {
|
|
5861
6798
|
return;
|
|
5862
6799
|
}
|
|
5863
|
-
|
|
6800
|
+
// User pan: map scroll to the time under the playhead, then tape seeks it.
|
|
6801
|
+
handleCameraScroll(timeSec => {
|
|
6802
|
+
if (cameraModeRef.current === 'tape' && !pointerZoomRef.current) {
|
|
6803
|
+
handleTapeSwipe(timeSec);
|
|
6804
|
+
}
|
|
5864
6805
|
syncViewport();
|
|
5865
6806
|
});
|
|
6807
|
+
rangeLayerRef.current?.applyViewport(viewportRef.current);
|
|
5866
6808
|
});
|
|
5867
6809
|
const unsubscribeZoom = wavesurfer.on('zoom', () => {
|
|
5868
6810
|
if (suppressViewportSyncRef.current) {
|
|
@@ -5871,22 +6813,28 @@ function WaveformView({
|
|
|
5871
6813
|
syncViewport();
|
|
5872
6814
|
});
|
|
5873
6815
|
const unsubscribeRedraw = wavesurfer.on('redrawcomplete', () => {
|
|
5874
|
-
if (!(zoomRef.current > constants/* WAVEFORM_ZOOM_MIN */.LW)) {
|
|
6816
|
+
if (!(zoomRef.current > constants/* WAVEFORM_ZOOM_MIN */.LW) && cameraModeRef.current !== 'tape') {
|
|
5875
6817
|
return;
|
|
5876
6818
|
}
|
|
5877
6819
|
tintZoomedWaveform(wavesurfer, getWaveformFills({
|
|
5878
6820
|
bufferProgress: bufferProgressRef.current,
|
|
5879
|
-
hoverProgress: hoverProgressRef.current
|
|
6821
|
+
hoverProgress: cameraModeRef.current === 'tape' ? null : hoverProgressRef.current,
|
|
6822
|
+
isTape: cameraModeRef.current === 'tape',
|
|
6823
|
+
rangeProgress: rangeProgressRef.current
|
|
5880
6824
|
}), true);
|
|
5881
6825
|
});
|
|
5882
6826
|
wavesurferRef.current = wavesurfer;
|
|
5883
6827
|
displayedPeaksRef.current = peaksRef.current;
|
|
6828
|
+
lastSetTimeSecRef.current = null;
|
|
5884
6829
|
disableScrollOverscroll(container);
|
|
5885
6830
|
syncViewport();
|
|
5886
6831
|
applyZoomWindowRef.current?.();
|
|
5887
6832
|
return () => {
|
|
5888
6833
|
releaseUserPanHold();
|
|
5889
6834
|
cancelJump();
|
|
6835
|
+
window.clearTimeout(hideScrubTimeChipTimerRef.current);
|
|
6836
|
+
window.clearTimeout(suppressNextTapPlayPauseTimerRef.current);
|
|
6837
|
+
window.cancelAnimationFrame(tapeSeekAnimationRef.current);
|
|
5890
6838
|
window.cancelAnimationFrame(peakTransitionAnimationRef.current);
|
|
5891
6839
|
unsubscribeClick();
|
|
5892
6840
|
unsubscribeScroll();
|
|
@@ -5895,19 +6843,41 @@ function WaveformView({
|
|
|
5895
6843
|
wavesurfer.destroy();
|
|
5896
6844
|
wavesurferRef.current = null;
|
|
5897
6845
|
displayedPeaksRef.current = null;
|
|
6846
|
+
lastSetTimeSecRef.current = null;
|
|
5898
6847
|
};
|
|
5899
|
-
}, [cancelJump, handleCameraScroll, height, releaseUserPanHold, syncViewport]);
|
|
6848
|
+
}, [cancelJump, handleCameraScroll, handleTapeSwipe, height, isUserPanning, releaseUserPanHold, syncViewport]);
|
|
5900
6849
|
(0,external_react_.useLayoutEffect)(() => {
|
|
5901
6850
|
const el = containerRef.current;
|
|
5902
6851
|
if (!el) {
|
|
5903
6852
|
return undefined;
|
|
5904
6853
|
}
|
|
5905
6854
|
setCanvasWidthPx(el.clientWidth);
|
|
6855
|
+
lastObservedWidthRef.current = el.clientWidth;
|
|
6856
|
+
const mountedHeight = Math.round(el.clientHeight);
|
|
6857
|
+
if (cameraModeRef.current === 'tape' && mountedHeight > 0) {
|
|
6858
|
+
liveHeightRef.current = mountedHeight;
|
|
6859
|
+
}
|
|
5906
6860
|
const observer = new ResizeObserver(entries => {
|
|
5907
6861
|
entries.forEach(entry => {
|
|
5908
|
-
|
|
6862
|
+
const nextWidth = entry.contentRect.width;
|
|
6863
|
+
const widthChanged = nextWidth !== lastObservedWidthRef.current;
|
|
6864
|
+
lastObservedWidthRef.current = nextWidth;
|
|
6865
|
+
setCanvasWidthPx(nextWidth);
|
|
6866
|
+
const nextHeight = Math.round(entry.contentRect.height);
|
|
6867
|
+
if (cameraModeRef.current === 'tape' && Number.isFinite(nextHeight) && nextHeight > 0 && nextHeight !== liveHeightRef.current) {
|
|
6868
|
+
liveHeightRef.current = nextHeight;
|
|
6869
|
+
const wavesurfer = wavesurferRef.current;
|
|
6870
|
+
if (wavesurfer && wavesurfer.setOptions) {
|
|
6871
|
+
wavesurfer.setOptions({
|
|
6872
|
+
height: nextHeight
|
|
6873
|
+
});
|
|
6874
|
+
}
|
|
6875
|
+
}
|
|
6876
|
+
syncViewport();
|
|
6877
|
+
if (widthChanged) {
|
|
6878
|
+
applyZoomWindowRef.current?.();
|
|
6879
|
+
}
|
|
5909
6880
|
});
|
|
5910
|
-
syncViewport();
|
|
5911
6881
|
});
|
|
5912
6882
|
observer.observe(el);
|
|
5913
6883
|
return () => observer.disconnect();
|
|
@@ -5932,7 +6902,7 @@ function WaveformView({
|
|
|
5932
6902
|
return;
|
|
5933
6903
|
}
|
|
5934
6904
|
wavesurfer.setOptions({
|
|
5935
|
-
interact: interactive
|
|
6905
|
+
interact: interactive && cameraModeRef.current !== 'tape'
|
|
5936
6906
|
});
|
|
5937
6907
|
}, [interactive]);
|
|
5938
6908
|
(0,external_react_.useLayoutEffect)(() => {
|
|
@@ -5963,13 +6933,17 @@ function WaveformView({
|
|
|
5963
6933
|
window.cancelAnimationFrame(playheadAnimationRef.current);
|
|
5964
6934
|
cancelJump();
|
|
5965
6935
|
releaseUserPanHold();
|
|
5966
|
-
|
|
6936
|
+
if (cameraModeRef.current !== 'tape') {
|
|
6937
|
+
clearFollowPin();
|
|
6938
|
+
}
|
|
5967
6939
|
syncViewport();
|
|
5968
6940
|
updatePlayheadPosition(media.currentTime);
|
|
5969
6941
|
};
|
|
5970
6942
|
const handleSeeked = () => {
|
|
5971
6943
|
onPlayheadSeek(media.currentTime);
|
|
5972
|
-
|
|
6944
|
+
if (!isUserPanning()) {
|
|
6945
|
+
seekTo(media.currentTime);
|
|
6946
|
+
}
|
|
5973
6947
|
updatePlayheadPosition(media.currentTime);
|
|
5974
6948
|
};
|
|
5975
6949
|
if (!media.paused) {
|
|
@@ -5988,7 +6962,7 @@ function WaveformView({
|
|
|
5988
6962
|
media.removeEventListener('pause', stopLoop);
|
|
5989
6963
|
media.removeEventListener('seeked', handleSeeked);
|
|
5990
6964
|
};
|
|
5991
|
-
}, [applyPlayheadCamera, cancelJump, clearFollowPin, mediaEl, onPlayheadSeek, releaseUserPanHold, seekTo, syncViewport, updatePlayheadPosition]);
|
|
6965
|
+
}, [applyPlayheadCamera, cancelJump, clearFollowPin, isUserPanning, mediaEl, onPlayheadSeek, releaseUserPanHold, seekTo, syncViewport, updatePlayheadPosition]);
|
|
5992
6966
|
(0,external_react_.useEffect)(() => {
|
|
5993
6967
|
const wavesurfer = wavesurferRef.current;
|
|
5994
6968
|
if (!wavesurfer || !wavesurfer.setOptions || !(durationSec > 0)) {
|
|
@@ -6023,9 +6997,11 @@ function WaveformView({
|
|
|
6023
6997
|
}
|
|
6024
6998
|
const fills = getWaveformFills({
|
|
6025
6999
|
bufferProgress,
|
|
6026
|
-
hoverProgress
|
|
7000
|
+
hoverProgress: isTape ? null : hoverProgress,
|
|
7001
|
+
isTape,
|
|
7002
|
+
rangeProgress: activeRangeProgress
|
|
6027
7003
|
});
|
|
6028
|
-
if (
|
|
7004
|
+
if (isScrollableWindow) {
|
|
6029
7005
|
tintZoomedWaveform(wavesurfer, fills);
|
|
6030
7006
|
return;
|
|
6031
7007
|
}
|
|
@@ -6033,8 +7009,9 @@ function WaveformView({
|
|
|
6033
7009
|
progressColor: toCanvasFill(fills.progressColor, devicePixelWidth(canvasWidthPx)),
|
|
6034
7010
|
waveColor: toCanvasFill(fills.waveColor, devicePixelWidth(canvasWidthPx))
|
|
6035
7011
|
});
|
|
7012
|
+
lastSetTimeSecRef.current = currentTimeRef.current;
|
|
6036
7013
|
wavesurfer.setTime(currentTimeRef.current);
|
|
6037
|
-
}, [bufferProgress, canvasWidthPx, hoverProgress, isZoomed]);
|
|
7014
|
+
}, [activeRangeProgress, bufferProgress, canvasWidthPx, hoverProgress, isRangeDragging, isScrollableWindow, isTape, isZoomed]);
|
|
6038
7015
|
(0,external_react_.useEffect)(() => {
|
|
6039
7016
|
const track = trackRef.current;
|
|
6040
7017
|
if (!track) {
|
|
@@ -6115,11 +7092,11 @@ function WaveformView({
|
|
|
6115
7092
|
};
|
|
6116
7093
|
}, [durationSec, markPointerZoom, setZoomLevel]);
|
|
6117
7094
|
const onHoverMove = (0,external_react_.useCallback)(event => {
|
|
6118
|
-
if (
|
|
7095
|
+
if (isTape || isTouchHoverInput(event)) {
|
|
6119
7096
|
return;
|
|
6120
7097
|
}
|
|
6121
7098
|
const rect = event.currentTarget.getBoundingClientRect();
|
|
6122
|
-
if (!(rect.width > 0)
|
|
7099
|
+
if (!(rect.width > 0)) {
|
|
6123
7100
|
return;
|
|
6124
7101
|
}
|
|
6125
7102
|
const pointerX = event.clientX - rect.left;
|
|
@@ -6127,24 +7104,81 @@ function WaveformView({
|
|
|
6127
7104
|
return;
|
|
6128
7105
|
}
|
|
6129
7106
|
const vp = viewportRef.current;
|
|
7107
|
+
const draft = activeRangeRef.current;
|
|
7108
|
+
setIsRangeHovered(!!draft && isPointerOverRange({
|
|
7109
|
+
pointerX,
|
|
7110
|
+
range: draft,
|
|
7111
|
+
viewport: vp
|
|
7112
|
+
}));
|
|
7113
|
+
if (!interactive || isRangeDraggingRef.current || !(durationSec > 0)) {
|
|
7114
|
+
return;
|
|
7115
|
+
}
|
|
6130
7116
|
if (vp.pixelsPerSecond > 0) {
|
|
6131
7117
|
setHoverProgress(Math.min(1, Math.max(0, timeFromPositionPx(pointerX, vp) / durationSec)));
|
|
6132
7118
|
return;
|
|
6133
7119
|
}
|
|
6134
7120
|
setHoverProgress(Math.min(1, Math.max(0, pointerX / rect.width)));
|
|
6135
|
-
}, [durationSec, interactive]);
|
|
7121
|
+
}, [durationSec, interactive, isTape]);
|
|
6136
7122
|
const onHoverLeave = (0,external_react_.useCallback)(() => {
|
|
6137
7123
|
setHoverProgress(null);
|
|
7124
|
+
setIsRangeHovered(false);
|
|
7125
|
+
}, []);
|
|
7126
|
+
const handleRangeDragChange = (0,external_react_.useCallback)(isDragging => {
|
|
7127
|
+
isRangeDraggingRef.current = isDragging;
|
|
7128
|
+
setIsRangeDragging(isDragging);
|
|
7129
|
+
if (isDragging) {
|
|
7130
|
+
setHoverProgress(null);
|
|
7131
|
+
} else {
|
|
7132
|
+
skipNextSeekRef.current = true;
|
|
7133
|
+
window.setTimeout(() => {
|
|
7134
|
+
skipNextSeekRef.current = false;
|
|
7135
|
+
}, 0);
|
|
7136
|
+
setPreviewRange(null);
|
|
7137
|
+
}
|
|
7138
|
+
onRangeDragChange?.(isDragging);
|
|
7139
|
+
}, [onRangeDragChange]);
|
|
7140
|
+
const getPlayheadSec = (0,external_react_.useCallback)(() => {
|
|
7141
|
+
return mediaElRef.current ? mediaElRef.current.currentTime : currentTimeRef.current;
|
|
7142
|
+
}, []);
|
|
7143
|
+
const bindOverlayPortalHost = (0,external_react_.useCallback)(node => {
|
|
7144
|
+
const host = node?.parentElement ?? null;
|
|
7145
|
+
setOverlayPortalHost(prev => prev === host ? prev : host);
|
|
6138
7146
|
}, []);
|
|
6139
|
-
const hoverLeft = hoverProgress == null ? null : timeLeftPercent(hoverProgress * durationSec, durationSec, viewportRef.current);
|
|
7147
|
+
const hoverLeft = isRangeDragging || hoverProgress == null ? null : timeLeftPercent(hoverProgress * durationSec, durationSec, viewportRef.current);
|
|
7148
|
+
const showRangeOverlay = Boolean(range) && (isRangeDragging || !isPlaying || !isRangeCollapsed(range));
|
|
7149
|
+
const scrubTimeChip = isTape && scrubPreviewTimeSec != null ? /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
7150
|
+
className: "bp-WaveformView-hover bp-WaveformView-hover--tape",
|
|
7151
|
+
"data-testid": "bp-waveform-hover"
|
|
7152
|
+
}, /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
7153
|
+
className: "bp-WaveformView-hoverTime",
|
|
7154
|
+
"data-testid": "bp-waveform-hover-time"
|
|
7155
|
+
}, formatTime(scrubPreviewTimeSec))) : null;
|
|
6140
7156
|
return /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
6141
|
-
|
|
7157
|
+
ref: bindOverlayPortalHost,
|
|
7158
|
+
className: classnames_default()('bp-WaveformView', {
|
|
7159
|
+
'bp-WaveformView--inert': !interactive,
|
|
7160
|
+
'bp-WaveformView--tape': isTape,
|
|
7161
|
+
'bp-WaveformView--zoomed': isZoomed
|
|
7162
|
+
}),
|
|
6142
7163
|
"data-testid": "bp-waveform-view"
|
|
6143
7164
|
}, /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
6144
7165
|
ref: trackRef,
|
|
6145
7166
|
className: "bp-WaveformView-track",
|
|
6146
|
-
onMouseLeave: interactive ? onHoverLeave : undefined,
|
|
6147
|
-
onMouseMove: interactive ? onHoverMove : undefined
|
|
7167
|
+
onMouseLeave: interactive && !isTape ? onHoverLeave : undefined,
|
|
7168
|
+
onMouseMove: interactive && !isTape ? onHoverMove : undefined,
|
|
7169
|
+
onPointerMove: interactive && !isTape ? event => {
|
|
7170
|
+
if (event.pointerType === 'touch') {
|
|
7171
|
+
onHoverLeave();
|
|
7172
|
+
return;
|
|
7173
|
+
}
|
|
7174
|
+
onHoverMove(event);
|
|
7175
|
+
} : undefined,
|
|
7176
|
+
onPointerUp: isTape ? event => {
|
|
7177
|
+
if (event.button > 0) {
|
|
7178
|
+
return;
|
|
7179
|
+
}
|
|
7180
|
+
toggleTapePlaybackRef.current?.();
|
|
7181
|
+
} : undefined
|
|
6148
7182
|
}, /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
6149
7183
|
ref: containerRef,
|
|
6150
7184
|
className: "bp-WaveformView-canvas"
|
|
@@ -6153,7 +7187,20 @@ function WaveformView({
|
|
|
6153
7187
|
"aria-hidden": "true",
|
|
6154
7188
|
className: "bp-WaveformView-playhead",
|
|
6155
7189
|
"data-testid": "bp-waveform-playhead"
|
|
6156
|
-
}),
|
|
7190
|
+
}), showRangeOverlay && range && /*#__PURE__*/external_react_["default"].createElement(waveform_WaveformRangeSelection, {
|
|
7191
|
+
ref: rangeLayerRef,
|
|
7192
|
+
currentTimeSec: currentTime,
|
|
7193
|
+
durationSec: durationSec,
|
|
7194
|
+
getPlayheadSec: getPlayheadSec,
|
|
7195
|
+
interactive: interactive,
|
|
7196
|
+
isHighlighted: isRangeDragging || isRangeHovered,
|
|
7197
|
+
keepHighlight: true,
|
|
7198
|
+
onDragChange: handleRangeDragChange,
|
|
7199
|
+
onPreviewChange: setPreviewRange,
|
|
7200
|
+
onRangeChange: interactive ? onRangeChange : undefined,
|
|
7201
|
+
range: range,
|
|
7202
|
+
viewport: viewport
|
|
7203
|
+
}), hoverLeft != null && hoverProgress != null && !isRangeDragging && /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
6157
7204
|
className: "bp-WaveformView-hover",
|
|
6158
7205
|
"data-testid": "bp-waveform-hover",
|
|
6159
7206
|
style: {
|
|
@@ -6162,12 +7209,9 @@ function WaveformView({
|
|
|
6162
7209
|
}, /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
6163
7210
|
className: "bp-WaveformView-hoverTime",
|
|
6164
7211
|
"data-testid": "bp-waveform-hover-time"
|
|
6165
|
-
}, formatTime(hoverProgress * durationSec)))));
|
|
7212
|
+
}, formatTime(hoverProgress * durationSec)))), scrubTimeChip && overlayPortalHost ? /*#__PURE__*/__WEBPACK_EXTERNAL_MODULE_react_dom_7dac9eee_createPortal__(scrubTimeChip, overlayPortalHost) : null);
|
|
6166
7213
|
}
|
|
6167
7214
|
/* 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
7215
|
;// ./src/lib/viewers/controls/icons/IconZoomIn24.tsx
|
|
6172
7216
|
|
|
6173
7217
|
function IconZoomIn24() {
|
|
@@ -6253,11 +7297,14 @@ function WaveformZoomControl({
|
|
|
6253
7297
|
}) {
|
|
6254
7298
|
const [isHovered, setHovered] = (0,external_react_.useState)(false);
|
|
6255
7299
|
const [isFocused, setFocused] = (0,external_react_.useState)(false);
|
|
6256
|
-
const
|
|
7300
|
+
const [isPinned, setPinned] = (0,external_react_.useState)(false);
|
|
7301
|
+
const wasFlyoutOpenOnPointerDownRef = (0,external_react_.useRef)(true); // first tap on + pins the flyout instead of zooming
|
|
7302
|
+
const zoomControlElRef = (0,external_react_.useRef)(null); // root; outside pointerdown unpins the flyout
|
|
7303
|
+
const dismissTimerRef = (0,external_react_.useRef)(0); // delay before hover-close of the flyout
|
|
6257
7304
|
const sliderId = `bp-waveform-zoom-slider${(0,external_react_.useId)()}`;
|
|
6258
7305
|
const zoom = clampWaveformZoom(zoomLevel, maxZoom);
|
|
6259
7306
|
const zoomValue = Math.round(sliderValueFromZoom(zoom, maxZoom));
|
|
6260
|
-
const isOpen = isHovered || isFocused || isRevealed;
|
|
7307
|
+
const isOpen = isHovered || isFocused || isRevealed || isPinned;
|
|
6261
7308
|
const isAtMinZoom = zoomValue <= 0;
|
|
6262
7309
|
const isAtMaxZoom = zoomValue >= constants/* WAVEFORM_ZOOM_SLIDER_MAX */.nh;
|
|
6263
7310
|
const clearDismiss = (0,external_react_.useCallback)(() => {
|
|
@@ -6265,13 +7312,42 @@ function WaveformZoomControl({
|
|
|
6265
7312
|
dismissTimerRef.current = 0;
|
|
6266
7313
|
}, []);
|
|
6267
7314
|
(0,external_react_.useEffect)(() => () => window.clearTimeout(dismissTimerRef.current), []);
|
|
7315
|
+
(0,external_react_.useEffect)(() => {
|
|
7316
|
+
if (!isPinned) {
|
|
7317
|
+
return undefined;
|
|
7318
|
+
}
|
|
7319
|
+
const closeIfOutside = event => {
|
|
7320
|
+
const zoomControlEl = zoomControlElRef.current;
|
|
7321
|
+
if (!zoomControlEl || zoomControlEl.contains(event.target)) {
|
|
7322
|
+
return;
|
|
7323
|
+
}
|
|
7324
|
+
setPinned(false);
|
|
7325
|
+
setFocused(false);
|
|
7326
|
+
setHovered(false);
|
|
7327
|
+
};
|
|
7328
|
+
document.addEventListener('pointerdown', closeIfOutside);
|
|
7329
|
+
return () => document.removeEventListener('pointerdown', closeIfOutside);
|
|
7330
|
+
}, [isPinned]);
|
|
6268
7331
|
const handleSlider = (0,external_react_.useCallback)(newValue => {
|
|
6269
7332
|
onZoomChange(zoomFromSliderValue(newValue, maxZoom));
|
|
6270
7333
|
}, [maxZoom, onZoomChange]);
|
|
6271
7334
|
const handleStep = (0,external_react_.useCallback)(delta => {
|
|
6272
|
-
onZoomChange(
|
|
6273
|
-
}, [maxZoom, onZoomChange,
|
|
7335
|
+
onZoomChange(stepWaveformZoom(zoom, maxZoom, delta));
|
|
7336
|
+
}, [maxZoom, onZoomChange, zoom]);
|
|
7337
|
+
const handleZoomInPointerDown = (0,external_react_.useCallback)(() => {
|
|
7338
|
+
wasFlyoutOpenOnPointerDownRef.current = isHovered || isFocused || isRevealed || isPinned;
|
|
7339
|
+
}, [isFocused, isHovered, isPinned, isRevealed]);
|
|
7340
|
+
const handleZoomInClick = (0,external_react_.useCallback)(() => {
|
|
7341
|
+
if (!wasFlyoutOpenOnPointerDownRef.current) {
|
|
7342
|
+
setPinned(true);
|
|
7343
|
+
return;
|
|
7344
|
+
}
|
|
7345
|
+
if (!isAtMaxZoom) {
|
|
7346
|
+
handleStep(constants/* WAVEFORM_ZOOM_BUTTON_STEP */.QD);
|
|
7347
|
+
}
|
|
7348
|
+
}, [handleStep, isAtMaxZoom]);
|
|
6274
7349
|
return /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
7350
|
+
ref: zoomControlElRef,
|
|
6275
7351
|
"aria-label": "Zoom",
|
|
6276
7352
|
className: classnames_default()('bp-WaveformZoomControl', {
|
|
6277
7353
|
'bp-is-open': isOpen
|
|
@@ -6282,6 +7358,7 @@ function WaveformZoomControl({
|
|
|
6282
7358
|
return;
|
|
6283
7359
|
}
|
|
6284
7360
|
setFocused(false);
|
|
7361
|
+
setPinned(false);
|
|
6285
7362
|
},
|
|
6286
7363
|
onFocus: () => {
|
|
6287
7364
|
clearDismiss();
|
|
@@ -6299,15 +7376,12 @@ function WaveformZoomControl({
|
|
|
6299
7376
|
},
|
|
6300
7377
|
role: "group"
|
|
6301
7378
|
}, /*#__PURE__*/external_react_["default"].createElement(MediaToggle/* default */.A, {
|
|
6302
|
-
"aria-disabled": isAtMaxZoom,
|
|
7379
|
+
"aria-disabled": isOpen && isAtMaxZoom,
|
|
6303
7380
|
className: "bp-WaveformZoomControl-button",
|
|
6304
7381
|
"data-resin-target": "waveformZoomIn",
|
|
6305
7382
|
"data-testid": "bp-waveform-zoom-in",
|
|
6306
|
-
onClick:
|
|
6307
|
-
|
|
6308
|
-
handleStep(constants/* WAVEFORM_ZOOM_BUTTON_STEP */.QD);
|
|
6309
|
-
}
|
|
6310
|
-
},
|
|
7383
|
+
onClick: handleZoomInClick,
|
|
7384
|
+
onPointerDown: handleZoomInPointerDown,
|
|
6311
7385
|
title: "Zoom in"
|
|
6312
7386
|
}, /*#__PURE__*/external_react_["default"].createElement(icons_IconZoomIn24, null)), /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
6313
7387
|
"aria-hidden": !isOpen,
|
|
@@ -6361,6 +7435,7 @@ function WaveformZoomControl({
|
|
|
6361
7435
|
|
|
6362
7436
|
|
|
6363
7437
|
|
|
7438
|
+
|
|
6364
7439
|
const PLACEHOLDER_PEAKS = placeholderPeaks();
|
|
6365
7440
|
function MP3ControlsV2({
|
|
6366
7441
|
autoplay,
|
|
@@ -6368,7 +7443,10 @@ function MP3ControlsV2({
|
|
|
6368
7443
|
commentMarkers,
|
|
6369
7444
|
currentTime,
|
|
6370
7445
|
durationTime,
|
|
7446
|
+
hasStartedPlayback = false,
|
|
6371
7447
|
isPlaying,
|
|
7448
|
+
keyboardVolumeStep = 0,
|
|
7449
|
+
keyboardZoomStep = 0,
|
|
6372
7450
|
mediaEl,
|
|
6373
7451
|
onAutoplayChange,
|
|
6374
7452
|
onCommentMarkerClick,
|
|
@@ -6388,12 +7466,16 @@ function MP3ControlsV2({
|
|
|
6388
7466
|
const [zoomLevel, setZoomLevel] = (0,external_react_.useState)(constants/* WAVEFORM_ZOOM_MIN */.LW);
|
|
6389
7467
|
const [maxZoom, setMaxZoom] = (0,external_react_.useState)(constants/* WAVEFORM_ZOOM_MIN */.LW);
|
|
6390
7468
|
const [isZoomRevealed, setIsZoomRevealed] = (0,external_react_.useState)(false);
|
|
6391
|
-
const zoomRevealTimerRef = (0,external_react_.useRef)(0);
|
|
7469
|
+
const zoomRevealTimerRef = (0,external_react_.useRef)(0); // hides the zoom flyout after WAVEFORM_ZOOM_DISMISS_MS
|
|
6392
7470
|
const hasRealPeaks = !!(peaks && peaks.length);
|
|
6393
7471
|
const waveformPeaks = hasRealPeaks ? peaks : PLACEHOLDER_PEAKS;
|
|
6394
7472
|
const waveformDurationSec = hasWaveformDuration ? durationValue : PLACEHOLDER_DURATION_SEC;
|
|
6395
|
-
const [playRequested, setPlayRequested] = (0,external_react_.useState)(
|
|
7473
|
+
const [playRequested, setPlayRequested] = (0,external_react_.useState)(hasStartedPlayback);
|
|
6396
7474
|
const [viewport, setViewport] = (0,external_react_.useState)(null);
|
|
7475
|
+
const isTape = useTapeWaveform();
|
|
7476
|
+
const hasAppliedTapeDefaultZoomRef = (0,external_react_.useRef)(false); // ~10s window applied; reset to 1× when leaving tape
|
|
7477
|
+
const lastKeyboardZoomStepRef = (0,external_react_.useRef)(0); // last +/− step applied; skip re-step when maxZoom retriggers the effect
|
|
7478
|
+
const userChangedTapeZoomRef = (0,external_react_.useRef)(false); // pinch/wheel zoom; skip re-applying the 10s default
|
|
6397
7479
|
const handleViewportChange = (0,external_react_.useCallback)(next => {
|
|
6398
7480
|
setMaxZoom(prev => prev === next.maxZoom ? prev : next.maxZoom);
|
|
6399
7481
|
setViewport(prev => viewportEquals(prev, next) ? prev : next);
|
|
@@ -6407,18 +7489,52 @@ function MP3ControlsV2({
|
|
|
6407
7489
|
}, constants/* WAVEFORM_ZOOM_DISMISS_MS */.m6);
|
|
6408
7490
|
}, []);
|
|
6409
7491
|
const handleWaveformZoom = (0,external_react_.useCallback)(nextZoom => {
|
|
7492
|
+
userChangedTapeZoomRef.current = true;
|
|
6410
7493
|
setZoomLevel(nextZoom);
|
|
6411
7494
|
revealZoomControl();
|
|
6412
7495
|
}, [revealZoomControl]);
|
|
7496
|
+
(0,external_react_.useEffect)(() => {
|
|
7497
|
+
const steps = keyboardZoomStep - lastKeyboardZoomStepRef.current;
|
|
7498
|
+
if (!steps) {
|
|
7499
|
+
return;
|
|
7500
|
+
}
|
|
7501
|
+
lastKeyboardZoomStepRef.current = keyboardZoomStep;
|
|
7502
|
+
if (!(maxZoom > constants/* WAVEFORM_ZOOM_MIN */.LW)) {
|
|
7503
|
+
return;
|
|
7504
|
+
}
|
|
7505
|
+
userChangedTapeZoomRef.current = true;
|
|
7506
|
+
setZoomLevel(prev => stepWaveformZoom(prev, maxZoom, steps * constants/* WAVEFORM_ZOOM_BUTTON_STEP */.QD));
|
|
7507
|
+
revealZoomControl();
|
|
7508
|
+
}, [keyboardZoomStep, maxZoom, revealZoomControl]);
|
|
6413
7509
|
(0,external_react_.useEffect)(() => {
|
|
6414
7510
|
setZoomLevel(prev => clampWaveformZoom(prev, maxZoom));
|
|
6415
7511
|
}, [maxZoom]);
|
|
7512
|
+
(0,external_react_.useEffect)(() => {
|
|
7513
|
+
if (!isTape) {
|
|
7514
|
+
if (hasAppliedTapeDefaultZoomRef.current) {
|
|
7515
|
+
hasAppliedTapeDefaultZoomRef.current = false;
|
|
7516
|
+
userChangedTapeZoomRef.current = false;
|
|
7517
|
+
setZoomLevel(constants/* WAVEFORM_ZOOM_MIN */.LW);
|
|
7518
|
+
}
|
|
7519
|
+
return;
|
|
7520
|
+
}
|
|
7521
|
+
if (!hasWaveformDuration || !hasRealPeaks || !viewport || !(viewport.widthPx > 0)) {
|
|
7522
|
+
return;
|
|
7523
|
+
}
|
|
7524
|
+
if (userChangedTapeZoomRef.current) {
|
|
7525
|
+
hasAppliedTapeDefaultZoomRef.current = true;
|
|
7526
|
+
return;
|
|
7527
|
+
}
|
|
7528
|
+
const nextZoom = getTapeDefaultZoom(durationValue, Math.max(maxZoom, viewport.maxZoom));
|
|
7529
|
+
hasAppliedTapeDefaultZoomRef.current = true;
|
|
7530
|
+
setZoomLevel(prev => prev === nextZoom ? prev : nextZoom);
|
|
7531
|
+
}, [durationValue, hasRealPeaks, hasWaveformDuration, isTape, maxZoom, viewport]);
|
|
6416
7532
|
(0,external_react_.useEffect)(() => () => window.clearTimeout(zoomRevealTimerRef.current), []);
|
|
6417
7533
|
(0,external_react_.useEffect)(() => {
|
|
6418
|
-
if (isPlaying) {
|
|
7534
|
+
if (isPlaying || hasStartedPlayback) {
|
|
6419
7535
|
setPlayRequested(true);
|
|
6420
7536
|
}
|
|
6421
|
-
}, [isPlaying]);
|
|
7537
|
+
}, [hasStartedPlayback, isPlaying]);
|
|
6422
7538
|
const handlePlayOverlayClick = (0,external_react_.useCallback)(() => {
|
|
6423
7539
|
setPlayRequested(true);
|
|
6424
7540
|
onPlayPause(true);
|
|
@@ -6436,11 +7552,13 @@ function MP3ControlsV2({
|
|
|
6436
7552
|
}
|
|
6437
7553
|
onTimeChange(marker.time);
|
|
6438
7554
|
}, [onCommentMarkerClick, onPlayPause, onTimeChange]);
|
|
6439
|
-
const
|
|
6440
|
-
const
|
|
6441
|
-
const
|
|
7555
|
+
const hasStarted = playRequested || hasStartedPlayback;
|
|
7556
|
+
const isWaveformInteractive = hasStarted && hasMediaMetadata;
|
|
7557
|
+
const isWaitingToPlay = hasStarted && !hasMediaMetadata;
|
|
7558
|
+
const showPlayOverlay = !hasStarted && !isPlaying;
|
|
6442
7559
|
const hasZoomHandlers = hasRealPeaks && !showPlayOverlay;
|
|
6443
7560
|
const hasZoomControl = hasZoomHandlers && hasMediaMetadata && maxZoom > constants/* WAVEFORM_ZOOM_MIN */.LW;
|
|
7561
|
+
const waveformZoomLevel = isTape || hasZoomHandlers ? zoomLevel : constants/* WAVEFORM_ZOOM_MIN */.LW;
|
|
6444
7562
|
return /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
6445
7563
|
className: "bp-MP3ControlsV2",
|
|
6446
7564
|
"data-testid": "media-controls-wrapper-v2"
|
|
@@ -6450,18 +7568,22 @@ function MP3ControlsV2({
|
|
|
6450
7568
|
className: "bp-MP3ControlsV2-waveform"
|
|
6451
7569
|
}, /*#__PURE__*/external_react_["default"].createElement(waveform_WaveformView, {
|
|
6452
7570
|
bufferedRange: bufferedRange,
|
|
7571
|
+
cameraMode: isTape ? 'tape' : 'desktop',
|
|
6453
7572
|
currentTime: currentTime,
|
|
6454
7573
|
durationSec: waveformDurationSec,
|
|
6455
7574
|
interactive: isWaveformInteractive,
|
|
7575
|
+
isPlaying: isPlaying,
|
|
6456
7576
|
mediaEl: mediaEl,
|
|
7577
|
+
onPlayPause: isWaveformInteractive ? onPlayPause : undefined,
|
|
6457
7578
|
onSeek: isWaveformInteractive ? onTimeChange : undefined,
|
|
6458
7579
|
onViewportChange: hasRealPeaks ? handleViewportChange : undefined,
|
|
6459
7580
|
onZoomChange: hasZoomHandlers ? handleWaveformZoom : undefined,
|
|
6460
7581
|
peaks: waveformPeaks,
|
|
6461
|
-
zoomLevel:
|
|
7582
|
+
zoomLevel: waveformZoomLevel
|
|
6462
7583
|
}), /*#__PURE__*/external_react_["default"].createElement(WaveformCommentMarkers, {
|
|
6463
7584
|
commentMarkers: waveformMarkers,
|
|
6464
7585
|
durationSec: hasWaveformDuration ? durationValue : 0,
|
|
7586
|
+
isTape: isTape,
|
|
6465
7587
|
onCommentMarkerClick: handleCommentMarkerClick,
|
|
6466
7588
|
selectedId: selectedMarkerId,
|
|
6467
7589
|
viewport: viewport
|
|
@@ -6470,7 +7592,7 @@ function MP3ControlsV2({
|
|
|
6470
7592
|
}, /*#__PURE__*/external_react_["default"].createElement(WaveformZoomControl, {
|
|
6471
7593
|
isRevealed: isZoomRevealed,
|
|
6472
7594
|
maxZoom: maxZoom,
|
|
6473
|
-
onZoomChange:
|
|
7595
|
+
onZoomChange: handleWaveformZoom,
|
|
6474
7596
|
zoomLevel: zoomLevel
|
|
6475
7597
|
})), showPlayOverlay && /*#__PURE__*/external_react_["default"].createElement("button", {
|
|
6476
7598
|
className: "bp-MP3ControlsV2-playOverlay"
|
|
@@ -6504,7 +7626,8 @@ function MP3ControlsV2({
|
|
|
6504
7626
|
durationTime: durationValue
|
|
6505
7627
|
})), /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
6506
7628
|
className: "bp-MP3ControlsV2-group"
|
|
6507
|
-
}, /*#__PURE__*/external_react_["default"].createElement(VolumeControls/* default */.
|
|
7629
|
+
}, /*#__PURE__*/external_react_["default"].createElement(VolumeControls/* default */.Ay, {
|
|
7630
|
+
keyboardVolumeStep: keyboardVolumeStep,
|
|
6508
7631
|
onMuteChange: onMuteChange,
|
|
6509
7632
|
onVolumeChange: onVolumeChange,
|
|
6510
7633
|
volume: volume
|
|
@@ -6590,19 +7713,26 @@ function isFpsAvailable(player) {
|
|
|
6590
7713
|
(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
6591
7714
|
|
|
6592
7715
|
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
7716
|
+
/* harmony export */ Av: () => (/* binding */ WAVEFORM_TAPE_DEFAULT_WINDOW_SEC),
|
|
7717
|
+
/* harmony export */ BG: () => (/* binding */ WAVEFORM_RANGE_COLLAPSED_OFFSET_PX),
|
|
6593
7718
|
/* harmony export */ Bq: () => (/* binding */ WAVEFORM_PLAYHEAD_JUMP_MS),
|
|
6594
7719
|
/* harmony export */ DY: () => (/* binding */ WAVEFORM_BAR_RADIUS),
|
|
6595
7720
|
/* harmony export */ EB: () => (/* binding */ CLIENT_DECODE_MAX_COMPRESSED_BYTES),
|
|
6596
7721
|
/* harmony export */ FY: () => (/* binding */ MAX_PEAK_COUNT),
|
|
6597
7722
|
/* harmony export */ GQ: () => (/* binding */ DURATION_MISMATCH_TOLERANCE_SEC),
|
|
7723
|
+
/* harmony export */ IQ: () => (/* binding */ WAVEFORM_RANGE_SNAP_PX),
|
|
6598
7724
|
/* harmony export */ Kl: () => (/* binding */ WAVEFORM_MIN_VIEW_WINDOW_SEC),
|
|
6599
7725
|
/* harmony export */ LW: () => (/* binding */ WAVEFORM_ZOOM_MIN),
|
|
7726
|
+
/* harmony export */ Le: () => (/* binding */ TAPE_POINTER_MEDIA_QUERY),
|
|
6600
7727
|
/* harmony export */ Lu: () => (/* binding */ WAVEFORM_BAR_GAP),
|
|
6601
7728
|
/* harmony export */ NM: () => (/* binding */ WAVEFORM_FOLLOW_INSET_PX),
|
|
6602
7729
|
/* harmony export */ QD: () => (/* binding */ WAVEFORM_ZOOM_BUTTON_STEP),
|
|
6603
7730
|
/* harmony export */ XS: () => (/* binding */ WAVEFORM_BAR_MIN_HEIGHT),
|
|
6604
7731
|
/* harmony export */ Zs: () => (/* binding */ WAVEFORM_FOLLOW_SCROLL_SETTLE_MS),
|
|
7732
|
+
/* harmony export */ bX: () => (/* binding */ WAVEFORM_RANGE_MIN_DURATION_MS),
|
|
6605
7733
|
/* harmony export */ f3: () => (/* binding */ CLIENT_DECODE_PEAK_COUNT),
|
|
7734
|
+
/* harmony export */ fI: () => (/* binding */ WAVEFORM_TAPE_CLICK_SUPPRESS_MS),
|
|
7735
|
+
/* harmony export */ h1: () => (/* binding */ WAVEFORM_RANGE_HANDLE_LINE_PX),
|
|
6606
7736
|
/* harmony export */ i8: () => (/* binding */ PEAK_UNIT_MAX),
|
|
6607
7737
|
/* harmony export */ m6: () => (/* binding */ WAVEFORM_ZOOM_DISMISS_MS),
|
|
6608
7738
|
/* harmony export */ mJ: () => (/* binding */ PEAK_UNIT_MIN),
|
|
@@ -6610,10 +7740,12 @@ function isFpsAvailable(player) {
|
|
|
6610
7740
|
/* harmony export */ nh: () => (/* binding */ WAVEFORM_ZOOM_SLIDER_MAX),
|
|
6611
7741
|
/* harmony export */ oN: () => (/* binding */ WAVEFORM_HEIGHT),
|
|
6612
7742
|
/* harmony export */ qY: () => (/* binding */ MAX_PAYLOAD_BYTES),
|
|
7743
|
+
/* harmony export */ r0: () => (/* binding */ WAVEFORM_RANGE_HIT_AREA_PX),
|
|
6613
7744
|
/* harmony export */ sh: () => (/* binding */ WAVEFORM_PAYLOAD_VERSION),
|
|
6614
7745
|
/* harmony export */ tK: () => (/* binding */ WAVEFORM_ZOOM_MAX),
|
|
6615
7746
|
/* harmony export */ zo: () => (/* binding */ WAVEFORM_BAR_WIDTH)
|
|
6616
7747
|
/* harmony export */ });
|
|
7748
|
+
/* unused harmony exports WAVEFORM_RANGE_PLAYHEAD_GAP_PX, WAVEFORM_RANGE_GRIP_IN_MS, WAVEFORM_RANGE_GRIP_OUT_MS */
|
|
6617
7749
|
/** Current waveform payload schema version. Bump only with a migration path. */
|
|
6618
7750
|
const WAVEFORM_PAYLOAD_VERSION = 1;
|
|
6619
7751
|
|
|
@@ -6642,6 +7774,10 @@ const WAVEFORM_ZOOM_MIN = 1;
|
|
|
6642
7774
|
const WAVEFORM_ZOOM_MAX = 24;
|
|
6643
7775
|
/** Visible window never shorter than this. */
|
|
6644
7776
|
const WAVEFORM_MIN_VIEW_WINDOW_SEC = 4;
|
|
7777
|
+
/** Tape (phone/tablet) default: seconds of audio visible in the viewport. */
|
|
7778
|
+
const WAVEFORM_TAPE_DEFAULT_WINDOW_SEC = 10;
|
|
7779
|
+
/** Primary pointer is a finger, not a mouse/trackpad. */
|
|
7780
|
+
const TAPE_POINTER_MEDIA_QUERY = '(hover: none) and (pointer: coarse)';
|
|
6645
7781
|
const WAVEFORM_ZOOM_SLIDER_MAX = 100;
|
|
6646
7782
|
/** One click on zoom in/out moves this many units on the 0–100 slider. */
|
|
6647
7783
|
const WAVEFORM_ZOOM_BUTTON_STEP = 10;
|
|
@@ -6650,6 +7786,8 @@ const WAVEFORM_FOLLOW_INSET_PX = 200;
|
|
|
6650
7786
|
const WAVEFORM_PLAYHEAD_JUMP_MS = 400;
|
|
6651
7787
|
/** After the last user pan, wait this long before the camera may pin again. */
|
|
6652
7788
|
const WAVEFORM_FOLLOW_SCROLL_SETTLE_MS = 150;
|
|
7789
|
+
/** Ignore a WaveSurfer click after a tape swipe (iOS delayed click). Must outlast the scrub-chip hide. */
|
|
7790
|
+
const WAVEFORM_TAPE_CLICK_SUPPRESS_MS = 200;
|
|
6653
7791
|
const WAVEFORM_BAR_GAP = 2;
|
|
6654
7792
|
const WAVEFORM_BAR_WIDTH = 2;
|
|
6655
7793
|
const WAVEFORM_BAR_RADIUS = WAVEFORM_BAR_WIDTH / 2;
|
|
@@ -6657,6 +7795,24 @@ const WAVEFORM_BAR_RADIUS = WAVEFORM_BAR_WIDTH / 2;
|
|
|
6657
7795
|
const WAVEFORM_BAR_MIN_HEIGHT = WAVEFORM_BAR_WIDTH;
|
|
6658
7796
|
const WAVEFORM_HEIGHT = 140;
|
|
6659
7797
|
|
|
7798
|
+
/** Hit target centered on each range handle line. */
|
|
7799
|
+
const WAVEFORM_RANGE_HIT_AREA_PX = 24;
|
|
7800
|
+
/** Visible handle line and playhead width. */
|
|
7801
|
+
const WAVEFORM_RANGE_HANDLE_LINE_PX = 2;
|
|
7802
|
+
/** Screen gap between the playhead and each collapsed handle line. */
|
|
7803
|
+
const WAVEFORM_RANGE_PLAYHEAD_GAP_PX = 1;
|
|
7804
|
+
/**
|
|
7805
|
+
* Offset of each collapsed handle from the timestamp/playhead center so the
|
|
7806
|
+
* 2px lines sit 1px left and right of the 2px playhead.
|
|
7807
|
+
*/
|
|
7808
|
+
const WAVEFORM_RANGE_COLLAPSED_OFFSET_PX = WAVEFORM_RANGE_HANDLE_LINE_PX / 2 + WAVEFORM_RANGE_PLAYHEAD_GAP_PX + WAVEFORM_RANGE_HANDLE_LINE_PX / 2;
|
|
7809
|
+
/** Snap a dragging handle to the playhead when this close. */
|
|
7810
|
+
const WAVEFORM_RANGE_SNAP_PX = 8;
|
|
7811
|
+
/** Shortest committed range. Collapsed drafts (`endMs: null`) are exempt. */
|
|
7812
|
+
const WAVEFORM_RANGE_MIN_DURATION_MS = 250;
|
|
7813
|
+
const WAVEFORM_RANGE_GRIP_IN_MS = 150;
|
|
7814
|
+
const WAVEFORM_RANGE_GRIP_OUT_MS = 100;
|
|
7815
|
+
|
|
6660
7816
|
/***/ },
|
|
6661
7817
|
|
|
6662
7818
|
/***/ 4971
|
|
@@ -6701,6 +7857,12 @@ function isWaveformErrorCode(value) {
|
|
|
6701
7857
|
|
|
6702
7858
|
/** Visible slice of the timeline. Emitted whenever zoom, scroll, or width changes. */
|
|
6703
7859
|
|
|
7860
|
+
/** Navigator fields used to detect iPad, including iPadOS reporting itself as Mac. */
|
|
7861
|
+
|
|
7862
|
+
/** Window bits needed to choose tape vs desktop (coarse pointer + iPad). */
|
|
7863
|
+
|
|
7864
|
+
/** Desktop walks then pins near the right inset. Tape keeps the playhead at center. */
|
|
7865
|
+
|
|
6704
7866
|
/** One canvas linear-gradient stop. `offset` is 0–1 along the bar. */
|
|
6705
7867
|
|
|
6706
7868
|
/**
|
|
@@ -14161,7 +15323,7 @@ var x = (y) => {
|
|
|
14161
15323
|
var x = {}; __webpack_require__.d(x, y); return x
|
|
14162
15324
|
}
|
|
14163
15325
|
var y = (x) => (() => (x))
|
|
14164
|
-
module.exports = x({ ["createElement"]: () => (__WEBPACK_EXTERNAL_MODULE_react__.createElement), ["default"]: () => (__WEBPACK_EXTERNAL_MODULE_react__["default"]), ["useCallback"]: () => (__WEBPACK_EXTERNAL_MODULE_react__.useCallback), ["useEffect"]: () => (__WEBPACK_EXTERNAL_MODULE_react__.useEffect), ["useId"]: () => (__WEBPACK_EXTERNAL_MODULE_react__.useId), ["useLayoutEffect"]: () => (__WEBPACK_EXTERNAL_MODULE_react__.useLayoutEffect), ["useMemo"]: () => (__WEBPACK_EXTERNAL_MODULE_react__.useMemo), ["useRef"]: () => (__WEBPACK_EXTERNAL_MODULE_react__.useRef), ["useState"]: () => (__WEBPACK_EXTERNAL_MODULE_react__.useState) });
|
|
15326
|
+
module.exports = x({ ["createElement"]: () => (__WEBPACK_EXTERNAL_MODULE_react__.createElement), ["default"]: () => (__WEBPACK_EXTERNAL_MODULE_react__["default"]), ["forwardRef"]: () => (__WEBPACK_EXTERNAL_MODULE_react__.forwardRef), ["useCallback"]: () => (__WEBPACK_EXTERNAL_MODULE_react__.useCallback), ["useEffect"]: () => (__WEBPACK_EXTERNAL_MODULE_react__.useEffect), ["useId"]: () => (__WEBPACK_EXTERNAL_MODULE_react__.useId), ["useImperativeHandle"]: () => (__WEBPACK_EXTERNAL_MODULE_react__.useImperativeHandle), ["useLayoutEffect"]: () => (__WEBPACK_EXTERNAL_MODULE_react__.useLayoutEffect), ["useMemo"]: () => (__WEBPACK_EXTERNAL_MODULE_react__.useMemo), ["useRef"]: () => (__WEBPACK_EXTERNAL_MODULE_react__.useRef), ["useState"]: () => (__WEBPACK_EXTERNAL_MODULE_react__.useState) });
|
|
14165
15327
|
|
|
14166
15328
|
/***/ },
|
|
14167
15329
|
|
|
@@ -23055,7 +24217,7 @@ class Browser {
|
|
|
23055
24217
|
;// ./src/lib/Logger.js
|
|
23056
24218
|
/* eslint-disable no-undef */
|
|
23057
24219
|
const CLIENT_NAME = "box-content-preview";
|
|
23058
|
-
const CLIENT_VERSION = "3.
|
|
24220
|
+
const CLIENT_VERSION = "3.92.0";
|
|
23059
24221
|
/* eslint-enable no-undef */
|
|
23060
24222
|
|
|
23061
24223
|
class Logger {
|
|
@@ -34434,10 +35596,9 @@ class MediaBaseViewer extends viewers_BaseViewer {
|
|
|
34434
35596
|
const template = this.options.representation.content.url_template;
|
|
34435
35597
|
this.mediaEl.addEventListener('error', this.errorHandler);
|
|
34436
35598
|
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/
|
|
35599
|
+
if (lib_Browser.isIOS() && this.mediaEl.tagName === 'VIDEO') {
|
|
35600
|
+
// Unblocks loadeddata on iOS <video>. Do not set this on <audio>:
|
|
35601
|
+
// after tap-to-open, Safari will start playback.
|
|
34441
35602
|
this.mediaEl.autoplay = true;
|
|
34442
35603
|
}
|
|
34443
35604
|
const contentUrl = this.createContentUrlV2(template);
|
|
@@ -35693,7 +36854,7 @@ function MP3Controls({
|
|
|
35693
36854
|
isPlaying: isPlaying,
|
|
35694
36855
|
movePlayback: movePlayback,
|
|
35695
36856
|
onPlayPause: onPlayPause
|
|
35696
|
-
}), /*#__PURE__*/external_react_["default"].createElement(VolumeControls/* default */.
|
|
36857
|
+
}), /*#__PURE__*/external_react_["default"].createElement(VolumeControls/* default */.Ay, {
|
|
35697
36858
|
onMuteChange: onMuteChange,
|
|
35698
36859
|
onVolumeChange: onVolumeChange,
|
|
35699
36860
|
volume: volume
|
|
@@ -35766,6 +36927,57 @@ function MP3Viewer_toPrimitive(t, r) { if ("object" != typeof t || !t) return t;
|
|
|
35766
36927
|
|
|
35767
36928
|
|
|
35768
36929
|
const CSS_CLASS_MP3 = 'bp-media-mp3';
|
|
36930
|
+
const AUDIO_V2_SHUTTLE_RATES = [2, 4, 8, 16];
|
|
36931
|
+
const AUDIO_V2_SHUTTLE_TICK_MS = 50;
|
|
36932
|
+
const AUDIO_V2_SKIP_SEC = 1;
|
|
36933
|
+
const AUDIO_V2_SHIFT_SKIP_SEC = 5;
|
|
36934
|
+
|
|
36935
|
+
/**
|
|
36936
|
+
* Next J/L shuttle rate. Opposite direction starts at 2×.
|
|
36937
|
+
*
|
|
36938
|
+
* @param {number} currentRate
|
|
36939
|
+
* @param {boolean} sameDirection
|
|
36940
|
+
* @return {number} 2, 4, 8, or 16
|
|
36941
|
+
*/
|
|
36942
|
+
function nextShuttleRate(currentRate, sameDirection) {
|
|
36943
|
+
if (!sameDirection) {
|
|
36944
|
+
return AUDIO_V2_SHUTTLE_RATES[0];
|
|
36945
|
+
}
|
|
36946
|
+
const index = AUDIO_V2_SHUTTLE_RATES.indexOf(currentRate);
|
|
36947
|
+
if (index < 0) {
|
|
36948
|
+
return AUDIO_V2_SHUTTLE_RATES[0];
|
|
36949
|
+
}
|
|
36950
|
+
return AUDIO_V2_SHUTTLE_RATES[Math.min(index + 1, AUDIO_V2_SHUTTLE_RATES.length - 1)];
|
|
36951
|
+
}
|
|
36952
|
+
|
|
36953
|
+
/**
|
|
36954
|
+
* Next/previous comment marker for ↑/↓. Walks by id so same-time stacks each get a stop.
|
|
36955
|
+
*
|
|
36956
|
+
* @param {Array<Object>} markers
|
|
36957
|
+
* @param {Object} options
|
|
36958
|
+
* @param {number} options.direction -1 previous, 1 next
|
|
36959
|
+
* @param {string|null} options.selectedId
|
|
36960
|
+
* @param {number} options.time current playhead
|
|
36961
|
+
* @return {Object|null} marker to select
|
|
36962
|
+
*/
|
|
36963
|
+
function nextCommentMarker(markers, {
|
|
36964
|
+
direction,
|
|
36965
|
+
selectedId,
|
|
36966
|
+
time
|
|
36967
|
+
}) {
|
|
36968
|
+
const sorted = (markers || []).filter(marker => Number.isFinite(marker.time)).sort((left, right) => left.time - right.time || String(left.id).localeCompare(String(right.id)));
|
|
36969
|
+
if (!sorted.length) {
|
|
36970
|
+
return null;
|
|
36971
|
+
}
|
|
36972
|
+
const selectedIndex = sorted.findIndex(marker => marker.id === selectedId);
|
|
36973
|
+
if (selectedIndex >= 0) {
|
|
36974
|
+
return sorted[Math.max(0, Math.min(sorted.length - 1, selectedIndex + direction))];
|
|
36975
|
+
}
|
|
36976
|
+
if (direction > 0) {
|
|
36977
|
+
return sorted.find(marker => marker.time >= time) || sorted[sorted.length - 1];
|
|
36978
|
+
}
|
|
36979
|
+
return [...sorted].reverse().find(marker => marker.time <= time) || sorted[0];
|
|
36980
|
+
}
|
|
35769
36981
|
function createLoadFailedError(message) {
|
|
35770
36982
|
const error = new Error(message);
|
|
35771
36983
|
error.name = 'LOAD_FAILED';
|
|
@@ -35778,6 +36990,7 @@ class MP3Viewer extends media_MediaBaseViewer {
|
|
|
35778
36990
|
* @inheritdoc
|
|
35779
36991
|
*/
|
|
35780
36992
|
MP3Viewer_defineProperty(this, "handlePlayRequest", () => {
|
|
36993
|
+
this.exitShuttle();
|
|
35781
36994
|
this.userRequestedPlay = true;
|
|
35782
36995
|
this.togglePlay();
|
|
35783
36996
|
if (this.shouldRaceClientWaveformDecode() && this.isWaveformDecodeRetryPending && !this.hasUsedWaveformDecodePlayRetry) {
|
|
@@ -35794,6 +37007,7 @@ class MP3Viewer extends media_MediaBaseViewer {
|
|
|
35794
37007
|
* @return {void}
|
|
35795
37008
|
*/
|
|
35796
37009
|
MP3Viewer_defineProperty(this, "handlePlayPause", shouldPlay => {
|
|
37010
|
+
this.exitShuttle();
|
|
35797
37011
|
if (shouldPlay) {
|
|
35798
37012
|
this.handlePlayRequest();
|
|
35799
37013
|
return;
|
|
@@ -35803,19 +37017,25 @@ class MP3Viewer extends media_MediaBaseViewer {
|
|
|
35803
37017
|
MP3Viewer_defineProperty(this, "handleCommentMarkersUpdated", (markers = []) => {
|
|
35804
37018
|
this.commentMarkers = markers;
|
|
35805
37019
|
const selected = markers.find(marker => marker.isSelected);
|
|
35806
|
-
|
|
35807
|
-
|
|
35808
|
-
|
|
35809
|
-
|
|
35810
|
-
|
|
35811
|
-
this.
|
|
35812
|
-
|
|
35813
|
-
|
|
37020
|
+
|
|
37021
|
+
// Host echoes often omit isSelected. Keep hostSelectedMarkerId so ↑/↓ can
|
|
37022
|
+
// still walk other comments at the same time. Clear only when that id is gone.
|
|
37023
|
+
if (selected) {
|
|
37024
|
+
if (selected.id !== this.hostSelectedMarkerId) {
|
|
37025
|
+
this.hostSelectedMarkerId = selected.id;
|
|
37026
|
+
if (Number.isFinite(selected.time)) {
|
|
37027
|
+
this.pendingHostSelectedSeek = selected;
|
|
37028
|
+
this.applyPendingHostSelectedSeek();
|
|
37029
|
+
}
|
|
35814
37030
|
}
|
|
37031
|
+
} else if (this.hostSelectedMarkerId && !markers.some(marker => marker.id === this.hostSelectedMarkerId)) {
|
|
37032
|
+
this.hostSelectedMarkerId = null;
|
|
37033
|
+
this.pendingHostSelectedSeek = null;
|
|
35815
37034
|
}
|
|
35816
37035
|
this.renderUI();
|
|
35817
37036
|
});
|
|
35818
37037
|
MP3Viewer_defineProperty(this, "handleCommentMarkerClick", marker => {
|
|
37038
|
+
this.exitShuttle();
|
|
35819
37039
|
this.hostSelectedMarkerId = marker.id;
|
|
35820
37040
|
this.pendingHostSelectedSeek = marker;
|
|
35821
37041
|
if (this.mediaEl) {
|
|
@@ -35869,6 +37089,12 @@ class MP3Viewer extends media_MediaBaseViewer {
|
|
|
35869
37089
|
this.mediaEl = this.mediaContainerEl.appendChild(document.createElement('audio'));
|
|
35870
37090
|
this.mediaEl.setAttribute('preload', 'auto');
|
|
35871
37091
|
this.commentMarkers = [];
|
|
37092
|
+
this.hostSelectedMarkerId = null;
|
|
37093
|
+
this.shuttleDirection = null;
|
|
37094
|
+
this.shuttleRate = 0;
|
|
37095
|
+
this.reverseShuttleTimer = 0;
|
|
37096
|
+
this.keyboardVolumeStep = 0;
|
|
37097
|
+
this.keyboardZoomStep = 0;
|
|
35872
37098
|
}
|
|
35873
37099
|
bindCommentMarkersListener() {
|
|
35874
37100
|
if (!this.isAudioPlayerV2) {
|
|
@@ -35888,6 +37114,212 @@ class MP3Viewer extends media_MediaBaseViewer {
|
|
|
35888
37114
|
return this.featureEnabled(constants/* AUDIO_PLAYER_V2 */.Ku) && this.useReactControls();
|
|
35889
37115
|
}
|
|
35890
37116
|
|
|
37117
|
+
/**
|
|
37118
|
+
* V2 audio keymap. Flag off and video keep MediaBaseViewer.handleKeydownReact.
|
|
37119
|
+
* Alt is not in Preview's key decoder — read it from the native event.
|
|
37120
|
+
*
|
|
37121
|
+
* @param {string} key
|
|
37122
|
+
* @param {KeyboardEvent} [event]
|
|
37123
|
+
* @return {boolean} consumed
|
|
37124
|
+
*/
|
|
37125
|
+
onKeydown(key, event) {
|
|
37126
|
+
if (this.isAudioPlayerV2 && this.handleKeydownAudioV2(key, event)) {
|
|
37127
|
+
return true;
|
|
37128
|
+
}
|
|
37129
|
+
return super.onKeydown(key, event);
|
|
37130
|
+
}
|
|
37131
|
+
handleKeydownAudioV2(key, event) {
|
|
37132
|
+
const decoded = (key || '').toLowerCase();
|
|
37133
|
+
const altKey = !!(event && event.altKey);
|
|
37134
|
+
switch (decoded) {
|
|
37135
|
+
case 'space':
|
|
37136
|
+
this.toggleV2Play();
|
|
37137
|
+
return true;
|
|
37138
|
+
case 'k':
|
|
37139
|
+
this.exitShuttle();
|
|
37140
|
+
this.pause(undefined, true);
|
|
37141
|
+
return true;
|
|
37142
|
+
case 'j':
|
|
37143
|
+
this.shuttle('reverse');
|
|
37144
|
+
return true;
|
|
37145
|
+
case 'l':
|
|
37146
|
+
this.shuttle('forward');
|
|
37147
|
+
return true;
|
|
37148
|
+
case 'arrowleft':
|
|
37149
|
+
this.quickSeek(-AUDIO_V2_SKIP_SEC);
|
|
37150
|
+
return true;
|
|
37151
|
+
case 'arrowright':
|
|
37152
|
+
this.quickSeek(AUDIO_V2_SKIP_SEC);
|
|
37153
|
+
return true;
|
|
37154
|
+
case ',':
|
|
37155
|
+
this.frameStep('back');
|
|
37156
|
+
return true;
|
|
37157
|
+
case '.':
|
|
37158
|
+
this.frameStep('forward');
|
|
37159
|
+
return true;
|
|
37160
|
+
case 'arrowup':
|
|
37161
|
+
if (altKey || !(this.commentMarkers || []).some(marker => Number.isFinite(marker.time))) {
|
|
37162
|
+
this.stepKeyboardVolume(1);
|
|
37163
|
+
return true;
|
|
37164
|
+
}
|
|
37165
|
+
this.jumpToCommentMarker(-1);
|
|
37166
|
+
return true;
|
|
37167
|
+
case 'arrowdown':
|
|
37168
|
+
if (altKey || !(this.commentMarkers || []).some(marker => Number.isFinite(marker.time))) {
|
|
37169
|
+
this.stepKeyboardVolume(-1);
|
|
37170
|
+
return true;
|
|
37171
|
+
}
|
|
37172
|
+
this.jumpToCommentMarker(1);
|
|
37173
|
+
return true;
|
|
37174
|
+
case 'end':
|
|
37175
|
+
if (!this.mediaEl || !Number.isFinite(this.mediaEl.duration)) {
|
|
37176
|
+
return false;
|
|
37177
|
+
}
|
|
37178
|
+
this.exitShuttle();
|
|
37179
|
+
this.setMediaTime(this.mediaEl.duration);
|
|
37180
|
+
return true;
|
|
37181
|
+
case '0':
|
|
37182
|
+
case 'home':
|
|
37183
|
+
this.exitShuttle();
|
|
37184
|
+
return false;
|
|
37185
|
+
case 'shift+arrowleft':
|
|
37186
|
+
this.quickSeek(-AUDIO_V2_SHIFT_SKIP_SEC);
|
|
37187
|
+
return true;
|
|
37188
|
+
case 'shift+arrowright':
|
|
37189
|
+
this.quickSeek(AUDIO_V2_SHIFT_SKIP_SEC);
|
|
37190
|
+
return true;
|
|
37191
|
+
case 'i':
|
|
37192
|
+
case 'o':
|
|
37193
|
+
case '/':
|
|
37194
|
+
case 'shift+l':
|
|
37195
|
+
// Range UI is not on this branch yet. Consume so I/O/loop cannot
|
|
37196
|
+
// fall through to shuttle or Preview navigation.
|
|
37197
|
+
return true;
|
|
37198
|
+
case 'shift++':
|
|
37199
|
+
case '+':
|
|
37200
|
+
case '=':
|
|
37201
|
+
this.stepKeyboardZoom(1);
|
|
37202
|
+
return true;
|
|
37203
|
+
case '-':
|
|
37204
|
+
case 'shift+_':
|
|
37205
|
+
this.stepKeyboardZoom(-1);
|
|
37206
|
+
return true;
|
|
37207
|
+
default:
|
|
37208
|
+
return false;
|
|
37209
|
+
}
|
|
37210
|
+
}
|
|
37211
|
+
toggleV2Play() {
|
|
37212
|
+
const reverseShuttle = this.shuttleDirection === 'reverse';
|
|
37213
|
+
const wasPlaying = !!(this.mediaEl && !this.mediaEl.paused);
|
|
37214
|
+
this.exitShuttle();
|
|
37215
|
+
if (reverseShuttle || wasPlaying) {
|
|
37216
|
+
this.pause(undefined, true);
|
|
37217
|
+
return;
|
|
37218
|
+
}
|
|
37219
|
+
this.handlePlayRequest();
|
|
37220
|
+
}
|
|
37221
|
+
shuttle(direction) {
|
|
37222
|
+
const sameDirection = this.shuttleDirection === direction;
|
|
37223
|
+
const rate = nextShuttleRate(this.shuttleRate, sameDirection);
|
|
37224
|
+
if (direction === 'forward') {
|
|
37225
|
+
this.startForwardShuttle(rate);
|
|
37226
|
+
return;
|
|
37227
|
+
}
|
|
37228
|
+
this.startReverseShuttle(rate);
|
|
37229
|
+
}
|
|
37230
|
+
startForwardShuttle(rate) {
|
|
37231
|
+
this.stopReverseShuttle();
|
|
37232
|
+
this.shuttleDirection = 'forward';
|
|
37233
|
+
this.shuttleRate = rate;
|
|
37234
|
+
this.userRequestedPlay = true;
|
|
37235
|
+
const playPromise = this.play();
|
|
37236
|
+
if (this.mediaEl) {
|
|
37237
|
+
this.mediaEl.playbackRate = this.shuttleRate;
|
|
37238
|
+
}
|
|
37239
|
+
if (playPromise && typeof playPromise.then === 'function') {
|
|
37240
|
+
playPromise.then(() => {
|
|
37241
|
+
if (this.mediaEl && this.shuttleDirection === 'forward') {
|
|
37242
|
+
this.mediaEl.playbackRate = this.shuttleRate;
|
|
37243
|
+
}
|
|
37244
|
+
}).catch(() => {});
|
|
37245
|
+
}
|
|
37246
|
+
}
|
|
37247
|
+
startReverseShuttle(rate) {
|
|
37248
|
+
this.stopReverseShuttle();
|
|
37249
|
+
this.shuttleDirection = 'reverse';
|
|
37250
|
+
this.shuttleRate = rate;
|
|
37251
|
+
this.userRequestedPlay = true;
|
|
37252
|
+
this.pause(undefined, true);
|
|
37253
|
+
this.handleRate();
|
|
37254
|
+
this.reverseShuttleTimer = window.setInterval(() => {
|
|
37255
|
+
if (!this.mediaEl || this.mediaEl.currentTime <= 0) {
|
|
37256
|
+
this.exitShuttle();
|
|
37257
|
+
return;
|
|
37258
|
+
}
|
|
37259
|
+
this.quickSeek(-(this.shuttleRate * AUDIO_V2_SHUTTLE_TICK_MS / 1000));
|
|
37260
|
+
if (this.mediaEl.currentTime <= 0) {
|
|
37261
|
+
this.exitShuttle();
|
|
37262
|
+
}
|
|
37263
|
+
}, AUDIO_V2_SHUTTLE_TICK_MS);
|
|
37264
|
+
}
|
|
37265
|
+
stopReverseShuttle() {
|
|
37266
|
+
if (this.reverseShuttleTimer) {
|
|
37267
|
+
window.clearInterval(this.reverseShuttleTimer);
|
|
37268
|
+
this.reverseShuttleTimer = 0;
|
|
37269
|
+
}
|
|
37270
|
+
}
|
|
37271
|
+
exitShuttle() {
|
|
37272
|
+
const wasShuttling = !!this.shuttleDirection;
|
|
37273
|
+
this.stopReverseShuttle();
|
|
37274
|
+
this.shuttleDirection = null;
|
|
37275
|
+
this.shuttleRate = 0;
|
|
37276
|
+
if (wasShuttling) {
|
|
37277
|
+
this.handleRate();
|
|
37278
|
+
}
|
|
37279
|
+
}
|
|
37280
|
+
|
|
37281
|
+
/**
|
|
37282
|
+
* Keep the settings rate unless forward shuttle owns playbackRate.
|
|
37283
|
+
*
|
|
37284
|
+
* @inheritdoc
|
|
37285
|
+
*/
|
|
37286
|
+
handleRate() {
|
|
37287
|
+
if (this.shuttleDirection === 'forward' && this.shuttleRate > 0 && this.mediaEl) {
|
|
37288
|
+
this.mediaEl.playbackRate = this.shuttleRate;
|
|
37289
|
+
if (this.controls) {
|
|
37290
|
+
this.renderUI();
|
|
37291
|
+
}
|
|
37292
|
+
return;
|
|
37293
|
+
}
|
|
37294
|
+
super.handleRate();
|
|
37295
|
+
}
|
|
37296
|
+
jumpToCommentMarker(direction) {
|
|
37297
|
+
if (!this.mediaEl) {
|
|
37298
|
+
return;
|
|
37299
|
+
}
|
|
37300
|
+
const target = nextCommentMarker(this.commentMarkers, {
|
|
37301
|
+
direction,
|
|
37302
|
+
selectedId: this.hostSelectedMarkerId,
|
|
37303
|
+
time: this.mediaEl.currentTime
|
|
37304
|
+
});
|
|
37305
|
+
if (!target || target.id === this.hostSelectedMarkerId) {
|
|
37306
|
+
return;
|
|
37307
|
+
}
|
|
37308
|
+
this.handleCommentMarkerClick(target);
|
|
37309
|
+
}
|
|
37310
|
+
stepKeyboardVolume(direction) {
|
|
37311
|
+
this.keyboardVolumeStep += 1;
|
|
37312
|
+
if (direction > 0) {
|
|
37313
|
+
this.increaseVolume();
|
|
37314
|
+
return;
|
|
37315
|
+
}
|
|
37316
|
+
this.decreaseVolume();
|
|
37317
|
+
}
|
|
37318
|
+
stepKeyboardZoom(direction) {
|
|
37319
|
+
this.keyboardZoomStep += direction;
|
|
37320
|
+
this.renderUI();
|
|
37321
|
+
}
|
|
37322
|
+
|
|
35891
37323
|
/**
|
|
35892
37324
|
* Load v2 controls (and wavesurfer) only when the audio player v2 gate is on.
|
|
35893
37325
|
*
|
|
@@ -35930,7 +37362,7 @@ class MP3Viewer extends media_MediaBaseViewer {
|
|
|
35930
37362
|
* @return {Promise<{ default: Function }>} MP3ControlsV2 module
|
|
35931
37363
|
*/
|
|
35932
37364
|
importV2Controls() {
|
|
35933
|
-
return Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__,
|
|
37365
|
+
return Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, 7450));
|
|
35934
37366
|
}
|
|
35935
37367
|
|
|
35936
37368
|
/**
|
|
@@ -35953,6 +37385,9 @@ class MP3Viewer extends media_MediaBaseViewer {
|
|
|
35953
37385
|
*/
|
|
35954
37386
|
destroy() {
|
|
35955
37387
|
this.removeListener('comment_markers', this.handleCommentMarkersUpdated);
|
|
37388
|
+
this.stopReverseShuttle();
|
|
37389
|
+
this.shuttleDirection = null;
|
|
37390
|
+
this.shuttleRate = 0;
|
|
35956
37391
|
this.abortWaveformLoads();
|
|
35957
37392
|
super.destroy();
|
|
35958
37393
|
}
|
|
@@ -36328,6 +37763,7 @@ class MP3Viewer extends media_MediaBaseViewer {
|
|
|
36328
37763
|
return;
|
|
36329
37764
|
}
|
|
36330
37765
|
this.pendingHostSelectedSeek = null;
|
|
37766
|
+
this.exitShuttle();
|
|
36331
37767
|
this.mediaEl.pause();
|
|
36332
37768
|
if (this.mediaEl.currentTime !== marker.time) {
|
|
36333
37769
|
this.mediaEl.currentTime = marker.time;
|
|
@@ -36370,6 +37806,9 @@ class MP3Viewer extends media_MediaBaseViewer {
|
|
|
36370
37806
|
const Mp3ControlsV2 = this.MP3ControlsV2;
|
|
36371
37807
|
this.controls.render(/*#__PURE__*/external_react_["default"].createElement(Mp3ControlsV2, MP3Viewer_extends({}, sharedProps, {
|
|
36372
37808
|
commentMarkers: this.commentMarkers || [],
|
|
37809
|
+
hasStartedPlayback: !!this.userRequestedPlay,
|
|
37810
|
+
keyboardVolumeStep: this.keyboardVolumeStep,
|
|
37811
|
+
keyboardZoomStep: this.keyboardZoomStep,
|
|
36373
37812
|
mediaEl: this.mediaEl,
|
|
36374
37813
|
onCommentMarkerClick: this.handleCommentMarkerClick,
|
|
36375
37814
|
peaks: this.waveformPeaks
|
|
@@ -37968,7 +39407,7 @@ function VideoControls({
|
|
|
37968
39407
|
onPlayPause: onPlayPause
|
|
37969
39408
|
})), /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
37970
39409
|
className: "bp-VideoControls-group bp-VideoControls-group--media-controls"
|
|
37971
|
-
}, /*#__PURE__*/external_react_["default"].createElement(VolumeControls/* default */.
|
|
39410
|
+
}, /*#__PURE__*/external_react_["default"].createElement(VolumeControls/* default */.Ay, {
|
|
37972
39411
|
onMuteChange: onMuteChange,
|
|
37973
39412
|
onVolumeChange: onVolumeChange,
|
|
37974
39413
|
volume: volume
|
|
@@ -38527,7 +39966,7 @@ function VideoControlsV2({
|
|
|
38527
39966
|
mediaEl: mediaEl
|
|
38528
39967
|
})), /*#__PURE__*/external_react_["default"].createElement("div", {
|
|
38529
39968
|
className: "bp-VideoControlsV2-group bp-VideoControlsV2-group--right"
|
|
38530
|
-
}, /*#__PURE__*/external_react_["default"].createElement(VolumeControls/* default */.
|
|
39969
|
+
}, /*#__PURE__*/external_react_["default"].createElement(VolumeControls/* default */.Ay, {
|
|
38531
39970
|
onMuteChange: onMuteChange,
|
|
38532
39971
|
onVolumeChange: onVolumeChange,
|
|
38533
39972
|
volume: volume
|