@waveform-playlist/ui-components 9.0.4 → 9.1.1
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 +37 -13
- package/dist/index.d.ts +37 -13
- package/dist/index.js +530 -349
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +473 -292
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
package/dist/index.mjs
CHANGED
|
@@ -334,7 +334,7 @@ var AutomaticScrollCheckbox = ({
|
|
|
334
334
|
};
|
|
335
335
|
|
|
336
336
|
// src/components/Channel.tsx
|
|
337
|
-
import {
|
|
337
|
+
import { useEffect as useEffect3 } from "react";
|
|
338
338
|
import styled9 from "styled-components";
|
|
339
339
|
|
|
340
340
|
// src/wfpl-theme.ts
|
|
@@ -410,6 +410,10 @@ var defaultTheme = {
|
|
|
410
410
|
annotationResizeHandleColor: "rgba(0, 0, 0, 0.4)",
|
|
411
411
|
annotationResizeHandleActiveColor: "rgba(0, 0, 0, 0.8)",
|
|
412
412
|
annotationTextItemHoverBackground: "rgba(0, 0, 0, 0.03)",
|
|
413
|
+
// Piano roll colors
|
|
414
|
+
pianoRollNoteColor: "#2a7070",
|
|
415
|
+
pianoRollSelectedNoteColor: "#3d9e9e",
|
|
416
|
+
pianoRollBackgroundColor: "#1a1a2e",
|
|
413
417
|
// Spacing and sizing
|
|
414
418
|
borderRadius: "4px",
|
|
415
419
|
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, sans-serif',
|
|
@@ -487,6 +491,10 @@ var darkTheme = {
|
|
|
487
491
|
annotationResizeHandleColor: "rgba(200, 160, 120, 0.5)",
|
|
488
492
|
annotationResizeHandleActiveColor: "rgba(220, 180, 140, 0.8)",
|
|
489
493
|
annotationTextItemHoverBackground: "rgba(200, 160, 120, 0.08)",
|
|
494
|
+
// Piano roll colors
|
|
495
|
+
pianoRollNoteColor: "#c49a6c",
|
|
496
|
+
pianoRollSelectedNoteColor: "#e8c090",
|
|
497
|
+
pianoRollBackgroundColor: "#0d0d14",
|
|
490
498
|
// Spacing and sizing
|
|
491
499
|
borderRadius: "4px",
|
|
492
500
|
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, sans-serif',
|
|
@@ -499,6 +507,7 @@ import {
|
|
|
499
507
|
createContext,
|
|
500
508
|
useContext,
|
|
501
509
|
useEffect,
|
|
510
|
+
useLayoutEffect,
|
|
502
511
|
useCallback,
|
|
503
512
|
useMemo,
|
|
504
513
|
useRef,
|
|
@@ -506,19 +515,32 @@ import {
|
|
|
506
515
|
} from "react";
|
|
507
516
|
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
508
517
|
var ViewportStore = class {
|
|
509
|
-
constructor() {
|
|
510
|
-
this._state = null;
|
|
518
|
+
constructor(containerEl) {
|
|
511
519
|
this._listeners = /* @__PURE__ */ new Set();
|
|
520
|
+
this._notifyRafId = null;
|
|
512
521
|
this.subscribe = (callback) => {
|
|
513
522
|
this._listeners.add(callback);
|
|
514
523
|
return () => this._listeners.delete(callback);
|
|
515
524
|
};
|
|
516
525
|
this.getSnapshot = () => this._state;
|
|
526
|
+
const width = containerEl?.clientWidth ?? (typeof window !== "undefined" ? window.innerWidth : 1024);
|
|
527
|
+
const buffer = width * 1.5;
|
|
528
|
+
this._state = {
|
|
529
|
+
scrollLeft: 0,
|
|
530
|
+
containerWidth: width,
|
|
531
|
+
visibleStart: 0,
|
|
532
|
+
visibleEnd: width + buffer
|
|
533
|
+
};
|
|
517
534
|
}
|
|
518
535
|
/**
|
|
519
536
|
* Update viewport state. Applies a 100px scroll threshold to skip updates
|
|
520
537
|
* that don't affect chunk visibility (1000px chunks with 1.5× overscan buffer).
|
|
521
538
|
* Only notifies listeners when the state actually changes.
|
|
539
|
+
*
|
|
540
|
+
* Listener notification is deferred by one frame via requestAnimationFrame
|
|
541
|
+
* to avoid conflicting with React 19's concurrent rendering. When React
|
|
542
|
+
* time-slices a render across frames, synchronous useSyncExternalStore
|
|
543
|
+
* notifications can trigger "Should not already be working" errors.
|
|
522
544
|
*/
|
|
523
545
|
update(scrollLeft, containerWidth) {
|
|
524
546
|
const buffer = containerWidth * 1.5;
|
|
@@ -528,8 +550,19 @@ var ViewportStore = class {
|
|
|
528
550
|
return;
|
|
529
551
|
}
|
|
530
552
|
this._state = { scrollLeft, containerWidth, visibleStart, visibleEnd };
|
|
531
|
-
|
|
532
|
-
|
|
553
|
+
if (this._notifyRafId === null) {
|
|
554
|
+
this._notifyRafId = requestAnimationFrame(() => {
|
|
555
|
+
this._notifyRafId = null;
|
|
556
|
+
for (const listener of this._listeners) {
|
|
557
|
+
listener();
|
|
558
|
+
}
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
cancelPendingNotification() {
|
|
563
|
+
if (this._notifyRafId !== null) {
|
|
564
|
+
cancelAnimationFrame(this._notifyRafId);
|
|
565
|
+
this._notifyRafId = null;
|
|
533
566
|
}
|
|
534
567
|
}
|
|
535
568
|
};
|
|
@@ -540,7 +573,7 @@ var NULL_SNAPSHOT = () => null;
|
|
|
540
573
|
var ScrollViewportProvider = ({ containerRef, children }) => {
|
|
541
574
|
const storeRef = useRef(null);
|
|
542
575
|
if (storeRef.current === null) {
|
|
543
|
-
storeRef.current = new ViewportStore();
|
|
576
|
+
storeRef.current = new ViewportStore(containerRef.current);
|
|
544
577
|
}
|
|
545
578
|
const store = storeRef.current;
|
|
546
579
|
const rafIdRef = useRef(null);
|
|
@@ -556,43 +589,27 @@ var ScrollViewportProvider = ({ containerRef, children }) => {
|
|
|
556
589
|
measure();
|
|
557
590
|
});
|
|
558
591
|
}, [measure]);
|
|
592
|
+
useLayoutEffect(() => {
|
|
593
|
+
measure();
|
|
594
|
+
}, [measure]);
|
|
559
595
|
useEffect(() => {
|
|
560
596
|
const el = containerRef.current;
|
|
561
597
|
if (!el) return;
|
|
562
|
-
measure();
|
|
563
598
|
el.addEventListener("scroll", scheduleUpdate, { passive: true });
|
|
564
|
-
let userHasInteracted = false;
|
|
565
|
-
const markInteracted = () => {
|
|
566
|
-
userHasInteracted = true;
|
|
567
|
-
};
|
|
568
|
-
el.addEventListener("pointerdown", markInteracted, { once: true });
|
|
569
|
-
el.addEventListener("keydown", markInteracted, { once: true });
|
|
570
|
-
el.addEventListener("wheel", markInteracted, { once: true, passive: true });
|
|
571
|
-
const resetHandler = () => {
|
|
572
|
-
if (!userHasInteracted && el.scrollLeft !== 0) {
|
|
573
|
-
el.scrollLeft = 0;
|
|
574
|
-
measure();
|
|
575
|
-
}
|
|
576
|
-
el.removeEventListener("scroll", resetHandler);
|
|
577
|
-
};
|
|
578
|
-
el.addEventListener("scroll", resetHandler);
|
|
579
599
|
const resizeObserver = new ResizeObserver(() => {
|
|
580
600
|
scheduleUpdate();
|
|
581
601
|
});
|
|
582
602
|
resizeObserver.observe(el);
|
|
583
603
|
return () => {
|
|
584
604
|
el.removeEventListener("scroll", scheduleUpdate);
|
|
585
|
-
el.removeEventListener("scroll", resetHandler);
|
|
586
|
-
el.removeEventListener("pointerdown", markInteracted);
|
|
587
|
-
el.removeEventListener("keydown", markInteracted);
|
|
588
|
-
el.removeEventListener("wheel", markInteracted);
|
|
589
605
|
resizeObserver.disconnect();
|
|
590
606
|
if (rafIdRef.current !== null) {
|
|
591
607
|
cancelAnimationFrame(rafIdRef.current);
|
|
592
608
|
rafIdRef.current = null;
|
|
593
609
|
}
|
|
610
|
+
store.cancelPendingNotification();
|
|
594
611
|
};
|
|
595
|
-
}, [containerRef,
|
|
612
|
+
}, [containerRef, scheduleUpdate, store]);
|
|
596
613
|
return /* @__PURE__ */ jsx3(ViewportStoreContext.Provider, { value: store, children });
|
|
597
614
|
};
|
|
598
615
|
var useScrollViewport = () => {
|
|
@@ -727,8 +744,6 @@ var Waveform = styled9.canvas.attrs((props) => ({
|
|
|
727
744
|
}))`
|
|
728
745
|
position: absolute;
|
|
729
746
|
top: 0;
|
|
730
|
-
/* Promote to own compositing layer for smoother scrolling */
|
|
731
|
-
will-change: transform;
|
|
732
747
|
/* Disable image rendering interpolation */
|
|
733
748
|
image-rendering: pixelated;
|
|
734
749
|
image-rendering: crisp-edges;
|
|
@@ -765,7 +780,8 @@ var Channel = (props) => {
|
|
|
765
780
|
const { canvasRef, canvasMapRef } = useChunkedCanvasRefs();
|
|
766
781
|
const clipOriginX = useClipViewportOrigin();
|
|
767
782
|
const visibleChunkIndices = useVisibleChunkIndices(length, MAX_CANVAS_WIDTH, clipOriginX);
|
|
768
|
-
|
|
783
|
+
useEffect3(() => {
|
|
784
|
+
const tDraw = performance.now();
|
|
769
785
|
const step = barWidth + barGap;
|
|
770
786
|
for (const [canvasIdx, canvas] of canvasMapRef.current.entries()) {
|
|
771
787
|
const globalPixelOffset = canvasIdx * MAX_CANVAS_WIDTH;
|
|
@@ -801,6 +817,9 @@ var Channel = (props) => {
|
|
|
801
817
|
}
|
|
802
818
|
}
|
|
803
819
|
}
|
|
820
|
+
console.log(
|
|
821
|
+
`[waveform] draw ch${index}: ${canvasMapRef.current.size} chunks, ${(performance.now() - tDraw).toFixed(1)}ms`
|
|
822
|
+
);
|
|
804
823
|
}, [
|
|
805
824
|
canvasMapRef,
|
|
806
825
|
data,
|
|
@@ -813,7 +832,8 @@ var Channel = (props) => {
|
|
|
813
832
|
barWidth,
|
|
814
833
|
barGap,
|
|
815
834
|
drawMode,
|
|
816
|
-
visibleChunkIndices
|
|
835
|
+
visibleChunkIndices,
|
|
836
|
+
index
|
|
817
837
|
]);
|
|
818
838
|
const waveforms = visibleChunkIndices.map((i) => {
|
|
819
839
|
const chunkLeft = i * MAX_CANVAS_WIDTH;
|
|
@@ -931,7 +951,7 @@ var ClipHeaderPresentational = ({
|
|
|
931
951
|
trackName,
|
|
932
952
|
isSelected = false
|
|
933
953
|
}) => {
|
|
934
|
-
return /* @__PURE__ */ jsx7(HeaderContainer, { $interactive: false, $isSelected: isSelected, children: /* @__PURE__ */ jsx7(TrackName, { children: trackName }) });
|
|
954
|
+
return /* @__PURE__ */ jsx7(HeaderContainer, { $interactive: false, $isSelected: isSelected, children: /* @__PURE__ */ jsx7(TrackName, { title: trackName, children: trackName }) });
|
|
935
955
|
};
|
|
936
956
|
var ClipHeader = ({
|
|
937
957
|
clipId,
|
|
@@ -953,7 +973,7 @@ var ClipHeader = ({
|
|
|
953
973
|
"data-clip-id": clipId,
|
|
954
974
|
$interactive: true,
|
|
955
975
|
$isSelected: isSelected,
|
|
956
|
-
children: /* @__PURE__ */ jsx7(TrackName, { children: trackName })
|
|
976
|
+
children: /* @__PURE__ */ jsx7(TrackName, { title: trackName, children: trackName })
|
|
957
977
|
}
|
|
958
978
|
);
|
|
959
979
|
};
|
|
@@ -1174,7 +1194,7 @@ var Clip = ({
|
|
|
1174
1194
|
"data-clip-container": "true",
|
|
1175
1195
|
"data-track-id": trackId,
|
|
1176
1196
|
onMouseDown,
|
|
1177
|
-
|
|
1197
|
+
tabIndex: -1,
|
|
1178
1198
|
children: [
|
|
1179
1199
|
showHeader && /* @__PURE__ */ jsx10(
|
|
1180
1200
|
ClipHeader,
|
|
@@ -1284,11 +1304,140 @@ var MasterVolumeControl = ({
|
|
|
1284
1304
|
] });
|
|
1285
1305
|
};
|
|
1286
1306
|
|
|
1287
|
-
// src/components/
|
|
1288
|
-
import {
|
|
1307
|
+
// src/components/PianoRollChannel.tsx
|
|
1308
|
+
import { useEffect as useEffect4, useMemo as useMemo2 } from "react";
|
|
1289
1309
|
import styled15 from "styled-components";
|
|
1290
|
-
import {
|
|
1291
|
-
|
|
1310
|
+
import { MAX_CANVAS_WIDTH as MAX_CANVAS_WIDTH2 } from "@waveform-playlist/core";
|
|
1311
|
+
import { jsx as jsx12 } from "react/jsx-runtime";
|
|
1312
|
+
var NoteCanvas = styled15.canvas.attrs((props) => ({
|
|
1313
|
+
style: {
|
|
1314
|
+
width: `${props.$cssWidth}px`,
|
|
1315
|
+
height: `${props.$waveHeight}px`,
|
|
1316
|
+
left: `${props.$left}px`
|
|
1317
|
+
}
|
|
1318
|
+
}))`
|
|
1319
|
+
position: absolute;
|
|
1320
|
+
top: 0;
|
|
1321
|
+
image-rendering: pixelated;
|
|
1322
|
+
image-rendering: crisp-edges;
|
|
1323
|
+
`;
|
|
1324
|
+
var Wrapper2 = styled15.div.attrs((props) => ({
|
|
1325
|
+
style: {
|
|
1326
|
+
top: `${props.$waveHeight * props.$index}px`,
|
|
1327
|
+
width: `${props.$cssWidth}px`,
|
|
1328
|
+
height: `${props.$waveHeight}px`
|
|
1329
|
+
}
|
|
1330
|
+
}))`
|
|
1331
|
+
position: absolute;
|
|
1332
|
+
background: ${(props) => props.$backgroundColor};
|
|
1333
|
+
transform: translateZ(0);
|
|
1334
|
+
backface-visibility: hidden;
|
|
1335
|
+
`;
|
|
1336
|
+
var PianoRollChannel = ({
|
|
1337
|
+
index,
|
|
1338
|
+
midiNotes,
|
|
1339
|
+
length,
|
|
1340
|
+
waveHeight,
|
|
1341
|
+
devicePixelRatio,
|
|
1342
|
+
samplesPerPixel,
|
|
1343
|
+
sampleRate,
|
|
1344
|
+
clipOffsetSeconds,
|
|
1345
|
+
noteColor = "#2a7070",
|
|
1346
|
+
selectedNoteColor = "#3d9e9e",
|
|
1347
|
+
isSelected = false,
|
|
1348
|
+
transparentBackground = false,
|
|
1349
|
+
backgroundColor = "#1a1a2e"
|
|
1350
|
+
}) => {
|
|
1351
|
+
const { canvasRef, canvasMapRef } = useChunkedCanvasRefs();
|
|
1352
|
+
const clipOriginX = useClipViewportOrigin();
|
|
1353
|
+
const visibleChunkIndices = useVisibleChunkIndices(length, MAX_CANVAS_WIDTH2, clipOriginX);
|
|
1354
|
+
const { minMidi, maxMidi } = useMemo2(() => {
|
|
1355
|
+
if (midiNotes.length === 0) return { minMidi: 0, maxMidi: 127 };
|
|
1356
|
+
let min = 127, max = 0;
|
|
1357
|
+
for (const note of midiNotes) {
|
|
1358
|
+
if (note.midi < min) min = note.midi;
|
|
1359
|
+
if (note.midi > max) max = note.midi;
|
|
1360
|
+
}
|
|
1361
|
+
return { minMidi: Math.max(0, min - 1), maxMidi: Math.min(127, max + 1) };
|
|
1362
|
+
}, [midiNotes]);
|
|
1363
|
+
const color = isSelected ? selectedNoteColor : noteColor;
|
|
1364
|
+
useEffect4(() => {
|
|
1365
|
+
const tDraw = performance.now();
|
|
1366
|
+
const noteRange = maxMidi - minMidi + 1;
|
|
1367
|
+
const noteHeight = Math.max(2, waveHeight / noteRange);
|
|
1368
|
+
const pixelsPerSecond = sampleRate / samplesPerPixel;
|
|
1369
|
+
for (const [canvasIdx, canvas] of canvasMapRef.current.entries()) {
|
|
1370
|
+
const chunkPixelStart = canvasIdx * MAX_CANVAS_WIDTH2;
|
|
1371
|
+
const canvasWidth = canvas.width / devicePixelRatio;
|
|
1372
|
+
const ctx = canvas.getContext("2d");
|
|
1373
|
+
if (!ctx) continue;
|
|
1374
|
+
ctx.resetTransform();
|
|
1375
|
+
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
1376
|
+
ctx.imageSmoothingEnabled = false;
|
|
1377
|
+
ctx.scale(devicePixelRatio, devicePixelRatio);
|
|
1378
|
+
const chunkStartTime = chunkPixelStart * samplesPerPixel / sampleRate;
|
|
1379
|
+
const chunkEndTime = (chunkPixelStart + canvasWidth) * samplesPerPixel / sampleRate;
|
|
1380
|
+
for (const note of midiNotes) {
|
|
1381
|
+
const noteStart = note.time - clipOffsetSeconds;
|
|
1382
|
+
const noteEnd = noteStart + note.duration;
|
|
1383
|
+
if (noteEnd <= chunkStartTime || noteStart >= chunkEndTime) continue;
|
|
1384
|
+
const x = noteStart * pixelsPerSecond - chunkPixelStart;
|
|
1385
|
+
const w = Math.max(2, note.duration * pixelsPerSecond);
|
|
1386
|
+
const y = (maxMidi - note.midi) / noteRange * waveHeight;
|
|
1387
|
+
const alpha = 0.3 + note.velocity * 0.7;
|
|
1388
|
+
ctx.fillStyle = color;
|
|
1389
|
+
ctx.globalAlpha = alpha;
|
|
1390
|
+
const r = 1;
|
|
1391
|
+
ctx.beginPath();
|
|
1392
|
+
ctx.roundRect(x, y, w, noteHeight, r);
|
|
1393
|
+
ctx.fill();
|
|
1394
|
+
}
|
|
1395
|
+
ctx.globalAlpha = 1;
|
|
1396
|
+
}
|
|
1397
|
+
console.log(
|
|
1398
|
+
`[piano-roll] draw ch${index}: ${canvasMapRef.current.size} chunks, ${midiNotes.length} notes, ${(performance.now() - tDraw).toFixed(1)}ms`
|
|
1399
|
+
);
|
|
1400
|
+
}, [
|
|
1401
|
+
canvasMapRef,
|
|
1402
|
+
midiNotes,
|
|
1403
|
+
waveHeight,
|
|
1404
|
+
devicePixelRatio,
|
|
1405
|
+
samplesPerPixel,
|
|
1406
|
+
sampleRate,
|
|
1407
|
+
clipOffsetSeconds,
|
|
1408
|
+
color,
|
|
1409
|
+
minMidi,
|
|
1410
|
+
maxMidi,
|
|
1411
|
+
length,
|
|
1412
|
+
visibleChunkIndices,
|
|
1413
|
+
index
|
|
1414
|
+
]);
|
|
1415
|
+
const canvases = visibleChunkIndices.map((i) => {
|
|
1416
|
+
const chunkLeft = i * MAX_CANVAS_WIDTH2;
|
|
1417
|
+
const currentWidth = Math.min(length - chunkLeft, MAX_CANVAS_WIDTH2);
|
|
1418
|
+
return /* @__PURE__ */ jsx12(
|
|
1419
|
+
NoteCanvas,
|
|
1420
|
+
{
|
|
1421
|
+
$cssWidth: currentWidth,
|
|
1422
|
+
$left: chunkLeft,
|
|
1423
|
+
width: currentWidth * devicePixelRatio,
|
|
1424
|
+
height: waveHeight * devicePixelRatio,
|
|
1425
|
+
$waveHeight: waveHeight,
|
|
1426
|
+
"data-index": i,
|
|
1427
|
+
ref: canvasRef
|
|
1428
|
+
},
|
|
1429
|
+
`${length}-${i}`
|
|
1430
|
+
);
|
|
1431
|
+
});
|
|
1432
|
+
const bgColor = transparentBackground ? "transparent" : backgroundColor;
|
|
1433
|
+
return /* @__PURE__ */ jsx12(Wrapper2, { $index: index, $cssWidth: length, $waveHeight: waveHeight, $backgroundColor: bgColor, children: canvases });
|
|
1434
|
+
};
|
|
1435
|
+
|
|
1436
|
+
// src/components/Playhead.tsx
|
|
1437
|
+
import { useRef as useRef3, useEffect as useEffect5 } from "react";
|
|
1438
|
+
import styled16 from "styled-components";
|
|
1439
|
+
import { jsx as jsx13, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1440
|
+
var PlayheadLine = styled16.div.attrs((props) => ({
|
|
1292
1441
|
style: {
|
|
1293
1442
|
transform: `translate3d(${props.$position}px, 0, 0)`
|
|
1294
1443
|
}
|
|
@@ -1304,9 +1453,9 @@ var PlayheadLine = styled15.div.attrs((props) => ({
|
|
|
1304
1453
|
will-change: transform;
|
|
1305
1454
|
`;
|
|
1306
1455
|
var Playhead = ({ position, color = "#ff0000" }) => {
|
|
1307
|
-
return /* @__PURE__ */
|
|
1456
|
+
return /* @__PURE__ */ jsx13(PlayheadLine, { $position: position, $color: color });
|
|
1308
1457
|
};
|
|
1309
|
-
var PlayheadWithMarkerContainer =
|
|
1458
|
+
var PlayheadWithMarkerContainer = styled16.div`
|
|
1310
1459
|
position: absolute;
|
|
1311
1460
|
top: 0;
|
|
1312
1461
|
left: 0;
|
|
@@ -1315,7 +1464,7 @@ var PlayheadWithMarkerContainer = styled15.div`
|
|
|
1315
1464
|
pointer-events: none;
|
|
1316
1465
|
will-change: transform;
|
|
1317
1466
|
`;
|
|
1318
|
-
var MarkerTriangle =
|
|
1467
|
+
var MarkerTriangle = styled16.div`
|
|
1319
1468
|
position: absolute;
|
|
1320
1469
|
top: -10px;
|
|
1321
1470
|
left: -6px;
|
|
@@ -1325,7 +1474,7 @@ var MarkerTriangle = styled15.div`
|
|
|
1325
1474
|
border-right: 7px solid transparent;
|
|
1326
1475
|
border-top: 10px solid ${(props) => props.$color};
|
|
1327
1476
|
`;
|
|
1328
|
-
var MarkerLine =
|
|
1477
|
+
var MarkerLine = styled16.div`
|
|
1329
1478
|
position: absolute;
|
|
1330
1479
|
top: 0;
|
|
1331
1480
|
left: 0;
|
|
@@ -1341,13 +1490,13 @@ var PlayheadWithMarker = ({
|
|
|
1341
1490
|
audioStartPositionRef,
|
|
1342
1491
|
samplesPerPixel,
|
|
1343
1492
|
sampleRate,
|
|
1344
|
-
controlsOffset,
|
|
1493
|
+
controlsOffset = 0,
|
|
1345
1494
|
getAudioContextTime,
|
|
1346
1495
|
getPlaybackTime
|
|
1347
1496
|
}) => {
|
|
1348
1497
|
const containerRef = useRef3(null);
|
|
1349
1498
|
const animationFrameRef = useRef3(null);
|
|
1350
|
-
|
|
1499
|
+
useEffect5(() => {
|
|
1351
1500
|
const updatePosition = () => {
|
|
1352
1501
|
if (containerRef.current) {
|
|
1353
1502
|
let time;
|
|
@@ -1392,7 +1541,7 @@ var PlayheadWithMarker = ({
|
|
|
1392
1541
|
getAudioContextTime,
|
|
1393
1542
|
getPlaybackTime
|
|
1394
1543
|
]);
|
|
1395
|
-
|
|
1544
|
+
useEffect5(() => {
|
|
1396
1545
|
if (!isPlaying && containerRef.current) {
|
|
1397
1546
|
const time = currentTimeRef.current ?? 0;
|
|
1398
1547
|
const pos = time * sampleRate / samplesPerPixel + controlsOffset;
|
|
@@ -1400,27 +1549,43 @@ var PlayheadWithMarker = ({
|
|
|
1400
1549
|
}
|
|
1401
1550
|
});
|
|
1402
1551
|
return /* @__PURE__ */ jsxs4(PlayheadWithMarkerContainer, { ref: containerRef, $color: color, children: [
|
|
1403
|
-
/* @__PURE__ */
|
|
1404
|
-
/* @__PURE__ */
|
|
1552
|
+
/* @__PURE__ */ jsx13(MarkerTriangle, { $color: color }),
|
|
1553
|
+
/* @__PURE__ */ jsx13(MarkerLine, { $color: color })
|
|
1405
1554
|
] });
|
|
1406
1555
|
};
|
|
1407
1556
|
|
|
1408
1557
|
// src/components/Playlist.tsx
|
|
1409
|
-
import
|
|
1558
|
+
import styled17, { withTheme } from "styled-components";
|
|
1410
1559
|
import { useRef as useRef4, useCallback as useCallback3 } from "react";
|
|
1411
|
-
import { jsx as
|
|
1412
|
-
var
|
|
1560
|
+
import { jsx as jsx14, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1561
|
+
var Wrapper3 = styled17.div`
|
|
1562
|
+
display: flex;
|
|
1413
1563
|
overflow-y: hidden;
|
|
1564
|
+
position: relative;
|
|
1565
|
+
`;
|
|
1566
|
+
var ControlsColumn = styled17.div.attrs((props) => ({
|
|
1567
|
+
style: { width: `${props.$width}px` }
|
|
1568
|
+
}))`
|
|
1569
|
+
flex-shrink: 0;
|
|
1570
|
+
overflow: hidden;
|
|
1571
|
+
`;
|
|
1572
|
+
var TimescaleGap = styled17.div.attrs((props) => ({
|
|
1573
|
+
style: { height: `${props.$height}px` }
|
|
1574
|
+
}))``;
|
|
1575
|
+
var ScrollArea = styled17.div`
|
|
1414
1576
|
overflow-x: auto;
|
|
1577
|
+
overflow-y: hidden;
|
|
1578
|
+
overflow-anchor: none;
|
|
1579
|
+
flex: 1;
|
|
1415
1580
|
position: relative;
|
|
1416
1581
|
`;
|
|
1417
|
-
var
|
|
1582
|
+
var ScrollContainerInner = styled17.div.attrs((props) => ({
|
|
1418
1583
|
style: props.$width !== void 0 ? { width: `${props.$width}px` } : {}
|
|
1419
1584
|
}))`
|
|
1420
1585
|
position: relative;
|
|
1421
1586
|
background: ${(props) => props.$backgroundColor || "transparent"};
|
|
1422
1587
|
`;
|
|
1423
|
-
var TimescaleWrapper =
|
|
1588
|
+
var TimescaleWrapper = styled17.div.attrs((props) => ({
|
|
1424
1589
|
style: props.$width ? { minWidth: `${props.$width}px` } : {}
|
|
1425
1590
|
}))`
|
|
1426
1591
|
background: ${(props) => props.$backgroundColor || "white"};
|
|
@@ -1428,14 +1593,14 @@ var TimescaleWrapper = styled16.div.attrs((props) => ({
|
|
|
1428
1593
|
position: relative;
|
|
1429
1594
|
overflow: hidden; /* Constrain loop region to timescale area */
|
|
1430
1595
|
`;
|
|
1431
|
-
var TracksContainer =
|
|
1596
|
+
var TracksContainer = styled17.div.attrs((props) => ({
|
|
1432
1597
|
style: props.$width !== void 0 ? { minWidth: `${props.$width}px` } : {}
|
|
1433
1598
|
}))`
|
|
1434
1599
|
position: relative;
|
|
1435
1600
|
background: ${(props) => props.$backgroundColor || "transparent"};
|
|
1436
1601
|
width: 100%;
|
|
1437
1602
|
`;
|
|
1438
|
-
var ClickOverlay =
|
|
1603
|
+
var ClickOverlay = styled17.div`
|
|
1439
1604
|
position: absolute;
|
|
1440
1605
|
top: 0;
|
|
1441
1606
|
left: 0;
|
|
@@ -1452,7 +1617,6 @@ var Playlist = ({
|
|
|
1452
1617
|
timescale,
|
|
1453
1618
|
timescaleWidth,
|
|
1454
1619
|
tracksWidth,
|
|
1455
|
-
scrollContainerWidth,
|
|
1456
1620
|
controlsWidth,
|
|
1457
1621
|
onTracksClick,
|
|
1458
1622
|
onTracksMouseDown,
|
|
@@ -1460,40 +1624,48 @@ var Playlist = ({
|
|
|
1460
1624
|
onTracksMouseUp,
|
|
1461
1625
|
scrollContainerRef,
|
|
1462
1626
|
isSelecting,
|
|
1463
|
-
"data-playlist-state": playlistState
|
|
1627
|
+
"data-playlist-state": playlistState,
|
|
1628
|
+
trackControlsSlots,
|
|
1629
|
+
timescaleGapHeight = 0
|
|
1464
1630
|
}) => {
|
|
1465
|
-
const
|
|
1631
|
+
const scrollAreaRef = useRef4(null);
|
|
1466
1632
|
const handleRef = useCallback3(
|
|
1467
1633
|
(el) => {
|
|
1468
|
-
|
|
1634
|
+
scrollAreaRef.current = el;
|
|
1469
1635
|
scrollContainerRef?.(el);
|
|
1470
1636
|
},
|
|
1471
1637
|
[scrollContainerRef]
|
|
1472
1638
|
);
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
/* @__PURE__ */ jsxs5(
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1639
|
+
const showControls = controlsWidth !== void 0 && controlsWidth > 0;
|
|
1640
|
+
return /* @__PURE__ */ jsxs5(Wrapper3, { "data-playlist-state": playlistState, children: [
|
|
1641
|
+
showControls && /* @__PURE__ */ jsxs5(ControlsColumn, { $width: controlsWidth, children: [
|
|
1642
|
+
timescaleGapHeight > 0 && /* @__PURE__ */ jsx14(TimescaleGap, { $height: timescaleGapHeight }),
|
|
1643
|
+
trackControlsSlots
|
|
1644
|
+
] }),
|
|
1645
|
+
/* @__PURE__ */ jsx14(ScrollArea, { "data-scroll-container": "true", ref: handleRef, children: /* @__PURE__ */ jsx14(ScrollViewportProvider, { containerRef: scrollAreaRef, children: /* @__PURE__ */ jsxs5(ScrollContainerInner, { $backgroundColor: backgroundColor, $width: tracksWidth, children: [
|
|
1646
|
+
timescale && /* @__PURE__ */ jsx14(TimescaleWrapper, { $width: timescaleWidth, $backgroundColor: timescaleBackgroundColor, children: timescale }),
|
|
1647
|
+
/* @__PURE__ */ jsxs5(TracksContainer, { $width: tracksWidth, $backgroundColor: backgroundColor, children: [
|
|
1648
|
+
children,
|
|
1649
|
+
(onTracksClick || onTracksMouseDown) && /* @__PURE__ */ jsx14(
|
|
1650
|
+
ClickOverlay,
|
|
1651
|
+
{
|
|
1652
|
+
$isSelecting: isSelecting,
|
|
1653
|
+
onClick: onTracksClick,
|
|
1654
|
+
onMouseDown: onTracksMouseDown,
|
|
1655
|
+
onMouseMove: onTracksMouseMove,
|
|
1656
|
+
onMouseUp: onTracksMouseUp
|
|
1657
|
+
}
|
|
1658
|
+
)
|
|
1659
|
+
] })
|
|
1660
|
+
] }) }) })
|
|
1661
|
+
] });
|
|
1490
1662
|
};
|
|
1491
1663
|
var StyledPlaylist = withTheme(Playlist);
|
|
1492
1664
|
|
|
1493
1665
|
// src/components/Selection.tsx
|
|
1494
|
-
import
|
|
1495
|
-
import { jsx as
|
|
1496
|
-
var SelectionOverlay =
|
|
1666
|
+
import styled18 from "styled-components";
|
|
1667
|
+
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
1668
|
+
var SelectionOverlay = styled18.div.attrs((props) => ({
|
|
1497
1669
|
style: {
|
|
1498
1670
|
left: `${props.$left}px`,
|
|
1499
1671
|
width: `${props.$width}px`
|
|
@@ -1516,14 +1688,14 @@ var Selection = ({
|
|
|
1516
1688
|
if (width <= 0) {
|
|
1517
1689
|
return null;
|
|
1518
1690
|
}
|
|
1519
|
-
return /* @__PURE__ */
|
|
1691
|
+
return /* @__PURE__ */ jsx15(SelectionOverlay, { $left: startPosition, $width: width, $color: color, "data-selection": true });
|
|
1520
1692
|
};
|
|
1521
1693
|
|
|
1522
1694
|
// src/components/LoopRegion.tsx
|
|
1523
1695
|
import { useCallback as useCallback4, useRef as useRef5, useState } from "react";
|
|
1524
|
-
import
|
|
1525
|
-
import { Fragment as Fragment2, jsx as
|
|
1526
|
-
var LoopRegionOverlayDiv =
|
|
1696
|
+
import styled19 from "styled-components";
|
|
1697
|
+
import { Fragment as Fragment2, jsx as jsx16, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1698
|
+
var LoopRegionOverlayDiv = styled19.div.attrs((props) => ({
|
|
1527
1699
|
style: {
|
|
1528
1700
|
left: `${props.$left}px`,
|
|
1529
1701
|
width: `${props.$width}px`
|
|
@@ -1536,7 +1708,7 @@ var LoopRegionOverlayDiv = styled18.div.attrs((props) => ({
|
|
|
1536
1708
|
z-index: 55; /* Between clips (z-index: 50) and selection (z-index: 60) */
|
|
1537
1709
|
pointer-events: none;
|
|
1538
1710
|
`;
|
|
1539
|
-
var LoopMarker =
|
|
1711
|
+
var LoopMarker = styled19.div.attrs((props) => ({
|
|
1540
1712
|
style: {
|
|
1541
1713
|
left: `${props.$left}px`
|
|
1542
1714
|
}
|
|
@@ -1572,7 +1744,7 @@ var LoopRegion = ({
|
|
|
1572
1744
|
return null;
|
|
1573
1745
|
}
|
|
1574
1746
|
return /* @__PURE__ */ jsxs6(Fragment2, { children: [
|
|
1575
|
-
/* @__PURE__ */
|
|
1747
|
+
/* @__PURE__ */ jsx16(
|
|
1576
1748
|
LoopRegionOverlayDiv,
|
|
1577
1749
|
{
|
|
1578
1750
|
$left: startPosition,
|
|
@@ -1581,7 +1753,7 @@ var LoopRegion = ({
|
|
|
1581
1753
|
"data-loop-region": true
|
|
1582
1754
|
}
|
|
1583
1755
|
),
|
|
1584
|
-
/* @__PURE__ */
|
|
1756
|
+
/* @__PURE__ */ jsx16(
|
|
1585
1757
|
LoopMarker,
|
|
1586
1758
|
{
|
|
1587
1759
|
$left: startPosition,
|
|
@@ -1590,7 +1762,7 @@ var LoopRegion = ({
|
|
|
1590
1762
|
"data-loop-marker": "start"
|
|
1591
1763
|
}
|
|
1592
1764
|
),
|
|
1593
|
-
/* @__PURE__ */
|
|
1765
|
+
/* @__PURE__ */ jsx16(
|
|
1594
1766
|
LoopMarker,
|
|
1595
1767
|
{
|
|
1596
1768
|
$left: endPosition - 2,
|
|
@@ -1601,7 +1773,7 @@ var LoopRegion = ({
|
|
|
1601
1773
|
)
|
|
1602
1774
|
] });
|
|
1603
1775
|
};
|
|
1604
|
-
var DraggableMarkerHandle =
|
|
1776
|
+
var DraggableMarkerHandle = styled19.div.attrs((props) => ({
|
|
1605
1777
|
style: {
|
|
1606
1778
|
left: `${props.$left}px`
|
|
1607
1779
|
}
|
|
@@ -1643,7 +1815,7 @@ var DraggableMarkerHandle = styled18.div.attrs((props) => ({
|
|
|
1643
1815
|
opacity: 1;
|
|
1644
1816
|
}
|
|
1645
1817
|
`;
|
|
1646
|
-
var TimescaleLoopShade =
|
|
1818
|
+
var TimescaleLoopShade = styled19.div.attrs((props) => ({
|
|
1647
1819
|
style: {
|
|
1648
1820
|
left: `${props.$left}px`,
|
|
1649
1821
|
width: `${props.$width}px`
|
|
@@ -1741,7 +1913,7 @@ var LoopRegionMarkers = ({
|
|
|
1741
1913
|
return null;
|
|
1742
1914
|
}
|
|
1743
1915
|
return /* @__PURE__ */ jsxs6(Fragment2, { children: [
|
|
1744
|
-
/* @__PURE__ */
|
|
1916
|
+
/* @__PURE__ */ jsx16(
|
|
1745
1917
|
TimescaleLoopShade,
|
|
1746
1918
|
{
|
|
1747
1919
|
$left: startPosition,
|
|
@@ -1752,7 +1924,7 @@ var LoopRegionMarkers = ({
|
|
|
1752
1924
|
"data-loop-region-timescale": true
|
|
1753
1925
|
}
|
|
1754
1926
|
),
|
|
1755
|
-
/* @__PURE__ */
|
|
1927
|
+
/* @__PURE__ */ jsx16(
|
|
1756
1928
|
DraggableMarkerHandle,
|
|
1757
1929
|
{
|
|
1758
1930
|
$left: startPosition,
|
|
@@ -1763,7 +1935,7 @@ var LoopRegionMarkers = ({
|
|
|
1763
1935
|
"data-loop-marker-handle": "start"
|
|
1764
1936
|
}
|
|
1765
1937
|
),
|
|
1766
|
-
/* @__PURE__ */
|
|
1938
|
+
/* @__PURE__ */ jsx16(
|
|
1767
1939
|
DraggableMarkerHandle,
|
|
1768
1940
|
{
|
|
1769
1941
|
$left: endPosition,
|
|
@@ -1776,13 +1948,10 @@ var LoopRegionMarkers = ({
|
|
|
1776
1948
|
)
|
|
1777
1949
|
] });
|
|
1778
1950
|
};
|
|
1779
|
-
var TimescaleLoopCreator =
|
|
1780
|
-
style: {
|
|
1781
|
-
left: `${props.$leftOffset || 0}px`
|
|
1782
|
-
}
|
|
1783
|
-
}))`
|
|
1951
|
+
var TimescaleLoopCreator = styled19.div`
|
|
1784
1952
|
position: absolute;
|
|
1785
1953
|
top: 0;
|
|
1954
|
+
left: 0;
|
|
1786
1955
|
right: 0;
|
|
1787
1956
|
height: 100%; /* Stay within timescale bounds, don't extend into tracks */
|
|
1788
1957
|
cursor: crosshair;
|
|
@@ -1795,8 +1964,7 @@ var TimescaleLoopRegion = ({
|
|
|
1795
1964
|
regionColor = "rgba(59, 130, 246, 0.3)",
|
|
1796
1965
|
onLoopRegionChange,
|
|
1797
1966
|
minPosition = 0,
|
|
1798
|
-
maxPosition = Infinity
|
|
1799
|
-
controlsOffset = 0
|
|
1967
|
+
maxPosition = Infinity
|
|
1800
1968
|
}) => {
|
|
1801
1969
|
const [, setIsCreating] = useState(false);
|
|
1802
1970
|
const createStartX = useRef5(0);
|
|
@@ -1833,14 +2001,13 @@ var TimescaleLoopRegion = ({
|
|
|
1833
2001
|
},
|
|
1834
2002
|
[minPosition, maxPosition, onLoopRegionChange]
|
|
1835
2003
|
);
|
|
1836
|
-
return /* @__PURE__ */
|
|
2004
|
+
return /* @__PURE__ */ jsx16(
|
|
1837
2005
|
TimescaleLoopCreator,
|
|
1838
2006
|
{
|
|
1839
2007
|
ref: containerRef,
|
|
1840
|
-
$leftOffset: controlsOffset,
|
|
1841
2008
|
onMouseDown: handleBackgroundMouseDown,
|
|
1842
2009
|
"data-timescale-loop-creator": true,
|
|
1843
|
-
children: hasLoopRegion && /* @__PURE__ */
|
|
2010
|
+
children: hasLoopRegion && /* @__PURE__ */ jsx16(
|
|
1844
2011
|
LoopRegionMarkers,
|
|
1845
2012
|
{
|
|
1846
2013
|
startPosition,
|
|
@@ -1859,10 +2026,10 @@ var TimescaleLoopRegion = ({
|
|
|
1859
2026
|
};
|
|
1860
2027
|
|
|
1861
2028
|
// src/components/SelectionTimeInputs.tsx
|
|
1862
|
-
import { useEffect as
|
|
2029
|
+
import { useEffect as useEffect7, useState as useState3 } from "react";
|
|
1863
2030
|
|
|
1864
2031
|
// src/components/TimeInput.tsx
|
|
1865
|
-
import { useEffect as
|
|
2032
|
+
import { useEffect as useEffect6, useState as useState2 } from "react";
|
|
1866
2033
|
|
|
1867
2034
|
// src/utils/timeFormat.ts
|
|
1868
2035
|
function clockFormat(seconds, decimals) {
|
|
@@ -1912,7 +2079,7 @@ function parseTime(timeStr, format) {
|
|
|
1912
2079
|
}
|
|
1913
2080
|
|
|
1914
2081
|
// src/components/TimeInput.tsx
|
|
1915
|
-
import { Fragment as Fragment3, jsx as
|
|
2082
|
+
import { Fragment as Fragment3, jsx as jsx17, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1916
2083
|
var TimeInput = ({
|
|
1917
2084
|
id,
|
|
1918
2085
|
label,
|
|
@@ -1923,7 +2090,7 @@ var TimeInput = ({
|
|
|
1923
2090
|
readOnly = false
|
|
1924
2091
|
}) => {
|
|
1925
2092
|
const [displayValue, setDisplayValue] = useState2("");
|
|
1926
|
-
|
|
2093
|
+
useEffect6(() => {
|
|
1927
2094
|
const formatted = formatTime(value, format);
|
|
1928
2095
|
setDisplayValue(formatted);
|
|
1929
2096
|
}, [value, format, id]);
|
|
@@ -1944,8 +2111,8 @@ var TimeInput = ({
|
|
|
1944
2111
|
}
|
|
1945
2112
|
};
|
|
1946
2113
|
return /* @__PURE__ */ jsxs7(Fragment3, { children: [
|
|
1947
|
-
/* @__PURE__ */
|
|
1948
|
-
/* @__PURE__ */
|
|
2114
|
+
/* @__PURE__ */ jsx17(ScreenReaderOnly, { as: "label", htmlFor: id, children: label }),
|
|
2115
|
+
/* @__PURE__ */ jsx17(
|
|
1949
2116
|
BaseInput,
|
|
1950
2117
|
{
|
|
1951
2118
|
type: "text",
|
|
@@ -1962,7 +2129,7 @@ var TimeInput = ({
|
|
|
1962
2129
|
};
|
|
1963
2130
|
|
|
1964
2131
|
// src/components/SelectionTimeInputs.tsx
|
|
1965
|
-
import { jsx as
|
|
2132
|
+
import { jsx as jsx18, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1966
2133
|
var SelectionTimeInputs = ({
|
|
1967
2134
|
selectionStart,
|
|
1968
2135
|
selectionEnd,
|
|
@@ -1970,7 +2137,7 @@ var SelectionTimeInputs = ({
|
|
|
1970
2137
|
className
|
|
1971
2138
|
}) => {
|
|
1972
2139
|
const [timeFormat, setTimeFormat] = useState3("hh:mm:ss.uuu");
|
|
1973
|
-
|
|
2140
|
+
useEffect7(() => {
|
|
1974
2141
|
const timeFormatSelect = document.querySelector(".time-format");
|
|
1975
2142
|
const handleFormatChange = () => {
|
|
1976
2143
|
if (timeFormatSelect) {
|
|
@@ -1996,7 +2163,7 @@ var SelectionTimeInputs = ({
|
|
|
1996
2163
|
}
|
|
1997
2164
|
};
|
|
1998
2165
|
return /* @__PURE__ */ jsxs8("div", { className, children: [
|
|
1999
|
-
/* @__PURE__ */
|
|
2166
|
+
/* @__PURE__ */ jsx18(
|
|
2000
2167
|
TimeInput,
|
|
2001
2168
|
{
|
|
2002
2169
|
id: "audio_start",
|
|
@@ -2007,7 +2174,7 @@ var SelectionTimeInputs = ({
|
|
|
2007
2174
|
onChange: handleStartChange
|
|
2008
2175
|
}
|
|
2009
2176
|
),
|
|
2010
|
-
/* @__PURE__ */
|
|
2177
|
+
/* @__PURE__ */ jsx18(
|
|
2011
2178
|
TimeInput,
|
|
2012
2179
|
{
|
|
2013
2180
|
id: "audio_end",
|
|
@@ -2023,7 +2190,7 @@ var SelectionTimeInputs = ({
|
|
|
2023
2190
|
|
|
2024
2191
|
// src/contexts/DevicePixelRatio.tsx
|
|
2025
2192
|
import { useState as useState4, createContext as createContext3, useContext as useContext3 } from "react";
|
|
2026
|
-
import { jsx as
|
|
2193
|
+
import { jsx as jsx19 } from "react/jsx-runtime";
|
|
2027
2194
|
function getScale() {
|
|
2028
2195
|
return window.devicePixelRatio;
|
|
2029
2196
|
}
|
|
@@ -2037,7 +2204,7 @@ var DevicePixelRatioProvider = ({ children }) => {
|
|
|
2037
2204
|
},
|
|
2038
2205
|
{ once: true }
|
|
2039
2206
|
);
|
|
2040
|
-
return /* @__PURE__ */
|
|
2207
|
+
return /* @__PURE__ */ jsx19(DevicePixelRatioContext.Provider, { value: Math.ceil(scale), children });
|
|
2041
2208
|
};
|
|
2042
2209
|
var useDevicePixelRatio = () => useContext3(DevicePixelRatioContext);
|
|
2043
2210
|
|
|
@@ -2066,8 +2233,8 @@ var useTheme2 = () => useContext5(ThemeContext);
|
|
|
2066
2233
|
|
|
2067
2234
|
// src/contexts/TrackControls.tsx
|
|
2068
2235
|
import { createContext as createContext5, useContext as useContext6, Fragment as Fragment4 } from "react";
|
|
2069
|
-
import { jsx as
|
|
2070
|
-
var TrackControlsContext = createContext5(/* @__PURE__ */
|
|
2236
|
+
import { jsx as jsx20 } from "react/jsx-runtime";
|
|
2237
|
+
var TrackControlsContext = createContext5(/* @__PURE__ */ jsx20(Fragment4, {}));
|
|
2071
2238
|
var useTrackControls = () => useContext6(TrackControlsContext);
|
|
2072
2239
|
|
|
2073
2240
|
// src/contexts/Playout.tsx
|
|
@@ -2076,7 +2243,7 @@ import {
|
|
|
2076
2243
|
createContext as createContext6,
|
|
2077
2244
|
useContext as useContext7
|
|
2078
2245
|
} from "react";
|
|
2079
|
-
import { jsx as
|
|
2246
|
+
import { jsx as jsx21 } from "react/jsx-runtime";
|
|
2080
2247
|
var defaultProgress = 0;
|
|
2081
2248
|
var defaultIsPlaying = false;
|
|
2082
2249
|
var defaultSelectionStart = 0;
|
|
@@ -2105,18 +2272,18 @@ var PlayoutProvider = ({ children }) => {
|
|
|
2105
2272
|
setSelectionStart(start);
|
|
2106
2273
|
setSelectionEnd(end);
|
|
2107
2274
|
};
|
|
2108
|
-
return /* @__PURE__ */
|
|
2275
|
+
return /* @__PURE__ */ jsx21(PlayoutStatusUpdateContext.Provider, { value: { setIsPlaying, setProgress, setSelection }, children: /* @__PURE__ */ jsx21(PlayoutStatusContext.Provider, { value: { isPlaying, progress, selectionStart, selectionEnd }, children }) });
|
|
2109
2276
|
};
|
|
2110
2277
|
var usePlayoutStatus = () => useContext7(PlayoutStatusContext);
|
|
2111
2278
|
var usePlayoutStatusUpdate = () => useContext7(PlayoutStatusUpdateContext);
|
|
2112
2279
|
|
|
2113
2280
|
// src/components/SpectrogramChannel.tsx
|
|
2114
|
-
import {
|
|
2115
|
-
import
|
|
2116
|
-
import { MAX_CANVAS_WIDTH as
|
|
2117
|
-
import { jsx as
|
|
2281
|
+
import { useRef as useRef6, useEffect as useEffect8 } from "react";
|
|
2282
|
+
import styled20 from "styled-components";
|
|
2283
|
+
import { MAX_CANVAS_WIDTH as MAX_CANVAS_WIDTH3 } from "@waveform-playlist/core";
|
|
2284
|
+
import { jsx as jsx22 } from "react/jsx-runtime";
|
|
2118
2285
|
var LINEAR_FREQUENCY_SCALE = (f, minF, maxF) => (f - minF) / (maxF - minF);
|
|
2119
|
-
var
|
|
2286
|
+
var Wrapper4 = styled20.div.attrs((props) => ({
|
|
2120
2287
|
style: {
|
|
2121
2288
|
top: `${props.$waveHeight * props.$index}px`,
|
|
2122
2289
|
width: `${props.$cssWidth}px`,
|
|
@@ -2128,7 +2295,7 @@ var Wrapper3 = styled19.div.attrs((props) => ({
|
|
|
2128
2295
|
transform: translateZ(0);
|
|
2129
2296
|
backface-visibility: hidden;
|
|
2130
2297
|
`;
|
|
2131
|
-
var SpectrogramCanvas =
|
|
2298
|
+
var SpectrogramCanvas = styled20.canvas.attrs((props) => ({
|
|
2132
2299
|
style: {
|
|
2133
2300
|
width: `${props.$cssWidth}px`,
|
|
2134
2301
|
height: `${props.$waveHeight}px`,
|
|
@@ -2137,8 +2304,6 @@ var SpectrogramCanvas = styled19.canvas.attrs((props) => ({
|
|
|
2137
2304
|
}))`
|
|
2138
2305
|
position: absolute;
|
|
2139
2306
|
top: 0;
|
|
2140
|
-
/* Promote to own compositing layer for smoother scrolling */
|
|
2141
|
-
will-change: transform;
|
|
2142
2307
|
image-rendering: pixelated;
|
|
2143
2308
|
image-rendering: crisp-edges;
|
|
2144
2309
|
`;
|
|
@@ -2174,18 +2339,18 @@ var SpectrogramChannel = ({
|
|
|
2174
2339
|
const onCanvasesReadyRef = useRef6(onCanvasesReady);
|
|
2175
2340
|
const isWorkerMode = !!(workerApi && clipId);
|
|
2176
2341
|
const clipOriginX = useClipViewportOrigin();
|
|
2177
|
-
const visibleChunkIndices = useVisibleChunkIndices(length,
|
|
2342
|
+
const visibleChunkIndices = useVisibleChunkIndices(length, MAX_CANVAS_WIDTH3, clipOriginX);
|
|
2178
2343
|
const lut = colorLUT ?? DEFAULT_COLOR_LUT;
|
|
2179
2344
|
const maxF = maxFrequency ?? (data ? data.sampleRate / 2 : 22050);
|
|
2180
2345
|
const scaleFn = frequencyScaleFn ?? LINEAR_FREQUENCY_SCALE;
|
|
2181
2346
|
const hasCustomFrequencyScale = Boolean(frequencyScaleFn);
|
|
2182
|
-
|
|
2347
|
+
useEffect8(() => {
|
|
2183
2348
|
workerApiRef.current = workerApi;
|
|
2184
2349
|
}, [workerApi]);
|
|
2185
|
-
|
|
2350
|
+
useEffect8(() => {
|
|
2186
2351
|
onCanvasesReadyRef.current = onCanvasesReady;
|
|
2187
2352
|
}, [onCanvasesReady]);
|
|
2188
|
-
|
|
2353
|
+
useEffect8(() => {
|
|
2189
2354
|
if (!isWorkerMode) return;
|
|
2190
2355
|
const currentWorkerApi = workerApiRef.current;
|
|
2191
2356
|
if (!currentWorkerApi || !clipId) return;
|
|
@@ -2240,15 +2405,15 @@ var SpectrogramChannel = ({
|
|
|
2240
2405
|
const match = id.match(/chunk(\d+)$/);
|
|
2241
2406
|
if (!match) {
|
|
2242
2407
|
console.warn(`[spectrogram] Unexpected canvas ID format: ${id}`);
|
|
2243
|
-
return
|
|
2408
|
+
return MAX_CANVAS_WIDTH3;
|
|
2244
2409
|
}
|
|
2245
2410
|
const chunkIdx = parseInt(match[1], 10);
|
|
2246
|
-
return Math.min(length - chunkIdx *
|
|
2411
|
+
return Math.min(length - chunkIdx * MAX_CANVAS_WIDTH3, MAX_CANVAS_WIDTH3);
|
|
2247
2412
|
});
|
|
2248
2413
|
onCanvasesReadyRef.current?.(allIds, allWidths);
|
|
2249
2414
|
}
|
|
2250
2415
|
}, [canvasMapRef, isWorkerMode, clipId, channelIndex, length, visibleChunkIndices]);
|
|
2251
|
-
|
|
2416
|
+
useEffect8(() => {
|
|
2252
2417
|
return () => {
|
|
2253
2418
|
const api = workerApiRef.current;
|
|
2254
2419
|
if (!api) return;
|
|
@@ -2262,7 +2427,7 @@ var SpectrogramChannel = ({
|
|
|
2262
2427
|
registeredIdsRef.current = [];
|
|
2263
2428
|
};
|
|
2264
2429
|
}, []);
|
|
2265
|
-
|
|
2430
|
+
useEffect8(() => {
|
|
2266
2431
|
if (isWorkerMode || !data) return;
|
|
2267
2432
|
const {
|
|
2268
2433
|
frequencyBinCount,
|
|
@@ -2275,7 +2440,7 @@ var SpectrogramChannel = ({
|
|
|
2275
2440
|
const rangeDb = rawRangeDb === 0 ? 1 : rawRangeDb;
|
|
2276
2441
|
const binToFreq = (bin) => bin / frequencyBinCount * (sampleRate / 2);
|
|
2277
2442
|
for (const [canvasIdx, canvas] of canvasMapRef.current.entries()) {
|
|
2278
|
-
const globalPixelOffset = canvasIdx *
|
|
2443
|
+
const globalPixelOffset = canvasIdx * MAX_CANVAS_WIDTH3;
|
|
2279
2444
|
const ctx = canvas.getContext("2d");
|
|
2280
2445
|
if (!ctx) continue;
|
|
2281
2446
|
const canvasWidth = canvas.width / devicePixelRatio;
|
|
@@ -2351,9 +2516,9 @@ var SpectrogramChannel = ({
|
|
|
2351
2516
|
visibleChunkIndices
|
|
2352
2517
|
]);
|
|
2353
2518
|
const canvases = visibleChunkIndices.map((i) => {
|
|
2354
|
-
const chunkLeft = i *
|
|
2355
|
-
const currentWidth = Math.min(length - chunkLeft,
|
|
2356
|
-
return /* @__PURE__ */
|
|
2519
|
+
const chunkLeft = i * MAX_CANVAS_WIDTH3;
|
|
2520
|
+
const currentWidth = Math.min(length - chunkLeft, MAX_CANVAS_WIDTH3);
|
|
2521
|
+
return /* @__PURE__ */ jsx22(
|
|
2357
2522
|
SpectrogramCanvas,
|
|
2358
2523
|
{
|
|
2359
2524
|
$cssWidth: currentWidth,
|
|
@@ -2367,11 +2532,11 @@ var SpectrogramChannel = ({
|
|
|
2367
2532
|
`${length}-${i}`
|
|
2368
2533
|
);
|
|
2369
2534
|
});
|
|
2370
|
-
return /* @__PURE__ */
|
|
2535
|
+
return /* @__PURE__ */ jsx22(Wrapper4, { $index: index, $cssWidth: length, $waveHeight: waveHeight, children: canvases });
|
|
2371
2536
|
};
|
|
2372
2537
|
|
|
2373
2538
|
// src/components/SmartChannel.tsx
|
|
2374
|
-
import { Fragment as Fragment5, jsx as
|
|
2539
|
+
import { Fragment as Fragment5, jsx as jsx23, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
2375
2540
|
var SmartChannel = ({
|
|
2376
2541
|
isSelected,
|
|
2377
2542
|
transparentBackground,
|
|
@@ -2385,10 +2550,19 @@ var SmartChannel = ({
|
|
|
2385
2550
|
spectrogramWorkerApi,
|
|
2386
2551
|
spectrogramClipId,
|
|
2387
2552
|
spectrogramOnCanvasesReady,
|
|
2553
|
+
midiNotes,
|
|
2554
|
+
sampleRate: sampleRateProp,
|
|
2555
|
+
clipOffsetSeconds,
|
|
2388
2556
|
...props
|
|
2389
2557
|
}) => {
|
|
2390
2558
|
const theme = useTheme2();
|
|
2391
|
-
const {
|
|
2559
|
+
const {
|
|
2560
|
+
waveHeight,
|
|
2561
|
+
barWidth,
|
|
2562
|
+
barGap,
|
|
2563
|
+
samplesPerPixel: contextSpp,
|
|
2564
|
+
sampleRate: contextSampleRate
|
|
2565
|
+
} = usePlaylistInfo();
|
|
2392
2566
|
const devicePixelRatio = useDevicePixelRatio();
|
|
2393
2567
|
const samplesPerPixel = sppProp ?? contextSpp;
|
|
2394
2568
|
const waveOutlineColor = isSelected && theme ? theme.selectedWaveOutlineColor : theme?.waveOutlineColor;
|
|
@@ -2396,7 +2570,7 @@ var SmartChannel = ({
|
|
|
2396
2570
|
const drawMode = theme?.waveformDrawMode || "inverted";
|
|
2397
2571
|
const hasSpectrogram = spectrogramData || spectrogramWorkerApi;
|
|
2398
2572
|
if (renderMode === "spectrogram" && hasSpectrogram) {
|
|
2399
|
-
return /* @__PURE__ */
|
|
2573
|
+
return /* @__PURE__ */ jsx23(
|
|
2400
2574
|
SpectrogramChannel,
|
|
2401
2575
|
{
|
|
2402
2576
|
index: props.index,
|
|
@@ -2418,7 +2592,7 @@ var SmartChannel = ({
|
|
|
2418
2592
|
if (renderMode === "both" && hasSpectrogram) {
|
|
2419
2593
|
const halfHeight = Math.floor(waveHeight / 2);
|
|
2420
2594
|
return /* @__PURE__ */ jsxs9(Fragment5, { children: [
|
|
2421
|
-
/* @__PURE__ */
|
|
2595
|
+
/* @__PURE__ */ jsx23(
|
|
2422
2596
|
SpectrogramChannel,
|
|
2423
2597
|
{
|
|
2424
2598
|
index: props.index * 2,
|
|
@@ -2437,7 +2611,7 @@ var SmartChannel = ({
|
|
|
2437
2611
|
onCanvasesReady: spectrogramOnCanvasesReady
|
|
2438
2612
|
}
|
|
2439
2613
|
),
|
|
2440
|
-
/* @__PURE__ */
|
|
2614
|
+
/* @__PURE__ */ jsx23(
|
|
2441
2615
|
"div",
|
|
2442
2616
|
{
|
|
2443
2617
|
style: {
|
|
@@ -2446,7 +2620,7 @@ var SmartChannel = ({
|
|
|
2446
2620
|
width: props.length,
|
|
2447
2621
|
height: halfHeight
|
|
2448
2622
|
},
|
|
2449
|
-
children: /* @__PURE__ */
|
|
2623
|
+
children: /* @__PURE__ */ jsx23(
|
|
2450
2624
|
Channel,
|
|
2451
2625
|
{
|
|
2452
2626
|
...props,
|
|
@@ -2465,7 +2639,27 @@ var SmartChannel = ({
|
|
|
2465
2639
|
)
|
|
2466
2640
|
] });
|
|
2467
2641
|
}
|
|
2468
|
-
|
|
2642
|
+
if (renderMode === "piano-roll") {
|
|
2643
|
+
return /* @__PURE__ */ jsx23(
|
|
2644
|
+
PianoRollChannel,
|
|
2645
|
+
{
|
|
2646
|
+
index: props.index,
|
|
2647
|
+
midiNotes: midiNotes ?? [],
|
|
2648
|
+
length: props.length,
|
|
2649
|
+
waveHeight,
|
|
2650
|
+
devicePixelRatio,
|
|
2651
|
+
samplesPerPixel,
|
|
2652
|
+
sampleRate: sampleRateProp ?? contextSampleRate,
|
|
2653
|
+
clipOffsetSeconds: clipOffsetSeconds ?? 0,
|
|
2654
|
+
noteColor: theme?.pianoRollNoteColor,
|
|
2655
|
+
selectedNoteColor: theme?.pianoRollSelectedNoteColor,
|
|
2656
|
+
isSelected,
|
|
2657
|
+
transparentBackground,
|
|
2658
|
+
backgroundColor: theme?.pianoRollBackgroundColor
|
|
2659
|
+
}
|
|
2660
|
+
);
|
|
2661
|
+
}
|
|
2662
|
+
return /* @__PURE__ */ jsx23(
|
|
2469
2663
|
Channel,
|
|
2470
2664
|
{
|
|
2471
2665
|
...props,
|
|
@@ -2482,11 +2676,11 @@ var SmartChannel = ({
|
|
|
2482
2676
|
};
|
|
2483
2677
|
|
|
2484
2678
|
// src/components/SpectrogramLabels.tsx
|
|
2485
|
-
import { useRef as useRef7, useLayoutEffect as
|
|
2486
|
-
import
|
|
2487
|
-
import { jsx as
|
|
2679
|
+
import { useRef as useRef7, useLayoutEffect as useLayoutEffect2 } from "react";
|
|
2680
|
+
import styled21 from "styled-components";
|
|
2681
|
+
import { jsx as jsx24 } from "react/jsx-runtime";
|
|
2488
2682
|
var LABELS_WIDTH = 72;
|
|
2489
|
-
var LabelsStickyWrapper =
|
|
2683
|
+
var LabelsStickyWrapper = styled21.div`
|
|
2490
2684
|
position: sticky;
|
|
2491
2685
|
left: 0;
|
|
2492
2686
|
z-index: 101;
|
|
@@ -2539,7 +2733,7 @@ var SpectrogramLabels = ({
|
|
|
2539
2733
|
const spectrogramHeight = renderMode === "both" ? Math.floor(waveHeight / 2) : waveHeight;
|
|
2540
2734
|
const totalHeight = numChannels * waveHeight;
|
|
2541
2735
|
const clipHeaderOffset = hasClipHeaders ? 22 : 0;
|
|
2542
|
-
|
|
2736
|
+
useLayoutEffect2(() => {
|
|
2543
2737
|
const canvas = canvasRef.current;
|
|
2544
2738
|
if (!canvas) return;
|
|
2545
2739
|
const ctx = canvas.getContext("2d");
|
|
@@ -2577,7 +2771,7 @@ var SpectrogramLabels = ({
|
|
|
2577
2771
|
spectrogramHeight,
|
|
2578
2772
|
clipHeaderOffset
|
|
2579
2773
|
]);
|
|
2580
|
-
return /* @__PURE__ */
|
|
2774
|
+
return /* @__PURE__ */ jsx24(LabelsStickyWrapper, { $height: totalHeight + clipHeaderOffset, children: /* @__PURE__ */ jsx24(
|
|
2581
2775
|
"canvas",
|
|
2582
2776
|
{
|
|
2583
2777
|
ref: canvasRef,
|
|
@@ -2596,8 +2790,8 @@ var SpectrogramLabels = ({
|
|
|
2596
2790
|
import { useContext as useContext9 } from "react";
|
|
2597
2791
|
|
|
2598
2792
|
// src/components/TimeScale.tsx
|
|
2599
|
-
import
|
|
2600
|
-
import
|
|
2793
|
+
import React17, { useLayoutEffect as useLayoutEffect3, useContext as useContext8, useMemo as useMemo3 } from "react";
|
|
2794
|
+
import styled22, { withTheme as withTheme2 } from "styled-components";
|
|
2601
2795
|
|
|
2602
2796
|
// src/utils/conversions.ts
|
|
2603
2797
|
function samplesToSeconds(samples, sampleRate) {
|
|
@@ -2620,18 +2814,17 @@ function secondsToPixels(seconds, samplesPerPixel, sampleRate) {
|
|
|
2620
2814
|
}
|
|
2621
2815
|
|
|
2622
2816
|
// src/components/TimeScale.tsx
|
|
2623
|
-
import { MAX_CANVAS_WIDTH as
|
|
2624
|
-
import { jsx as
|
|
2817
|
+
import { MAX_CANVAS_WIDTH as MAX_CANVAS_WIDTH4 } from "@waveform-playlist/core";
|
|
2818
|
+
import { jsx as jsx25, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
2625
2819
|
function formatTime2(milliseconds) {
|
|
2626
2820
|
const seconds = Math.floor(milliseconds / 1e3);
|
|
2627
2821
|
const s = seconds % 60;
|
|
2628
2822
|
const m = (seconds - s) / 60;
|
|
2629
2823
|
return `${m}:${String(s).padStart(2, "0")}`;
|
|
2630
2824
|
}
|
|
2631
|
-
var PlaylistTimeScaleScroll =
|
|
2825
|
+
var PlaylistTimeScaleScroll = styled22.div.attrs((props) => ({
|
|
2632
2826
|
style: {
|
|
2633
2827
|
width: `${props.$cssWidth}px`,
|
|
2634
|
-
marginLeft: `${props.$controlWidth}px`,
|
|
2635
2828
|
height: `${props.$timeScaleHeight}px`
|
|
2636
2829
|
}
|
|
2637
2830
|
}))`
|
|
@@ -2640,7 +2833,7 @@ var PlaylistTimeScaleScroll = styled21.div.attrs((props) => ({
|
|
|
2640
2833
|
border-bottom: 1px solid ${(props) => props.theme.timeColor};
|
|
2641
2834
|
box-sizing: border-box;
|
|
2642
2835
|
`;
|
|
2643
|
-
var TimeTickChunk =
|
|
2836
|
+
var TimeTickChunk = styled22.canvas.attrs((props) => ({
|
|
2644
2837
|
style: {
|
|
2645
2838
|
width: `${props.$cssWidth}px`,
|
|
2646
2839
|
height: `${props.$timeScaleHeight}px`,
|
|
@@ -2649,10 +2842,8 @@ var TimeTickChunk = styled21.canvas.attrs((props) => ({
|
|
|
2649
2842
|
}))`
|
|
2650
2843
|
position: absolute;
|
|
2651
2844
|
bottom: 0;
|
|
2652
|
-
/* Promote to own compositing layer for smoother scrolling */
|
|
2653
|
-
will-change: transform;
|
|
2654
2845
|
`;
|
|
2655
|
-
var TimeStamp =
|
|
2846
|
+
var TimeStamp = styled22.div.attrs((props) => ({
|
|
2656
2847
|
style: {
|
|
2657
2848
|
left: `${props.$left + 4}px`
|
|
2658
2849
|
// Offset 4px to the right of the tick
|
|
@@ -2673,14 +2864,9 @@ var TimeScale = (props) => {
|
|
|
2673
2864
|
renderTimestamp
|
|
2674
2865
|
} = props;
|
|
2675
2866
|
const { canvasRef, canvasMapRef } = useChunkedCanvasRefs();
|
|
2676
|
-
const {
|
|
2677
|
-
sampleRate,
|
|
2678
|
-
samplesPerPixel,
|
|
2679
|
-
timeScaleHeight,
|
|
2680
|
-
controls: { show: showControls, width: controlWidth }
|
|
2681
|
-
} = useContext8(PlaylistInfoContext);
|
|
2867
|
+
const { sampleRate, samplesPerPixel, timeScaleHeight } = useContext8(PlaylistInfoContext);
|
|
2682
2868
|
const devicePixelRatio = useDevicePixelRatio();
|
|
2683
|
-
const { widthX, canvasInfo, timeMarkersWithPositions } =
|
|
2869
|
+
const { widthX, canvasInfo, timeMarkersWithPositions } = useMemo3(() => {
|
|
2684
2870
|
const nextCanvasInfo = /* @__PURE__ */ new Map();
|
|
2685
2871
|
const nextMarkers = [];
|
|
2686
2872
|
const nextWidthX = secondsToPixels(duration / 1e3, samplesPerPixel, sampleRate);
|
|
@@ -2691,7 +2877,7 @@ var TimeScale = (props) => {
|
|
|
2691
2877
|
if (counter % marker === 0) {
|
|
2692
2878
|
const timeMs = counter;
|
|
2693
2879
|
const timestamp = formatTime2(timeMs);
|
|
2694
|
-
const element = renderTimestamp ? /* @__PURE__ */
|
|
2880
|
+
const element = renderTimestamp ? /* @__PURE__ */ jsx25(React17.Fragment, { children: renderTimestamp(timeMs, pix) }, `timestamp-${counter}`) : /* @__PURE__ */ jsx25(TimeStamp, { $left: pix, children: timestamp }, timestamp);
|
|
2695
2881
|
nextMarkers.push({ pix, element });
|
|
2696
2882
|
nextCanvasInfo.set(pix, timeScaleHeight);
|
|
2697
2883
|
} else if (counter % bigStep === 0) {
|
|
@@ -2716,11 +2902,11 @@ var TimeScale = (props) => {
|
|
|
2716
2902
|
renderTimestamp,
|
|
2717
2903
|
timeScaleHeight
|
|
2718
2904
|
]);
|
|
2719
|
-
const visibleChunkIndices = useVisibleChunkIndices(widthX,
|
|
2905
|
+
const visibleChunkIndices = useVisibleChunkIndices(widthX, MAX_CANVAS_WIDTH4);
|
|
2720
2906
|
const visibleChunks = visibleChunkIndices.map((i) => {
|
|
2721
|
-
const chunkLeft = i *
|
|
2722
|
-
const chunkWidth = Math.min(widthX - chunkLeft,
|
|
2723
|
-
return /* @__PURE__ */
|
|
2907
|
+
const chunkLeft = i * MAX_CANVAS_WIDTH4;
|
|
2908
|
+
const chunkWidth = Math.min(widthX - chunkLeft, MAX_CANVAS_WIDTH4);
|
|
2909
|
+
return /* @__PURE__ */ jsx25(
|
|
2724
2910
|
TimeTickChunk,
|
|
2725
2911
|
{
|
|
2726
2912
|
$cssWidth: chunkWidth,
|
|
@@ -2734,14 +2920,14 @@ var TimeScale = (props) => {
|
|
|
2734
2920
|
`timescale-${i}`
|
|
2735
2921
|
);
|
|
2736
2922
|
});
|
|
2737
|
-
const firstChunkLeft = visibleChunkIndices.length > 0 ? visibleChunkIndices[0] *
|
|
2738
|
-
const lastChunkRight = visibleChunkIndices.length > 0 ? (visibleChunkIndices[visibleChunkIndices.length - 1] + 1) *
|
|
2923
|
+
const firstChunkLeft = visibleChunkIndices.length > 0 ? visibleChunkIndices[0] * MAX_CANVAS_WIDTH4 : 0;
|
|
2924
|
+
const lastChunkRight = visibleChunkIndices.length > 0 ? (visibleChunkIndices[visibleChunkIndices.length - 1] + 1) * MAX_CANVAS_WIDTH4 : Infinity;
|
|
2739
2925
|
const visibleMarkers = visibleChunkIndices.length > 0 ? timeMarkersWithPositions.filter(({ pix }) => pix >= firstChunkLeft && pix < lastChunkRight).map(({ element }) => element) : timeMarkersWithPositions.map(({ element }) => element);
|
|
2740
|
-
|
|
2926
|
+
useLayoutEffect3(() => {
|
|
2741
2927
|
for (const [chunkIdx, canvas] of canvasMapRef.current.entries()) {
|
|
2742
2928
|
const ctx = canvas.getContext("2d");
|
|
2743
2929
|
if (!ctx) continue;
|
|
2744
|
-
const chunkLeft = chunkIdx *
|
|
2930
|
+
const chunkLeft = chunkIdx * MAX_CANVAS_WIDTH4;
|
|
2745
2931
|
const chunkWidth = canvas.width / devicePixelRatio;
|
|
2746
2932
|
ctx.resetTransform();
|
|
2747
2933
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
@@ -2764,23 +2950,15 @@ var TimeScale = (props) => {
|
|
|
2764
2950
|
canvasInfo,
|
|
2765
2951
|
visibleChunkIndices
|
|
2766
2952
|
]);
|
|
2767
|
-
return /* @__PURE__ */ jsxs10(
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
$controlWidth: showControls ? controlWidth : 0,
|
|
2772
|
-
$timeScaleHeight: timeScaleHeight,
|
|
2773
|
-
children: [
|
|
2774
|
-
visibleMarkers,
|
|
2775
|
-
visibleChunks
|
|
2776
|
-
]
|
|
2777
|
-
}
|
|
2778
|
-
);
|
|
2953
|
+
return /* @__PURE__ */ jsxs10(PlaylistTimeScaleScroll, { $cssWidth: widthX, $timeScaleHeight: timeScaleHeight, children: [
|
|
2954
|
+
visibleMarkers,
|
|
2955
|
+
visibleChunks
|
|
2956
|
+
] });
|
|
2779
2957
|
};
|
|
2780
2958
|
var StyledTimeScale = withTheme2(TimeScale);
|
|
2781
2959
|
|
|
2782
2960
|
// src/components/SmartScale.tsx
|
|
2783
|
-
import { jsx as
|
|
2961
|
+
import { jsx as jsx26 } from "react/jsx-runtime";
|
|
2784
2962
|
var timeinfo = /* @__PURE__ */ new Map([
|
|
2785
2963
|
[
|
|
2786
2964
|
700,
|
|
@@ -2856,7 +3034,7 @@ function getScaleInfo(samplesPerPixel) {
|
|
|
2856
3034
|
var SmartScale = ({ renderTimestamp }) => {
|
|
2857
3035
|
const { samplesPerPixel, duration } = useContext9(PlaylistInfoContext);
|
|
2858
3036
|
let config = getScaleInfo(samplesPerPixel);
|
|
2859
|
-
return /* @__PURE__ */
|
|
3037
|
+
return /* @__PURE__ */ jsx26(
|
|
2860
3038
|
StyledTimeScale,
|
|
2861
3039
|
{
|
|
2862
3040
|
marker: config.marker,
|
|
@@ -2869,9 +3047,9 @@ var SmartScale = ({ renderTimestamp }) => {
|
|
|
2869
3047
|
};
|
|
2870
3048
|
|
|
2871
3049
|
// src/components/TimeFormatSelect.tsx
|
|
2872
|
-
import
|
|
2873
|
-
import { jsx as
|
|
2874
|
-
var SelectWrapper =
|
|
3050
|
+
import styled23 from "styled-components";
|
|
3051
|
+
import { jsx as jsx27 } from "react/jsx-runtime";
|
|
3052
|
+
var SelectWrapper = styled23.div`
|
|
2875
3053
|
display: inline-flex;
|
|
2876
3054
|
align-items: center;
|
|
2877
3055
|
gap: 0.5rem;
|
|
@@ -2893,7 +3071,7 @@ var TimeFormatSelect = ({
|
|
|
2893
3071
|
const handleChange = (e) => {
|
|
2894
3072
|
onChange(e.target.value);
|
|
2895
3073
|
};
|
|
2896
|
-
return /* @__PURE__ */
|
|
3074
|
+
return /* @__PURE__ */ jsx27(SelectWrapper, { className, children: /* @__PURE__ */ jsx27(
|
|
2897
3075
|
BaseSelect,
|
|
2898
3076
|
{
|
|
2899
3077
|
className: "time-format",
|
|
@@ -2901,50 +3079,30 @@ var TimeFormatSelect = ({
|
|
|
2901
3079
|
onChange: handleChange,
|
|
2902
3080
|
disabled,
|
|
2903
3081
|
"aria-label": "Time format selection",
|
|
2904
|
-
children: TIME_FORMAT_OPTIONS.map((option) => /* @__PURE__ */
|
|
3082
|
+
children: TIME_FORMAT_OPTIONS.map((option) => /* @__PURE__ */ jsx27("option", { value: option.value, children: option.label }, option.value))
|
|
2905
3083
|
}
|
|
2906
3084
|
) });
|
|
2907
3085
|
};
|
|
2908
3086
|
|
|
2909
3087
|
// src/components/Track.tsx
|
|
2910
|
-
import
|
|
2911
|
-
import { jsx as
|
|
2912
|
-
var Container =
|
|
3088
|
+
import styled24 from "styled-components";
|
|
3089
|
+
import { jsx as jsx28 } from "react/jsx-runtime";
|
|
3090
|
+
var Container = styled24.div.attrs((props) => ({
|
|
2913
3091
|
style: {
|
|
2914
3092
|
height: `${props.$waveHeight * props.$numChannels + (props.$hasClipHeaders ? CLIP_HEADER_HEIGHT : 0)}px`
|
|
2915
3093
|
}
|
|
2916
3094
|
}))`
|
|
2917
3095
|
position: relative;
|
|
2918
|
-
display: flex;
|
|
2919
3096
|
${(props) => props.$width !== void 0 && `width: ${props.$width}px;`}
|
|
2920
3097
|
`;
|
|
2921
|
-
var ChannelContainer =
|
|
3098
|
+
var ChannelContainer = styled24.div.attrs((props) => ({
|
|
2922
3099
|
style: {
|
|
2923
3100
|
paddingLeft: `${props.$offset || 0}px`
|
|
2924
3101
|
}
|
|
2925
3102
|
}))`
|
|
2926
3103
|
position: relative;
|
|
2927
3104
|
background: ${(props) => props.$backgroundColor || "transparent"};
|
|
2928
|
-
flex: 1;
|
|
2929
|
-
`;
|
|
2930
|
-
var ControlsWrapper = styled23.div.attrs((props) => ({
|
|
2931
|
-
style: {
|
|
2932
|
-
width: `${props.$controlWidth}px`
|
|
2933
|
-
}
|
|
2934
|
-
}))`
|
|
2935
|
-
position: sticky;
|
|
2936
|
-
z-index: 102; /* Above waveform content and spectrogram labels (101), below Docusaurus navbar (200) */
|
|
2937
|
-
left: 0;
|
|
2938
3105
|
height: 100%;
|
|
2939
|
-
flex-shrink: 0;
|
|
2940
|
-
pointer-events: auto;
|
|
2941
|
-
background: ${(props) => props.theme.surfaceColor};
|
|
2942
|
-
transition: background 0.15s ease-in-out;
|
|
2943
|
-
|
|
2944
|
-
/* Selected track: highlighted background */
|
|
2945
|
-
${(props) => props.$isSelected && `
|
|
2946
|
-
background: ${props.theme.selectedTrackControlsBackground};
|
|
2947
|
-
`}
|
|
2948
3106
|
`;
|
|
2949
3107
|
var Track = ({
|
|
2950
3108
|
numChannels,
|
|
@@ -2956,44 +3114,34 @@ var Track = ({
|
|
|
2956
3114
|
hasClipHeaders = false,
|
|
2957
3115
|
onClick,
|
|
2958
3116
|
trackId,
|
|
2959
|
-
isSelected = false
|
|
3117
|
+
isSelected: _isSelected = false
|
|
2960
3118
|
}) => {
|
|
2961
|
-
const {
|
|
2962
|
-
|
|
2963
|
-
controls: { show, width: controlWidth }
|
|
2964
|
-
} = usePlaylistInfo();
|
|
2965
|
-
const controls = useTrackControls();
|
|
2966
|
-
return /* @__PURE__ */ jsxs11(
|
|
3119
|
+
const { waveHeight } = usePlaylistInfo();
|
|
3120
|
+
return /* @__PURE__ */ jsx28(
|
|
2967
3121
|
Container,
|
|
2968
3122
|
{
|
|
2969
3123
|
$numChannels: numChannels,
|
|
2970
3124
|
className,
|
|
2971
3125
|
$waveHeight: waveHeight,
|
|
2972
|
-
$controlWidth: show ? controlWidth : 0,
|
|
2973
3126
|
$width: width,
|
|
2974
3127
|
$hasClipHeaders: hasClipHeaders,
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
"data-track-id": trackId,
|
|
2986
|
-
children
|
|
2987
|
-
}
|
|
2988
|
-
)
|
|
2989
|
-
]
|
|
3128
|
+
children: /* @__PURE__ */ jsx28(
|
|
3129
|
+
ChannelContainer,
|
|
3130
|
+
{
|
|
3131
|
+
$backgroundColor: backgroundColor,
|
|
3132
|
+
$offset: offset,
|
|
3133
|
+
onClick,
|
|
3134
|
+
"data-track-id": trackId,
|
|
3135
|
+
children
|
|
3136
|
+
}
|
|
3137
|
+
)
|
|
2990
3138
|
}
|
|
2991
3139
|
);
|
|
2992
3140
|
};
|
|
2993
3141
|
|
|
2994
3142
|
// src/components/TrackControls/Button.tsx
|
|
2995
|
-
import
|
|
2996
|
-
var Button =
|
|
3143
|
+
import styled25 from "styled-components";
|
|
3144
|
+
var Button = styled25.button.attrs({
|
|
2997
3145
|
type: "button"
|
|
2998
3146
|
})`
|
|
2999
3147
|
display: inline-block;
|
|
@@ -3068,8 +3216,8 @@ var Button = styled24.button.attrs({
|
|
|
3068
3216
|
`;
|
|
3069
3217
|
|
|
3070
3218
|
// src/components/TrackControls/ButtonGroup.tsx
|
|
3071
|
-
import
|
|
3072
|
-
var ButtonGroup =
|
|
3219
|
+
import styled26 from "styled-components";
|
|
3220
|
+
var ButtonGroup = styled26.div`
|
|
3073
3221
|
margin-bottom: 0.3rem;
|
|
3074
3222
|
|
|
3075
3223
|
button:not(:first-child) {
|
|
@@ -3084,10 +3232,10 @@ var ButtonGroup = styled25.div`
|
|
|
3084
3232
|
`;
|
|
3085
3233
|
|
|
3086
3234
|
// src/components/TrackControls/CloseButton.tsx
|
|
3087
|
-
import
|
|
3235
|
+
import styled27 from "styled-components";
|
|
3088
3236
|
import { X as XIcon } from "@phosphor-icons/react";
|
|
3089
|
-
import { jsx as
|
|
3090
|
-
var StyledCloseButton =
|
|
3237
|
+
import { jsx as jsx29 } from "react/jsx-runtime";
|
|
3238
|
+
var StyledCloseButton = styled27.button`
|
|
3091
3239
|
position: absolute;
|
|
3092
3240
|
left: 0;
|
|
3093
3241
|
top: 0;
|
|
@@ -3110,11 +3258,11 @@ var StyledCloseButton = styled26.button`
|
|
|
3110
3258
|
color: #dc3545;
|
|
3111
3259
|
}
|
|
3112
3260
|
`;
|
|
3113
|
-
var CloseButton = ({ onClick, title = "Remove track" }) => /* @__PURE__ */
|
|
3261
|
+
var CloseButton = ({ onClick, title = "Remove track" }) => /* @__PURE__ */ jsx29(StyledCloseButton, { onClick, title, children: /* @__PURE__ */ jsx29(XIcon, { size: 12, weight: "bold" }) });
|
|
3114
3262
|
|
|
3115
3263
|
// src/components/TrackControls/Controls.tsx
|
|
3116
|
-
import
|
|
3117
|
-
var Controls =
|
|
3264
|
+
import styled28 from "styled-components";
|
|
3265
|
+
var Controls = styled28.div`
|
|
3118
3266
|
background: transparent;
|
|
3119
3267
|
width: 100%;
|
|
3120
3268
|
height: 100%;
|
|
@@ -3130,8 +3278,8 @@ var Controls = styled27.div`
|
|
|
3130
3278
|
`;
|
|
3131
3279
|
|
|
3132
3280
|
// src/components/TrackControls/Header.tsx
|
|
3133
|
-
import
|
|
3134
|
-
var Header =
|
|
3281
|
+
import styled29 from "styled-components";
|
|
3282
|
+
var Header = styled29.header`
|
|
3135
3283
|
overflow: hidden;
|
|
3136
3284
|
height: 26px;
|
|
3137
3285
|
width: 100%;
|
|
@@ -3146,27 +3294,27 @@ var Header = styled28.header`
|
|
|
3146
3294
|
|
|
3147
3295
|
// src/components/TrackControls/VolumeDownIcon.tsx
|
|
3148
3296
|
import { SpeakerLowIcon } from "@phosphor-icons/react";
|
|
3149
|
-
import { jsx as
|
|
3150
|
-
var VolumeDownIcon = (props) => /* @__PURE__ */
|
|
3297
|
+
import { jsx as jsx30 } from "react/jsx-runtime";
|
|
3298
|
+
var VolumeDownIcon = (props) => /* @__PURE__ */ jsx30(SpeakerLowIcon, { weight: "light", ...props });
|
|
3151
3299
|
|
|
3152
3300
|
// src/components/TrackControls/VolumeUpIcon.tsx
|
|
3153
3301
|
import { SpeakerHighIcon } from "@phosphor-icons/react";
|
|
3154
|
-
import { jsx as
|
|
3155
|
-
var VolumeUpIcon = (props) => /* @__PURE__ */
|
|
3302
|
+
import { jsx as jsx31 } from "react/jsx-runtime";
|
|
3303
|
+
var VolumeUpIcon = (props) => /* @__PURE__ */ jsx31(SpeakerHighIcon, { weight: "light", ...props });
|
|
3156
3304
|
|
|
3157
3305
|
// src/components/TrackControls/TrashIcon.tsx
|
|
3158
3306
|
import { TrashIcon as PhosphorTrashIcon } from "@phosphor-icons/react";
|
|
3159
|
-
import { jsx as
|
|
3160
|
-
var TrashIcon = (props) => /* @__PURE__ */
|
|
3307
|
+
import { jsx as jsx32 } from "react/jsx-runtime";
|
|
3308
|
+
var TrashIcon = (props) => /* @__PURE__ */ jsx32(PhosphorTrashIcon, { weight: "light", ...props });
|
|
3161
3309
|
|
|
3162
3310
|
// src/components/TrackControls/DotsIcon.tsx
|
|
3163
3311
|
import { DotsThreeIcon } from "@phosphor-icons/react";
|
|
3164
|
-
import { jsx as
|
|
3165
|
-
var DotsIcon = (props) => /* @__PURE__ */
|
|
3312
|
+
import { jsx as jsx33 } from "react/jsx-runtime";
|
|
3313
|
+
var DotsIcon = (props) => /* @__PURE__ */ jsx33(DotsThreeIcon, { weight: "bold", ...props });
|
|
3166
3314
|
|
|
3167
3315
|
// src/components/TrackControls/Slider.tsx
|
|
3168
|
-
import
|
|
3169
|
-
var Slider =
|
|
3316
|
+
import styled30 from "styled-components";
|
|
3317
|
+
var Slider = styled30(BaseSlider)`
|
|
3170
3318
|
width: 75%;
|
|
3171
3319
|
height: 5px;
|
|
3172
3320
|
background: ${(props) => props.theme.sliderTrackColor};
|
|
@@ -3218,8 +3366,8 @@ var Slider = styled29(BaseSlider)`
|
|
|
3218
3366
|
`;
|
|
3219
3367
|
|
|
3220
3368
|
// src/components/TrackControls/SliderWrapper.tsx
|
|
3221
|
-
import
|
|
3222
|
-
var SliderWrapper =
|
|
3369
|
+
import styled31 from "styled-components";
|
|
3370
|
+
var SliderWrapper = styled31.label`
|
|
3223
3371
|
width: 100%;
|
|
3224
3372
|
display: flex;
|
|
3225
3373
|
justify-content: space-between;
|
|
@@ -3230,15 +3378,15 @@ var SliderWrapper = styled30.label`
|
|
|
3230
3378
|
`;
|
|
3231
3379
|
|
|
3232
3380
|
// src/components/TrackMenu.tsx
|
|
3233
|
-
import
|
|
3381
|
+
import React19, { useState as useState6, useEffect as useEffect9, useRef as useRef8, useCallback as useCallback5 } from "react";
|
|
3234
3382
|
import { createPortal } from "react-dom";
|
|
3235
|
-
import
|
|
3236
|
-
import { jsx as
|
|
3237
|
-
var MenuContainer =
|
|
3383
|
+
import styled32 from "styled-components";
|
|
3384
|
+
import { jsx as jsx34, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
3385
|
+
var MenuContainer = styled32.div`
|
|
3238
3386
|
position: relative;
|
|
3239
3387
|
display: inline-block;
|
|
3240
3388
|
`;
|
|
3241
|
-
var MenuButton =
|
|
3389
|
+
var MenuButton = styled32.button`
|
|
3242
3390
|
background: none;
|
|
3243
3391
|
border: none;
|
|
3244
3392
|
cursor: pointer;
|
|
@@ -3253,7 +3401,8 @@ var MenuButton = styled31.button`
|
|
|
3253
3401
|
opacity: 1;
|
|
3254
3402
|
}
|
|
3255
3403
|
`;
|
|
3256
|
-
var
|
|
3404
|
+
var DROPDOWN_MIN_WIDTH = 180;
|
|
3405
|
+
var Dropdown = styled32.div`
|
|
3257
3406
|
position: fixed;
|
|
3258
3407
|
top: ${(p) => p.$top}px;
|
|
3259
3408
|
left: ${(p) => p.$left}px;
|
|
@@ -3263,31 +3412,53 @@ var Dropdown = styled31.div`
|
|
|
3263
3412
|
border: 1px solid rgba(128, 128, 128, 0.4);
|
|
3264
3413
|
border-radius: 6px;
|
|
3265
3414
|
padding: 0.5rem 0;
|
|
3266
|
-
min-width:
|
|
3415
|
+
min-width: ${DROPDOWN_MIN_WIDTH}px;
|
|
3267
3416
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
|
3268
3417
|
`;
|
|
3269
|
-
var Divider =
|
|
3418
|
+
var Divider = styled32.hr`
|
|
3270
3419
|
border: none;
|
|
3271
3420
|
border-top: 1px solid rgba(128, 128, 128, 0.3);
|
|
3272
3421
|
margin: 0.35rem 0;
|
|
3273
3422
|
`;
|
|
3274
3423
|
var TrackMenu = ({ items: itemsProp }) => {
|
|
3275
3424
|
const [open, setOpen] = useState6(false);
|
|
3276
|
-
const close = () => setOpen(false);
|
|
3425
|
+
const close = useCallback5(() => setOpen(false), []);
|
|
3277
3426
|
const items = typeof itemsProp === "function" ? itemsProp(close) : itemsProp;
|
|
3278
3427
|
const [dropdownPos, setDropdownPos] = useState6({ top: 0, left: 0 });
|
|
3279
3428
|
const buttonRef = useRef8(null);
|
|
3280
3429
|
const dropdownRef = useRef8(null);
|
|
3281
|
-
|
|
3282
|
-
if (
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
|
|
3430
|
+
const updatePosition = useCallback5(() => {
|
|
3431
|
+
if (!buttonRef.current) return;
|
|
3432
|
+
const rect = buttonRef.current.getBoundingClientRect();
|
|
3433
|
+
const vw = window.innerWidth;
|
|
3434
|
+
const vh = window.innerHeight;
|
|
3435
|
+
const dropHeight = dropdownRef.current?.offsetHeight ?? 160;
|
|
3436
|
+
let left = rect.right + 4;
|
|
3437
|
+
if (left + DROPDOWN_MIN_WIDTH > vw) {
|
|
3438
|
+
left = rect.left - DROPDOWN_MIN_WIDTH - 4;
|
|
3288
3439
|
}
|
|
3289
|
-
|
|
3290
|
-
|
|
3440
|
+
left = Math.max(4, Math.min(left, vw - DROPDOWN_MIN_WIDTH - 4));
|
|
3441
|
+
let top = rect.top;
|
|
3442
|
+
if (top + dropHeight > vh - 4) {
|
|
3443
|
+
top = Math.max(4, rect.bottom - dropHeight);
|
|
3444
|
+
}
|
|
3445
|
+
setDropdownPos({ top, left });
|
|
3446
|
+
}, []);
|
|
3447
|
+
useEffect9(() => {
|
|
3448
|
+
if (!open) return;
|
|
3449
|
+
updatePosition();
|
|
3450
|
+
const rafId = requestAnimationFrame(() => updatePosition());
|
|
3451
|
+
const onScroll = () => updatePosition();
|
|
3452
|
+
const onResize = () => updatePosition();
|
|
3453
|
+
window.addEventListener("scroll", onScroll, true);
|
|
3454
|
+
window.addEventListener("resize", onResize);
|
|
3455
|
+
return () => {
|
|
3456
|
+
cancelAnimationFrame(rafId);
|
|
3457
|
+
window.removeEventListener("scroll", onScroll, true);
|
|
3458
|
+
window.removeEventListener("resize", onResize);
|
|
3459
|
+
};
|
|
3460
|
+
}, [open, updatePosition]);
|
|
3461
|
+
useEffect9(() => {
|
|
3291
3462
|
if (!open) return;
|
|
3292
3463
|
const handleClick = (e) => {
|
|
3293
3464
|
const target = e.target;
|
|
@@ -3295,11 +3466,20 @@ var TrackMenu = ({ items: itemsProp }) => {
|
|
|
3295
3466
|
setOpen(false);
|
|
3296
3467
|
}
|
|
3297
3468
|
};
|
|
3469
|
+
const handleKeyDown = (e) => {
|
|
3470
|
+
if (e.key === "Escape") {
|
|
3471
|
+
setOpen(false);
|
|
3472
|
+
}
|
|
3473
|
+
};
|
|
3298
3474
|
document.addEventListener("mousedown", handleClick);
|
|
3299
|
-
|
|
3475
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
3476
|
+
return () => {
|
|
3477
|
+
document.removeEventListener("mousedown", handleClick);
|
|
3478
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
3479
|
+
};
|
|
3300
3480
|
}, [open]);
|
|
3301
|
-
return /* @__PURE__ */
|
|
3302
|
-
/* @__PURE__ */
|
|
3481
|
+
return /* @__PURE__ */ jsxs11(MenuContainer, { children: [
|
|
3482
|
+
/* @__PURE__ */ jsx34(
|
|
3303
3483
|
MenuButton,
|
|
3304
3484
|
{
|
|
3305
3485
|
ref: buttonRef,
|
|
@@ -3310,19 +3490,19 @@ var TrackMenu = ({ items: itemsProp }) => {
|
|
|
3310
3490
|
onMouseDown: (e) => e.stopPropagation(),
|
|
3311
3491
|
title: "Track menu",
|
|
3312
3492
|
"aria-label": "Track menu",
|
|
3313
|
-
children: /* @__PURE__ */
|
|
3493
|
+
children: /* @__PURE__ */ jsx34(DotsIcon, { size: 16 })
|
|
3314
3494
|
}
|
|
3315
3495
|
),
|
|
3316
3496
|
open && typeof document !== "undefined" && createPortal(
|
|
3317
|
-
/* @__PURE__ */
|
|
3497
|
+
/* @__PURE__ */ jsx34(
|
|
3318
3498
|
Dropdown,
|
|
3319
3499
|
{
|
|
3320
3500
|
ref: dropdownRef,
|
|
3321
3501
|
$top: dropdownPos.top,
|
|
3322
3502
|
$left: dropdownPos.left,
|
|
3323
3503
|
onMouseDown: (e) => e.stopPropagation(),
|
|
3324
|
-
children: items.map((item, index) => /* @__PURE__ */
|
|
3325
|
-
index > 0 && /* @__PURE__ */
|
|
3504
|
+
children: items.map((item, index) => /* @__PURE__ */ jsxs11(React19.Fragment, { children: [
|
|
3505
|
+
index > 0 && /* @__PURE__ */ jsx34(Divider, {}),
|
|
3326
3506
|
item.content
|
|
3327
3507
|
] }, item.id))
|
|
3328
3508
|
}
|
|
@@ -3364,6 +3544,7 @@ export {
|
|
|
3364
3544
|
LoopRegion,
|
|
3365
3545
|
LoopRegionMarkers,
|
|
3366
3546
|
MasterVolumeControl,
|
|
3547
|
+
PianoRollChannel,
|
|
3367
3548
|
Playhead,
|
|
3368
3549
|
PlayheadWithMarker,
|
|
3369
3550
|
Playlist,
|