@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.mjs
CHANGED
|
@@ -327,7 +327,7 @@ var AutomaticScrollCheckbox = ({
|
|
|
327
327
|
};
|
|
328
328
|
|
|
329
329
|
// src/components/Channel.tsx
|
|
330
|
-
import { useLayoutEffect, useCallback, useRef } from "react";
|
|
330
|
+
import { useLayoutEffect, useEffect as useEffect2, useCallback as useCallback2, useRef as useRef2 } from "react";
|
|
331
331
|
import styled9 from "styled-components";
|
|
332
332
|
|
|
333
333
|
// src/wfpl-theme.ts
|
|
@@ -487,9 +487,112 @@ var darkTheme = {
|
|
|
487
487
|
fontSizeSmall: "12px"
|
|
488
488
|
};
|
|
489
489
|
|
|
490
|
-
// src/
|
|
490
|
+
// src/contexts/ScrollViewport.tsx
|
|
491
|
+
import {
|
|
492
|
+
createContext,
|
|
493
|
+
useContext,
|
|
494
|
+
useEffect,
|
|
495
|
+
useCallback,
|
|
496
|
+
useRef,
|
|
497
|
+
useSyncExternalStore
|
|
498
|
+
} from "react";
|
|
491
499
|
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
500
|
+
var ViewportStore = class {
|
|
501
|
+
constructor() {
|
|
502
|
+
this._state = null;
|
|
503
|
+
this._listeners = /* @__PURE__ */ new Set();
|
|
504
|
+
this.subscribe = (callback) => {
|
|
505
|
+
this._listeners.add(callback);
|
|
506
|
+
return () => this._listeners.delete(callback);
|
|
507
|
+
};
|
|
508
|
+
this.getSnapshot = () => this._state;
|
|
509
|
+
}
|
|
510
|
+
/**
|
|
511
|
+
* Update viewport state. Applies a 100px scroll threshold to skip updates
|
|
512
|
+
* that don't affect chunk visibility (1000px chunks with 1.5× overscan buffer).
|
|
513
|
+
* Only notifies listeners when the state actually changes.
|
|
514
|
+
*/
|
|
515
|
+
update(scrollLeft, containerWidth) {
|
|
516
|
+
const buffer = containerWidth * 1.5;
|
|
517
|
+
const visibleStart = Math.max(0, scrollLeft - buffer);
|
|
518
|
+
const visibleEnd = scrollLeft + containerWidth + buffer;
|
|
519
|
+
if (this._state && this._state.containerWidth === containerWidth && Math.abs(this._state.scrollLeft - scrollLeft) < 100) {
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
this._state = { scrollLeft, containerWidth, visibleStart, visibleEnd };
|
|
523
|
+
for (const listener of this._listeners) {
|
|
524
|
+
listener();
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
};
|
|
528
|
+
var ViewportStoreContext = createContext(null);
|
|
529
|
+
var EMPTY_SUBSCRIBE = () => () => {
|
|
530
|
+
};
|
|
531
|
+
var NULL_SNAPSHOT = () => null;
|
|
532
|
+
var ScrollViewportProvider = ({
|
|
533
|
+
containerRef,
|
|
534
|
+
children
|
|
535
|
+
}) => {
|
|
536
|
+
const storeRef = useRef(null);
|
|
537
|
+
if (storeRef.current === null) {
|
|
538
|
+
storeRef.current = new ViewportStore();
|
|
539
|
+
}
|
|
540
|
+
const store = storeRef.current;
|
|
541
|
+
const rafIdRef = useRef(null);
|
|
542
|
+
const measure = useCallback(() => {
|
|
543
|
+
const el = containerRef.current;
|
|
544
|
+
if (!el) return;
|
|
545
|
+
store.update(el.scrollLeft, el.clientWidth);
|
|
546
|
+
}, [containerRef, store]);
|
|
547
|
+
const scheduleUpdate = useCallback(() => {
|
|
548
|
+
if (rafIdRef.current !== null) return;
|
|
549
|
+
rafIdRef.current = requestAnimationFrame(() => {
|
|
550
|
+
rafIdRef.current = null;
|
|
551
|
+
measure();
|
|
552
|
+
});
|
|
553
|
+
}, [measure]);
|
|
554
|
+
useEffect(() => {
|
|
555
|
+
const el = containerRef.current;
|
|
556
|
+
if (!el) return;
|
|
557
|
+
measure();
|
|
558
|
+
el.addEventListener("scroll", scheduleUpdate, { passive: true });
|
|
559
|
+
const resizeObserver = new ResizeObserver(() => {
|
|
560
|
+
scheduleUpdate();
|
|
561
|
+
});
|
|
562
|
+
resizeObserver.observe(el);
|
|
563
|
+
return () => {
|
|
564
|
+
el.removeEventListener("scroll", scheduleUpdate);
|
|
565
|
+
resizeObserver.disconnect();
|
|
566
|
+
if (rafIdRef.current !== null) {
|
|
567
|
+
cancelAnimationFrame(rafIdRef.current);
|
|
568
|
+
rafIdRef.current = null;
|
|
569
|
+
}
|
|
570
|
+
};
|
|
571
|
+
}, [containerRef, measure, scheduleUpdate]);
|
|
572
|
+
return /* @__PURE__ */ jsx3(ViewportStoreContext.Provider, { value: store, children });
|
|
573
|
+
};
|
|
574
|
+
var useScrollViewport = () => {
|
|
575
|
+
const store = useContext(ViewportStoreContext);
|
|
576
|
+
return useSyncExternalStore(
|
|
577
|
+
store ? store.subscribe : EMPTY_SUBSCRIBE,
|
|
578
|
+
store ? store.getSnapshot : NULL_SNAPSHOT,
|
|
579
|
+
NULL_SNAPSHOT
|
|
580
|
+
);
|
|
581
|
+
};
|
|
582
|
+
function useScrollViewportSelector(selector) {
|
|
583
|
+
const store = useContext(ViewportStoreContext);
|
|
584
|
+
return useSyncExternalStore(
|
|
585
|
+
store ? store.subscribe : EMPTY_SUBSCRIBE,
|
|
586
|
+
() => selector(store ? store.getSnapshot() : null),
|
|
587
|
+
() => selector(null)
|
|
588
|
+
);
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
// src/constants.ts
|
|
492
592
|
var MAX_CANVAS_WIDTH = 1e3;
|
|
593
|
+
|
|
594
|
+
// src/components/Channel.tsx
|
|
595
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
493
596
|
function createCanvasFillStyle(ctx, color, width, height) {
|
|
494
597
|
if (!isWaveformGradient(color)) {
|
|
495
598
|
return color;
|
|
@@ -508,11 +611,12 @@ function createCanvasFillStyle(ctx, color, width, height) {
|
|
|
508
611
|
var Waveform = styled9.canvas.attrs((props) => ({
|
|
509
612
|
style: {
|
|
510
613
|
width: `${props.$cssWidth}px`,
|
|
511
|
-
height: `${props.$waveHeight}px
|
|
614
|
+
height: `${props.$waveHeight}px`,
|
|
615
|
+
left: `${props.$left}px`
|
|
512
616
|
}
|
|
513
617
|
}))`
|
|
514
|
-
|
|
515
|
-
|
|
618
|
+
position: absolute;
|
|
619
|
+
top: 0;
|
|
516
620
|
/* Promote to own compositing layer for smoother scrolling */
|
|
517
621
|
will-change: transform;
|
|
518
622
|
/* Disable image rendering interpolation */
|
|
@@ -548,8 +652,25 @@ var Channel = (props) => {
|
|
|
548
652
|
transparentBackground = false,
|
|
549
653
|
drawMode = "inverted"
|
|
550
654
|
} = props;
|
|
551
|
-
const canvasesRef =
|
|
552
|
-
const
|
|
655
|
+
const canvasesRef = useRef2([]);
|
|
656
|
+
const visibleChunkKey = useScrollViewportSelector((viewport) => {
|
|
657
|
+
const totalChunks = Math.ceil(length / MAX_CANVAS_WIDTH);
|
|
658
|
+
const indices = [];
|
|
659
|
+
for (let i = 0; i < totalChunks; i++) {
|
|
660
|
+
const chunkLeft = i * MAX_CANVAS_WIDTH;
|
|
661
|
+
const chunkWidth = Math.min(length - chunkLeft, MAX_CANVAS_WIDTH);
|
|
662
|
+
if (viewport) {
|
|
663
|
+
const chunkEnd = chunkLeft + chunkWidth;
|
|
664
|
+
if (chunkEnd <= viewport.visibleStart || chunkLeft >= viewport.visibleEnd) {
|
|
665
|
+
continue;
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
indices.push(i);
|
|
669
|
+
}
|
|
670
|
+
return indices.join(",");
|
|
671
|
+
});
|
|
672
|
+
const visibleChunkIndices = visibleChunkKey ? visibleChunkKey.split(",").map(Number) : [];
|
|
673
|
+
const canvasRef = useCallback2(
|
|
553
674
|
(canvas) => {
|
|
554
675
|
if (canvas !== null) {
|
|
555
676
|
const index2 = parseInt(canvas.dataset.index, 10);
|
|
@@ -558,12 +679,22 @@ var Channel = (props) => {
|
|
|
558
679
|
},
|
|
559
680
|
[]
|
|
560
681
|
);
|
|
682
|
+
useEffect2(() => {
|
|
683
|
+
const canvases = canvasesRef.current;
|
|
684
|
+
for (let i = canvases.length - 1; i >= 0; i--) {
|
|
685
|
+
if (canvases[i] && !canvases[i].isConnected) {
|
|
686
|
+
delete canvases[i];
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
});
|
|
561
690
|
useLayoutEffect(() => {
|
|
562
691
|
const canvases = canvasesRef.current;
|
|
563
692
|
const step = barWidth + barGap;
|
|
564
|
-
let globalPixelOffset = 0;
|
|
565
693
|
for (let i = 0; i < canvases.length; i++) {
|
|
566
694
|
const canvas = canvases[i];
|
|
695
|
+
if (!canvas) continue;
|
|
696
|
+
const canvasIdx = parseInt(canvas.dataset.index, 10);
|
|
697
|
+
const globalPixelOffset = canvasIdx * MAX_CANVAS_WIDTH;
|
|
567
698
|
const ctx = canvas.getContext("2d");
|
|
568
699
|
const h2 = Math.floor(waveHeight / 2);
|
|
569
700
|
const maxValue = 2 ** (bits - 1);
|
|
@@ -606,7 +737,6 @@ var Channel = (props) => {
|
|
|
606
737
|
}
|
|
607
738
|
}
|
|
608
739
|
}
|
|
609
|
-
globalPixelOffset += canvas.width / devicePixelRatio;
|
|
610
740
|
}
|
|
611
741
|
}, [
|
|
612
742
|
data,
|
|
@@ -618,32 +748,29 @@ var Channel = (props) => {
|
|
|
618
748
|
length,
|
|
619
749
|
barWidth,
|
|
620
750
|
barGap,
|
|
621
|
-
drawMode
|
|
751
|
+
drawMode,
|
|
752
|
+
visibleChunkKey
|
|
622
753
|
]);
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
const currentWidth = Math.min(totalWidth, MAX_CANVAS_WIDTH);
|
|
628
|
-
const waveform = /* @__PURE__ */ jsx3(
|
|
754
|
+
const waveforms = visibleChunkIndices.map((i) => {
|
|
755
|
+
const chunkLeft = i * MAX_CANVAS_WIDTH;
|
|
756
|
+
const currentWidth = Math.min(length - chunkLeft, MAX_CANVAS_WIDTH);
|
|
757
|
+
return /* @__PURE__ */ jsx4(
|
|
629
758
|
Waveform,
|
|
630
759
|
{
|
|
631
760
|
$cssWidth: currentWidth,
|
|
761
|
+
$left: chunkLeft,
|
|
632
762
|
width: currentWidth * devicePixelRatio,
|
|
633
763
|
height: waveHeight * devicePixelRatio,
|
|
634
764
|
$waveHeight: waveHeight,
|
|
635
|
-
"data-index":
|
|
765
|
+
"data-index": i,
|
|
636
766
|
ref: canvasRef
|
|
637
767
|
},
|
|
638
|
-
`${length}-${
|
|
768
|
+
`${length}-${i}`
|
|
639
769
|
);
|
|
640
|
-
|
|
641
|
-
totalWidth -= currentWidth;
|
|
642
|
-
waveformCount += 1;
|
|
643
|
-
}
|
|
770
|
+
});
|
|
644
771
|
const bgColor = waveFillColor;
|
|
645
772
|
const backgroundCss = transparentBackground ? "transparent" : waveformColorToCss(bgColor);
|
|
646
|
-
return /* @__PURE__ */
|
|
773
|
+
return /* @__PURE__ */ jsx4(
|
|
647
774
|
Wrapper,
|
|
648
775
|
{
|
|
649
776
|
$index: index,
|
|
@@ -656,6 +783,44 @@ var Channel = (props) => {
|
|
|
656
783
|
);
|
|
657
784
|
};
|
|
658
785
|
|
|
786
|
+
// src/components/ErrorBoundary.tsx
|
|
787
|
+
import React3 from "react";
|
|
788
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
789
|
+
var errorContainerStyle = {
|
|
790
|
+
padding: "16px",
|
|
791
|
+
background: "#1a1a2e",
|
|
792
|
+
color: "#e0e0e0",
|
|
793
|
+
border: "1px solid #d08070",
|
|
794
|
+
borderRadius: "4px",
|
|
795
|
+
fontFamily: "monospace",
|
|
796
|
+
fontSize: "13px",
|
|
797
|
+
minHeight: "60px",
|
|
798
|
+
display: "flex",
|
|
799
|
+
alignItems: "center",
|
|
800
|
+
justifyContent: "center"
|
|
801
|
+
};
|
|
802
|
+
var PlaylistErrorBoundary = class extends React3.Component {
|
|
803
|
+
constructor(props) {
|
|
804
|
+
super(props);
|
|
805
|
+
this.state = { hasError: false, error: null };
|
|
806
|
+
}
|
|
807
|
+
static getDerivedStateFromError(error) {
|
|
808
|
+
return { hasError: true, error };
|
|
809
|
+
}
|
|
810
|
+
componentDidCatch(error, errorInfo) {
|
|
811
|
+
console.error("[waveform-playlist] Render error:", error, errorInfo.componentStack);
|
|
812
|
+
}
|
|
813
|
+
render() {
|
|
814
|
+
if (this.state.hasError) {
|
|
815
|
+
if (this.props.fallback) {
|
|
816
|
+
return this.props.fallback;
|
|
817
|
+
}
|
|
818
|
+
return /* @__PURE__ */ jsx5("div", { style: errorContainerStyle, children: "Waveform playlist encountered an error. Check console for details." });
|
|
819
|
+
}
|
|
820
|
+
return this.props.children;
|
|
821
|
+
}
|
|
822
|
+
};
|
|
823
|
+
|
|
659
824
|
// src/components/Clip.tsx
|
|
660
825
|
import styled13 from "styled-components";
|
|
661
826
|
import { useDraggable } from "@dnd-kit/core";
|
|
@@ -663,7 +828,7 @@ import { CSS } from "@dnd-kit/utilities";
|
|
|
663
828
|
|
|
664
829
|
// src/components/ClipHeader.tsx
|
|
665
830
|
import styled10 from "styled-components";
|
|
666
|
-
import { jsx as
|
|
831
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
667
832
|
var CLIP_HEADER_HEIGHT = 22;
|
|
668
833
|
var HeaderContainer = styled10.div`
|
|
669
834
|
position: relative;
|
|
@@ -703,27 +868,27 @@ var ClipHeaderPresentational = ({
|
|
|
703
868
|
trackName,
|
|
704
869
|
isSelected = false
|
|
705
870
|
}) => {
|
|
706
|
-
return /* @__PURE__ */
|
|
871
|
+
return /* @__PURE__ */ jsx6(
|
|
707
872
|
HeaderContainer,
|
|
708
873
|
{
|
|
709
874
|
$isDragging: false,
|
|
710
875
|
$interactive: false,
|
|
711
876
|
$isSelected: isSelected,
|
|
712
|
-
children: /* @__PURE__ */
|
|
877
|
+
children: /* @__PURE__ */ jsx6(TrackName, { children: trackName })
|
|
713
878
|
}
|
|
714
879
|
);
|
|
715
880
|
};
|
|
716
881
|
var ClipHeader = ({
|
|
717
882
|
clipId,
|
|
718
|
-
trackIndex,
|
|
719
|
-
clipIndex,
|
|
883
|
+
trackIndex: _trackIndex,
|
|
884
|
+
clipIndex: _clipIndex,
|
|
720
885
|
trackName,
|
|
721
886
|
isSelected = false,
|
|
722
887
|
disableDrag = false,
|
|
723
888
|
dragHandleProps
|
|
724
889
|
}) => {
|
|
725
890
|
if (disableDrag || !dragHandleProps) {
|
|
726
|
-
return /* @__PURE__ */
|
|
891
|
+
return /* @__PURE__ */ jsx6(
|
|
727
892
|
ClipHeaderPresentational,
|
|
728
893
|
{
|
|
729
894
|
trackName,
|
|
@@ -732,7 +897,7 @@ var ClipHeader = ({
|
|
|
732
897
|
);
|
|
733
898
|
}
|
|
734
899
|
const { attributes, listeners, setActivatorNodeRef } = dragHandleProps;
|
|
735
|
-
return /* @__PURE__ */
|
|
900
|
+
return /* @__PURE__ */ jsx6(
|
|
736
901
|
HeaderContainer,
|
|
737
902
|
{
|
|
738
903
|
ref: setActivatorNodeRef,
|
|
@@ -741,15 +906,15 @@ var ClipHeader = ({
|
|
|
741
906
|
$isSelected: isSelected,
|
|
742
907
|
...listeners,
|
|
743
908
|
...attributes,
|
|
744
|
-
children: /* @__PURE__ */
|
|
909
|
+
children: /* @__PURE__ */ jsx6(TrackName, { children: trackName })
|
|
745
910
|
}
|
|
746
911
|
);
|
|
747
912
|
};
|
|
748
913
|
|
|
749
914
|
// src/components/ClipBoundary.tsx
|
|
750
|
-
import
|
|
915
|
+
import React4 from "react";
|
|
751
916
|
import styled11 from "styled-components";
|
|
752
|
-
import { jsx as
|
|
917
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
753
918
|
var CLIP_BOUNDARY_WIDTH = 8;
|
|
754
919
|
var CLIP_BOUNDARY_WIDTH_TOUCH = 24;
|
|
755
920
|
var BoundaryContainer = styled11.div`
|
|
@@ -783,18 +948,18 @@ var BoundaryContainer = styled11.div`
|
|
|
783
948
|
`;
|
|
784
949
|
var ClipBoundary = ({
|
|
785
950
|
clipId,
|
|
786
|
-
trackIndex,
|
|
787
|
-
clipIndex,
|
|
951
|
+
trackIndex: _trackIndex,
|
|
952
|
+
clipIndex: _clipIndex,
|
|
788
953
|
edge,
|
|
789
954
|
dragHandleProps,
|
|
790
955
|
touchOptimized = false
|
|
791
956
|
}) => {
|
|
792
|
-
const [isHovered, setIsHovered] =
|
|
957
|
+
const [isHovered, setIsHovered] = React4.useState(false);
|
|
793
958
|
if (!dragHandleProps) {
|
|
794
959
|
return null;
|
|
795
960
|
}
|
|
796
961
|
const { attributes, listeners, setActivatorNodeRef, isDragging } = dragHandleProps;
|
|
797
|
-
return /* @__PURE__ */
|
|
962
|
+
return /* @__PURE__ */ jsx7(
|
|
798
963
|
BoundaryContainer,
|
|
799
964
|
{
|
|
800
965
|
ref: setActivatorNodeRef,
|
|
@@ -814,7 +979,7 @@ var ClipBoundary = ({
|
|
|
814
979
|
|
|
815
980
|
// src/components/FadeOverlay.tsx
|
|
816
981
|
import styled12, { useTheme } from "styled-components";
|
|
817
|
-
import { jsx as
|
|
982
|
+
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
818
983
|
var FadeContainer = styled12.div.attrs((props) => ({
|
|
819
984
|
style: {
|
|
820
985
|
left: `${props.$left}px`,
|
|
@@ -871,7 +1036,7 @@ var FadeOverlay = ({
|
|
|
871
1036
|
const theme = useTheme();
|
|
872
1037
|
if (width < 1) return null;
|
|
873
1038
|
const fillColor = color || theme?.fadeOverlayColor || "rgba(0, 0, 0, 0.4)";
|
|
874
|
-
return /* @__PURE__ */
|
|
1039
|
+
return /* @__PURE__ */ jsx8(FadeContainer, { $left: left, $width: width, $type: type, children: /* @__PURE__ */ jsx8(FadeSvg, { $type: type, viewBox: `0 0 ${width} 100`, preserveAspectRatio: "none", children: /* @__PURE__ */ jsx8(
|
|
875
1040
|
"path",
|
|
876
1041
|
{
|
|
877
1042
|
d: generateFadePath(width, 100, curveType),
|
|
@@ -881,7 +1046,7 @@ var FadeOverlay = ({
|
|
|
881
1046
|
};
|
|
882
1047
|
|
|
883
1048
|
// src/components/Clip.tsx
|
|
884
|
-
import { Fragment, jsx as
|
|
1049
|
+
import { Fragment, jsx as jsx9, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
885
1050
|
var ClipContainer = styled13.div.attrs((props) => ({
|
|
886
1051
|
style: props.$isOverlay ? {} : {
|
|
887
1052
|
left: `${props.$left}px`,
|
|
@@ -979,7 +1144,7 @@ var Clip = ({
|
|
|
979
1144
|
"data-track-id": trackId,
|
|
980
1145
|
onMouseDown,
|
|
981
1146
|
children: [
|
|
982
|
-
showHeader && /* @__PURE__ */
|
|
1147
|
+
showHeader && /* @__PURE__ */ jsx9(
|
|
983
1148
|
ClipHeader,
|
|
984
1149
|
{
|
|
985
1150
|
clipId,
|
|
@@ -993,7 +1158,7 @@ var Clip = ({
|
|
|
993
1158
|
),
|
|
994
1159
|
/* @__PURE__ */ jsxs2(ChannelsWrapper, { $isOverlay: isOverlay, children: [
|
|
995
1160
|
children,
|
|
996
|
-
showFades && fadeIn && fadeIn.duration > 0 && /* @__PURE__ */
|
|
1161
|
+
showFades && fadeIn && fadeIn.duration > 0 && /* @__PURE__ */ jsx9(
|
|
997
1162
|
FadeOverlay,
|
|
998
1163
|
{
|
|
999
1164
|
left: 0,
|
|
@@ -1002,7 +1167,7 @@ var Clip = ({
|
|
|
1002
1167
|
curveType: fadeIn.type
|
|
1003
1168
|
}
|
|
1004
1169
|
),
|
|
1005
|
-
showFades && fadeOut && fadeOut.duration > 0 && /* @__PURE__ */
|
|
1170
|
+
showFades && fadeOut && fadeOut.duration > 0 && /* @__PURE__ */ jsx9(
|
|
1006
1171
|
FadeOverlay,
|
|
1007
1172
|
{
|
|
1008
1173
|
left: width - Math.floor(fadeOut.duration * sampleRate / samplesPerPixel),
|
|
@@ -1013,7 +1178,7 @@ var Clip = ({
|
|
|
1013
1178
|
)
|
|
1014
1179
|
] }),
|
|
1015
1180
|
showHeader && !disableHeaderDrag && !isOverlay && /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
1016
|
-
/* @__PURE__ */
|
|
1181
|
+
/* @__PURE__ */ jsx9(
|
|
1017
1182
|
ClipBoundary,
|
|
1018
1183
|
{
|
|
1019
1184
|
clipId,
|
|
@@ -1029,7 +1194,7 @@ var Clip = ({
|
|
|
1029
1194
|
}
|
|
1030
1195
|
}
|
|
1031
1196
|
),
|
|
1032
|
-
/* @__PURE__ */
|
|
1197
|
+
/* @__PURE__ */ jsx9(
|
|
1033
1198
|
ClipBoundary,
|
|
1034
1199
|
{
|
|
1035
1200
|
clipId,
|
|
@@ -1053,7 +1218,7 @@ var Clip = ({
|
|
|
1053
1218
|
|
|
1054
1219
|
// src/components/MasterVolumeControl.tsx
|
|
1055
1220
|
import styled14 from "styled-components";
|
|
1056
|
-
import { jsx as
|
|
1221
|
+
import { jsx as jsx10, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1057
1222
|
var VolumeContainer = styled14.div`
|
|
1058
1223
|
display: inline-flex;
|
|
1059
1224
|
align-items: center;
|
|
@@ -1076,8 +1241,8 @@ var MasterVolumeControl = ({
|
|
|
1076
1241
|
onChange(parseFloat(e.target.value) / 100);
|
|
1077
1242
|
};
|
|
1078
1243
|
return /* @__PURE__ */ jsxs3(VolumeContainer, { className, children: [
|
|
1079
|
-
/* @__PURE__ */
|
|
1080
|
-
/* @__PURE__ */
|
|
1244
|
+
/* @__PURE__ */ jsx10(VolumeLabel, { htmlFor: "master-gain", children: "Master Volume" }),
|
|
1245
|
+
/* @__PURE__ */ jsx10(
|
|
1081
1246
|
VolumeSlider,
|
|
1082
1247
|
{
|
|
1083
1248
|
min: "0",
|
|
@@ -1092,9 +1257,9 @@ var MasterVolumeControl = ({
|
|
|
1092
1257
|
};
|
|
1093
1258
|
|
|
1094
1259
|
// src/components/Playhead.tsx
|
|
1095
|
-
import { useRef as
|
|
1260
|
+
import { useRef as useRef3, useEffect as useEffect3 } from "react";
|
|
1096
1261
|
import styled15 from "styled-components";
|
|
1097
|
-
import { jsx as
|
|
1262
|
+
import { jsx as jsx11, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1098
1263
|
var PlayheadLine = styled15.div.attrs((props) => ({
|
|
1099
1264
|
style: {
|
|
1100
1265
|
transform: `translate3d(${props.$position}px, 0, 0)`
|
|
@@ -1111,7 +1276,7 @@ var PlayheadLine = styled15.div.attrs((props) => ({
|
|
|
1111
1276
|
will-change: transform;
|
|
1112
1277
|
`;
|
|
1113
1278
|
var Playhead = ({ position, color = "#ff0000" }) => {
|
|
1114
|
-
return /* @__PURE__ */
|
|
1279
|
+
return /* @__PURE__ */ jsx11(PlayheadLine, { $position: position, $color: color });
|
|
1115
1280
|
};
|
|
1116
1281
|
var PlayheadWithMarkerContainer = styled15.div`
|
|
1117
1282
|
position: absolute;
|
|
@@ -1151,9 +1316,9 @@ var PlayheadWithMarker = ({
|
|
|
1151
1316
|
controlsOffset,
|
|
1152
1317
|
getAudioContextTime
|
|
1153
1318
|
}) => {
|
|
1154
|
-
const containerRef =
|
|
1155
|
-
const animationFrameRef =
|
|
1156
|
-
|
|
1319
|
+
const containerRef = useRef3(null);
|
|
1320
|
+
const animationFrameRef = useRef3(null);
|
|
1321
|
+
useEffect3(() => {
|
|
1157
1322
|
const updatePosition = () => {
|
|
1158
1323
|
if (containerRef.current) {
|
|
1159
1324
|
let time;
|
|
@@ -1182,7 +1347,7 @@ var PlayheadWithMarker = ({
|
|
|
1182
1347
|
}
|
|
1183
1348
|
};
|
|
1184
1349
|
}, [isPlaying, sampleRate, samplesPerPixel, controlsOffset, currentTimeRef, playbackStartTimeRef, audioStartPositionRef, getAudioContextTime]);
|
|
1185
|
-
|
|
1350
|
+
useEffect3(() => {
|
|
1186
1351
|
if (!isPlaying && containerRef.current) {
|
|
1187
1352
|
const time = currentTimeRef.current ?? 0;
|
|
1188
1353
|
const pos = time * sampleRate / samplesPerPixel + controlsOffset;
|
|
@@ -1190,14 +1355,15 @@ var PlayheadWithMarker = ({
|
|
|
1190
1355
|
}
|
|
1191
1356
|
});
|
|
1192
1357
|
return /* @__PURE__ */ jsxs4(PlayheadWithMarkerContainer, { ref: containerRef, $color: color, children: [
|
|
1193
|
-
/* @__PURE__ */
|
|
1194
|
-
/* @__PURE__ */
|
|
1358
|
+
/* @__PURE__ */ jsx11(MarkerTriangle, { $color: color }),
|
|
1359
|
+
/* @__PURE__ */ jsx11(MarkerLine, { $color: color })
|
|
1195
1360
|
] });
|
|
1196
1361
|
};
|
|
1197
1362
|
|
|
1198
1363
|
// src/components/Playlist.tsx
|
|
1199
1364
|
import styled16, { withTheme } from "styled-components";
|
|
1200
|
-
import {
|
|
1365
|
+
import { useRef as useRef4, useCallback as useCallback3 } from "react";
|
|
1366
|
+
import { jsx as jsx12, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1201
1367
|
var Wrapper2 = styled16.div`
|
|
1202
1368
|
overflow-y: hidden;
|
|
1203
1369
|
overflow-x: auto;
|
|
@@ -1251,16 +1417,21 @@ var Playlist = ({
|
|
|
1251
1417
|
isSelecting,
|
|
1252
1418
|
"data-playlist-state": playlistState
|
|
1253
1419
|
}) => {
|
|
1254
|
-
|
|
1420
|
+
const wrapperRef = useRef4(null);
|
|
1421
|
+
const handleRef = useCallback3((el) => {
|
|
1422
|
+
wrapperRef.current = el;
|
|
1423
|
+
scrollContainerRef?.(el);
|
|
1424
|
+
}, [scrollContainerRef]);
|
|
1425
|
+
return /* @__PURE__ */ jsx12(Wrapper2, { "data-scroll-container": "true", "data-playlist-state": playlistState, ref: handleRef, children: /* @__PURE__ */ jsx12(ScrollViewportProvider, { containerRef: wrapperRef, children: /* @__PURE__ */ jsxs5(
|
|
1255
1426
|
ScrollContainer,
|
|
1256
1427
|
{
|
|
1257
1428
|
$backgroundColor: backgroundColor,
|
|
1258
1429
|
$width: scrollContainerWidth,
|
|
1259
1430
|
children: [
|
|
1260
|
-
timescale && /* @__PURE__ */
|
|
1431
|
+
timescale && /* @__PURE__ */ jsx12(TimescaleWrapper, { $width: timescaleWidth, $backgroundColor: timescaleBackgroundColor, children: timescale }),
|
|
1261
1432
|
/* @__PURE__ */ jsxs5(TracksContainer, { $width: tracksWidth, $backgroundColor: backgroundColor, children: [
|
|
1262
1433
|
children,
|
|
1263
|
-
(onTracksClick || onTracksMouseDown) && /* @__PURE__ */
|
|
1434
|
+
(onTracksClick || onTracksMouseDown) && /* @__PURE__ */ jsx12(
|
|
1264
1435
|
ClickOverlay,
|
|
1265
1436
|
{
|
|
1266
1437
|
$controlsWidth: controlsWidth,
|
|
@@ -1274,13 +1445,13 @@ var Playlist = ({
|
|
|
1274
1445
|
] })
|
|
1275
1446
|
]
|
|
1276
1447
|
}
|
|
1277
|
-
) });
|
|
1448
|
+
) }) });
|
|
1278
1449
|
};
|
|
1279
1450
|
var StyledPlaylist = withTheme(Playlist);
|
|
1280
1451
|
|
|
1281
1452
|
// src/components/Selection.tsx
|
|
1282
1453
|
import styled17 from "styled-components";
|
|
1283
|
-
import { jsx as
|
|
1454
|
+
import { jsx as jsx13 } from "react/jsx-runtime";
|
|
1284
1455
|
var SelectionOverlay = styled17.div.attrs((props) => ({
|
|
1285
1456
|
style: {
|
|
1286
1457
|
left: `${props.$left}px`,
|
|
@@ -1304,13 +1475,13 @@ var Selection = ({
|
|
|
1304
1475
|
if (width <= 0) {
|
|
1305
1476
|
return null;
|
|
1306
1477
|
}
|
|
1307
|
-
return /* @__PURE__ */
|
|
1478
|
+
return /* @__PURE__ */ jsx13(SelectionOverlay, { $left: startPosition, $width: width, $color: color, "data-selection": true });
|
|
1308
1479
|
};
|
|
1309
1480
|
|
|
1310
1481
|
// src/components/LoopRegion.tsx
|
|
1311
|
-
import { useCallback as
|
|
1482
|
+
import { useCallback as useCallback4, useRef as useRef5, useState } from "react";
|
|
1312
1483
|
import styled18 from "styled-components";
|
|
1313
|
-
import { Fragment as Fragment2, jsx as
|
|
1484
|
+
import { Fragment as Fragment2, jsx as jsx14, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1314
1485
|
var LoopRegionOverlayDiv = styled18.div.attrs((props) => ({
|
|
1315
1486
|
style: {
|
|
1316
1487
|
left: `${props.$left}px`,
|
|
@@ -1360,7 +1531,7 @@ var LoopRegion = ({
|
|
|
1360
1531
|
return null;
|
|
1361
1532
|
}
|
|
1362
1533
|
return /* @__PURE__ */ jsxs6(Fragment2, { children: [
|
|
1363
|
-
/* @__PURE__ */
|
|
1534
|
+
/* @__PURE__ */ jsx14(
|
|
1364
1535
|
LoopRegionOverlayDiv,
|
|
1365
1536
|
{
|
|
1366
1537
|
$left: startPosition,
|
|
@@ -1369,7 +1540,7 @@ var LoopRegion = ({
|
|
|
1369
1540
|
"data-loop-region": true
|
|
1370
1541
|
}
|
|
1371
1542
|
),
|
|
1372
|
-
/* @__PURE__ */
|
|
1543
|
+
/* @__PURE__ */ jsx14(
|
|
1373
1544
|
LoopMarker,
|
|
1374
1545
|
{
|
|
1375
1546
|
$left: startPosition,
|
|
@@ -1378,7 +1549,7 @@ var LoopRegion = ({
|
|
|
1378
1549
|
"data-loop-marker": "start"
|
|
1379
1550
|
}
|
|
1380
1551
|
),
|
|
1381
|
-
/* @__PURE__ */
|
|
1552
|
+
/* @__PURE__ */ jsx14(
|
|
1382
1553
|
LoopMarker,
|
|
1383
1554
|
{
|
|
1384
1555
|
$left: endPosition - 2,
|
|
@@ -1460,11 +1631,11 @@ var LoopRegionMarkers = ({
|
|
|
1460
1631
|
maxPosition = Infinity
|
|
1461
1632
|
}) => {
|
|
1462
1633
|
const [draggingMarker, setDraggingMarker] = useState(null);
|
|
1463
|
-
const dragStartX =
|
|
1464
|
-
const dragStartPosition =
|
|
1465
|
-
const dragStartEnd =
|
|
1634
|
+
const dragStartX = useRef5(0);
|
|
1635
|
+
const dragStartPosition = useRef5(0);
|
|
1636
|
+
const dragStartEnd = useRef5(0);
|
|
1466
1637
|
const width = Math.max(0, endPosition - startPosition);
|
|
1467
|
-
const handleMarkerMouseDown =
|
|
1638
|
+
const handleMarkerMouseDown = useCallback4((e, marker) => {
|
|
1468
1639
|
e.preventDefault();
|
|
1469
1640
|
e.stopPropagation();
|
|
1470
1641
|
setDraggingMarker(marker);
|
|
@@ -1489,7 +1660,7 @@ var LoopRegionMarkers = ({
|
|
|
1489
1660
|
document.addEventListener("mousemove", handleMouseMove);
|
|
1490
1661
|
document.addEventListener("mouseup", handleMouseUp);
|
|
1491
1662
|
}, [startPosition, endPosition, minPosition, maxPosition, onLoopStartChange, onLoopEndChange]);
|
|
1492
|
-
const handleRegionMouseDown =
|
|
1663
|
+
const handleRegionMouseDown = useCallback4((e) => {
|
|
1493
1664
|
e.preventDefault();
|
|
1494
1665
|
e.stopPropagation();
|
|
1495
1666
|
setDraggingMarker("region");
|
|
@@ -1523,7 +1694,7 @@ var LoopRegionMarkers = ({
|
|
|
1523
1694
|
return null;
|
|
1524
1695
|
}
|
|
1525
1696
|
return /* @__PURE__ */ jsxs6(Fragment2, { children: [
|
|
1526
|
-
/* @__PURE__ */
|
|
1697
|
+
/* @__PURE__ */ jsx14(
|
|
1527
1698
|
TimescaleLoopShade,
|
|
1528
1699
|
{
|
|
1529
1700
|
$left: startPosition,
|
|
@@ -1534,7 +1705,7 @@ var LoopRegionMarkers = ({
|
|
|
1534
1705
|
"data-loop-region-timescale": true
|
|
1535
1706
|
}
|
|
1536
1707
|
),
|
|
1537
|
-
/* @__PURE__ */
|
|
1708
|
+
/* @__PURE__ */ jsx14(
|
|
1538
1709
|
DraggableMarkerHandle,
|
|
1539
1710
|
{
|
|
1540
1711
|
$left: startPosition,
|
|
@@ -1545,7 +1716,7 @@ var LoopRegionMarkers = ({
|
|
|
1545
1716
|
"data-loop-marker-handle": "start"
|
|
1546
1717
|
}
|
|
1547
1718
|
),
|
|
1548
|
-
/* @__PURE__ */
|
|
1719
|
+
/* @__PURE__ */ jsx14(
|
|
1549
1720
|
DraggableMarkerHandle,
|
|
1550
1721
|
{
|
|
1551
1722
|
$left: endPosition,
|
|
@@ -1580,11 +1751,11 @@ var TimescaleLoopRegion = ({
|
|
|
1580
1751
|
maxPosition = Infinity,
|
|
1581
1752
|
controlsOffset = 0
|
|
1582
1753
|
}) => {
|
|
1583
|
-
const [
|
|
1584
|
-
const createStartX =
|
|
1585
|
-
const containerRef =
|
|
1754
|
+
const [, setIsCreating] = useState(false);
|
|
1755
|
+
const createStartX = useRef5(0);
|
|
1756
|
+
const containerRef = useRef5(null);
|
|
1586
1757
|
const hasLoopRegion = endPosition > startPosition;
|
|
1587
|
-
const handleBackgroundMouseDown =
|
|
1758
|
+
const handleBackgroundMouseDown = useCallback4((e) => {
|
|
1588
1759
|
const target = e.target;
|
|
1589
1760
|
if (target.closest("[data-loop-marker-handle]") || target.closest("[data-loop-region-timescale]")) {
|
|
1590
1761
|
return;
|
|
@@ -1612,14 +1783,14 @@ var TimescaleLoopRegion = ({
|
|
|
1612
1783
|
document.addEventListener("mousemove", handleMouseMove);
|
|
1613
1784
|
document.addEventListener("mouseup", handleMouseUp);
|
|
1614
1785
|
}, [minPosition, maxPosition, onLoopRegionChange]);
|
|
1615
|
-
return /* @__PURE__ */
|
|
1786
|
+
return /* @__PURE__ */ jsx14(
|
|
1616
1787
|
TimescaleLoopCreator,
|
|
1617
1788
|
{
|
|
1618
1789
|
ref: containerRef,
|
|
1619
1790
|
$leftOffset: controlsOffset,
|
|
1620
1791
|
onMouseDown: handleBackgroundMouseDown,
|
|
1621
1792
|
"data-timescale-loop-creator": true,
|
|
1622
|
-
children: hasLoopRegion && /* @__PURE__ */
|
|
1793
|
+
children: hasLoopRegion && /* @__PURE__ */ jsx14(
|
|
1623
1794
|
LoopRegionMarkers,
|
|
1624
1795
|
{
|
|
1625
1796
|
startPosition,
|
|
@@ -1638,10 +1809,10 @@ var TimescaleLoopRegion = ({
|
|
|
1638
1809
|
};
|
|
1639
1810
|
|
|
1640
1811
|
// src/components/SelectionTimeInputs.tsx
|
|
1641
|
-
import { useEffect as
|
|
1812
|
+
import { useEffect as useEffect5, useState as useState3 } from "react";
|
|
1642
1813
|
|
|
1643
1814
|
// src/components/TimeInput.tsx
|
|
1644
|
-
import { useEffect as
|
|
1815
|
+
import { useEffect as useEffect4, useState as useState2 } from "react";
|
|
1645
1816
|
|
|
1646
1817
|
// src/utils/timeFormat.ts
|
|
1647
1818
|
function clockFormat(seconds, decimals) {
|
|
@@ -1691,7 +1862,7 @@ function parseTime(timeStr, format) {
|
|
|
1691
1862
|
}
|
|
1692
1863
|
|
|
1693
1864
|
// src/components/TimeInput.tsx
|
|
1694
|
-
import { Fragment as Fragment3, jsx as
|
|
1865
|
+
import { Fragment as Fragment3, jsx as jsx15, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1695
1866
|
var TimeInput = ({
|
|
1696
1867
|
id,
|
|
1697
1868
|
label,
|
|
@@ -1702,7 +1873,7 @@ var TimeInput = ({
|
|
|
1702
1873
|
readOnly = false
|
|
1703
1874
|
}) => {
|
|
1704
1875
|
const [displayValue, setDisplayValue] = useState2("");
|
|
1705
|
-
|
|
1876
|
+
useEffect4(() => {
|
|
1706
1877
|
const formatted = formatTime(value, format);
|
|
1707
1878
|
setDisplayValue(formatted);
|
|
1708
1879
|
}, [value, format, id]);
|
|
@@ -1723,8 +1894,8 @@ var TimeInput = ({
|
|
|
1723
1894
|
}
|
|
1724
1895
|
};
|
|
1725
1896
|
return /* @__PURE__ */ jsxs7(Fragment3, { children: [
|
|
1726
|
-
/* @__PURE__ */
|
|
1727
|
-
/* @__PURE__ */
|
|
1897
|
+
/* @__PURE__ */ jsx15(ScreenReaderOnly, { as: "label", htmlFor: id, children: label }),
|
|
1898
|
+
/* @__PURE__ */ jsx15(
|
|
1728
1899
|
BaseInput,
|
|
1729
1900
|
{
|
|
1730
1901
|
type: "text",
|
|
@@ -1741,7 +1912,7 @@ var TimeInput = ({
|
|
|
1741
1912
|
};
|
|
1742
1913
|
|
|
1743
1914
|
// src/components/SelectionTimeInputs.tsx
|
|
1744
|
-
import {
|
|
1915
|
+
import { jsx as jsx16, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1745
1916
|
var SelectionTimeInputs = ({
|
|
1746
1917
|
selectionStart,
|
|
1747
1918
|
selectionEnd,
|
|
@@ -1749,7 +1920,7 @@ var SelectionTimeInputs = ({
|
|
|
1749
1920
|
className
|
|
1750
1921
|
}) => {
|
|
1751
1922
|
const [timeFormat, setTimeFormat] = useState3("hh:mm:ss.uuu");
|
|
1752
|
-
|
|
1923
|
+
useEffect5(() => {
|
|
1753
1924
|
const timeFormatSelect = document.querySelector(".time-format");
|
|
1754
1925
|
const handleFormatChange = () => {
|
|
1755
1926
|
if (timeFormatSelect) {
|
|
@@ -1774,8 +1945,8 @@ var SelectionTimeInputs = ({
|
|
|
1774
1945
|
onSelectionChange(selectionStart, value);
|
|
1775
1946
|
}
|
|
1776
1947
|
};
|
|
1777
|
-
return /* @__PURE__ */ jsxs8(
|
|
1778
|
-
/* @__PURE__ */
|
|
1948
|
+
return /* @__PURE__ */ jsxs8("div", { className, children: [
|
|
1949
|
+
/* @__PURE__ */ jsx16(
|
|
1779
1950
|
TimeInput,
|
|
1780
1951
|
{
|
|
1781
1952
|
id: "audio_start",
|
|
@@ -1786,7 +1957,7 @@ var SelectionTimeInputs = ({
|
|
|
1786
1957
|
onChange: handleStartChange
|
|
1787
1958
|
}
|
|
1788
1959
|
),
|
|
1789
|
-
/* @__PURE__ */
|
|
1960
|
+
/* @__PURE__ */ jsx16(
|
|
1790
1961
|
TimeInput,
|
|
1791
1962
|
{
|
|
1792
1963
|
id: "audio_end",
|
|
@@ -1801,12 +1972,12 @@ var SelectionTimeInputs = ({
|
|
|
1801
1972
|
};
|
|
1802
1973
|
|
|
1803
1974
|
// src/contexts/DevicePixelRatio.tsx
|
|
1804
|
-
import { useState as useState4, createContext, useContext } from "react";
|
|
1805
|
-
import { jsx as
|
|
1975
|
+
import { useState as useState4, createContext as createContext2, useContext as useContext2 } from "react";
|
|
1976
|
+
import { jsx as jsx17 } from "react/jsx-runtime";
|
|
1806
1977
|
function getScale() {
|
|
1807
1978
|
return window.devicePixelRatio;
|
|
1808
1979
|
}
|
|
1809
|
-
var DevicePixelRatioContext =
|
|
1980
|
+
var DevicePixelRatioContext = createContext2(getScale());
|
|
1810
1981
|
var DevicePixelRatioProvider = ({ children }) => {
|
|
1811
1982
|
const [scale, setScale] = useState4(getScale());
|
|
1812
1983
|
matchMedia(`(resolution: ${getScale()}dppx)`).addEventListener(
|
|
@@ -1816,13 +1987,13 @@ var DevicePixelRatioProvider = ({ children }) => {
|
|
|
1816
1987
|
},
|
|
1817
1988
|
{ once: true }
|
|
1818
1989
|
);
|
|
1819
|
-
return /* @__PURE__ */
|
|
1990
|
+
return /* @__PURE__ */ jsx17(DevicePixelRatioContext.Provider, { value: Math.ceil(scale), children });
|
|
1820
1991
|
};
|
|
1821
|
-
var useDevicePixelRatio = () =>
|
|
1992
|
+
var useDevicePixelRatio = () => useContext2(DevicePixelRatioContext);
|
|
1822
1993
|
|
|
1823
1994
|
// src/contexts/PlaylistInfo.tsx
|
|
1824
|
-
import { createContext as
|
|
1825
|
-
var PlaylistInfoContext =
|
|
1995
|
+
import { createContext as createContext3, useContext as useContext3 } from "react";
|
|
1996
|
+
var PlaylistInfoContext = createContext3({
|
|
1826
1997
|
sampleRate: 48e3,
|
|
1827
1998
|
samplesPerPixel: 1e3,
|
|
1828
1999
|
zoomLevels: [1e3, 1500, 2e3, 2500],
|
|
@@ -1836,26 +2007,26 @@ var PlaylistInfoContext = createContext2({
|
|
|
1836
2007
|
barWidth: 1,
|
|
1837
2008
|
barGap: 0
|
|
1838
2009
|
});
|
|
1839
|
-
var usePlaylistInfo = () =>
|
|
2010
|
+
var usePlaylistInfo = () => useContext3(PlaylistInfoContext);
|
|
1840
2011
|
|
|
1841
2012
|
// src/contexts/Theme.tsx
|
|
1842
|
-
import { useContext as
|
|
2013
|
+
import { useContext as useContext4 } from "react";
|
|
1843
2014
|
import { ThemeContext } from "styled-components";
|
|
1844
|
-
var useTheme2 = () =>
|
|
2015
|
+
var useTheme2 = () => useContext4(ThemeContext);
|
|
1845
2016
|
|
|
1846
2017
|
// src/contexts/TrackControls.tsx
|
|
1847
|
-
import { createContext as
|
|
1848
|
-
import { jsx as
|
|
1849
|
-
var TrackControlsContext =
|
|
1850
|
-
var useTrackControls = () =>
|
|
2018
|
+
import { createContext as createContext4, useContext as useContext5, Fragment as Fragment4 } from "react";
|
|
2019
|
+
import { jsx as jsx18 } from "react/jsx-runtime";
|
|
2020
|
+
var TrackControlsContext = createContext4(/* @__PURE__ */ jsx18(Fragment4, {}));
|
|
2021
|
+
var useTrackControls = () => useContext5(TrackControlsContext);
|
|
1851
2022
|
|
|
1852
2023
|
// src/contexts/Playout.tsx
|
|
1853
2024
|
import {
|
|
1854
2025
|
useState as useState5,
|
|
1855
|
-
createContext as
|
|
1856
|
-
useContext as
|
|
2026
|
+
createContext as createContext5,
|
|
2027
|
+
useContext as useContext6
|
|
1857
2028
|
} from "react";
|
|
1858
|
-
import { jsx as
|
|
2029
|
+
import { jsx as jsx19 } from "react/jsx-runtime";
|
|
1859
2030
|
var defaultProgress = 0;
|
|
1860
2031
|
var defaultIsPlaying = false;
|
|
1861
2032
|
var defaultSelectionStart = 0;
|
|
@@ -1866,8 +2037,8 @@ var defaultPlayout = {
|
|
|
1866
2037
|
selectionStart: defaultSelectionStart,
|
|
1867
2038
|
selectionEnd: defaultSelectionEnd
|
|
1868
2039
|
};
|
|
1869
|
-
var PlayoutStatusContext =
|
|
1870
|
-
var PlayoutStatusUpdateContext =
|
|
2040
|
+
var PlayoutStatusContext = createContext5(defaultPlayout);
|
|
2041
|
+
var PlayoutStatusUpdateContext = createContext5({
|
|
1871
2042
|
setIsPlaying: () => {
|
|
1872
2043
|
},
|
|
1873
2044
|
setProgress: () => {
|
|
@@ -1884,16 +2055,16 @@ var PlayoutProvider = ({ children }) => {
|
|
|
1884
2055
|
setSelectionStart(start);
|
|
1885
2056
|
setSelectionEnd(end);
|
|
1886
2057
|
};
|
|
1887
|
-
return /* @__PURE__ */
|
|
2058
|
+
return /* @__PURE__ */ jsx19(PlayoutStatusUpdateContext.Provider, { value: { setIsPlaying, setProgress, setSelection }, children: /* @__PURE__ */ jsx19(PlayoutStatusContext.Provider, { value: { isPlaying, progress, selectionStart, selectionEnd }, children }) });
|
|
1888
2059
|
};
|
|
1889
|
-
var usePlayoutStatus = () =>
|
|
1890
|
-
var usePlayoutStatusUpdate = () =>
|
|
2060
|
+
var usePlayoutStatus = () => useContext6(PlayoutStatusContext);
|
|
2061
|
+
var usePlayoutStatusUpdate = () => useContext6(PlayoutStatusUpdateContext);
|
|
1891
2062
|
|
|
1892
2063
|
// src/components/SpectrogramChannel.tsx
|
|
1893
|
-
import { useLayoutEffect as useLayoutEffect2, useCallback as
|
|
2064
|
+
import { useLayoutEffect as useLayoutEffect2, useCallback as useCallback5, useRef as useRef6, useEffect as useEffect6 } from "react";
|
|
1894
2065
|
import styled19 from "styled-components";
|
|
1895
|
-
import { jsx as
|
|
1896
|
-
var
|
|
2066
|
+
import { jsx as jsx20 } from "react/jsx-runtime";
|
|
2067
|
+
var LINEAR_FREQUENCY_SCALE = (f, minF, maxF) => (f - minF) / (maxF - minF);
|
|
1897
2068
|
var Wrapper3 = styled19.div.attrs((props) => ({
|
|
1898
2069
|
style: {
|
|
1899
2070
|
top: `${props.$waveHeight * props.$index}px`,
|
|
@@ -1909,11 +2080,13 @@ var Wrapper3 = styled19.div.attrs((props) => ({
|
|
|
1909
2080
|
var SpectrogramCanvas = styled19.canvas.attrs((props) => ({
|
|
1910
2081
|
style: {
|
|
1911
2082
|
width: `${props.$cssWidth}px`,
|
|
1912
|
-
height: `${props.$waveHeight}px
|
|
2083
|
+
height: `${props.$waveHeight}px`,
|
|
2084
|
+
left: `${props.$left}px`
|
|
1913
2085
|
}
|
|
1914
2086
|
}))`
|
|
1915
|
-
|
|
1916
|
-
|
|
2087
|
+
position: absolute;
|
|
2088
|
+
top: 0;
|
|
2089
|
+
/* Promote to own compositing layer for smoother scrolling */
|
|
1917
2090
|
will-change: transform;
|
|
1918
2091
|
image-rendering: pixelated;
|
|
1919
2092
|
image-rendering: crisp-edges;
|
|
@@ -1925,6 +2098,7 @@ function defaultGetColorMap() {
|
|
|
1925
2098
|
}
|
|
1926
2099
|
return lut;
|
|
1927
2100
|
}
|
|
2101
|
+
var DEFAULT_COLOR_LUT = defaultGetColorMap();
|
|
1928
2102
|
var SpectrogramChannel = ({
|
|
1929
2103
|
index,
|
|
1930
2104
|
channelIndex: channelIndexProp,
|
|
@@ -1942,11 +2116,30 @@ var SpectrogramChannel = ({
|
|
|
1942
2116
|
onCanvasesReady
|
|
1943
2117
|
}) => {
|
|
1944
2118
|
const channelIndex = channelIndexProp ?? index;
|
|
1945
|
-
const canvasesRef =
|
|
1946
|
-
const registeredIdsRef =
|
|
1947
|
-
const transferredCanvasesRef =
|
|
2119
|
+
const canvasesRef = useRef6([]);
|
|
2120
|
+
const registeredIdsRef = useRef6([]);
|
|
2121
|
+
const transferredCanvasesRef = useRef6(/* @__PURE__ */ new WeakSet());
|
|
2122
|
+
const workerApiRef = useRef6(workerApi);
|
|
2123
|
+
const onCanvasesReadyRef = useRef6(onCanvasesReady);
|
|
1948
2124
|
const isWorkerMode = !!(workerApi && clipId);
|
|
1949
|
-
const
|
|
2125
|
+
const visibleChunkKey = useScrollViewportSelector((viewport) => {
|
|
2126
|
+
const totalChunks = Math.ceil(length / MAX_CANVAS_WIDTH);
|
|
2127
|
+
const indices = [];
|
|
2128
|
+
for (let i = 0; i < totalChunks; i++) {
|
|
2129
|
+
const chunkLeft = i * MAX_CANVAS_WIDTH;
|
|
2130
|
+
const chunkWidth = Math.min(length - chunkLeft, MAX_CANVAS_WIDTH);
|
|
2131
|
+
if (viewport) {
|
|
2132
|
+
const chunkEnd = chunkLeft + chunkWidth;
|
|
2133
|
+
if (chunkEnd <= viewport.visibleStart || chunkLeft >= viewport.visibleEnd) {
|
|
2134
|
+
continue;
|
|
2135
|
+
}
|
|
2136
|
+
}
|
|
2137
|
+
indices.push(i);
|
|
2138
|
+
}
|
|
2139
|
+
return indices.join(",");
|
|
2140
|
+
});
|
|
2141
|
+
const visibleChunkIndices = visibleChunkKey ? visibleChunkKey.split(",").map(Number) : [];
|
|
2142
|
+
const canvasRef = useCallback5(
|
|
1950
2143
|
(canvas) => {
|
|
1951
2144
|
if (canvas !== null) {
|
|
1952
2145
|
const idx = parseInt(canvas.dataset.index, 10);
|
|
@@ -1955,53 +2148,101 @@ var SpectrogramChannel = ({
|
|
|
1955
2148
|
},
|
|
1956
2149
|
[]
|
|
1957
2150
|
);
|
|
1958
|
-
|
|
2151
|
+
const lut = colorLUT ?? DEFAULT_COLOR_LUT;
|
|
2152
|
+
const maxF = maxFrequency ?? (data ? data.sampleRate / 2 : 22050);
|
|
2153
|
+
const scaleFn = frequencyScaleFn ?? LINEAR_FREQUENCY_SCALE;
|
|
2154
|
+
const hasCustomFrequencyScale = Boolean(frequencyScaleFn);
|
|
2155
|
+
useEffect6(() => {
|
|
2156
|
+
workerApiRef.current = workerApi;
|
|
2157
|
+
}, [workerApi]);
|
|
2158
|
+
useEffect6(() => {
|
|
2159
|
+
onCanvasesReadyRef.current = onCanvasesReady;
|
|
2160
|
+
}, [onCanvasesReady]);
|
|
2161
|
+
useEffect6(() => {
|
|
1959
2162
|
if (!isWorkerMode) return;
|
|
1960
|
-
const
|
|
1961
|
-
|
|
2163
|
+
const currentWorkerApi = workerApiRef.current;
|
|
2164
|
+
if (!currentWorkerApi || !clipId) return;
|
|
1962
2165
|
const canvases2 = canvasesRef.current;
|
|
1963
|
-
const
|
|
1964
|
-
const
|
|
2166
|
+
const newIds = [];
|
|
2167
|
+
const newWidths = [];
|
|
1965
2168
|
for (let i = 0; i < canvases2.length; i++) {
|
|
1966
2169
|
const canvas = canvases2[i];
|
|
1967
2170
|
if (!canvas) continue;
|
|
1968
2171
|
if (transferredCanvasesRef.current.has(canvas)) continue;
|
|
1969
|
-
const
|
|
2172
|
+
const canvasIdx = parseInt(canvas.dataset.index, 10);
|
|
2173
|
+
const canvasId = `${clipId}-ch${channelIndex}-chunk${canvasIdx}`;
|
|
2174
|
+
let offscreen;
|
|
1970
2175
|
try {
|
|
1971
|
-
|
|
1972
|
-
workerApi.registerCanvas(canvasId, offscreen);
|
|
1973
|
-
transferredCanvasesRef.current.add(canvas);
|
|
1974
|
-
ids.push(canvasId);
|
|
1975
|
-
widths.push(Math.min(length - i * MAX_CANVAS_WIDTH2, MAX_CANVAS_WIDTH2));
|
|
2176
|
+
offscreen = canvas.transferControlToOffscreen();
|
|
1976
2177
|
} catch (err) {
|
|
1977
2178
|
console.warn(`[spectrogram] transferControlToOffscreen failed for ${canvasId}:`, err);
|
|
1978
2179
|
continue;
|
|
1979
2180
|
}
|
|
2181
|
+
transferredCanvasesRef.current.add(canvas);
|
|
2182
|
+
try {
|
|
2183
|
+
currentWorkerApi.registerCanvas(canvasId, offscreen);
|
|
2184
|
+
newIds.push(canvasId);
|
|
2185
|
+
newWidths.push(Math.min(length - canvasIdx * MAX_CANVAS_WIDTH, MAX_CANVAS_WIDTH));
|
|
2186
|
+
} catch (err) {
|
|
2187
|
+
console.warn(`[spectrogram] registerCanvas failed for ${canvasId}:`, err);
|
|
2188
|
+
continue;
|
|
2189
|
+
}
|
|
1980
2190
|
}
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
2191
|
+
if (newIds.length > 0) {
|
|
2192
|
+
registeredIdsRef.current = [...registeredIdsRef.current, ...newIds];
|
|
2193
|
+
onCanvasesReadyRef.current?.(newIds, newWidths);
|
|
1984
2194
|
}
|
|
2195
|
+
}, [isWorkerMode, clipId, channelIndex, length, visibleChunkKey]);
|
|
2196
|
+
useEffect6(() => {
|
|
2197
|
+
if (!isWorkerMode) return;
|
|
2198
|
+
const currentWorkerApi = workerApiRef.current;
|
|
2199
|
+
if (!currentWorkerApi) return;
|
|
2200
|
+
const remaining = [];
|
|
2201
|
+
for (const id of registeredIdsRef.current) {
|
|
2202
|
+
const match = id.match(/chunk(\d+)$/);
|
|
2203
|
+
if (!match) {
|
|
2204
|
+
remaining.push(id);
|
|
2205
|
+
continue;
|
|
2206
|
+
}
|
|
2207
|
+
const chunkIdx = parseInt(match[1], 10);
|
|
2208
|
+
const canvas = canvasesRef.current[chunkIdx];
|
|
2209
|
+
if (canvas && canvas.isConnected) {
|
|
2210
|
+
remaining.push(id);
|
|
2211
|
+
} else {
|
|
2212
|
+
try {
|
|
2213
|
+
currentWorkerApi.unregisterCanvas(id);
|
|
2214
|
+
} catch (err) {
|
|
2215
|
+
console.warn(`[spectrogram] unregisterCanvas failed for ${id}:`, err);
|
|
2216
|
+
}
|
|
2217
|
+
}
|
|
2218
|
+
}
|
|
2219
|
+
registeredIdsRef.current = remaining;
|
|
2220
|
+
});
|
|
2221
|
+
useEffect6(() => {
|
|
1985
2222
|
return () => {
|
|
2223
|
+
const api = workerApiRef.current;
|
|
2224
|
+
if (!api) return;
|
|
1986
2225
|
for (const id of registeredIdsRef.current) {
|
|
1987
|
-
|
|
2226
|
+
try {
|
|
2227
|
+
api.unregisterCanvas(id);
|
|
2228
|
+
} catch (err) {
|
|
2229
|
+
console.warn(`[spectrogram] unregisterCanvas failed for ${id}:`, err);
|
|
2230
|
+
}
|
|
1988
2231
|
}
|
|
1989
2232
|
registeredIdsRef.current = [];
|
|
1990
2233
|
};
|
|
1991
|
-
}, [
|
|
1992
|
-
const lut = colorLUT ?? defaultGetColorMap();
|
|
1993
|
-
const maxF = maxFrequency ?? (data ? data.sampleRate / 2 : 22050);
|
|
1994
|
-
const scaleFn = frequencyScaleFn ?? ((f, minF, maxF2) => (f - minF) / (maxF2 - minF));
|
|
2234
|
+
}, []);
|
|
1995
2235
|
useLayoutEffect2(() => {
|
|
1996
2236
|
if (isWorkerMode || !data) return;
|
|
1997
2237
|
const canvases2 = canvasesRef.current;
|
|
1998
2238
|
const { frequencyBinCount, frameCount, hopSize, sampleRate, gainDb, rangeDb: rawRangeDb } = data;
|
|
1999
2239
|
const rangeDb = rawRangeDb === 0 ? 1 : rawRangeDb;
|
|
2000
|
-
let globalPixelOffset = 0;
|
|
2001
2240
|
const binToFreq = (bin) => bin / frequencyBinCount * (sampleRate / 2);
|
|
2002
|
-
for (let
|
|
2003
|
-
const canvas = canvases2[
|
|
2241
|
+
for (let i = 0; i < canvases2.length; i++) {
|
|
2242
|
+
const canvas = canvases2[i];
|
|
2004
2243
|
if (!canvas) continue;
|
|
2244
|
+
const canvasIdx = parseInt(canvas.dataset.index, 10);
|
|
2245
|
+
const globalPixelOffset = canvasIdx * MAX_CANVAS_WIDTH;
|
|
2005
2246
|
const ctx = canvas.getContext("2d");
|
|
2006
2247
|
if (!ctx) continue;
|
|
2007
2248
|
const canvasWidth = canvas.width / devicePixelRatio;
|
|
@@ -2021,7 +2262,7 @@ var SpectrogramChannel = ({
|
|
|
2021
2262
|
for (let y = 0; y < canvasHeight; y++) {
|
|
2022
2263
|
const normalizedY = 1 - y / canvasHeight;
|
|
2023
2264
|
let bin = Math.floor(normalizedY * frequencyBinCount);
|
|
2024
|
-
if (
|
|
2265
|
+
if (hasCustomFrequencyScale) {
|
|
2025
2266
|
let lo = 0;
|
|
2026
2267
|
let hi = frequencyBinCount - 1;
|
|
2027
2268
|
while (lo < hi) {
|
|
@@ -2060,36 +2301,30 @@ var SpectrogramChannel = ({
|
|
|
2060
2301
|
ctx.imageSmoothingEnabled = false;
|
|
2061
2302
|
ctx.drawImage(tmpCanvas, 0, 0, canvas.width, canvas.height);
|
|
2062
2303
|
}
|
|
2063
|
-
globalPixelOffset += canvasWidth;
|
|
2064
2304
|
}
|
|
2065
|
-
}, [isWorkerMode, data, length, waveHeight, devicePixelRatio, samplesPerPixel, lut,
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
},
|
|
2082
|
-
`${length}-${canvasCount}`
|
|
2083
|
-
)
|
|
2305
|
+
}, [isWorkerMode, data, length, waveHeight, devicePixelRatio, samplesPerPixel, lut, minFrequency, maxF, scaleFn, hasCustomFrequencyScale, visibleChunkKey]);
|
|
2306
|
+
const canvases = visibleChunkIndices.map((i) => {
|
|
2307
|
+
const chunkLeft = i * MAX_CANVAS_WIDTH;
|
|
2308
|
+
const currentWidth = Math.min(length - chunkLeft, MAX_CANVAS_WIDTH);
|
|
2309
|
+
return /* @__PURE__ */ jsx20(
|
|
2310
|
+
SpectrogramCanvas,
|
|
2311
|
+
{
|
|
2312
|
+
$cssWidth: currentWidth,
|
|
2313
|
+
$left: chunkLeft,
|
|
2314
|
+
width: currentWidth * devicePixelRatio,
|
|
2315
|
+
height: waveHeight * devicePixelRatio,
|
|
2316
|
+
$waveHeight: waveHeight,
|
|
2317
|
+
"data-index": i,
|
|
2318
|
+
ref: canvasRef
|
|
2319
|
+
},
|
|
2320
|
+
`${length}-${i}`
|
|
2084
2321
|
);
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
}
|
|
2088
|
-
return /* @__PURE__ */ jsx18(Wrapper3, { $index: index, $cssWidth: length, $waveHeight: waveHeight, children: canvases });
|
|
2322
|
+
});
|
|
2323
|
+
return /* @__PURE__ */ jsx20(Wrapper3, { $index: index, $cssWidth: length, $waveHeight: waveHeight, children: canvases });
|
|
2089
2324
|
};
|
|
2090
2325
|
|
|
2091
2326
|
// src/components/SmartChannel.tsx
|
|
2092
|
-
import { Fragment as
|
|
2327
|
+
import { Fragment as Fragment5, jsx as jsx21, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
2093
2328
|
var SmartChannel = ({
|
|
2094
2329
|
isSelected,
|
|
2095
2330
|
transparentBackground,
|
|
@@ -2114,7 +2349,7 @@ var SmartChannel = ({
|
|
|
2114
2349
|
const drawMode = theme?.waveformDrawMode || "inverted";
|
|
2115
2350
|
const hasSpectrogram = spectrogramData || spectrogramWorkerApi;
|
|
2116
2351
|
if (renderMode === "spectrogram" && hasSpectrogram) {
|
|
2117
|
-
return /* @__PURE__ */
|
|
2352
|
+
return /* @__PURE__ */ jsx21(
|
|
2118
2353
|
SpectrogramChannel,
|
|
2119
2354
|
{
|
|
2120
2355
|
index: props.index,
|
|
@@ -2135,8 +2370,8 @@ var SmartChannel = ({
|
|
|
2135
2370
|
}
|
|
2136
2371
|
if (renderMode === "both" && hasSpectrogram) {
|
|
2137
2372
|
const halfHeight = Math.floor(waveHeight / 2);
|
|
2138
|
-
return /* @__PURE__ */ jsxs9(
|
|
2139
|
-
/* @__PURE__ */
|
|
2373
|
+
return /* @__PURE__ */ jsxs9(Fragment5, { children: [
|
|
2374
|
+
/* @__PURE__ */ jsx21(
|
|
2140
2375
|
SpectrogramChannel,
|
|
2141
2376
|
{
|
|
2142
2377
|
index: props.index * 2,
|
|
@@ -2155,11 +2390,10 @@ var SmartChannel = ({
|
|
|
2155
2390
|
onCanvasesReady: spectrogramOnCanvasesReady
|
|
2156
2391
|
}
|
|
2157
2392
|
),
|
|
2158
|
-
/* @__PURE__ */
|
|
2393
|
+
/* @__PURE__ */ jsx21("div", { style: { position: "absolute", top: (props.index * 2 + 1) * halfHeight, width: props.length, height: halfHeight }, children: /* @__PURE__ */ jsx21(
|
|
2159
2394
|
Channel,
|
|
2160
2395
|
{
|
|
2161
2396
|
...props,
|
|
2162
|
-
...theme,
|
|
2163
2397
|
index: 0,
|
|
2164
2398
|
waveOutlineColor,
|
|
2165
2399
|
waveFillColor,
|
|
@@ -2173,11 +2407,10 @@ var SmartChannel = ({
|
|
|
2173
2407
|
) })
|
|
2174
2408
|
] });
|
|
2175
2409
|
}
|
|
2176
|
-
return /* @__PURE__ */
|
|
2410
|
+
return /* @__PURE__ */ jsx21(
|
|
2177
2411
|
Channel,
|
|
2178
2412
|
{
|
|
2179
2413
|
...props,
|
|
2180
|
-
...theme,
|
|
2181
2414
|
waveOutlineColor,
|
|
2182
2415
|
waveFillColor,
|
|
2183
2416
|
waveHeight,
|
|
@@ -2191,9 +2424,9 @@ var SmartChannel = ({
|
|
|
2191
2424
|
};
|
|
2192
2425
|
|
|
2193
2426
|
// src/components/SpectrogramLabels.tsx
|
|
2194
|
-
import { useRef as
|
|
2427
|
+
import { useRef as useRef7, useLayoutEffect as useLayoutEffect3 } from "react";
|
|
2195
2428
|
import styled20 from "styled-components";
|
|
2196
|
-
import { jsx as
|
|
2429
|
+
import { jsx as jsx22 } from "react/jsx-runtime";
|
|
2197
2430
|
var LABELS_WIDTH = 72;
|
|
2198
2431
|
var LabelsStickyWrapper = styled20.div`
|
|
2199
2432
|
position: sticky;
|
|
@@ -2243,7 +2476,7 @@ var SpectrogramLabels = ({
|
|
|
2243
2476
|
renderMode = "spectrogram",
|
|
2244
2477
|
hasClipHeaders = false
|
|
2245
2478
|
}) => {
|
|
2246
|
-
const canvasRef =
|
|
2479
|
+
const canvasRef = useRef7(null);
|
|
2247
2480
|
const devicePixelRatio = useDevicePixelRatio();
|
|
2248
2481
|
const spectrogramHeight = renderMode === "both" ? Math.floor(waveHeight / 2) : waveHeight;
|
|
2249
2482
|
const totalHeight = numChannels * waveHeight;
|
|
@@ -2275,7 +2508,7 @@ var SpectrogramLabels = ({
|
|
|
2275
2508
|
}
|
|
2276
2509
|
}
|
|
2277
2510
|
}, [waveHeight, numChannels, frequencyScaleFn, minFrequency, maxFrequency, labelsColor, labelsBackground, devicePixelRatio, spectrogramHeight, clipHeaderOffset]);
|
|
2278
|
-
return /* @__PURE__ */
|
|
2511
|
+
return /* @__PURE__ */ jsx22(LabelsStickyWrapper, { $height: totalHeight + clipHeaderOffset, children: /* @__PURE__ */ jsx22(
|
|
2279
2512
|
"canvas",
|
|
2280
2513
|
{
|
|
2281
2514
|
ref: canvasRef,
|
|
@@ -2291,10 +2524,10 @@ var SpectrogramLabels = ({
|
|
|
2291
2524
|
};
|
|
2292
2525
|
|
|
2293
2526
|
// src/components/SmartScale.tsx
|
|
2294
|
-
import { useContext as
|
|
2527
|
+
import { useContext as useContext8 } from "react";
|
|
2295
2528
|
|
|
2296
2529
|
// src/components/TimeScale.tsx
|
|
2297
|
-
import
|
|
2530
|
+
import React15, { useRef as useRef8, useEffect as useEffect7, useLayoutEffect as useLayoutEffect4, useContext as useContext7, useMemo, useCallback as useCallback6 } from "react";
|
|
2298
2531
|
import styled21, { withTheme as withTheme2 } from "styled-components";
|
|
2299
2532
|
|
|
2300
2533
|
// src/utils/conversions.ts
|
|
@@ -2318,7 +2551,7 @@ function secondsToPixels(seconds, samplesPerPixel, sampleRate) {
|
|
|
2318
2551
|
}
|
|
2319
2552
|
|
|
2320
2553
|
// src/components/TimeScale.tsx
|
|
2321
|
-
import { jsx as
|
|
2554
|
+
import { jsx as jsx23, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
2322
2555
|
function formatTime2(milliseconds) {
|
|
2323
2556
|
const seconds = Math.floor(milliseconds / 1e3);
|
|
2324
2557
|
const s = seconds % 60;
|
|
@@ -2337,16 +2570,17 @@ var PlaylistTimeScaleScroll = styled21.div.attrs((props) => ({
|
|
|
2337
2570
|
border-bottom: 1px solid ${(props) => props.theme.timeColor};
|
|
2338
2571
|
box-sizing: border-box;
|
|
2339
2572
|
`;
|
|
2340
|
-
var
|
|
2573
|
+
var TimeTickChunk = styled21.canvas.attrs((props) => ({
|
|
2341
2574
|
style: {
|
|
2342
2575
|
width: `${props.$cssWidth}px`,
|
|
2343
|
-
height: `${props.$timeScaleHeight}px
|
|
2576
|
+
height: `${props.$timeScaleHeight}px`,
|
|
2577
|
+
left: `${props.$left}px`
|
|
2344
2578
|
}
|
|
2345
2579
|
}))`
|
|
2346
2580
|
position: absolute;
|
|
2347
|
-
left: 0;
|
|
2348
|
-
right: 0;
|
|
2349
2581
|
bottom: 0;
|
|
2582
|
+
/* Promote to own compositing layer for smoother scrolling */
|
|
2583
|
+
will-change: transform;
|
|
2350
2584
|
`;
|
|
2351
2585
|
var TimeStamp = styled21.div.attrs((props) => ({
|
|
2352
2586
|
style: {
|
|
@@ -2368,60 +2602,111 @@ var TimeScale = (props) => {
|
|
|
2368
2602
|
secondStep,
|
|
2369
2603
|
renderTimestamp
|
|
2370
2604
|
} = props;
|
|
2371
|
-
const
|
|
2372
|
-
const timeMarkers = [];
|
|
2373
|
-
const canvasRef = useRef6(null);
|
|
2605
|
+
const canvasRefsMap = useRef8(/* @__PURE__ */ new Map());
|
|
2374
2606
|
const {
|
|
2375
2607
|
sampleRate,
|
|
2376
2608
|
samplesPerPixel,
|
|
2377
2609
|
timeScaleHeight,
|
|
2378
2610
|
controls: { show: showControls, width: controlWidth }
|
|
2379
|
-
} =
|
|
2611
|
+
} = useContext7(PlaylistInfoContext);
|
|
2380
2612
|
const devicePixelRatio = useDevicePixelRatio();
|
|
2381
|
-
|
|
2382
|
-
if (
|
|
2383
|
-
const
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2613
|
+
const canvasRefCallback = useCallback6((canvas) => {
|
|
2614
|
+
if (canvas !== null) {
|
|
2615
|
+
const idx = parseInt(canvas.dataset.index, 10);
|
|
2616
|
+
canvasRefsMap.current.set(idx, canvas);
|
|
2617
|
+
}
|
|
2618
|
+
}, []);
|
|
2619
|
+
const { widthX, canvasInfo, timeMarkersWithPositions } = useMemo(() => {
|
|
2620
|
+
const nextCanvasInfo = /* @__PURE__ */ new Map();
|
|
2621
|
+
const nextMarkers = [];
|
|
2622
|
+
const nextWidthX = secondsToPixels(duration / 1e3, samplesPerPixel, sampleRate);
|
|
2623
|
+
const pixPerSec = sampleRate / samplesPerPixel;
|
|
2624
|
+
let counter = 0;
|
|
2625
|
+
for (let i = 0; i < nextWidthX; i += pixPerSec * secondStep / 1e3) {
|
|
2626
|
+
const pix = Math.floor(i);
|
|
2627
|
+
if (counter % marker === 0) {
|
|
2628
|
+
const timeMs = counter;
|
|
2629
|
+
const timestamp = formatTime2(timeMs);
|
|
2630
|
+
const element = renderTimestamp ? /* @__PURE__ */ jsx23(React15.Fragment, { children: renderTimestamp(timeMs, pix) }, `timestamp-${counter}`) : /* @__PURE__ */ jsx23(TimeStamp, { $left: pix, children: timestamp }, timestamp);
|
|
2631
|
+
nextMarkers.push({ pix, element });
|
|
2632
|
+
nextCanvasInfo.set(pix, timeScaleHeight);
|
|
2633
|
+
} else if (counter % bigStep === 0) {
|
|
2634
|
+
nextCanvasInfo.set(pix, Math.floor(timeScaleHeight / 2));
|
|
2635
|
+
} else if (counter % secondStep === 0) {
|
|
2636
|
+
nextCanvasInfo.set(pix, Math.floor(timeScaleHeight / 5));
|
|
2637
|
+
}
|
|
2638
|
+
counter += secondStep;
|
|
2639
|
+
}
|
|
2640
|
+
return {
|
|
2641
|
+
widthX: nextWidthX,
|
|
2642
|
+
canvasInfo: nextCanvasInfo,
|
|
2643
|
+
timeMarkersWithPositions: nextMarkers
|
|
2644
|
+
};
|
|
2645
|
+
}, [duration, samplesPerPixel, sampleRate, marker, bigStep, secondStep, renderTimestamp, timeScaleHeight]);
|
|
2646
|
+
const visibleChunkKey = useScrollViewportSelector((viewport) => {
|
|
2647
|
+
const totalChunks = Math.ceil(widthX / MAX_CANVAS_WIDTH);
|
|
2648
|
+
const indices = [];
|
|
2649
|
+
for (let i = 0; i < totalChunks; i++) {
|
|
2650
|
+
const chunkLeft = i * MAX_CANVAS_WIDTH;
|
|
2651
|
+
const chunkWidth = Math.min(widthX - chunkLeft, MAX_CANVAS_WIDTH);
|
|
2652
|
+
if (viewport) {
|
|
2653
|
+
const chunkEnd = chunkLeft + chunkWidth;
|
|
2654
|
+
if (chunkEnd <= viewport.visibleStart || chunkLeft >= viewport.visibleEnd) {
|
|
2655
|
+
continue;
|
|
2394
2656
|
}
|
|
2395
2657
|
}
|
|
2658
|
+
indices.push(i);
|
|
2396
2659
|
}
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2660
|
+
return indices.join(",");
|
|
2661
|
+
});
|
|
2662
|
+
const visibleChunkIndices = visibleChunkKey ? visibleChunkKey.split(",").map(Number) : [];
|
|
2663
|
+
const visibleChunks = visibleChunkIndices.map((i) => {
|
|
2664
|
+
const chunkLeft = i * MAX_CANVAS_WIDTH;
|
|
2665
|
+
const chunkWidth = Math.min(widthX - chunkLeft, MAX_CANVAS_WIDTH);
|
|
2666
|
+
return /* @__PURE__ */ jsx23(
|
|
2667
|
+
TimeTickChunk,
|
|
2668
|
+
{
|
|
2669
|
+
$cssWidth: chunkWidth,
|
|
2670
|
+
$left: chunkLeft,
|
|
2671
|
+
$timeScaleHeight: timeScaleHeight,
|
|
2672
|
+
width: chunkWidth * devicePixelRatio,
|
|
2673
|
+
height: timeScaleHeight * devicePixelRatio,
|
|
2674
|
+
"data-index": i,
|
|
2675
|
+
ref: canvasRefCallback
|
|
2676
|
+
},
|
|
2677
|
+
`timescale-${i}`
|
|
2678
|
+
);
|
|
2679
|
+
});
|
|
2680
|
+
const firstChunkLeft = visibleChunkIndices.length > 0 ? visibleChunkIndices[0] * MAX_CANVAS_WIDTH : 0;
|
|
2681
|
+
const lastChunkRight = visibleChunkIndices.length > 0 ? (visibleChunkIndices[visibleChunkIndices.length - 1] + 1) * MAX_CANVAS_WIDTH : Infinity;
|
|
2682
|
+
const visibleMarkers = visibleChunkIndices.length > 0 ? timeMarkersWithPositions.filter(({ pix }) => pix >= firstChunkLeft && pix < lastChunkRight).map(({ element }) => element) : timeMarkersWithPositions.map(({ element }) => element);
|
|
2683
|
+
useEffect7(() => {
|
|
2684
|
+
const currentMap = canvasRefsMap.current;
|
|
2685
|
+
for (const [idx, canvas] of currentMap.entries()) {
|
|
2686
|
+
if (!canvas.isConnected) {
|
|
2687
|
+
currentMap.delete(idx);
|
|
2688
|
+
}
|
|
2422
2689
|
}
|
|
2423
|
-
|
|
2424
|
-
|
|
2690
|
+
});
|
|
2691
|
+
useLayoutEffect4(() => {
|
|
2692
|
+
for (const [chunkIdx, canvas] of canvasRefsMap.current.entries()) {
|
|
2693
|
+
const ctx = canvas.getContext("2d");
|
|
2694
|
+
if (!ctx) continue;
|
|
2695
|
+
const chunkLeft = chunkIdx * MAX_CANVAS_WIDTH;
|
|
2696
|
+
const chunkWidth = canvas.width / devicePixelRatio;
|
|
2697
|
+
ctx.resetTransform();
|
|
2698
|
+
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
2699
|
+
ctx.imageSmoothingEnabled = false;
|
|
2700
|
+
ctx.fillStyle = timeColor;
|
|
2701
|
+
ctx.scale(devicePixelRatio, devicePixelRatio);
|
|
2702
|
+
for (const [pixLeft, scaleHeight] of canvasInfo.entries()) {
|
|
2703
|
+
if (pixLeft < chunkLeft || pixLeft >= chunkLeft + chunkWidth) continue;
|
|
2704
|
+
const localX = pixLeft - chunkLeft;
|
|
2705
|
+
const scaleY = timeScaleHeight - scaleHeight;
|
|
2706
|
+
ctx.fillRect(localX, scaleY, 1, scaleHeight);
|
|
2707
|
+
}
|
|
2708
|
+
}
|
|
2709
|
+
}, [duration, devicePixelRatio, timeColor, timeScaleHeight, canvasInfo, visibleChunkKey]);
|
|
2425
2710
|
return /* @__PURE__ */ jsxs10(
|
|
2426
2711
|
PlaylistTimeScaleScroll,
|
|
2427
2712
|
{
|
|
@@ -2429,17 +2714,8 @@ var TimeScale = (props) => {
|
|
|
2429
2714
|
$controlWidth: showControls ? controlWidth : 0,
|
|
2430
2715
|
$timeScaleHeight: timeScaleHeight,
|
|
2431
2716
|
children: [
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
TimeTicks,
|
|
2435
|
-
{
|
|
2436
|
-
$cssWidth: widthX,
|
|
2437
|
-
$timeScaleHeight: timeScaleHeight,
|
|
2438
|
-
width: widthX * devicePixelRatio,
|
|
2439
|
-
height: timeScaleHeight * devicePixelRatio,
|
|
2440
|
-
ref: canvasRef
|
|
2441
|
-
}
|
|
2442
|
-
)
|
|
2717
|
+
visibleMarkers,
|
|
2718
|
+
visibleChunks
|
|
2443
2719
|
]
|
|
2444
2720
|
}
|
|
2445
2721
|
);
|
|
@@ -2447,7 +2723,7 @@ var TimeScale = (props) => {
|
|
|
2447
2723
|
var StyledTimeScale = withTheme2(TimeScale);
|
|
2448
2724
|
|
|
2449
2725
|
// src/components/SmartScale.tsx
|
|
2450
|
-
import { jsx as
|
|
2726
|
+
import { jsx as jsx24 } from "react/jsx-runtime";
|
|
2451
2727
|
var timeinfo = /* @__PURE__ */ new Map([
|
|
2452
2728
|
[
|
|
2453
2729
|
700,
|
|
@@ -2521,9 +2797,9 @@ function getScaleInfo(samplesPerPixel) {
|
|
|
2521
2797
|
return config;
|
|
2522
2798
|
}
|
|
2523
2799
|
var SmartScale = ({ renderTimestamp }) => {
|
|
2524
|
-
const { samplesPerPixel, duration } =
|
|
2800
|
+
const { samplesPerPixel, duration } = useContext8(PlaylistInfoContext);
|
|
2525
2801
|
let config = getScaleInfo(samplesPerPixel);
|
|
2526
|
-
return /* @__PURE__ */
|
|
2802
|
+
return /* @__PURE__ */ jsx24(
|
|
2527
2803
|
StyledTimeScale,
|
|
2528
2804
|
{
|
|
2529
2805
|
marker: config.marker,
|
|
@@ -2537,7 +2813,7 @@ var SmartScale = ({ renderTimestamp }) => {
|
|
|
2537
2813
|
|
|
2538
2814
|
// src/components/TimeFormatSelect.tsx
|
|
2539
2815
|
import styled22 from "styled-components";
|
|
2540
|
-
import { jsx as
|
|
2816
|
+
import { jsx as jsx25 } from "react/jsx-runtime";
|
|
2541
2817
|
var SelectWrapper = styled22.div`
|
|
2542
2818
|
display: inline-flex;
|
|
2543
2819
|
align-items: center;
|
|
@@ -2560,7 +2836,7 @@ var TimeFormatSelect = ({
|
|
|
2560
2836
|
const handleChange = (e) => {
|
|
2561
2837
|
onChange(e.target.value);
|
|
2562
2838
|
};
|
|
2563
|
-
return /* @__PURE__ */
|
|
2839
|
+
return /* @__PURE__ */ jsx25(SelectWrapper, { className, children: /* @__PURE__ */ jsx25(
|
|
2564
2840
|
BaseSelect,
|
|
2565
2841
|
{
|
|
2566
2842
|
className: "time-format",
|
|
@@ -2568,14 +2844,14 @@ var TimeFormatSelect = ({
|
|
|
2568
2844
|
onChange: handleChange,
|
|
2569
2845
|
disabled,
|
|
2570
2846
|
"aria-label": "Time format selection",
|
|
2571
|
-
children: TIME_FORMAT_OPTIONS.map((option) => /* @__PURE__ */
|
|
2847
|
+
children: TIME_FORMAT_OPTIONS.map((option) => /* @__PURE__ */ jsx25("option", { value: option.value, children: option.label }, option.value))
|
|
2572
2848
|
}
|
|
2573
2849
|
) });
|
|
2574
2850
|
};
|
|
2575
2851
|
|
|
2576
2852
|
// src/components/Track.tsx
|
|
2577
2853
|
import styled23 from "styled-components";
|
|
2578
|
-
import { jsx as
|
|
2854
|
+
import { jsx as jsx26, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
2579
2855
|
var Container = styled23.div.attrs((props) => ({
|
|
2580
2856
|
style: {
|
|
2581
2857
|
height: `${props.$waveHeight * props.$numChannels + (props.$hasClipHeaders ? CLIP_HEADER_HEIGHT : 0)}px`
|
|
@@ -2641,7 +2917,7 @@ var Track = ({
|
|
|
2641
2917
|
$hasClipHeaders: hasClipHeaders,
|
|
2642
2918
|
$isSelected: isSelected,
|
|
2643
2919
|
children: [
|
|
2644
|
-
/* @__PURE__ */
|
|
2920
|
+
/* @__PURE__ */ jsx26(
|
|
2645
2921
|
ControlsWrapper,
|
|
2646
2922
|
{
|
|
2647
2923
|
$controlWidth: show ? controlWidth : 0,
|
|
@@ -2649,7 +2925,7 @@ var Track = ({
|
|
|
2649
2925
|
children: controls
|
|
2650
2926
|
}
|
|
2651
2927
|
),
|
|
2652
|
-
/* @__PURE__ */
|
|
2928
|
+
/* @__PURE__ */ jsx26(
|
|
2653
2929
|
ChannelContainer,
|
|
2654
2930
|
{
|
|
2655
2931
|
$controlWidth: show ? controlWidth : 0,
|
|
@@ -2757,7 +3033,7 @@ var ButtonGroup = styled25.div`
|
|
|
2757
3033
|
// src/components/TrackControls/CloseButton.tsx
|
|
2758
3034
|
import styled26 from "styled-components";
|
|
2759
3035
|
import { X as XIcon } from "@phosphor-icons/react";
|
|
2760
|
-
import { jsx as
|
|
3036
|
+
import { jsx as jsx27 } from "react/jsx-runtime";
|
|
2761
3037
|
var StyledCloseButton = styled26.button`
|
|
2762
3038
|
position: absolute;
|
|
2763
3039
|
left: 0;
|
|
@@ -2782,7 +3058,7 @@ var StyledCloseButton = styled26.button`
|
|
|
2782
3058
|
var CloseButton = ({
|
|
2783
3059
|
onClick,
|
|
2784
3060
|
title = "Remove track"
|
|
2785
|
-
}) => /* @__PURE__ */
|
|
3061
|
+
}) => /* @__PURE__ */ jsx27(StyledCloseButton, { onClick, title, children: /* @__PURE__ */ jsx27(XIcon, { size: 12, weight: "bold" }) });
|
|
2786
3062
|
|
|
2787
3063
|
// src/components/TrackControls/Controls.tsx
|
|
2788
3064
|
import styled27 from "styled-components";
|
|
@@ -2818,23 +3094,23 @@ var Header = styled28.header`
|
|
|
2818
3094
|
|
|
2819
3095
|
// src/components/TrackControls/VolumeDownIcon.tsx
|
|
2820
3096
|
import { SpeakerLowIcon } from "@phosphor-icons/react";
|
|
2821
|
-
import { jsx as
|
|
2822
|
-
var VolumeDownIcon = (props) => /* @__PURE__ */
|
|
3097
|
+
import { jsx as jsx28 } from "react/jsx-runtime";
|
|
3098
|
+
var VolumeDownIcon = (props) => /* @__PURE__ */ jsx28(SpeakerLowIcon, { weight: "light", ...props });
|
|
2823
3099
|
|
|
2824
3100
|
// src/components/TrackControls/VolumeUpIcon.tsx
|
|
2825
3101
|
import { SpeakerHighIcon } from "@phosphor-icons/react";
|
|
2826
|
-
import { jsx as
|
|
2827
|
-
var VolumeUpIcon = (props) => /* @__PURE__ */
|
|
3102
|
+
import { jsx as jsx29 } from "react/jsx-runtime";
|
|
3103
|
+
var VolumeUpIcon = (props) => /* @__PURE__ */ jsx29(SpeakerHighIcon, { weight: "light", ...props });
|
|
2828
3104
|
|
|
2829
3105
|
// src/components/TrackControls/TrashIcon.tsx
|
|
2830
3106
|
import { TrashIcon as PhosphorTrashIcon } from "@phosphor-icons/react";
|
|
2831
|
-
import { jsx as
|
|
2832
|
-
var TrashIcon = (props) => /* @__PURE__ */
|
|
3107
|
+
import { jsx as jsx30 } from "react/jsx-runtime";
|
|
3108
|
+
var TrashIcon = (props) => /* @__PURE__ */ jsx30(PhosphorTrashIcon, { weight: "light", ...props });
|
|
2833
3109
|
|
|
2834
3110
|
// src/components/TrackControls/DotsIcon.tsx
|
|
2835
3111
|
import { DotsThreeIcon } from "@phosphor-icons/react";
|
|
2836
|
-
import { jsx as
|
|
2837
|
-
var DotsIcon = (props) => /* @__PURE__ */
|
|
3112
|
+
import { jsx as jsx31 } from "react/jsx-runtime";
|
|
3113
|
+
var DotsIcon = (props) => /* @__PURE__ */ jsx31(DotsThreeIcon, { weight: "bold", ...props });
|
|
2838
3114
|
|
|
2839
3115
|
// src/components/TrackControls/Slider.tsx
|
|
2840
3116
|
import styled29 from "styled-components";
|
|
@@ -2902,10 +3178,10 @@ var SliderWrapper = styled30.label`
|
|
|
2902
3178
|
`;
|
|
2903
3179
|
|
|
2904
3180
|
// src/components/TrackMenu.tsx
|
|
2905
|
-
import
|
|
3181
|
+
import React17, { useState as useState6, useEffect as useEffect8, useRef as useRef9 } from "react";
|
|
2906
3182
|
import { createPortal } from "react-dom";
|
|
2907
3183
|
import styled31 from "styled-components";
|
|
2908
|
-
import { jsx as
|
|
3184
|
+
import { jsx as jsx32, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
2909
3185
|
var MenuContainer = styled31.div`
|
|
2910
3186
|
position: relative;
|
|
2911
3187
|
display: inline-block;
|
|
@@ -2950,9 +3226,9 @@ var TrackMenu = ({
|
|
|
2950
3226
|
const close = () => setOpen(false);
|
|
2951
3227
|
const items = typeof itemsProp === "function" ? itemsProp(close) : itemsProp;
|
|
2952
3228
|
const [dropdownPos, setDropdownPos] = useState6({ top: 0, left: 0 });
|
|
2953
|
-
const buttonRef =
|
|
2954
|
-
const dropdownRef =
|
|
2955
|
-
|
|
3229
|
+
const buttonRef = useRef9(null);
|
|
3230
|
+
const dropdownRef = useRef9(null);
|
|
3231
|
+
useEffect8(() => {
|
|
2956
3232
|
if (open && buttonRef.current) {
|
|
2957
3233
|
const rect = buttonRef.current.getBoundingClientRect();
|
|
2958
3234
|
setDropdownPos({
|
|
@@ -2961,7 +3237,7 @@ var TrackMenu = ({
|
|
|
2961
3237
|
});
|
|
2962
3238
|
}
|
|
2963
3239
|
}, [open]);
|
|
2964
|
-
|
|
3240
|
+
useEffect8(() => {
|
|
2965
3241
|
if (!open) return;
|
|
2966
3242
|
const handleClick = (e) => {
|
|
2967
3243
|
const target = e.target;
|
|
@@ -2973,7 +3249,7 @@ var TrackMenu = ({
|
|
|
2973
3249
|
return () => document.removeEventListener("mousedown", handleClick);
|
|
2974
3250
|
}, [open]);
|
|
2975
3251
|
return /* @__PURE__ */ jsxs12(MenuContainer, { children: [
|
|
2976
|
-
/* @__PURE__ */
|
|
3252
|
+
/* @__PURE__ */ jsx32(
|
|
2977
3253
|
MenuButton,
|
|
2978
3254
|
{
|
|
2979
3255
|
ref: buttonRef,
|
|
@@ -2984,19 +3260,19 @@ var TrackMenu = ({
|
|
|
2984
3260
|
onMouseDown: (e) => e.stopPropagation(),
|
|
2985
3261
|
title: "Track menu",
|
|
2986
3262
|
"aria-label": "Track menu",
|
|
2987
|
-
children: /* @__PURE__ */
|
|
3263
|
+
children: /* @__PURE__ */ jsx32(DotsIcon, { size: 16 })
|
|
2988
3264
|
}
|
|
2989
3265
|
),
|
|
2990
3266
|
open && typeof document !== "undefined" && createPortal(
|
|
2991
|
-
/* @__PURE__ */
|
|
3267
|
+
/* @__PURE__ */ jsx32(
|
|
2992
3268
|
Dropdown,
|
|
2993
3269
|
{
|
|
2994
3270
|
ref: dropdownRef,
|
|
2995
3271
|
$top: dropdownPos.top,
|
|
2996
3272
|
$left: dropdownPos.left,
|
|
2997
3273
|
onMouseDown: (e) => e.stopPropagation(),
|
|
2998
|
-
children: items.map((item, index) => /* @__PURE__ */ jsxs12(
|
|
2999
|
-
index > 0 && /* @__PURE__ */
|
|
3274
|
+
children: items.map((item, index) => /* @__PURE__ */ jsxs12(React17.Fragment, { children: [
|
|
3275
|
+
index > 0 && /* @__PURE__ */ jsx32(Divider, {}),
|
|
3000
3276
|
item.content
|
|
3001
3277
|
] }, item.id))
|
|
3002
3278
|
}
|
|
@@ -3036,13 +3312,16 @@ export {
|
|
|
3036
3312
|
InlineLabel,
|
|
3037
3313
|
LoopRegion,
|
|
3038
3314
|
LoopRegionMarkers,
|
|
3315
|
+
MAX_CANVAS_WIDTH,
|
|
3039
3316
|
MasterVolumeControl,
|
|
3040
3317
|
Playhead,
|
|
3041
3318
|
PlayheadWithMarker,
|
|
3042
3319
|
Playlist,
|
|
3320
|
+
PlaylistErrorBoundary,
|
|
3043
3321
|
PlaylistInfoContext,
|
|
3044
3322
|
PlayoutProvider,
|
|
3045
3323
|
ScreenReaderOnly,
|
|
3324
|
+
ScrollViewportProvider,
|
|
3046
3325
|
Selection,
|
|
3047
3326
|
SelectionTimeInputs,
|
|
3048
3327
|
Slider,
|
|
@@ -3078,6 +3357,8 @@ export {
|
|
|
3078
3357
|
usePlaylistInfo,
|
|
3079
3358
|
usePlayoutStatus,
|
|
3080
3359
|
usePlayoutStatusUpdate,
|
|
3360
|
+
useScrollViewport,
|
|
3361
|
+
useScrollViewportSelector,
|
|
3081
3362
|
useTheme2 as useTheme,
|
|
3082
3363
|
useTrackControls,
|
|
3083
3364
|
waveformColorToCss
|