@waveform-playlist/ui-components 6.0.2 → 7.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +69 -3
- package/dist/index.d.ts +69 -3
- package/dist/index.js +585 -306
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +558 -277
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -5
package/dist/index.js
CHANGED
|
@@ -60,13 +60,16 @@ __export(index_exports, {
|
|
|
60
60
|
InlineLabel: () => InlineLabel,
|
|
61
61
|
LoopRegion: () => LoopRegion,
|
|
62
62
|
LoopRegionMarkers: () => LoopRegionMarkers,
|
|
63
|
+
MAX_CANVAS_WIDTH: () => MAX_CANVAS_WIDTH,
|
|
63
64
|
MasterVolumeControl: () => MasterVolumeControl,
|
|
64
65
|
Playhead: () => Playhead,
|
|
65
66
|
PlayheadWithMarker: () => PlayheadWithMarker,
|
|
66
67
|
Playlist: () => Playlist,
|
|
68
|
+
PlaylistErrorBoundary: () => PlaylistErrorBoundary,
|
|
67
69
|
PlaylistInfoContext: () => PlaylistInfoContext,
|
|
68
70
|
PlayoutProvider: () => PlayoutProvider,
|
|
69
71
|
ScreenReaderOnly: () => ScreenReaderOnly,
|
|
72
|
+
ScrollViewportProvider: () => ScrollViewportProvider,
|
|
70
73
|
Selection: () => Selection,
|
|
71
74
|
SelectionTimeInputs: () => SelectionTimeInputs,
|
|
72
75
|
Slider: () => Slider,
|
|
@@ -102,6 +105,8 @@ __export(index_exports, {
|
|
|
102
105
|
usePlaylistInfo: () => usePlaylistInfo,
|
|
103
106
|
usePlayoutStatus: () => usePlayoutStatus,
|
|
104
107
|
usePlayoutStatusUpdate: () => usePlayoutStatusUpdate,
|
|
108
|
+
useScrollViewport: () => useScrollViewport,
|
|
109
|
+
useScrollViewportSelector: () => useScrollViewportSelector,
|
|
105
110
|
useTheme: () => useTheme2,
|
|
106
111
|
useTrackControls: () => useTrackControls,
|
|
107
112
|
waveformColorToCss: () => waveformColorToCss
|
|
@@ -437,7 +442,7 @@ var AutomaticScrollCheckbox = ({
|
|
|
437
442
|
};
|
|
438
443
|
|
|
439
444
|
// src/components/Channel.tsx
|
|
440
|
-
var
|
|
445
|
+
var import_react2 = require("react");
|
|
441
446
|
var import_styled_components9 = __toESM(require("styled-components"));
|
|
442
447
|
|
|
443
448
|
// src/wfpl-theme.ts
|
|
@@ -597,9 +602,105 @@ var darkTheme = {
|
|
|
597
602
|
fontSizeSmall: "12px"
|
|
598
603
|
};
|
|
599
604
|
|
|
600
|
-
// src/
|
|
605
|
+
// src/contexts/ScrollViewport.tsx
|
|
606
|
+
var import_react = require("react");
|
|
601
607
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
608
|
+
var ViewportStore = class {
|
|
609
|
+
constructor() {
|
|
610
|
+
this._state = null;
|
|
611
|
+
this._listeners = /* @__PURE__ */ new Set();
|
|
612
|
+
this.subscribe = (callback) => {
|
|
613
|
+
this._listeners.add(callback);
|
|
614
|
+
return () => this._listeners.delete(callback);
|
|
615
|
+
};
|
|
616
|
+
this.getSnapshot = () => this._state;
|
|
617
|
+
}
|
|
618
|
+
/**
|
|
619
|
+
* Update viewport state. Applies a 100px scroll threshold to skip updates
|
|
620
|
+
* that don't affect chunk visibility (1000px chunks with 1.5× overscan buffer).
|
|
621
|
+
* Only notifies listeners when the state actually changes.
|
|
622
|
+
*/
|
|
623
|
+
update(scrollLeft, containerWidth) {
|
|
624
|
+
const buffer = containerWidth * 1.5;
|
|
625
|
+
const visibleStart = Math.max(0, scrollLeft - buffer);
|
|
626
|
+
const visibleEnd = scrollLeft + containerWidth + buffer;
|
|
627
|
+
if (this._state && this._state.containerWidth === containerWidth && Math.abs(this._state.scrollLeft - scrollLeft) < 100) {
|
|
628
|
+
return;
|
|
629
|
+
}
|
|
630
|
+
this._state = { scrollLeft, containerWidth, visibleStart, visibleEnd };
|
|
631
|
+
for (const listener of this._listeners) {
|
|
632
|
+
listener();
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
};
|
|
636
|
+
var ViewportStoreContext = (0, import_react.createContext)(null);
|
|
637
|
+
var EMPTY_SUBSCRIBE = () => () => {
|
|
638
|
+
};
|
|
639
|
+
var NULL_SNAPSHOT = () => null;
|
|
640
|
+
var ScrollViewportProvider = ({
|
|
641
|
+
containerRef,
|
|
642
|
+
children
|
|
643
|
+
}) => {
|
|
644
|
+
const storeRef = (0, import_react.useRef)(null);
|
|
645
|
+
if (storeRef.current === null) {
|
|
646
|
+
storeRef.current = new ViewportStore();
|
|
647
|
+
}
|
|
648
|
+
const store = storeRef.current;
|
|
649
|
+
const rafIdRef = (0, import_react.useRef)(null);
|
|
650
|
+
const measure = (0, import_react.useCallback)(() => {
|
|
651
|
+
const el = containerRef.current;
|
|
652
|
+
if (!el) return;
|
|
653
|
+
store.update(el.scrollLeft, el.clientWidth);
|
|
654
|
+
}, [containerRef, store]);
|
|
655
|
+
const scheduleUpdate = (0, import_react.useCallback)(() => {
|
|
656
|
+
if (rafIdRef.current !== null) return;
|
|
657
|
+
rafIdRef.current = requestAnimationFrame(() => {
|
|
658
|
+
rafIdRef.current = null;
|
|
659
|
+
measure();
|
|
660
|
+
});
|
|
661
|
+
}, [measure]);
|
|
662
|
+
(0, import_react.useEffect)(() => {
|
|
663
|
+
const el = containerRef.current;
|
|
664
|
+
if (!el) return;
|
|
665
|
+
measure();
|
|
666
|
+
el.addEventListener("scroll", scheduleUpdate, { passive: true });
|
|
667
|
+
const resizeObserver = new ResizeObserver(() => {
|
|
668
|
+
scheduleUpdate();
|
|
669
|
+
});
|
|
670
|
+
resizeObserver.observe(el);
|
|
671
|
+
return () => {
|
|
672
|
+
el.removeEventListener("scroll", scheduleUpdate);
|
|
673
|
+
resizeObserver.disconnect();
|
|
674
|
+
if (rafIdRef.current !== null) {
|
|
675
|
+
cancelAnimationFrame(rafIdRef.current);
|
|
676
|
+
rafIdRef.current = null;
|
|
677
|
+
}
|
|
678
|
+
};
|
|
679
|
+
}, [containerRef, measure, scheduleUpdate]);
|
|
680
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ViewportStoreContext.Provider, { value: store, children });
|
|
681
|
+
};
|
|
682
|
+
var useScrollViewport = () => {
|
|
683
|
+
const store = (0, import_react.useContext)(ViewportStoreContext);
|
|
684
|
+
return (0, import_react.useSyncExternalStore)(
|
|
685
|
+
store ? store.subscribe : EMPTY_SUBSCRIBE,
|
|
686
|
+
store ? store.getSnapshot : NULL_SNAPSHOT,
|
|
687
|
+
NULL_SNAPSHOT
|
|
688
|
+
);
|
|
689
|
+
};
|
|
690
|
+
function useScrollViewportSelector(selector) {
|
|
691
|
+
const store = (0, import_react.useContext)(ViewportStoreContext);
|
|
692
|
+
return (0, import_react.useSyncExternalStore)(
|
|
693
|
+
store ? store.subscribe : EMPTY_SUBSCRIBE,
|
|
694
|
+
() => selector(store ? store.getSnapshot() : null),
|
|
695
|
+
() => selector(null)
|
|
696
|
+
);
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
// src/constants.ts
|
|
602
700
|
var MAX_CANVAS_WIDTH = 1e3;
|
|
701
|
+
|
|
702
|
+
// src/components/Channel.tsx
|
|
703
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
603
704
|
function createCanvasFillStyle(ctx, color, width, height) {
|
|
604
705
|
if (!isWaveformGradient(color)) {
|
|
605
706
|
return color;
|
|
@@ -618,11 +719,12 @@ function createCanvasFillStyle(ctx, color, width, height) {
|
|
|
618
719
|
var Waveform = import_styled_components9.default.canvas.attrs((props) => ({
|
|
619
720
|
style: {
|
|
620
721
|
width: `${props.$cssWidth}px`,
|
|
621
|
-
height: `${props.$waveHeight}px
|
|
722
|
+
height: `${props.$waveHeight}px`,
|
|
723
|
+
left: `${props.$left}px`
|
|
622
724
|
}
|
|
623
725
|
}))`
|
|
624
|
-
|
|
625
|
-
|
|
726
|
+
position: absolute;
|
|
727
|
+
top: 0;
|
|
626
728
|
/* Promote to own compositing layer for smoother scrolling */
|
|
627
729
|
will-change: transform;
|
|
628
730
|
/* Disable image rendering interpolation */
|
|
@@ -658,8 +760,25 @@ var Channel = (props) => {
|
|
|
658
760
|
transparentBackground = false,
|
|
659
761
|
drawMode = "inverted"
|
|
660
762
|
} = props;
|
|
661
|
-
const canvasesRef = (0,
|
|
662
|
-
const
|
|
763
|
+
const canvasesRef = (0, import_react2.useRef)([]);
|
|
764
|
+
const visibleChunkKey = useScrollViewportSelector((viewport) => {
|
|
765
|
+
const totalChunks = Math.ceil(length / MAX_CANVAS_WIDTH);
|
|
766
|
+
const indices = [];
|
|
767
|
+
for (let i = 0; i < totalChunks; i++) {
|
|
768
|
+
const chunkLeft = i * MAX_CANVAS_WIDTH;
|
|
769
|
+
const chunkWidth = Math.min(length - chunkLeft, MAX_CANVAS_WIDTH);
|
|
770
|
+
if (viewport) {
|
|
771
|
+
const chunkEnd = chunkLeft + chunkWidth;
|
|
772
|
+
if (chunkEnd <= viewport.visibleStart || chunkLeft >= viewport.visibleEnd) {
|
|
773
|
+
continue;
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
indices.push(i);
|
|
777
|
+
}
|
|
778
|
+
return indices.join(",");
|
|
779
|
+
});
|
|
780
|
+
const visibleChunkIndices = visibleChunkKey ? visibleChunkKey.split(",").map(Number) : [];
|
|
781
|
+
const canvasRef = (0, import_react2.useCallback)(
|
|
663
782
|
(canvas) => {
|
|
664
783
|
if (canvas !== null) {
|
|
665
784
|
const index2 = parseInt(canvas.dataset.index, 10);
|
|
@@ -668,12 +787,22 @@ var Channel = (props) => {
|
|
|
668
787
|
},
|
|
669
788
|
[]
|
|
670
789
|
);
|
|
671
|
-
(0,
|
|
790
|
+
(0, import_react2.useEffect)(() => {
|
|
791
|
+
const canvases = canvasesRef.current;
|
|
792
|
+
for (let i = canvases.length - 1; i >= 0; i--) {
|
|
793
|
+
if (canvases[i] && !canvases[i].isConnected) {
|
|
794
|
+
delete canvases[i];
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
});
|
|
798
|
+
(0, import_react2.useLayoutEffect)(() => {
|
|
672
799
|
const canvases = canvasesRef.current;
|
|
673
800
|
const step = barWidth + barGap;
|
|
674
|
-
let globalPixelOffset = 0;
|
|
675
801
|
for (let i = 0; i < canvases.length; i++) {
|
|
676
802
|
const canvas = canvases[i];
|
|
803
|
+
if (!canvas) continue;
|
|
804
|
+
const canvasIdx = parseInt(canvas.dataset.index, 10);
|
|
805
|
+
const globalPixelOffset = canvasIdx * MAX_CANVAS_WIDTH;
|
|
677
806
|
const ctx = canvas.getContext("2d");
|
|
678
807
|
const h2 = Math.floor(waveHeight / 2);
|
|
679
808
|
const maxValue = 2 ** (bits - 1);
|
|
@@ -716,7 +845,6 @@ var Channel = (props) => {
|
|
|
716
845
|
}
|
|
717
846
|
}
|
|
718
847
|
}
|
|
719
|
-
globalPixelOffset += canvas.width / devicePixelRatio;
|
|
720
848
|
}
|
|
721
849
|
}, [
|
|
722
850
|
data,
|
|
@@ -728,32 +856,29 @@ var Channel = (props) => {
|
|
|
728
856
|
length,
|
|
729
857
|
barWidth,
|
|
730
858
|
barGap,
|
|
731
|
-
drawMode
|
|
859
|
+
drawMode,
|
|
860
|
+
visibleChunkKey
|
|
732
861
|
]);
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
const currentWidth = Math.min(totalWidth, MAX_CANVAS_WIDTH);
|
|
738
|
-
const waveform = /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
862
|
+
const waveforms = visibleChunkIndices.map((i) => {
|
|
863
|
+
const chunkLeft = i * MAX_CANVAS_WIDTH;
|
|
864
|
+
const currentWidth = Math.min(length - chunkLeft, MAX_CANVAS_WIDTH);
|
|
865
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
739
866
|
Waveform,
|
|
740
867
|
{
|
|
741
868
|
$cssWidth: currentWidth,
|
|
869
|
+
$left: chunkLeft,
|
|
742
870
|
width: currentWidth * devicePixelRatio,
|
|
743
871
|
height: waveHeight * devicePixelRatio,
|
|
744
872
|
$waveHeight: waveHeight,
|
|
745
|
-
"data-index":
|
|
873
|
+
"data-index": i,
|
|
746
874
|
ref: canvasRef
|
|
747
875
|
},
|
|
748
|
-
`${length}-${
|
|
876
|
+
`${length}-${i}`
|
|
749
877
|
);
|
|
750
|
-
|
|
751
|
-
totalWidth -= currentWidth;
|
|
752
|
-
waveformCount += 1;
|
|
753
|
-
}
|
|
878
|
+
});
|
|
754
879
|
const bgColor = waveFillColor;
|
|
755
880
|
const backgroundCss = transparentBackground ? "transparent" : waveformColorToCss(bgColor);
|
|
756
|
-
return /* @__PURE__ */ (0,
|
|
881
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
757
882
|
Wrapper,
|
|
758
883
|
{
|
|
759
884
|
$index: index,
|
|
@@ -766,6 +891,44 @@ var Channel = (props) => {
|
|
|
766
891
|
);
|
|
767
892
|
};
|
|
768
893
|
|
|
894
|
+
// src/components/ErrorBoundary.tsx
|
|
895
|
+
var import_react3 = __toESM(require("react"));
|
|
896
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
897
|
+
var errorContainerStyle = {
|
|
898
|
+
padding: "16px",
|
|
899
|
+
background: "#1a1a2e",
|
|
900
|
+
color: "#e0e0e0",
|
|
901
|
+
border: "1px solid #d08070",
|
|
902
|
+
borderRadius: "4px",
|
|
903
|
+
fontFamily: "monospace",
|
|
904
|
+
fontSize: "13px",
|
|
905
|
+
minHeight: "60px",
|
|
906
|
+
display: "flex",
|
|
907
|
+
alignItems: "center",
|
|
908
|
+
justifyContent: "center"
|
|
909
|
+
};
|
|
910
|
+
var PlaylistErrorBoundary = class extends import_react3.default.Component {
|
|
911
|
+
constructor(props) {
|
|
912
|
+
super(props);
|
|
913
|
+
this.state = { hasError: false, error: null };
|
|
914
|
+
}
|
|
915
|
+
static getDerivedStateFromError(error) {
|
|
916
|
+
return { hasError: true, error };
|
|
917
|
+
}
|
|
918
|
+
componentDidCatch(error, errorInfo) {
|
|
919
|
+
console.error("[waveform-playlist] Render error:", error, errorInfo.componentStack);
|
|
920
|
+
}
|
|
921
|
+
render() {
|
|
922
|
+
if (this.state.hasError) {
|
|
923
|
+
if (this.props.fallback) {
|
|
924
|
+
return this.props.fallback;
|
|
925
|
+
}
|
|
926
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: errorContainerStyle, children: "Waveform playlist encountered an error. Check console for details." });
|
|
927
|
+
}
|
|
928
|
+
return this.props.children;
|
|
929
|
+
}
|
|
930
|
+
};
|
|
931
|
+
|
|
769
932
|
// src/components/Clip.tsx
|
|
770
933
|
var import_styled_components13 = __toESM(require("styled-components"));
|
|
771
934
|
var import_core = require("@dnd-kit/core");
|
|
@@ -773,7 +936,7 @@ var import_utilities = require("@dnd-kit/utilities");
|
|
|
773
936
|
|
|
774
937
|
// src/components/ClipHeader.tsx
|
|
775
938
|
var import_styled_components10 = __toESM(require("styled-components"));
|
|
776
|
-
var
|
|
939
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
777
940
|
var CLIP_HEADER_HEIGHT = 22;
|
|
778
941
|
var HeaderContainer = import_styled_components10.default.div`
|
|
779
942
|
position: relative;
|
|
@@ -813,27 +976,27 @@ var ClipHeaderPresentational = ({
|
|
|
813
976
|
trackName,
|
|
814
977
|
isSelected = false
|
|
815
978
|
}) => {
|
|
816
|
-
return /* @__PURE__ */ (0,
|
|
979
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
817
980
|
HeaderContainer,
|
|
818
981
|
{
|
|
819
982
|
$isDragging: false,
|
|
820
983
|
$interactive: false,
|
|
821
984
|
$isSelected: isSelected,
|
|
822
|
-
children: /* @__PURE__ */ (0,
|
|
985
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(TrackName, { children: trackName })
|
|
823
986
|
}
|
|
824
987
|
);
|
|
825
988
|
};
|
|
826
989
|
var ClipHeader = ({
|
|
827
990
|
clipId,
|
|
828
|
-
trackIndex,
|
|
829
|
-
clipIndex,
|
|
991
|
+
trackIndex: _trackIndex,
|
|
992
|
+
clipIndex: _clipIndex,
|
|
830
993
|
trackName,
|
|
831
994
|
isSelected = false,
|
|
832
995
|
disableDrag = false,
|
|
833
996
|
dragHandleProps
|
|
834
997
|
}) => {
|
|
835
998
|
if (disableDrag || !dragHandleProps) {
|
|
836
|
-
return /* @__PURE__ */ (0,
|
|
999
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
837
1000
|
ClipHeaderPresentational,
|
|
838
1001
|
{
|
|
839
1002
|
trackName,
|
|
@@ -842,7 +1005,7 @@ var ClipHeader = ({
|
|
|
842
1005
|
);
|
|
843
1006
|
}
|
|
844
1007
|
const { attributes, listeners, setActivatorNodeRef } = dragHandleProps;
|
|
845
|
-
return /* @__PURE__ */ (0,
|
|
1008
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
846
1009
|
HeaderContainer,
|
|
847
1010
|
{
|
|
848
1011
|
ref: setActivatorNodeRef,
|
|
@@ -851,15 +1014,15 @@ var ClipHeader = ({
|
|
|
851
1014
|
$isSelected: isSelected,
|
|
852
1015
|
...listeners,
|
|
853
1016
|
...attributes,
|
|
854
|
-
children: /* @__PURE__ */ (0,
|
|
1017
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(TrackName, { children: trackName })
|
|
855
1018
|
}
|
|
856
1019
|
);
|
|
857
1020
|
};
|
|
858
1021
|
|
|
859
1022
|
// src/components/ClipBoundary.tsx
|
|
860
|
-
var
|
|
1023
|
+
var import_react4 = __toESM(require("react"));
|
|
861
1024
|
var import_styled_components11 = __toESM(require("styled-components"));
|
|
862
|
-
var
|
|
1025
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
863
1026
|
var CLIP_BOUNDARY_WIDTH = 8;
|
|
864
1027
|
var CLIP_BOUNDARY_WIDTH_TOUCH = 24;
|
|
865
1028
|
var BoundaryContainer = import_styled_components11.default.div`
|
|
@@ -893,18 +1056,18 @@ var BoundaryContainer = import_styled_components11.default.div`
|
|
|
893
1056
|
`;
|
|
894
1057
|
var ClipBoundary = ({
|
|
895
1058
|
clipId,
|
|
896
|
-
trackIndex,
|
|
897
|
-
clipIndex,
|
|
1059
|
+
trackIndex: _trackIndex,
|
|
1060
|
+
clipIndex: _clipIndex,
|
|
898
1061
|
edge,
|
|
899
1062
|
dragHandleProps,
|
|
900
1063
|
touchOptimized = false
|
|
901
1064
|
}) => {
|
|
902
|
-
const [isHovered, setIsHovered] =
|
|
1065
|
+
const [isHovered, setIsHovered] = import_react4.default.useState(false);
|
|
903
1066
|
if (!dragHandleProps) {
|
|
904
1067
|
return null;
|
|
905
1068
|
}
|
|
906
1069
|
const { attributes, listeners, setActivatorNodeRef, isDragging } = dragHandleProps;
|
|
907
|
-
return /* @__PURE__ */ (0,
|
|
1070
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
908
1071
|
BoundaryContainer,
|
|
909
1072
|
{
|
|
910
1073
|
ref: setActivatorNodeRef,
|
|
@@ -924,7 +1087,7 @@ var ClipBoundary = ({
|
|
|
924
1087
|
|
|
925
1088
|
// src/components/FadeOverlay.tsx
|
|
926
1089
|
var import_styled_components12 = __toESM(require("styled-components"));
|
|
927
|
-
var
|
|
1090
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
928
1091
|
var FadeContainer = import_styled_components12.default.div.attrs((props) => ({
|
|
929
1092
|
style: {
|
|
930
1093
|
left: `${props.$left}px`,
|
|
@@ -981,7 +1144,7 @@ var FadeOverlay = ({
|
|
|
981
1144
|
const theme = (0, import_styled_components12.useTheme)();
|
|
982
1145
|
if (width < 1) return null;
|
|
983
1146
|
const fillColor = color || theme?.fadeOverlayColor || "rgba(0, 0, 0, 0.4)";
|
|
984
|
-
return /* @__PURE__ */ (0,
|
|
1147
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(FadeContainer, { $left: left, $width: width, $type: type, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(FadeSvg, { $type: type, viewBox: `0 0 ${width} 100`, preserveAspectRatio: "none", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
985
1148
|
"path",
|
|
986
1149
|
{
|
|
987
1150
|
d: generateFadePath(width, 100, curveType),
|
|
@@ -991,7 +1154,7 @@ var FadeOverlay = ({
|
|
|
991
1154
|
};
|
|
992
1155
|
|
|
993
1156
|
// src/components/Clip.tsx
|
|
994
|
-
var
|
|
1157
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
995
1158
|
var ClipContainer = import_styled_components13.default.div.attrs((props) => ({
|
|
996
1159
|
style: props.$isOverlay ? {} : {
|
|
997
1160
|
left: `${props.$left}px`,
|
|
@@ -1076,7 +1239,7 @@ var Clip = ({
|
|
|
1076
1239
|
zIndex: isDragging ? 100 : void 0
|
|
1077
1240
|
// Below controls (z-index: 999) but above other clips
|
|
1078
1241
|
} : void 0;
|
|
1079
|
-
return /* @__PURE__ */ (0,
|
|
1242
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
1080
1243
|
ClipContainer,
|
|
1081
1244
|
{
|
|
1082
1245
|
ref: setNodeRef,
|
|
@@ -1089,7 +1252,7 @@ var Clip = ({
|
|
|
1089
1252
|
"data-track-id": trackId,
|
|
1090
1253
|
onMouseDown,
|
|
1091
1254
|
children: [
|
|
1092
|
-
showHeader && /* @__PURE__ */ (0,
|
|
1255
|
+
showHeader && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1093
1256
|
ClipHeader,
|
|
1094
1257
|
{
|
|
1095
1258
|
clipId,
|
|
@@ -1101,9 +1264,9 @@ var Clip = ({
|
|
|
1101
1264
|
dragHandleProps: enableDrag ? { attributes, listeners, setActivatorNodeRef } : void 0
|
|
1102
1265
|
}
|
|
1103
1266
|
),
|
|
1104
|
-
/* @__PURE__ */ (0,
|
|
1267
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(ChannelsWrapper, { $isOverlay: isOverlay, children: [
|
|
1105
1268
|
children,
|
|
1106
|
-
showFades && fadeIn && fadeIn.duration > 0 && /* @__PURE__ */ (0,
|
|
1269
|
+
showFades && fadeIn && fadeIn.duration > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1107
1270
|
FadeOverlay,
|
|
1108
1271
|
{
|
|
1109
1272
|
left: 0,
|
|
@@ -1112,7 +1275,7 @@ var Clip = ({
|
|
|
1112
1275
|
curveType: fadeIn.type
|
|
1113
1276
|
}
|
|
1114
1277
|
),
|
|
1115
|
-
showFades && fadeOut && fadeOut.duration > 0 && /* @__PURE__ */ (0,
|
|
1278
|
+
showFades && fadeOut && fadeOut.duration > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1116
1279
|
FadeOverlay,
|
|
1117
1280
|
{
|
|
1118
1281
|
left: width - Math.floor(fadeOut.duration * sampleRate / samplesPerPixel),
|
|
@@ -1122,8 +1285,8 @@ var Clip = ({
|
|
|
1122
1285
|
}
|
|
1123
1286
|
)
|
|
1124
1287
|
] }),
|
|
1125
|
-
showHeader && !disableHeaderDrag && !isOverlay && /* @__PURE__ */ (0,
|
|
1126
|
-
/* @__PURE__ */ (0,
|
|
1288
|
+
showHeader && !disableHeaderDrag && !isOverlay && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
|
|
1289
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1127
1290
|
ClipBoundary,
|
|
1128
1291
|
{
|
|
1129
1292
|
clipId,
|
|
@@ -1139,7 +1302,7 @@ var Clip = ({
|
|
|
1139
1302
|
}
|
|
1140
1303
|
}
|
|
1141
1304
|
),
|
|
1142
|
-
/* @__PURE__ */ (0,
|
|
1305
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1143
1306
|
ClipBoundary,
|
|
1144
1307
|
{
|
|
1145
1308
|
clipId,
|
|
@@ -1163,7 +1326,7 @@ var Clip = ({
|
|
|
1163
1326
|
|
|
1164
1327
|
// src/components/MasterVolumeControl.tsx
|
|
1165
1328
|
var import_styled_components14 = __toESM(require("styled-components"));
|
|
1166
|
-
var
|
|
1329
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
1167
1330
|
var VolumeContainer = import_styled_components14.default.div`
|
|
1168
1331
|
display: inline-flex;
|
|
1169
1332
|
align-items: center;
|
|
@@ -1185,9 +1348,9 @@ var MasterVolumeControl = ({
|
|
|
1185
1348
|
const handleChange = (e) => {
|
|
1186
1349
|
onChange(parseFloat(e.target.value) / 100);
|
|
1187
1350
|
};
|
|
1188
|
-
return /* @__PURE__ */ (0,
|
|
1189
|
-
/* @__PURE__ */ (0,
|
|
1190
|
-
/* @__PURE__ */ (0,
|
|
1351
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(VolumeContainer, { className, children: [
|
|
1352
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(VolumeLabel, { htmlFor: "master-gain", children: "Master Volume" }),
|
|
1353
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1191
1354
|
VolumeSlider,
|
|
1192
1355
|
{
|
|
1193
1356
|
min: "0",
|
|
@@ -1202,9 +1365,9 @@ var MasterVolumeControl = ({
|
|
|
1202
1365
|
};
|
|
1203
1366
|
|
|
1204
1367
|
// src/components/Playhead.tsx
|
|
1205
|
-
var
|
|
1368
|
+
var import_react5 = require("react");
|
|
1206
1369
|
var import_styled_components15 = __toESM(require("styled-components"));
|
|
1207
|
-
var
|
|
1370
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
1208
1371
|
var PlayheadLine = import_styled_components15.default.div.attrs((props) => ({
|
|
1209
1372
|
style: {
|
|
1210
1373
|
transform: `translate3d(${props.$position}px, 0, 0)`
|
|
@@ -1221,7 +1384,7 @@ var PlayheadLine = import_styled_components15.default.div.attrs((props) => ({
|
|
|
1221
1384
|
will-change: transform;
|
|
1222
1385
|
`;
|
|
1223
1386
|
var Playhead = ({ position, color = "#ff0000" }) => {
|
|
1224
|
-
return /* @__PURE__ */ (0,
|
|
1387
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(PlayheadLine, { $position: position, $color: color });
|
|
1225
1388
|
};
|
|
1226
1389
|
var PlayheadWithMarkerContainer = import_styled_components15.default.div`
|
|
1227
1390
|
position: absolute;
|
|
@@ -1261,9 +1424,9 @@ var PlayheadWithMarker = ({
|
|
|
1261
1424
|
controlsOffset,
|
|
1262
1425
|
getAudioContextTime
|
|
1263
1426
|
}) => {
|
|
1264
|
-
const containerRef = (0,
|
|
1265
|
-
const animationFrameRef = (0,
|
|
1266
|
-
(0,
|
|
1427
|
+
const containerRef = (0, import_react5.useRef)(null);
|
|
1428
|
+
const animationFrameRef = (0, import_react5.useRef)(null);
|
|
1429
|
+
(0, import_react5.useEffect)(() => {
|
|
1267
1430
|
const updatePosition = () => {
|
|
1268
1431
|
if (containerRef.current) {
|
|
1269
1432
|
let time;
|
|
@@ -1292,22 +1455,23 @@ var PlayheadWithMarker = ({
|
|
|
1292
1455
|
}
|
|
1293
1456
|
};
|
|
1294
1457
|
}, [isPlaying, sampleRate, samplesPerPixel, controlsOffset, currentTimeRef, playbackStartTimeRef, audioStartPositionRef, getAudioContextTime]);
|
|
1295
|
-
(0,
|
|
1458
|
+
(0, import_react5.useEffect)(() => {
|
|
1296
1459
|
if (!isPlaying && containerRef.current) {
|
|
1297
1460
|
const time = currentTimeRef.current ?? 0;
|
|
1298
1461
|
const pos = time * sampleRate / samplesPerPixel + controlsOffset;
|
|
1299
1462
|
containerRef.current.style.transform = `translate3d(${pos}px, 0, 0)`;
|
|
1300
1463
|
}
|
|
1301
1464
|
});
|
|
1302
|
-
return /* @__PURE__ */ (0,
|
|
1303
|
-
/* @__PURE__ */ (0,
|
|
1304
|
-
/* @__PURE__ */ (0,
|
|
1465
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(PlayheadWithMarkerContainer, { ref: containerRef, $color: color, children: [
|
|
1466
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(MarkerTriangle, { $color: color }),
|
|
1467
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(MarkerLine, { $color: color })
|
|
1305
1468
|
] });
|
|
1306
1469
|
};
|
|
1307
1470
|
|
|
1308
1471
|
// src/components/Playlist.tsx
|
|
1309
1472
|
var import_styled_components16 = __toESM(require("styled-components"));
|
|
1310
|
-
var
|
|
1473
|
+
var import_react6 = require("react");
|
|
1474
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
1311
1475
|
var Wrapper2 = import_styled_components16.default.div`
|
|
1312
1476
|
overflow-y: hidden;
|
|
1313
1477
|
overflow-x: auto;
|
|
@@ -1361,16 +1525,21 @@ var Playlist = ({
|
|
|
1361
1525
|
isSelecting,
|
|
1362
1526
|
"data-playlist-state": playlistState
|
|
1363
1527
|
}) => {
|
|
1364
|
-
|
|
1528
|
+
const wrapperRef = (0, import_react6.useRef)(null);
|
|
1529
|
+
const handleRef = (0, import_react6.useCallback)((el) => {
|
|
1530
|
+
wrapperRef.current = el;
|
|
1531
|
+
scrollContainerRef?.(el);
|
|
1532
|
+
}, [scrollContainerRef]);
|
|
1533
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Wrapper2, { "data-scroll-container": "true", "data-playlist-state": playlistState, ref: handleRef, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ScrollViewportProvider, { containerRef: wrapperRef, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
1365
1534
|
ScrollContainer,
|
|
1366
1535
|
{
|
|
1367
1536
|
$backgroundColor: backgroundColor,
|
|
1368
1537
|
$width: scrollContainerWidth,
|
|
1369
1538
|
children: [
|
|
1370
|
-
timescale && /* @__PURE__ */ (0,
|
|
1371
|
-
/* @__PURE__ */ (0,
|
|
1539
|
+
timescale && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(TimescaleWrapper, { $width: timescaleWidth, $backgroundColor: timescaleBackgroundColor, children: timescale }),
|
|
1540
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(TracksContainer, { $width: tracksWidth, $backgroundColor: backgroundColor, children: [
|
|
1372
1541
|
children,
|
|
1373
|
-
(onTracksClick || onTracksMouseDown) && /* @__PURE__ */ (0,
|
|
1542
|
+
(onTracksClick || onTracksMouseDown) && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1374
1543
|
ClickOverlay,
|
|
1375
1544
|
{
|
|
1376
1545
|
$controlsWidth: controlsWidth,
|
|
@@ -1384,13 +1553,13 @@ var Playlist = ({
|
|
|
1384
1553
|
] })
|
|
1385
1554
|
]
|
|
1386
1555
|
}
|
|
1387
|
-
) });
|
|
1556
|
+
) }) });
|
|
1388
1557
|
};
|
|
1389
1558
|
var StyledPlaylist = (0, import_styled_components16.withTheme)(Playlist);
|
|
1390
1559
|
|
|
1391
1560
|
// src/components/Selection.tsx
|
|
1392
1561
|
var import_styled_components17 = __toESM(require("styled-components"));
|
|
1393
|
-
var
|
|
1562
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
1394
1563
|
var SelectionOverlay = import_styled_components17.default.div.attrs((props) => ({
|
|
1395
1564
|
style: {
|
|
1396
1565
|
left: `${props.$left}px`,
|
|
@@ -1414,13 +1583,13 @@ var Selection = ({
|
|
|
1414
1583
|
if (width <= 0) {
|
|
1415
1584
|
return null;
|
|
1416
1585
|
}
|
|
1417
|
-
return /* @__PURE__ */ (0,
|
|
1586
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(SelectionOverlay, { $left: startPosition, $width: width, $color: color, "data-selection": true });
|
|
1418
1587
|
};
|
|
1419
1588
|
|
|
1420
1589
|
// src/components/LoopRegion.tsx
|
|
1421
|
-
var
|
|
1590
|
+
var import_react7 = require("react");
|
|
1422
1591
|
var import_styled_components18 = __toESM(require("styled-components"));
|
|
1423
|
-
var
|
|
1592
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
1424
1593
|
var LoopRegionOverlayDiv = import_styled_components18.default.div.attrs((props) => ({
|
|
1425
1594
|
style: {
|
|
1426
1595
|
left: `${props.$left}px`,
|
|
@@ -1469,8 +1638,8 @@ var LoopRegion = ({
|
|
|
1469
1638
|
if (width <= 0) {
|
|
1470
1639
|
return null;
|
|
1471
1640
|
}
|
|
1472
|
-
return /* @__PURE__ */ (0,
|
|
1473
|
-
/* @__PURE__ */ (0,
|
|
1641
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
|
|
1642
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1474
1643
|
LoopRegionOverlayDiv,
|
|
1475
1644
|
{
|
|
1476
1645
|
$left: startPosition,
|
|
@@ -1479,7 +1648,7 @@ var LoopRegion = ({
|
|
|
1479
1648
|
"data-loop-region": true
|
|
1480
1649
|
}
|
|
1481
1650
|
),
|
|
1482
|
-
/* @__PURE__ */ (0,
|
|
1651
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1483
1652
|
LoopMarker,
|
|
1484
1653
|
{
|
|
1485
1654
|
$left: startPosition,
|
|
@@ -1488,7 +1657,7 @@ var LoopRegion = ({
|
|
|
1488
1657
|
"data-loop-marker": "start"
|
|
1489
1658
|
}
|
|
1490
1659
|
),
|
|
1491
|
-
/* @__PURE__ */ (0,
|
|
1660
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1492
1661
|
LoopMarker,
|
|
1493
1662
|
{
|
|
1494
1663
|
$left: endPosition - 2,
|
|
@@ -1569,12 +1738,12 @@ var LoopRegionMarkers = ({
|
|
|
1569
1738
|
minPosition = 0,
|
|
1570
1739
|
maxPosition = Infinity
|
|
1571
1740
|
}) => {
|
|
1572
|
-
const [draggingMarker, setDraggingMarker] = (0,
|
|
1573
|
-
const dragStartX = (0,
|
|
1574
|
-
const dragStartPosition = (0,
|
|
1575
|
-
const dragStartEnd = (0,
|
|
1741
|
+
const [draggingMarker, setDraggingMarker] = (0, import_react7.useState)(null);
|
|
1742
|
+
const dragStartX = (0, import_react7.useRef)(0);
|
|
1743
|
+
const dragStartPosition = (0, import_react7.useRef)(0);
|
|
1744
|
+
const dragStartEnd = (0, import_react7.useRef)(0);
|
|
1576
1745
|
const width = Math.max(0, endPosition - startPosition);
|
|
1577
|
-
const handleMarkerMouseDown = (0,
|
|
1746
|
+
const handleMarkerMouseDown = (0, import_react7.useCallback)((e, marker) => {
|
|
1578
1747
|
e.preventDefault();
|
|
1579
1748
|
e.stopPropagation();
|
|
1580
1749
|
setDraggingMarker(marker);
|
|
@@ -1599,7 +1768,7 @@ var LoopRegionMarkers = ({
|
|
|
1599
1768
|
document.addEventListener("mousemove", handleMouseMove);
|
|
1600
1769
|
document.addEventListener("mouseup", handleMouseUp);
|
|
1601
1770
|
}, [startPosition, endPosition, minPosition, maxPosition, onLoopStartChange, onLoopEndChange]);
|
|
1602
|
-
const handleRegionMouseDown = (0,
|
|
1771
|
+
const handleRegionMouseDown = (0, import_react7.useCallback)((e) => {
|
|
1603
1772
|
e.preventDefault();
|
|
1604
1773
|
e.stopPropagation();
|
|
1605
1774
|
setDraggingMarker("region");
|
|
@@ -1632,8 +1801,8 @@ var LoopRegionMarkers = ({
|
|
|
1632
1801
|
if (width <= 0) {
|
|
1633
1802
|
return null;
|
|
1634
1803
|
}
|
|
1635
|
-
return /* @__PURE__ */ (0,
|
|
1636
|
-
/* @__PURE__ */ (0,
|
|
1804
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
|
|
1805
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1637
1806
|
TimescaleLoopShade,
|
|
1638
1807
|
{
|
|
1639
1808
|
$left: startPosition,
|
|
@@ -1644,7 +1813,7 @@ var LoopRegionMarkers = ({
|
|
|
1644
1813
|
"data-loop-region-timescale": true
|
|
1645
1814
|
}
|
|
1646
1815
|
),
|
|
1647
|
-
/* @__PURE__ */ (0,
|
|
1816
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1648
1817
|
DraggableMarkerHandle,
|
|
1649
1818
|
{
|
|
1650
1819
|
$left: startPosition,
|
|
@@ -1655,7 +1824,7 @@ var LoopRegionMarkers = ({
|
|
|
1655
1824
|
"data-loop-marker-handle": "start"
|
|
1656
1825
|
}
|
|
1657
1826
|
),
|
|
1658
|
-
/* @__PURE__ */ (0,
|
|
1827
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1659
1828
|
DraggableMarkerHandle,
|
|
1660
1829
|
{
|
|
1661
1830
|
$left: endPosition,
|
|
@@ -1690,11 +1859,11 @@ var TimescaleLoopRegion = ({
|
|
|
1690
1859
|
maxPosition = Infinity,
|
|
1691
1860
|
controlsOffset = 0
|
|
1692
1861
|
}) => {
|
|
1693
|
-
const [
|
|
1694
|
-
const createStartX = (0,
|
|
1695
|
-
const containerRef = (0,
|
|
1862
|
+
const [, setIsCreating] = (0, import_react7.useState)(false);
|
|
1863
|
+
const createStartX = (0, import_react7.useRef)(0);
|
|
1864
|
+
const containerRef = (0, import_react7.useRef)(null);
|
|
1696
1865
|
const hasLoopRegion = endPosition > startPosition;
|
|
1697
|
-
const handleBackgroundMouseDown = (0,
|
|
1866
|
+
const handleBackgroundMouseDown = (0, import_react7.useCallback)((e) => {
|
|
1698
1867
|
const target = e.target;
|
|
1699
1868
|
if (target.closest("[data-loop-marker-handle]") || target.closest("[data-loop-region-timescale]")) {
|
|
1700
1869
|
return;
|
|
@@ -1722,14 +1891,14 @@ var TimescaleLoopRegion = ({
|
|
|
1722
1891
|
document.addEventListener("mousemove", handleMouseMove);
|
|
1723
1892
|
document.addEventListener("mouseup", handleMouseUp);
|
|
1724
1893
|
}, [minPosition, maxPosition, onLoopRegionChange]);
|
|
1725
|
-
return /* @__PURE__ */ (0,
|
|
1894
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1726
1895
|
TimescaleLoopCreator,
|
|
1727
1896
|
{
|
|
1728
1897
|
ref: containerRef,
|
|
1729
1898
|
$leftOffset: controlsOffset,
|
|
1730
1899
|
onMouseDown: handleBackgroundMouseDown,
|
|
1731
1900
|
"data-timescale-loop-creator": true,
|
|
1732
|
-
children: hasLoopRegion && /* @__PURE__ */ (0,
|
|
1901
|
+
children: hasLoopRegion && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1733
1902
|
LoopRegionMarkers,
|
|
1734
1903
|
{
|
|
1735
1904
|
startPosition,
|
|
@@ -1748,10 +1917,10 @@ var TimescaleLoopRegion = ({
|
|
|
1748
1917
|
};
|
|
1749
1918
|
|
|
1750
1919
|
// src/components/SelectionTimeInputs.tsx
|
|
1751
|
-
var
|
|
1920
|
+
var import_react9 = require("react");
|
|
1752
1921
|
|
|
1753
1922
|
// src/components/TimeInput.tsx
|
|
1754
|
-
var
|
|
1923
|
+
var import_react8 = require("react");
|
|
1755
1924
|
|
|
1756
1925
|
// src/utils/timeFormat.ts
|
|
1757
1926
|
function clockFormat(seconds, decimals) {
|
|
@@ -1801,7 +1970,7 @@ function parseTime(timeStr, format) {
|
|
|
1801
1970
|
}
|
|
1802
1971
|
|
|
1803
1972
|
// src/components/TimeInput.tsx
|
|
1804
|
-
var
|
|
1973
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
1805
1974
|
var TimeInput = ({
|
|
1806
1975
|
id,
|
|
1807
1976
|
label,
|
|
@@ -1811,8 +1980,8 @@ var TimeInput = ({
|
|
|
1811
1980
|
onChange,
|
|
1812
1981
|
readOnly = false
|
|
1813
1982
|
}) => {
|
|
1814
|
-
const [displayValue, setDisplayValue] = (0,
|
|
1815
|
-
(0,
|
|
1983
|
+
const [displayValue, setDisplayValue] = (0, import_react8.useState)("");
|
|
1984
|
+
(0, import_react8.useEffect)(() => {
|
|
1816
1985
|
const formatted = formatTime(value, format);
|
|
1817
1986
|
setDisplayValue(formatted);
|
|
1818
1987
|
}, [value, format, id]);
|
|
@@ -1832,9 +2001,9 @@ var TimeInput = ({
|
|
|
1832
2001
|
e.currentTarget.blur();
|
|
1833
2002
|
}
|
|
1834
2003
|
};
|
|
1835
|
-
return /* @__PURE__ */ (0,
|
|
1836
|
-
/* @__PURE__ */ (0,
|
|
1837
|
-
/* @__PURE__ */ (0,
|
|
2004
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
|
|
2005
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ScreenReaderOnly, { as: "label", htmlFor: id, children: label }),
|
|
2006
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1838
2007
|
BaseInput,
|
|
1839
2008
|
{
|
|
1840
2009
|
type: "text",
|
|
@@ -1851,15 +2020,15 @@ var TimeInput = ({
|
|
|
1851
2020
|
};
|
|
1852
2021
|
|
|
1853
2022
|
// src/components/SelectionTimeInputs.tsx
|
|
1854
|
-
var
|
|
2023
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
1855
2024
|
var SelectionTimeInputs = ({
|
|
1856
2025
|
selectionStart,
|
|
1857
2026
|
selectionEnd,
|
|
1858
2027
|
onSelectionChange,
|
|
1859
2028
|
className
|
|
1860
2029
|
}) => {
|
|
1861
|
-
const [timeFormat, setTimeFormat] = (0,
|
|
1862
|
-
(0,
|
|
2030
|
+
const [timeFormat, setTimeFormat] = (0, import_react9.useState)("hh:mm:ss.uuu");
|
|
2031
|
+
(0, import_react9.useEffect)(() => {
|
|
1863
2032
|
const timeFormatSelect = document.querySelector(".time-format");
|
|
1864
2033
|
const handleFormatChange = () => {
|
|
1865
2034
|
if (timeFormatSelect) {
|
|
@@ -1884,8 +2053,8 @@ var SelectionTimeInputs = ({
|
|
|
1884
2053
|
onSelectionChange(selectionStart, value);
|
|
1885
2054
|
}
|
|
1886
2055
|
};
|
|
1887
|
-
return /* @__PURE__ */ (0,
|
|
1888
|
-
/* @__PURE__ */ (0,
|
|
2056
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className, children: [
|
|
2057
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
1889
2058
|
TimeInput,
|
|
1890
2059
|
{
|
|
1891
2060
|
id: "audio_start",
|
|
@@ -1896,7 +2065,7 @@ var SelectionTimeInputs = ({
|
|
|
1896
2065
|
onChange: handleStartChange
|
|
1897
2066
|
}
|
|
1898
2067
|
),
|
|
1899
|
-
/* @__PURE__ */ (0,
|
|
2068
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
1900
2069
|
TimeInput,
|
|
1901
2070
|
{
|
|
1902
2071
|
id: "audio_end",
|
|
@@ -1911,14 +2080,14 @@ var SelectionTimeInputs = ({
|
|
|
1911
2080
|
};
|
|
1912
2081
|
|
|
1913
2082
|
// src/contexts/DevicePixelRatio.tsx
|
|
1914
|
-
var
|
|
1915
|
-
var
|
|
2083
|
+
var import_react10 = require("react");
|
|
2084
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
1916
2085
|
function getScale() {
|
|
1917
2086
|
return window.devicePixelRatio;
|
|
1918
2087
|
}
|
|
1919
|
-
var DevicePixelRatioContext = (0,
|
|
2088
|
+
var DevicePixelRatioContext = (0, import_react10.createContext)(getScale());
|
|
1920
2089
|
var DevicePixelRatioProvider = ({ children }) => {
|
|
1921
|
-
const [scale, setScale] = (0,
|
|
2090
|
+
const [scale, setScale] = (0, import_react10.useState)(getScale());
|
|
1922
2091
|
matchMedia(`(resolution: ${getScale()}dppx)`).addEventListener(
|
|
1923
2092
|
"change",
|
|
1924
2093
|
() => {
|
|
@@ -1926,13 +2095,13 @@ var DevicePixelRatioProvider = ({ children }) => {
|
|
|
1926
2095
|
},
|
|
1927
2096
|
{ once: true }
|
|
1928
2097
|
);
|
|
1929
|
-
return /* @__PURE__ */ (0,
|
|
2098
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(DevicePixelRatioContext.Provider, { value: Math.ceil(scale), children });
|
|
1930
2099
|
};
|
|
1931
|
-
var useDevicePixelRatio = () => (0,
|
|
2100
|
+
var useDevicePixelRatio = () => (0, import_react10.useContext)(DevicePixelRatioContext);
|
|
1932
2101
|
|
|
1933
2102
|
// src/contexts/PlaylistInfo.tsx
|
|
1934
|
-
var
|
|
1935
|
-
var PlaylistInfoContext = (0,
|
|
2103
|
+
var import_react11 = require("react");
|
|
2104
|
+
var PlaylistInfoContext = (0, import_react11.createContext)({
|
|
1936
2105
|
sampleRate: 48e3,
|
|
1937
2106
|
samplesPerPixel: 1e3,
|
|
1938
2107
|
zoomLevels: [1e3, 1500, 2e3, 2500],
|
|
@@ -1946,22 +2115,22 @@ var PlaylistInfoContext = (0, import_react8.createContext)({
|
|
|
1946
2115
|
barWidth: 1,
|
|
1947
2116
|
barGap: 0
|
|
1948
2117
|
});
|
|
1949
|
-
var usePlaylistInfo = () => (0,
|
|
2118
|
+
var usePlaylistInfo = () => (0, import_react11.useContext)(PlaylistInfoContext);
|
|
1950
2119
|
|
|
1951
2120
|
// src/contexts/Theme.tsx
|
|
1952
|
-
var
|
|
2121
|
+
var import_react12 = require("react");
|
|
1953
2122
|
var import_styled_components19 = require("styled-components");
|
|
1954
|
-
var useTheme2 = () => (0,
|
|
2123
|
+
var useTheme2 = () => (0, import_react12.useContext)(import_styled_components19.ThemeContext);
|
|
1955
2124
|
|
|
1956
2125
|
// src/contexts/TrackControls.tsx
|
|
1957
|
-
var
|
|
1958
|
-
var
|
|
1959
|
-
var TrackControlsContext = (0,
|
|
1960
|
-
var useTrackControls = () => (0,
|
|
2126
|
+
var import_react13 = require("react");
|
|
2127
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
2128
|
+
var TrackControlsContext = (0, import_react13.createContext)(/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react13.Fragment, {}));
|
|
2129
|
+
var useTrackControls = () => (0, import_react13.useContext)(TrackControlsContext);
|
|
1961
2130
|
|
|
1962
2131
|
// src/contexts/Playout.tsx
|
|
1963
|
-
var
|
|
1964
|
-
var
|
|
2132
|
+
var import_react14 = require("react");
|
|
2133
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
1965
2134
|
var defaultProgress = 0;
|
|
1966
2135
|
var defaultIsPlaying = false;
|
|
1967
2136
|
var defaultSelectionStart = 0;
|
|
@@ -1972,8 +2141,8 @@ var defaultPlayout = {
|
|
|
1972
2141
|
selectionStart: defaultSelectionStart,
|
|
1973
2142
|
selectionEnd: defaultSelectionEnd
|
|
1974
2143
|
};
|
|
1975
|
-
var PlayoutStatusContext = (0,
|
|
1976
|
-
var PlayoutStatusUpdateContext = (0,
|
|
2144
|
+
var PlayoutStatusContext = (0, import_react14.createContext)(defaultPlayout);
|
|
2145
|
+
var PlayoutStatusUpdateContext = (0, import_react14.createContext)({
|
|
1977
2146
|
setIsPlaying: () => {
|
|
1978
2147
|
},
|
|
1979
2148
|
setProgress: () => {
|
|
@@ -1982,24 +2151,24 @@ var PlayoutStatusUpdateContext = (0, import_react11.createContext)({
|
|
|
1982
2151
|
}
|
|
1983
2152
|
});
|
|
1984
2153
|
var PlayoutProvider = ({ children }) => {
|
|
1985
|
-
const [isPlaying, setIsPlaying] = (0,
|
|
1986
|
-
const [progress, setProgress] = (0,
|
|
1987
|
-
const [selectionStart, setSelectionStart] = (0,
|
|
1988
|
-
const [selectionEnd, setSelectionEnd] = (0,
|
|
2154
|
+
const [isPlaying, setIsPlaying] = (0, import_react14.useState)(defaultIsPlaying);
|
|
2155
|
+
const [progress, setProgress] = (0, import_react14.useState)(defaultProgress);
|
|
2156
|
+
const [selectionStart, setSelectionStart] = (0, import_react14.useState)(defaultSelectionStart);
|
|
2157
|
+
const [selectionEnd, setSelectionEnd] = (0, import_react14.useState)(defaultSelectionEnd);
|
|
1989
2158
|
const setSelection = (start, end) => {
|
|
1990
2159
|
setSelectionStart(start);
|
|
1991
2160
|
setSelectionEnd(end);
|
|
1992
2161
|
};
|
|
1993
|
-
return /* @__PURE__ */ (0,
|
|
2162
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(PlayoutStatusUpdateContext.Provider, { value: { setIsPlaying, setProgress, setSelection }, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(PlayoutStatusContext.Provider, { value: { isPlaying, progress, selectionStart, selectionEnd }, children }) });
|
|
1994
2163
|
};
|
|
1995
|
-
var usePlayoutStatus = () => (0,
|
|
1996
|
-
var usePlayoutStatusUpdate = () => (0,
|
|
2164
|
+
var usePlayoutStatus = () => (0, import_react14.useContext)(PlayoutStatusContext);
|
|
2165
|
+
var usePlayoutStatusUpdate = () => (0, import_react14.useContext)(PlayoutStatusUpdateContext);
|
|
1997
2166
|
|
|
1998
2167
|
// src/components/SpectrogramChannel.tsx
|
|
1999
|
-
var
|
|
2168
|
+
var import_react15 = require("react");
|
|
2000
2169
|
var import_styled_components20 = __toESM(require("styled-components"));
|
|
2001
|
-
var
|
|
2002
|
-
var
|
|
2170
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
2171
|
+
var LINEAR_FREQUENCY_SCALE = (f, minF, maxF) => (f - minF) / (maxF - minF);
|
|
2003
2172
|
var Wrapper3 = import_styled_components20.default.div.attrs((props) => ({
|
|
2004
2173
|
style: {
|
|
2005
2174
|
top: `${props.$waveHeight * props.$index}px`,
|
|
@@ -2015,11 +2184,13 @@ var Wrapper3 = import_styled_components20.default.div.attrs((props) => ({
|
|
|
2015
2184
|
var SpectrogramCanvas = import_styled_components20.default.canvas.attrs((props) => ({
|
|
2016
2185
|
style: {
|
|
2017
2186
|
width: `${props.$cssWidth}px`,
|
|
2018
|
-
height: `${props.$waveHeight}px
|
|
2187
|
+
height: `${props.$waveHeight}px`,
|
|
2188
|
+
left: `${props.$left}px`
|
|
2019
2189
|
}
|
|
2020
2190
|
}))`
|
|
2021
|
-
|
|
2022
|
-
|
|
2191
|
+
position: absolute;
|
|
2192
|
+
top: 0;
|
|
2193
|
+
/* Promote to own compositing layer for smoother scrolling */
|
|
2023
2194
|
will-change: transform;
|
|
2024
2195
|
image-rendering: pixelated;
|
|
2025
2196
|
image-rendering: crisp-edges;
|
|
@@ -2031,6 +2202,7 @@ function defaultGetColorMap() {
|
|
|
2031
2202
|
}
|
|
2032
2203
|
return lut;
|
|
2033
2204
|
}
|
|
2205
|
+
var DEFAULT_COLOR_LUT = defaultGetColorMap();
|
|
2034
2206
|
var SpectrogramChannel = ({
|
|
2035
2207
|
index,
|
|
2036
2208
|
channelIndex: channelIndexProp,
|
|
@@ -2048,11 +2220,30 @@ var SpectrogramChannel = ({
|
|
|
2048
2220
|
onCanvasesReady
|
|
2049
2221
|
}) => {
|
|
2050
2222
|
const channelIndex = channelIndexProp ?? index;
|
|
2051
|
-
const canvasesRef = (0,
|
|
2052
|
-
const registeredIdsRef = (0,
|
|
2053
|
-
const transferredCanvasesRef = (0,
|
|
2223
|
+
const canvasesRef = (0, import_react15.useRef)([]);
|
|
2224
|
+
const registeredIdsRef = (0, import_react15.useRef)([]);
|
|
2225
|
+
const transferredCanvasesRef = (0, import_react15.useRef)(/* @__PURE__ */ new WeakSet());
|
|
2226
|
+
const workerApiRef = (0, import_react15.useRef)(workerApi);
|
|
2227
|
+
const onCanvasesReadyRef = (0, import_react15.useRef)(onCanvasesReady);
|
|
2054
2228
|
const isWorkerMode = !!(workerApi && clipId);
|
|
2055
|
-
const
|
|
2229
|
+
const visibleChunkKey = useScrollViewportSelector((viewport) => {
|
|
2230
|
+
const totalChunks = Math.ceil(length / MAX_CANVAS_WIDTH);
|
|
2231
|
+
const indices = [];
|
|
2232
|
+
for (let i = 0; i < totalChunks; i++) {
|
|
2233
|
+
const chunkLeft = i * MAX_CANVAS_WIDTH;
|
|
2234
|
+
const chunkWidth = Math.min(length - chunkLeft, MAX_CANVAS_WIDTH);
|
|
2235
|
+
if (viewport) {
|
|
2236
|
+
const chunkEnd = chunkLeft + chunkWidth;
|
|
2237
|
+
if (chunkEnd <= viewport.visibleStart || chunkLeft >= viewport.visibleEnd) {
|
|
2238
|
+
continue;
|
|
2239
|
+
}
|
|
2240
|
+
}
|
|
2241
|
+
indices.push(i);
|
|
2242
|
+
}
|
|
2243
|
+
return indices.join(",");
|
|
2244
|
+
});
|
|
2245
|
+
const visibleChunkIndices = visibleChunkKey ? visibleChunkKey.split(",").map(Number) : [];
|
|
2246
|
+
const canvasRef = (0, import_react15.useCallback)(
|
|
2056
2247
|
(canvas) => {
|
|
2057
2248
|
if (canvas !== null) {
|
|
2058
2249
|
const idx = parseInt(canvas.dataset.index, 10);
|
|
@@ -2061,53 +2252,101 @@ var SpectrogramChannel = ({
|
|
|
2061
2252
|
},
|
|
2062
2253
|
[]
|
|
2063
2254
|
);
|
|
2064
|
-
|
|
2255
|
+
const lut = colorLUT ?? DEFAULT_COLOR_LUT;
|
|
2256
|
+
const maxF = maxFrequency ?? (data ? data.sampleRate / 2 : 22050);
|
|
2257
|
+
const scaleFn = frequencyScaleFn ?? LINEAR_FREQUENCY_SCALE;
|
|
2258
|
+
const hasCustomFrequencyScale = Boolean(frequencyScaleFn);
|
|
2259
|
+
(0, import_react15.useEffect)(() => {
|
|
2260
|
+
workerApiRef.current = workerApi;
|
|
2261
|
+
}, [workerApi]);
|
|
2262
|
+
(0, import_react15.useEffect)(() => {
|
|
2263
|
+
onCanvasesReadyRef.current = onCanvasesReady;
|
|
2264
|
+
}, [onCanvasesReady]);
|
|
2265
|
+
(0, import_react15.useEffect)(() => {
|
|
2065
2266
|
if (!isWorkerMode) return;
|
|
2066
|
-
const
|
|
2067
|
-
|
|
2267
|
+
const currentWorkerApi = workerApiRef.current;
|
|
2268
|
+
if (!currentWorkerApi || !clipId) return;
|
|
2068
2269
|
const canvases2 = canvasesRef.current;
|
|
2069
|
-
const
|
|
2070
|
-
const
|
|
2270
|
+
const newIds = [];
|
|
2271
|
+
const newWidths = [];
|
|
2071
2272
|
for (let i = 0; i < canvases2.length; i++) {
|
|
2072
2273
|
const canvas = canvases2[i];
|
|
2073
2274
|
if (!canvas) continue;
|
|
2074
2275
|
if (transferredCanvasesRef.current.has(canvas)) continue;
|
|
2075
|
-
const
|
|
2276
|
+
const canvasIdx = parseInt(canvas.dataset.index, 10);
|
|
2277
|
+
const canvasId = `${clipId}-ch${channelIndex}-chunk${canvasIdx}`;
|
|
2278
|
+
let offscreen;
|
|
2076
2279
|
try {
|
|
2077
|
-
|
|
2078
|
-
workerApi.registerCanvas(canvasId, offscreen);
|
|
2079
|
-
transferredCanvasesRef.current.add(canvas);
|
|
2080
|
-
ids.push(canvasId);
|
|
2081
|
-
widths.push(Math.min(length - i * MAX_CANVAS_WIDTH2, MAX_CANVAS_WIDTH2));
|
|
2280
|
+
offscreen = canvas.transferControlToOffscreen();
|
|
2082
2281
|
} catch (err) {
|
|
2083
2282
|
console.warn(`[spectrogram] transferControlToOffscreen failed for ${canvasId}:`, err);
|
|
2084
2283
|
continue;
|
|
2085
2284
|
}
|
|
2285
|
+
transferredCanvasesRef.current.add(canvas);
|
|
2286
|
+
try {
|
|
2287
|
+
currentWorkerApi.registerCanvas(canvasId, offscreen);
|
|
2288
|
+
newIds.push(canvasId);
|
|
2289
|
+
newWidths.push(Math.min(length - canvasIdx * MAX_CANVAS_WIDTH, MAX_CANVAS_WIDTH));
|
|
2290
|
+
} catch (err) {
|
|
2291
|
+
console.warn(`[spectrogram] registerCanvas failed for ${canvasId}:`, err);
|
|
2292
|
+
continue;
|
|
2293
|
+
}
|
|
2086
2294
|
}
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2295
|
+
if (newIds.length > 0) {
|
|
2296
|
+
registeredIdsRef.current = [...registeredIdsRef.current, ...newIds];
|
|
2297
|
+
onCanvasesReadyRef.current?.(newIds, newWidths);
|
|
2090
2298
|
}
|
|
2299
|
+
}, [isWorkerMode, clipId, channelIndex, length, visibleChunkKey]);
|
|
2300
|
+
(0, import_react15.useEffect)(() => {
|
|
2301
|
+
if (!isWorkerMode) return;
|
|
2302
|
+
const currentWorkerApi = workerApiRef.current;
|
|
2303
|
+
if (!currentWorkerApi) return;
|
|
2304
|
+
const remaining = [];
|
|
2305
|
+
for (const id of registeredIdsRef.current) {
|
|
2306
|
+
const match = id.match(/chunk(\d+)$/);
|
|
2307
|
+
if (!match) {
|
|
2308
|
+
remaining.push(id);
|
|
2309
|
+
continue;
|
|
2310
|
+
}
|
|
2311
|
+
const chunkIdx = parseInt(match[1], 10);
|
|
2312
|
+
const canvas = canvasesRef.current[chunkIdx];
|
|
2313
|
+
if (canvas && canvas.isConnected) {
|
|
2314
|
+
remaining.push(id);
|
|
2315
|
+
} else {
|
|
2316
|
+
try {
|
|
2317
|
+
currentWorkerApi.unregisterCanvas(id);
|
|
2318
|
+
} catch (err) {
|
|
2319
|
+
console.warn(`[spectrogram] unregisterCanvas failed for ${id}:`, err);
|
|
2320
|
+
}
|
|
2321
|
+
}
|
|
2322
|
+
}
|
|
2323
|
+
registeredIdsRef.current = remaining;
|
|
2324
|
+
});
|
|
2325
|
+
(0, import_react15.useEffect)(() => {
|
|
2091
2326
|
return () => {
|
|
2327
|
+
const api = workerApiRef.current;
|
|
2328
|
+
if (!api) return;
|
|
2092
2329
|
for (const id of registeredIdsRef.current) {
|
|
2093
|
-
|
|
2330
|
+
try {
|
|
2331
|
+
api.unregisterCanvas(id);
|
|
2332
|
+
} catch (err) {
|
|
2333
|
+
console.warn(`[spectrogram] unregisterCanvas failed for ${id}:`, err);
|
|
2334
|
+
}
|
|
2094
2335
|
}
|
|
2095
2336
|
registeredIdsRef.current = [];
|
|
2096
2337
|
};
|
|
2097
|
-
}, [
|
|
2098
|
-
|
|
2099
|
-
const maxF = maxFrequency ?? (data ? data.sampleRate / 2 : 22050);
|
|
2100
|
-
const scaleFn = frequencyScaleFn ?? ((f, minF, maxF2) => (f - minF) / (maxF2 - minF));
|
|
2101
|
-
(0, import_react12.useLayoutEffect)(() => {
|
|
2338
|
+
}, []);
|
|
2339
|
+
(0, import_react15.useLayoutEffect)(() => {
|
|
2102
2340
|
if (isWorkerMode || !data) return;
|
|
2103
2341
|
const canvases2 = canvasesRef.current;
|
|
2104
2342
|
const { frequencyBinCount, frameCount, hopSize, sampleRate, gainDb, rangeDb: rawRangeDb } = data;
|
|
2105
2343
|
const rangeDb = rawRangeDb === 0 ? 1 : rawRangeDb;
|
|
2106
|
-
let globalPixelOffset = 0;
|
|
2107
2344
|
const binToFreq = (bin) => bin / frequencyBinCount * (sampleRate / 2);
|
|
2108
|
-
for (let
|
|
2109
|
-
const canvas = canvases2[
|
|
2345
|
+
for (let i = 0; i < canvases2.length; i++) {
|
|
2346
|
+
const canvas = canvases2[i];
|
|
2110
2347
|
if (!canvas) continue;
|
|
2348
|
+
const canvasIdx = parseInt(canvas.dataset.index, 10);
|
|
2349
|
+
const globalPixelOffset = canvasIdx * MAX_CANVAS_WIDTH;
|
|
2111
2350
|
const ctx = canvas.getContext("2d");
|
|
2112
2351
|
if (!ctx) continue;
|
|
2113
2352
|
const canvasWidth = canvas.width / devicePixelRatio;
|
|
@@ -2127,7 +2366,7 @@ var SpectrogramChannel = ({
|
|
|
2127
2366
|
for (let y = 0; y < canvasHeight; y++) {
|
|
2128
2367
|
const normalizedY = 1 - y / canvasHeight;
|
|
2129
2368
|
let bin = Math.floor(normalizedY * frequencyBinCount);
|
|
2130
|
-
if (
|
|
2369
|
+
if (hasCustomFrequencyScale) {
|
|
2131
2370
|
let lo = 0;
|
|
2132
2371
|
let hi = frequencyBinCount - 1;
|
|
2133
2372
|
while (lo < hi) {
|
|
@@ -2166,36 +2405,30 @@ var SpectrogramChannel = ({
|
|
|
2166
2405
|
ctx.imageSmoothingEnabled = false;
|
|
2167
2406
|
ctx.drawImage(tmpCanvas, 0, 0, canvas.width, canvas.height);
|
|
2168
2407
|
}
|
|
2169
|
-
globalPixelOffset += canvasWidth;
|
|
2170
2408
|
}
|
|
2171
|
-
}, [isWorkerMode, data, length, waveHeight, devicePixelRatio, samplesPerPixel, lut,
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
},
|
|
2188
|
-
`${length}-${canvasCount}`
|
|
2189
|
-
)
|
|
2409
|
+
}, [isWorkerMode, data, length, waveHeight, devicePixelRatio, samplesPerPixel, lut, minFrequency, maxF, scaleFn, hasCustomFrequencyScale, visibleChunkKey]);
|
|
2410
|
+
const canvases = visibleChunkIndices.map((i) => {
|
|
2411
|
+
const chunkLeft = i * MAX_CANVAS_WIDTH;
|
|
2412
|
+
const currentWidth = Math.min(length - chunkLeft, MAX_CANVAS_WIDTH);
|
|
2413
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
2414
|
+
SpectrogramCanvas,
|
|
2415
|
+
{
|
|
2416
|
+
$cssWidth: currentWidth,
|
|
2417
|
+
$left: chunkLeft,
|
|
2418
|
+
width: currentWidth * devicePixelRatio,
|
|
2419
|
+
height: waveHeight * devicePixelRatio,
|
|
2420
|
+
$waveHeight: waveHeight,
|
|
2421
|
+
"data-index": i,
|
|
2422
|
+
ref: canvasRef
|
|
2423
|
+
},
|
|
2424
|
+
`${length}-${i}`
|
|
2190
2425
|
);
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
}
|
|
2194
|
-
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Wrapper3, { $index: index, $cssWidth: length, $waveHeight: waveHeight, children: canvases });
|
|
2426
|
+
});
|
|
2427
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Wrapper3, { $index: index, $cssWidth: length, $waveHeight: waveHeight, children: canvases });
|
|
2195
2428
|
};
|
|
2196
2429
|
|
|
2197
2430
|
// src/components/SmartChannel.tsx
|
|
2198
|
-
var
|
|
2431
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
2199
2432
|
var SmartChannel = ({
|
|
2200
2433
|
isSelected,
|
|
2201
2434
|
transparentBackground,
|
|
@@ -2220,7 +2453,7 @@ var SmartChannel = ({
|
|
|
2220
2453
|
const drawMode = theme?.waveformDrawMode || "inverted";
|
|
2221
2454
|
const hasSpectrogram = spectrogramData || spectrogramWorkerApi;
|
|
2222
2455
|
if (renderMode === "spectrogram" && hasSpectrogram) {
|
|
2223
|
-
return /* @__PURE__ */ (0,
|
|
2456
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
2224
2457
|
SpectrogramChannel,
|
|
2225
2458
|
{
|
|
2226
2459
|
index: props.index,
|
|
@@ -2241,8 +2474,8 @@ var SmartChannel = ({
|
|
|
2241
2474
|
}
|
|
2242
2475
|
if (renderMode === "both" && hasSpectrogram) {
|
|
2243
2476
|
const halfHeight = Math.floor(waveHeight / 2);
|
|
2244
|
-
return /* @__PURE__ */ (0,
|
|
2245
|
-
/* @__PURE__ */ (0,
|
|
2477
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
|
|
2478
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
2246
2479
|
SpectrogramChannel,
|
|
2247
2480
|
{
|
|
2248
2481
|
index: props.index * 2,
|
|
@@ -2261,11 +2494,10 @@ var SmartChannel = ({
|
|
|
2261
2494
|
onCanvasesReady: spectrogramOnCanvasesReady
|
|
2262
2495
|
}
|
|
2263
2496
|
),
|
|
2264
|
-
/* @__PURE__ */ (0,
|
|
2497
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { position: "absolute", top: (props.index * 2 + 1) * halfHeight, width: props.length, height: halfHeight }, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
2265
2498
|
Channel,
|
|
2266
2499
|
{
|
|
2267
2500
|
...props,
|
|
2268
|
-
...theme,
|
|
2269
2501
|
index: 0,
|
|
2270
2502
|
waveOutlineColor,
|
|
2271
2503
|
waveFillColor,
|
|
@@ -2279,11 +2511,10 @@ var SmartChannel = ({
|
|
|
2279
2511
|
) })
|
|
2280
2512
|
] });
|
|
2281
2513
|
}
|
|
2282
|
-
return /* @__PURE__ */ (0,
|
|
2514
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
2283
2515
|
Channel,
|
|
2284
2516
|
{
|
|
2285
2517
|
...props,
|
|
2286
|
-
...theme,
|
|
2287
2518
|
waveOutlineColor,
|
|
2288
2519
|
waveFillColor,
|
|
2289
2520
|
waveHeight,
|
|
@@ -2297,9 +2528,9 @@ var SmartChannel = ({
|
|
|
2297
2528
|
};
|
|
2298
2529
|
|
|
2299
2530
|
// src/components/SpectrogramLabels.tsx
|
|
2300
|
-
var
|
|
2531
|
+
var import_react16 = require("react");
|
|
2301
2532
|
var import_styled_components21 = __toESM(require("styled-components"));
|
|
2302
|
-
var
|
|
2533
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
2303
2534
|
var LABELS_WIDTH = 72;
|
|
2304
2535
|
var LabelsStickyWrapper = import_styled_components21.default.div`
|
|
2305
2536
|
position: sticky;
|
|
@@ -2349,12 +2580,12 @@ var SpectrogramLabels = ({
|
|
|
2349
2580
|
renderMode = "spectrogram",
|
|
2350
2581
|
hasClipHeaders = false
|
|
2351
2582
|
}) => {
|
|
2352
|
-
const canvasRef = (0,
|
|
2583
|
+
const canvasRef = (0, import_react16.useRef)(null);
|
|
2353
2584
|
const devicePixelRatio = useDevicePixelRatio();
|
|
2354
2585
|
const spectrogramHeight = renderMode === "both" ? Math.floor(waveHeight / 2) : waveHeight;
|
|
2355
2586
|
const totalHeight = numChannels * waveHeight;
|
|
2356
2587
|
const clipHeaderOffset = hasClipHeaders ? 22 : 0;
|
|
2357
|
-
(0,
|
|
2588
|
+
(0, import_react16.useLayoutEffect)(() => {
|
|
2358
2589
|
const canvas = canvasRef.current;
|
|
2359
2590
|
if (!canvas) return;
|
|
2360
2591
|
const ctx = canvas.getContext("2d");
|
|
@@ -2381,7 +2612,7 @@ var SpectrogramLabels = ({
|
|
|
2381
2612
|
}
|
|
2382
2613
|
}
|
|
2383
2614
|
}, [waveHeight, numChannels, frequencyScaleFn, minFrequency, maxFrequency, labelsColor, labelsBackground, devicePixelRatio, spectrogramHeight, clipHeaderOffset]);
|
|
2384
|
-
return /* @__PURE__ */ (0,
|
|
2615
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(LabelsStickyWrapper, { $height: totalHeight + clipHeaderOffset, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
2385
2616
|
"canvas",
|
|
2386
2617
|
{
|
|
2387
2618
|
ref: canvasRef,
|
|
@@ -2397,10 +2628,10 @@ var SpectrogramLabels = ({
|
|
|
2397
2628
|
};
|
|
2398
2629
|
|
|
2399
2630
|
// src/components/SmartScale.tsx
|
|
2400
|
-
var
|
|
2631
|
+
var import_react18 = require("react");
|
|
2401
2632
|
|
|
2402
2633
|
// src/components/TimeScale.tsx
|
|
2403
|
-
var
|
|
2634
|
+
var import_react17 = __toESM(require("react"));
|
|
2404
2635
|
var import_styled_components22 = __toESM(require("styled-components"));
|
|
2405
2636
|
|
|
2406
2637
|
// src/utils/conversions.ts
|
|
@@ -2424,7 +2655,7 @@ function secondsToPixels(seconds, samplesPerPixel, sampleRate) {
|
|
|
2424
2655
|
}
|
|
2425
2656
|
|
|
2426
2657
|
// src/components/TimeScale.tsx
|
|
2427
|
-
var
|
|
2658
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
2428
2659
|
function formatTime2(milliseconds) {
|
|
2429
2660
|
const seconds = Math.floor(milliseconds / 1e3);
|
|
2430
2661
|
const s = seconds % 60;
|
|
@@ -2443,16 +2674,17 @@ var PlaylistTimeScaleScroll = import_styled_components22.default.div.attrs((prop
|
|
|
2443
2674
|
border-bottom: 1px solid ${(props) => props.theme.timeColor};
|
|
2444
2675
|
box-sizing: border-box;
|
|
2445
2676
|
`;
|
|
2446
|
-
var
|
|
2677
|
+
var TimeTickChunk = import_styled_components22.default.canvas.attrs((props) => ({
|
|
2447
2678
|
style: {
|
|
2448
2679
|
width: `${props.$cssWidth}px`,
|
|
2449
|
-
height: `${props.$timeScaleHeight}px
|
|
2680
|
+
height: `${props.$timeScaleHeight}px`,
|
|
2681
|
+
left: `${props.$left}px`
|
|
2450
2682
|
}
|
|
2451
2683
|
}))`
|
|
2452
2684
|
position: absolute;
|
|
2453
|
-
left: 0;
|
|
2454
|
-
right: 0;
|
|
2455
2685
|
bottom: 0;
|
|
2686
|
+
/* Promote to own compositing layer for smoother scrolling */
|
|
2687
|
+
will-change: transform;
|
|
2456
2688
|
`;
|
|
2457
2689
|
var TimeStamp = import_styled_components22.default.div.attrs((props) => ({
|
|
2458
2690
|
style: {
|
|
@@ -2474,78 +2706,120 @@ var TimeScale = (props) => {
|
|
|
2474
2706
|
secondStep,
|
|
2475
2707
|
renderTimestamp
|
|
2476
2708
|
} = props;
|
|
2477
|
-
const
|
|
2478
|
-
const timeMarkers = [];
|
|
2479
|
-
const canvasRef = (0, import_react14.useRef)(null);
|
|
2709
|
+
const canvasRefsMap = (0, import_react17.useRef)(/* @__PURE__ */ new Map());
|
|
2480
2710
|
const {
|
|
2481
2711
|
sampleRate,
|
|
2482
2712
|
samplesPerPixel,
|
|
2483
2713
|
timeScaleHeight,
|
|
2484
2714
|
controls: { show: showControls, width: controlWidth }
|
|
2485
|
-
} = (0,
|
|
2715
|
+
} = (0, import_react17.useContext)(PlaylistInfoContext);
|
|
2486
2716
|
const devicePixelRatio = useDevicePixelRatio();
|
|
2487
|
-
(0,
|
|
2488
|
-
if (
|
|
2489
|
-
const
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2717
|
+
const canvasRefCallback = (0, import_react17.useCallback)((canvas) => {
|
|
2718
|
+
if (canvas !== null) {
|
|
2719
|
+
const idx = parseInt(canvas.dataset.index, 10);
|
|
2720
|
+
canvasRefsMap.current.set(idx, canvas);
|
|
2721
|
+
}
|
|
2722
|
+
}, []);
|
|
2723
|
+
const { widthX, canvasInfo, timeMarkersWithPositions } = (0, import_react17.useMemo)(() => {
|
|
2724
|
+
const nextCanvasInfo = /* @__PURE__ */ new Map();
|
|
2725
|
+
const nextMarkers = [];
|
|
2726
|
+
const nextWidthX = secondsToPixels(duration / 1e3, samplesPerPixel, sampleRate);
|
|
2727
|
+
const pixPerSec = sampleRate / samplesPerPixel;
|
|
2728
|
+
let counter = 0;
|
|
2729
|
+
for (let i = 0; i < nextWidthX; i += pixPerSec * secondStep / 1e3) {
|
|
2730
|
+
const pix = Math.floor(i);
|
|
2731
|
+
if (counter % marker === 0) {
|
|
2732
|
+
const timeMs = counter;
|
|
2733
|
+
const timestamp = formatTime2(timeMs);
|
|
2734
|
+
const element = renderTimestamp ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react17.default.Fragment, { children: renderTimestamp(timeMs, pix) }, `timestamp-${counter}`) : /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(TimeStamp, { $left: pix, children: timestamp }, timestamp);
|
|
2735
|
+
nextMarkers.push({ pix, element });
|
|
2736
|
+
nextCanvasInfo.set(pix, timeScaleHeight);
|
|
2737
|
+
} else if (counter % bigStep === 0) {
|
|
2738
|
+
nextCanvasInfo.set(pix, Math.floor(timeScaleHeight / 2));
|
|
2739
|
+
} else if (counter % secondStep === 0) {
|
|
2740
|
+
nextCanvasInfo.set(pix, Math.floor(timeScaleHeight / 5));
|
|
2741
|
+
}
|
|
2742
|
+
counter += secondStep;
|
|
2743
|
+
}
|
|
2744
|
+
return {
|
|
2745
|
+
widthX: nextWidthX,
|
|
2746
|
+
canvasInfo: nextCanvasInfo,
|
|
2747
|
+
timeMarkersWithPositions: nextMarkers
|
|
2748
|
+
};
|
|
2749
|
+
}, [duration, samplesPerPixel, sampleRate, marker, bigStep, secondStep, renderTimestamp, timeScaleHeight]);
|
|
2750
|
+
const visibleChunkKey = useScrollViewportSelector((viewport) => {
|
|
2751
|
+
const totalChunks = Math.ceil(widthX / MAX_CANVAS_WIDTH);
|
|
2752
|
+
const indices = [];
|
|
2753
|
+
for (let i = 0; i < totalChunks; i++) {
|
|
2754
|
+
const chunkLeft = i * MAX_CANVAS_WIDTH;
|
|
2755
|
+
const chunkWidth = Math.min(widthX - chunkLeft, MAX_CANVAS_WIDTH);
|
|
2756
|
+
if (viewport) {
|
|
2757
|
+
const chunkEnd = chunkLeft + chunkWidth;
|
|
2758
|
+
if (chunkEnd <= viewport.visibleStart || chunkLeft >= viewport.visibleEnd) {
|
|
2759
|
+
continue;
|
|
2500
2760
|
}
|
|
2501
2761
|
}
|
|
2762
|
+
indices.push(i);
|
|
2502
2763
|
}
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2764
|
+
return indices.join(",");
|
|
2765
|
+
});
|
|
2766
|
+
const visibleChunkIndices = visibleChunkKey ? visibleChunkKey.split(",").map(Number) : [];
|
|
2767
|
+
const visibleChunks = visibleChunkIndices.map((i) => {
|
|
2768
|
+
const chunkLeft = i * MAX_CANVAS_WIDTH;
|
|
2769
|
+
const chunkWidth = Math.min(widthX - chunkLeft, MAX_CANVAS_WIDTH);
|
|
2770
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
2771
|
+
TimeTickChunk,
|
|
2772
|
+
{
|
|
2773
|
+
$cssWidth: chunkWidth,
|
|
2774
|
+
$left: chunkLeft,
|
|
2775
|
+
$timeScaleHeight: timeScaleHeight,
|
|
2776
|
+
width: chunkWidth * devicePixelRatio,
|
|
2777
|
+
height: timeScaleHeight * devicePixelRatio,
|
|
2778
|
+
"data-index": i,
|
|
2779
|
+
ref: canvasRefCallback
|
|
2780
|
+
},
|
|
2781
|
+
`timescale-${i}`
|
|
2782
|
+
);
|
|
2783
|
+
});
|
|
2784
|
+
const firstChunkLeft = visibleChunkIndices.length > 0 ? visibleChunkIndices[0] * MAX_CANVAS_WIDTH : 0;
|
|
2785
|
+
const lastChunkRight = visibleChunkIndices.length > 0 ? (visibleChunkIndices[visibleChunkIndices.length - 1] + 1) * MAX_CANVAS_WIDTH : Infinity;
|
|
2786
|
+
const visibleMarkers = visibleChunkIndices.length > 0 ? timeMarkersWithPositions.filter(({ pix }) => pix >= firstChunkLeft && pix < lastChunkRight).map(({ element }) => element) : timeMarkersWithPositions.map(({ element }) => element);
|
|
2787
|
+
(0, import_react17.useEffect)(() => {
|
|
2788
|
+
const currentMap = canvasRefsMap.current;
|
|
2789
|
+
for (const [idx, canvas] of currentMap.entries()) {
|
|
2790
|
+
if (!canvas.isConnected) {
|
|
2791
|
+
currentMap.delete(idx);
|
|
2792
|
+
}
|
|
2528
2793
|
}
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2794
|
+
});
|
|
2795
|
+
(0, import_react17.useLayoutEffect)(() => {
|
|
2796
|
+
for (const [chunkIdx, canvas] of canvasRefsMap.current.entries()) {
|
|
2797
|
+
const ctx = canvas.getContext("2d");
|
|
2798
|
+
if (!ctx) continue;
|
|
2799
|
+
const chunkLeft = chunkIdx * MAX_CANVAS_WIDTH;
|
|
2800
|
+
const chunkWidth = canvas.width / devicePixelRatio;
|
|
2801
|
+
ctx.resetTransform();
|
|
2802
|
+
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
2803
|
+
ctx.imageSmoothingEnabled = false;
|
|
2804
|
+
ctx.fillStyle = timeColor;
|
|
2805
|
+
ctx.scale(devicePixelRatio, devicePixelRatio);
|
|
2806
|
+
for (const [pixLeft, scaleHeight] of canvasInfo.entries()) {
|
|
2807
|
+
if (pixLeft < chunkLeft || pixLeft >= chunkLeft + chunkWidth) continue;
|
|
2808
|
+
const localX = pixLeft - chunkLeft;
|
|
2809
|
+
const scaleY = timeScaleHeight - scaleHeight;
|
|
2810
|
+
ctx.fillRect(localX, scaleY, 1, scaleHeight);
|
|
2811
|
+
}
|
|
2812
|
+
}
|
|
2813
|
+
}, [duration, devicePixelRatio, timeColor, timeScaleHeight, canvasInfo, visibleChunkKey]);
|
|
2814
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
2532
2815
|
PlaylistTimeScaleScroll,
|
|
2533
2816
|
{
|
|
2534
2817
|
$cssWidth: widthX,
|
|
2535
2818
|
$controlWidth: showControls ? controlWidth : 0,
|
|
2536
2819
|
$timeScaleHeight: timeScaleHeight,
|
|
2537
2820
|
children: [
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
TimeTicks,
|
|
2541
|
-
{
|
|
2542
|
-
$cssWidth: widthX,
|
|
2543
|
-
$timeScaleHeight: timeScaleHeight,
|
|
2544
|
-
width: widthX * devicePixelRatio,
|
|
2545
|
-
height: timeScaleHeight * devicePixelRatio,
|
|
2546
|
-
ref: canvasRef
|
|
2547
|
-
}
|
|
2548
|
-
)
|
|
2821
|
+
visibleMarkers,
|
|
2822
|
+
visibleChunks
|
|
2549
2823
|
]
|
|
2550
2824
|
}
|
|
2551
2825
|
);
|
|
@@ -2553,7 +2827,7 @@ var TimeScale = (props) => {
|
|
|
2553
2827
|
var StyledTimeScale = (0, import_styled_components22.withTheme)(TimeScale);
|
|
2554
2828
|
|
|
2555
2829
|
// src/components/SmartScale.tsx
|
|
2556
|
-
var
|
|
2830
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
2557
2831
|
var timeinfo = /* @__PURE__ */ new Map([
|
|
2558
2832
|
[
|
|
2559
2833
|
700,
|
|
@@ -2627,9 +2901,9 @@ function getScaleInfo(samplesPerPixel) {
|
|
|
2627
2901
|
return config;
|
|
2628
2902
|
}
|
|
2629
2903
|
var SmartScale = ({ renderTimestamp }) => {
|
|
2630
|
-
const { samplesPerPixel, duration } = (0,
|
|
2904
|
+
const { samplesPerPixel, duration } = (0, import_react18.useContext)(PlaylistInfoContext);
|
|
2631
2905
|
let config = getScaleInfo(samplesPerPixel);
|
|
2632
|
-
return /* @__PURE__ */ (0,
|
|
2906
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
2633
2907
|
StyledTimeScale,
|
|
2634
2908
|
{
|
|
2635
2909
|
marker: config.marker,
|
|
@@ -2643,7 +2917,7 @@ var SmartScale = ({ renderTimestamp }) => {
|
|
|
2643
2917
|
|
|
2644
2918
|
// src/components/TimeFormatSelect.tsx
|
|
2645
2919
|
var import_styled_components23 = __toESM(require("styled-components"));
|
|
2646
|
-
var
|
|
2920
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
2647
2921
|
var SelectWrapper = import_styled_components23.default.div`
|
|
2648
2922
|
display: inline-flex;
|
|
2649
2923
|
align-items: center;
|
|
@@ -2666,7 +2940,7 @@ var TimeFormatSelect = ({
|
|
|
2666
2940
|
const handleChange = (e) => {
|
|
2667
2941
|
onChange(e.target.value);
|
|
2668
2942
|
};
|
|
2669
|
-
return /* @__PURE__ */ (0,
|
|
2943
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(SelectWrapper, { className, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
2670
2944
|
BaseSelect,
|
|
2671
2945
|
{
|
|
2672
2946
|
className: "time-format",
|
|
@@ -2674,14 +2948,14 @@ var TimeFormatSelect = ({
|
|
|
2674
2948
|
onChange: handleChange,
|
|
2675
2949
|
disabled,
|
|
2676
2950
|
"aria-label": "Time format selection",
|
|
2677
|
-
children: TIME_FORMAT_OPTIONS.map((option) => /* @__PURE__ */ (0,
|
|
2951
|
+
children: TIME_FORMAT_OPTIONS.map((option) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("option", { value: option.value, children: option.label }, option.value))
|
|
2678
2952
|
}
|
|
2679
2953
|
) });
|
|
2680
2954
|
};
|
|
2681
2955
|
|
|
2682
2956
|
// src/components/Track.tsx
|
|
2683
2957
|
var import_styled_components24 = __toESM(require("styled-components"));
|
|
2684
|
-
var
|
|
2958
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
2685
2959
|
var Container = import_styled_components24.default.div.attrs((props) => ({
|
|
2686
2960
|
style: {
|
|
2687
2961
|
height: `${props.$waveHeight * props.$numChannels + (props.$hasClipHeaders ? CLIP_HEADER_HEIGHT : 0)}px`
|
|
@@ -2736,7 +3010,7 @@ var Track = ({
|
|
|
2736
3010
|
controls: { show, width: controlWidth }
|
|
2737
3011
|
} = usePlaylistInfo();
|
|
2738
3012
|
const controls = useTrackControls();
|
|
2739
|
-
return /* @__PURE__ */ (0,
|
|
3013
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
|
|
2740
3014
|
Container,
|
|
2741
3015
|
{
|
|
2742
3016
|
$numChannels: numChannels,
|
|
@@ -2747,7 +3021,7 @@ var Track = ({
|
|
|
2747
3021
|
$hasClipHeaders: hasClipHeaders,
|
|
2748
3022
|
$isSelected: isSelected,
|
|
2749
3023
|
children: [
|
|
2750
|
-
/* @__PURE__ */ (0,
|
|
3024
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
2751
3025
|
ControlsWrapper,
|
|
2752
3026
|
{
|
|
2753
3027
|
$controlWidth: show ? controlWidth : 0,
|
|
@@ -2755,7 +3029,7 @@ var Track = ({
|
|
|
2755
3029
|
children: controls
|
|
2756
3030
|
}
|
|
2757
3031
|
),
|
|
2758
|
-
/* @__PURE__ */ (0,
|
|
3032
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
2759
3033
|
ChannelContainer,
|
|
2760
3034
|
{
|
|
2761
3035
|
$controlWidth: show ? controlWidth : 0,
|
|
@@ -2862,8 +3136,8 @@ var ButtonGroup = import_styled_components26.default.div`
|
|
|
2862
3136
|
|
|
2863
3137
|
// src/components/TrackControls/CloseButton.tsx
|
|
2864
3138
|
var import_styled_components27 = __toESM(require("styled-components"));
|
|
2865
|
-
var
|
|
2866
|
-
var
|
|
3139
|
+
var import_react19 = require("@phosphor-icons/react");
|
|
3140
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
2867
3141
|
var StyledCloseButton = import_styled_components27.default.button`
|
|
2868
3142
|
position: absolute;
|
|
2869
3143
|
left: 0;
|
|
@@ -2888,7 +3162,7 @@ var StyledCloseButton = import_styled_components27.default.button`
|
|
|
2888
3162
|
var CloseButton = ({
|
|
2889
3163
|
onClick,
|
|
2890
3164
|
title = "Remove track"
|
|
2891
|
-
}) => /* @__PURE__ */ (0,
|
|
3165
|
+
}) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(StyledCloseButton, { onClick, title, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react19.X, { size: 12, weight: "bold" }) });
|
|
2892
3166
|
|
|
2893
3167
|
// src/components/TrackControls/Controls.tsx
|
|
2894
3168
|
var import_styled_components28 = __toESM(require("styled-components"));
|
|
@@ -2923,24 +3197,24 @@ var Header = import_styled_components29.default.header`
|
|
|
2923
3197
|
`;
|
|
2924
3198
|
|
|
2925
3199
|
// src/components/TrackControls/VolumeDownIcon.tsx
|
|
2926
|
-
var
|
|
2927
|
-
var
|
|
2928
|
-
var VolumeDownIcon = (props) => /* @__PURE__ */ (0,
|
|
3200
|
+
var import_react20 = require("@phosphor-icons/react");
|
|
3201
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
3202
|
+
var VolumeDownIcon = (props) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_react20.SpeakerLowIcon, { weight: "light", ...props });
|
|
2929
3203
|
|
|
2930
3204
|
// src/components/TrackControls/VolumeUpIcon.tsx
|
|
2931
|
-
var
|
|
2932
|
-
var
|
|
2933
|
-
var VolumeUpIcon = (props) => /* @__PURE__ */ (0,
|
|
3205
|
+
var import_react21 = require("@phosphor-icons/react");
|
|
3206
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
3207
|
+
var VolumeUpIcon = (props) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_react21.SpeakerHighIcon, { weight: "light", ...props });
|
|
2934
3208
|
|
|
2935
3209
|
// src/components/TrackControls/TrashIcon.tsx
|
|
2936
|
-
var
|
|
2937
|
-
var
|
|
2938
|
-
var TrashIcon = (props) => /* @__PURE__ */ (0,
|
|
3210
|
+
var import_react22 = require("@phosphor-icons/react");
|
|
3211
|
+
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
3212
|
+
var TrashIcon = (props) => /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_react22.TrashIcon, { weight: "light", ...props });
|
|
2939
3213
|
|
|
2940
3214
|
// src/components/TrackControls/DotsIcon.tsx
|
|
2941
|
-
var
|
|
2942
|
-
var
|
|
2943
|
-
var DotsIcon = (props) => /* @__PURE__ */ (0,
|
|
3215
|
+
var import_react23 = require("@phosphor-icons/react");
|
|
3216
|
+
var import_jsx_runtime31 = require("react/jsx-runtime");
|
|
3217
|
+
var DotsIcon = (props) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_react23.DotsThreeIcon, { weight: "bold", ...props });
|
|
2944
3218
|
|
|
2945
3219
|
// src/components/TrackControls/Slider.tsx
|
|
2946
3220
|
var import_styled_components30 = __toESM(require("styled-components"));
|
|
@@ -3008,10 +3282,10 @@ var SliderWrapper = import_styled_components31.default.label`
|
|
|
3008
3282
|
`;
|
|
3009
3283
|
|
|
3010
3284
|
// src/components/TrackMenu.tsx
|
|
3011
|
-
var
|
|
3285
|
+
var import_react24 = __toESM(require("react"));
|
|
3012
3286
|
var import_react_dom = require("react-dom");
|
|
3013
3287
|
var import_styled_components32 = __toESM(require("styled-components"));
|
|
3014
|
-
var
|
|
3288
|
+
var import_jsx_runtime32 = require("react/jsx-runtime");
|
|
3015
3289
|
var MenuContainer = import_styled_components32.default.div`
|
|
3016
3290
|
position: relative;
|
|
3017
3291
|
display: inline-block;
|
|
@@ -3052,13 +3326,13 @@ var Divider = import_styled_components32.default.hr`
|
|
|
3052
3326
|
var TrackMenu = ({
|
|
3053
3327
|
items: itemsProp
|
|
3054
3328
|
}) => {
|
|
3055
|
-
const [open, setOpen] = (0,
|
|
3329
|
+
const [open, setOpen] = (0, import_react24.useState)(false);
|
|
3056
3330
|
const close = () => setOpen(false);
|
|
3057
3331
|
const items = typeof itemsProp === "function" ? itemsProp(close) : itemsProp;
|
|
3058
|
-
const [dropdownPos, setDropdownPos] = (0,
|
|
3059
|
-
const buttonRef = (0,
|
|
3060
|
-
const dropdownRef = (0,
|
|
3061
|
-
(0,
|
|
3332
|
+
const [dropdownPos, setDropdownPos] = (0, import_react24.useState)({ top: 0, left: 0 });
|
|
3333
|
+
const buttonRef = (0, import_react24.useRef)(null);
|
|
3334
|
+
const dropdownRef = (0, import_react24.useRef)(null);
|
|
3335
|
+
(0, import_react24.useEffect)(() => {
|
|
3062
3336
|
if (open && buttonRef.current) {
|
|
3063
3337
|
const rect = buttonRef.current.getBoundingClientRect();
|
|
3064
3338
|
setDropdownPos({
|
|
@@ -3067,7 +3341,7 @@ var TrackMenu = ({
|
|
|
3067
3341
|
});
|
|
3068
3342
|
}
|
|
3069
3343
|
}, [open]);
|
|
3070
|
-
(0,
|
|
3344
|
+
(0, import_react24.useEffect)(() => {
|
|
3071
3345
|
if (!open) return;
|
|
3072
3346
|
const handleClick = (e) => {
|
|
3073
3347
|
const target = e.target;
|
|
@@ -3078,8 +3352,8 @@ var TrackMenu = ({
|
|
|
3078
3352
|
document.addEventListener("mousedown", handleClick);
|
|
3079
3353
|
return () => document.removeEventListener("mousedown", handleClick);
|
|
3080
3354
|
}, [open]);
|
|
3081
|
-
return /* @__PURE__ */ (0,
|
|
3082
|
-
/* @__PURE__ */ (0,
|
|
3355
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(MenuContainer, { children: [
|
|
3356
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
3083
3357
|
MenuButton,
|
|
3084
3358
|
{
|
|
3085
3359
|
ref: buttonRef,
|
|
@@ -3090,19 +3364,19 @@ var TrackMenu = ({
|
|
|
3090
3364
|
onMouseDown: (e) => e.stopPropagation(),
|
|
3091
3365
|
title: "Track menu",
|
|
3092
3366
|
"aria-label": "Track menu",
|
|
3093
|
-
children: /* @__PURE__ */ (0,
|
|
3367
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(DotsIcon, { size: 16 })
|
|
3094
3368
|
}
|
|
3095
3369
|
),
|
|
3096
3370
|
open && typeof document !== "undefined" && (0, import_react_dom.createPortal)(
|
|
3097
|
-
/* @__PURE__ */ (0,
|
|
3371
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
3098
3372
|
Dropdown,
|
|
3099
3373
|
{
|
|
3100
3374
|
ref: dropdownRef,
|
|
3101
3375
|
$top: dropdownPos.top,
|
|
3102
3376
|
$left: dropdownPos.left,
|
|
3103
3377
|
onMouseDown: (e) => e.stopPropagation(),
|
|
3104
|
-
children: items.map((item, index) => /* @__PURE__ */ (0,
|
|
3105
|
-
index > 0 && /* @__PURE__ */ (0,
|
|
3378
|
+
children: items.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_react24.default.Fragment, { children: [
|
|
3379
|
+
index > 0 && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Divider, {}),
|
|
3106
3380
|
item.content
|
|
3107
3381
|
] }, item.id))
|
|
3108
3382
|
}
|
|
@@ -3143,13 +3417,16 @@ var TrackMenu = ({
|
|
|
3143
3417
|
InlineLabel,
|
|
3144
3418
|
LoopRegion,
|
|
3145
3419
|
LoopRegionMarkers,
|
|
3420
|
+
MAX_CANVAS_WIDTH,
|
|
3146
3421
|
MasterVolumeControl,
|
|
3147
3422
|
Playhead,
|
|
3148
3423
|
PlayheadWithMarker,
|
|
3149
3424
|
Playlist,
|
|
3425
|
+
PlaylistErrorBoundary,
|
|
3150
3426
|
PlaylistInfoContext,
|
|
3151
3427
|
PlayoutProvider,
|
|
3152
3428
|
ScreenReaderOnly,
|
|
3429
|
+
ScrollViewportProvider,
|
|
3153
3430
|
Selection,
|
|
3154
3431
|
SelectionTimeInputs,
|
|
3155
3432
|
Slider,
|
|
@@ -3185,6 +3462,8 @@ var TrackMenu = ({
|
|
|
3185
3462
|
usePlaylistInfo,
|
|
3186
3463
|
usePlayoutStatus,
|
|
3187
3464
|
usePlayoutStatusUpdate,
|
|
3465
|
+
useScrollViewport,
|
|
3466
|
+
useScrollViewportSelector,
|
|
3188
3467
|
useTheme,
|
|
3189
3468
|
useTrackControls,
|
|
3190
3469
|
waveformColorToCss
|