@waveform-playlist/ui-components 5.0.0-alpha.0 → 5.0.0-alpha.10
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 -1
- package/dist/index.d.ts +69 -1
- package/dist/index.js +481 -123
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +455 -101
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -44,6 +44,7 @@ __export(index_exports, {
|
|
|
44
44
|
Button: () => Button,
|
|
45
45
|
ButtonGroup: () => ButtonGroup,
|
|
46
46
|
CLIP_BOUNDARY_WIDTH: () => CLIP_BOUNDARY_WIDTH,
|
|
47
|
+
CLIP_BOUNDARY_WIDTH_TOUCH: () => CLIP_BOUNDARY_WIDTH_TOUCH,
|
|
47
48
|
CLIP_HEADER_HEIGHT: () => CLIP_HEADER_HEIGHT,
|
|
48
49
|
Channel: () => Channel,
|
|
49
50
|
Clip: () => Clip,
|
|
@@ -55,6 +56,8 @@ __export(index_exports, {
|
|
|
55
56
|
FadeOverlay: () => FadeOverlay,
|
|
56
57
|
Header: () => Header,
|
|
57
58
|
InlineLabel: () => InlineLabel,
|
|
59
|
+
LoopRegion: () => LoopRegion,
|
|
60
|
+
LoopRegionMarkers: () => LoopRegionMarkers,
|
|
58
61
|
MasterVolumeControl: () => MasterVolumeControl,
|
|
59
62
|
Playhead: () => Playhead,
|
|
60
63
|
PlayheadWithMarker: () => PlayheadWithMarker,
|
|
@@ -73,6 +76,7 @@ __export(index_exports, {
|
|
|
73
76
|
TimeFormatSelect: () => TimeFormatSelect,
|
|
74
77
|
TimeInput: () => TimeInput,
|
|
75
78
|
TimeScale: () => TimeScale,
|
|
79
|
+
TimescaleLoopRegion: () => TimescaleLoopRegion,
|
|
76
80
|
Track: () => Track,
|
|
77
81
|
TrackControlsContext: () => TrackControlsContext,
|
|
78
82
|
TrackControlsWithDelete: () => TrackControlsWithDelete,
|
|
@@ -461,6 +465,10 @@ var defaultTheme = {
|
|
|
461
465
|
playheadColor: "#f00",
|
|
462
466
|
selectionColor: "rgba(255, 105, 180, 0.7)",
|
|
463
467
|
// hot pink - high contrast on light backgrounds
|
|
468
|
+
loopRegionColor: "rgba(59, 130, 246, 0.3)",
|
|
469
|
+
// Blue - distinct from pink selection
|
|
470
|
+
loopMarkerColor: "#3b82f6",
|
|
471
|
+
// Blue marker triangles
|
|
464
472
|
clipHeaderBackgroundColor: "rgba(0, 0, 0, 0.1)",
|
|
465
473
|
clipHeaderBorderColor: "rgba(0, 0, 0, 0.2)",
|
|
466
474
|
clipHeaderTextColor: "#333",
|
|
@@ -530,8 +538,12 @@ var darkTheme = {
|
|
|
530
538
|
// Dark warm brown background
|
|
531
539
|
playheadColor: "#3a8838",
|
|
532
540
|
// Darker Ampelmännchen green playhead
|
|
533
|
-
selectionColor: "rgba(
|
|
534
|
-
//
|
|
541
|
+
selectionColor: "rgba(60, 140, 58, 0.6)",
|
|
542
|
+
// Darker Ampelmännchen green selection - visible on dark backgrounds
|
|
543
|
+
loopRegionColor: "rgba(96, 165, 250, 0.35)",
|
|
544
|
+
// Light blue - distinct from green selection
|
|
545
|
+
loopMarkerColor: "#60a5fa",
|
|
546
|
+
// Light blue marker triangles
|
|
535
547
|
clipHeaderBackgroundColor: "rgba(20, 16, 12, 0.85)",
|
|
536
548
|
// Dark background for clip headers
|
|
537
549
|
clipHeaderBorderColor: "rgba(200, 160, 120, 0.25)",
|
|
@@ -772,6 +784,7 @@ var HeaderContainer = import_styled_components10.default.div`
|
|
|
772
784
|
z-index: 110;
|
|
773
785
|
flex-shrink: 0;
|
|
774
786
|
pointer-events: auto; /* Re-enable pointer events (parent ClipContainer has pointer-events: none) */
|
|
787
|
+
touch-action: ${(props) => props.$interactive ? "none" : "auto"}; /* Prevent browser scroll during drag on touch devices */
|
|
775
788
|
|
|
776
789
|
${(props) => props.$interactive && `
|
|
777
790
|
&:hover {
|
|
@@ -844,16 +857,18 @@ var import_react2 = __toESM(require("react"));
|
|
|
844
857
|
var import_styled_components11 = __toESM(require("styled-components"));
|
|
845
858
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
846
859
|
var CLIP_BOUNDARY_WIDTH = 8;
|
|
860
|
+
var CLIP_BOUNDARY_WIDTH_TOUCH = 24;
|
|
847
861
|
var BoundaryContainer = import_styled_components11.default.div`
|
|
848
862
|
position: absolute;
|
|
849
863
|
${(props) => props.$edge === "left" ? "left: 0;" : "right: 0;"}
|
|
850
864
|
top: 0;
|
|
851
865
|
bottom: 0;
|
|
852
|
-
width: ${CLIP_BOUNDARY_WIDTH}px;
|
|
866
|
+
width: ${(props) => props.$touchOptimized ? CLIP_BOUNDARY_WIDTH_TOUCH : CLIP_BOUNDARY_WIDTH}px;
|
|
853
867
|
cursor: col-resize;
|
|
854
868
|
user-select: none;
|
|
855
869
|
z-index: 105; /* Above waveform, below header */
|
|
856
870
|
pointer-events: auto; /* Re-enable pointer events (parent ClipContainer has pointer-events: none) */
|
|
871
|
+
touch-action: none; /* Prevent browser scroll during drag on touch devices */
|
|
857
872
|
|
|
858
873
|
/* Invisible by default, visible on hover */
|
|
859
874
|
background: ${(props) => props.$isDragging ? "rgba(255, 255, 255, 0.4)" : props.$isHovered ? "rgba(255, 255, 255, 0.2)" : "transparent"};
|
|
@@ -877,7 +892,8 @@ var ClipBoundary = ({
|
|
|
877
892
|
trackIndex,
|
|
878
893
|
clipIndex,
|
|
879
894
|
edge,
|
|
880
|
-
dragHandleProps
|
|
895
|
+
dragHandleProps,
|
|
896
|
+
touchOptimized = false
|
|
881
897
|
}) => {
|
|
882
898
|
const [isHovered, setIsHovered] = import_react2.default.useState(false);
|
|
883
899
|
if (!dragHandleProps) {
|
|
@@ -893,6 +909,7 @@ var ClipBoundary = ({
|
|
|
893
909
|
$edge: edge,
|
|
894
910
|
$isDragging: isDragging,
|
|
895
911
|
$isHovered: isHovered,
|
|
912
|
+
$touchOptimized: touchOptimized,
|
|
896
913
|
onMouseEnter: () => setIsHovered(true),
|
|
897
914
|
onMouseLeave: () => setIsHovered(false),
|
|
898
915
|
...listeners,
|
|
@@ -1015,7 +1032,8 @@ var Clip = ({
|
|
|
1015
1032
|
fadeIn,
|
|
1016
1033
|
fadeOut,
|
|
1017
1034
|
sampleRate = 44100,
|
|
1018
|
-
showFades = false
|
|
1035
|
+
showFades = false,
|
|
1036
|
+
touchOptimized = false
|
|
1019
1037
|
}) => {
|
|
1020
1038
|
const left = Math.floor(startSample / samplesPerPixel);
|
|
1021
1039
|
const endPixel = Math.floor((startSample + durationSamples) / samplesPerPixel);
|
|
@@ -1108,6 +1126,7 @@ var Clip = ({
|
|
|
1108
1126
|
trackIndex,
|
|
1109
1127
|
clipIndex,
|
|
1110
1128
|
edge: "left",
|
|
1129
|
+
touchOptimized,
|
|
1111
1130
|
dragHandleProps: {
|
|
1112
1131
|
attributes: leftBoundaryAttributes,
|
|
1113
1132
|
listeners: leftBoundaryListeners,
|
|
@@ -1123,6 +1142,7 @@ var Clip = ({
|
|
|
1123
1142
|
trackIndex,
|
|
1124
1143
|
clipIndex,
|
|
1125
1144
|
edge: "right",
|
|
1145
|
+
touchOptimized,
|
|
1126
1146
|
dragHandleProps: {
|
|
1127
1147
|
attributes: rightBoundaryAttributes,
|
|
1128
1148
|
listeners: rightBoundaryListeners,
|
|
@@ -1300,7 +1320,8 @@ var TimescaleWrapper = import_styled_components16.default.div.attrs((props) => (
|
|
|
1300
1320
|
}))`
|
|
1301
1321
|
background: ${(props) => props.$backgroundColor || "white"};
|
|
1302
1322
|
width: 100%;
|
|
1303
|
-
|
|
1323
|
+
position: relative;
|
|
1324
|
+
overflow: hidden; /* Constrain loop region to timescale area */
|
|
1304
1325
|
`;
|
|
1305
1326
|
var TracksContainer = import_styled_components16.default.div.attrs((props) => ({
|
|
1306
1327
|
style: props.$width !== void 0 ? { minWidth: `${props.$width}px` } : {}
|
|
@@ -1316,7 +1337,8 @@ var ClickOverlay = import_styled_components16.default.div`
|
|
|
1316
1337
|
right: 0;
|
|
1317
1338
|
bottom: 0;
|
|
1318
1339
|
cursor: crosshair;
|
|
1319
|
-
|
|
1340
|
+
/* When selecting, raise z-index above clip boundaries (z-index: 105) to prevent interference */
|
|
1341
|
+
z-index: ${(props) => props.$isSelecting ? 110 : 1};
|
|
1320
1342
|
`;
|
|
1321
1343
|
var Playlist = ({
|
|
1322
1344
|
children,
|
|
@@ -1331,7 +1353,8 @@ var Playlist = ({
|
|
|
1331
1353
|
onTracksMouseDown,
|
|
1332
1354
|
onTracksMouseMove,
|
|
1333
1355
|
onTracksMouseUp,
|
|
1334
|
-
scrollContainerRef
|
|
1356
|
+
scrollContainerRef,
|
|
1357
|
+
isSelecting
|
|
1335
1358
|
}) => {
|
|
1336
1359
|
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Wrapper2, { "data-scroll-container": "true", ref: scrollContainerRef, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
1337
1360
|
ScrollContainer,
|
|
@@ -1346,6 +1369,7 @@ var Playlist = ({
|
|
|
1346
1369
|
ClickOverlay,
|
|
1347
1370
|
{
|
|
1348
1371
|
$controlsWidth: controlsWidth,
|
|
1372
|
+
$isSelecting: isSelecting,
|
|
1349
1373
|
onClick: onTracksClick,
|
|
1350
1374
|
onMouseDown: onTracksMouseDown,
|
|
1351
1375
|
onMouseMove: onTracksMouseMove,
|
|
@@ -1372,7 +1396,7 @@ var SelectionOverlay = import_styled_components17.default.div.attrs((props) => (
|
|
|
1372
1396
|
top: 0;
|
|
1373
1397
|
background: ${(props) => props.$color};
|
|
1374
1398
|
height: 100%;
|
|
1375
|
-
z-index:
|
|
1399
|
+
z-index: 60; /* Above clips (z-index: 10) and fades (z-index: 50), below playhead (z-index: 100) */
|
|
1376
1400
|
pointer-events: none;
|
|
1377
1401
|
opacity: 0.3;
|
|
1378
1402
|
`;
|
|
@@ -1385,14 +1409,344 @@ var Selection = ({
|
|
|
1385
1409
|
if (width <= 0) {
|
|
1386
1410
|
return null;
|
|
1387
1411
|
}
|
|
1388
|
-
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SelectionOverlay, { $left: startPosition, $width: width, $color: color });
|
|
1412
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SelectionOverlay, { $left: startPosition, $width: width, $color: color, "data-selection": true });
|
|
1413
|
+
};
|
|
1414
|
+
|
|
1415
|
+
// src/components/LoopRegion.tsx
|
|
1416
|
+
var import_react4 = require("react");
|
|
1417
|
+
var import_styled_components18 = __toESM(require("styled-components"));
|
|
1418
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
1419
|
+
var LoopRegionOverlayDiv = import_styled_components18.default.div.attrs((props) => ({
|
|
1420
|
+
style: {
|
|
1421
|
+
left: `${props.$left}px`,
|
|
1422
|
+
width: `${props.$width}px`
|
|
1423
|
+
}
|
|
1424
|
+
}))`
|
|
1425
|
+
position: absolute;
|
|
1426
|
+
top: 0;
|
|
1427
|
+
background: ${(props) => props.$color};
|
|
1428
|
+
height: 100%;
|
|
1429
|
+
z-index: 55; /* Between clips (z-index: 50) and selection (z-index: 60) */
|
|
1430
|
+
pointer-events: none;
|
|
1431
|
+
`;
|
|
1432
|
+
var LoopMarker = import_styled_components18.default.div.attrs((props) => ({
|
|
1433
|
+
style: {
|
|
1434
|
+
left: `${props.$left}px`
|
|
1435
|
+
}
|
|
1436
|
+
}))`
|
|
1437
|
+
position: absolute;
|
|
1438
|
+
top: 0;
|
|
1439
|
+
width: 2px;
|
|
1440
|
+
height: 100%;
|
|
1441
|
+
background: ${(props) => props.$color};
|
|
1442
|
+
z-index: 90; /* Below playhead (z-index: 100) */
|
|
1443
|
+
pointer-events: none;
|
|
1444
|
+
|
|
1445
|
+
/* Triangle marker at top */
|
|
1446
|
+
&::before {
|
|
1447
|
+
content: '';
|
|
1448
|
+
position: absolute;
|
|
1449
|
+
top: 0;
|
|
1450
|
+
${(props) => props.$isStart ? "left: 0" : "right: 0"};
|
|
1451
|
+
width: 0;
|
|
1452
|
+
height: 0;
|
|
1453
|
+
border-top: 8px solid ${(props) => props.$color};
|
|
1454
|
+
${(props) => props.$isStart ? "border-right: 8px solid transparent;" : "border-left: 8px solid transparent;"}
|
|
1455
|
+
}
|
|
1456
|
+
`;
|
|
1457
|
+
var LoopRegion = ({
|
|
1458
|
+
startPosition,
|
|
1459
|
+
endPosition,
|
|
1460
|
+
regionColor = "rgba(59, 130, 246, 0.3)",
|
|
1461
|
+
markerColor = "#3b82f6"
|
|
1462
|
+
}) => {
|
|
1463
|
+
const width = Math.max(0, endPosition - startPosition);
|
|
1464
|
+
if (width <= 0) {
|
|
1465
|
+
return null;
|
|
1466
|
+
}
|
|
1467
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
|
|
1468
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1469
|
+
LoopRegionOverlayDiv,
|
|
1470
|
+
{
|
|
1471
|
+
$left: startPosition,
|
|
1472
|
+
$width: width,
|
|
1473
|
+
$color: regionColor,
|
|
1474
|
+
"data-loop-region": true
|
|
1475
|
+
}
|
|
1476
|
+
),
|
|
1477
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1478
|
+
LoopMarker,
|
|
1479
|
+
{
|
|
1480
|
+
$left: startPosition,
|
|
1481
|
+
$color: markerColor,
|
|
1482
|
+
$isStart: true,
|
|
1483
|
+
"data-loop-marker": "start"
|
|
1484
|
+
}
|
|
1485
|
+
),
|
|
1486
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1487
|
+
LoopMarker,
|
|
1488
|
+
{
|
|
1489
|
+
$left: endPosition - 2,
|
|
1490
|
+
$color: markerColor,
|
|
1491
|
+
$isStart: false,
|
|
1492
|
+
"data-loop-marker": "end"
|
|
1493
|
+
}
|
|
1494
|
+
)
|
|
1495
|
+
] });
|
|
1496
|
+
};
|
|
1497
|
+
var DraggableMarkerHandle = import_styled_components18.default.div.attrs((props) => ({
|
|
1498
|
+
style: {
|
|
1499
|
+
left: `${props.$left}px`
|
|
1500
|
+
}
|
|
1501
|
+
}))`
|
|
1502
|
+
position: absolute;
|
|
1503
|
+
top: 0;
|
|
1504
|
+
width: 12px;
|
|
1505
|
+
height: 100%;
|
|
1506
|
+
cursor: ew-resize;
|
|
1507
|
+
z-index: 100;
|
|
1508
|
+
/* Center the handle on the marker position */
|
|
1509
|
+
transform: translateX(-5px);
|
|
1510
|
+
|
|
1511
|
+
/* Visual marker line */
|
|
1512
|
+
&::before {
|
|
1513
|
+
content: '';
|
|
1514
|
+
position: absolute;
|
|
1515
|
+
top: 0;
|
|
1516
|
+
left: 5px;
|
|
1517
|
+
width: 2px;
|
|
1518
|
+
height: 100%;
|
|
1519
|
+
background: ${(props) => props.$color};
|
|
1520
|
+
opacity: ${(props) => props.$isDragging ? 1 : 0.8};
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
/* Triangle marker at top */
|
|
1524
|
+
&::after {
|
|
1525
|
+
content: '';
|
|
1526
|
+
position: absolute;
|
|
1527
|
+
top: 0;
|
|
1528
|
+
${(props) => props.$isStart ? "left: 5px" : "left: -1px"};
|
|
1529
|
+
width: 0;
|
|
1530
|
+
height: 0;
|
|
1531
|
+
border-top: 10px solid ${(props) => props.$color};
|
|
1532
|
+
${(props) => props.$isStart ? "border-right: 10px solid transparent;" : "border-left: 10px solid transparent;"}
|
|
1533
|
+
}
|
|
1534
|
+
|
|
1535
|
+
&:hover::before {
|
|
1536
|
+
opacity: 1;
|
|
1537
|
+
}
|
|
1538
|
+
`;
|
|
1539
|
+
var TimescaleLoopShade = import_styled_components18.default.div.attrs((props) => ({
|
|
1540
|
+
style: {
|
|
1541
|
+
left: `${props.$left}px`,
|
|
1542
|
+
width: `${props.$width}px`
|
|
1543
|
+
}
|
|
1544
|
+
}))`
|
|
1545
|
+
position: absolute;
|
|
1546
|
+
top: 0;
|
|
1547
|
+
height: 100%;
|
|
1548
|
+
background: ${(props) => props.$color};
|
|
1549
|
+
z-index: 50;
|
|
1550
|
+
cursor: grab;
|
|
1551
|
+
|
|
1552
|
+
&:active {
|
|
1553
|
+
cursor: grabbing;
|
|
1554
|
+
}
|
|
1555
|
+
`;
|
|
1556
|
+
var LoopRegionMarkers = ({
|
|
1557
|
+
startPosition,
|
|
1558
|
+
endPosition,
|
|
1559
|
+
markerColor = "#3b82f6",
|
|
1560
|
+
regionColor = "rgba(59, 130, 246, 0.3)",
|
|
1561
|
+
onLoopStartChange,
|
|
1562
|
+
onLoopEndChange,
|
|
1563
|
+
onLoopRegionMove,
|
|
1564
|
+
minPosition = 0,
|
|
1565
|
+
maxPosition = Infinity
|
|
1566
|
+
}) => {
|
|
1567
|
+
const [draggingMarker, setDraggingMarker] = (0, import_react4.useState)(null);
|
|
1568
|
+
const dragStartX = (0, import_react4.useRef)(0);
|
|
1569
|
+
const dragStartPosition = (0, import_react4.useRef)(0);
|
|
1570
|
+
const dragStartEnd = (0, import_react4.useRef)(0);
|
|
1571
|
+
const width = Math.max(0, endPosition - startPosition);
|
|
1572
|
+
const handleMarkerMouseDown = (0, import_react4.useCallback)((e, marker) => {
|
|
1573
|
+
e.preventDefault();
|
|
1574
|
+
e.stopPropagation();
|
|
1575
|
+
setDraggingMarker(marker);
|
|
1576
|
+
dragStartX.current = e.clientX;
|
|
1577
|
+
dragStartPosition.current = marker === "start" ? startPosition : endPosition;
|
|
1578
|
+
const handleMouseMove = (moveEvent) => {
|
|
1579
|
+
const delta = moveEvent.clientX - dragStartX.current;
|
|
1580
|
+
const newPosition = dragStartPosition.current + delta;
|
|
1581
|
+
if (marker === "start") {
|
|
1582
|
+
const clampedPosition = Math.max(minPosition, Math.min(endPosition - 10, newPosition));
|
|
1583
|
+
onLoopStartChange?.(clampedPosition);
|
|
1584
|
+
} else {
|
|
1585
|
+
const clampedPosition = Math.max(startPosition + 10, Math.min(maxPosition, newPosition));
|
|
1586
|
+
onLoopEndChange?.(clampedPosition);
|
|
1587
|
+
}
|
|
1588
|
+
};
|
|
1589
|
+
const handleMouseUp = () => {
|
|
1590
|
+
setDraggingMarker(null);
|
|
1591
|
+
document.removeEventListener("mousemove", handleMouseMove);
|
|
1592
|
+
document.removeEventListener("mouseup", handleMouseUp);
|
|
1593
|
+
};
|
|
1594
|
+
document.addEventListener("mousemove", handleMouseMove);
|
|
1595
|
+
document.addEventListener("mouseup", handleMouseUp);
|
|
1596
|
+
}, [startPosition, endPosition, minPosition, maxPosition, onLoopStartChange, onLoopEndChange]);
|
|
1597
|
+
const handleRegionMouseDown = (0, import_react4.useCallback)((e) => {
|
|
1598
|
+
e.preventDefault();
|
|
1599
|
+
e.stopPropagation();
|
|
1600
|
+
setDraggingMarker("region");
|
|
1601
|
+
dragStartX.current = e.clientX;
|
|
1602
|
+
dragStartPosition.current = startPosition;
|
|
1603
|
+
dragStartEnd.current = endPosition;
|
|
1604
|
+
const regionWidth = endPosition - startPosition;
|
|
1605
|
+
const handleMouseMove = (moveEvent) => {
|
|
1606
|
+
const delta = moveEvent.clientX - dragStartX.current;
|
|
1607
|
+
let newStart = dragStartPosition.current + delta;
|
|
1608
|
+
let newEnd = dragStartEnd.current + delta;
|
|
1609
|
+
if (newStart < minPosition) {
|
|
1610
|
+
newStart = minPosition;
|
|
1611
|
+
newEnd = minPosition + regionWidth;
|
|
1612
|
+
}
|
|
1613
|
+
if (newEnd > maxPosition) {
|
|
1614
|
+
newEnd = maxPosition;
|
|
1615
|
+
newStart = maxPosition - regionWidth;
|
|
1616
|
+
}
|
|
1617
|
+
onLoopRegionMove?.(newStart, newEnd);
|
|
1618
|
+
};
|
|
1619
|
+
const handleMouseUp = () => {
|
|
1620
|
+
setDraggingMarker(null);
|
|
1621
|
+
document.removeEventListener("mousemove", handleMouseMove);
|
|
1622
|
+
document.removeEventListener("mouseup", handleMouseUp);
|
|
1623
|
+
};
|
|
1624
|
+
document.addEventListener("mousemove", handleMouseMove);
|
|
1625
|
+
document.addEventListener("mouseup", handleMouseUp);
|
|
1626
|
+
}, [startPosition, endPosition, minPosition, maxPosition, onLoopRegionMove]);
|
|
1627
|
+
if (width <= 0) {
|
|
1628
|
+
return null;
|
|
1629
|
+
}
|
|
1630
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
|
|
1631
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1632
|
+
TimescaleLoopShade,
|
|
1633
|
+
{
|
|
1634
|
+
$left: startPosition,
|
|
1635
|
+
$width: width,
|
|
1636
|
+
$color: regionColor,
|
|
1637
|
+
$isDragging: draggingMarker === "region",
|
|
1638
|
+
onMouseDown: handleRegionMouseDown,
|
|
1639
|
+
"data-loop-region-timescale": true
|
|
1640
|
+
}
|
|
1641
|
+
),
|
|
1642
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1643
|
+
DraggableMarkerHandle,
|
|
1644
|
+
{
|
|
1645
|
+
$left: startPosition,
|
|
1646
|
+
$color: markerColor,
|
|
1647
|
+
$isStart: true,
|
|
1648
|
+
$isDragging: draggingMarker === "start",
|
|
1649
|
+
onMouseDown: (e) => handleMarkerMouseDown(e, "start"),
|
|
1650
|
+
"data-loop-marker-handle": "start"
|
|
1651
|
+
}
|
|
1652
|
+
),
|
|
1653
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1654
|
+
DraggableMarkerHandle,
|
|
1655
|
+
{
|
|
1656
|
+
$left: endPosition,
|
|
1657
|
+
$color: markerColor,
|
|
1658
|
+
$isStart: false,
|
|
1659
|
+
$isDragging: draggingMarker === "end",
|
|
1660
|
+
onMouseDown: (e) => handleMarkerMouseDown(e, "end"),
|
|
1661
|
+
"data-loop-marker-handle": "end"
|
|
1662
|
+
}
|
|
1663
|
+
)
|
|
1664
|
+
] });
|
|
1665
|
+
};
|
|
1666
|
+
var TimescaleLoopCreator = import_styled_components18.default.div.attrs((props) => ({
|
|
1667
|
+
style: {
|
|
1668
|
+
left: `${props.$leftOffset || 0}px`
|
|
1669
|
+
}
|
|
1670
|
+
}))`
|
|
1671
|
+
position: absolute;
|
|
1672
|
+
top: 0;
|
|
1673
|
+
right: 0;
|
|
1674
|
+
height: 100%; /* Stay within timescale bounds, don't extend into tracks */
|
|
1675
|
+
cursor: crosshair;
|
|
1676
|
+
z-index: 40; /* Below markers and shading */
|
|
1677
|
+
`;
|
|
1678
|
+
var TimescaleLoopRegion = ({
|
|
1679
|
+
startPosition,
|
|
1680
|
+
endPosition,
|
|
1681
|
+
markerColor = "#3b82f6",
|
|
1682
|
+
regionColor = "rgba(59, 130, 246, 0.3)",
|
|
1683
|
+
onLoopRegionChange,
|
|
1684
|
+
minPosition = 0,
|
|
1685
|
+
maxPosition = Infinity,
|
|
1686
|
+
controlsOffset = 0
|
|
1687
|
+
}) => {
|
|
1688
|
+
const [isCreating, setIsCreating] = (0, import_react4.useState)(false);
|
|
1689
|
+
const createStartX = (0, import_react4.useRef)(0);
|
|
1690
|
+
const containerRef = (0, import_react4.useRef)(null);
|
|
1691
|
+
const hasLoopRegion = endPosition > startPosition;
|
|
1692
|
+
const handleBackgroundMouseDown = (0, import_react4.useCallback)((e) => {
|
|
1693
|
+
const target = e.target;
|
|
1694
|
+
if (target.closest("[data-loop-marker-handle]") || target.closest("[data-loop-region-timescale]")) {
|
|
1695
|
+
return;
|
|
1696
|
+
}
|
|
1697
|
+
e.preventDefault();
|
|
1698
|
+
setIsCreating(true);
|
|
1699
|
+
const rect = containerRef.current?.getBoundingClientRect();
|
|
1700
|
+
if (!rect) return;
|
|
1701
|
+
const clickX = e.clientX - rect.left;
|
|
1702
|
+
const clampedX = Math.max(minPosition, Math.min(maxPosition, clickX));
|
|
1703
|
+
createStartX.current = clampedX;
|
|
1704
|
+
onLoopRegionChange?.(clampedX, clampedX);
|
|
1705
|
+
const handleMouseMove = (moveEvent) => {
|
|
1706
|
+
const currentX = moveEvent.clientX - rect.left;
|
|
1707
|
+
const clampedCurrentX = Math.max(minPosition, Math.min(maxPosition, currentX));
|
|
1708
|
+
const newStart = Math.min(createStartX.current, clampedCurrentX);
|
|
1709
|
+
const newEnd = Math.max(createStartX.current, clampedCurrentX);
|
|
1710
|
+
onLoopRegionChange?.(newStart, newEnd);
|
|
1711
|
+
};
|
|
1712
|
+
const handleMouseUp = () => {
|
|
1713
|
+
setIsCreating(false);
|
|
1714
|
+
document.removeEventListener("mousemove", handleMouseMove);
|
|
1715
|
+
document.removeEventListener("mouseup", handleMouseUp);
|
|
1716
|
+
};
|
|
1717
|
+
document.addEventListener("mousemove", handleMouseMove);
|
|
1718
|
+
document.addEventListener("mouseup", handleMouseUp);
|
|
1719
|
+
}, [minPosition, maxPosition, onLoopRegionChange]);
|
|
1720
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1721
|
+
TimescaleLoopCreator,
|
|
1722
|
+
{
|
|
1723
|
+
ref: containerRef,
|
|
1724
|
+
$leftOffset: controlsOffset,
|
|
1725
|
+
onMouseDown: handleBackgroundMouseDown,
|
|
1726
|
+
"data-timescale-loop-creator": true,
|
|
1727
|
+
children: hasLoopRegion && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1728
|
+
LoopRegionMarkers,
|
|
1729
|
+
{
|
|
1730
|
+
startPosition,
|
|
1731
|
+
endPosition,
|
|
1732
|
+
markerColor,
|
|
1733
|
+
regionColor,
|
|
1734
|
+
minPosition,
|
|
1735
|
+
maxPosition,
|
|
1736
|
+
onLoopStartChange: (newStart) => onLoopRegionChange?.(newStart, endPosition),
|
|
1737
|
+
onLoopEndChange: (newEnd) => onLoopRegionChange?.(startPosition, newEnd),
|
|
1738
|
+
onLoopRegionMove: (newStart, newEnd) => onLoopRegionChange?.(newStart, newEnd)
|
|
1739
|
+
}
|
|
1740
|
+
)
|
|
1741
|
+
}
|
|
1742
|
+
);
|
|
1389
1743
|
};
|
|
1390
1744
|
|
|
1391
1745
|
// src/components/SelectionTimeInputs.tsx
|
|
1392
|
-
var
|
|
1746
|
+
var import_react6 = require("react");
|
|
1393
1747
|
|
|
1394
1748
|
// src/components/TimeInput.tsx
|
|
1395
|
-
var
|
|
1749
|
+
var import_react5 = require("react");
|
|
1396
1750
|
|
|
1397
1751
|
// src/utils/timeFormat.ts
|
|
1398
1752
|
function clockFormat(seconds, decimals) {
|
|
@@ -1442,7 +1796,7 @@ function parseTime(timeStr, format) {
|
|
|
1442
1796
|
}
|
|
1443
1797
|
|
|
1444
1798
|
// src/components/TimeInput.tsx
|
|
1445
|
-
var
|
|
1799
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
1446
1800
|
var TimeInput = ({
|
|
1447
1801
|
id,
|
|
1448
1802
|
label,
|
|
@@ -1452,8 +1806,8 @@ var TimeInput = ({
|
|
|
1452
1806
|
onChange,
|
|
1453
1807
|
readOnly = false
|
|
1454
1808
|
}) => {
|
|
1455
|
-
const [displayValue, setDisplayValue] = (0,
|
|
1456
|
-
(0,
|
|
1809
|
+
const [displayValue, setDisplayValue] = (0, import_react5.useState)("");
|
|
1810
|
+
(0, import_react5.useEffect)(() => {
|
|
1457
1811
|
const formatted = formatTime(value, format);
|
|
1458
1812
|
setDisplayValue(formatted);
|
|
1459
1813
|
}, [value, format, id]);
|
|
@@ -1473,9 +1827,9 @@ var TimeInput = ({
|
|
|
1473
1827
|
e.currentTarget.blur();
|
|
1474
1828
|
}
|
|
1475
1829
|
};
|
|
1476
|
-
return /* @__PURE__ */ (0,
|
|
1477
|
-
/* @__PURE__ */ (0,
|
|
1478
|
-
/* @__PURE__ */ (0,
|
|
1830
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
|
|
1831
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ScreenReaderOnly, { as: "label", htmlFor: id, children: label }),
|
|
1832
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1479
1833
|
BaseInput,
|
|
1480
1834
|
{
|
|
1481
1835
|
type: "text",
|
|
@@ -1492,15 +1846,15 @@ var TimeInput = ({
|
|
|
1492
1846
|
};
|
|
1493
1847
|
|
|
1494
1848
|
// src/components/SelectionTimeInputs.tsx
|
|
1495
|
-
var
|
|
1849
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
1496
1850
|
var SelectionTimeInputs = ({
|
|
1497
1851
|
selectionStart,
|
|
1498
1852
|
selectionEnd,
|
|
1499
1853
|
onSelectionChange,
|
|
1500
1854
|
className
|
|
1501
1855
|
}) => {
|
|
1502
|
-
const [timeFormat, setTimeFormat] = (0,
|
|
1503
|
-
(0,
|
|
1856
|
+
const [timeFormat, setTimeFormat] = (0, import_react6.useState)("hh:mm:ss.uuu");
|
|
1857
|
+
(0, import_react6.useEffect)(() => {
|
|
1504
1858
|
const timeFormatSelect = document.querySelector(".time-format");
|
|
1505
1859
|
const handleFormatChange = () => {
|
|
1506
1860
|
if (timeFormatSelect) {
|
|
@@ -1525,8 +1879,8 @@ var SelectionTimeInputs = ({
|
|
|
1525
1879
|
onSelectionChange(selectionStart, value);
|
|
1526
1880
|
}
|
|
1527
1881
|
};
|
|
1528
|
-
return /* @__PURE__ */ (0,
|
|
1529
|
-
/* @__PURE__ */ (0,
|
|
1882
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
|
|
1883
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1530
1884
|
TimeInput,
|
|
1531
1885
|
{
|
|
1532
1886
|
id: "audio_start",
|
|
@@ -1537,7 +1891,7 @@ var SelectionTimeInputs = ({
|
|
|
1537
1891
|
onChange: handleStartChange
|
|
1538
1892
|
}
|
|
1539
1893
|
),
|
|
1540
|
-
/* @__PURE__ */ (0,
|
|
1894
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1541
1895
|
TimeInput,
|
|
1542
1896
|
{
|
|
1543
1897
|
id: "audio_end",
|
|
@@ -1552,14 +1906,14 @@ var SelectionTimeInputs = ({
|
|
|
1552
1906
|
};
|
|
1553
1907
|
|
|
1554
1908
|
// src/contexts/DevicePixelRatio.tsx
|
|
1555
|
-
var
|
|
1556
|
-
var
|
|
1909
|
+
var import_react7 = require("react");
|
|
1910
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
1557
1911
|
function getScale() {
|
|
1558
1912
|
return window.devicePixelRatio;
|
|
1559
1913
|
}
|
|
1560
|
-
var DevicePixelRatioContext = (0,
|
|
1914
|
+
var DevicePixelRatioContext = (0, import_react7.createContext)(getScale());
|
|
1561
1915
|
var DevicePixelRatioProvider = ({ children }) => {
|
|
1562
|
-
const [scale, setScale] = (0,
|
|
1916
|
+
const [scale, setScale] = (0, import_react7.useState)(getScale());
|
|
1563
1917
|
matchMedia(`(resolution: ${getScale()}dppx)`).addEventListener(
|
|
1564
1918
|
"change",
|
|
1565
1919
|
() => {
|
|
@@ -1567,13 +1921,13 @@ var DevicePixelRatioProvider = ({ children }) => {
|
|
|
1567
1921
|
},
|
|
1568
1922
|
{ once: true }
|
|
1569
1923
|
);
|
|
1570
|
-
return /* @__PURE__ */ (0,
|
|
1924
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DevicePixelRatioContext.Provider, { value: Math.ceil(scale), children });
|
|
1571
1925
|
};
|
|
1572
|
-
var useDevicePixelRatio = () => (0,
|
|
1926
|
+
var useDevicePixelRatio = () => (0, import_react7.useContext)(DevicePixelRatioContext);
|
|
1573
1927
|
|
|
1574
1928
|
// src/contexts/PlaylistInfo.tsx
|
|
1575
|
-
var
|
|
1576
|
-
var PlaylistInfoContext = (0,
|
|
1929
|
+
var import_react8 = require("react");
|
|
1930
|
+
var PlaylistInfoContext = (0, import_react8.createContext)({
|
|
1577
1931
|
sampleRate: 48e3,
|
|
1578
1932
|
samplesPerPixel: 1e3,
|
|
1579
1933
|
zoomLevels: [1e3, 1500, 2e3, 2500],
|
|
@@ -1587,22 +1941,22 @@ var PlaylistInfoContext = (0, import_react7.createContext)({
|
|
|
1587
1941
|
barWidth: 1,
|
|
1588
1942
|
barGap: 0
|
|
1589
1943
|
});
|
|
1590
|
-
var usePlaylistInfo = () => (0,
|
|
1944
|
+
var usePlaylistInfo = () => (0, import_react8.useContext)(PlaylistInfoContext);
|
|
1591
1945
|
|
|
1592
1946
|
// src/contexts/Theme.tsx
|
|
1593
|
-
var import_react8 = require("react");
|
|
1594
|
-
var import_styled_components18 = require("styled-components");
|
|
1595
|
-
var useTheme2 = () => (0, import_react8.useContext)(import_styled_components18.ThemeContext);
|
|
1596
|
-
|
|
1597
|
-
// src/contexts/TrackControls.tsx
|
|
1598
1947
|
var import_react9 = require("react");
|
|
1599
|
-
var
|
|
1600
|
-
var
|
|
1601
|
-
var useTrackControls = () => (0, import_react9.useContext)(TrackControlsContext);
|
|
1948
|
+
var import_styled_components19 = require("styled-components");
|
|
1949
|
+
var useTheme2 = () => (0, import_react9.useContext)(import_styled_components19.ThemeContext);
|
|
1602
1950
|
|
|
1603
|
-
// src/contexts/
|
|
1951
|
+
// src/contexts/TrackControls.tsx
|
|
1604
1952
|
var import_react10 = require("react");
|
|
1605
1953
|
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
1954
|
+
var TrackControlsContext = (0, import_react10.createContext)(/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react10.Fragment, {}));
|
|
1955
|
+
var useTrackControls = () => (0, import_react10.useContext)(TrackControlsContext);
|
|
1956
|
+
|
|
1957
|
+
// src/contexts/Playout.tsx
|
|
1958
|
+
var import_react11 = require("react");
|
|
1959
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
1606
1960
|
var defaultProgress = 0;
|
|
1607
1961
|
var defaultIsPlaying = false;
|
|
1608
1962
|
var defaultSelectionStart = 0;
|
|
@@ -1613,8 +1967,8 @@ var defaultPlayout = {
|
|
|
1613
1967
|
selectionStart: defaultSelectionStart,
|
|
1614
1968
|
selectionEnd: defaultSelectionEnd
|
|
1615
1969
|
};
|
|
1616
|
-
var PlayoutStatusContext = (0,
|
|
1617
|
-
var PlayoutStatusUpdateContext = (0,
|
|
1970
|
+
var PlayoutStatusContext = (0, import_react11.createContext)(defaultPlayout);
|
|
1971
|
+
var PlayoutStatusUpdateContext = (0, import_react11.createContext)({
|
|
1618
1972
|
setIsPlaying: () => {
|
|
1619
1973
|
},
|
|
1620
1974
|
setProgress: () => {
|
|
@@ -1623,21 +1977,21 @@ var PlayoutStatusUpdateContext = (0, import_react10.createContext)({
|
|
|
1623
1977
|
}
|
|
1624
1978
|
});
|
|
1625
1979
|
var PlayoutProvider = ({ children }) => {
|
|
1626
|
-
const [isPlaying, setIsPlaying] = (0,
|
|
1627
|
-
const [progress, setProgress] = (0,
|
|
1628
|
-
const [selectionStart, setSelectionStart] = (0,
|
|
1629
|
-
const [selectionEnd, setSelectionEnd] = (0,
|
|
1980
|
+
const [isPlaying, setIsPlaying] = (0, import_react11.useState)(defaultIsPlaying);
|
|
1981
|
+
const [progress, setProgress] = (0, import_react11.useState)(defaultProgress);
|
|
1982
|
+
const [selectionStart, setSelectionStart] = (0, import_react11.useState)(defaultSelectionStart);
|
|
1983
|
+
const [selectionEnd, setSelectionEnd] = (0, import_react11.useState)(defaultSelectionEnd);
|
|
1630
1984
|
const setSelection = (start, end) => {
|
|
1631
1985
|
setSelectionStart(start);
|
|
1632
1986
|
setSelectionEnd(end);
|
|
1633
1987
|
};
|
|
1634
|
-
return /* @__PURE__ */ (0,
|
|
1988
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(PlayoutStatusUpdateContext.Provider, { value: { setIsPlaying, setProgress, setSelection }, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(PlayoutStatusContext.Provider, { value: { isPlaying, progress, selectionStart, selectionEnd }, children }) });
|
|
1635
1989
|
};
|
|
1636
|
-
var usePlayoutStatus = () => (0,
|
|
1637
|
-
var usePlayoutStatusUpdate = () => (0,
|
|
1990
|
+
var usePlayoutStatus = () => (0, import_react11.useContext)(PlayoutStatusContext);
|
|
1991
|
+
var usePlayoutStatusUpdate = () => (0, import_react11.useContext)(PlayoutStatusUpdateContext);
|
|
1638
1992
|
|
|
1639
1993
|
// src/components/SmartChannel.tsx
|
|
1640
|
-
var
|
|
1994
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
1641
1995
|
var SmartChannel = ({ isSelected, transparentBackground, ...props }) => {
|
|
1642
1996
|
const theme = useTheme2();
|
|
1643
1997
|
const { waveHeight, barWidth, barGap } = usePlaylistInfo();
|
|
@@ -1645,7 +1999,7 @@ var SmartChannel = ({ isSelected, transparentBackground, ...props }) => {
|
|
|
1645
1999
|
const waveOutlineColor = isSelected && theme ? theme.selectedWaveOutlineColor : theme?.waveOutlineColor;
|
|
1646
2000
|
const waveFillColor = isSelected && theme ? theme.selectedWaveFillColor : theme?.waveFillColor;
|
|
1647
2001
|
const drawMode = theme?.waveformDrawMode || "inverted";
|
|
1648
|
-
return /* @__PURE__ */ (0,
|
|
2002
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
1649
2003
|
Channel,
|
|
1650
2004
|
{
|
|
1651
2005
|
...props,
|
|
@@ -1663,11 +2017,11 @@ var SmartChannel = ({ isSelected, transparentBackground, ...props }) => {
|
|
|
1663
2017
|
};
|
|
1664
2018
|
|
|
1665
2019
|
// src/components/SmartScale.tsx
|
|
1666
|
-
var
|
|
2020
|
+
var import_react13 = require("react");
|
|
1667
2021
|
|
|
1668
2022
|
// src/components/TimeScale.tsx
|
|
1669
|
-
var
|
|
1670
|
-
var
|
|
2023
|
+
var import_react12 = __toESM(require("react"));
|
|
2024
|
+
var import_styled_components20 = __toESM(require("styled-components"));
|
|
1671
2025
|
|
|
1672
2026
|
// src/utils/conversions.ts
|
|
1673
2027
|
function samplesToSeconds(samples, sampleRate) {
|
|
@@ -1690,14 +2044,14 @@ function secondsToPixels(seconds, samplesPerPixel, sampleRate) {
|
|
|
1690
2044
|
}
|
|
1691
2045
|
|
|
1692
2046
|
// src/components/TimeScale.tsx
|
|
1693
|
-
var
|
|
2047
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
1694
2048
|
function formatTime2(milliseconds) {
|
|
1695
2049
|
const seconds = Math.floor(milliseconds / 1e3);
|
|
1696
2050
|
const s = seconds % 60;
|
|
1697
2051
|
const m = (seconds - s) / 60;
|
|
1698
2052
|
return `${m}:${String(s).padStart(2, "0")}`;
|
|
1699
2053
|
}
|
|
1700
|
-
var PlaylistTimeScaleScroll =
|
|
2054
|
+
var PlaylistTimeScaleScroll = import_styled_components20.default.div.attrs((props) => ({
|
|
1701
2055
|
style: {
|
|
1702
2056
|
width: `${props.$cssWidth}px`,
|
|
1703
2057
|
marginLeft: `${props.$controlWidth}px`,
|
|
@@ -1709,7 +2063,7 @@ var PlaylistTimeScaleScroll = import_styled_components19.default.div.attrs((prop
|
|
|
1709
2063
|
border-bottom: 1px solid ${(props) => props.theme.timeColor};
|
|
1710
2064
|
box-sizing: border-box;
|
|
1711
2065
|
`;
|
|
1712
|
-
var TimeTicks =
|
|
2066
|
+
var TimeTicks = import_styled_components20.default.canvas.attrs((props) => ({
|
|
1713
2067
|
style: {
|
|
1714
2068
|
width: `${props.$cssWidth}px`,
|
|
1715
2069
|
height: `${props.$timeScaleHeight}px`
|
|
@@ -1720,7 +2074,7 @@ var TimeTicks = import_styled_components19.default.canvas.attrs((props) => ({
|
|
|
1720
2074
|
right: 0;
|
|
1721
2075
|
bottom: 0;
|
|
1722
2076
|
`;
|
|
1723
|
-
var TimeStamp =
|
|
2077
|
+
var TimeStamp = import_styled_components20.default.div.attrs((props) => ({
|
|
1724
2078
|
style: {
|
|
1725
2079
|
left: `${props.$left + 4}px`
|
|
1726
2080
|
// Offset 4px to the right of the tick
|
|
@@ -1742,15 +2096,15 @@ var TimeScale = (props) => {
|
|
|
1742
2096
|
} = props;
|
|
1743
2097
|
const canvasInfo = /* @__PURE__ */ new Map();
|
|
1744
2098
|
const timeMarkers = [];
|
|
1745
|
-
const canvasRef = (0,
|
|
2099
|
+
const canvasRef = (0, import_react12.useRef)(null);
|
|
1746
2100
|
const {
|
|
1747
2101
|
sampleRate,
|
|
1748
2102
|
samplesPerPixel,
|
|
1749
2103
|
timeScaleHeight,
|
|
1750
2104
|
controls: { show: showControls, width: controlWidth }
|
|
1751
|
-
} = (0,
|
|
2105
|
+
} = (0, import_react12.useContext)(PlaylistInfoContext);
|
|
1752
2106
|
const devicePixelRatio = useDevicePixelRatio();
|
|
1753
|
-
(0,
|
|
2107
|
+
(0, import_react12.useEffect)(() => {
|
|
1754
2108
|
if (canvasRef.current !== null) {
|
|
1755
2109
|
const canvas = canvasRef.current;
|
|
1756
2110
|
const ctx = canvas.getContext("2d");
|
|
@@ -1784,7 +2138,7 @@ var TimeScale = (props) => {
|
|
|
1784
2138
|
if (counter % marker === 0) {
|
|
1785
2139
|
const timeMs = counter;
|
|
1786
2140
|
const timestamp = formatTime2(timeMs);
|
|
1787
|
-
const timestampContent = renderTimestamp ? /* @__PURE__ */ (0,
|
|
2141
|
+
const timestampContent = renderTimestamp ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react12.default.Fragment, { children: renderTimestamp(timeMs, pix) }, `timestamp-${counter}`) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(TimeStamp, { $left: pix, children: timestamp }, timestamp);
|
|
1788
2142
|
timeMarkers.push(timestampContent);
|
|
1789
2143
|
canvasInfo.set(pix, timeScaleHeight);
|
|
1790
2144
|
} else if (counter % bigStep === 0) {
|
|
@@ -1794,7 +2148,7 @@ var TimeScale = (props) => {
|
|
|
1794
2148
|
}
|
|
1795
2149
|
counter += secondStep;
|
|
1796
2150
|
}
|
|
1797
|
-
return /* @__PURE__ */ (0,
|
|
2151
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
1798
2152
|
PlaylistTimeScaleScroll,
|
|
1799
2153
|
{
|
|
1800
2154
|
$cssWidth: widthX,
|
|
@@ -1802,7 +2156,7 @@ var TimeScale = (props) => {
|
|
|
1802
2156
|
$timeScaleHeight: timeScaleHeight,
|
|
1803
2157
|
children: [
|
|
1804
2158
|
timeMarkers,
|
|
1805
|
-
/* @__PURE__ */ (0,
|
|
2159
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1806
2160
|
TimeTicks,
|
|
1807
2161
|
{
|
|
1808
2162
|
$cssWidth: widthX,
|
|
@@ -1816,10 +2170,10 @@ var TimeScale = (props) => {
|
|
|
1816
2170
|
}
|
|
1817
2171
|
);
|
|
1818
2172
|
};
|
|
1819
|
-
var StyledTimeScale = (0,
|
|
2173
|
+
var StyledTimeScale = (0, import_styled_components20.withTheme)(TimeScale);
|
|
1820
2174
|
|
|
1821
2175
|
// src/components/SmartScale.tsx
|
|
1822
|
-
var
|
|
2176
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
1823
2177
|
var timeinfo = /* @__PURE__ */ new Map([
|
|
1824
2178
|
[
|
|
1825
2179
|
700,
|
|
@@ -1893,9 +2247,9 @@ function getScaleInfo(samplesPerPixel) {
|
|
|
1893
2247
|
return config;
|
|
1894
2248
|
}
|
|
1895
2249
|
var SmartScale = () => {
|
|
1896
|
-
const { samplesPerPixel, duration } = (0,
|
|
2250
|
+
const { samplesPerPixel, duration } = (0, import_react13.useContext)(PlaylistInfoContext);
|
|
1897
2251
|
let config = getScaleInfo(samplesPerPixel);
|
|
1898
|
-
return /* @__PURE__ */ (0,
|
|
2252
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1899
2253
|
StyledTimeScale,
|
|
1900
2254
|
{
|
|
1901
2255
|
marker: config.marker,
|
|
@@ -1907,9 +2261,9 @@ var SmartScale = () => {
|
|
|
1907
2261
|
};
|
|
1908
2262
|
|
|
1909
2263
|
// src/components/TimeFormatSelect.tsx
|
|
1910
|
-
var
|
|
1911
|
-
var
|
|
1912
|
-
var SelectWrapper =
|
|
2264
|
+
var import_styled_components21 = __toESM(require("styled-components"));
|
|
2265
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
2266
|
+
var SelectWrapper = import_styled_components21.default.div`
|
|
1913
2267
|
display: inline-flex;
|
|
1914
2268
|
align-items: center;
|
|
1915
2269
|
gap: 0.5rem;
|
|
@@ -1931,7 +2285,7 @@ var TimeFormatSelect = ({
|
|
|
1931
2285
|
const handleChange = (e) => {
|
|
1932
2286
|
onChange(e.target.value);
|
|
1933
2287
|
};
|
|
1934
|
-
return /* @__PURE__ */ (0,
|
|
2288
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(SelectWrapper, { className, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
1935
2289
|
BaseSelect,
|
|
1936
2290
|
{
|
|
1937
2291
|
className: "time-format",
|
|
@@ -1939,15 +2293,15 @@ var TimeFormatSelect = ({
|
|
|
1939
2293
|
onChange: handleChange,
|
|
1940
2294
|
disabled,
|
|
1941
2295
|
"aria-label": "Time format selection",
|
|
1942
|
-
children: TIME_FORMAT_OPTIONS.map((option) => /* @__PURE__ */ (0,
|
|
2296
|
+
children: TIME_FORMAT_OPTIONS.map((option) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("option", { value: option.value, children: option.label }, option.value))
|
|
1943
2297
|
}
|
|
1944
2298
|
) });
|
|
1945
2299
|
};
|
|
1946
2300
|
|
|
1947
2301
|
// src/components/Track.tsx
|
|
1948
|
-
var
|
|
1949
|
-
var
|
|
1950
|
-
var Container =
|
|
2302
|
+
var import_styled_components22 = __toESM(require("styled-components"));
|
|
2303
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
2304
|
+
var Container = import_styled_components22.default.div.attrs((props) => ({
|
|
1951
2305
|
style: {
|
|
1952
2306
|
height: `${props.$waveHeight * props.$numChannels + (props.$hasClipHeaders ? CLIP_HEADER_HEIGHT : 0)}px`
|
|
1953
2307
|
}
|
|
@@ -1956,7 +2310,7 @@ var Container = import_styled_components21.default.div.attrs((props) => ({
|
|
|
1956
2310
|
display: flex;
|
|
1957
2311
|
${(props) => props.$width !== void 0 && `width: ${props.$width}px;`}
|
|
1958
2312
|
`;
|
|
1959
|
-
var ChannelContainer =
|
|
2313
|
+
var ChannelContainer = import_styled_components22.default.div.attrs((props) => ({
|
|
1960
2314
|
style: {
|
|
1961
2315
|
paddingLeft: `${props.$offset || 0}px`
|
|
1962
2316
|
}
|
|
@@ -1965,7 +2319,7 @@ var ChannelContainer = import_styled_components21.default.div.attrs((props) => (
|
|
|
1965
2319
|
background: ${(props) => props.$backgroundColor || "transparent"};
|
|
1966
2320
|
flex: 1;
|
|
1967
2321
|
`;
|
|
1968
|
-
var ControlsWrapper =
|
|
2322
|
+
var ControlsWrapper = import_styled_components22.default.div.attrs((props) => ({
|
|
1969
2323
|
style: {
|
|
1970
2324
|
width: `${props.$controlWidth}px`
|
|
1971
2325
|
}
|
|
@@ -2001,7 +2355,7 @@ var Track = ({
|
|
|
2001
2355
|
controls: { show, width: controlWidth }
|
|
2002
2356
|
} = usePlaylistInfo();
|
|
2003
2357
|
const controls = useTrackControls();
|
|
2004
|
-
return /* @__PURE__ */ (0,
|
|
2358
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
2005
2359
|
Container,
|
|
2006
2360
|
{
|
|
2007
2361
|
$numChannels: numChannels,
|
|
@@ -2012,7 +2366,7 @@ var Track = ({
|
|
|
2012
2366
|
$hasClipHeaders: hasClipHeaders,
|
|
2013
2367
|
$isSelected: isSelected,
|
|
2014
2368
|
children: [
|
|
2015
|
-
/* @__PURE__ */ (0,
|
|
2369
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
2016
2370
|
ControlsWrapper,
|
|
2017
2371
|
{
|
|
2018
2372
|
$controlWidth: show ? controlWidth : 0,
|
|
@@ -2020,7 +2374,7 @@ var Track = ({
|
|
|
2020
2374
|
children: controls
|
|
2021
2375
|
}
|
|
2022
2376
|
),
|
|
2023
|
-
/* @__PURE__ */ (0,
|
|
2377
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
2024
2378
|
ChannelContainer,
|
|
2025
2379
|
{
|
|
2026
2380
|
$controlWidth: show ? controlWidth : 0,
|
|
@@ -2037,8 +2391,8 @@ var Track = ({
|
|
|
2037
2391
|
};
|
|
2038
2392
|
|
|
2039
2393
|
// src/components/TrackControls/Button.tsx
|
|
2040
|
-
var
|
|
2041
|
-
var Button =
|
|
2394
|
+
var import_styled_components23 = __toESM(require("styled-components"));
|
|
2395
|
+
var Button = import_styled_components23.default.button.attrs({
|
|
2042
2396
|
type: "button"
|
|
2043
2397
|
})`
|
|
2044
2398
|
display: inline-block;
|
|
@@ -2110,8 +2464,8 @@ var Button = import_styled_components22.default.button.attrs({
|
|
|
2110
2464
|
`;
|
|
2111
2465
|
|
|
2112
2466
|
// src/components/TrackControls/ButtonGroup.tsx
|
|
2113
|
-
var
|
|
2114
|
-
var ButtonGroup =
|
|
2467
|
+
var import_styled_components24 = __toESM(require("styled-components"));
|
|
2468
|
+
var ButtonGroup = import_styled_components24.default.div`
|
|
2115
2469
|
margin-bottom: 0.3rem;
|
|
2116
2470
|
|
|
2117
2471
|
button:not(:first-child) {
|
|
@@ -2126,8 +2480,8 @@ var ButtonGroup = import_styled_components23.default.div`
|
|
|
2126
2480
|
`;
|
|
2127
2481
|
|
|
2128
2482
|
// src/components/TrackControls/Controls.tsx
|
|
2129
|
-
var
|
|
2130
|
-
var Controls =
|
|
2483
|
+
var import_styled_components25 = __toESM(require("styled-components"));
|
|
2484
|
+
var Controls = import_styled_components25.default.div`
|
|
2131
2485
|
background: transparent;
|
|
2132
2486
|
width: 100%;
|
|
2133
2487
|
height: 100%;
|
|
@@ -2143,8 +2497,8 @@ var Controls = import_styled_components24.default.div`
|
|
|
2143
2497
|
`;
|
|
2144
2498
|
|
|
2145
2499
|
// src/components/TrackControls/Header.tsx
|
|
2146
|
-
var
|
|
2147
|
-
var Header =
|
|
2500
|
+
var import_styled_components26 = __toESM(require("styled-components"));
|
|
2501
|
+
var Header = import_styled_components26.default.header`
|
|
2148
2502
|
overflow: hidden;
|
|
2149
2503
|
height: 26px;
|
|
2150
2504
|
width: 100%;
|
|
@@ -2158,23 +2512,23 @@ var Header = import_styled_components25.default.header`
|
|
|
2158
2512
|
`;
|
|
2159
2513
|
|
|
2160
2514
|
// src/components/TrackControls/VolumeDownIcon.tsx
|
|
2161
|
-
var import_react13 = require("@phosphor-icons/react");
|
|
2162
|
-
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
2163
|
-
var VolumeDownIcon = (props) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react13.SpeakerLowIcon, { weight: "light", ...props });
|
|
2164
|
-
|
|
2165
|
-
// src/components/TrackControls/VolumeUpIcon.tsx
|
|
2166
2515
|
var import_react14 = require("@phosphor-icons/react");
|
|
2167
2516
|
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
2168
|
-
var
|
|
2517
|
+
var VolumeDownIcon = (props) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react14.SpeakerLowIcon, { weight: "light", ...props });
|
|
2169
2518
|
|
|
2170
|
-
// src/components/TrackControls/
|
|
2519
|
+
// src/components/TrackControls/VolumeUpIcon.tsx
|
|
2171
2520
|
var import_react15 = require("@phosphor-icons/react");
|
|
2172
2521
|
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
2173
|
-
var
|
|
2522
|
+
var VolumeUpIcon = (props) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react15.SpeakerHighIcon, { weight: "light", ...props });
|
|
2523
|
+
|
|
2524
|
+
// src/components/TrackControls/TrashIcon.tsx
|
|
2525
|
+
var import_react16 = require("@phosphor-icons/react");
|
|
2526
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
2527
|
+
var TrashIcon = (props) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react16.TrashIcon, { weight: "light", ...props });
|
|
2174
2528
|
|
|
2175
2529
|
// src/components/TrackControls/Slider.tsx
|
|
2176
|
-
var
|
|
2177
|
-
var Slider = (0,
|
|
2530
|
+
var import_styled_components27 = __toESM(require("styled-components"));
|
|
2531
|
+
var Slider = (0, import_styled_components27.default)(BaseSlider)`
|
|
2178
2532
|
width: 75%;
|
|
2179
2533
|
height: 5px;
|
|
2180
2534
|
background: ${(props) => props.theme.sliderTrackColor};
|
|
@@ -2226,8 +2580,8 @@ var Slider = (0, import_styled_components26.default)(BaseSlider)`
|
|
|
2226
2580
|
`;
|
|
2227
2581
|
|
|
2228
2582
|
// src/components/TrackControls/SliderWrapper.tsx
|
|
2229
|
-
var
|
|
2230
|
-
var SliderWrapper =
|
|
2583
|
+
var import_styled_components28 = __toESM(require("styled-components"));
|
|
2584
|
+
var SliderWrapper = import_styled_components28.default.label`
|
|
2231
2585
|
width: 100%;
|
|
2232
2586
|
display: flex;
|
|
2233
2587
|
justify-content: space-between;
|
|
@@ -2238,15 +2592,15 @@ var SliderWrapper = import_styled_components27.default.label`
|
|
|
2238
2592
|
`;
|
|
2239
2593
|
|
|
2240
2594
|
// src/components/TrackControlsWithDelete.tsx
|
|
2241
|
-
var
|
|
2242
|
-
var
|
|
2243
|
-
var HeaderContainer2 =
|
|
2595
|
+
var import_styled_components29 = __toESM(require("styled-components"));
|
|
2596
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
2597
|
+
var HeaderContainer2 = import_styled_components29.default.div`
|
|
2244
2598
|
display: flex;
|
|
2245
2599
|
align-items: center;
|
|
2246
2600
|
gap: 0.25rem;
|
|
2247
2601
|
padding: 0.5rem 0.5rem 0.25rem 0.5rem;
|
|
2248
2602
|
`;
|
|
2249
|
-
var TrackNameSpan =
|
|
2603
|
+
var TrackNameSpan = import_styled_components29.default.span`
|
|
2250
2604
|
flex: 1;
|
|
2251
2605
|
font-weight: 600;
|
|
2252
2606
|
font-size: 0.875rem;
|
|
@@ -2255,7 +2609,7 @@ var TrackNameSpan = import_styled_components28.default.span`
|
|
|
2255
2609
|
white-space: nowrap;
|
|
2256
2610
|
margin: 0 0.25rem;
|
|
2257
2611
|
`;
|
|
2258
|
-
var DeleteIconButton =
|
|
2612
|
+
var DeleteIconButton = import_styled_components29.default.button`
|
|
2259
2613
|
display: flex;
|
|
2260
2614
|
align-items: center;
|
|
2261
2615
|
justify-content: center;
|
|
@@ -2293,13 +2647,13 @@ var TrackControlsWithDelete = ({
|
|
|
2293
2647
|
onPanChange,
|
|
2294
2648
|
onDelete
|
|
2295
2649
|
}) => {
|
|
2296
|
-
return /* @__PURE__ */ (0,
|
|
2297
|
-
/* @__PURE__ */ (0,
|
|
2298
|
-
/* @__PURE__ */ (0,
|
|
2299
|
-
/* @__PURE__ */ (0,
|
|
2650
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(Controls, { children: [
|
|
2651
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(HeaderContainer2, { children: [
|
|
2652
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(DeleteIconButton, { onClick: onDelete, title: "Delete track", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(TrashIcon, {}) }),
|
|
2653
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(TrackNameSpan, { children: trackName })
|
|
2300
2654
|
] }),
|
|
2301
|
-
/* @__PURE__ */ (0,
|
|
2302
|
-
/* @__PURE__ */ (0,
|
|
2655
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(ButtonGroup, { children: [
|
|
2656
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
2303
2657
|
Button,
|
|
2304
2658
|
{
|
|
2305
2659
|
$variant: muted ? "danger" : "outline",
|
|
@@ -2307,7 +2661,7 @@ var TrackControlsWithDelete = ({
|
|
|
2307
2661
|
children: "Mute"
|
|
2308
2662
|
}
|
|
2309
2663
|
),
|
|
2310
|
-
/* @__PURE__ */ (0,
|
|
2664
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
2311
2665
|
Button,
|
|
2312
2666
|
{
|
|
2313
2667
|
$variant: soloed ? "info" : "outline",
|
|
@@ -2316,9 +2670,9 @@ var TrackControlsWithDelete = ({
|
|
|
2316
2670
|
}
|
|
2317
2671
|
)
|
|
2318
2672
|
] }),
|
|
2319
|
-
/* @__PURE__ */ (0,
|
|
2320
|
-
/* @__PURE__ */ (0,
|
|
2321
|
-
/* @__PURE__ */ (0,
|
|
2673
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(SliderWrapper, { children: [
|
|
2674
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(VolumeDownIcon, {}),
|
|
2675
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
2322
2676
|
Slider,
|
|
2323
2677
|
{
|
|
2324
2678
|
min: "0",
|
|
@@ -2328,11 +2682,11 @@ var TrackControlsWithDelete = ({
|
|
|
2328
2682
|
onChange: (e) => onVolumeChange(parseFloat(e.target.value))
|
|
2329
2683
|
}
|
|
2330
2684
|
),
|
|
2331
|
-
/* @__PURE__ */ (0,
|
|
2685
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(VolumeUpIcon, {})
|
|
2332
2686
|
] }),
|
|
2333
|
-
/* @__PURE__ */ (0,
|
|
2334
|
-
/* @__PURE__ */ (0,
|
|
2335
|
-
/* @__PURE__ */ (0,
|
|
2687
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(SliderWrapper, { children: [
|
|
2688
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { children: "L" }),
|
|
2689
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
2336
2690
|
Slider,
|
|
2337
2691
|
{
|
|
2338
2692
|
min: "-1",
|
|
@@ -2342,7 +2696,7 @@ var TrackControlsWithDelete = ({
|
|
|
2342
2696
|
onChange: (e) => onPanChange(parseFloat(e.target.value))
|
|
2343
2697
|
}
|
|
2344
2698
|
),
|
|
2345
|
-
/* @__PURE__ */ (0,
|
|
2699
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { children: "R" })
|
|
2346
2700
|
] })
|
|
2347
2701
|
] });
|
|
2348
2702
|
};
|
|
@@ -2362,6 +2716,7 @@ var TrackControlsWithDelete = ({
|
|
|
2362
2716
|
Button,
|
|
2363
2717
|
ButtonGroup,
|
|
2364
2718
|
CLIP_BOUNDARY_WIDTH,
|
|
2719
|
+
CLIP_BOUNDARY_WIDTH_TOUCH,
|
|
2365
2720
|
CLIP_HEADER_HEIGHT,
|
|
2366
2721
|
Channel,
|
|
2367
2722
|
Clip,
|
|
@@ -2373,6 +2728,8 @@ var TrackControlsWithDelete = ({
|
|
|
2373
2728
|
FadeOverlay,
|
|
2374
2729
|
Header,
|
|
2375
2730
|
InlineLabel,
|
|
2731
|
+
LoopRegion,
|
|
2732
|
+
LoopRegionMarkers,
|
|
2376
2733
|
MasterVolumeControl,
|
|
2377
2734
|
Playhead,
|
|
2378
2735
|
PlayheadWithMarker,
|
|
@@ -2391,6 +2748,7 @@ var TrackControlsWithDelete = ({
|
|
|
2391
2748
|
TimeFormatSelect,
|
|
2392
2749
|
TimeInput,
|
|
2393
2750
|
TimeScale,
|
|
2751
|
+
TimescaleLoopRegion,
|
|
2394
2752
|
Track,
|
|
2395
2753
|
TrackControlsContext,
|
|
2396
2754
|
TrackControlsWithDelete,
|