@signalsandsorcery/plugin-sdk 2.36.1 → 2.38.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.d.mts +139 -4
- package/dist/index.d.ts +139 -4
- package/dist/index.js +880 -710
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +783 -615
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -69,7 +69,7 @@ import React9 from "react";
|
|
|
69
69
|
import { AlertCircle, ChevronDown, GripVertical } from "lucide-react";
|
|
70
70
|
|
|
71
71
|
// src/components/TrackDrawer.tsx
|
|
72
|
-
import { useState as
|
|
72
|
+
import { useState as useState5, useMemo as useMemo3 } from "react";
|
|
73
73
|
|
|
74
74
|
// src/constants/fx-presets.ts
|
|
75
75
|
var EQ_PRESETS = {
|
|
@@ -1051,14 +1051,132 @@ function TrackExternalFxSection({
|
|
|
1051
1051
|
);
|
|
1052
1052
|
}
|
|
1053
1053
|
|
|
1054
|
-
// src/components/
|
|
1054
|
+
// src/components/TrackFreezeSection.tsx
|
|
1055
1055
|
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1056
|
+
var STALE_LABELS = {
|
|
1057
|
+
midi: "MIDI changed",
|
|
1058
|
+
preset: "preset changed",
|
|
1059
|
+
instrument: "instrument changed",
|
|
1060
|
+
"external-fx": "FX changed",
|
|
1061
|
+
role: "role changed"
|
|
1062
|
+
};
|
|
1063
|
+
function TrackFreezeSection({
|
|
1064
|
+
state,
|
|
1065
|
+
busy,
|
|
1066
|
+
error,
|
|
1067
|
+
onFreeze,
|
|
1068
|
+
onUnfreeze
|
|
1069
|
+
}) {
|
|
1070
|
+
const frozen = state?.frozen === true;
|
|
1071
|
+
const stale = frozen && state?.stale === true;
|
|
1072
|
+
const missing = state?.missingDeps ?? [];
|
|
1073
|
+
const unfreezeBlocked = frozen && missing.length > 0;
|
|
1074
|
+
const statusLine = !state ? "Reading freeze state\u2026" : !frozen ? state.latentFreshFreeze ? "Live \u2014 a fresh stem is cached, freezing is instant." : "Live \u2014 playing through the instrument and FX chain." : stale ? `\u26A0\uFE0F\u2744 Frozen (stale) \u2014 ${state.staleReasons.map((r) => STALE_LABELS[r] ?? r).join(", ")} since the stem rendered. Playback keeps the old stem until you re-freeze.` : "\u2744 Frozen \u2014 playing the rendered stem. Mixer (volume \xB7 pan \xB7 mute \xB7 solo) stays live.";
|
|
1075
|
+
const primaryLabel = busy === "freeze" ? "Rendering stem\u2026" : busy === "unfreeze" ? "Restoring chain\u2026" : !frozen ? "\u2744 Freeze track" : stale ? "\u2744 Re-freeze (render new stem)" : "Unfreeze track";
|
|
1076
|
+
const primaryAction = !frozen || stale ? onFreeze : onUnfreeze;
|
|
1077
|
+
const primaryDisabled = busy !== null || !state || frozen && !stale && unfreezeBlocked;
|
|
1078
|
+
return /* @__PURE__ */ jsxs4("div", { className: "flex flex-col gap-2", "data-testid": "sdk-freeze-section", children: [
|
|
1079
|
+
/* @__PURE__ */ jsx4("p", { className: "text-[11px] text-sas-muted/80 leading-snug", "data-testid": "sdk-freeze-status", children: statusLine }),
|
|
1080
|
+
frozen && missing.length > 0 && /* @__PURE__ */ jsxs4(
|
|
1081
|
+
"div",
|
|
1082
|
+
{
|
|
1083
|
+
className: "text-[11px] leading-snug rounded-sm border border-sas-border bg-sas-panel-alt px-2 py-1.5 text-sas-muted",
|
|
1084
|
+
"data-testid": "sdk-freeze-missing-deps",
|
|
1085
|
+
children: [
|
|
1086
|
+
"Missing on this machine:",
|
|
1087
|
+
" ",
|
|
1088
|
+
/* @__PURE__ */ jsx4("span", { className: "text-sas-accent", children: missing.map((d) => d.name).join(", ") }),
|
|
1089
|
+
". ",
|
|
1090
|
+
"Install (or rescan plugins if blacklisted) to unfreeze \u2014 the frozen sound keeps playing meanwhile."
|
|
1091
|
+
]
|
|
1092
|
+
}
|
|
1093
|
+
),
|
|
1094
|
+
/* @__PURE__ */ jsx4(
|
|
1095
|
+
"button",
|
|
1096
|
+
{
|
|
1097
|
+
type: "button",
|
|
1098
|
+
"data-testid": "sdk-freeze-primary",
|
|
1099
|
+
disabled: primaryDisabled,
|
|
1100
|
+
onClick: primaryAction,
|
|
1101
|
+
className: `w-full py-2 text-xs font-medium rounded-sm border transition-colors ${primaryDisabled ? "border-sas-border text-sas-muted/40 cursor-not-allowed" : "border-sas-accent bg-sas-accent/20 text-sas-accent hover:bg-sas-accent/40"}`,
|
|
1102
|
+
title: !frozen ? "Render this track to audio and disable its plugins (mix controls stay live)" : stale ? "Sound inputs changed \u2014 render a fresh stem" : unfreezeBlocked ? "Unfreeze needs the missing plugins installed" : "Remove the stem and re-enable the instrument + FX chain",
|
|
1103
|
+
children: primaryLabel
|
|
1104
|
+
}
|
|
1105
|
+
),
|
|
1106
|
+
frozen && stale && !unfreezeBlocked && /* @__PURE__ */ jsx4(
|
|
1107
|
+
"button",
|
|
1108
|
+
{
|
|
1109
|
+
type: "button",
|
|
1110
|
+
"data-testid": "sdk-freeze-unfreeze-secondary",
|
|
1111
|
+
disabled: busy !== null,
|
|
1112
|
+
onClick: onUnfreeze,
|
|
1113
|
+
className: "w-full py-1.5 text-[11px] rounded-sm border border-sas-border text-sas-muted hover:border-sas-accent hover:text-sas-accent transition-colors",
|
|
1114
|
+
children: "Unfreeze instead (back to live editing)"
|
|
1115
|
+
}
|
|
1116
|
+
),
|
|
1117
|
+
error && /* @__PURE__ */ jsx4("p", { className: "text-[11px] text-red-400 leading-snug", "data-testid": "sdk-freeze-error", children: error }),
|
|
1118
|
+
/* @__PURE__ */ jsx4("p", { className: "text-[10px] text-sas-muted/50 leading-snug", children: "Frozen tracks survive missing plugins and travel inside project backups. The stem is kept after unfreezing, so re-freezing an unchanged track is instant." })
|
|
1119
|
+
] });
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
// src/hooks/useTrackFreeze.ts
|
|
1123
|
+
import { useState as useState4, useEffect as useEffect2, useCallback as useCallback3 } from "react";
|
|
1124
|
+
function useTrackFreeze(host, trackId) {
|
|
1125
|
+
const enabled = !!host && typeof host.getTrackFreezeState === "function";
|
|
1126
|
+
const [state, setState] = useState4(null);
|
|
1127
|
+
const [busy, setBusy] = useState4(null);
|
|
1128
|
+
const [error, setError] = useState4(null);
|
|
1129
|
+
const refresh = useCallback3(async () => {
|
|
1130
|
+
if (!enabled || !host?.getTrackFreezeState) return;
|
|
1131
|
+
try {
|
|
1132
|
+
setState(await host.getTrackFreezeState(trackId));
|
|
1133
|
+
} catch {
|
|
1134
|
+
setState(null);
|
|
1135
|
+
}
|
|
1136
|
+
}, [enabled, host, trackId]);
|
|
1137
|
+
useEffect2(() => {
|
|
1138
|
+
void refresh();
|
|
1139
|
+
}, [refresh]);
|
|
1140
|
+
useEffect2(() => {
|
|
1141
|
+
if (!enabled) return void 0;
|
|
1142
|
+
const onFreezeChanged = () => {
|
|
1143
|
+
void refresh();
|
|
1144
|
+
};
|
|
1145
|
+
window.addEventListener("sas:freeze-changed", onFreezeChanged);
|
|
1146
|
+
return () => window.removeEventListener("sas:freeze-changed", onFreezeChanged);
|
|
1147
|
+
}, [enabled, refresh]);
|
|
1148
|
+
const run = useCallback3(
|
|
1149
|
+
async (action) => {
|
|
1150
|
+
if (!host) return;
|
|
1151
|
+
const method = action === "freeze" ? host.freezeTrack : host.unfreezeTrack;
|
|
1152
|
+
if (typeof method !== "function") return;
|
|
1153
|
+
setBusy(action);
|
|
1154
|
+
setError(null);
|
|
1155
|
+
try {
|
|
1156
|
+
setState(await method.call(host, trackId));
|
|
1157
|
+
} catch (e) {
|
|
1158
|
+
setError(e instanceof Error ? e.message : String(e));
|
|
1159
|
+
void refresh();
|
|
1160
|
+
} finally {
|
|
1161
|
+
setBusy(null);
|
|
1162
|
+
}
|
|
1163
|
+
},
|
|
1164
|
+
[host, trackId, refresh]
|
|
1165
|
+
);
|
|
1166
|
+
const freeze = useCallback3(() => run("freeze"), [run]);
|
|
1167
|
+
const unfreeze = useCallback3(() => run("unfreeze"), [run]);
|
|
1168
|
+
return { enabled, state, busy, error, refresh, freeze, unfreeze };
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
// src/components/TrackDrawer.tsx
|
|
1172
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1056
1173
|
var TAB_LABELS = {
|
|
1057
1174
|
fx: "FX",
|
|
1058
1175
|
pick: "Pick",
|
|
1059
1176
|
history: "History",
|
|
1060
1177
|
import: "Import",
|
|
1061
|
-
edit: "Edit"
|
|
1178
|
+
edit: "Edit",
|
|
1179
|
+
freeze: "\u2744 Freeze"
|
|
1062
1180
|
};
|
|
1063
1181
|
function TrackDrawer({
|
|
1064
1182
|
activeTab,
|
|
@@ -1070,6 +1188,7 @@ function TrackDrawer({
|
|
|
1070
1188
|
onFxDryWetChange,
|
|
1071
1189
|
fxDisabled = false,
|
|
1072
1190
|
externalFxHost,
|
|
1191
|
+
freeze,
|
|
1073
1192
|
instruments = [],
|
|
1074
1193
|
currentPluginId = null,
|
|
1075
1194
|
isLoading = false,
|
|
@@ -1092,12 +1211,15 @@ function TrackDrawer({
|
|
|
1092
1211
|
editSnap,
|
|
1093
1212
|
onAuditionNote
|
|
1094
1213
|
}) {
|
|
1095
|
-
const [search, setSearch] =
|
|
1214
|
+
const [search, setSearch] = useState5("");
|
|
1096
1215
|
const fxEnabled = !!onFxToggle;
|
|
1097
1216
|
const pickEnabled = !!onSelect;
|
|
1098
1217
|
const historyEnabled = !!onRestoreSound;
|
|
1099
1218
|
const importEnabled = !!onImportSound;
|
|
1100
1219
|
const editEnabled = !!onNotesChange;
|
|
1220
|
+
const internalFreeze = useTrackFreeze(freeze ? void 0 : externalFxHost, trackId);
|
|
1221
|
+
const fz = freeze ?? internalFreeze;
|
|
1222
|
+
const freezeEnabled = fz.enabled;
|
|
1101
1223
|
const enabledTabs = useMemo3(() => {
|
|
1102
1224
|
const tabs = [];
|
|
1103
1225
|
if (fxEnabled) tabs.push("fx");
|
|
@@ -1105,8 +1227,9 @@ function TrackDrawer({
|
|
|
1105
1227
|
if (historyEnabled) tabs.push("history");
|
|
1106
1228
|
if (importEnabled) tabs.push("import");
|
|
1107
1229
|
if (editEnabled) tabs.push("edit");
|
|
1230
|
+
if (freezeEnabled) tabs.push("freeze");
|
|
1108
1231
|
return tabs;
|
|
1109
|
-
}, [fxEnabled, pickEnabled, historyEnabled, importEnabled, editEnabled]);
|
|
1232
|
+
}, [fxEnabled, pickEnabled, historyEnabled, importEnabled, editEnabled, freezeEnabled]);
|
|
1110
1233
|
const SURGE_XT_DEFAULT_ID = "Surge XT";
|
|
1111
1234
|
const filtered = useMemo3(() => {
|
|
1112
1235
|
let all = instruments.filter((i) => i.name !== "Surge XT");
|
|
@@ -1128,12 +1251,12 @@ function TrackDrawer({
|
|
|
1128
1251
|
const history = soundHistory ?? [];
|
|
1129
1252
|
const effectiveTab = enabledTabs.includes(activeTab) ? activeTab : enabledTabs[0] ?? "fx";
|
|
1130
1253
|
const tabClass = (active) => `px-2 py-0.5 text-xs rounded-sm transition-colors ${active ? "bg-sas-accent/20 text-sas-accent font-medium" : "text-sas-muted hover:text-sas-accent"}`;
|
|
1131
|
-
const strip = enabledTabs.length > 1 ? /* @__PURE__ */
|
|
1254
|
+
const strip = enabledTabs.length > 1 ? /* @__PURE__ */ jsx5(
|
|
1132
1255
|
"div",
|
|
1133
1256
|
{
|
|
1134
1257
|
className: "flex items-center gap-1 border-b border-sas-border pb-1",
|
|
1135
1258
|
"data-testid": "sdk-drawer-tabs",
|
|
1136
|
-
children: enabledTabs.map((tab) => /* @__PURE__ */
|
|
1259
|
+
children: enabledTabs.map((tab) => /* @__PURE__ */ jsx5(
|
|
1137
1260
|
"button",
|
|
1138
1261
|
{
|
|
1139
1262
|
type: "button",
|
|
@@ -1147,9 +1270,9 @@ function TrackDrawer({
|
|
|
1147
1270
|
}
|
|
1148
1271
|
) : null;
|
|
1149
1272
|
const currentSound = soundHistoryCursor >= 0 && soundHistoryCursor < history.length ? history[soundHistoryCursor].label : null;
|
|
1150
|
-
const header = strip || currentSound ? /* @__PURE__ */
|
|
1273
|
+
const header = strip || currentSound ? /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-1", "data-testid": "sdk-drawer-header", children: [
|
|
1151
1274
|
strip,
|
|
1152
|
-
currentSound && /* @__PURE__ */
|
|
1275
|
+
currentSound && /* @__PURE__ */ jsx5(
|
|
1153
1276
|
"span",
|
|
1154
1277
|
{
|
|
1155
1278
|
className: "text-[10px] text-sas-muted/60 truncate px-0.5",
|
|
@@ -1158,10 +1281,41 @@ function TrackDrawer({
|
|
|
1158
1281
|
}
|
|
1159
1282
|
)
|
|
1160
1283
|
] }) : null;
|
|
1284
|
+
if (effectiveTab === "freeze") {
|
|
1285
|
+
return /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-2", "data-testid": "sdk-drawer-freeze", children: [
|
|
1286
|
+
header,
|
|
1287
|
+
/* @__PURE__ */ jsx5(
|
|
1288
|
+
TrackFreezeSection,
|
|
1289
|
+
{
|
|
1290
|
+
state: fz.state,
|
|
1291
|
+
busy: fz.busy,
|
|
1292
|
+
error: fz.error,
|
|
1293
|
+
onFreeze: () => void fz.freeze(),
|
|
1294
|
+
onUnfreeze: () => void fz.unfreeze()
|
|
1295
|
+
}
|
|
1296
|
+
)
|
|
1297
|
+
] });
|
|
1298
|
+
}
|
|
1299
|
+
if (fz.state?.frozen === true) {
|
|
1300
|
+
return /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-2", "data-testid": "sdk-drawer-frozen-lock", children: [
|
|
1301
|
+
header,
|
|
1302
|
+
/* @__PURE__ */ jsx5("div", { className: "text-[11px] text-sas-muted/80 leading-snug rounded-sm border border-sas-border bg-sas-panel-alt px-2 py-2", children: "\u2744 This track is frozen \u2014 it plays its rendered stem, so sound editing here would be inaudible. Volume, pan, mute and solo stay live." }),
|
|
1303
|
+
/* @__PURE__ */ jsx5(
|
|
1304
|
+
"button",
|
|
1305
|
+
{
|
|
1306
|
+
type: "button",
|
|
1307
|
+
"data-testid": "sdk-drawer-frozen-goto",
|
|
1308
|
+
onClick: () => onTabChange?.("freeze"),
|
|
1309
|
+
className: "w-full py-2 text-xs font-medium rounded-sm border border-sas-accent bg-sas-accent/20 text-sas-accent hover:bg-sas-accent/40 transition-colors",
|
|
1310
|
+
children: "Open the Freeze tab to unfreeze"
|
|
1311
|
+
}
|
|
1312
|
+
)
|
|
1313
|
+
] });
|
|
1314
|
+
}
|
|
1161
1315
|
if (effectiveTab === "edit") {
|
|
1162
|
-
return /* @__PURE__ */
|
|
1316
|
+
return /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-2", "data-testid": "sdk-drawer-edit", children: [
|
|
1163
1317
|
header,
|
|
1164
|
-
/* @__PURE__ */
|
|
1318
|
+
/* @__PURE__ */ jsx5(
|
|
1165
1319
|
PianoRollEditor,
|
|
1166
1320
|
{
|
|
1167
1321
|
notes: editNotes ?? [],
|
|
@@ -1176,9 +1330,9 @@ function TrackDrawer({
|
|
|
1176
1330
|
] });
|
|
1177
1331
|
}
|
|
1178
1332
|
if (effectiveTab === "fx") {
|
|
1179
|
-
return /* @__PURE__ */
|
|
1333
|
+
return /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-2", "data-testid": "sdk-drawer-fx", children: [
|
|
1180
1334
|
header,
|
|
1181
|
-
/* @__PURE__ */
|
|
1335
|
+
/* @__PURE__ */ jsx5(
|
|
1182
1336
|
FxToggleBar,
|
|
1183
1337
|
{
|
|
1184
1338
|
trackId,
|
|
@@ -1189,20 +1343,20 @@ function TrackDrawer({
|
|
|
1189
1343
|
disabled: fxDisabled
|
|
1190
1344
|
}
|
|
1191
1345
|
),
|
|
1192
|
-
externalFxHost && /* @__PURE__ */
|
|
1346
|
+
externalFxHost && /* @__PURE__ */ jsx5(TrackExternalFxSection, { host: externalFxHost, trackId, disabled: fxDisabled })
|
|
1193
1347
|
] });
|
|
1194
1348
|
}
|
|
1195
1349
|
if (effectiveTab === "import") {
|
|
1196
1350
|
const soundNoun = /preset/i.test(importSoundLabel ?? "") ? "preset" : /sample/i.test(importSoundLabel ?? "") ? "sample" : "sound";
|
|
1197
|
-
return /* @__PURE__ */
|
|
1351
|
+
return /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-2", "data-testid": "sdk-drawer-import", children: [
|
|
1198
1352
|
header,
|
|
1199
|
-
/* @__PURE__ */
|
|
1353
|
+
/* @__PURE__ */ jsxs5("p", { className: "text-[11px] text-sas-muted/70 leading-snug", children: [
|
|
1200
1354
|
"Copy the sound from a matching track in another scene \u2014 your MIDI stays, only the",
|
|
1201
1355
|
" ",
|
|
1202
1356
|
soundNoun,
|
|
1203
1357
|
" changes."
|
|
1204
1358
|
] }),
|
|
1205
|
-
/* @__PURE__ */
|
|
1359
|
+
/* @__PURE__ */ jsxs5(
|
|
1206
1360
|
"button",
|
|
1207
1361
|
{
|
|
1208
1362
|
type: "button",
|
|
@@ -1220,16 +1374,16 @@ function TrackDrawer({
|
|
|
1220
1374
|
}
|
|
1221
1375
|
if (effectiveTab === "history") {
|
|
1222
1376
|
const order = history.map((_, i) => i).reverse();
|
|
1223
|
-
return /* @__PURE__ */
|
|
1377
|
+
return /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-2", children: [
|
|
1224
1378
|
header,
|
|
1225
|
-
history.length === 0 ? /* @__PURE__ */
|
|
1379
|
+
history.length === 0 ? /* @__PURE__ */ jsx5(
|
|
1226
1380
|
"div",
|
|
1227
1381
|
{
|
|
1228
1382
|
className: "text-xs text-sas-muted/60 text-center py-3",
|
|
1229
1383
|
"data-testid": "sdk-history-empty",
|
|
1230
1384
|
children: "No sounds yet \u2014 shuffle to build history."
|
|
1231
1385
|
}
|
|
1232
|
-
) : /* @__PURE__ */
|
|
1386
|
+
) : /* @__PURE__ */ jsx5(
|
|
1233
1387
|
"ul",
|
|
1234
1388
|
{
|
|
1235
1389
|
className: "flex flex-col gap-1 max-h-[160px] overflow-y-auto",
|
|
@@ -1237,8 +1391,8 @@ function TrackDrawer({
|
|
|
1237
1391
|
children: order.map((i) => {
|
|
1238
1392
|
const entry = history[i];
|
|
1239
1393
|
const isCurrent = i === soundHistoryCursor;
|
|
1240
|
-
return /* @__PURE__ */
|
|
1241
|
-
/* @__PURE__ */
|
|
1394
|
+
return /* @__PURE__ */ jsxs5("li", { className: "flex items-center gap-1", children: [
|
|
1395
|
+
/* @__PURE__ */ jsxs5(
|
|
1242
1396
|
"button",
|
|
1243
1397
|
{
|
|
1244
1398
|
type: "button",
|
|
@@ -1248,12 +1402,12 @@ function TrackDrawer({
|
|
|
1248
1402
|
className: `flex-1 min-w-0 flex items-center justify-between px-2 py-1.5 rounded-sm border text-left text-xs transition-colors ${isCurrent ? "border-sas-accent bg-sas-accent/20 text-sas-accent cursor-default" : "border-sas-border bg-sas-panel-alt text-sas-muted hover:border-sas-accent hover:text-sas-accent"}`,
|
|
1249
1403
|
title: isCurrent ? "Current sound" : `Restore: ${entry.label}`,
|
|
1250
1404
|
children: [
|
|
1251
|
-
/* @__PURE__ */
|
|
1252
|
-
/* @__PURE__ */
|
|
1405
|
+
/* @__PURE__ */ jsx5("span", { className: "truncate", children: entry.label }),
|
|
1406
|
+
/* @__PURE__ */ jsx5("span", { className: "text-[10px] text-sas-muted/60 flex-shrink-0 ml-2", children: isCurrent ? "\u25CF current" : "restore" })
|
|
1253
1407
|
]
|
|
1254
1408
|
}
|
|
1255
1409
|
),
|
|
1256
|
-
onToggleFavorite && /* @__PURE__ */
|
|
1410
|
+
onToggleFavorite && /* @__PURE__ */ jsx5(
|
|
1257
1411
|
"button",
|
|
1258
1412
|
{
|
|
1259
1413
|
type: "button",
|
|
@@ -1271,10 +1425,10 @@ function TrackDrawer({
|
|
|
1271
1425
|
] });
|
|
1272
1426
|
}
|
|
1273
1427
|
if (effectiveTab === "pick" && editorStage) {
|
|
1274
|
-
return /* @__PURE__ */
|
|
1428
|
+
return /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-2", children: [
|
|
1275
1429
|
header,
|
|
1276
|
-
/* @__PURE__ */
|
|
1277
|
-
/* @__PURE__ */
|
|
1430
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2", children: [
|
|
1431
|
+
/* @__PURE__ */ jsx5(
|
|
1278
1432
|
"button",
|
|
1279
1433
|
{
|
|
1280
1434
|
onClick: () => onBackToInstruments?.(),
|
|
@@ -1282,9 +1436,9 @@ function TrackDrawer({
|
|
|
1282
1436
|
children: "\u2190 Back"
|
|
1283
1437
|
}
|
|
1284
1438
|
),
|
|
1285
|
-
/* @__PURE__ */
|
|
1439
|
+
/* @__PURE__ */ jsx5("span", { className: "text-xs text-sas-muted font-medium truncate flex-1", children: selectedInstrumentName ?? "Plugin" })
|
|
1286
1440
|
] }),
|
|
1287
|
-
/* @__PURE__ */
|
|
1441
|
+
/* @__PURE__ */ jsx5(
|
|
1288
1442
|
"button",
|
|
1289
1443
|
{
|
|
1290
1444
|
onClick: () => onShowEditor?.(),
|
|
@@ -1296,10 +1450,10 @@ function TrackDrawer({
|
|
|
1296
1450
|
}
|
|
1297
1451
|
const isDefaultSelected = currentPluginId === null;
|
|
1298
1452
|
const isSelected = (pluginId) => pluginId === currentPluginId;
|
|
1299
|
-
return /* @__PURE__ */
|
|
1453
|
+
return /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-2", children: [
|
|
1300
1454
|
header,
|
|
1301
|
-
/* @__PURE__ */
|
|
1302
|
-
/* @__PURE__ */
|
|
1455
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2", children: [
|
|
1456
|
+
/* @__PURE__ */ jsx5(
|
|
1303
1457
|
"input",
|
|
1304
1458
|
{
|
|
1305
1459
|
type: "text",
|
|
@@ -1309,7 +1463,7 @@ function TrackDrawer({
|
|
|
1309
1463
|
className: "sas-input flex-1 px-2 py-1 text-xs"
|
|
1310
1464
|
}
|
|
1311
1465
|
),
|
|
1312
|
-
/* @__PURE__ */
|
|
1466
|
+
/* @__PURE__ */ jsx5(
|
|
1313
1467
|
"button",
|
|
1314
1468
|
{
|
|
1315
1469
|
onClick: () => onRefresh?.(),
|
|
@@ -1320,43 +1474,43 @@ function TrackDrawer({
|
|
|
1320
1474
|
}
|
|
1321
1475
|
)
|
|
1322
1476
|
] }),
|
|
1323
|
-
isLoading && instruments.length === 0 ? /* @__PURE__ */
|
|
1324
|
-
/* @__PURE__ */
|
|
1477
|
+
isLoading && instruments.length === 0 ? /* @__PURE__ */ jsx5("div", { className: "text-xs text-sas-muted/60 text-center py-3", children: "Scanning plugins..." }) : /* @__PURE__ */ jsxs5("div", { className: "grid grid-cols-3 gap-1 max-h-[140px] overflow-y-auto", children: [
|
|
1478
|
+
/* @__PURE__ */ jsxs5(
|
|
1325
1479
|
"button",
|
|
1326
1480
|
{
|
|
1327
1481
|
onClick: () => onSelect?.(SURGE_XT_DEFAULT_ID),
|
|
1328
1482
|
className: `flex flex-col items-start px-2 py-1.5 rounded-sm border text-left transition-colors ${isDefaultSelected ? "border-sas-accent bg-sas-accent/20 text-sas-accent" : "border-sas-border bg-sas-panel-alt text-sas-muted hover:border-sas-accent hover:text-sas-accent"}`,
|
|
1329
1483
|
title: "Surge XT \u2014 Default instrument",
|
|
1330
1484
|
children: [
|
|
1331
|
-
/* @__PURE__ */
|
|
1485
|
+
/* @__PURE__ */ jsxs5("span", { className: "text-xs font-medium truncate w-full", children: [
|
|
1332
1486
|
isDefaultSelected && "\u2713 ",
|
|
1333
1487
|
"Surge XT"
|
|
1334
1488
|
] }),
|
|
1335
|
-
/* @__PURE__ */
|
|
1489
|
+
/* @__PURE__ */ jsx5("span", { className: "text-[9px] text-sas-muted/50 truncate w-full", children: "Default" })
|
|
1336
1490
|
]
|
|
1337
1491
|
},
|
|
1338
1492
|
"__surge-xt-default__"
|
|
1339
1493
|
),
|
|
1340
1494
|
filtered.map((inst) => {
|
|
1341
1495
|
const selected = isSelected(inst.pluginId);
|
|
1342
|
-
return /* @__PURE__ */
|
|
1496
|
+
return /* @__PURE__ */ jsxs5(
|
|
1343
1497
|
"button",
|
|
1344
1498
|
{
|
|
1345
1499
|
onClick: () => onSelect?.(inst.pluginId),
|
|
1346
1500
|
className: `flex flex-col items-start px-2 py-1.5 rounded-sm border text-left transition-colors ${selected ? "border-sas-accent bg-sas-accent/20 text-sas-accent" : inst.missing ? "border-amber-500/50 bg-amber-500/10 text-amber-400 hover:border-amber-500" : "border-sas-border bg-sas-panel-alt text-sas-muted hover:border-sas-accent hover:text-sas-accent"}`,
|
|
1347
1501
|
title: `${inst.name} by ${inst.manufacturer} (${inst.type.toUpperCase()})${inst.missing ? " \u2014 MISSING" : ""}`,
|
|
1348
1502
|
children: [
|
|
1349
|
-
/* @__PURE__ */
|
|
1503
|
+
/* @__PURE__ */ jsxs5("span", { className: "text-xs font-medium truncate w-full", children: [
|
|
1350
1504
|
selected && "\u2713 ",
|
|
1351
1505
|
inst.name
|
|
1352
1506
|
] }),
|
|
1353
|
-
/* @__PURE__ */
|
|
1507
|
+
/* @__PURE__ */ jsx5("span", { className: "text-[9px] text-sas-muted/50 truncate w-full", children: inst.manufacturer || inst.type.toUpperCase() })
|
|
1354
1508
|
]
|
|
1355
1509
|
},
|
|
1356
1510
|
inst.pluginId
|
|
1357
1511
|
);
|
|
1358
1512
|
}),
|
|
1359
|
-
filtered.length === 0 && /* @__PURE__ */
|
|
1513
|
+
filtered.length === 0 && /* @__PURE__ */ jsx5("div", { className: "col-span-2 text-xs text-sas-muted/60 text-center py-2", children: search.trim() ? "No matches" : "No other plugins found" })
|
|
1360
1514
|
] })
|
|
1361
1515
|
] });
|
|
1362
1516
|
}
|
|
@@ -1365,9 +1519,9 @@ function TrackDrawer({
|
|
|
1365
1519
|
import { useRef as useRef3 } from "react";
|
|
1366
1520
|
|
|
1367
1521
|
// src/components/Modal.tsx
|
|
1368
|
-
import { useEffect as
|
|
1522
|
+
import { useEffect as useEffect3 } from "react";
|
|
1369
1523
|
import { createPortal } from "react-dom";
|
|
1370
|
-
import { jsx as
|
|
1524
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
1371
1525
|
function Modal({
|
|
1372
1526
|
open,
|
|
1373
1527
|
onClose,
|
|
@@ -1377,7 +1531,7 @@ function Modal({
|
|
|
1377
1531
|
closeOnEscape = true,
|
|
1378
1532
|
initialFocusRef
|
|
1379
1533
|
}) {
|
|
1380
|
-
|
|
1534
|
+
useEffect3(() => {
|
|
1381
1535
|
if (!open) return void 0;
|
|
1382
1536
|
const onKey = (e) => {
|
|
1383
1537
|
if (closeOnEscape && e.key === "Escape") {
|
|
@@ -1391,7 +1545,7 @@ function Modal({
|
|
|
1391
1545
|
}, [open, onClose, closeOnEscape, initialFocusRef]);
|
|
1392
1546
|
if (!open) return null;
|
|
1393
1547
|
return createPortal(
|
|
1394
|
-
/* @__PURE__ */
|
|
1548
|
+
/* @__PURE__ */ jsx6(
|
|
1395
1549
|
"div",
|
|
1396
1550
|
{
|
|
1397
1551
|
className: "fixed inset-0 z-[1000] flex items-center justify-center bg-black/60",
|
|
@@ -1405,7 +1559,7 @@ function Modal({
|
|
|
1405
1559
|
}
|
|
1406
1560
|
|
|
1407
1561
|
// src/components/ConfirmDialog.tsx
|
|
1408
|
-
import { jsx as
|
|
1562
|
+
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1409
1563
|
function ConfirmDialog({
|
|
1410
1564
|
open,
|
|
1411
1565
|
title,
|
|
@@ -1418,7 +1572,7 @@ function ConfirmDialog({
|
|
|
1418
1572
|
testIdPrefix = "confirm-dialog"
|
|
1419
1573
|
}) {
|
|
1420
1574
|
const cancelRef = useRef3(null);
|
|
1421
|
-
return /* @__PURE__ */
|
|
1575
|
+
return /* @__PURE__ */ jsx7(Modal, { open, onClose: onCancel, testIdPrefix, initialFocusRef: cancelRef, children: /* @__PURE__ */ jsxs6(
|
|
1422
1576
|
"div",
|
|
1423
1577
|
{
|
|
1424
1578
|
className: "w-[360px] max-w-[90vw] flex flex-col rounded-md border border-sas-border bg-sas-panel shadow-xl",
|
|
@@ -1428,8 +1582,8 @@ function ConfirmDialog({
|
|
|
1428
1582
|
"aria-label": title,
|
|
1429
1583
|
"data-testid": `${testIdPrefix}-modal`,
|
|
1430
1584
|
children: [
|
|
1431
|
-
/* @__PURE__ */
|
|
1432
|
-
/* @__PURE__ */
|
|
1585
|
+
/* @__PURE__ */ jsx7("div", { className: "px-4 py-3 border-b border-sas-border", children: /* @__PURE__ */ jsx7("span", { className: "text-sm font-medium text-sas-text", "data-testid": `${testIdPrefix}-title`, children: title }) }),
|
|
1586
|
+
/* @__PURE__ */ jsx7(
|
|
1433
1587
|
"div",
|
|
1434
1588
|
{
|
|
1435
1589
|
className: "px-4 py-3 text-xs text-sas-muted leading-relaxed break-words",
|
|
@@ -1437,8 +1591,8 @@ function ConfirmDialog({
|
|
|
1437
1591
|
children: message
|
|
1438
1592
|
}
|
|
1439
1593
|
),
|
|
1440
|
-
/* @__PURE__ */
|
|
1441
|
-
/* @__PURE__ */
|
|
1594
|
+
/* @__PURE__ */ jsxs6("div", { className: "flex justify-end gap-2 px-4 py-3 border-t border-sas-border", children: [
|
|
1595
|
+
/* @__PURE__ */ jsx7(
|
|
1442
1596
|
"button",
|
|
1443
1597
|
{
|
|
1444
1598
|
ref: cancelRef,
|
|
@@ -1449,7 +1603,7 @@ function ConfirmDialog({
|
|
|
1449
1603
|
children: cancelLabel
|
|
1450
1604
|
}
|
|
1451
1605
|
),
|
|
1452
|
-
/* @__PURE__ */
|
|
1606
|
+
/* @__PURE__ */ jsx7(
|
|
1453
1607
|
"button",
|
|
1454
1608
|
{
|
|
1455
1609
|
type: "button",
|
|
@@ -1466,7 +1620,7 @@ function ConfirmDialog({
|
|
|
1466
1620
|
}
|
|
1467
1621
|
|
|
1468
1622
|
// src/components/LevelMeter.tsx
|
|
1469
|
-
import { jsx as
|
|
1623
|
+
import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1470
1624
|
var COLOR_GREEN = "#2BD576";
|
|
1471
1625
|
var COLOR_ORANGE = "#F5A623";
|
|
1472
1626
|
var COLOR_RED = "#FF4D5E";
|
|
@@ -1494,7 +1648,7 @@ var LevelMeter = ({
|
|
|
1494
1648
|
const widthPct = active ? dbToPct(peakDb) : 0;
|
|
1495
1649
|
const showPeak = peakHoldDb != null && active && peakHoldDb > -60;
|
|
1496
1650
|
const peakHoldPct = showPeak ? dbToPct(peakHoldDb) : 0;
|
|
1497
|
-
return /* @__PURE__ */
|
|
1651
|
+
return /* @__PURE__ */ jsxs7(
|
|
1498
1652
|
"div",
|
|
1499
1653
|
{
|
|
1500
1654
|
className: `sas-level-meter ${className ?? ""}`,
|
|
@@ -1505,7 +1659,7 @@ var LevelMeter = ({
|
|
|
1505
1659
|
gap: compact ? 0 : 6
|
|
1506
1660
|
},
|
|
1507
1661
|
children: [
|
|
1508
|
-
/* @__PURE__ */
|
|
1662
|
+
/* @__PURE__ */ jsxs7(
|
|
1509
1663
|
"div",
|
|
1510
1664
|
{
|
|
1511
1665
|
style: {
|
|
@@ -1519,8 +1673,8 @@ var LevelMeter = ({
|
|
|
1519
1673
|
minWidth: compact ? 0 : 60
|
|
1520
1674
|
},
|
|
1521
1675
|
children: [
|
|
1522
|
-
/* @__PURE__ */
|
|
1523
|
-
/* @__PURE__ */
|
|
1676
|
+
/* @__PURE__ */ jsx8("div", { style: { position: "absolute", inset: 0, background: METER_GRADIENT } }),
|
|
1677
|
+
/* @__PURE__ */ jsx8(
|
|
1524
1678
|
"div",
|
|
1525
1679
|
{
|
|
1526
1680
|
style: {
|
|
@@ -1534,7 +1688,7 @@ var LevelMeter = ({
|
|
|
1534
1688
|
}
|
|
1535
1689
|
}
|
|
1536
1690
|
),
|
|
1537
|
-
/* @__PURE__ */
|
|
1691
|
+
/* @__PURE__ */ jsx8(
|
|
1538
1692
|
"div",
|
|
1539
1693
|
{
|
|
1540
1694
|
"data-testid": `${id}-segments`,
|
|
@@ -1547,7 +1701,7 @@ var LevelMeter = ({
|
|
|
1547
1701
|
}
|
|
1548
1702
|
}
|
|
1549
1703
|
),
|
|
1550
|
-
showPeak && /* @__PURE__ */
|
|
1704
|
+
showPeak && /* @__PURE__ */ jsx8(
|
|
1551
1705
|
"div",
|
|
1552
1706
|
{
|
|
1553
1707
|
"data-testid": `${id}-peak`,
|
|
@@ -1568,7 +1722,7 @@ var LevelMeter = ({
|
|
|
1568
1722
|
]
|
|
1569
1723
|
}
|
|
1570
1724
|
),
|
|
1571
|
-
!compact && /* @__PURE__ */
|
|
1725
|
+
!compact && /* @__PURE__ */ jsx8(
|
|
1572
1726
|
"span",
|
|
1573
1727
|
{
|
|
1574
1728
|
style: {
|
|
@@ -1581,7 +1735,7 @@ var LevelMeter = ({
|
|
|
1581
1735
|
children: active && peakDb > -120 ? `${peakDb.toFixed(0)} dB` : "\u2014"
|
|
1582
1736
|
}
|
|
1583
1737
|
),
|
|
1584
|
-
clipped && /* @__PURE__ */
|
|
1738
|
+
clipped && /* @__PURE__ */ jsx8(
|
|
1585
1739
|
"span",
|
|
1586
1740
|
{
|
|
1587
1741
|
"data-testid": `${id}-clip`,
|
|
@@ -1606,7 +1760,7 @@ var LevelMeter = ({
|
|
|
1606
1760
|
};
|
|
1607
1761
|
|
|
1608
1762
|
// src/hooks/useTrackLevels.ts
|
|
1609
|
-
import { useEffect as
|
|
1763
|
+
import { useEffect as useEffect4, useRef as useRef4, useState as useState6 } from "react";
|
|
1610
1764
|
var meterDiagRLast = /* @__PURE__ */ new Map();
|
|
1611
1765
|
var POLL_INTERVAL_MS = 33;
|
|
1612
1766
|
var HIDDEN_RECHECK_MS = 250;
|
|
@@ -1631,7 +1785,7 @@ function useTrackLevels(host, enabled = true) {
|
|
|
1631
1785
|
}
|
|
1632
1786
|
};
|
|
1633
1787
|
}
|
|
1634
|
-
|
|
1788
|
+
useEffect4(() => {
|
|
1635
1789
|
const notify = () => {
|
|
1636
1790
|
listenersRef.current.forEach((l) => l());
|
|
1637
1791
|
};
|
|
@@ -1701,8 +1855,8 @@ function sameLevel(a, b) {
|
|
|
1701
1855
|
return a.peakDb === b.peakDb && a.clipped === b.clipped;
|
|
1702
1856
|
}
|
|
1703
1857
|
function useTrackLevel(handle, trackId) {
|
|
1704
|
-
const [level, setLevel] =
|
|
1705
|
-
|
|
1858
|
+
const [level, setLevel] = useState6(null);
|
|
1859
|
+
useEffect4(() => {
|
|
1706
1860
|
if (!handle) {
|
|
1707
1861
|
setLevel(null);
|
|
1708
1862
|
return;
|
|
@@ -1726,11 +1880,11 @@ function sameMeter(a, b) {
|
|
|
1726
1880
|
return a.active === b.active && a.clipped === b.clipped && a.peakDb === b.peakDb && Math.round(a.peakHoldDb * 2) === Math.round(b.peakHoldDb * 2);
|
|
1727
1881
|
}
|
|
1728
1882
|
function useTrackMeter(handle, trackId) {
|
|
1729
|
-
const [view, setView] =
|
|
1883
|
+
const [view, setView] = useState6(IDLE_METER_VIEW);
|
|
1730
1884
|
const heldDbRef = useRef4(METER_FLOOR_DB);
|
|
1731
1885
|
const heldAtRef = useRef4(0);
|
|
1732
1886
|
const lastTickRef = useRef4(0);
|
|
1733
|
-
|
|
1887
|
+
useEffect4(() => {
|
|
1734
1888
|
if (!handle) {
|
|
1735
1889
|
heldDbRef.current = METER_FLOOR_DB;
|
|
1736
1890
|
lastTickRef.current = 0;
|
|
@@ -1773,8 +1927,8 @@ function useTrackMeter(handle, trackId) {
|
|
|
1773
1927
|
return view;
|
|
1774
1928
|
}
|
|
1775
1929
|
function useTransportPlaying(host) {
|
|
1776
|
-
const [playing, setPlaying] =
|
|
1777
|
-
|
|
1930
|
+
const [playing, setPlaying] = useState6(false);
|
|
1931
|
+
useEffect4(() => {
|
|
1778
1932
|
if (!host) {
|
|
1779
1933
|
setPlaying(false);
|
|
1780
1934
|
return;
|
|
@@ -1802,7 +1956,7 @@ function useTransportPlaying(host) {
|
|
|
1802
1956
|
}
|
|
1803
1957
|
|
|
1804
1958
|
// src/components/TrackMeterStrip.tsx
|
|
1805
|
-
import { jsx as
|
|
1959
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
1806
1960
|
var TrackMeterStrip = ({
|
|
1807
1961
|
levels,
|
|
1808
1962
|
trackId,
|
|
@@ -1810,12 +1964,12 @@ var TrackMeterStrip = ({
|
|
|
1810
1964
|
className
|
|
1811
1965
|
}) => {
|
|
1812
1966
|
const meter = useTrackMeter(levels, trackId);
|
|
1813
|
-
return /* @__PURE__ */
|
|
1967
|
+
return /* @__PURE__ */ jsx9(
|
|
1814
1968
|
"div",
|
|
1815
1969
|
{
|
|
1816
1970
|
"data-testid": "sdk-track-meter",
|
|
1817
1971
|
className: `w-full px-2 py-1 bg-sas-panel-alt border border-t-0 border-sas-border ${roundBottom ? "rounded-b-sm" : ""} ${className ?? ""}`,
|
|
1818
|
-
children: /* @__PURE__ */
|
|
1972
|
+
children: /* @__PURE__ */ jsx9(
|
|
1819
1973
|
LevelMeter,
|
|
1820
1974
|
{
|
|
1821
1975
|
compact: true,
|
|
@@ -1831,7 +1985,7 @@ var TrackMeterStrip = ({
|
|
|
1831
1985
|
};
|
|
1832
1986
|
|
|
1833
1987
|
// src/components/VolumeSlider.tsx
|
|
1834
|
-
import { useCallback as
|
|
1988
|
+
import { useCallback as useCallback4, useState as useState7, useRef as useRef5, useEffect as useEffect5 } from "react";
|
|
1835
1989
|
|
|
1836
1990
|
// src/utils/volume-conversion.ts
|
|
1837
1991
|
var SLIDER_UNITY = 0.75;
|
|
@@ -1853,7 +2007,7 @@ function dbToSlider(db) {
|
|
|
1853
2007
|
}
|
|
1854
2008
|
|
|
1855
2009
|
// src/components/VolumeSlider.tsx
|
|
1856
|
-
import { jsx as
|
|
2010
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
1857
2011
|
function formatDb(value) {
|
|
1858
2012
|
const db = sliderToDb(value);
|
|
1859
2013
|
if (db <= -60) return "-\u221E dB";
|
|
@@ -1863,10 +2017,10 @@ function formatDb(value) {
|
|
|
1863
2017
|
function useDebouncedCallback(callback, delay) {
|
|
1864
2018
|
const timeoutRef = useRef5(null);
|
|
1865
2019
|
const callbackRef = useRef5(callback);
|
|
1866
|
-
|
|
2020
|
+
useEffect5(() => {
|
|
1867
2021
|
callbackRef.current = callback;
|
|
1868
2022
|
}, [callback]);
|
|
1869
|
-
const debouncedCallback =
|
|
2023
|
+
const debouncedCallback = useCallback4(
|
|
1870
2024
|
(...args) => {
|
|
1871
2025
|
if (timeoutRef.current) {
|
|
1872
2026
|
clearTimeout(timeoutRef.current);
|
|
@@ -1877,7 +2031,7 @@ function useDebouncedCallback(callback, delay) {
|
|
|
1877
2031
|
},
|
|
1878
2032
|
[delay]
|
|
1879
2033
|
);
|
|
1880
|
-
|
|
2034
|
+
useEffect5(() => {
|
|
1881
2035
|
return () => {
|
|
1882
2036
|
if (timeoutRef.current) {
|
|
1883
2037
|
clearTimeout(timeoutRef.current);
|
|
@@ -1892,15 +2046,15 @@ var VolumeSlider = ({
|
|
|
1892
2046
|
disabled = false,
|
|
1893
2047
|
className = ""
|
|
1894
2048
|
}) => {
|
|
1895
|
-
const [localValue, setLocalValue] =
|
|
1896
|
-
const [isDragging, setIsDragging] =
|
|
1897
|
-
|
|
2049
|
+
const [localValue, setLocalValue] = useState7(value);
|
|
2050
|
+
const [isDragging, setIsDragging] = useState7(false);
|
|
2051
|
+
useEffect5(() => {
|
|
1898
2052
|
if (!isDragging) {
|
|
1899
2053
|
setLocalValue(value);
|
|
1900
2054
|
}
|
|
1901
2055
|
}, [value, isDragging]);
|
|
1902
2056
|
const debouncedOnChange = useDebouncedCallback(onChange, 50);
|
|
1903
|
-
const handleChange =
|
|
2057
|
+
const handleChange = useCallback4(
|
|
1904
2058
|
(e) => {
|
|
1905
2059
|
const newValue = parseFloat(e.target.value);
|
|
1906
2060
|
setLocalValue(newValue);
|
|
@@ -1908,19 +2062,19 @@ var VolumeSlider = ({
|
|
|
1908
2062
|
},
|
|
1909
2063
|
[debouncedOnChange]
|
|
1910
2064
|
);
|
|
1911
|
-
const handleMouseDown =
|
|
2065
|
+
const handleMouseDown = useCallback4(() => {
|
|
1912
2066
|
setIsDragging(true);
|
|
1913
2067
|
}, []);
|
|
1914
|
-
const handleMouseUp =
|
|
2068
|
+
const handleMouseUp = useCallback4(() => {
|
|
1915
2069
|
setIsDragging(false);
|
|
1916
2070
|
onChange(localValue);
|
|
1917
2071
|
}, [localValue, onChange]);
|
|
1918
|
-
return /* @__PURE__ */
|
|
2072
|
+
return /* @__PURE__ */ jsx10(
|
|
1919
2073
|
"div",
|
|
1920
2074
|
{
|
|
1921
2075
|
className: `flex items-center ${className}`,
|
|
1922
2076
|
title: `Volume: ${formatDb(localValue)}`,
|
|
1923
|
-
children: /* @__PURE__ */
|
|
2077
|
+
children: /* @__PURE__ */ jsx10(
|
|
1924
2078
|
"input",
|
|
1925
2079
|
{
|
|
1926
2080
|
type: "range",
|
|
@@ -1960,8 +2114,8 @@ var VolumeSlider = ({
|
|
|
1960
2114
|
};
|
|
1961
2115
|
|
|
1962
2116
|
// src/components/PanSlider.tsx
|
|
1963
|
-
import { useCallback as
|
|
1964
|
-
import { jsx as
|
|
2117
|
+
import { useCallback as useCallback5, useState as useState8, useRef as useRef6, useEffect as useEffect6 } from "react";
|
|
2118
|
+
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
1965
2119
|
function toPanDisplay(value) {
|
|
1966
2120
|
if (Math.abs(value) < 0.02) {
|
|
1967
2121
|
return "Center";
|
|
@@ -1972,10 +2126,10 @@ function toPanDisplay(value) {
|
|
|
1972
2126
|
function useDebouncedCallback2(callback, delay) {
|
|
1973
2127
|
const timeoutRef = useRef6(null);
|
|
1974
2128
|
const callbackRef = useRef6(callback);
|
|
1975
|
-
|
|
2129
|
+
useEffect6(() => {
|
|
1976
2130
|
callbackRef.current = callback;
|
|
1977
2131
|
}, [callback]);
|
|
1978
|
-
const debouncedCallback =
|
|
2132
|
+
const debouncedCallback = useCallback5(
|
|
1979
2133
|
(...args) => {
|
|
1980
2134
|
if (timeoutRef.current) {
|
|
1981
2135
|
clearTimeout(timeoutRef.current);
|
|
@@ -1986,7 +2140,7 @@ function useDebouncedCallback2(callback, delay) {
|
|
|
1986
2140
|
},
|
|
1987
2141
|
[delay]
|
|
1988
2142
|
);
|
|
1989
|
-
|
|
2143
|
+
useEffect6(() => {
|
|
1990
2144
|
return () => {
|
|
1991
2145
|
if (timeoutRef.current) {
|
|
1992
2146
|
clearTimeout(timeoutRef.current);
|
|
@@ -2001,15 +2155,15 @@ var PanSlider = ({
|
|
|
2001
2155
|
disabled = false,
|
|
2002
2156
|
className = ""
|
|
2003
2157
|
}) => {
|
|
2004
|
-
const [localValue, setLocalValue] =
|
|
2005
|
-
const [isDragging, setIsDragging] =
|
|
2006
|
-
|
|
2158
|
+
const [localValue, setLocalValue] = useState8(value);
|
|
2159
|
+
const [isDragging, setIsDragging] = useState8(false);
|
|
2160
|
+
useEffect6(() => {
|
|
2007
2161
|
if (!isDragging) {
|
|
2008
2162
|
setLocalValue(value);
|
|
2009
2163
|
}
|
|
2010
2164
|
}, [value, isDragging]);
|
|
2011
2165
|
const debouncedOnChange = useDebouncedCallback2(onChange, 50);
|
|
2012
|
-
const handleChange =
|
|
2166
|
+
const handleChange = useCallback5(
|
|
2013
2167
|
(e) => {
|
|
2014
2168
|
const newValue = parseFloat(e.target.value);
|
|
2015
2169
|
setLocalValue(newValue);
|
|
@@ -2017,23 +2171,23 @@ var PanSlider = ({
|
|
|
2017
2171
|
},
|
|
2018
2172
|
[debouncedOnChange]
|
|
2019
2173
|
);
|
|
2020
|
-
const handleMouseDown =
|
|
2174
|
+
const handleMouseDown = useCallback5(() => {
|
|
2021
2175
|
setIsDragging(true);
|
|
2022
2176
|
}, []);
|
|
2023
|
-
const handleMouseUp =
|
|
2177
|
+
const handleMouseUp = useCallback5(() => {
|
|
2024
2178
|
setIsDragging(false);
|
|
2025
2179
|
onChange(localValue);
|
|
2026
2180
|
}, [localValue, onChange]);
|
|
2027
|
-
const handleDoubleClick =
|
|
2181
|
+
const handleDoubleClick = useCallback5(() => {
|
|
2028
2182
|
setLocalValue(0);
|
|
2029
2183
|
onChange(0);
|
|
2030
2184
|
}, [onChange]);
|
|
2031
|
-
return /* @__PURE__ */
|
|
2185
|
+
return /* @__PURE__ */ jsx11(
|
|
2032
2186
|
"div",
|
|
2033
2187
|
{
|
|
2034
2188
|
className: `flex items-center ${className}`,
|
|
2035
2189
|
title: `Pan: ${toPanDisplay(localValue)}`,
|
|
2036
|
-
children: /* @__PURE__ */
|
|
2190
|
+
children: /* @__PURE__ */ jsx11(
|
|
2037
2191
|
"input",
|
|
2038
2192
|
{
|
|
2039
2193
|
type: "range",
|
|
@@ -2074,8 +2228,8 @@ var PanSlider = ({
|
|
|
2074
2228
|
};
|
|
2075
2229
|
|
|
2076
2230
|
// src/components/SorceryProgressBar.tsx
|
|
2077
|
-
import { useState as
|
|
2078
|
-
import { jsx as
|
|
2231
|
+
import { useState as useState9, useEffect as useEffect7, useRef as useRef7 } from "react";
|
|
2232
|
+
import { jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
2079
2233
|
function calculateTimeBasedTarget(elapsedMs, estimatedDurationMs) {
|
|
2080
2234
|
const t = elapsedMs / estimatedDurationMs;
|
|
2081
2235
|
if (t <= 0) return 0;
|
|
@@ -2120,7 +2274,7 @@ function SorceryProgressBar({
|
|
|
2120
2274
|
onProgressChange,
|
|
2121
2275
|
estimatedDurationMs
|
|
2122
2276
|
}) {
|
|
2123
|
-
const [progress, setProgress] =
|
|
2277
|
+
const [progress, setProgress] = useState9(initialProgress);
|
|
2124
2278
|
const timerRef = useRef7(null);
|
|
2125
2279
|
const isLoadingRef = useRef7(false);
|
|
2126
2280
|
const hasStartedRef = useRef7(false);
|
|
@@ -2133,7 +2287,7 @@ function SorceryProgressBar({
|
|
|
2133
2287
|
initialProgressRef.current = initialProgress;
|
|
2134
2288
|
const estimatedDurationMsRef = useRef7(estimatedDurationMs);
|
|
2135
2289
|
estimatedDurationMsRef.current = estimatedDurationMs;
|
|
2136
|
-
|
|
2290
|
+
useEffect7(() => {
|
|
2137
2291
|
const wasLoading = isLoadingRef.current;
|
|
2138
2292
|
isLoadingRef.current = isLoading;
|
|
2139
2293
|
if (isLoading && !wasLoading) {
|
|
@@ -2195,12 +2349,12 @@ function SorceryProgressBar({
|
|
|
2195
2349
|
const displayProgress = Math.floor(progress);
|
|
2196
2350
|
const isComplete = !isLoading && progress === 100;
|
|
2197
2351
|
const transitionDuration = progress < 50 ? "300ms" : progress < 80 ? "500ms" : "700ms";
|
|
2198
|
-
return /* @__PURE__ */
|
|
2352
|
+
return /* @__PURE__ */ jsxs8(
|
|
2199
2353
|
"div",
|
|
2200
2354
|
{
|
|
2201
2355
|
className: `relative w-full ${heightClass} bg-sas-panel-alt border border-sas-border rounded-sm overflow-hidden shadow-inner`,
|
|
2202
2356
|
children: [
|
|
2203
|
-
/* @__PURE__ */
|
|
2357
|
+
/* @__PURE__ */ jsx12(
|
|
2204
2358
|
"div",
|
|
2205
2359
|
{
|
|
2206
2360
|
className: `
|
|
@@ -2218,13 +2372,13 @@ function SorceryProgressBar({
|
|
|
2218
2372
|
}
|
|
2219
2373
|
}
|
|
2220
2374
|
),
|
|
2221
|
-
/* @__PURE__ */
|
|
2375
|
+
/* @__PURE__ */ jsx12("div", { className: "absolute inset-0 flex items-center justify-center", children: isLoading && progress < 100 ? /* @__PURE__ */ jsxs8("span", { className: "font-mono text-xs text-sas-accent font-bold drop-shadow-md tracking-wider", children: [
|
|
2222
2376
|
statusText,
|
|
2223
2377
|
" ",
|
|
2224
2378
|
displayProgress,
|
|
2225
2379
|
"%"
|
|
2226
|
-
] }) : isComplete ? /* @__PURE__ */
|
|
2227
|
-
/* @__PURE__ */
|
|
2380
|
+
] }) : isComplete ? /* @__PURE__ */ jsx12("span", { className: "font-mono text-xs text-sas-text font-bold drop-shadow-md tracking-wider", children: completeText }) : null }),
|
|
2381
|
+
/* @__PURE__ */ jsx12(
|
|
2228
2382
|
"div",
|
|
2229
2383
|
{
|
|
2230
2384
|
className: "absolute inset-0 pointer-events-none opacity-10",
|
|
@@ -2310,7 +2464,7 @@ function parseLLMNoteResponse(content) {
|
|
|
2310
2464
|
}
|
|
2311
2465
|
|
|
2312
2466
|
// src/components/TrackRow.tsx
|
|
2313
|
-
import { Fragment, jsx as
|
|
2467
|
+
import { Fragment, jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
2314
2468
|
function TrackRow({
|
|
2315
2469
|
track,
|
|
2316
2470
|
prompt,
|
|
@@ -2371,6 +2525,8 @@ function TrackRow({
|
|
|
2371
2525
|
}) {
|
|
2372
2526
|
const { muted: isMuted, solo: isSoloed, volume: currentVolume, pan: currentPan } = runtimeState;
|
|
2373
2527
|
const [confirmDelete, setConfirmDelete] = React9.useState(false);
|
|
2528
|
+
const freeze = useTrackFreeze(externalFxHost, track.id);
|
|
2529
|
+
const freezeBadge = freeze.state?.frozen === true ? freeze.state.missingDeps.length > 0 ? "missing" : freeze.state.stale ? "stale" : "frozen" : null;
|
|
2374
2530
|
const needsGeneration = !!(prompt?.trim() && !hasMidi && !isGenerating);
|
|
2375
2531
|
const hasFxActive = Object.values(fxDetailState).some(
|
|
2376
2532
|
(d) => d.enabled
|
|
@@ -2380,8 +2536,8 @@ function TrackRow({
|
|
|
2380
2536
|
const handleKeyDown = promptEnterToGenerate(() => onGenerate?.(), !onGenerate);
|
|
2381
2537
|
const borderColorStyle = needsGeneration ? void 0 : accentColor;
|
|
2382
2538
|
const borderClass = needsGeneration ? "border-amber-400 animate-pulse" : "border-sas-border";
|
|
2383
|
-
return /* @__PURE__ */
|
|
2384
|
-
/* @__PURE__ */
|
|
2539
|
+
return /* @__PURE__ */ jsxs9("div", { "data-testid": "sdk-track-row-wrapper", className: "w-full", ...drag?.rowProps ?? {}, children: [
|
|
2540
|
+
/* @__PURE__ */ jsxs9(
|
|
2385
2541
|
"div",
|
|
2386
2542
|
{
|
|
2387
2543
|
"data-testid": "sdk-track-row",
|
|
@@ -2391,7 +2547,7 @@ function TrackRow({
|
|
|
2391
2547
|
borderLeftWidth: "3px"
|
|
2392
2548
|
},
|
|
2393
2549
|
children: [
|
|
2394
|
-
drag && /* @__PURE__ */
|
|
2550
|
+
drag && /* @__PURE__ */ jsx13(
|
|
2395
2551
|
"div",
|
|
2396
2552
|
{
|
|
2397
2553
|
"data-testid": "sdk-drag-handle",
|
|
@@ -2399,10 +2555,10 @@ function TrackRow({
|
|
|
2399
2555
|
className: "flex-shrink-0 self-stretch flex items-center -ml-0.5 pr-0.5 text-sas-muted/40 hover:text-sas-muted cursor-grab active:cursor-grabbing relative z-30",
|
|
2400
2556
|
title: "Drag to reorder",
|
|
2401
2557
|
"aria-label": "Drag to reorder track",
|
|
2402
|
-
children: /* @__PURE__ */
|
|
2558
|
+
children: /* @__PURE__ */ jsx13(GripVertical, { className: "w-3.5 h-3.5", strokeWidth: 2 })
|
|
2403
2559
|
}
|
|
2404
2560
|
),
|
|
2405
|
-
isGenerating && /* @__PURE__ */
|
|
2561
|
+
isGenerating && /* @__PURE__ */ jsx13("div", { className: "absolute left-0 top-0 bottom-0 right-44 z-20", children: /* @__PURE__ */ jsx13(
|
|
2406
2562
|
SorceryProgressBar,
|
|
2407
2563
|
{
|
|
2408
2564
|
isLoading: true,
|
|
@@ -2413,14 +2569,14 @@ function TrackRow({
|
|
|
2413
2569
|
estimatedDurationMs: estimatedGenerationMs
|
|
2414
2570
|
}
|
|
2415
2571
|
) }),
|
|
2416
|
-
/* @__PURE__ */
|
|
2572
|
+
/* @__PURE__ */ jsxs9(
|
|
2417
2573
|
"div",
|
|
2418
2574
|
{
|
|
2419
2575
|
"data-testid": "sdk-track-content",
|
|
2420
2576
|
className: `flex flex-col flex-1 min-w-0 relative z-10 transition-opacity ${soloedOut ? "opacity-40" : ""}`,
|
|
2421
2577
|
title: soloedOut ? "Silenced \u2014 another track is soloed" : void 0,
|
|
2422
2578
|
children: [
|
|
2423
|
-
contentSlot ? contentSlot : onPromptChange ? /* @__PURE__ */
|
|
2579
|
+
contentSlot ? contentSlot : onPromptChange ? /* @__PURE__ */ jsx13(
|
|
2424
2580
|
"input",
|
|
2425
2581
|
{
|
|
2426
2582
|
type: "text",
|
|
@@ -2433,10 +2589,10 @@ function TrackRow({
|
|
|
2433
2589
|
className: "sas-input w-full px-2 py-1 text-xs disabled:opacity-50 disabled:cursor-not-allowed"
|
|
2434
2590
|
}
|
|
2435
2591
|
) : null,
|
|
2436
|
-
/* @__PURE__ */
|
|
2437
|
-
track.name && /* @__PURE__ */
|
|
2438
|
-
/* @__PURE__ */
|
|
2439
|
-
/* @__PURE__ */
|
|
2592
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2 mt-1", children: [
|
|
2593
|
+
track.name && /* @__PURE__ */ jsx13("span", { className: "text-[10px] text-sas-muted/60 truncate pl-2 flex-shrink-0 max-w-[80px]", title: track.name, children: track.name }),
|
|
2594
|
+
/* @__PURE__ */ jsx13("span", { className: "text-[9px] text-sas-muted/50 flex-shrink-0", children: "vol:" }),
|
|
2595
|
+
/* @__PURE__ */ jsx13(
|
|
2440
2596
|
VolumeSlider,
|
|
2441
2597
|
{
|
|
2442
2598
|
value: currentVolume,
|
|
@@ -2445,8 +2601,8 @@ function TrackRow({
|
|
|
2445
2601
|
className: "flex-1 min-w-[40px]"
|
|
2446
2602
|
}
|
|
2447
2603
|
),
|
|
2448
|
-
/* @__PURE__ */
|
|
2449
|
-
/* @__PURE__ */
|
|
2604
|
+
/* @__PURE__ */ jsx13("span", { className: "text-[9px] text-sas-muted/50 flex-shrink-0", children: "pan:" }),
|
|
2605
|
+
/* @__PURE__ */ jsx13(
|
|
2450
2606
|
PanSlider,
|
|
2451
2607
|
{
|
|
2452
2608
|
value: currentPan,
|
|
@@ -2459,27 +2615,27 @@ function TrackRow({
|
|
|
2459
2615
|
]
|
|
2460
2616
|
}
|
|
2461
2617
|
),
|
|
2462
|
-
error && /* @__PURE__ */
|
|
2618
|
+
error && /* @__PURE__ */ jsx13(
|
|
2463
2619
|
"div",
|
|
2464
2620
|
{
|
|
2465
2621
|
"data-testid": "sdk-error-indicator",
|
|
2466
2622
|
className: "flex-shrink-0 relative z-10 self-stretch flex items-center px-1 group cursor-help",
|
|
2467
2623
|
title: error,
|
|
2468
|
-
children: /* @__PURE__ */
|
|
2469
|
-
/* @__PURE__ */
|
|
2624
|
+
children: /* @__PURE__ */ jsxs9("div", { className: "relative", children: [
|
|
2625
|
+
/* @__PURE__ */ jsx13(
|
|
2470
2626
|
AlertCircle,
|
|
2471
2627
|
{
|
|
2472
2628
|
className: "w-5 h-5 text-red-500 animate-pulse",
|
|
2473
2629
|
strokeWidth: 2.5
|
|
2474
2630
|
}
|
|
2475
2631
|
),
|
|
2476
|
-
/* @__PURE__ */
|
|
2632
|
+
/* @__PURE__ */ jsx13("div", { className: "absolute bottom-full left-1/2 -translate-x-1/2 mb-2 px-2 py-1 bg-red-900/95 text-red-100 text-xs rounded shadow-lg whitespace-nowrap opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none z-50 max-w-[200px] truncate", children: error })
|
|
2477
2633
|
] })
|
|
2478
2634
|
}
|
|
2479
2635
|
),
|
|
2480
|
-
/* @__PURE__ */
|
|
2481
|
-
/* @__PURE__ */
|
|
2482
|
-
onGenerate && /* @__PURE__ */
|
|
2636
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex flex-col gap-0.5 flex-shrink-0 relative z-30 justify-center", children: [
|
|
2637
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex gap-1 items-center", children: [
|
|
2638
|
+
onGenerate && /* @__PURE__ */ jsx13(
|
|
2483
2639
|
"button",
|
|
2484
2640
|
{
|
|
2485
2641
|
"data-testid": "sdk-generate-button",
|
|
@@ -2490,7 +2646,7 @@ function TrackRow({
|
|
|
2490
2646
|
children: "Create"
|
|
2491
2647
|
}
|
|
2492
2648
|
),
|
|
2493
|
-
onCopy && /* @__PURE__ */
|
|
2649
|
+
onCopy && /* @__PURE__ */ jsx13(
|
|
2494
2650
|
"button",
|
|
2495
2651
|
{
|
|
2496
2652
|
"data-testid": "sdk-copy-button",
|
|
@@ -2501,7 +2657,7 @@ function TrackRow({
|
|
|
2501
2657
|
children: "Copy"
|
|
2502
2658
|
}
|
|
2503
2659
|
),
|
|
2504
|
-
/* @__PURE__ */
|
|
2660
|
+
/* @__PURE__ */ jsx13(
|
|
2505
2661
|
"button",
|
|
2506
2662
|
{
|
|
2507
2663
|
"data-testid": "sdk-mute-button",
|
|
@@ -2511,7 +2667,7 @@ function TrackRow({
|
|
|
2511
2667
|
children: "M"
|
|
2512
2668
|
}
|
|
2513
2669
|
),
|
|
2514
|
-
onDelete && /* @__PURE__ */
|
|
2670
|
+
onDelete && /* @__PURE__ */ jsx13(
|
|
2515
2671
|
"button",
|
|
2516
2672
|
{
|
|
2517
2673
|
"data-testid": "sdk-delete-button",
|
|
@@ -2522,8 +2678,8 @@ function TrackRow({
|
|
|
2522
2678
|
}
|
|
2523
2679
|
)
|
|
2524
2680
|
] }),
|
|
2525
|
-
/* @__PURE__ */
|
|
2526
|
-
onShuffle && /* @__PURE__ */
|
|
2681
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex gap-1 items-center", children: [
|
|
2682
|
+
onShuffle && /* @__PURE__ */ jsx13(
|
|
2527
2683
|
"button",
|
|
2528
2684
|
{
|
|
2529
2685
|
"data-testid": "sdk-shuffle-button",
|
|
@@ -2534,7 +2690,16 @@ function TrackRow({
|
|
|
2534
2690
|
children: "Shuffle"
|
|
2535
2691
|
}
|
|
2536
2692
|
),
|
|
2537
|
-
|
|
2693
|
+
freezeBadge && /* @__PURE__ */ jsx13(
|
|
2694
|
+
"span",
|
|
2695
|
+
{
|
|
2696
|
+
"data-testid": "sdk-track-freeze-badge",
|
|
2697
|
+
className: `px-1 py-0.5 text-xs leading-none rounded-sm self-center ${freezeBadge === "frozen" ? "text-sas-accent" : "text-amber-400"}`,
|
|
2698
|
+
title: freezeBadge === "frozen" ? "Frozen \u2014 playing the rendered stem (mixer stays live)" : freezeBadge === "stale" ? "Frozen (stale) \u2014 sound edited since the stem rendered; re-freeze in the drawer" : `Frozen \u2014 plugin(s) missing on this machine: ${freeze.state?.missingDeps.map((d) => d.name).join(", ")}`,
|
|
2699
|
+
children: freezeBadge === "frozen" ? "\u2744" : freezeBadge === "stale" ? "\u26A0\u2744" : "\u2744!"
|
|
2700
|
+
}
|
|
2701
|
+
),
|
|
2702
|
+
onToggleFxDrawer && /* @__PURE__ */ jsx13(
|
|
2538
2703
|
"button",
|
|
2539
2704
|
{
|
|
2540
2705
|
"data-testid": "sdk-fx-button",
|
|
@@ -2545,7 +2710,7 @@ function TrackRow({
|
|
|
2545
2710
|
children: "FX"
|
|
2546
2711
|
}
|
|
2547
2712
|
),
|
|
2548
|
-
/* @__PURE__ */
|
|
2713
|
+
/* @__PURE__ */ jsx13(
|
|
2549
2714
|
"button",
|
|
2550
2715
|
{
|
|
2551
2716
|
"data-testid": "sdk-solo-button",
|
|
@@ -2556,7 +2721,7 @@ function TrackRow({
|
|
|
2556
2721
|
children: "S"
|
|
2557
2722
|
}
|
|
2558
2723
|
),
|
|
2559
|
-
onToggleDrawer && /* @__PURE__ */
|
|
2724
|
+
onToggleDrawer && /* @__PURE__ */ jsx13(
|
|
2560
2725
|
"button",
|
|
2561
2726
|
{
|
|
2562
2727
|
"data-testid": "sdk-plugin-button",
|
|
@@ -2564,7 +2729,7 @@ function TrackRow({
|
|
|
2564
2729
|
disabled: isGenerating,
|
|
2565
2730
|
className: `px-1.5 py-0.5 text-xs font-bold rounded transition-colors ${isGenerating ? "bg-sas-panel text-sas-muted/50 cursor-not-allowed" : soundTabOpen ? "bg-sas-accent border-sas-accent text-sas-bg" : instrumentMissing ? "bg-amber-500/20 text-amber-400 hover:bg-amber-500/40" : "bg-sas-panel-alt text-sas-muted hover:bg-sas-border"}`,
|
|
2566
2731
|
title: `Sound \u2014 presets & history${instrumentMissing ? " (instrument missing)" : ""}`,
|
|
2567
|
-
children: /* @__PURE__ */
|
|
2732
|
+
children: /* @__PURE__ */ jsx13(ChevronDown, { className: "w-3 h-3", strokeWidth: 2.5 })
|
|
2568
2733
|
}
|
|
2569
2734
|
)
|
|
2570
2735
|
] })
|
|
@@ -2572,13 +2737,13 @@ function TrackRow({
|
|
|
2572
2737
|
]
|
|
2573
2738
|
}
|
|
2574
2739
|
),
|
|
2575
|
-
levels && /* @__PURE__ */
|
|
2576
|
-
drawerOpen && /* @__PURE__ */
|
|
2740
|
+
levels && /* @__PURE__ */ jsx13(TrackMeterStrip, { levels, trackId: track.id, roundBottom: !drawerOpen }),
|
|
2741
|
+
drawerOpen && /* @__PURE__ */ jsx13(
|
|
2577
2742
|
"div",
|
|
2578
2743
|
{
|
|
2579
2744
|
"data-testid": "sdk-track-drawer",
|
|
2580
2745
|
className: "border border-t-0 border-sas-border bg-sas-bg rounded-b-sm px-3 py-2 max-h-[260px] overflow-y-auto",
|
|
2581
|
-
children: /* @__PURE__ */
|
|
2746
|
+
children: /* @__PURE__ */ jsx13(
|
|
2582
2747
|
TrackDrawer,
|
|
2583
2748
|
{
|
|
2584
2749
|
activeTab: drawerTab,
|
|
@@ -2589,6 +2754,7 @@ function TrackRow({
|
|
|
2589
2754
|
onFxPresetChange,
|
|
2590
2755
|
onFxDryWetChange,
|
|
2591
2756
|
externalFxHost,
|
|
2757
|
+
freeze,
|
|
2592
2758
|
fxDisabled: isGenerating,
|
|
2593
2759
|
instruments: availableInstruments,
|
|
2594
2760
|
currentPluginId: currentInstrumentPluginId ?? null,
|
|
@@ -2615,13 +2781,13 @@ function TrackRow({
|
|
|
2615
2781
|
)
|
|
2616
2782
|
}
|
|
2617
2783
|
),
|
|
2618
|
-
/* @__PURE__ */
|
|
2784
|
+
/* @__PURE__ */ jsx13(
|
|
2619
2785
|
ConfirmDialog,
|
|
2620
2786
|
{
|
|
2621
2787
|
open: confirmDelete,
|
|
2622
2788
|
title: "Delete track?",
|
|
2623
|
-
message: /* @__PURE__ */
|
|
2624
|
-
/* @__PURE__ */
|
|
2789
|
+
message: /* @__PURE__ */ jsxs9(Fragment, { children: [
|
|
2790
|
+
/* @__PURE__ */ jsx13("span", { className: "text-sas-text", children: track.name?.trim() || "This track" }),
|
|
2625
2791
|
" will be permanently removed from this scene. This cannot be undone."
|
|
2626
2792
|
] }),
|
|
2627
2793
|
confirmLabel: "Delete",
|
|
@@ -2638,12 +2804,12 @@ function TrackRow({
|
|
|
2638
2804
|
|
|
2639
2805
|
// src/components/CrossfadeTrackRow.tsx
|
|
2640
2806
|
import React10 from "react";
|
|
2641
|
-
import { Fragment as Fragment2, jsx as
|
|
2807
|
+
import { Fragment as Fragment2, jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
2642
2808
|
function LayerCaption({ tag, layer }) {
|
|
2643
|
-
return /* @__PURE__ */
|
|
2644
|
-
/* @__PURE__ */
|
|
2645
|
-
/* @__PURE__ */
|
|
2646
|
-
layer.soundLabel && /* @__PURE__ */
|
|
2809
|
+
return /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-1.5 min-w-0 px-2 py-0.5", children: [
|
|
2810
|
+
/* @__PURE__ */ jsx14("span", { className: "text-[9px] font-bold uppercase tracking-wide text-sas-accent flex-shrink-0", children: tag }),
|
|
2811
|
+
/* @__PURE__ */ jsx14("span", { className: "text-[11px] text-sas-text truncate", title: layer.sourceName ?? layer.name, children: layer.sourceName ?? layer.name }),
|
|
2812
|
+
layer.soundLabel && /* @__PURE__ */ jsxs10("span", { className: "text-[9px] text-sas-muted/60 truncate flex-shrink-0", title: layer.soundLabel, children: [
|
|
2647
2813
|
"\xB7 ",
|
|
2648
2814
|
layer.soundLabel
|
|
2649
2815
|
] })
|
|
@@ -2663,7 +2829,7 @@ function CrossfadeTrackRow({
|
|
|
2663
2829
|
accentColor = "#9333EA"
|
|
2664
2830
|
}) {
|
|
2665
2831
|
const [confirmDelete, setConfirmDelete] = React10.useState(false);
|
|
2666
|
-
const renderLayer = (layer, slot, tag) => /* @__PURE__ */
|
|
2832
|
+
const renderLayer = (layer, slot, tag) => /* @__PURE__ */ jsx14(
|
|
2667
2833
|
TrackRow,
|
|
2668
2834
|
{
|
|
2669
2835
|
track: { id: layer.trackId, name: "", role: layer.role },
|
|
@@ -2673,23 +2839,23 @@ function CrossfadeTrackRow({
|
|
|
2673
2839
|
drawerTab: "fx",
|
|
2674
2840
|
levels,
|
|
2675
2841
|
accentColor,
|
|
2676
|
-
contentSlot: /* @__PURE__ */
|
|
2842
|
+
contentSlot: /* @__PURE__ */ jsx14(LayerCaption, { tag, layer }),
|
|
2677
2843
|
onMuteToggle,
|
|
2678
2844
|
onSoloToggle,
|
|
2679
2845
|
onVolumeChange: (v) => onVolumeChange(slot, v),
|
|
2680
2846
|
onPanChange: (p) => onPanChange(slot, p)
|
|
2681
2847
|
}
|
|
2682
2848
|
);
|
|
2683
|
-
return /* @__PURE__ */
|
|
2849
|
+
return /* @__PURE__ */ jsxs10(
|
|
2684
2850
|
"div",
|
|
2685
2851
|
{
|
|
2686
2852
|
"data-testid": "crossfade-track-row",
|
|
2687
2853
|
className: "w-full rounded-sm border border-sas-border bg-sas-panel/40 overflow-hidden",
|
|
2688
2854
|
style: { borderLeftColor: accentColor, borderLeftWidth: "3px" },
|
|
2689
2855
|
children: [
|
|
2690
|
-
/* @__PURE__ */
|
|
2691
|
-
/* @__PURE__ */
|
|
2692
|
-
/* @__PURE__ */
|
|
2856
|
+
/* @__PURE__ */ jsxs10("div", { className: "flex items-center justify-between px-2 py-1 bg-sas-panel-alt/60", children: [
|
|
2857
|
+
/* @__PURE__ */ jsx14("span", { className: "text-[10px] font-bold uppercase tracking-wide", style: { color: accentColor }, children: "\u21C4 Crossfade" }),
|
|
2858
|
+
/* @__PURE__ */ jsx14(
|
|
2693
2859
|
"button",
|
|
2694
2860
|
{
|
|
2695
2861
|
"data-testid": "crossfade-delete-button",
|
|
@@ -2702,8 +2868,8 @@ function CrossfadeTrackRow({
|
|
|
2702
2868
|
)
|
|
2703
2869
|
] }),
|
|
2704
2870
|
renderLayer(origin, "origin", "Origin"),
|
|
2705
|
-
/* @__PURE__ */
|
|
2706
|
-
/* @__PURE__ */
|
|
2871
|
+
/* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-2 px-3 py-1.5", "data-testid": "crossfade-slider-row", children: [
|
|
2872
|
+
/* @__PURE__ */ jsx14(
|
|
2707
2873
|
"span",
|
|
2708
2874
|
{
|
|
2709
2875
|
className: "text-[9px] text-sas-muted/60 truncate max-w-[70px] text-right flex-shrink-0",
|
|
@@ -2711,7 +2877,7 @@ function CrossfadeTrackRow({
|
|
|
2711
2877
|
children: origin.sourceName ?? origin.name
|
|
2712
2878
|
}
|
|
2713
2879
|
),
|
|
2714
|
-
/* @__PURE__ */
|
|
2880
|
+
/* @__PURE__ */ jsx14(
|
|
2715
2881
|
"input",
|
|
2716
2882
|
{
|
|
2717
2883
|
type: "range",
|
|
@@ -2727,7 +2893,7 @@ function CrossfadeTrackRow({
|
|
|
2727
2893
|
"aria-label": "Crossfade position"
|
|
2728
2894
|
}
|
|
2729
2895
|
),
|
|
2730
|
-
/* @__PURE__ */
|
|
2896
|
+
/* @__PURE__ */ jsx14(
|
|
2731
2897
|
"span",
|
|
2732
2898
|
{
|
|
2733
2899
|
className: "text-[9px] text-sas-muted/60 truncate max-w-[70px] flex-shrink-0",
|
|
@@ -2737,12 +2903,12 @@ function CrossfadeTrackRow({
|
|
|
2737
2903
|
)
|
|
2738
2904
|
] }),
|
|
2739
2905
|
renderLayer(target, "target", "Target"),
|
|
2740
|
-
/* @__PURE__ */
|
|
2906
|
+
/* @__PURE__ */ jsx14(
|
|
2741
2907
|
ConfirmDialog,
|
|
2742
2908
|
{
|
|
2743
2909
|
open: confirmDelete,
|
|
2744
2910
|
title: "Delete crossfade?",
|
|
2745
|
-
message: /* @__PURE__ */
|
|
2911
|
+
message: /* @__PURE__ */ jsx14(Fragment2, { children: "This crossfade pair (both layers) will be permanently removed from this scene. This cannot be undone." }),
|
|
2746
2912
|
confirmLabel: "Delete",
|
|
2747
2913
|
onConfirm: () => {
|
|
2748
2914
|
setConfirmDelete(false);
|
|
@@ -3016,21 +3182,21 @@ function defaultFadeGesture(role) {
|
|
|
3016
3182
|
|
|
3017
3183
|
// src/components/FadeTrackRow.tsx
|
|
3018
3184
|
import React11 from "react";
|
|
3019
|
-
import { Fragment as Fragment3, jsx as
|
|
3185
|
+
import { Fragment as Fragment3, jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
3020
3186
|
function FadeCaption({
|
|
3021
3187
|
layer,
|
|
3022
3188
|
direction,
|
|
3023
3189
|
gesture
|
|
3024
3190
|
}) {
|
|
3025
3191
|
const tag = direction === "in" ? "Fade in" : "Fade out";
|
|
3026
|
-
return /* @__PURE__ */
|
|
3027
|
-
/* @__PURE__ */
|
|
3028
|
-
/* @__PURE__ */
|
|
3029
|
-
layer.soundLabel && /* @__PURE__ */
|
|
3192
|
+
return /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-1.5 min-w-0 px-2 py-0.5", children: [
|
|
3193
|
+
/* @__PURE__ */ jsx15("span", { className: "text-[9px] font-bold uppercase tracking-wide text-sas-accent flex-shrink-0", children: tag }),
|
|
3194
|
+
/* @__PURE__ */ jsx15("span", { className: "text-[11px] text-sas-text truncate", title: layer.sourceName ?? layer.name, children: layer.sourceName ?? layer.name }),
|
|
3195
|
+
layer.soundLabel && /* @__PURE__ */ jsxs11("span", { className: "text-[9px] text-sas-muted/60 truncate flex-shrink-0", title: layer.soundLabel, children: [
|
|
3030
3196
|
"\xB7 ",
|
|
3031
3197
|
layer.soundLabel
|
|
3032
3198
|
] }),
|
|
3033
|
-
/* @__PURE__ */
|
|
3199
|
+
/* @__PURE__ */ jsxs11("span", { className: "text-[9px] text-sas-muted/50 flex-shrink-0", title: `Fade gesture: ${gesture}`, children: [
|
|
3034
3200
|
"\xB7 ",
|
|
3035
3201
|
gesture
|
|
3036
3202
|
] })
|
|
@@ -3056,15 +3222,15 @@ function FadeTrackRow({
|
|
|
3056
3222
|
const rightLabel = direction === "in" ? layer.sourceName ?? layer.name : "(silent)";
|
|
3057
3223
|
const verb = effect && effect !== "fade" ? effect.charAt(0).toUpperCase() + effect.slice(1) : "Fade";
|
|
3058
3224
|
const badge = direction === "in" ? `\u2197 ${verb} in` : `\u2198 ${verb} out`;
|
|
3059
|
-
return /* @__PURE__ */
|
|
3225
|
+
return /* @__PURE__ */ jsxs11(
|
|
3060
3226
|
"div",
|
|
3061
3227
|
{
|
|
3062
3228
|
"data-testid": "fade-track-row",
|
|
3063
3229
|
className: "w-full rounded-sm border border-sas-border bg-sas-panel/40 overflow-hidden",
|
|
3064
3230
|
style: { borderLeftColor: accentColor, borderLeftWidth: "3px" },
|
|
3065
3231
|
children: [
|
|
3066
|
-
/* @__PURE__ */
|
|
3067
|
-
/* @__PURE__ */
|
|
3232
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex items-center justify-between px-2 py-1 bg-sas-panel-alt/60", children: [
|
|
3233
|
+
/* @__PURE__ */ jsx15(
|
|
3068
3234
|
"span",
|
|
3069
3235
|
{
|
|
3070
3236
|
"data-testid": "fade-direction-badge",
|
|
@@ -3073,7 +3239,7 @@ function FadeTrackRow({
|
|
|
3073
3239
|
children: badge
|
|
3074
3240
|
}
|
|
3075
3241
|
),
|
|
3076
|
-
/* @__PURE__ */
|
|
3242
|
+
/* @__PURE__ */ jsx15(
|
|
3077
3243
|
"button",
|
|
3078
3244
|
{
|
|
3079
3245
|
"data-testid": "fade-delete-button",
|
|
@@ -3085,7 +3251,7 @@ function FadeTrackRow({
|
|
|
3085
3251
|
}
|
|
3086
3252
|
)
|
|
3087
3253
|
] }),
|
|
3088
|
-
/* @__PURE__ */
|
|
3254
|
+
/* @__PURE__ */ jsx15(
|
|
3089
3255
|
TrackRow,
|
|
3090
3256
|
{
|
|
3091
3257
|
track: { id: layer.trackId, name: "", role: layer.role },
|
|
@@ -3095,15 +3261,15 @@ function FadeTrackRow({
|
|
|
3095
3261
|
drawerTab: "fx",
|
|
3096
3262
|
levels,
|
|
3097
3263
|
accentColor,
|
|
3098
|
-
contentSlot: /* @__PURE__ */
|
|
3264
|
+
contentSlot: /* @__PURE__ */ jsx15(FadeCaption, { layer, direction, gesture }),
|
|
3099
3265
|
onMuteToggle,
|
|
3100
3266
|
onSoloToggle,
|
|
3101
3267
|
onVolumeChange,
|
|
3102
3268
|
onPanChange
|
|
3103
3269
|
}
|
|
3104
3270
|
),
|
|
3105
|
-
/* @__PURE__ */
|
|
3106
|
-
/* @__PURE__ */
|
|
3271
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-2 px-3 py-1.5", "data-testid": "fade-slider-row", children: [
|
|
3272
|
+
/* @__PURE__ */ jsx15(
|
|
3107
3273
|
"span",
|
|
3108
3274
|
{
|
|
3109
3275
|
className: "text-[9px] text-sas-muted/60 truncate max-w-[70px] text-right flex-shrink-0",
|
|
@@ -3111,7 +3277,7 @@ function FadeTrackRow({
|
|
|
3111
3277
|
children: leftLabel
|
|
3112
3278
|
}
|
|
3113
3279
|
),
|
|
3114
|
-
/* @__PURE__ */
|
|
3280
|
+
/* @__PURE__ */ jsx15(
|
|
3115
3281
|
"input",
|
|
3116
3282
|
{
|
|
3117
3283
|
type: "range",
|
|
@@ -3127,7 +3293,7 @@ function FadeTrackRow({
|
|
|
3127
3293
|
"aria-label": "Fade position"
|
|
3128
3294
|
}
|
|
3129
3295
|
),
|
|
3130
|
-
/* @__PURE__ */
|
|
3296
|
+
/* @__PURE__ */ jsx15(
|
|
3131
3297
|
"span",
|
|
3132
3298
|
{
|
|
3133
3299
|
className: "text-[9px] text-sas-muted/60 truncate max-w-[70px] flex-shrink-0",
|
|
@@ -3136,12 +3302,12 @@ function FadeTrackRow({
|
|
|
3136
3302
|
}
|
|
3137
3303
|
)
|
|
3138
3304
|
] }),
|
|
3139
|
-
/* @__PURE__ */
|
|
3305
|
+
/* @__PURE__ */ jsx15(
|
|
3140
3306
|
ConfirmDialog,
|
|
3141
3307
|
{
|
|
3142
3308
|
open: confirmDelete,
|
|
3143
3309
|
title: "Delete fade?",
|
|
3144
|
-
message: /* @__PURE__ */
|
|
3310
|
+
message: /* @__PURE__ */ jsx15(Fragment3, { children: "This fade track will be permanently removed from this scene. This cannot be undone." }),
|
|
3145
3311
|
confirmLabel: "Delete",
|
|
3146
3312
|
onConfirm: () => {
|
|
3147
3313
|
setConfirmDelete(false);
|
|
@@ -3158,20 +3324,20 @@ function FadeTrackRow({
|
|
|
3158
3324
|
|
|
3159
3325
|
// src/components/GroupFadeTrackRow.tsx
|
|
3160
3326
|
import React12 from "react";
|
|
3161
|
-
import { Fragment as Fragment4, jsx as
|
|
3327
|
+
import { Fragment as Fragment4, jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
3162
3328
|
function MemberCaption({
|
|
3163
3329
|
member,
|
|
3164
3330
|
direction
|
|
3165
3331
|
}) {
|
|
3166
3332
|
const tag = direction === "in" ? "Fade in" : "Fade out";
|
|
3167
|
-
return /* @__PURE__ */
|
|
3168
|
-
member.memberLabel && /* @__PURE__ */
|
|
3169
|
-
/* @__PURE__ */
|
|
3170
|
-
member.soundLabel && /* @__PURE__ */
|
|
3333
|
+
return /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-1.5 min-w-0 px-2 py-0.5", children: [
|
|
3334
|
+
member.memberLabel && /* @__PURE__ */ jsx16("span", { className: "text-[9px] font-bold uppercase tracking-wide text-sas-accent flex-shrink-0", children: member.memberLabel }),
|
|
3335
|
+
/* @__PURE__ */ jsx16("span", { className: "text-[11px] text-sas-text truncate", title: member.sourceName ?? member.name, children: member.sourceName ?? member.name }),
|
|
3336
|
+
member.soundLabel && /* @__PURE__ */ jsxs12("span", { className: "text-[9px] text-sas-muted/60 truncate flex-shrink-0", title: member.soundLabel, children: [
|
|
3171
3337
|
"\xB7 ",
|
|
3172
3338
|
member.soundLabel
|
|
3173
3339
|
] }),
|
|
3174
|
-
!member.memberLabel && /* @__PURE__ */
|
|
3340
|
+
!member.memberLabel && /* @__PURE__ */ jsxs12("span", { className: "text-[9px] text-sas-muted/50 flex-shrink-0", children: [
|
|
3175
3341
|
"\xB7 ",
|
|
3176
3342
|
tag
|
|
3177
3343
|
] })
|
|
@@ -3200,16 +3366,16 @@ function GroupFadeTrackRow({
|
|
|
3200
3366
|
const badge = direction === "in" ? "\u2197 Fade in" : "\u2198 Fade out";
|
|
3201
3367
|
const leftLabel = direction === "in" ? "(silent)" : groupLabel;
|
|
3202
3368
|
const rightLabel = direction === "in" ? groupLabel : "(silent)";
|
|
3203
|
-
return /* @__PURE__ */
|
|
3369
|
+
return /* @__PURE__ */ jsxs12(
|
|
3204
3370
|
"div",
|
|
3205
3371
|
{
|
|
3206
3372
|
"data-testid": "group-fade-track-row",
|
|
3207
3373
|
className: "w-full rounded-sm border border-sas-border bg-sas-panel/40 overflow-hidden",
|
|
3208
3374
|
style: { borderLeftColor: accentColor, borderLeftWidth: "3px" },
|
|
3209
3375
|
children: [
|
|
3210
|
-
/* @__PURE__ */
|
|
3211
|
-
/* @__PURE__ */
|
|
3212
|
-
/* @__PURE__ */
|
|
3376
|
+
/* @__PURE__ */ jsxs12("div", { className: "flex items-center justify-between px-2 py-1 bg-sas-panel-alt/60 gap-2", children: [
|
|
3377
|
+
/* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-2 min-w-0", children: [
|
|
3378
|
+
/* @__PURE__ */ jsx16(
|
|
3213
3379
|
"span",
|
|
3214
3380
|
{
|
|
3215
3381
|
"data-testid": "group-fade-direction-badge",
|
|
@@ -3218,7 +3384,7 @@ function GroupFadeTrackRow({
|
|
|
3218
3384
|
children: badge
|
|
3219
3385
|
}
|
|
3220
3386
|
),
|
|
3221
|
-
/* @__PURE__ */
|
|
3387
|
+
/* @__PURE__ */ jsx16(
|
|
3222
3388
|
"span",
|
|
3223
3389
|
{
|
|
3224
3390
|
"data-testid": "group-fade-label",
|
|
@@ -3228,8 +3394,8 @@ function GroupFadeTrackRow({
|
|
|
3228
3394
|
}
|
|
3229
3395
|
)
|
|
3230
3396
|
] }),
|
|
3231
|
-
/* @__PURE__ */
|
|
3232
|
-
/* @__PURE__ */
|
|
3397
|
+
/* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-1 flex-shrink-0", children: [
|
|
3398
|
+
/* @__PURE__ */ jsx16(
|
|
3233
3399
|
"button",
|
|
3234
3400
|
{
|
|
3235
3401
|
"data-testid": "group-fade-mute-button",
|
|
@@ -3239,7 +3405,7 @@ function GroupFadeTrackRow({
|
|
|
3239
3405
|
children: "M"
|
|
3240
3406
|
}
|
|
3241
3407
|
),
|
|
3242
|
-
/* @__PURE__ */
|
|
3408
|
+
/* @__PURE__ */ jsx16(
|
|
3243
3409
|
"button",
|
|
3244
3410
|
{
|
|
3245
3411
|
"data-testid": "group-fade-solo-button",
|
|
@@ -3249,7 +3415,7 @@ function GroupFadeTrackRow({
|
|
|
3249
3415
|
children: "S"
|
|
3250
3416
|
}
|
|
3251
3417
|
),
|
|
3252
|
-
/* @__PURE__ */
|
|
3418
|
+
/* @__PURE__ */ jsx16(
|
|
3253
3419
|
"button",
|
|
3254
3420
|
{
|
|
3255
3421
|
"data-testid": "group-fade-delete-button",
|
|
@@ -3262,7 +3428,7 @@ function GroupFadeTrackRow({
|
|
|
3262
3428
|
)
|
|
3263
3429
|
] })
|
|
3264
3430
|
] }),
|
|
3265
|
-
members.map((member) => /* @__PURE__ */
|
|
3431
|
+
members.map((member) => /* @__PURE__ */ jsx16(
|
|
3266
3432
|
TrackRow,
|
|
3267
3433
|
{
|
|
3268
3434
|
track: { id: member.trackId, name: "", role: member.role },
|
|
@@ -3272,7 +3438,7 @@ function GroupFadeTrackRow({
|
|
|
3272
3438
|
drawerTab: "fx",
|
|
3273
3439
|
levels,
|
|
3274
3440
|
accentColor,
|
|
3275
|
-
contentSlot: /* @__PURE__ */
|
|
3441
|
+
contentSlot: /* @__PURE__ */ jsx16(MemberCaption, { member, direction }),
|
|
3276
3442
|
onMuteToggle: () => onMemberMuteToggle(member.trackId),
|
|
3277
3443
|
onSoloToggle: () => onMemberSoloToggle(member.trackId),
|
|
3278
3444
|
onVolumeChange: (vol) => onMemberVolumeChange(member.trackId, vol),
|
|
@@ -3280,8 +3446,8 @@ function GroupFadeTrackRow({
|
|
|
3280
3446
|
},
|
|
3281
3447
|
member.trackId
|
|
3282
3448
|
)),
|
|
3283
|
-
/* @__PURE__ */
|
|
3284
|
-
/* @__PURE__ */
|
|
3449
|
+
/* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-2 px-3 py-1.5", "data-testid": "group-fade-slider-row", children: [
|
|
3450
|
+
/* @__PURE__ */ jsx16(
|
|
3285
3451
|
"span",
|
|
3286
3452
|
{
|
|
3287
3453
|
className: "text-[9px] text-sas-muted/60 truncate max-w-[70px] text-right flex-shrink-0",
|
|
@@ -3289,7 +3455,7 @@ function GroupFadeTrackRow({
|
|
|
3289
3455
|
children: leftLabel
|
|
3290
3456
|
}
|
|
3291
3457
|
),
|
|
3292
|
-
/* @__PURE__ */
|
|
3458
|
+
/* @__PURE__ */ jsx16(
|
|
3293
3459
|
"input",
|
|
3294
3460
|
{
|
|
3295
3461
|
type: "range",
|
|
@@ -3305,7 +3471,7 @@ function GroupFadeTrackRow({
|
|
|
3305
3471
|
"aria-label": "Group fade position"
|
|
3306
3472
|
}
|
|
3307
3473
|
),
|
|
3308
|
-
/* @__PURE__ */
|
|
3474
|
+
/* @__PURE__ */ jsx16(
|
|
3309
3475
|
"span",
|
|
3310
3476
|
{
|
|
3311
3477
|
className: "text-[9px] text-sas-muted/60 truncate max-w-[70px] flex-shrink-0",
|
|
@@ -3314,12 +3480,12 @@ function GroupFadeTrackRow({
|
|
|
3314
3480
|
}
|
|
3315
3481
|
)
|
|
3316
3482
|
] }),
|
|
3317
|
-
/* @__PURE__ */
|
|
3483
|
+
/* @__PURE__ */ jsx16(
|
|
3318
3484
|
ConfirmDialog,
|
|
3319
3485
|
{
|
|
3320
3486
|
open: confirmDelete,
|
|
3321
3487
|
title: "Delete group fade?",
|
|
3322
|
-
message: /* @__PURE__ */
|
|
3488
|
+
message: /* @__PURE__ */ jsxs12(Fragment4, { children: [
|
|
3323
3489
|
"All ",
|
|
3324
3490
|
members.length,
|
|
3325
3491
|
" member tracks of this fade will be permanently removed from this scene. This cannot be undone."
|
|
@@ -3339,8 +3505,8 @@ function GroupFadeTrackRow({
|
|
|
3339
3505
|
}
|
|
3340
3506
|
|
|
3341
3507
|
// src/components/FadeModal.tsx
|
|
3342
|
-
import { useCallback as
|
|
3343
|
-
import { Fragment as Fragment5, jsx as
|
|
3508
|
+
import { useCallback as useCallback6, useEffect as useEffect8, useMemo as useMemo4, useRef as useRef8, useState as useState10 } from "react";
|
|
3509
|
+
import { Fragment as Fragment5, jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
3344
3510
|
function shortId(dbId) {
|
|
3345
3511
|
return dbId.length > 8 ? dbId.slice(0, 8) : dbId;
|
|
3346
3512
|
}
|
|
@@ -3383,7 +3549,7 @@ function OrphanRow({
|
|
|
3383
3549
|
}) {
|
|
3384
3550
|
const primary = track.prompt?.trim() || track.name;
|
|
3385
3551
|
const meta = [track.role, shortId(track.dbId), gesture].filter(Boolean).join(" \xB7 ");
|
|
3386
|
-
return /* @__PURE__ */
|
|
3552
|
+
return /* @__PURE__ */ jsxs13(
|
|
3387
3553
|
"button",
|
|
3388
3554
|
{
|
|
3389
3555
|
type: "button",
|
|
@@ -3395,8 +3561,8 @@ function OrphanRow({
|
|
|
3395
3561
|
disabled,
|
|
3396
3562
|
className: `w-full text-left px-2 py-1.5 rounded-sm border transition-colors disabled:opacity-50 ${selected ? "bg-sas-accent/15 border-sas-accent" : "bg-sas-panel border-sas-border hover:border-sas-accent/50"}`,
|
|
3397
3563
|
children: [
|
|
3398
|
-
/* @__PURE__ */
|
|
3399
|
-
meta && /* @__PURE__ */
|
|
3564
|
+
/* @__PURE__ */ jsx17("div", { className: "text-xs text-sas-text truncate", title: primary, children: primary }),
|
|
3565
|
+
meta && /* @__PURE__ */ jsx17("div", { className: "text-[10px] text-sas-muted truncate mt-0.5", title: track.dbId, children: meta })
|
|
3400
3566
|
]
|
|
3401
3567
|
}
|
|
3402
3568
|
);
|
|
@@ -3413,14 +3579,14 @@ function FadeModal({
|
|
|
3413
3579
|
onCreate,
|
|
3414
3580
|
testIdPrefix = "fade-modal"
|
|
3415
3581
|
}) {
|
|
3416
|
-
const [load, setLoad] =
|
|
3417
|
-
const [selectedDbId, setSelectedDbId] =
|
|
3418
|
-
const [isCreating, setIsCreating] =
|
|
3419
|
-
const [error, setError] =
|
|
3420
|
-
const [fromName, setFromName] =
|
|
3421
|
-
const [toName, setToName] =
|
|
3582
|
+
const [load, setLoad] = useState10({ status: "loading" });
|
|
3583
|
+
const [selectedDbId, setSelectedDbId] = useState10("");
|
|
3584
|
+
const [isCreating, setIsCreating] = useState10(false);
|
|
3585
|
+
const [error, setError] = useState10(null);
|
|
3586
|
+
const [fromName, setFromName] = useState10(null);
|
|
3587
|
+
const [toName, setToName] = useState10(null);
|
|
3422
3588
|
const cancelRef = useRef8(null);
|
|
3423
|
-
const refresh =
|
|
3589
|
+
const refresh = useCallback6(async () => {
|
|
3424
3590
|
if (!host.listSceneFamilyTracks) {
|
|
3425
3591
|
setLoad({ status: "error", message: "This host does not support fades." });
|
|
3426
3592
|
return;
|
|
@@ -3440,7 +3606,7 @@ function FadeModal({
|
|
|
3440
3606
|
setLoad({ status: "error", message: err instanceof Error ? err.message : "Failed to load tracks." });
|
|
3441
3607
|
}
|
|
3442
3608
|
}, [host, fromSceneId, toSceneId]);
|
|
3443
|
-
|
|
3609
|
+
useEffect8(() => {
|
|
3444
3610
|
if (open) {
|
|
3445
3611
|
setError(null);
|
|
3446
3612
|
setIsCreating(false);
|
|
@@ -3460,17 +3626,17 @@ function FadeModal({
|
|
|
3460
3626
|
],
|
|
3461
3627
|
[fadeOut, fadeIn]
|
|
3462
3628
|
);
|
|
3463
|
-
|
|
3629
|
+
useEffect8(() => {
|
|
3464
3630
|
if (!allOrphans.some((o) => o.track.dbId === selectedDbId)) {
|
|
3465
3631
|
setSelectedDbId(allOrphans[0]?.track.dbId ?? "");
|
|
3466
3632
|
}
|
|
3467
3633
|
}, [allOrphans, selectedDbId]);
|
|
3468
3634
|
const selected = allOrphans.find((o) => o.track.dbId === selectedDbId) ?? null;
|
|
3469
3635
|
const canCreate = !isCreating && !!selected;
|
|
3470
|
-
const handleClose =
|
|
3636
|
+
const handleClose = useCallback6(() => {
|
|
3471
3637
|
if (!isCreating) onClose();
|
|
3472
3638
|
}, [isCreating, onClose]);
|
|
3473
|
-
const handleCreate =
|
|
3639
|
+
const handleCreate = useCallback6(async () => {
|
|
3474
3640
|
if (!selected) return;
|
|
3475
3641
|
setIsCreating(true);
|
|
3476
3642
|
setError(null);
|
|
@@ -3491,16 +3657,16 @@ function FadeModal({
|
|
|
3491
3657
|
if (!open) return null;
|
|
3492
3658
|
const renderSection = (heading, list, section) => {
|
|
3493
3659
|
if (list.length === 0) return null;
|
|
3494
|
-
return /* @__PURE__ */
|
|
3495
|
-
/* @__PURE__ */
|
|
3496
|
-
/* @__PURE__ */
|
|
3660
|
+
return /* @__PURE__ */ jsxs13("div", { className: "block", children: [
|
|
3661
|
+
/* @__PURE__ */ jsx17("span", { className: "text-[10px] uppercase tracking-wide text-sas-muted", children: heading }),
|
|
3662
|
+
/* @__PURE__ */ jsx17(
|
|
3497
3663
|
"div",
|
|
3498
3664
|
{
|
|
3499
3665
|
role: "radiogroup",
|
|
3500
3666
|
"aria-label": heading,
|
|
3501
3667
|
"data-testid": `${testIdPrefix}-${section === "out" ? "fade-out" : "fade-in"}-list`,
|
|
3502
3668
|
className: "mt-1 space-y-1 max-h-40 overflow-y-auto pr-0.5",
|
|
3503
|
-
children: list.map((t) => /* @__PURE__ */
|
|
3669
|
+
children: list.map((t) => /* @__PURE__ */ jsx17(
|
|
3504
3670
|
OrphanRow,
|
|
3505
3671
|
{
|
|
3506
3672
|
track: t,
|
|
@@ -3516,32 +3682,32 @@ function FadeModal({
|
|
|
3516
3682
|
)
|
|
3517
3683
|
] });
|
|
3518
3684
|
};
|
|
3519
|
-
return /* @__PURE__ */
|
|
3685
|
+
return /* @__PURE__ */ jsx17(Modal, { open, onClose: handleClose, testIdPrefix, initialFocusRef: cancelRef, children: /* @__PURE__ */ jsxs13(
|
|
3520
3686
|
"div",
|
|
3521
3687
|
{
|
|
3522
3688
|
className: "bg-sas-panel border border-sas-border rounded-md shadow-xl w-[420px] max-w-[92vw] p-4 space-y-3",
|
|
3523
3689
|
onClick: (e) => e.stopPropagation(),
|
|
3524
3690
|
"data-testid": `${testIdPrefix}-box`,
|
|
3525
3691
|
children: [
|
|
3526
|
-
/* @__PURE__ */
|
|
3527
|
-
/* @__PURE__ */
|
|
3692
|
+
/* @__PURE__ */ jsx17("h3", { className: "text-sm font-bold text-sas-text", children: "Add fade" }),
|
|
3693
|
+
/* @__PURE__ */ jsxs13("p", { className: "text-[11px] text-sas-muted leading-relaxed", children: [
|
|
3528
3694
|
"Tracks with no counterpart between",
|
|
3529
3695
|
" ",
|
|
3530
|
-
/* @__PURE__ */
|
|
3696
|
+
/* @__PURE__ */ jsx17("span", { className: "text-sas-text", children: fromLabel ?? "the origin scene" }),
|
|
3531
3697
|
" and",
|
|
3532
3698
|
" ",
|
|
3533
|
-
/* @__PURE__ */
|
|
3699
|
+
/* @__PURE__ */ jsx17("span", { className: "text-sas-text", children: toLabel ?? "the target scene" }),
|
|
3534
3700
|
" can gracefully fade out (leaving) or fade in (entering) across this transition."
|
|
3535
3701
|
] }),
|
|
3536
|
-
load.status === "loading" && /* @__PURE__ */
|
|
3537
|
-
load.status === "error" && /* @__PURE__ */
|
|
3538
|
-
load.status === "ready" && (allOrphans.length === 0 ? /* @__PURE__ */
|
|
3702
|
+
load.status === "loading" && /* @__PURE__ */ jsx17("div", { className: "text-xs text-sas-muted py-4 text-center", children: "Loading tracks\u2026" }),
|
|
3703
|
+
load.status === "error" && /* @__PURE__ */ jsx17("div", { className: "text-xs text-sas-danger py-4 text-center", children: load.message }),
|
|
3704
|
+
load.status === "ready" && (allOrphans.length === 0 ? /* @__PURE__ */ jsx17("div", { className: "text-xs text-sas-muted py-4 text-center", "data-testid": `${testIdPrefix}-empty`, children: "Every track has a counterpart in the other scene \u2014 nothing to fade. Use \u201C+ Crossfade\u201D to bridge matching tracks." }) : /* @__PURE__ */ jsxs13(Fragment5, { children: [
|
|
3539
3705
|
renderSection(`Fade out${fromLabel ? ` (from ${fromLabel})` : ""}`, fadeOut, "out"),
|
|
3540
3706
|
renderSection(`Fade in${toLabel ? ` (to ${toLabel})` : ""}`, fadeIn, "in")
|
|
3541
3707
|
] })),
|
|
3542
|
-
error && /* @__PURE__ */
|
|
3543
|
-
/* @__PURE__ */
|
|
3544
|
-
/* @__PURE__ */
|
|
3708
|
+
error && /* @__PURE__ */ jsx17("div", { className: "text-xs text-sas-danger", "data-testid": `${testIdPrefix}-error`, children: error }),
|
|
3709
|
+
/* @__PURE__ */ jsxs13("div", { className: "flex justify-end gap-2 pt-1", children: [
|
|
3710
|
+
/* @__PURE__ */ jsx17(
|
|
3545
3711
|
"button",
|
|
3546
3712
|
{
|
|
3547
3713
|
ref: cancelRef,
|
|
@@ -3552,7 +3718,7 @@ function FadeModal({
|
|
|
3552
3718
|
children: "Cancel"
|
|
3553
3719
|
}
|
|
3554
3720
|
),
|
|
3555
|
-
/* @__PURE__ */
|
|
3721
|
+
/* @__PURE__ */ jsx17(
|
|
3556
3722
|
"button",
|
|
3557
3723
|
{
|
|
3558
3724
|
"data-testid": `${testIdPrefix}-confirm`,
|
|
@@ -3569,8 +3735,8 @@ function FadeModal({
|
|
|
3569
3735
|
}
|
|
3570
3736
|
|
|
3571
3737
|
// src/components/ImportTrackModal.tsx
|
|
3572
|
-
import { useCallback as
|
|
3573
|
-
import { jsx as
|
|
3738
|
+
import { useCallback as useCallback7, useEffect as useEffect9, useState as useState11 } from "react";
|
|
3739
|
+
import { jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
3574
3740
|
function ImportTrackModal({
|
|
3575
3741
|
host,
|
|
3576
3742
|
open,
|
|
@@ -3582,10 +3748,10 @@ function ImportTrackModal({
|
|
|
3582
3748
|
onPick,
|
|
3583
3749
|
onPortTrack
|
|
3584
3750
|
}) {
|
|
3585
|
-
const [load, setLoad] =
|
|
3586
|
-
const [selectedSceneId, setSelectedSceneId] =
|
|
3587
|
-
const [importingTrackId, setImportingTrackId] =
|
|
3588
|
-
const refresh =
|
|
3751
|
+
const [load, setLoad] = useState11({ status: "loading" });
|
|
3752
|
+
const [selectedSceneId, setSelectedSceneId] = useState11(null);
|
|
3753
|
+
const [importingTrackId, setImportingTrackId] = useState11(null);
|
|
3754
|
+
const refresh = useCallback7(async () => {
|
|
3589
3755
|
if (!host.listImportableTracks) {
|
|
3590
3756
|
setLoad({ status: "error", message: "This host does not support importing tracks." });
|
|
3591
3757
|
return;
|
|
@@ -3601,14 +3767,14 @@ function ImportTrackModal({
|
|
|
3601
3767
|
setLoad({ status: "error", message: err instanceof Error ? err.message : "Failed to load scenes." });
|
|
3602
3768
|
}
|
|
3603
3769
|
}, [host, mode, onPortTrack]);
|
|
3604
|
-
|
|
3770
|
+
useEffect9(() => {
|
|
3605
3771
|
if (open) {
|
|
3606
3772
|
setSelectedSceneId(null);
|
|
3607
3773
|
setImportingTrackId(null);
|
|
3608
3774
|
void refresh();
|
|
3609
3775
|
}
|
|
3610
3776
|
}, [open, refresh]);
|
|
3611
|
-
const handleImport =
|
|
3777
|
+
const handleImport = useCallback7(
|
|
3612
3778
|
async (track, sourceSceneId, sceneName, isSameScene) => {
|
|
3613
3779
|
if (isSameScene && onPortTrack) {
|
|
3614
3780
|
if (!track.importable) return;
|
|
@@ -3649,16 +3815,16 @@ function ImportTrackModal({
|
|
|
3649
3815
|
if (!open) return null;
|
|
3650
3816
|
const scenes = load.status === "ready" ? load.scenes : [];
|
|
3651
3817
|
const selectedScene = scenes.find((s) => s.sceneId === selectedSceneId) ?? null;
|
|
3652
|
-
return /* @__PURE__ */
|
|
3818
|
+
return /* @__PURE__ */ jsx18(Modal, { open, onClose, testIdPrefix, children: /* @__PURE__ */ jsxs14(
|
|
3653
3819
|
"div",
|
|
3654
3820
|
{
|
|
3655
3821
|
className: "w-[420px] max-h-[70vh] overflow-hidden flex flex-col rounded-md border border-sas-border bg-sas-panel shadow-xl",
|
|
3656
3822
|
onClick: (e) => e.stopPropagation(),
|
|
3657
3823
|
"data-testid": `${testIdPrefix}-modal`,
|
|
3658
3824
|
children: [
|
|
3659
|
-
/* @__PURE__ */
|
|
3660
|
-
/* @__PURE__ */
|
|
3661
|
-
selectedScene && /* @__PURE__ */
|
|
3825
|
+
/* @__PURE__ */ jsxs14("div", { className: "flex items-center justify-between px-3 py-2 border-b border-sas-border", children: [
|
|
3826
|
+
/* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-2", children: [
|
|
3827
|
+
selectedScene && /* @__PURE__ */ jsx18(
|
|
3662
3828
|
"button",
|
|
3663
3829
|
{
|
|
3664
3830
|
className: "text-sas-muted hover:text-sas-accent text-xs",
|
|
@@ -3667,9 +3833,9 @@ function ImportTrackModal({
|
|
|
3667
3833
|
children: "\u2190"
|
|
3668
3834
|
}
|
|
3669
3835
|
),
|
|
3670
|
-
/* @__PURE__ */
|
|
3836
|
+
/* @__PURE__ */ jsx18("span", { className: "text-sm font-medium text-sas-text", children: selectedScene ? selectedScene.sceneName : title })
|
|
3671
3837
|
] }),
|
|
3672
|
-
/* @__PURE__ */
|
|
3838
|
+
/* @__PURE__ */ jsx18(
|
|
3673
3839
|
"button",
|
|
3674
3840
|
{
|
|
3675
3841
|
className: "text-sas-muted hover:text-sas-accent text-sm",
|
|
@@ -3679,30 +3845,30 @@ function ImportTrackModal({
|
|
|
3679
3845
|
}
|
|
3680
3846
|
)
|
|
3681
3847
|
] }),
|
|
3682
|
-
/* @__PURE__ */
|
|
3683
|
-
load.status === "loading" && /* @__PURE__ */
|
|
3684
|
-
load.status === "error" && /* @__PURE__ */
|
|
3685
|
-
load.status === "ready" && scenes.length === 0 && /* @__PURE__ */
|
|
3686
|
-
load.status === "ready" && scenes.length > 0 && !selectedScene && /* @__PURE__ */
|
|
3848
|
+
/* @__PURE__ */ jsxs14("div", { className: "overflow-y-auto p-2 flex-1", children: [
|
|
3849
|
+
load.status === "loading" && /* @__PURE__ */ jsx18("div", { className: "py-8 text-center text-xs text-sas-muted", "data-testid": `${testIdPrefix}-loading`, children: "Loading scenes\u2026" }),
|
|
3850
|
+
load.status === "error" && /* @__PURE__ */ jsx18("div", { className: "py-8 text-center text-xs text-red-400", "data-testid": `${testIdPrefix}-error`, children: load.message }),
|
|
3851
|
+
load.status === "ready" && scenes.length === 0 && /* @__PURE__ */ jsx18("div", { className: "py-8 text-center text-xs text-sas-muted", "data-testid": `${testIdPrefix}-empty`, children: mode === "sound" ? "No other scenes have a sound to import." : "No other scenes have a compatible track to import." }),
|
|
3852
|
+
load.status === "ready" && scenes.length > 0 && !selectedScene && /* @__PURE__ */ jsx18("ul", { className: "flex flex-col gap-1", "data-testid": `${testIdPrefix}-scene-list`, children: scenes.map((scene) => /* @__PURE__ */ jsx18("li", { children: /* @__PURE__ */ jsxs14(
|
|
3687
3853
|
"button",
|
|
3688
3854
|
{
|
|
3689
3855
|
className: "w-full flex items-center justify-between px-2 py-1.5 rounded-sm border border-sas-border bg-sas-panel-alt text-left text-xs text-sas-text hover:border-sas-accent hover:text-sas-accent transition-colors",
|
|
3690
3856
|
onClick: () => setSelectedSceneId(scene.sceneId),
|
|
3691
3857
|
"data-testid": `${testIdPrefix}-scene`,
|
|
3692
3858
|
children: [
|
|
3693
|
-
/* @__PURE__ */
|
|
3694
|
-
/* @__PURE__ */
|
|
3859
|
+
/* @__PURE__ */ jsx18("span", { className: "truncate", children: scene.sceneName }),
|
|
3860
|
+
/* @__PURE__ */ jsxs14("span", { className: "text-sas-muted", children: [
|
|
3695
3861
|
scene.tracks.length,
|
|
3696
3862
|
" \u2192"
|
|
3697
3863
|
] })
|
|
3698
3864
|
]
|
|
3699
3865
|
}
|
|
3700
3866
|
) }, scene.sceneId)) }),
|
|
3701
|
-
selectedScene && /* @__PURE__ */
|
|
3867
|
+
selectedScene && /* @__PURE__ */ jsx18("ul", { className: "flex flex-col gap-1", "data-testid": `${testIdPrefix}-track-list`, children: selectedScene.tracks.map((track) => {
|
|
3702
3868
|
const busy = importingTrackId === track.trackId;
|
|
3703
3869
|
const gated = mode === "track" && !track.importable;
|
|
3704
3870
|
const disabled = gated || busy;
|
|
3705
|
-
return /* @__PURE__ */
|
|
3871
|
+
return /* @__PURE__ */ jsx18("li", { children: /* @__PURE__ */ jsxs14(
|
|
3706
3872
|
"button",
|
|
3707
3873
|
{
|
|
3708
3874
|
className: `w-full flex items-center justify-between px-2 py-1.5 rounded-sm border text-left text-xs transition-colors ${disabled ? "bg-sas-panel border-sas-border text-sas-muted/50 cursor-not-allowed" : "bg-sas-panel-alt border-sas-border text-sas-text hover:border-sas-accent hover:text-sas-accent"}`,
|
|
@@ -3712,14 +3878,14 @@ function ImportTrackModal({
|
|
|
3712
3878
|
"data-testid": `${testIdPrefix}-track`,
|
|
3713
3879
|
"data-importable": mode === "sound" || track.importable ? "true" : "false",
|
|
3714
3880
|
children: [
|
|
3715
|
-
/* @__PURE__ */
|
|
3881
|
+
/* @__PURE__ */ jsxs14("span", { className: "truncate", children: [
|
|
3716
3882
|
track.name,
|
|
3717
|
-
track.role ? /* @__PURE__ */
|
|
3883
|
+
track.role ? /* @__PURE__ */ jsxs14("span", { className: "text-sas-muted", children: [
|
|
3718
3884
|
" \xB7 ",
|
|
3719
3885
|
track.role
|
|
3720
3886
|
] }) : null
|
|
3721
3887
|
] }),
|
|
3722
|
-
busy ? /* @__PURE__ */
|
|
3888
|
+
busy ? /* @__PURE__ */ jsx18("span", { className: "text-sas-muted", children: "\u2026" }) : gated ? /* @__PURE__ */ jsx18("span", { className: "text-sas-muted", children: "\u2298" }) : null
|
|
3723
3889
|
]
|
|
3724
3890
|
}
|
|
3725
3891
|
) }, track.dbId);
|
|
@@ -3731,8 +3897,8 @@ function ImportTrackModal({
|
|
|
3731
3897
|
}
|
|
3732
3898
|
|
|
3733
3899
|
// src/components/CrossfadeModal.tsx
|
|
3734
|
-
import { useCallback as
|
|
3735
|
-
import { Fragment as Fragment6, jsx as
|
|
3900
|
+
import { useCallback as useCallback8, useEffect as useEffect10, useMemo as useMemo5, useRef as useRef9, useState as useState12 } from "react";
|
|
3901
|
+
import { Fragment as Fragment6, jsx as jsx19, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
3736
3902
|
function shortId2(dbId) {
|
|
3737
3903
|
return dbId.length > 8 ? dbId.slice(0, 8) : dbId;
|
|
3738
3904
|
}
|
|
@@ -3745,7 +3911,7 @@ function CandidateRow({
|
|
|
3745
3911
|
}) {
|
|
3746
3912
|
const primary = track.prompt?.trim() || track.name;
|
|
3747
3913
|
const meta = [track.role, shortId2(track.dbId)].filter(Boolean).join(" \xB7 ");
|
|
3748
|
-
return /* @__PURE__ */
|
|
3914
|
+
return /* @__PURE__ */ jsxs15(
|
|
3749
3915
|
"button",
|
|
3750
3916
|
{
|
|
3751
3917
|
type: "button",
|
|
@@ -3757,8 +3923,8 @@ function CandidateRow({
|
|
|
3757
3923
|
disabled,
|
|
3758
3924
|
className: `w-full text-left px-2 py-1.5 rounded-sm border transition-colors disabled:opacity-50 ${selected ? "bg-sas-accent/15 border-sas-accent" : "bg-sas-panel border-sas-border hover:border-sas-accent/50"}`,
|
|
3759
3925
|
children: [
|
|
3760
|
-
/* @__PURE__ */
|
|
3761
|
-
meta && /* @__PURE__ */
|
|
3926
|
+
/* @__PURE__ */ jsx19("div", { className: "text-xs text-sas-text truncate", title: primary, children: primary }),
|
|
3927
|
+
meta && /* @__PURE__ */ jsx19("div", { className: "text-[10px] text-sas-muted truncate mt-0.5", title: track.dbId, children: meta })
|
|
3762
3928
|
]
|
|
3763
3929
|
}
|
|
3764
3930
|
);
|
|
@@ -3775,15 +3941,15 @@ function CrossfadeModal({
|
|
|
3775
3941
|
onCreate,
|
|
3776
3942
|
testIdPrefix = "crossfade-modal"
|
|
3777
3943
|
}) {
|
|
3778
|
-
const [load, setLoad] =
|
|
3779
|
-
const [originDbId, setOriginDbId] =
|
|
3780
|
-
const [targetDbId, setTargetDbId] =
|
|
3781
|
-
const [isCreating, setIsCreating] =
|
|
3782
|
-
const [error, setError] =
|
|
3783
|
-
const [fromName, setFromName] =
|
|
3784
|
-
const [toName, setToName] =
|
|
3944
|
+
const [load, setLoad] = useState12({ status: "loading" });
|
|
3945
|
+
const [originDbId, setOriginDbId] = useState12("");
|
|
3946
|
+
const [targetDbId, setTargetDbId] = useState12("");
|
|
3947
|
+
const [isCreating, setIsCreating] = useState12(false);
|
|
3948
|
+
const [error, setError] = useState12(null);
|
|
3949
|
+
const [fromName, setFromName] = useState12(null);
|
|
3950
|
+
const [toName, setToName] = useState12(null);
|
|
3785
3951
|
const cancelRef = useRef9(null);
|
|
3786
|
-
const refresh =
|
|
3952
|
+
const refresh = useCallback8(async () => {
|
|
3787
3953
|
if (!host.listSceneFamilyTracks) {
|
|
3788
3954
|
setLoad({ status: "error", message: "This host does not support crossfade tracks." });
|
|
3789
3955
|
return;
|
|
@@ -3803,7 +3969,7 @@ function CrossfadeModal({
|
|
|
3803
3969
|
setLoad({ status: "error", message: err instanceof Error ? err.message : "Failed to load tracks." });
|
|
3804
3970
|
}
|
|
3805
3971
|
}, [host, fromSceneId, toSceneId]);
|
|
3806
|
-
|
|
3972
|
+
useEffect10(() => {
|
|
3807
3973
|
if (open) {
|
|
3808
3974
|
setError(null);
|
|
3809
3975
|
setIsCreating(false);
|
|
@@ -3821,12 +3987,12 @@ function CrossfadeModal({
|
|
|
3821
3987
|
() => load.status === "ready" ? load.target.filter((t) => !excludeSet.has(t.dbId)) : [],
|
|
3822
3988
|
[load, excludeSet]
|
|
3823
3989
|
);
|
|
3824
|
-
|
|
3990
|
+
useEffect10(() => {
|
|
3825
3991
|
if (!originCandidates.some((t) => t.dbId === originDbId)) {
|
|
3826
3992
|
setOriginDbId(originCandidates[0]?.dbId ?? "");
|
|
3827
3993
|
}
|
|
3828
3994
|
}, [originCandidates, originDbId]);
|
|
3829
|
-
|
|
3995
|
+
useEffect10(() => {
|
|
3830
3996
|
if (!targetCandidates.some((t) => t.dbId === targetDbId)) {
|
|
3831
3997
|
setTargetDbId(targetCandidates[0]?.dbId ?? "");
|
|
3832
3998
|
}
|
|
@@ -3834,10 +4000,10 @@ function CrossfadeModal({
|
|
|
3834
4000
|
const originTrack = originCandidates.find((t) => t.dbId === originDbId) ?? null;
|
|
3835
4001
|
const targetTrack = targetCandidates.find((t) => t.dbId === targetDbId) ?? null;
|
|
3836
4002
|
const canCreate = !isCreating && !!originTrack && !!targetTrack;
|
|
3837
|
-
const handleClose =
|
|
4003
|
+
const handleClose = useCallback8(() => {
|
|
3838
4004
|
if (!isCreating) onClose();
|
|
3839
4005
|
}, [isCreating, onClose]);
|
|
3840
|
-
const handleCreate =
|
|
4006
|
+
const handleCreate = useCallback8(async () => {
|
|
3841
4007
|
if (!originTrack || !targetTrack) return;
|
|
3842
4008
|
setIsCreating(true);
|
|
3843
4009
|
setError(null);
|
|
@@ -3855,26 +4021,26 @@ function CrossfadeModal({
|
|
|
3855
4021
|
const fromLabel = fromName ?? fromSceneName ?? null;
|
|
3856
4022
|
const toLabel = toName ?? toSceneName ?? null;
|
|
3857
4023
|
if (!open) return null;
|
|
3858
|
-
return /* @__PURE__ */
|
|
4024
|
+
return /* @__PURE__ */ jsx19(Modal, { open, onClose: handleClose, testIdPrefix, initialFocusRef: cancelRef, children: /* @__PURE__ */ jsxs15(
|
|
3859
4025
|
"div",
|
|
3860
4026
|
{
|
|
3861
4027
|
className: "bg-sas-panel border border-sas-border rounded-md shadow-xl w-[420px] max-w-[92vw] p-4 space-y-3",
|
|
3862
4028
|
onClick: (e) => e.stopPropagation(),
|
|
3863
4029
|
"data-testid": `${testIdPrefix}-box`,
|
|
3864
4030
|
children: [
|
|
3865
|
-
/* @__PURE__ */
|
|
3866
|
-
/* @__PURE__ */
|
|
4031
|
+
/* @__PURE__ */ jsx19("h3", { className: "text-sm font-bold text-sas-text", children: "Add crossfade" }),
|
|
4032
|
+
/* @__PURE__ */ jsxs15("p", { className: "text-[11px] text-sas-muted leading-relaxed", children: [
|
|
3867
4033
|
"Bridge a track from",
|
|
3868
4034
|
" ",
|
|
3869
|
-
/* @__PURE__ */
|
|
4035
|
+
/* @__PURE__ */ jsx19("span", { className: "text-sas-text", children: fromLabel ?? "the origin scene" }),
|
|
3870
4036
|
" into one from",
|
|
3871
4037
|
" ",
|
|
3872
|
-
/* @__PURE__ */
|
|
4038
|
+
/* @__PURE__ */ jsx19("span", { className: "text-sas-text", children: toLabel ?? "the target scene" }),
|
|
3873
4039
|
". Both layers share one generated part; each keeps its own preset."
|
|
3874
4040
|
] }),
|
|
3875
|
-
load.status === "loading" && /* @__PURE__ */
|
|
3876
|
-
load.status === "error" && /* @__PURE__ */
|
|
3877
|
-
load.status === "ready" && (originCandidates.length === 0 ? /* @__PURE__ */
|
|
4041
|
+
load.status === "loading" && /* @__PURE__ */ jsx19("div", { className: "text-xs text-sas-muted py-4 text-center", children: "Loading tracks\u2026" }),
|
|
4042
|
+
load.status === "error" && /* @__PURE__ */ jsx19("div", { className: "text-xs text-sas-danger py-4 text-center", children: load.message }),
|
|
4043
|
+
load.status === "ready" && (originCandidates.length === 0 ? /* @__PURE__ */ jsxs15(
|
|
3878
4044
|
"div",
|
|
3879
4045
|
{
|
|
3880
4046
|
className: "text-xs text-sas-muted py-4 text-center",
|
|
@@ -3885,20 +4051,20 @@ function CrossfadeModal({
|
|
|
3885
4051
|
". Add one (or free one from another crossfade) first."
|
|
3886
4052
|
]
|
|
3887
4053
|
}
|
|
3888
|
-
) : /* @__PURE__ */
|
|
3889
|
-
/* @__PURE__ */
|
|
3890
|
-
/* @__PURE__ */
|
|
4054
|
+
) : /* @__PURE__ */ jsxs15(Fragment6, { children: [
|
|
4055
|
+
/* @__PURE__ */ jsxs15("div", { className: "block", children: [
|
|
4056
|
+
/* @__PURE__ */ jsxs15("span", { className: "text-[10px] uppercase tracking-wide text-sas-muted", children: [
|
|
3891
4057
|
"Origin ",
|
|
3892
4058
|
fromLabel ? `(${fromLabel})` : "(top)"
|
|
3893
4059
|
] }),
|
|
3894
|
-
/* @__PURE__ */
|
|
4060
|
+
/* @__PURE__ */ jsx19(
|
|
3895
4061
|
"div",
|
|
3896
4062
|
{
|
|
3897
4063
|
role: "radiogroup",
|
|
3898
4064
|
"aria-label": "Origin track",
|
|
3899
4065
|
"data-testid": `${testIdPrefix}-origin-list`,
|
|
3900
4066
|
className: "mt-1 space-y-1 max-h-40 overflow-y-auto pr-0.5",
|
|
3901
|
-
children: originCandidates.map((t) => /* @__PURE__ */
|
|
4067
|
+
children: originCandidates.map((t) => /* @__PURE__ */ jsx19(
|
|
3902
4068
|
CandidateRow,
|
|
3903
4069
|
{
|
|
3904
4070
|
track: t,
|
|
@@ -3912,23 +4078,23 @@ function CrossfadeModal({
|
|
|
3912
4078
|
}
|
|
3913
4079
|
)
|
|
3914
4080
|
] }),
|
|
3915
|
-
/* @__PURE__ */
|
|
3916
|
-
/* @__PURE__ */
|
|
4081
|
+
/* @__PURE__ */ jsxs15("div", { className: "block", children: [
|
|
4082
|
+
/* @__PURE__ */ jsxs15("span", { className: "text-[10px] uppercase tracking-wide text-sas-muted", children: [
|
|
3917
4083
|
"Target ",
|
|
3918
4084
|
toLabel ? `(${toLabel})` : "(bottom)"
|
|
3919
4085
|
] }),
|
|
3920
|
-
targetCandidates.length === 0 ? /* @__PURE__ */
|
|
4086
|
+
targetCandidates.length === 0 ? /* @__PURE__ */ jsxs15("div", { className: "text-xs text-sas-danger mt-0.5", "data-testid": `${testIdPrefix}-empty-target`, children: [
|
|
3921
4087
|
"No available tracks in ",
|
|
3922
4088
|
toLabel ?? "the target scene",
|
|
3923
4089
|
" to crossfade into."
|
|
3924
|
-
] }) : /* @__PURE__ */
|
|
4090
|
+
] }) : /* @__PURE__ */ jsx19(
|
|
3925
4091
|
"div",
|
|
3926
4092
|
{
|
|
3927
4093
|
role: "radiogroup",
|
|
3928
4094
|
"aria-label": "Target track",
|
|
3929
4095
|
"data-testid": `${testIdPrefix}-target-list`,
|
|
3930
4096
|
className: "mt-1 space-y-1 max-h-40 overflow-y-auto pr-0.5",
|
|
3931
|
-
children: targetCandidates.map((t) => /* @__PURE__ */
|
|
4097
|
+
children: targetCandidates.map((t) => /* @__PURE__ */ jsx19(
|
|
3932
4098
|
CandidateRow,
|
|
3933
4099
|
{
|
|
3934
4100
|
track: t,
|
|
@@ -3943,9 +4109,9 @@ function CrossfadeModal({
|
|
|
3943
4109
|
)
|
|
3944
4110
|
] })
|
|
3945
4111
|
] })),
|
|
3946
|
-
error && /* @__PURE__ */
|
|
3947
|
-
/* @__PURE__ */
|
|
3948
|
-
/* @__PURE__ */
|
|
4112
|
+
error && /* @__PURE__ */ jsx19("div", { className: "text-xs text-sas-danger", "data-testid": `${testIdPrefix}-error`, children: error }),
|
|
4113
|
+
/* @__PURE__ */ jsxs15("div", { className: "flex justify-end gap-2 pt-1", children: [
|
|
4114
|
+
/* @__PURE__ */ jsx19(
|
|
3949
4115
|
"button",
|
|
3950
4116
|
{
|
|
3951
4117
|
ref: cancelRef,
|
|
@@ -3956,7 +4122,7 @@ function CrossfadeModal({
|
|
|
3956
4122
|
children: "Cancel"
|
|
3957
4123
|
}
|
|
3958
4124
|
),
|
|
3959
|
-
/* @__PURE__ */
|
|
4125
|
+
/* @__PURE__ */ jsx19(
|
|
3960
4126
|
"button",
|
|
3961
4127
|
{
|
|
3962
4128
|
"data-testid": `${testIdPrefix}-confirm`,
|
|
@@ -3973,10 +4139,10 @@ function CrossfadeModal({
|
|
|
3973
4139
|
}
|
|
3974
4140
|
|
|
3975
4141
|
// src/components/TransitionDesigner.tsx
|
|
3976
|
-
import { useCallback as
|
|
4142
|
+
import { useCallback as useCallback10, useEffect as useEffect11, useMemo as useMemo6, useRef as useRef11, useState as useState14 } from "react";
|
|
3977
4143
|
|
|
3978
4144
|
// src/hooks/useTrackReorder.ts
|
|
3979
|
-
import { useCallback as
|
|
4145
|
+
import { useCallback as useCallback9, useRef as useRef10, useState as useState13 } from "react";
|
|
3980
4146
|
function moveItem(arr, from, to) {
|
|
3981
4147
|
const next = arr.slice();
|
|
3982
4148
|
if (from === to || from < 0 || to < 0 || from >= next.length || to >= next.length) {
|
|
@@ -3993,12 +4159,12 @@ function useTrackReorder({
|
|
|
3993
4159
|
getId,
|
|
3994
4160
|
onError
|
|
3995
4161
|
}) {
|
|
3996
|
-
const [draggingIndex, setDraggingIndex] =
|
|
3997
|
-
const [dragOverIndex, setDragOverIndex] =
|
|
4162
|
+
const [draggingIndex, setDraggingIndex] = useState13(null);
|
|
4163
|
+
const [dragOverIndex, setDragOverIndex] = useState13(null);
|
|
3998
4164
|
const fromRef = useRef10(null);
|
|
3999
4165
|
const itemsRef = useRef10(items);
|
|
4000
4166
|
itemsRef.current = items;
|
|
4001
|
-
const dragPropsFor =
|
|
4167
|
+
const dragPropsFor = useCallback9(
|
|
4002
4168
|
(index) => ({
|
|
4003
4169
|
handleProps: {
|
|
4004
4170
|
draggable: true,
|
|
@@ -4180,7 +4346,7 @@ function dbIdsFromKeys(keys) {
|
|
|
4180
4346
|
}
|
|
4181
4347
|
|
|
4182
4348
|
// src/components/TransitionDesigner.tsx
|
|
4183
|
-
import { jsx as
|
|
4349
|
+
import { jsx as jsx20, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
4184
4350
|
var CROSSFADE_ESTIMATE_MS = 15e3;
|
|
4185
4351
|
var FADE_ESTIMATE_MS = 11e3;
|
|
4186
4352
|
var CREATE_ALL_CONCURRENCY = 5;
|
|
@@ -4207,14 +4373,14 @@ function TransitionDesigner({
|
|
|
4207
4373
|
testIdPrefix = "transition-designer"
|
|
4208
4374
|
}) {
|
|
4209
4375
|
const fadeOnly = !onCreateCrossfade;
|
|
4210
|
-
const [load, setLoad] =
|
|
4211
|
-
const [fromName, setFromName] =
|
|
4212
|
-
const [toName, setToName] =
|
|
4213
|
-
const [originSlots, setOriginSlots] =
|
|
4214
|
-
const [targetSlots, setTargetSlots] =
|
|
4215
|
-
const [creatingKeys, setCreatingKeys] =
|
|
4216
|
-
const [rowErrors, setRowErrors] =
|
|
4217
|
-
const [rowEffects, setRowEffects] =
|
|
4376
|
+
const [load, setLoad] = useState14({ status: "loading" });
|
|
4377
|
+
const [fromName, setFromName] = useState14(null);
|
|
4378
|
+
const [toName, setToName] = useState14(null);
|
|
4379
|
+
const [originSlots, setOriginSlots] = useState14([]);
|
|
4380
|
+
const [targetSlots, setTargetSlots] = useState14([]);
|
|
4381
|
+
const [creatingKeys, setCreatingKeys] = useState14(() => /* @__PURE__ */ new Set());
|
|
4382
|
+
const [rowErrors, setRowErrors] = useState14({});
|
|
4383
|
+
const [rowEffects, setRowEffects] = useState14({});
|
|
4218
4384
|
const rowEffectsRef = useRef11(rowEffects);
|
|
4219
4385
|
rowEffectsRef.current = rowEffects;
|
|
4220
4386
|
const audioEffectsEnabled = !!onCreateAudioTransition;
|
|
@@ -4227,8 +4393,8 @@ function TransitionDesigner({
|
|
|
4227
4393
|
const creatingKeysRef = useRef11(creatingKeys);
|
|
4228
4394
|
creatingKeysRef.current = creatingKeys;
|
|
4229
4395
|
const dragRef = useRef11(null);
|
|
4230
|
-
const [dragging, setDragging] =
|
|
4231
|
-
const [dragOver, setDragOver] =
|
|
4396
|
+
const [dragging, setDragging] = useState14(null);
|
|
4397
|
+
const [dragOver, setDragOver] = useState14(null);
|
|
4232
4398
|
const excludeSet = useMemo6(() => new Set(excludeSourceDbIds ?? []), [excludeSourceDbIds]);
|
|
4233
4399
|
const originPool = useMemo6(
|
|
4234
4400
|
() => load.status === "ready" ? load.origin.filter((t) => !excludeSet.has(t.dbId)) : [],
|
|
@@ -4244,7 +4410,7 @@ function TransitionDesigner({
|
|
|
4244
4410
|
originByIdRef.current = originById;
|
|
4245
4411
|
const targetByIdRef = useRef11(targetById);
|
|
4246
4412
|
targetByIdRef.current = targetById;
|
|
4247
|
-
const refresh =
|
|
4413
|
+
const refresh = useCallback10(async () => {
|
|
4248
4414
|
if (!host.listSceneFamilyTracks) {
|
|
4249
4415
|
setLoad({ status: "error", message: "This host does not support transition tracks." });
|
|
4250
4416
|
return;
|
|
@@ -4287,10 +4453,10 @@ function TransitionDesigner({
|
|
|
4287
4453
|
});
|
|
4288
4454
|
}
|
|
4289
4455
|
}, [host, fromSceneId, toSceneId, transitionSceneId, mapColumnSubjects]);
|
|
4290
|
-
|
|
4456
|
+
useEffect11(() => {
|
|
4291
4457
|
void refresh();
|
|
4292
4458
|
}, [refresh]);
|
|
4293
|
-
|
|
4459
|
+
useEffect11(() => {
|
|
4294
4460
|
if (load.status !== "ready") return;
|
|
4295
4461
|
const [po, pt] = padPair(
|
|
4296
4462
|
reconcileSlots(originSlotsRef.current, originPool.map((t) => t.dbId)),
|
|
@@ -4299,7 +4465,7 @@ function TransitionDesigner({
|
|
|
4299
4465
|
if (!slotsEqual(po, originSlotsRef.current)) setOriginSlots(po);
|
|
4300
4466
|
if (!slotsEqual(pt, targetSlotsRef.current)) setTargetSlots(pt);
|
|
4301
4467
|
}, [originPool, targetPool, load.status]);
|
|
4302
|
-
const mutate =
|
|
4468
|
+
const mutate = useCallback10(
|
|
4303
4469
|
(nextOrigin, nextTarget) => {
|
|
4304
4470
|
const norm = normalizeSlots(nextOrigin, nextTarget);
|
|
4305
4471
|
const [po, pt] = padPair(norm.originOrder, norm.targetOrder);
|
|
@@ -4312,7 +4478,7 @@ function TransitionDesigner({
|
|
|
4312
4478
|
},
|
|
4313
4479
|
[host, transitionSceneId]
|
|
4314
4480
|
);
|
|
4315
|
-
const setRowEffect =
|
|
4481
|
+
const setRowEffect = useCallback10(
|
|
4316
4482
|
(sourceDbId, effect) => {
|
|
4317
4483
|
setRowEffects((prev) => {
|
|
4318
4484
|
const next = { ...prev, [sourceDbId]: effect };
|
|
@@ -4326,7 +4492,7 @@ function TransitionDesigner({
|
|
|
4326
4492
|
},
|
|
4327
4493
|
[host, transitionSceneId]
|
|
4328
4494
|
);
|
|
4329
|
-
const insertGapAbove =
|
|
4495
|
+
const insertGapAbove = useCallback10(
|
|
4330
4496
|
(col, index) => {
|
|
4331
4497
|
const slots = col === "origin" ? originSlots : targetSlots;
|
|
4332
4498
|
const next = [...slots.slice(0, index), null, ...slots.slice(index)];
|
|
@@ -4335,7 +4501,7 @@ function TransitionDesigner({
|
|
|
4335
4501
|
},
|
|
4336
4502
|
[originSlots, targetSlots, mutate]
|
|
4337
4503
|
);
|
|
4338
|
-
const removeGap =
|
|
4504
|
+
const removeGap = useCallback10(
|
|
4339
4505
|
(col, index) => {
|
|
4340
4506
|
const slots = col === "origin" ? originSlots : targetSlots;
|
|
4341
4507
|
const next = slots.filter((_, i) => i !== index);
|
|
@@ -4344,7 +4510,7 @@ function TransitionDesigner({
|
|
|
4344
4510
|
},
|
|
4345
4511
|
[originSlots, targetSlots, mutate]
|
|
4346
4512
|
);
|
|
4347
|
-
const handleDrop =
|
|
4513
|
+
const handleDrop = useCallback10(
|
|
4348
4514
|
(col, to) => {
|
|
4349
4515
|
const from = dragRef.current;
|
|
4350
4516
|
dragRef.current = null;
|
|
@@ -4383,7 +4549,7 @@ function TransitionDesigner({
|
|
|
4383
4549
|
}).length,
|
|
4384
4550
|
[effectiveRows, creatingKeys]
|
|
4385
4551
|
);
|
|
4386
|
-
const createRow =
|
|
4552
|
+
const createRow = useCallback10(
|
|
4387
4553
|
async (row) => {
|
|
4388
4554
|
const key = rowKey(row);
|
|
4389
4555
|
if (!key || !row.type || creatingKeysRef.current.has(key)) return;
|
|
@@ -4438,7 +4604,7 @@ function TransitionDesigner({
|
|
|
4438
4604
|
},
|
|
4439
4605
|
[onCreateCrossfade, onCreateFade, onCreateAudioTransition]
|
|
4440
4606
|
);
|
|
4441
|
-
const createAll =
|
|
4607
|
+
const createAll = useCallback10(async () => {
|
|
4442
4608
|
const source = fadeOnly ? fadeOnlyRowsRef.current : buildRowSlots(originSlotsRef.current, targetSlotsRef.current);
|
|
4443
4609
|
const eligible = source.filter((r) => {
|
|
4444
4610
|
const k = rowKey(r);
|
|
@@ -4507,15 +4673,15 @@ function TransitionDesigner({
|
|
|
4507
4673
|
const base = "group relative rounded-sm border px-2 py-1.5 text-left transition-colors select-none";
|
|
4508
4674
|
const tone = isDragTarget ? "border-sas-accent bg-sas-accent/10" : "border-sas-border bg-sas-panel";
|
|
4509
4675
|
if (slotId === null) {
|
|
4510
|
-
return /* @__PURE__ */
|
|
4676
|
+
return /* @__PURE__ */ jsxs16(
|
|
4511
4677
|
"div",
|
|
4512
4678
|
{
|
|
4513
4679
|
...cellDragProps(col, index, false),
|
|
4514
4680
|
"data-testid": `${testIdPrefix}-${col}-gap-${index}`,
|
|
4515
4681
|
className: `${base} ${tone} border-dashed flex items-center justify-between ${isDragging ? "opacity-40" : "opacity-70"}`,
|
|
4516
4682
|
children: [
|
|
4517
|
-
/* @__PURE__ */
|
|
4518
|
-
/* @__PURE__ */
|
|
4683
|
+
/* @__PURE__ */ jsx20("span", { className: "text-[10px] uppercase tracking-wide text-sas-muted", children: "\u2014 gap \u2014" }),
|
|
4684
|
+
/* @__PURE__ */ jsx20(
|
|
4519
4685
|
"button",
|
|
4520
4686
|
{
|
|
4521
4687
|
type: "button",
|
|
@@ -4532,7 +4698,7 @@ function TransitionDesigner({
|
|
|
4532
4698
|
}
|
|
4533
4699
|
const primary = track ? track.prompt?.trim() || track.name : slotId;
|
|
4534
4700
|
const meta = track ? [track.role, shortId3(track.dbId)].filter(Boolean).join(" \xB7 ") : "missing";
|
|
4535
|
-
return /* @__PURE__ */
|
|
4701
|
+
return /* @__PURE__ */ jsx20(
|
|
4536
4702
|
"div",
|
|
4537
4703
|
{
|
|
4538
4704
|
...cellDragProps(col, index, locked),
|
|
@@ -4540,13 +4706,13 @@ function TransitionDesigner({
|
|
|
4540
4706
|
"data-value": slotId,
|
|
4541
4707
|
className: `${base} ${tone} ${isDragging ? "opacity-40" : ""} ${locked ? "opacity-60" : "cursor-grab active:cursor-grabbing"}`,
|
|
4542
4708
|
title: track ? track.dbId : "Track no longer available",
|
|
4543
|
-
children: /* @__PURE__ */
|
|
4544
|
-
/* @__PURE__ */
|
|
4545
|
-
/* @__PURE__ */
|
|
4546
|
-
/* @__PURE__ */
|
|
4547
|
-
meta && /* @__PURE__ */
|
|
4709
|
+
children: /* @__PURE__ */ jsxs16("div", { className: "flex items-start gap-1", children: [
|
|
4710
|
+
/* @__PURE__ */ jsx20("span", { className: "text-sas-muted/60 text-xs leading-tight pt-0.5", "aria-hidden": true, children: "\u283F" }),
|
|
4711
|
+
/* @__PURE__ */ jsxs16("div", { className: "min-w-0 flex-1", children: [
|
|
4712
|
+
/* @__PURE__ */ jsx20("div", { className: "text-xs text-sas-text truncate", children: primary }),
|
|
4713
|
+
meta && /* @__PURE__ */ jsx20("div", { className: "text-[10px] text-sas-muted truncate mt-0.5", children: meta })
|
|
4548
4714
|
] }),
|
|
4549
|
-
/* @__PURE__ */
|
|
4715
|
+
/* @__PURE__ */ jsx20(
|
|
4550
4716
|
"button",
|
|
4551
4717
|
{
|
|
4552
4718
|
type: "button",
|
|
@@ -4569,26 +4735,26 @@ function TransitionDesigner({
|
|
|
4569
4735
|
const key = rowKey(row);
|
|
4570
4736
|
const isCreatingThis = key !== null && creatingKeys.has(key);
|
|
4571
4737
|
const errMsg = key !== null ? rowErrors[key] : void 0;
|
|
4572
|
-
return /* @__PURE__ */
|
|
4738
|
+
return /* @__PURE__ */ jsxs16(
|
|
4573
4739
|
"div",
|
|
4574
4740
|
{
|
|
4575
4741
|
"data-testid": `${testIdPrefix}-row-${i}`,
|
|
4576
4742
|
className: "grid grid-cols-[1fr_auto] gap-2 items-center",
|
|
4577
4743
|
children: [
|
|
4578
|
-
/* @__PURE__ */
|
|
4744
|
+
/* @__PURE__ */ jsxs16(
|
|
4579
4745
|
"div",
|
|
4580
4746
|
{
|
|
4581
4747
|
"data-testid": `${testIdPrefix}-subject-${slotId}`,
|
|
4582
4748
|
className: `rounded-sm border border-sas-border bg-sas-panel px-2 py-1.5 ${isCreatingThis ? "opacity-60" : ""}`,
|
|
4583
4749
|
title: track ? track.dbId : "Track no longer available",
|
|
4584
4750
|
children: [
|
|
4585
|
-
/* @__PURE__ */
|
|
4586
|
-
/* @__PURE__ */
|
|
4751
|
+
/* @__PURE__ */ jsx20("div", { className: "text-xs text-sas-text truncate", children: track ? track.prompt?.trim() || track.name : slotId }),
|
|
4752
|
+
/* @__PURE__ */ jsx20("div", { className: "text-[10px] text-sas-muted truncate mt-0.5", children: track ? [track.role, shortId3(track.dbId)].filter(Boolean).join(" \xB7 ") : "missing" })
|
|
4587
4753
|
]
|
|
4588
4754
|
}
|
|
4589
4755
|
),
|
|
4590
|
-
/* @__PURE__ */
|
|
4591
|
-
/* @__PURE__ */
|
|
4756
|
+
/* @__PURE__ */ jsxs16("div", { className: "w-[160px] flex flex-col items-center gap-1", children: [
|
|
4757
|
+
/* @__PURE__ */ jsx20(
|
|
4592
4758
|
"span",
|
|
4593
4759
|
{
|
|
4594
4760
|
"data-testid": `${testIdPrefix}-type-${i}`,
|
|
@@ -4596,7 +4762,7 @@ function TransitionDesigner({
|
|
|
4596
4762
|
children: row.type ? TYPE_LABEL[row.type] : "\u2014"
|
|
4597
4763
|
}
|
|
4598
4764
|
),
|
|
4599
|
-
isCreatingThis ? /* @__PURE__ */
|
|
4765
|
+
isCreatingThis ? /* @__PURE__ */ jsx20("div", { className: "w-full", children: /* @__PURE__ */ jsx20(
|
|
4600
4766
|
SorceryProgressBar,
|
|
4601
4767
|
{
|
|
4602
4768
|
isLoading: true,
|
|
@@ -4604,7 +4770,7 @@ function TransitionDesigner({
|
|
|
4604
4770
|
statusText: "CREATING",
|
|
4605
4771
|
estimatedDurationMs: fadeEstimateMs ?? FADE_ESTIMATE_MS
|
|
4606
4772
|
}
|
|
4607
|
-
) }) : /* @__PURE__ */
|
|
4773
|
+
) }) : /* @__PURE__ */ jsx20(
|
|
4608
4774
|
"button",
|
|
4609
4775
|
{
|
|
4610
4776
|
type: "button",
|
|
@@ -4614,7 +4780,7 @@ function TransitionDesigner({
|
|
|
4614
4780
|
children: "Create"
|
|
4615
4781
|
}
|
|
4616
4782
|
),
|
|
4617
|
-
errMsg && /* @__PURE__ */
|
|
4783
|
+
errMsg && /* @__PURE__ */ jsx20(
|
|
4618
4784
|
"span",
|
|
4619
4785
|
{
|
|
4620
4786
|
"data-testid": `${testIdPrefix}-row-error-${i}`,
|
|
@@ -4631,18 +4797,18 @@ function TransitionDesigner({
|
|
|
4631
4797
|
if (fadeOnly) {
|
|
4632
4798
|
const outRows = fadeOnlyRows.filter((r) => r.type === "fade-out");
|
|
4633
4799
|
const inRows = fadeOnlyRows.filter((r) => r.type === "fade-in");
|
|
4634
|
-
return /* @__PURE__ */
|
|
4635
|
-
/* @__PURE__ */
|
|
4636
|
-
/* @__PURE__ */
|
|
4637
|
-
/* @__PURE__ */
|
|
4800
|
+
return /* @__PURE__ */ jsxs16("div", { className: "space-y-2", "data-testid": `${testIdPrefix}-box`, children: [
|
|
4801
|
+
/* @__PURE__ */ jsxs16("div", { className: "flex items-center justify-between gap-3 pb-1 border-b border-sas-border", children: [
|
|
4802
|
+
/* @__PURE__ */ jsxs16("p", { className: "text-[11px] text-sas-muted leading-snug min-w-0", children: [
|
|
4803
|
+
/* @__PURE__ */ jsx20("span", { className: "text-sas-text", children: fromLabel }),
|
|
4638
4804
|
" \u2192",
|
|
4639
4805
|
" ",
|
|
4640
|
-
/* @__PURE__ */
|
|
4806
|
+
/* @__PURE__ */ jsx20("span", { className: "text-sas-text", children: toLabel }),
|
|
4641
4807
|
familyLabel ? ` \xB7 ${familyLabel}` : "",
|
|
4642
4808
|
" \xB7 each entry fades on its own \u2014 origin fades out, target fades in."
|
|
4643
4809
|
] }),
|
|
4644
|
-
/* @__PURE__ */
|
|
4645
|
-
creatingKeys.size > 0 && /* @__PURE__ */
|
|
4810
|
+
/* @__PURE__ */ jsxs16("div", { className: "flex items-center gap-2 shrink-0", children: [
|
|
4811
|
+
creatingKeys.size > 0 && /* @__PURE__ */ jsxs16(
|
|
4646
4812
|
"span",
|
|
4647
4813
|
{
|
|
4648
4814
|
className: "text-[10px] text-sas-accent whitespace-nowrap",
|
|
@@ -4653,7 +4819,7 @@ function TransitionDesigner({
|
|
|
4653
4819
|
]
|
|
4654
4820
|
}
|
|
4655
4821
|
),
|
|
4656
|
-
/* @__PURE__ */
|
|
4822
|
+
/* @__PURE__ */ jsxs16(
|
|
4657
4823
|
"button",
|
|
4658
4824
|
{
|
|
4659
4825
|
type: "button",
|
|
@@ -4670,26 +4836,26 @@ function TransitionDesigner({
|
|
|
4670
4836
|
)
|
|
4671
4837
|
] })
|
|
4672
4838
|
] }),
|
|
4673
|
-
load.status === "loading" && /* @__PURE__ */
|
|
4674
|
-
load.status === "error" && /* @__PURE__ */
|
|
4675
|
-
load.status === "ready" && (fadeOnlyRows.length === 0 ? /* @__PURE__ */
|
|
4839
|
+
load.status === "loading" && /* @__PURE__ */ jsx20("div", { className: "text-xs text-sas-muted py-6 text-center", children: "Loading tracks\u2026" }),
|
|
4840
|
+
load.status === "error" && /* @__PURE__ */ jsx20("div", { className: "text-xs text-sas-danger py-6 text-center", "data-testid": `${testIdPrefix}-error`, children: load.message }),
|
|
4841
|
+
load.status === "ready" && (fadeOnlyRows.length === 0 ? /* @__PURE__ */ jsxs16("div", { className: "text-xs text-sas-muted py-6 text-center", "data-testid": `${testIdPrefix}-empty`, children: [
|
|
4676
4842
|
"Nothing to fade in this panel for either scene. Add tracks to ",
|
|
4677
4843
|
fromLabel,
|
|
4678
4844
|
" or ",
|
|
4679
4845
|
toLabel,
|
|
4680
4846
|
" ",
|
|
4681
4847
|
"first (or free one by deleting an existing fade)."
|
|
4682
|
-
] }) : /* @__PURE__ */
|
|
4683
|
-
outRows.length > 0 && /* @__PURE__ */
|
|
4684
|
-
/* @__PURE__ */
|
|
4848
|
+
] }) : /* @__PURE__ */ jsxs16("div", { className: "space-y-3", children: [
|
|
4849
|
+
outRows.length > 0 && /* @__PURE__ */ jsxs16("div", { className: "space-y-2", "data-testid": `${testIdPrefix}-fade-out-section`, children: [
|
|
4850
|
+
/* @__PURE__ */ jsxs16("span", { className: "text-[10px] uppercase tracking-wide text-sas-muted", children: [
|
|
4685
4851
|
"Origin (",
|
|
4686
4852
|
fromLabel,
|
|
4687
4853
|
") \u2014 fades out"
|
|
4688
4854
|
] }),
|
|
4689
4855
|
outRows.map((row, i) => renderFadeOnlyRow(row, i))
|
|
4690
4856
|
] }),
|
|
4691
|
-
inRows.length > 0 && /* @__PURE__ */
|
|
4692
|
-
/* @__PURE__ */
|
|
4857
|
+
inRows.length > 0 && /* @__PURE__ */ jsxs16("div", { className: "space-y-2", "data-testid": `${testIdPrefix}-fade-in-section`, children: [
|
|
4858
|
+
/* @__PURE__ */ jsxs16("span", { className: "text-[10px] uppercase tracking-wide text-sas-muted", children: [
|
|
4693
4859
|
"Target (",
|
|
4694
4860
|
toLabel,
|
|
4695
4861
|
") \u2014 fades in"
|
|
@@ -4699,22 +4865,22 @@ function TransitionDesigner({
|
|
|
4699
4865
|
] }))
|
|
4700
4866
|
] });
|
|
4701
4867
|
}
|
|
4702
|
-
return /* @__PURE__ */
|
|
4703
|
-
/* @__PURE__ */
|
|
4704
|
-
/* @__PURE__ */
|
|
4705
|
-
/* @__PURE__ */
|
|
4868
|
+
return /* @__PURE__ */ jsxs16("div", { className: "space-y-2", "data-testid": `${testIdPrefix}-box`, children: [
|
|
4869
|
+
/* @__PURE__ */ jsxs16("div", { className: "flex items-center justify-between gap-3 pb-1 border-b border-sas-border", children: [
|
|
4870
|
+
/* @__PURE__ */ jsxs16("p", { className: "text-[11px] text-sas-muted leading-snug min-w-0", children: [
|
|
4871
|
+
/* @__PURE__ */ jsx20("span", { className: "text-sas-text", children: fromLabel }),
|
|
4706
4872
|
" \u2192",
|
|
4707
4873
|
" ",
|
|
4708
|
-
/* @__PURE__ */
|
|
4874
|
+
/* @__PURE__ */ jsx20("span", { className: "text-sas-text", children: toLabel }),
|
|
4709
4875
|
familyLabel ? ` \xB7 ${familyLabel}` : "",
|
|
4710
4876
|
" \xB7 line up a track on each side to crossfade; leave one blank (or insert a gap) to fade."
|
|
4711
4877
|
] }),
|
|
4712
|
-
/* @__PURE__ */
|
|
4713
|
-
creatingKeys.size > 0 && /* @__PURE__ */
|
|
4878
|
+
/* @__PURE__ */ jsxs16("div", { className: "flex items-center gap-2 shrink-0", children: [
|
|
4879
|
+
creatingKeys.size > 0 && /* @__PURE__ */ jsxs16("span", { className: "text-[10px] text-sas-accent whitespace-nowrap", "data-testid": `${testIdPrefix}-creating-count`, children: [
|
|
4714
4880
|
creatingKeys.size,
|
|
4715
4881
|
" creating\u2026"
|
|
4716
4882
|
] }),
|
|
4717
|
-
/* @__PURE__ */
|
|
4883
|
+
/* @__PURE__ */ jsxs16(
|
|
4718
4884
|
"button",
|
|
4719
4885
|
{
|
|
4720
4886
|
type: "button",
|
|
@@ -4731,49 +4897,49 @@ function TransitionDesigner({
|
|
|
4731
4897
|
)
|
|
4732
4898
|
] })
|
|
4733
4899
|
] }),
|
|
4734
|
-
/* @__PURE__ */
|
|
4735
|
-
/* @__PURE__ */
|
|
4900
|
+
/* @__PURE__ */ jsxs16("div", { className: "grid grid-cols-[1fr_auto_1fr] gap-2", children: [
|
|
4901
|
+
/* @__PURE__ */ jsxs16("span", { className: "text-[10px] uppercase tracking-wide text-sas-muted truncate", children: [
|
|
4736
4902
|
"Origin (",
|
|
4737
4903
|
fromLabel,
|
|
4738
4904
|
")"
|
|
4739
4905
|
] }),
|
|
4740
|
-
/* @__PURE__ */
|
|
4741
|
-
/* @__PURE__ */
|
|
4906
|
+
/* @__PURE__ */ jsx20("span", { className: "text-[10px] uppercase tracking-wide text-sas-muted text-center px-2", children: "Transition" }),
|
|
4907
|
+
/* @__PURE__ */ jsxs16("span", { className: "text-[10px] uppercase tracking-wide text-sas-muted truncate text-right", children: [
|
|
4742
4908
|
"Target (",
|
|
4743
4909
|
toLabel,
|
|
4744
4910
|
")"
|
|
4745
4911
|
] })
|
|
4746
4912
|
] }),
|
|
4747
|
-
load.status === "loading" && /* @__PURE__ */
|
|
4748
|
-
load.status === "error" && /* @__PURE__ */
|
|
4749
|
-
load.status === "ready" && (rows.length === 0 ? /* @__PURE__ */
|
|
4913
|
+
load.status === "loading" && /* @__PURE__ */ jsx20("div", { className: "text-xs text-sas-muted py-6 text-center", children: "Loading tracks\u2026" }),
|
|
4914
|
+
load.status === "error" && /* @__PURE__ */ jsx20("div", { className: "text-xs text-sas-danger py-6 text-center", "data-testid": `${testIdPrefix}-error`, children: load.message }),
|
|
4915
|
+
load.status === "ready" && (rows.length === 0 ? /* @__PURE__ */ jsxs16("div", { className: "text-xs text-sas-muted py-6 text-center", "data-testid": `${testIdPrefix}-empty`, children: [
|
|
4750
4916
|
"No tracks to arrange in this panel for either scene. Add tracks to ",
|
|
4751
4917
|
fromLabel,
|
|
4752
4918
|
" or ",
|
|
4753
4919
|
toLabel,
|
|
4754
4920
|
" ",
|
|
4755
4921
|
"first (or free one by deleting an existing crossfade/fade)."
|
|
4756
|
-
] }) : /* @__PURE__ */
|
|
4922
|
+
] }) : /* @__PURE__ */ jsx20("div", { className: "space-y-2", children: rows.map((row, i) => {
|
|
4757
4923
|
const key = rowKey(row);
|
|
4758
4924
|
const isCreatingThis = key !== null && creatingKeys.has(key);
|
|
4759
4925
|
const errMsg = key !== null ? rowErrors[key] : void 0;
|
|
4760
|
-
return /* @__PURE__ */
|
|
4926
|
+
return /* @__PURE__ */ jsxs16(
|
|
4761
4927
|
"div",
|
|
4762
4928
|
{
|
|
4763
4929
|
"data-testid": `${testIdPrefix}-row-${i}`,
|
|
4764
4930
|
className: "grid grid-cols-[1fr_auto_1fr] gap-2 items-center",
|
|
4765
4931
|
children: [
|
|
4766
4932
|
renderCell("origin", i, row.originId),
|
|
4767
|
-
/* @__PURE__ */
|
|
4768
|
-
!row.type ? /* @__PURE__ */
|
|
4933
|
+
/* @__PURE__ */ jsxs16("div", { className: "w-[160px] flex flex-col items-center gap-1", children: [
|
|
4934
|
+
!row.type ? /* @__PURE__ */ jsx20("span", { className: "text-[10px] text-sas-muted/50", children: "\u2014" }) : row.type === "crossfade" ? /* @__PURE__ */ jsx20(
|
|
4769
4935
|
"span",
|
|
4770
4936
|
{
|
|
4771
4937
|
"data-testid": `${testIdPrefix}-type-${i}`,
|
|
4772
4938
|
className: "text-[10px] font-medium px-1.5 py-0.5 rounded-sm border border-sas-accent/50 text-sas-accent",
|
|
4773
4939
|
children: TYPE_LABEL[row.type]
|
|
4774
4940
|
}
|
|
4775
|
-
) : audioEffectsEnabled ? /* @__PURE__ */
|
|
4776
|
-
/* @__PURE__ */
|
|
4941
|
+
) : audioEffectsEnabled ? /* @__PURE__ */ jsxs16("div", { className: "flex items-center gap-1", "data-testid": `${testIdPrefix}-type-${i}`, children: [
|
|
4942
|
+
/* @__PURE__ */ jsx20(
|
|
4777
4943
|
"select",
|
|
4778
4944
|
{
|
|
4779
4945
|
"data-testid": `${testIdPrefix}-effect-${i}`,
|
|
@@ -4783,11 +4949,11 @@ function TransitionDesigner({
|
|
|
4783
4949
|
if (id) setRowEffect(id, e.target.value);
|
|
4784
4950
|
},
|
|
4785
4951
|
className: "text-[10px] bg-sas-panel border border-sas-border rounded-sm px-1 py-0.5 text-sas-text",
|
|
4786
|
-
children: AUDIO_EFFECTS.map((eff) => /* @__PURE__ */
|
|
4952
|
+
children: AUDIO_EFFECTS.map((eff) => /* @__PURE__ */ jsx20("option", { value: eff, children: AUDIO_EFFECT_LABEL[eff] }, eff))
|
|
4787
4953
|
}
|
|
4788
4954
|
),
|
|
4789
|
-
/* @__PURE__ */
|
|
4790
|
-
] }) : /* @__PURE__ */
|
|
4955
|
+
/* @__PURE__ */ jsx20("span", { className: "text-[9px] text-sas-muted", children: row.type === "fade-out" ? "out" : "in" })
|
|
4956
|
+
] }) : /* @__PURE__ */ jsx20(
|
|
4791
4957
|
"span",
|
|
4792
4958
|
{
|
|
4793
4959
|
"data-testid": `${testIdPrefix}-type-${i}`,
|
|
@@ -4795,7 +4961,7 @@ function TransitionDesigner({
|
|
|
4795
4961
|
children: TYPE_LABEL[row.type]
|
|
4796
4962
|
}
|
|
4797
4963
|
),
|
|
4798
|
-
isCreatingThis ? /* @__PURE__ */
|
|
4964
|
+
isCreatingThis ? /* @__PURE__ */ jsx20("div", { className: "w-full", children: /* @__PURE__ */ jsx20(
|
|
4799
4965
|
SorceryProgressBar,
|
|
4800
4966
|
{
|
|
4801
4967
|
isLoading: true,
|
|
@@ -4803,7 +4969,7 @@ function TransitionDesigner({
|
|
|
4803
4969
|
statusText: "CREATING",
|
|
4804
4970
|
estimatedDurationMs: row.type === "crossfade" ? CROSSFADE_ESTIMATE_MS : FADE_ESTIMATE_MS
|
|
4805
4971
|
}
|
|
4806
|
-
) }) : /* @__PURE__ */
|
|
4972
|
+
) }) : /* @__PURE__ */ jsx20(
|
|
4807
4973
|
"button",
|
|
4808
4974
|
{
|
|
4809
4975
|
type: "button",
|
|
@@ -4814,7 +4980,7 @@ function TransitionDesigner({
|
|
|
4814
4980
|
children: "Create"
|
|
4815
4981
|
}
|
|
4816
4982
|
),
|
|
4817
|
-
errMsg && /* @__PURE__ */
|
|
4983
|
+
errMsg && /* @__PURE__ */ jsx20(
|
|
4818
4984
|
"span",
|
|
4819
4985
|
{
|
|
4820
4986
|
"data-testid": `${testIdPrefix}-row-error-${i}`,
|
|
@@ -4833,8 +4999,8 @@ function TransitionDesigner({
|
|
|
4833
4999
|
}
|
|
4834
5000
|
|
|
4835
5001
|
// src/components/PanelMasterStrip.tsx
|
|
4836
|
-
import { useMemo as useMemo7, useState as
|
|
4837
|
-
import { jsx as
|
|
5002
|
+
import { useMemo as useMemo7, useState as useState15 } from "react";
|
|
5003
|
+
import { jsx as jsx21, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
4838
5004
|
function PanelMasterStrip({
|
|
4839
5005
|
bus,
|
|
4840
5006
|
levels = null,
|
|
@@ -4853,7 +5019,7 @@ function PanelMasterStrip({
|
|
|
4853
5019
|
onToggleFxEnabled,
|
|
4854
5020
|
onShowFxEditor
|
|
4855
5021
|
}) {
|
|
4856
|
-
const [search, setSearch] =
|
|
5022
|
+
const [search, setSearch] = useState15("");
|
|
4857
5023
|
const filtered = useMemo7(() => {
|
|
4858
5024
|
const q = search.trim().toLowerCase();
|
|
4859
5025
|
if (!q) return availableFx;
|
|
@@ -4861,14 +5027,14 @@ function PanelMasterStrip({
|
|
|
4861
5027
|
(fx) => fx.name.toLowerCase().includes(q) || fx.manufacturer.toLowerCase().includes(q)
|
|
4862
5028
|
);
|
|
4863
5029
|
}, [availableFx, search]);
|
|
4864
|
-
return /* @__PURE__ */
|
|
5030
|
+
return /* @__PURE__ */ jsxs17(
|
|
4865
5031
|
"div",
|
|
4866
5032
|
{
|
|
4867
5033
|
"data-testid": "panel-master-strip",
|
|
4868
5034
|
className: `flex flex-col gap-1 px-2 py-1.5 rounded-sm border border-sas-border border-l-2 border-l-sas-accent/50 bg-sas-accent/5 transition-opacity ${soloedOut ? "opacity-40" : ""}`,
|
|
4869
5035
|
children: [
|
|
4870
|
-
/* @__PURE__ */
|
|
4871
|
-
/* @__PURE__ */
|
|
5036
|
+
/* @__PURE__ */ jsxs17("div", { className: "flex items-center gap-2", children: [
|
|
5037
|
+
/* @__PURE__ */ jsx21(
|
|
4872
5038
|
"span",
|
|
4873
5039
|
{
|
|
4874
5040
|
className: "text-[9px] font-bold tracking-widest text-sas-muted/70 select-none",
|
|
@@ -4876,8 +5042,8 @@ function PanelMasterStrip({
|
|
|
4876
5042
|
children: "BUS"
|
|
4877
5043
|
}
|
|
4878
5044
|
),
|
|
4879
|
-
/* @__PURE__ */
|
|
4880
|
-
/* @__PURE__ */
|
|
5045
|
+
/* @__PURE__ */ jsxs17("div", { className: "flex-1 min-w-[8rem] flex flex-col gap-0.5", children: [
|
|
5046
|
+
/* @__PURE__ */ jsx21(
|
|
4881
5047
|
VolumeSlider,
|
|
4882
5048
|
{
|
|
4883
5049
|
value: dbToSlider(bus.volume),
|
|
@@ -4885,8 +5051,8 @@ function PanelMasterStrip({
|
|
|
4885
5051
|
disabled
|
|
4886
5052
|
}
|
|
4887
5053
|
),
|
|
4888
|
-
/* @__PURE__ */
|
|
4889
|
-
/* @__PURE__ */
|
|
5054
|
+
/* @__PURE__ */ jsxs17("div", { className: "flex flex-col gap-px", "data-testid": "bus-meter", children: [
|
|
5055
|
+
/* @__PURE__ */ jsx21(
|
|
4890
5056
|
LevelMeter,
|
|
4891
5057
|
{
|
|
4892
5058
|
peakDb: levels?.leftDb ?? -120,
|
|
@@ -4896,7 +5062,7 @@ function PanelMasterStrip({
|
|
|
4896
5062
|
"data-testid": "bus-meter-left"
|
|
4897
5063
|
}
|
|
4898
5064
|
),
|
|
4899
|
-
/* @__PURE__ */
|
|
5065
|
+
/* @__PURE__ */ jsx21(
|
|
4900
5066
|
LevelMeter,
|
|
4901
5067
|
{
|
|
4902
5068
|
peakDb: levels?.rightDb ?? -120,
|
|
@@ -4907,7 +5073,7 @@ function PanelMasterStrip({
|
|
|
4907
5073
|
)
|
|
4908
5074
|
] })
|
|
4909
5075
|
] }),
|
|
4910
|
-
/* @__PURE__ */
|
|
5076
|
+
/* @__PURE__ */ jsx21(
|
|
4911
5077
|
"button",
|
|
4912
5078
|
{
|
|
4913
5079
|
"data-testid": "bus-mute-button",
|
|
@@ -4918,7 +5084,7 @@ function PanelMasterStrip({
|
|
|
4918
5084
|
children: "M"
|
|
4919
5085
|
}
|
|
4920
5086
|
),
|
|
4921
|
-
/* @__PURE__ */
|
|
5087
|
+
/* @__PURE__ */ jsx21(
|
|
4922
5088
|
"button",
|
|
4923
5089
|
{
|
|
4924
5090
|
"data-testid": "bus-solo-button",
|
|
@@ -4929,14 +5095,14 @@ function PanelMasterStrip({
|
|
|
4929
5095
|
children: "S"
|
|
4930
5096
|
}
|
|
4931
5097
|
),
|
|
4932
|
-
/* @__PURE__ */
|
|
5098
|
+
/* @__PURE__ */ jsx21("div", { className: "flex items-center gap-1 max-w-[45%] min-w-0 overflow-x-auto", children: bus.fx.map((fx) => /* @__PURE__ */ jsxs17(
|
|
4933
5099
|
"span",
|
|
4934
5100
|
{
|
|
4935
5101
|
"data-testid": `bus-fx-chip-${fx.index}`,
|
|
4936
5102
|
className: `flex items-center gap-1 px-1.5 py-0.5 rounded-sm border text-[10px] whitespace-nowrap ${fx.enabled ? "border-sas-accent/60 text-sas-accent bg-sas-accent/10" : "border-sas-border text-sas-muted/50 bg-sas-panel"}`,
|
|
4937
5103
|
title: `${fx.name}${fx.enabled ? "" : " (bypassed)"}`,
|
|
4938
5104
|
children: [
|
|
4939
|
-
/* @__PURE__ */
|
|
5105
|
+
/* @__PURE__ */ jsx21(
|
|
4940
5106
|
"button",
|
|
4941
5107
|
{
|
|
4942
5108
|
"data-testid": `bus-fx-toggle-${fx.index}`,
|
|
@@ -4947,7 +5113,7 @@ function PanelMasterStrip({
|
|
|
4947
5113
|
children: fx.enabled ? "\u25CF" : "\u25CB"
|
|
4948
5114
|
}
|
|
4949
5115
|
),
|
|
4950
|
-
onShowFxEditor ? /* @__PURE__ */
|
|
5116
|
+
onShowFxEditor ? /* @__PURE__ */ jsx21(
|
|
4951
5117
|
"button",
|
|
4952
5118
|
{
|
|
4953
5119
|
"data-testid": `bus-fx-edit-${fx.index}`,
|
|
@@ -4957,8 +5123,8 @@ function PanelMasterStrip({
|
|
|
4957
5123
|
title: `Open ${fx.name} editor`,
|
|
4958
5124
|
children: fx.name
|
|
4959
5125
|
}
|
|
4960
|
-
) : /* @__PURE__ */
|
|
4961
|
-
/* @__PURE__ */
|
|
5126
|
+
) : /* @__PURE__ */ jsx21("span", { className: "max-w-[80px] truncate", children: fx.name }),
|
|
5127
|
+
/* @__PURE__ */ jsx21(
|
|
4962
5128
|
"button",
|
|
4963
5129
|
{
|
|
4964
5130
|
"data-testid": `bus-fx-remove-${fx.index}`,
|
|
@@ -4973,7 +5139,7 @@ function PanelMasterStrip({
|
|
|
4973
5139
|
},
|
|
4974
5140
|
`${fx.index}:${fx.pluginId}`
|
|
4975
5141
|
)) }),
|
|
4976
|
-
/* @__PURE__ */
|
|
5142
|
+
/* @__PURE__ */ jsx21(
|
|
4977
5143
|
"button",
|
|
4978
5144
|
{
|
|
4979
5145
|
"data-testid": "bus-fx-add-button",
|
|
@@ -4985,9 +5151,9 @@ function PanelMasterStrip({
|
|
|
4985
5151
|
}
|
|
4986
5152
|
)
|
|
4987
5153
|
] }),
|
|
4988
|
-
fxPickerOpen && /* @__PURE__ */
|
|
4989
|
-
/* @__PURE__ */
|
|
4990
|
-
/* @__PURE__ */
|
|
5154
|
+
fxPickerOpen && /* @__PURE__ */ jsxs17("div", { "data-testid": "bus-fx-picker", className: "flex flex-col gap-2 pt-1", children: [
|
|
5155
|
+
/* @__PURE__ */ jsxs17("div", { className: "flex items-center gap-2", children: [
|
|
5156
|
+
/* @__PURE__ */ jsx21(
|
|
4991
5157
|
"input",
|
|
4992
5158
|
{
|
|
4993
5159
|
type: "text",
|
|
@@ -4997,7 +5163,7 @@ function PanelMasterStrip({
|
|
|
4997
5163
|
className: "sas-input flex-1 px-2 py-1 text-xs"
|
|
4998
5164
|
}
|
|
4999
5165
|
),
|
|
5000
|
-
onRefreshFx && /* @__PURE__ */
|
|
5166
|
+
onRefreshFx && /* @__PURE__ */ jsx21(
|
|
5001
5167
|
"button",
|
|
5002
5168
|
{
|
|
5003
5169
|
onClick: () => onRefreshFx(),
|
|
@@ -5008,8 +5174,8 @@ function PanelMasterStrip({
|
|
|
5008
5174
|
}
|
|
5009
5175
|
)
|
|
5010
5176
|
] }),
|
|
5011
|
-
fxLoading && availableFx.length === 0 ? /* @__PURE__ */
|
|
5012
|
-
filtered.map((fx) => /* @__PURE__ */
|
|
5177
|
+
fxLoading && availableFx.length === 0 ? /* @__PURE__ */ jsx21("div", { className: "text-xs text-sas-muted/60 text-center py-3", children: "Scanning plugins..." }) : /* @__PURE__ */ jsxs17("div", { className: "grid grid-cols-3 gap-1 max-h-[140px] overflow-y-auto", children: [
|
|
5178
|
+
filtered.map((fx) => /* @__PURE__ */ jsxs17(
|
|
5013
5179
|
"button",
|
|
5014
5180
|
{
|
|
5015
5181
|
"data-testid": `bus-fx-pick-${fx.pluginId}`,
|
|
@@ -5017,13 +5183,13 @@ function PanelMasterStrip({
|
|
|
5017
5183
|
className: "flex flex-col items-start px-2 py-1.5 rounded-sm border text-left transition-colors border-sas-border bg-sas-panel-alt text-sas-muted hover:border-sas-accent hover:text-sas-accent",
|
|
5018
5184
|
title: `${fx.name} by ${fx.manufacturer} (${fx.type.toUpperCase()})`,
|
|
5019
5185
|
children: [
|
|
5020
|
-
/* @__PURE__ */
|
|
5021
|
-
/* @__PURE__ */
|
|
5186
|
+
/* @__PURE__ */ jsx21("span", { className: "text-xs font-medium truncate w-full", children: fx.name }),
|
|
5187
|
+
/* @__PURE__ */ jsx21("span", { className: "text-[9px] text-sas-muted/50 truncate w-full", children: fx.manufacturer || fx.type.toUpperCase() })
|
|
5022
5188
|
]
|
|
5023
5189
|
},
|
|
5024
5190
|
fx.pluginId
|
|
5025
5191
|
)),
|
|
5026
|
-
filtered.length === 0 && /* @__PURE__ */
|
|
5192
|
+
filtered.length === 0 && /* @__PURE__ */ jsx21("div", { className: "col-span-3 text-xs text-sas-muted/60 text-center py-2", children: search.trim() ? "No matches" : "No FX plugins found" })
|
|
5027
5193
|
] })
|
|
5028
5194
|
] })
|
|
5029
5195
|
]
|
|
@@ -5032,18 +5198,18 @@ function PanelMasterStrip({
|
|
|
5032
5198
|
}
|
|
5033
5199
|
|
|
5034
5200
|
// src/hooks/usePanelBus.ts
|
|
5035
|
-
import { useCallback as
|
|
5201
|
+
import { useCallback as useCallback11, useEffect as useEffect12, useRef as useRef12, useState as useState16 } from "react";
|
|
5036
5202
|
var LEVELS_POLL_MS = 66;
|
|
5037
5203
|
function usePanelBus(host, activeSceneId) {
|
|
5038
5204
|
const supported = typeof host.getPanelBusState === "function";
|
|
5039
|
-
const [bus, setBus] =
|
|
5040
|
-
const [levels, setLevels] =
|
|
5041
|
-
const [availableFx, setAvailableFx] =
|
|
5042
|
-
const [fxLoading, setFxLoading] =
|
|
5043
|
-
const [fxPickerOpen, setFxPickerOpen] =
|
|
5205
|
+
const [bus, setBus] = useState16(null);
|
|
5206
|
+
const [levels, setLevels] = useState16(null);
|
|
5207
|
+
const [availableFx, setAvailableFx] = useState16([]);
|
|
5208
|
+
const [fxLoading, setFxLoading] = useState16(false);
|
|
5209
|
+
const [fxPickerOpen, setFxPickerOpen] = useState16(false);
|
|
5044
5210
|
const fxLoadedRef = useRef12(false);
|
|
5045
5211
|
const loadSeqRef = useRef12(0);
|
|
5046
|
-
const reload =
|
|
5212
|
+
const reload = useCallback11(async () => {
|
|
5047
5213
|
if (!supported || !activeSceneId || !host.getPanelBusState) {
|
|
5048
5214
|
setBus(null);
|
|
5049
5215
|
return;
|
|
@@ -5055,12 +5221,12 @@ function usePanelBus(host, activeSceneId) {
|
|
|
5055
5221
|
} catch {
|
|
5056
5222
|
}
|
|
5057
5223
|
}, [host, activeSceneId, supported]);
|
|
5058
|
-
|
|
5224
|
+
useEffect12(() => {
|
|
5059
5225
|
setBus(null);
|
|
5060
5226
|
setFxPickerOpen(false);
|
|
5061
5227
|
void reload();
|
|
5062
5228
|
}, [reload]);
|
|
5063
|
-
|
|
5229
|
+
useEffect12(() => {
|
|
5064
5230
|
if (!supported || !activeSceneId || !bus?.engaged || !host.getPanelBusLevels) {
|
|
5065
5231
|
setLevels(null);
|
|
5066
5232
|
return;
|
|
@@ -5082,7 +5248,7 @@ function usePanelBus(host, activeSceneId) {
|
|
|
5082
5248
|
clearInterval(id);
|
|
5083
5249
|
};
|
|
5084
5250
|
}, [supported, activeSceneId, bus?.engaged, host]);
|
|
5085
|
-
const loadFxList =
|
|
5251
|
+
const loadFxList = useCallback11(
|
|
5086
5252
|
async (opts) => {
|
|
5087
5253
|
if (!supported || !host.getAvailableFx) return;
|
|
5088
5254
|
if (fxLoadedRef.current && !opts.force && !opts.rescan) return;
|
|
@@ -5098,14 +5264,14 @@ function usePanelBus(host, activeSceneId) {
|
|
|
5098
5264
|
},
|
|
5099
5265
|
[host, supported]
|
|
5100
5266
|
);
|
|
5101
|
-
const openPicker =
|
|
5267
|
+
const openPicker = useCallback11(
|
|
5102
5268
|
(open) => {
|
|
5103
5269
|
setFxPickerOpen(open);
|
|
5104
5270
|
if (open) void loadFxList({});
|
|
5105
5271
|
},
|
|
5106
5272
|
[loadFxList]
|
|
5107
5273
|
);
|
|
5108
|
-
const mutate =
|
|
5274
|
+
const mutate = useCallback11(
|
|
5109
5275
|
(fn) => {
|
|
5110
5276
|
if (!fn || !activeSceneId) return;
|
|
5111
5277
|
void (async () => {
|
|
@@ -5149,8 +5315,8 @@ function usePanelBus(host, activeSceneId) {
|
|
|
5149
5315
|
}
|
|
5150
5316
|
|
|
5151
5317
|
// src/components/DownloadPackButton.tsx
|
|
5152
|
-
import { useCallback as
|
|
5153
|
-
import { jsx as
|
|
5318
|
+
import { useCallback as useCallback12, useEffect as useEffect13, useState as useState17 } from "react";
|
|
5319
|
+
import { jsx as jsx22, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
5154
5320
|
function formatSize(bytes) {
|
|
5155
5321
|
if (!bytes || bytes <= 0) return "";
|
|
5156
5322
|
const gb = bytes / 1024 ** 3;
|
|
@@ -5166,10 +5332,10 @@ var DownloadPackButton = ({
|
|
|
5166
5332
|
variant = "compact",
|
|
5167
5333
|
onDownloadComplete
|
|
5168
5334
|
}) => {
|
|
5169
|
-
const [status, setStatus] =
|
|
5170
|
-
const [progress, setProgress] =
|
|
5171
|
-
const [errorMessage, setErrorMessage] =
|
|
5172
|
-
|
|
5335
|
+
const [status, setStatus] = useState17("idle");
|
|
5336
|
+
const [progress, setProgress] = useState17(0);
|
|
5337
|
+
const [errorMessage, setErrorMessage] = useState17(null);
|
|
5338
|
+
useEffect13(() => {
|
|
5173
5339
|
const unsub = host.onSamplePackProgress(packId, (p) => {
|
|
5174
5340
|
setStatus(p.status);
|
|
5175
5341
|
setProgress(p.progress);
|
|
@@ -5184,7 +5350,7 @@ var DownloadPackButton = ({
|
|
|
5184
5350
|
});
|
|
5185
5351
|
return unsub;
|
|
5186
5352
|
}, [host, packId, onDownloadComplete]);
|
|
5187
|
-
const handleClick =
|
|
5353
|
+
const handleClick = useCallback12(async () => {
|
|
5188
5354
|
if (status !== "idle" && status !== "error") return;
|
|
5189
5355
|
try {
|
|
5190
5356
|
setStatus("downloading");
|
|
@@ -5238,8 +5404,8 @@ var DownloadPackButton = ({
|
|
|
5238
5404
|
} else {
|
|
5239
5405
|
className = `${baseClasses} text-sas-muted hover:text-sas-accent border-sas-border hover:border-sas-accent`;
|
|
5240
5406
|
}
|
|
5241
|
-
return /* @__PURE__ */
|
|
5242
|
-
/* @__PURE__ */
|
|
5407
|
+
return /* @__PURE__ */ jsxs18("div", { children: [
|
|
5408
|
+
/* @__PURE__ */ jsx22(
|
|
5243
5409
|
"button",
|
|
5244
5410
|
{
|
|
5245
5411
|
"data-testid": `download-pack-button-${packId}`,
|
|
@@ -5250,12 +5416,12 @@ var DownloadPackButton = ({
|
|
|
5250
5416
|
children: buttonLabel
|
|
5251
5417
|
}
|
|
5252
5418
|
),
|
|
5253
|
-
variant === "large" && status === "error" && errorMessage && /* @__PURE__ */
|
|
5419
|
+
variant === "large" && status === "error" && errorMessage && /* @__PURE__ */ jsx22("div", { className: "text-xs text-sas-danger mt-2", "data-testid": `download-pack-error-${packId}`, children: errorMessage })
|
|
5254
5420
|
] });
|
|
5255
5421
|
};
|
|
5256
5422
|
|
|
5257
5423
|
// src/components/SamplePackCTACard.tsx
|
|
5258
|
-
import { jsx as
|
|
5424
|
+
import { jsx as jsx23, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
5259
5425
|
var SamplePackCTACard = ({
|
|
5260
5426
|
host,
|
|
5261
5427
|
pack,
|
|
@@ -5263,7 +5429,7 @@ var SamplePackCTACard = ({
|
|
|
5263
5429
|
onDownloadComplete
|
|
5264
5430
|
}) => {
|
|
5265
5431
|
if (status === "checking") {
|
|
5266
|
-
return /* @__PURE__ */
|
|
5432
|
+
return /* @__PURE__ */ jsx23(
|
|
5267
5433
|
"div",
|
|
5268
5434
|
{
|
|
5269
5435
|
"data-testid": `sample-pack-cta-checking-${pack.packId}`,
|
|
@@ -5274,16 +5440,16 @@ var SamplePackCTACard = ({
|
|
|
5274
5440
|
}
|
|
5275
5441
|
const headline = status === "stale" ? `${pack.displayName} update available` : `${pack.displayName} not installed`;
|
|
5276
5442
|
const sublabel = status === "stale" ? `A newer version is available for download.` : pack.description;
|
|
5277
|
-
return /* @__PURE__ */
|
|
5443
|
+
return /* @__PURE__ */ jsxs19(
|
|
5278
5444
|
"div",
|
|
5279
5445
|
{
|
|
5280
5446
|
"data-testid": `sample-pack-cta-${pack.packId}`,
|
|
5281
5447
|
className: "flex flex-col items-center justify-center py-12 px-6 text-center",
|
|
5282
5448
|
children: [
|
|
5283
|
-
/* @__PURE__ */
|
|
5284
|
-
/* @__PURE__ */
|
|
5285
|
-
/* @__PURE__ */
|
|
5286
|
-
/* @__PURE__ */
|
|
5449
|
+
/* @__PURE__ */ jsx23("div", { className: "text-sm uppercase tracking-wide text-sas-muted mb-2", children: status === "stale" ? "Update available" : "Sample library not installed" }),
|
|
5450
|
+
/* @__PURE__ */ jsx23("div", { className: "text-base text-sas-text mb-1", children: headline }),
|
|
5451
|
+
/* @__PURE__ */ jsx23("div", { className: "text-xs text-sas-muted mb-6 max-w-md", children: sublabel }),
|
|
5452
|
+
/* @__PURE__ */ jsx23(
|
|
5287
5453
|
DownloadPackButton,
|
|
5288
5454
|
{
|
|
5289
5455
|
host,
|
|
@@ -5300,7 +5466,7 @@ var SamplePackCTACard = ({
|
|
|
5300
5466
|
};
|
|
5301
5467
|
|
|
5302
5468
|
// src/components/WaveformView.tsx
|
|
5303
|
-
import { useEffect as
|
|
5469
|
+
import { useEffect as useEffect14, useRef as useRef13, useState as useState18 } from "react";
|
|
5304
5470
|
|
|
5305
5471
|
// src/components/waveform.ts
|
|
5306
5472
|
function computePeaks(audioBuffer, bins, targetSamples) {
|
|
@@ -5363,7 +5529,7 @@ function drawWaveform(canvas, peaks, options = {}) {
|
|
|
5363
5529
|
}
|
|
5364
5530
|
|
|
5365
5531
|
// src/components/WaveformView.tsx
|
|
5366
|
-
import { jsx as
|
|
5532
|
+
import { jsx as jsx24 } from "react/jsx-runtime";
|
|
5367
5533
|
var WaveformView = ({
|
|
5368
5534
|
host,
|
|
5369
5535
|
filePath,
|
|
@@ -5373,8 +5539,8 @@ var WaveformView = ({
|
|
|
5373
5539
|
targetSamples
|
|
5374
5540
|
}) => {
|
|
5375
5541
|
const canvasRef = useRef13(null);
|
|
5376
|
-
const [peaks, setPeaks] =
|
|
5377
|
-
|
|
5542
|
+
const [peaks, setPeaks] = useState18(null);
|
|
5543
|
+
useEffect14(() => {
|
|
5378
5544
|
let cancelled = false;
|
|
5379
5545
|
let audioContext = null;
|
|
5380
5546
|
(async () => {
|
|
@@ -5400,7 +5566,7 @@ var WaveformView = ({
|
|
|
5400
5566
|
cancelled = true;
|
|
5401
5567
|
};
|
|
5402
5568
|
}, [host, filePath, bins, targetSamples]);
|
|
5403
|
-
|
|
5569
|
+
useEffect14(() => {
|
|
5404
5570
|
if (!peaks) return;
|
|
5405
5571
|
const canvas = canvasRef.current;
|
|
5406
5572
|
if (!canvas) return;
|
|
@@ -5411,7 +5577,7 @@ var WaveformView = ({
|
|
|
5411
5577
|
observer.observe(canvas);
|
|
5412
5578
|
return () => observer.disconnect();
|
|
5413
5579
|
}, [peaks, fillStyle]);
|
|
5414
|
-
return /* @__PURE__ */
|
|
5580
|
+
return /* @__PURE__ */ jsx24(
|
|
5415
5581
|
"canvas",
|
|
5416
5582
|
{
|
|
5417
5583
|
ref: canvasRef,
|
|
@@ -5422,8 +5588,8 @@ var WaveformView = ({
|
|
|
5422
5588
|
};
|
|
5423
5589
|
|
|
5424
5590
|
// src/components/ScrollingWaveform.tsx
|
|
5425
|
-
import { useEffect as
|
|
5426
|
-
import { jsx as
|
|
5591
|
+
import { useEffect as useEffect15, useRef as useRef14 } from "react";
|
|
5592
|
+
import { jsx as jsx25 } from "react/jsx-runtime";
|
|
5427
5593
|
var ScrollingWaveform = ({
|
|
5428
5594
|
getPeakDb,
|
|
5429
5595
|
active,
|
|
@@ -5435,7 +5601,7 @@ var ScrollingWaveform = ({
|
|
|
5435
5601
|
const ringRef = useRef14(new Float32Array(columns));
|
|
5436
5602
|
const writeIdxRef = useRef14(0);
|
|
5437
5603
|
const rafRef = useRef14(null);
|
|
5438
|
-
|
|
5604
|
+
useEffect15(() => {
|
|
5439
5605
|
if (ringRef.current.length !== columns) {
|
|
5440
5606
|
const next = new Float32Array(columns);
|
|
5441
5607
|
const prev = ringRef.current;
|
|
@@ -5447,7 +5613,7 @@ var ScrollingWaveform = ({
|
|
|
5447
5613
|
writeIdxRef.current = writeIdxRef.current % columns;
|
|
5448
5614
|
}
|
|
5449
5615
|
}, [columns]);
|
|
5450
|
-
|
|
5616
|
+
useEffect15(() => {
|
|
5451
5617
|
if (!active) {
|
|
5452
5618
|
if (rafRef.current !== null) {
|
|
5453
5619
|
cancelAnimationFrame(rafRef.current);
|
|
@@ -5499,7 +5665,7 @@ var ScrollingWaveform = ({
|
|
|
5499
5665
|
}
|
|
5500
5666
|
};
|
|
5501
5667
|
}, [active, getPeakDb, fillStyle]);
|
|
5502
|
-
return /* @__PURE__ */
|
|
5668
|
+
return /* @__PURE__ */ jsx25(
|
|
5503
5669
|
"canvas",
|
|
5504
5670
|
{
|
|
5505
5671
|
ref: canvasRef,
|
|
@@ -5510,8 +5676,8 @@ var ScrollingWaveform = ({
|
|
|
5510
5676
|
};
|
|
5511
5677
|
|
|
5512
5678
|
// src/components/OffsetScrubber.tsx
|
|
5513
|
-
import { useCallback as
|
|
5514
|
-
import { jsx as
|
|
5679
|
+
import { useCallback as useCallback13, useEffect as useEffect16, useMemo as useMemo8, useRef as useRef15, useState as useState19 } from "react";
|
|
5680
|
+
import { jsx as jsx26, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
5515
5681
|
var SLIDER_HEIGHT_PX = 28;
|
|
5516
5682
|
var TICK_HEIGHT_PX = 14;
|
|
5517
5683
|
var DOWNBEAT_TICK_HEIGHT_PX = 22;
|
|
@@ -5525,9 +5691,9 @@ function OffsetScrubber({
|
|
|
5525
5691
|
disabled = false
|
|
5526
5692
|
}) {
|
|
5527
5693
|
const trackRef = useRef15(null);
|
|
5528
|
-
const [draftOffset, setDraftOffset] =
|
|
5529
|
-
const [isDragging, setIsDragging] =
|
|
5530
|
-
|
|
5694
|
+
const [draftOffset, setDraftOffset] = useState19(offsetSamples);
|
|
5695
|
+
const [isDragging, setIsDragging] = useState19(false);
|
|
5696
|
+
useEffect16(() => {
|
|
5531
5697
|
if (!isDragging) setDraftOffset(offsetSamples);
|
|
5532
5698
|
}, [offsetSamples, isDragging]);
|
|
5533
5699
|
const sampleRate = cuePoints?.sample_rate ?? 44100;
|
|
@@ -5536,14 +5702,14 @@ function OffsetScrubber({
|
|
|
5536
5702
|
return Math.round(60 / projectBpm * sampleRate);
|
|
5537
5703
|
}, [projectBpm, sampleRate]);
|
|
5538
5704
|
const rangeSamples = beatsForRange * meter;
|
|
5539
|
-
const sampleToFraction =
|
|
5705
|
+
const sampleToFraction = useCallback13(
|
|
5540
5706
|
(sample) => {
|
|
5541
5707
|
const clamped = Math.max(-rangeSamples, Math.min(rangeSamples, sample));
|
|
5542
5708
|
return (clamped + rangeSamples) / (2 * rangeSamples);
|
|
5543
5709
|
},
|
|
5544
5710
|
[rangeSamples]
|
|
5545
5711
|
);
|
|
5546
|
-
const fractionToSample =
|
|
5712
|
+
const fractionToSample = useCallback13(
|
|
5547
5713
|
(fraction) => {
|
|
5548
5714
|
const clamped = Math.max(0, Math.min(1, fraction));
|
|
5549
5715
|
return Math.round(clamped * 2 * rangeSamples - rangeSamples);
|
|
@@ -5557,7 +5723,7 @@ function OffsetScrubber({
|
|
|
5557
5723
|
const negatives = positives.slice(1).map((p) => -p);
|
|
5558
5724
|
return [...negatives, ...positives].sort((a, b) => a - b);
|
|
5559
5725
|
}, [cuePoints]);
|
|
5560
|
-
const snapToBeat =
|
|
5726
|
+
const snapToBeat = useCallback13(
|
|
5561
5727
|
(sample) => {
|
|
5562
5728
|
if (snapTargets.length === 0) return sample;
|
|
5563
5729
|
let best = snapTargets[0];
|
|
@@ -5573,7 +5739,7 @@ function OffsetScrubber({
|
|
|
5573
5739
|
},
|
|
5574
5740
|
[snapTargets]
|
|
5575
5741
|
);
|
|
5576
|
-
const handlePointerDown =
|
|
5742
|
+
const handlePointerDown = useCallback13(
|
|
5577
5743
|
(e) => {
|
|
5578
5744
|
if (disabled || !cuePoints) return;
|
|
5579
5745
|
e.preventDefault();
|
|
@@ -5607,7 +5773,7 @@ function OffsetScrubber({
|
|
|
5607
5773
|
},
|
|
5608
5774
|
[disabled, cuePoints, fractionToSample, onChange, snapToBeat]
|
|
5609
5775
|
);
|
|
5610
|
-
const handleResetToZero =
|
|
5776
|
+
const handleResetToZero = useCallback13(() => {
|
|
5611
5777
|
if (disabled) return;
|
|
5612
5778
|
setDraftOffset(0);
|
|
5613
5779
|
onChange(0);
|
|
@@ -5626,9 +5792,9 @@ function OffsetScrubber({
|
|
|
5626
5792
|
});
|
|
5627
5793
|
}, [cuePoints, sampleToFraction]);
|
|
5628
5794
|
const isDisabled = disabled || !cuePoints || cuePoints.beats.length === 0;
|
|
5629
|
-
return /* @__PURE__ */
|
|
5630
|
-
/* @__PURE__ */
|
|
5631
|
-
/* @__PURE__ */
|
|
5795
|
+
return /* @__PURE__ */ jsxs20("div", { "data-testid": "offset-scrubber", className: "flex items-center gap-2 w-full", children: [
|
|
5796
|
+
/* @__PURE__ */ jsx26("span", { className: "text-[9px] text-sas-muted/60 uppercase tracking-wide flex-shrink-0", children: "Align" }),
|
|
5797
|
+
/* @__PURE__ */ jsxs20(
|
|
5632
5798
|
"div",
|
|
5633
5799
|
{
|
|
5634
5800
|
ref: trackRef,
|
|
@@ -5644,7 +5810,7 @@ function OffsetScrubber({
|
|
|
5644
5810
|
"aria-valuenow": draftOffset,
|
|
5645
5811
|
"aria-disabled": isDisabled,
|
|
5646
5812
|
children: [
|
|
5647
|
-
/* @__PURE__ */
|
|
5813
|
+
/* @__PURE__ */ jsx26(
|
|
5648
5814
|
"div",
|
|
5649
5815
|
{
|
|
5650
5816
|
"aria-hidden": "true",
|
|
@@ -5652,7 +5818,7 @@ function OffsetScrubber({
|
|
|
5652
5818
|
style: { left: "50%" }
|
|
5653
5819
|
}
|
|
5654
5820
|
),
|
|
5655
|
-
ticks.map((t) => /* @__PURE__ */
|
|
5821
|
+
ticks.map((t) => /* @__PURE__ */ jsx26(
|
|
5656
5822
|
"div",
|
|
5657
5823
|
{
|
|
5658
5824
|
"data-testid": t.isDownbeat ? "offset-tick-downbeat" : "offset-tick",
|
|
@@ -5667,7 +5833,7 @@ function OffsetScrubber({
|
|
|
5667
5833
|
},
|
|
5668
5834
|
t.i
|
|
5669
5835
|
)),
|
|
5670
|
-
/* @__PURE__ */
|
|
5836
|
+
/* @__PURE__ */ jsx26(
|
|
5671
5837
|
"div",
|
|
5672
5838
|
{
|
|
5673
5839
|
"data-testid": "offset-scrubber-thumb",
|
|
@@ -5684,7 +5850,7 @@ function OffsetScrubber({
|
|
|
5684
5850
|
]
|
|
5685
5851
|
}
|
|
5686
5852
|
),
|
|
5687
|
-
/* @__PURE__ */
|
|
5853
|
+
/* @__PURE__ */ jsx26(
|
|
5688
5854
|
"span",
|
|
5689
5855
|
{
|
|
5690
5856
|
"data-testid": "offset-scrubber-readout",
|
|
@@ -5692,7 +5858,7 @@ function OffsetScrubber({
|
|
|
5692
5858
|
children: formatOffset(draftOffset, sampleRate)
|
|
5693
5859
|
}
|
|
5694
5860
|
),
|
|
5695
|
-
/* @__PURE__ */
|
|
5861
|
+
/* @__PURE__ */ jsx26(
|
|
5696
5862
|
"button",
|
|
5697
5863
|
{
|
|
5698
5864
|
type: "button",
|
|
@@ -5704,7 +5870,7 @@ function OffsetScrubber({
|
|
|
5704
5870
|
children: "\u2316"
|
|
5705
5871
|
}
|
|
5706
5872
|
),
|
|
5707
|
-
bpmMismatch && /* @__PURE__ */
|
|
5873
|
+
bpmMismatch && /* @__PURE__ */ jsx26(
|
|
5708
5874
|
"span",
|
|
5709
5875
|
{
|
|
5710
5876
|
"data-testid": "offset-bpm-mismatch",
|
|
@@ -5776,16 +5942,16 @@ function synthesizeCuePoints({
|
|
|
5776
5942
|
}
|
|
5777
5943
|
|
|
5778
5944
|
// src/panel-core/useGeneratorPanelCore.tsx
|
|
5779
|
-
import { useState as
|
|
5945
|
+
import { useState as useState24, useEffect as useEffect19, useCallback as useCallback17, useRef as useRef19, useMemo as useMemo10 } from "react";
|
|
5780
5946
|
|
|
5781
5947
|
// src/hooks/useSceneState.ts
|
|
5782
|
-
import { useState as
|
|
5948
|
+
import { useState as useState20, useCallback as useCallback14, useRef as useRef16 } from "react";
|
|
5783
5949
|
function useSceneState(activeSceneId, initialValue) {
|
|
5784
|
-
const [stateMap, setStateMap] =
|
|
5950
|
+
const [stateMap, setStateMap] = useState20(() => /* @__PURE__ */ new Map());
|
|
5785
5951
|
const activeSceneIdRef = useRef16(activeSceneId);
|
|
5786
5952
|
activeSceneIdRef.current = activeSceneId;
|
|
5787
5953
|
const currentValue = activeSceneId !== null && stateMap.has(activeSceneId) ? stateMap.get(activeSceneId) : initialValue;
|
|
5788
|
-
const setForCurrentScene =
|
|
5954
|
+
const setForCurrentScene = useCallback14((value) => {
|
|
5789
5955
|
const sid = activeSceneIdRef.current;
|
|
5790
5956
|
if (sid === null) return;
|
|
5791
5957
|
setStateMap((prev) => {
|
|
@@ -5796,7 +5962,7 @@ function useSceneState(activeSceneId, initialValue) {
|
|
|
5796
5962
|
return newMap;
|
|
5797
5963
|
});
|
|
5798
5964
|
}, [initialValue]);
|
|
5799
|
-
const setForScene =
|
|
5965
|
+
const setForScene = useCallback14((sceneId, value) => {
|
|
5800
5966
|
setStateMap((prev) => {
|
|
5801
5967
|
const current = prev.has(sceneId) ? prev.get(sceneId) : initialValue;
|
|
5802
5968
|
const next = typeof value === "function" ? value(current) : value;
|
|
@@ -5809,10 +5975,10 @@ function useSceneState(activeSceneId, initialValue) {
|
|
|
5809
5975
|
}
|
|
5810
5976
|
|
|
5811
5977
|
// src/hooks/useAnySolo.ts
|
|
5812
|
-
import { useEffect as
|
|
5978
|
+
import { useEffect as useEffect17, useState as useState21 } from "react";
|
|
5813
5979
|
function useAnySolo(host) {
|
|
5814
|
-
const [anySolo, setAnySolo] =
|
|
5815
|
-
|
|
5980
|
+
const [anySolo, setAnySolo] = useState21(false);
|
|
5981
|
+
useEffect17(() => {
|
|
5816
5982
|
let active = true;
|
|
5817
5983
|
const refresh = () => {
|
|
5818
5984
|
host.isAnySoloActive().then((v) => {
|
|
@@ -5831,7 +5997,7 @@ function useAnySolo(host) {
|
|
|
5831
5997
|
}
|
|
5832
5998
|
|
|
5833
5999
|
// src/hooks/useSoundHistory.ts
|
|
5834
|
-
import { useCallback as
|
|
6000
|
+
import { useCallback as useCallback15, useMemo as useMemo9, useRef as useRef17, useState as useState22 } from "react";
|
|
5835
6001
|
var EMPTY = { entries: [], cursor: -1 };
|
|
5836
6002
|
function sameDescriptor(a, b) {
|
|
5837
6003
|
if (a === b) return true;
|
|
@@ -5848,9 +6014,9 @@ function useSoundHistory(applySound, opts = {}) {
|
|
|
5848
6014
|
const onChangeRef = useRef17(opts.onChange);
|
|
5849
6015
|
onChangeRef.current = opts.onChange;
|
|
5850
6016
|
const dataRef = useRef17({});
|
|
5851
|
-
const [, setVersion] =
|
|
5852
|
-
const bump =
|
|
5853
|
-
const commit =
|
|
6017
|
+
const [, setVersion] = useState22(0);
|
|
6018
|
+
const bump = useCallback15(() => setVersion((v) => v + 1), []);
|
|
6019
|
+
const commit = useCallback15(
|
|
5854
6020
|
(trackId, next, notify) => {
|
|
5855
6021
|
dataRef.current = { ...dataRef.current, [trackId]: next };
|
|
5856
6022
|
bump();
|
|
@@ -5858,7 +6024,7 @@ function useSoundHistory(applySound, opts = {}) {
|
|
|
5858
6024
|
},
|
|
5859
6025
|
[bump]
|
|
5860
6026
|
);
|
|
5861
|
-
const record =
|
|
6027
|
+
const record = useCallback15(
|
|
5862
6028
|
(trackId, descriptor, label) => {
|
|
5863
6029
|
const h = dataRef.current[trackId];
|
|
5864
6030
|
const current = h && h.cursor >= 0 ? h.entries[h.cursor] : void 0;
|
|
@@ -5873,7 +6039,7 @@ function useSoundHistory(applySound, opts = {}) {
|
|
|
5873
6039
|
},
|
|
5874
6040
|
[max, commit]
|
|
5875
6041
|
);
|
|
5876
|
-
const restoreTo =
|
|
6042
|
+
const restoreTo = useCallback15(
|
|
5877
6043
|
async (trackId, index) => {
|
|
5878
6044
|
const h = dataRef.current[trackId];
|
|
5879
6045
|
if (!h || index < 0 || index >= h.entries.length || index === h.cursor) return false;
|
|
@@ -5883,7 +6049,7 @@ function useSoundHistory(applySound, opts = {}) {
|
|
|
5883
6049
|
},
|
|
5884
6050
|
[commit]
|
|
5885
6051
|
);
|
|
5886
|
-
const undo =
|
|
6052
|
+
const undo = useCallback15(
|
|
5887
6053
|
(trackId) => {
|
|
5888
6054
|
const h = dataRef.current[trackId];
|
|
5889
6055
|
if (!h || h.cursor <= 0) return Promise.resolve(false);
|
|
@@ -5891,7 +6057,7 @@ function useSoundHistory(applySound, opts = {}) {
|
|
|
5891
6057
|
},
|
|
5892
6058
|
[restoreTo]
|
|
5893
6059
|
);
|
|
5894
|
-
const toggleFavorite =
|
|
6060
|
+
const toggleFavorite = useCallback15(
|
|
5895
6061
|
(trackId, index) => {
|
|
5896
6062
|
const h = dataRef.current[trackId];
|
|
5897
6063
|
if (!h || index < 0 || index >= h.entries.length) return;
|
|
@@ -5900,7 +6066,7 @@ function useSoundHistory(applySound, opts = {}) {
|
|
|
5900
6066
|
},
|
|
5901
6067
|
[commit]
|
|
5902
6068
|
);
|
|
5903
|
-
const restore =
|
|
6069
|
+
const restore = useCallback15(
|
|
5904
6070
|
(trackId, state) => {
|
|
5905
6071
|
const entries = Array.isArray(state?.entries) ? [...state.entries] : [];
|
|
5906
6072
|
const raw = typeof state?.cursor === "number" ? state.cursor : entries.length - 1;
|
|
@@ -5909,15 +6075,15 @@ function useSoundHistory(applySound, opts = {}) {
|
|
|
5909
6075
|
},
|
|
5910
6076
|
[commit]
|
|
5911
6077
|
);
|
|
5912
|
-
const list =
|
|
6078
|
+
const list = useCallback15(
|
|
5913
6079
|
(trackId) => dataRef.current[trackId] ?? EMPTY,
|
|
5914
6080
|
[]
|
|
5915
6081
|
);
|
|
5916
|
-
const canUndo =
|
|
6082
|
+
const canUndo = useCallback15((trackId) => {
|
|
5917
6083
|
const h = dataRef.current[trackId];
|
|
5918
6084
|
return !!h && h.cursor > 0;
|
|
5919
6085
|
}, []);
|
|
5920
|
-
const clear =
|
|
6086
|
+
const clear = useCallback15(
|
|
5921
6087
|
(trackId) => {
|
|
5922
6088
|
if (dataRef.current[trackId]) {
|
|
5923
6089
|
const next = { ...dataRef.current };
|
|
@@ -5929,7 +6095,7 @@ function useSoundHistory(applySound, opts = {}) {
|
|
|
5929
6095
|
},
|
|
5930
6096
|
[bump]
|
|
5931
6097
|
);
|
|
5932
|
-
const reset =
|
|
6098
|
+
const reset = useCallback15(() => {
|
|
5933
6099
|
dataRef.current = {};
|
|
5934
6100
|
bump();
|
|
5935
6101
|
}, [bump]);
|
|
@@ -6009,7 +6175,7 @@ function resolveTrackGroups(parsedGroups, tracks, getDbId, opts = {}) {
|
|
|
6009
6175
|
}
|
|
6010
6176
|
|
|
6011
6177
|
// src/panel-core/useTransitionOps.ts
|
|
6012
|
-
import { useCallback as
|
|
6178
|
+
import { useCallback as useCallback16, useEffect as useEffect18, useRef as useRef18, useState as useState23 } from "react";
|
|
6013
6179
|
function useTransitionOps({
|
|
6014
6180
|
host,
|
|
6015
6181
|
adapter,
|
|
@@ -6027,7 +6193,7 @@ function useTransitionOps({
|
|
|
6027
6193
|
}) {
|
|
6028
6194
|
const { identity } = adapter;
|
|
6029
6195
|
const appliedFadeAutomationRef = useRef18(/* @__PURE__ */ new Set());
|
|
6030
|
-
const applyCrossfadeAutomation =
|
|
6196
|
+
const applyCrossfadeAutomation = useCallback16(
|
|
6031
6197
|
async (originTrackId, targetTrackId, bars, bpm, sliderPos) => {
|
|
6032
6198
|
if (host.setTrackVolumeAutomation) {
|
|
6033
6199
|
const curves = buildCrossfadeVolumeCurves(bars, bpm, sliderPos);
|
|
@@ -6044,7 +6210,7 @@ function useTransitionOps({
|
|
|
6044
6210
|
},
|
|
6045
6211
|
[host]
|
|
6046
6212
|
);
|
|
6047
|
-
const applyFadeAutomation =
|
|
6213
|
+
const applyFadeAutomation = useCallback16(
|
|
6048
6214
|
async (trackId, direction, bars, bpm, sliderPos, gesture) => {
|
|
6049
6215
|
if (!host.setTrackVolumeAutomation) return;
|
|
6050
6216
|
const points = buildFadeVolumeCurve(bars, bpm, direction, sliderPos, gesture);
|
|
@@ -6053,7 +6219,7 @@ function useTransitionOps({
|
|
|
6053
6219
|
},
|
|
6054
6220
|
[host]
|
|
6055
6221
|
);
|
|
6056
|
-
const copyTrackFx =
|
|
6222
|
+
const copyTrackFx = useCallback16(
|
|
6057
6223
|
async (newTrackId, sourceDbId) => {
|
|
6058
6224
|
if (typeof host.copyTrackFxFrom !== "function") return;
|
|
6059
6225
|
try {
|
|
@@ -6070,8 +6236,8 @@ function useTransitionOps({
|
|
|
6070
6236
|
},
|
|
6071
6237
|
[host]
|
|
6072
6238
|
);
|
|
6073
|
-
const [isCreatingCrossfade, setIsCreatingCrossfade] =
|
|
6074
|
-
const handleCreateCrossfade =
|
|
6239
|
+
const [isCreatingCrossfade, setIsCreatingCrossfade] = useState23(false);
|
|
6240
|
+
const handleCreateCrossfade = useCallback16(
|
|
6075
6241
|
async (origin, target) => {
|
|
6076
6242
|
const scene = activeSceneId;
|
|
6077
6243
|
const fromSceneId = sceneContext?.transitionFromSceneId ?? "";
|
|
@@ -6201,9 +6367,9 @@ function useTransitionOps({
|
|
|
6201
6367
|
loadTracks
|
|
6202
6368
|
]
|
|
6203
6369
|
);
|
|
6204
|
-
const [isCreatingGroupFade, setIsCreatingGroupFade] =
|
|
6205
|
-
const [isCreatingFade, setIsCreatingFade] =
|
|
6206
|
-
const handleCreateFade =
|
|
6370
|
+
const [isCreatingGroupFade, setIsCreatingGroupFade] = useState23(false);
|
|
6371
|
+
const [isCreatingFade, setIsCreatingFade] = useState23(false);
|
|
6372
|
+
const handleCreateFade = useCallback16(
|
|
6207
6373
|
async (selection, direction, gesture) => {
|
|
6208
6374
|
const scene = activeSceneId;
|
|
6209
6375
|
const fromSceneId = sceneContext?.transitionFromSceneId ?? "";
|
|
@@ -6314,7 +6480,7 @@ function useTransitionOps({
|
|
|
6314
6480
|
loadTracks
|
|
6315
6481
|
]
|
|
6316
6482
|
);
|
|
6317
|
-
const handleCrossfadeMute =
|
|
6483
|
+
const handleCrossfadeMute = useCallback16(
|
|
6318
6484
|
(pair) => {
|
|
6319
6485
|
const newMuted = !pair.origin.runtimeState.muted;
|
|
6320
6486
|
for (const id of [pair.origin.handle.id, pair.target.handle.id]) {
|
|
@@ -6329,7 +6495,7 @@ function useTransitionOps({
|
|
|
6329
6495
|
},
|
|
6330
6496
|
[host, setTracks]
|
|
6331
6497
|
);
|
|
6332
|
-
const handleCrossfadeSolo =
|
|
6498
|
+
const handleCrossfadeSolo = useCallback16(
|
|
6333
6499
|
(pair) => {
|
|
6334
6500
|
const newSolo = !pair.origin.runtimeState.solo;
|
|
6335
6501
|
for (const id of [pair.origin.handle.id, pair.target.handle.id]) {
|
|
@@ -6344,7 +6510,7 @@ function useTransitionOps({
|
|
|
6344
6510
|
},
|
|
6345
6511
|
[host, setTracks]
|
|
6346
6512
|
);
|
|
6347
|
-
const handleCrossfadeDelete =
|
|
6513
|
+
const handleCrossfadeDelete = useCallback16(
|
|
6348
6514
|
async (pair) => {
|
|
6349
6515
|
try {
|
|
6350
6516
|
for (const member of [pair.origin, pair.target]) {
|
|
@@ -6371,7 +6537,7 @@ function useTransitionOps({
|
|
|
6371
6537
|
[host, activeSceneId, setCrossfadePairsMeta, setTracks]
|
|
6372
6538
|
);
|
|
6373
6539
|
const crossfadeSliderTimers = useRef18({});
|
|
6374
|
-
const handleCrossfadeSlider =
|
|
6540
|
+
const handleCrossfadeSlider = useCallback16(
|
|
6375
6541
|
(pair, pos) => {
|
|
6376
6542
|
setCrossfadePairsMeta(
|
|
6377
6543
|
(prev) => prev.map((p) => p.groupId === pair.groupId ? { ...p, sliderPos: pos } : p)
|
|
@@ -6404,7 +6570,7 @@ function useTransitionOps({
|
|
|
6404
6570
|
},
|
|
6405
6571
|
[host, activeSceneId, applyCrossfadeAutomation, setCrossfadePairsMeta]
|
|
6406
6572
|
);
|
|
6407
|
-
const handleFadeDelete =
|
|
6573
|
+
const handleFadeDelete = useCallback16(
|
|
6408
6574
|
async (fade) => {
|
|
6409
6575
|
try {
|
|
6410
6576
|
await host.deleteTrack(fade.track.handle.id);
|
|
@@ -6425,7 +6591,7 @@ function useTransitionOps({
|
|
|
6425
6591
|
[host, activeSceneId, setFadesMeta, setTracks]
|
|
6426
6592
|
);
|
|
6427
6593
|
const fadeSliderTimers = useRef18({});
|
|
6428
|
-
const handleFadeSlider =
|
|
6594
|
+
const handleFadeSlider = useCallback16(
|
|
6429
6595
|
(fade, pos) => {
|
|
6430
6596
|
setFadesMeta(
|
|
6431
6597
|
(prev) => prev.map((f) => f.dbId === fade.dbId ? { ...f, meta: { ...f.meta, sliderPos: pos } } : f)
|
|
@@ -6455,7 +6621,7 @@ function useTransitionOps({
|
|
|
6455
6621
|
},
|
|
6456
6622
|
[host, activeSceneId, applyFadeAutomation, setFadesMeta]
|
|
6457
6623
|
);
|
|
6458
|
-
const handleCreateVerbatimGroupFade =
|
|
6624
|
+
const handleCreateVerbatimGroupFade = useCallback16(
|
|
6459
6625
|
async (subject, direction) => {
|
|
6460
6626
|
const groupAdapter = adapter.transitionGroup;
|
|
6461
6627
|
if (!groupAdapter) throw new Error("This panel does not support group fades.");
|
|
@@ -6571,7 +6737,7 @@ function useTransitionOps({
|
|
|
6571
6737
|
]
|
|
6572
6738
|
);
|
|
6573
6739
|
const groupFadeSliderTimers = useRef18({});
|
|
6574
|
-
const handleGroupFadeSlider =
|
|
6740
|
+
const handleGroupFadeSlider = useCallback16(
|
|
6575
6741
|
(group, pos) => {
|
|
6576
6742
|
setFadesMeta(
|
|
6577
6743
|
(prev) => prev.map(
|
|
@@ -6610,7 +6776,7 @@ function useTransitionOps({
|
|
|
6610
6776
|
},
|
|
6611
6777
|
[host, activeSceneId, applyFadeAutomation, setFadesMeta]
|
|
6612
6778
|
);
|
|
6613
|
-
const handleGroupFadeDelete =
|
|
6779
|
+
const handleGroupFadeDelete = useCallback16(
|
|
6614
6780
|
async (group) => {
|
|
6615
6781
|
const suffixes = ["fade", ...adapter.transitionGroup?.cleanupKeySuffixes ?? []];
|
|
6616
6782
|
try {
|
|
@@ -6638,7 +6804,7 @@ function useTransitionOps({
|
|
|
6638
6804
|
[host, adapter, activeSceneId, setFadesMeta, setTracks]
|
|
6639
6805
|
);
|
|
6640
6806
|
const lastResyncKeyRef = useRef18("");
|
|
6641
|
-
|
|
6807
|
+
useEffect18(() => {
|
|
6642
6808
|
if (!host.getTrackSound || resolvedCrossfadePairs.length === 0 && resolvedFades.length === 0) {
|
|
6643
6809
|
return;
|
|
6644
6810
|
}
|
|
@@ -6679,7 +6845,7 @@ function useTransitionOps({
|
|
|
6679
6845
|
cancelled = true;
|
|
6680
6846
|
};
|
|
6681
6847
|
}, [resolvedCrossfadePairs, resolvedFades, host, adapter]);
|
|
6682
|
-
|
|
6848
|
+
useEffect18(() => {
|
|
6683
6849
|
if (!host.setTrackVolumeAutomation || resolvedFades.length === 0) return;
|
|
6684
6850
|
void (async () => {
|
|
6685
6851
|
const mc = await host.getMusicalContext();
|
|
@@ -6717,7 +6883,7 @@ function useTransitionOps({
|
|
|
6717
6883
|
}
|
|
6718
6884
|
|
|
6719
6885
|
// src/panel-core/useGeneratorPanelCore.tsx
|
|
6720
|
-
import { jsx as
|
|
6886
|
+
import { jsx as jsx27, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
6721
6887
|
var EMPTY_PLACEHOLDERS = [];
|
|
6722
6888
|
function useGeneratorPanelCore({
|
|
6723
6889
|
ui,
|
|
@@ -6738,7 +6904,7 @@ function useGeneratorPanelCore({
|
|
|
6738
6904
|
const { identity, features } = adapter;
|
|
6739
6905
|
const logTag = identity.logTag;
|
|
6740
6906
|
const adapterRef = useRef19(adapter);
|
|
6741
|
-
|
|
6907
|
+
useEffect19(() => {
|
|
6742
6908
|
if (adapterRef.current !== adapter) {
|
|
6743
6909
|
adapterRef.current = adapter;
|
|
6744
6910
|
console.warn(
|
|
@@ -6748,15 +6914,15 @@ function useGeneratorPanelCore({
|
|
|
6748
6914
|
}, [adapter, logTag]);
|
|
6749
6915
|
const supportsMeters = typeof host.getTrackLevels === "function";
|
|
6750
6916
|
const trackLevels = useTrackLevels(host, isExpanded);
|
|
6751
|
-
const [tracks, setTracks] =
|
|
6752
|
-
const [isLoadingTracks, setIsLoadingTracks] =
|
|
6753
|
-
const [importOpen, setImportOpen] =
|
|
6754
|
-
const [soundImportTarget, setSoundImportTarget] =
|
|
6755
|
-
const [designerView, setDesignerView] =
|
|
6756
|
-
const [transitionSourceTotal, setTransitionSourceTotal] =
|
|
6757
|
-
const [crossfadePairsMeta, setCrossfadePairsMeta] =
|
|
6758
|
-
const [fadesMeta, setFadesMeta] =
|
|
6759
|
-
const [genericGroupMetas, setGenericGroupMetas] =
|
|
6917
|
+
const [tracks, setTracks] = useState24([]);
|
|
6918
|
+
const [isLoadingTracks, setIsLoadingTracks] = useState24(false);
|
|
6919
|
+
const [importOpen, setImportOpen] = useState24(false);
|
|
6920
|
+
const [soundImportTarget, setSoundImportTarget] = useState24(null);
|
|
6921
|
+
const [designerView, setDesignerView] = useState24(false);
|
|
6922
|
+
const [transitionSourceTotal, setTransitionSourceTotal] = useState24(0);
|
|
6923
|
+
const [crossfadePairsMeta, setCrossfadePairsMeta] = useState24([]);
|
|
6924
|
+
const [fadesMeta, setFadesMeta] = useState24([]);
|
|
6925
|
+
const [genericGroupMetas, setGenericGroupMetas] = useState24({});
|
|
6760
6926
|
const [isComposing, , setIsComposingForScene] = useSceneState(activeSceneId, false);
|
|
6761
6927
|
const [placeholders, , setPlaceholdersForScene] = useSceneState(
|
|
6762
6928
|
activeSceneId,
|
|
@@ -6764,11 +6930,11 @@ function useGeneratorPanelCore({
|
|
|
6764
6930
|
);
|
|
6765
6931
|
const saveTimeoutRefs = useRef19({});
|
|
6766
6932
|
const editLoadStartedRef = useRef19(/* @__PURE__ */ new Set());
|
|
6767
|
-
const [availableInstruments, setAvailableInstruments] =
|
|
6768
|
-
const [instrumentsLoading, setInstrumentsLoading] =
|
|
6933
|
+
const [availableInstruments, setAvailableInstruments] = useState24([]);
|
|
6934
|
+
const [instrumentsLoading, setInstrumentsLoading] = useState24(false);
|
|
6769
6935
|
const engineToDbIdRef = useRef19(/* @__PURE__ */ new Map());
|
|
6770
6936
|
const tracksLoadedForSceneRef = useRef19(null);
|
|
6771
|
-
const persistSoundHistory =
|
|
6937
|
+
const persistSoundHistory = useCallback17(
|
|
6772
6938
|
(trackId, state) => {
|
|
6773
6939
|
if (!activeSceneId) return;
|
|
6774
6940
|
const dbId = engineToDbIdRef.current.get(trackId) ?? trackId;
|
|
@@ -6788,7 +6954,7 @@ function useGeneratorPanelCore({
|
|
|
6788
6954
|
setItems: setTracks,
|
|
6789
6955
|
getId: (t) => t.handle.dbId
|
|
6790
6956
|
});
|
|
6791
|
-
const loadTracks =
|
|
6957
|
+
const loadTracks = useCallback17(
|
|
6792
6958
|
async (incremental = false) => {
|
|
6793
6959
|
const sceneAtStart = activeSceneId;
|
|
6794
6960
|
if (!sceneAtStart) {
|
|
@@ -6913,10 +7079,10 @@ function useGeneratorPanelCore({
|
|
|
6913
7079
|
},
|
|
6914
7080
|
[host, activeSceneId, soundHistory, adapter, logTag]
|
|
6915
7081
|
);
|
|
6916
|
-
|
|
7082
|
+
useEffect19(() => {
|
|
6917
7083
|
loadTracks();
|
|
6918
7084
|
}, [loadTracks]);
|
|
6919
|
-
|
|
7085
|
+
useEffect19(() => {
|
|
6920
7086
|
const map = /* @__PURE__ */ new Map();
|
|
6921
7087
|
for (const t of tracks) {
|
|
6922
7088
|
map.set(t.handle.id, t.handle.dbId);
|
|
@@ -6924,7 +7090,7 @@ function useGeneratorPanelCore({
|
|
|
6924
7090
|
engineToDbIdRef.current = map;
|
|
6925
7091
|
}, [tracks]);
|
|
6926
7092
|
const loadedCompletedIdsRef = useRef19(/* @__PURE__ */ new Set());
|
|
6927
|
-
|
|
7093
|
+
useEffect19(() => {
|
|
6928
7094
|
if (placeholders.length === 0) {
|
|
6929
7095
|
loadedCompletedIdsRef.current.clear();
|
|
6930
7096
|
return;
|
|
@@ -6943,16 +7109,16 @@ function useGeneratorPanelCore({
|
|
|
6943
7109
|
loadTracks(true);
|
|
6944
7110
|
}
|
|
6945
7111
|
}, [placeholders, loadTracks, logTag]);
|
|
6946
|
-
const adoptAndLoad =
|
|
7112
|
+
const adoptAndLoad = useCallback17(() => {
|
|
6947
7113
|
loadTracks(true);
|
|
6948
7114
|
}, [loadTracks]);
|
|
6949
|
-
|
|
7115
|
+
useEffect19(() => {
|
|
6950
7116
|
const unsub = host.onEngineReady(() => {
|
|
6951
7117
|
adoptAndLoad();
|
|
6952
7118
|
});
|
|
6953
7119
|
return unsub;
|
|
6954
7120
|
}, [host, adoptAndLoad]);
|
|
6955
|
-
|
|
7121
|
+
useEffect19(() => {
|
|
6956
7122
|
if (typeof host.onAfterAgentMutation !== "function") return;
|
|
6957
7123
|
let timer = null;
|
|
6958
7124
|
const unsub = host.onAfterAgentMutation(() => {
|
|
@@ -6967,13 +7133,13 @@ function useGeneratorPanelCore({
|
|
|
6967
7133
|
if (timer) clearTimeout(timer);
|
|
6968
7134
|
};
|
|
6969
7135
|
}, [host, loadTracks]);
|
|
6970
|
-
|
|
7136
|
+
useEffect19(() => {
|
|
6971
7137
|
const unsub = host.onTrackStateChange((trackId, state) => {
|
|
6972
7138
|
setTracks((prev) => prev.map((t) => t.handle.id === trackId ? { ...t, runtimeState: state } : t));
|
|
6973
7139
|
});
|
|
6974
7140
|
return unsub;
|
|
6975
7141
|
}, [host]);
|
|
6976
|
-
|
|
7142
|
+
useEffect19(() => {
|
|
6977
7143
|
if (!features.bulkComposePlaceholders) return;
|
|
6978
7144
|
console.log(`[${logTag}] Subscribing to composeProgress`);
|
|
6979
7145
|
const unsub = host.onComposeProgress((event) => {
|
|
@@ -7007,7 +7173,7 @@ function useGeneratorPanelCore({
|
|
|
7007
7173
|
});
|
|
7008
7174
|
return unsub;
|
|
7009
7175
|
}, [host, setIsComposingForScene, setPlaceholdersForScene, features.bulkComposePlaceholders, logTag]);
|
|
7010
|
-
|
|
7176
|
+
useEffect19(() => {
|
|
7011
7177
|
const refs = saveTimeoutRefs;
|
|
7012
7178
|
return () => {
|
|
7013
7179
|
for (const timeout of Object.values(refs.current)) {
|
|
@@ -7016,8 +7182,8 @@ function useGeneratorPanelCore({
|
|
|
7016
7182
|
};
|
|
7017
7183
|
}, []);
|
|
7018
7184
|
const isAddingTrackRef = useRef19(false);
|
|
7019
|
-
const [isAddingTrack, setIsAddingTrack] =
|
|
7020
|
-
const handleAddTrack =
|
|
7185
|
+
const [isAddingTrack, setIsAddingTrack] = useState24(false);
|
|
7186
|
+
const handleAddTrack = useCallback17(async () => {
|
|
7021
7187
|
if (isAddingTrackRef.current) return;
|
|
7022
7188
|
if (!activeSceneId) {
|
|
7023
7189
|
host.showToast("warning", "Select SCENE");
|
|
@@ -7065,7 +7231,7 @@ function useGeneratorPanelCore({
|
|
|
7065
7231
|
setIsAddingTrack(false);
|
|
7066
7232
|
}
|
|
7067
7233
|
}, [host, adapter, identity, activeSceneId, isConnected, isAuthenticated, tracks.length, onExpandSelf, loadTracks, logTag]);
|
|
7068
|
-
const handlePortTrack =
|
|
7234
|
+
const handlePortTrack = useCallback17(
|
|
7069
7235
|
async (sel) => {
|
|
7070
7236
|
if (!activeSceneId) {
|
|
7071
7237
|
host.showToast("warning", "Select SCENE");
|
|
@@ -7128,7 +7294,7 @@ function useGeneratorPanelCore({
|
|
|
7128
7294
|
},
|
|
7129
7295
|
[host, adapter, identity, activeSceneId, isConnected, tracks.length, loadTracks]
|
|
7130
7296
|
);
|
|
7131
|
-
const handleSoundImportPick =
|
|
7297
|
+
const handleSoundImportPick = useCallback17(
|
|
7132
7298
|
async (sel) => {
|
|
7133
7299
|
const target = soundImportTarget;
|
|
7134
7300
|
if (!target || !host.getTrackSound) {
|
|
@@ -7159,8 +7325,8 @@ function useGeneratorPanelCore({
|
|
|
7159
7325
|
},
|
|
7160
7326
|
[soundImportTarget, host, adapter, identity.familyKey, soundHistory]
|
|
7161
7327
|
);
|
|
7162
|
-
const [isExportingMidi, setIsExportingMidi] =
|
|
7163
|
-
const handleExportMidi =
|
|
7328
|
+
const [isExportingMidi, setIsExportingMidi] = useState24(false);
|
|
7329
|
+
const handleExportMidi = useCallback17(async () => {
|
|
7164
7330
|
if (isExportingMidi) return;
|
|
7165
7331
|
setIsExportingMidi(true);
|
|
7166
7332
|
try {
|
|
@@ -7191,10 +7357,10 @@ function useGeneratorPanelCore({
|
|
|
7191
7357
|
const xfFromId = sceneContext?.transitionFromSceneId ?? null;
|
|
7192
7358
|
const xfToId = sceneContext?.transitionToSceneId ?? null;
|
|
7193
7359
|
const canCrossfade = features.transitionDesigner && sceneContext?.sceneType === "transition" && !!xfFromId && !!xfToId && !!host.listSceneFamilyTracks;
|
|
7194
|
-
|
|
7360
|
+
useEffect19(() => {
|
|
7195
7361
|
if (!canCrossfade) setDesignerView(false);
|
|
7196
7362
|
}, [canCrossfade]);
|
|
7197
|
-
|
|
7363
|
+
useEffect19(() => {
|
|
7198
7364
|
if (!canCrossfade || !xfFromId || !xfToId || !host.listSceneFamilyTracks) {
|
|
7199
7365
|
setTransitionSourceTotal(0);
|
|
7200
7366
|
return;
|
|
@@ -7210,12 +7376,12 @@ function useGeneratorPanelCore({
|
|
|
7210
7376
|
};
|
|
7211
7377
|
}, [canCrossfade, xfFromId, xfToId, host]);
|
|
7212
7378
|
const transitionDone = crossfadePairsMeta.length * 2 + fadesMeta.length;
|
|
7213
|
-
|
|
7379
|
+
useEffect19(() => {
|
|
7214
7380
|
if (!onHeaderContent) return;
|
|
7215
7381
|
const addDisabled = needsContract || !isConnected || !activeSceneId || tracks.length >= identity.maxTracks || isAddingTrack;
|
|
7216
7382
|
onHeaderContent(
|
|
7217
|
-
/* @__PURE__ */
|
|
7218
|
-
features.importTracks && (!canCrossfade || !designerView) && host.listImportableTracks && /* @__PURE__ */
|
|
7383
|
+
/* @__PURE__ */ jsxs21("div", { className: "flex gap-1 items-center", children: [
|
|
7384
|
+
features.importTracks && (!canCrossfade || !designerView) && host.listImportableTracks && /* @__PURE__ */ jsx27(
|
|
7219
7385
|
"button",
|
|
7220
7386
|
{
|
|
7221
7387
|
"data-testid": `import-from-scene-${identity.familyKey}-button`,
|
|
@@ -7229,7 +7395,7 @@ function useGeneratorPanelCore({
|
|
|
7229
7395
|
children: identity.importTrackLabel ?? "Import Track"
|
|
7230
7396
|
}
|
|
7231
7397
|
),
|
|
7232
|
-
(!canCrossfade || !designerView) && /* @__PURE__ */
|
|
7398
|
+
(!canCrossfade || !designerView) && /* @__PURE__ */ jsx27(
|
|
7233
7399
|
"button",
|
|
7234
7400
|
{
|
|
7235
7401
|
"data-testid": `add-${identity.familyKey}-track-button`,
|
|
@@ -7245,7 +7411,7 @@ function useGeneratorPanelCore({
|
|
|
7245
7411
|
children: identity.addTrackLabel ?? "Add Track"
|
|
7246
7412
|
}
|
|
7247
7413
|
),
|
|
7248
|
-
canCrossfade && /* @__PURE__ */
|
|
7414
|
+
canCrossfade && /* @__PURE__ */ jsxs21(
|
|
7249
7415
|
"button",
|
|
7250
7416
|
{
|
|
7251
7417
|
"data-testid": `${identity.familyKey}-view-toggle`,
|
|
@@ -7264,7 +7430,7 @@ function useGeneratorPanelCore({
|
|
|
7264
7430
|
title: designerView ? "Back to the track list" : "Open the transition designer",
|
|
7265
7431
|
className: "relative overflow-hidden px-2 py-0.5 text-[10px] font-medium rounded-sm border border-sas-accent/40 text-sas-accent transition-colors hover:border-sas-accent disabled:opacity-50",
|
|
7266
7432
|
children: [
|
|
7267
|
-
transitionSourceTotal > 0 && /* @__PURE__ */
|
|
7433
|
+
transitionSourceTotal > 0 && /* @__PURE__ */ jsx27(
|
|
7268
7434
|
"span",
|
|
7269
7435
|
{
|
|
7270
7436
|
className: "absolute inset-y-0 left-0 bg-sas-accent/25",
|
|
@@ -7272,7 +7438,7 @@ function useGeneratorPanelCore({
|
|
|
7272
7438
|
"aria-hidden": true
|
|
7273
7439
|
}
|
|
7274
7440
|
),
|
|
7275
|
-
/* @__PURE__ */
|
|
7441
|
+
/* @__PURE__ */ jsxs21("span", { className: "relative", children: [
|
|
7276
7442
|
"\u21C4 ",
|
|
7277
7443
|
designerView ? "Transition" : "Tracks",
|
|
7278
7444
|
transitionSourceTotal > 0 ? ` ${transitionDone}/${transitionSourceTotal}` : ""
|
|
@@ -7303,7 +7469,7 @@ function useGeneratorPanelCore({
|
|
|
7303
7469
|
identity,
|
|
7304
7470
|
features.importTracks
|
|
7305
7471
|
]);
|
|
7306
|
-
|
|
7472
|
+
useEffect19(() => {
|
|
7307
7473
|
if (!onLoading) return;
|
|
7308
7474
|
const anyGenerating = tracks.some((t) => t.isGenerating);
|
|
7309
7475
|
onLoading(isLoadingTracks || anyGenerating || isBulkActive);
|
|
@@ -7311,7 +7477,7 @@ function useGeneratorPanelCore({
|
|
|
7311
7477
|
onLoading(false);
|
|
7312
7478
|
};
|
|
7313
7479
|
}, [onLoading, isLoadingTracks, tracks, isBulkActive]);
|
|
7314
|
-
const handleDeleteTrack =
|
|
7480
|
+
const handleDeleteTrack = useCallback17(
|
|
7315
7481
|
async (trackId) => {
|
|
7316
7482
|
try {
|
|
7317
7483
|
await host.deleteTrack(trackId);
|
|
@@ -7327,7 +7493,7 @@ function useGeneratorPanelCore({
|
|
|
7327
7493
|
},
|
|
7328
7494
|
[host, activeSceneId]
|
|
7329
7495
|
);
|
|
7330
|
-
const handlePromptChange =
|
|
7496
|
+
const handlePromptChange = useCallback17(
|
|
7331
7497
|
(trackId, prompt) => {
|
|
7332
7498
|
setTracks((prev) => prev.map((t) => t.handle.id === trackId ? { ...t, prompt } : t));
|
|
7333
7499
|
const dbId = engineToDbIdRef.current.get(trackId) ?? trackId;
|
|
@@ -7364,11 +7530,11 @@ function useGeneratorPanelCore({
|
|
|
7364
7530
|
}
|
|
7365
7531
|
return s;
|
|
7366
7532
|
}, [resolvedGenericGroups]);
|
|
7367
|
-
const engineToDbId =
|
|
7533
|
+
const engineToDbId = useCallback17(
|
|
7368
7534
|
(trackId) => engineToDbIdRef.current.get(trackId) ?? trackId,
|
|
7369
7535
|
[]
|
|
7370
7536
|
);
|
|
7371
|
-
const updateTrack =
|
|
7537
|
+
const updateTrack = useCallback17(
|
|
7372
7538
|
(trackId, patch) => {
|
|
7373
7539
|
setTracks(
|
|
7374
7540
|
(prev) => prev.map(
|
|
@@ -7378,18 +7544,18 @@ function useGeneratorPanelCore({
|
|
|
7378
7544
|
},
|
|
7379
7545
|
[]
|
|
7380
7546
|
);
|
|
7381
|
-
const markEditLoaded =
|
|
7547
|
+
const markEditLoaded = useCallback17((trackId) => {
|
|
7382
7548
|
editLoadStartedRef.current.add(trackId);
|
|
7383
7549
|
}, []);
|
|
7384
7550
|
const tracksRef = useRef19(tracks);
|
|
7385
|
-
|
|
7551
|
+
useEffect19(() => {
|
|
7386
7552
|
tracksRef.current = tracks;
|
|
7387
7553
|
}, [tracks]);
|
|
7388
7554
|
const resolvedGenericGroupsRef = useRef19(resolvedGenericGroups);
|
|
7389
|
-
|
|
7555
|
+
useEffect19(() => {
|
|
7390
7556
|
resolvedGenericGroupsRef.current = resolvedGenericGroups;
|
|
7391
7557
|
}, [resolvedGenericGroups]);
|
|
7392
|
-
const makeServices =
|
|
7558
|
+
const makeServices = useCallback17(() => {
|
|
7393
7559
|
return {
|
|
7394
7560
|
host,
|
|
7395
7561
|
activeSceneId,
|
|
@@ -7408,7 +7574,7 @@ function useGeneratorPanelCore({
|
|
|
7408
7574
|
resolvedGroups: (metaKey) => resolvedGenericGroupsRef.current[metaKey]?.resolved ?? []
|
|
7409
7575
|
};
|
|
7410
7576
|
}, [host, activeSceneId, updateTrack, loadTracks, soundHistory, engineToDbId, markEditLoaded, identity, adapter]);
|
|
7411
|
-
const handleGenerate =
|
|
7577
|
+
const handleGenerate = useCallback17(
|
|
7412
7578
|
async (trackId) => {
|
|
7413
7579
|
const track = tracks.find((t) => t.handle.id === trackId);
|
|
7414
7580
|
if (!track || !track.prompt.trim()) return;
|
|
@@ -7435,7 +7601,7 @@ function useGeneratorPanelCore({
|
|
|
7435
7601
|
},
|
|
7436
7602
|
[host, adapter, tracks, isAuthenticated, makeServices]
|
|
7437
7603
|
);
|
|
7438
|
-
const handleMuteToggle =
|
|
7604
|
+
const handleMuteToggle = useCallback17(
|
|
7439
7605
|
(trackId) => {
|
|
7440
7606
|
const track = tracks.find((t) => t.handle.id === trackId);
|
|
7441
7607
|
if (!track) return;
|
|
@@ -7455,7 +7621,7 @@ function useGeneratorPanelCore({
|
|
|
7455
7621
|
},
|
|
7456
7622
|
[host, tracks]
|
|
7457
7623
|
);
|
|
7458
|
-
const handleSoloToggle =
|
|
7624
|
+
const handleSoloToggle = useCallback17(
|
|
7459
7625
|
(trackId) => {
|
|
7460
7626
|
const track = tracks.find((t) => t.handle.id === trackId);
|
|
7461
7627
|
if (!track) return;
|
|
@@ -7475,7 +7641,7 @@ function useGeneratorPanelCore({
|
|
|
7475
7641
|
},
|
|
7476
7642
|
[host, tracks]
|
|
7477
7643
|
);
|
|
7478
|
-
const handleVolumeChange =
|
|
7644
|
+
const handleVolumeChange = useCallback17(
|
|
7479
7645
|
(trackId, volume) => {
|
|
7480
7646
|
setTracks(
|
|
7481
7647
|
(prev) => prev.map((t) => t.handle.id === trackId ? { ...t, runtimeState: { ...t.runtimeState, volume } } : t)
|
|
@@ -7485,7 +7651,7 @@ function useGeneratorPanelCore({
|
|
|
7485
7651
|
},
|
|
7486
7652
|
[host]
|
|
7487
7653
|
);
|
|
7488
|
-
const handlePanChange =
|
|
7654
|
+
const handlePanChange = useCallback17(
|
|
7489
7655
|
(trackId, pan) => {
|
|
7490
7656
|
setTracks(
|
|
7491
7657
|
(prev) => prev.map((t) => t.handle.id === trackId ? { ...t, runtimeState: { ...t.runtimeState, pan } } : t)
|
|
@@ -7495,7 +7661,7 @@ function useGeneratorPanelCore({
|
|
|
7495
7661
|
},
|
|
7496
7662
|
[host]
|
|
7497
7663
|
);
|
|
7498
|
-
const handleShuffle =
|
|
7664
|
+
const handleShuffle = useCallback17(
|
|
7499
7665
|
async (trackId) => {
|
|
7500
7666
|
const track = tracks.find((t) => t.handle.id === trackId);
|
|
7501
7667
|
if (!track) return;
|
|
@@ -7537,7 +7703,7 @@ function useGeneratorPanelCore({
|
|
|
7537
7703
|
},
|
|
7538
7704
|
[host, adapter, tracks, soundHistory, logTag]
|
|
7539
7705
|
);
|
|
7540
|
-
const handleCopy =
|
|
7706
|
+
const handleCopy = useCallback17(
|
|
7541
7707
|
async (trackId) => {
|
|
7542
7708
|
try {
|
|
7543
7709
|
const newHandle = await host.duplicateTrack(trackId);
|
|
@@ -7550,7 +7716,7 @@ function useGeneratorPanelCore({
|
|
|
7550
7716
|
},
|
|
7551
7717
|
[host, loadTracks]
|
|
7552
7718
|
);
|
|
7553
|
-
const handleFxToggle =
|
|
7719
|
+
const handleFxToggle = useCallback17(
|
|
7554
7720
|
(trackId, category, enabled) => {
|
|
7555
7721
|
setTracks(
|
|
7556
7722
|
(prev) => prev.map(
|
|
@@ -7573,7 +7739,7 @@ function useGeneratorPanelCore({
|
|
|
7573
7739
|
},
|
|
7574
7740
|
[host]
|
|
7575
7741
|
);
|
|
7576
|
-
const handleFxPresetChange =
|
|
7742
|
+
const handleFxPresetChange = useCallback17(
|
|
7577
7743
|
(trackId, category, presetIndex) => {
|
|
7578
7744
|
setTracks(
|
|
7579
7745
|
(prev) => prev.map(
|
|
@@ -7599,7 +7765,7 @@ function useGeneratorPanelCore({
|
|
|
7599
7765
|
},
|
|
7600
7766
|
[host]
|
|
7601
7767
|
);
|
|
7602
|
-
const handleFxDryWetChange =
|
|
7768
|
+
const handleFxDryWetChange = useCallback17(
|
|
7603
7769
|
(trackId, category, value) => {
|
|
7604
7770
|
setTracks(
|
|
7605
7771
|
(prev) => prev.map(
|
|
@@ -7611,7 +7777,7 @@ function useGeneratorPanelCore({
|
|
|
7611
7777
|
},
|
|
7612
7778
|
[host]
|
|
7613
7779
|
);
|
|
7614
|
-
const toggleFxDrawer =
|
|
7780
|
+
const toggleFxDrawer = useCallback17(
|
|
7615
7781
|
(trackId) => {
|
|
7616
7782
|
setTracks(
|
|
7617
7783
|
(prev) => prev.map((t) => {
|
|
@@ -7633,7 +7799,7 @@ function useGeneratorPanelCore({
|
|
|
7633
7799
|
},
|
|
7634
7800
|
[host, tracks]
|
|
7635
7801
|
);
|
|
7636
|
-
const loadEditNotes =
|
|
7802
|
+
const loadEditNotes = useCallback17(
|
|
7637
7803
|
async (trackId) => {
|
|
7638
7804
|
try {
|
|
7639
7805
|
const mc = await host.getMusicalContext();
|
|
@@ -7651,7 +7817,7 @@ function useGeneratorPanelCore({
|
|
|
7651
7817
|
},
|
|
7652
7818
|
[host, logTag]
|
|
7653
7819
|
);
|
|
7654
|
-
const handleNotesChange =
|
|
7820
|
+
const handleNotesChange = useCallback17(
|
|
7655
7821
|
(trackId, notes) => {
|
|
7656
7822
|
setTracks((prev) => prev.map((t) => t.handle.id === trackId ? { ...t, editNotes: notes } : t));
|
|
7657
7823
|
const key = `edit:${trackId}`;
|
|
@@ -7681,7 +7847,7 @@ function useGeneratorPanelCore({
|
|
|
7681
7847
|
},
|
|
7682
7848
|
[host]
|
|
7683
7849
|
);
|
|
7684
|
-
const handleTabChange =
|
|
7850
|
+
const handleTabChange = useCallback17(
|
|
7685
7851
|
(trackId, tab) => {
|
|
7686
7852
|
setTracks((prev) => prev.map((t) => t.handle.id === trackId ? { ...t, drawerOpen: true, drawerTab: tab } : t));
|
|
7687
7853
|
if (tab === "fx") {
|
|
@@ -7706,10 +7872,10 @@ function useGeneratorPanelCore({
|
|
|
7706
7872
|
},
|
|
7707
7873
|
[host, availableInstruments.length, instrumentsLoading, loadEditNotes]
|
|
7708
7874
|
);
|
|
7709
|
-
const handleProgressChange =
|
|
7875
|
+
const handleProgressChange = useCallback17((trackId, pct) => {
|
|
7710
7876
|
setTracks((prev) => prev.map((t) => t.handle.id === trackId ? { ...t, generationProgress: pct } : t));
|
|
7711
7877
|
}, []);
|
|
7712
|
-
const handleToggleDrawer =
|
|
7878
|
+
const handleToggleDrawer = useCallback17((trackId) => {
|
|
7713
7879
|
setTracks(
|
|
7714
7880
|
(prev) => prev.map((t) => {
|
|
7715
7881
|
if (t.handle.id !== trackId) return t;
|
|
@@ -7718,7 +7884,7 @@ function useGeneratorPanelCore({
|
|
|
7718
7884
|
})
|
|
7719
7885
|
);
|
|
7720
7886
|
}, []);
|
|
7721
|
-
const handleInstrumentSelect =
|
|
7887
|
+
const handleInstrumentSelect = useCallback17(
|
|
7722
7888
|
async (trackId, pluginId) => {
|
|
7723
7889
|
const isDefaultInstrument = pluginId === (identity.defaultInstrumentPluginId ?? "Surge XT");
|
|
7724
7890
|
if (isDefaultInstrument) {
|
|
@@ -7771,7 +7937,7 @@ function useGeneratorPanelCore({
|
|
|
7771
7937
|
},
|
|
7772
7938
|
[host, identity.defaultInstrumentPluginId, logTag]
|
|
7773
7939
|
);
|
|
7774
|
-
const handleShowEditor =
|
|
7940
|
+
const handleShowEditor = useCallback17(
|
|
7775
7941
|
async (trackId) => {
|
|
7776
7942
|
try {
|
|
7777
7943
|
await host.showInstrumentEditor(trackId);
|
|
@@ -7782,12 +7948,12 @@ function useGeneratorPanelCore({
|
|
|
7782
7948
|
},
|
|
7783
7949
|
[host]
|
|
7784
7950
|
);
|
|
7785
|
-
const handleBackToInstruments =
|
|
7951
|
+
const handleBackToInstruments = useCallback17((trackId) => {
|
|
7786
7952
|
setTracks(
|
|
7787
7953
|
(prev) => prev.map((t) => t.handle.id === trackId ? { ...t, editorStage: false } : t)
|
|
7788
7954
|
);
|
|
7789
7955
|
}, []);
|
|
7790
|
-
const handleRefreshInstruments =
|
|
7956
|
+
const handleRefreshInstruments = useCallback17(() => {
|
|
7791
7957
|
setInstrumentsLoading(true);
|
|
7792
7958
|
host.getAvailableInstruments().then((instruments) => {
|
|
7793
7959
|
setAvailableInstruments(instruments);
|
|
@@ -7796,7 +7962,7 @@ function useGeneratorPanelCore({
|
|
|
7796
7962
|
setInstrumentsLoading(false);
|
|
7797
7963
|
});
|
|
7798
7964
|
}, [host]);
|
|
7799
|
-
const onAuditionNote =
|
|
7965
|
+
const onAuditionNote = useCallback17(
|
|
7800
7966
|
(trackId, pitch, velocity, ms) => {
|
|
7801
7967
|
void host.auditionNote(trackId, pitch, velocity, ms);
|
|
7802
7968
|
},
|
|
@@ -7849,7 +8015,7 @@ function useGeneratorPanelCore({
|
|
|
7849
8015
|
resolvedCrossfadePairs,
|
|
7850
8016
|
resolvedFades
|
|
7851
8017
|
});
|
|
7852
|
-
const setGroupMute =
|
|
8018
|
+
const setGroupMute = useCallback17(
|
|
7853
8019
|
(trackIds, muted) => {
|
|
7854
8020
|
for (const id of trackIds) {
|
|
7855
8021
|
setTracks(
|
|
@@ -7861,7 +8027,7 @@ function useGeneratorPanelCore({
|
|
|
7861
8027
|
},
|
|
7862
8028
|
[host]
|
|
7863
8029
|
);
|
|
7864
|
-
const setGroupSolo =
|
|
8030
|
+
const setGroupSolo = useCallback17(
|
|
7865
8031
|
(trackIds, solo) => {
|
|
7866
8032
|
for (const id of trackIds) {
|
|
7867
8033
|
setTracks(
|
|
@@ -7873,7 +8039,7 @@ function useGeneratorPanelCore({
|
|
|
7873
8039
|
},
|
|
7874
8040
|
[host]
|
|
7875
8041
|
);
|
|
7876
|
-
const deleteGroup =
|
|
8042
|
+
const deleteGroup = useCallback17(
|
|
7877
8043
|
async (members, cleanupKeySuffixes) => {
|
|
7878
8044
|
for (const member of members) {
|
|
7879
8045
|
try {
|
|
@@ -8009,8 +8175,8 @@ function useGeneratorPanelCore({
|
|
|
8009
8175
|
}
|
|
8010
8176
|
|
|
8011
8177
|
// src/panel-core/GeneratorPanelShell.tsx
|
|
8012
|
-
import React23, { useCallback as
|
|
8013
|
-
import { Fragment as Fragment7, jsx as
|
|
8178
|
+
import React23, { useCallback as useCallback18 } from "react";
|
|
8179
|
+
import { Fragment as Fragment7, jsx as jsx28, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
8014
8180
|
function GeneratorPanelShell({ core, slots }) {
|
|
8015
8181
|
const {
|
|
8016
8182
|
ui,
|
|
@@ -8066,7 +8232,7 @@ function GeneratorPanelShell({ core, slots }) {
|
|
|
8066
8232
|
const { host, activeSceneId, isAuthenticated, sceneContext, onSelectScene, onOpenContract } = ui;
|
|
8067
8233
|
const panelBus = usePanelBus(host, activeSceneId);
|
|
8068
8234
|
const { identity, features } = adapter;
|
|
8069
|
-
const buildRowProps =
|
|
8235
|
+
const buildRowProps = useCallback18(
|
|
8070
8236
|
(track, drag) => {
|
|
8071
8237
|
const id = track.handle.id;
|
|
8072
8238
|
const pickerProps = features.instrumentPicker ? {
|
|
@@ -8166,12 +8332,12 @@ function GeneratorPanelShell({ core, slots }) {
|
|
|
8166
8332
|
]
|
|
8167
8333
|
);
|
|
8168
8334
|
if (!activeSceneId) {
|
|
8169
|
-
return /* @__PURE__ */
|
|
8335
|
+
return /* @__PURE__ */ jsx28(
|
|
8170
8336
|
"div",
|
|
8171
8337
|
{
|
|
8172
8338
|
"data-testid": `no-scene-placeholder-${identity.familyKey}`,
|
|
8173
8339
|
className: "flex items-center justify-center py-8",
|
|
8174
|
-
children: /* @__PURE__ */
|
|
8340
|
+
children: /* @__PURE__ */ jsx28(
|
|
8175
8341
|
"button",
|
|
8176
8342
|
{
|
|
8177
8343
|
onClick: () => onSelectScene?.(),
|
|
@@ -8183,12 +8349,12 @@ function GeneratorPanelShell({ core, slots }) {
|
|
|
8183
8349
|
);
|
|
8184
8350
|
}
|
|
8185
8351
|
if (!sceneContext?.hasContract) {
|
|
8186
|
-
return /* @__PURE__ */
|
|
8352
|
+
return /* @__PURE__ */ jsx28(
|
|
8187
8353
|
"div",
|
|
8188
8354
|
{
|
|
8189
8355
|
"data-testid": `no-contract-placeholder-${identity.familyKey}`,
|
|
8190
8356
|
className: "flex items-center justify-center py-8",
|
|
8191
|
-
children: /* @__PURE__ */
|
|
8357
|
+
children: /* @__PURE__ */ jsx28(
|
|
8192
8358
|
"button",
|
|
8193
8359
|
{
|
|
8194
8360
|
onClick: () => onOpenContract?.(),
|
|
@@ -8200,7 +8366,7 @@ function GeneratorPanelShell({ core, slots }) {
|
|
|
8200
8366
|
);
|
|
8201
8367
|
}
|
|
8202
8368
|
if (features.bulkComposePlaceholders && isComposing) {
|
|
8203
|
-
return /* @__PURE__ */
|
|
8369
|
+
return /* @__PURE__ */ jsx28("div", { "data-testid": `${identity.familyKey}-section`, className: "p-2", children: /* @__PURE__ */ jsx28(SorceryProgressBar, { isLoading: true, statusText: "COMPOSING...", heightClass: "h-10" }) });
|
|
8204
8370
|
}
|
|
8205
8371
|
const activePlaceholders = features.bulkComposePlaceholders ? placeholders : [];
|
|
8206
8372
|
if (activePlaceholders.length > 0) {
|
|
@@ -8211,18 +8377,18 @@ function GeneratorPanelShell({ core, slots }) {
|
|
|
8211
8377
|
tracksByDbId.set(t.handle.id, t);
|
|
8212
8378
|
}
|
|
8213
8379
|
}
|
|
8214
|
-
return /* @__PURE__ */
|
|
8380
|
+
return /* @__PURE__ */ jsx28("div", { "data-testid": `${identity.familyKey}-section`, className: "p-2 space-y-2", children: activePlaceholders.map((ph) => {
|
|
8215
8381
|
const loadedTrack = ph.status === "completed" ? tracksByDbId.get(ph.id) : void 0;
|
|
8216
8382
|
if (loadedTrack) {
|
|
8217
|
-
return /* @__PURE__ */
|
|
8383
|
+
return /* @__PURE__ */ jsx28(TrackRow, { ...buildRowProps(loadedTrack) }, ph.id);
|
|
8218
8384
|
}
|
|
8219
|
-
return /* @__PURE__ */
|
|
8385
|
+
return /* @__PURE__ */ jsx28(
|
|
8220
8386
|
"div",
|
|
8221
8387
|
{
|
|
8222
8388
|
"data-testid": "bulk-placeholder-track",
|
|
8223
8389
|
className: "relative rounded-sm border w-full overflow-hidden border-sas-border bg-sas-panel-alt",
|
|
8224
8390
|
style: { borderLeftColor: identity.placeholderAccentColor, borderLeftWidth: "3px" },
|
|
8225
|
-
children: /* @__PURE__ */
|
|
8391
|
+
children: /* @__PURE__ */ jsx28(SorceryProgressBar, { isLoading: true, statusText: "CONJURING MIDI...", heightClass: "h-10" })
|
|
8226
8392
|
},
|
|
8227
8393
|
ph.id
|
|
8228
8394
|
);
|
|
@@ -8234,13 +8400,13 @@ function GeneratorPanelShell({ core, slots }) {
|
|
|
8234
8400
|
supportsMeters,
|
|
8235
8401
|
levels: supportsMeters ? trackLevels : void 0,
|
|
8236
8402
|
handlers,
|
|
8237
|
-
renderDefaultTrackRow: (track, overrides, drag) => /* @__PURE__ */
|
|
8403
|
+
renderDefaultTrackRow: (track, overrides, drag) => /* @__PURE__ */ jsx28(TrackRow, { ...{ ...buildRowProps(track, drag), ...overrides ?? {} } }, track.handle.id),
|
|
8238
8404
|
setGroupMute,
|
|
8239
8405
|
setGroupSolo,
|
|
8240
8406
|
deleteGroup
|
|
8241
8407
|
};
|
|
8242
|
-
return /* @__PURE__ */
|
|
8243
|
-
features.importTracks && host.listImportableTracks && /* @__PURE__ */
|
|
8408
|
+
return /* @__PURE__ */ jsxs22("div", { "data-testid": `${identity.familyKey}-section`, className: "p-2 space-y-2", children: [
|
|
8409
|
+
features.importTracks && host.listImportableTracks && /* @__PURE__ */ jsx28(
|
|
8244
8410
|
ImportTrackModal,
|
|
8245
8411
|
{
|
|
8246
8412
|
host,
|
|
@@ -8253,7 +8419,7 @@ function GeneratorPanelShell({ core, slots }) {
|
|
|
8253
8419
|
testIdPrefix: `${identity.familyKey}-import`
|
|
8254
8420
|
}
|
|
8255
8421
|
),
|
|
8256
|
-
features.importTracks && host.listImportableTracks && host.getTrackSound && /* @__PURE__ */
|
|
8422
|
+
features.importTracks && host.listImportableTracks && host.getTrackSound && /* @__PURE__ */ jsx28(
|
|
8257
8423
|
ImportTrackModal,
|
|
8258
8424
|
{
|
|
8259
8425
|
host,
|
|
@@ -8268,7 +8434,7 @@ function GeneratorPanelShell({ core, slots }) {
|
|
|
8268
8434
|
}
|
|
8269
8435
|
),
|
|
8270
8436
|
slots?.modals,
|
|
8271
|
-
canCrossfade && xfFromId && xfToId && /* @__PURE__ */
|
|
8437
|
+
canCrossfade && xfFromId && xfToId && /* @__PURE__ */ jsx28("div", { className: designerView ? "contents" : "hidden", children: /* @__PURE__ */ jsx28(
|
|
8272
8438
|
TransitionDesigner,
|
|
8273
8439
|
{
|
|
8274
8440
|
host,
|
|
@@ -8287,8 +8453,8 @@ function GeneratorPanelShell({ core, slots }) {
|
|
|
8287
8453
|
testIdPrefix: `${identity.familyKey}-transition-designer`
|
|
8288
8454
|
}
|
|
8289
8455
|
) }),
|
|
8290
|
-
!(designerView && canCrossfade) && (isLoadingTracks ? /* @__PURE__ */
|
|
8291
|
-
panelBus.supported && panelBus.bus && /* @__PURE__ */
|
|
8456
|
+
!(designerView && canCrossfade) && (isLoadingTracks ? /* @__PURE__ */ jsx28("div", { className: "text-sas-muted text-xs text-center py-4", children: "Loading tracks..." }) : /* @__PURE__ */ jsxs22(Fragment7, { children: [
|
|
8457
|
+
panelBus.supported && panelBus.bus && /* @__PURE__ */ jsx28(
|
|
8292
8458
|
PanelMasterStrip,
|
|
8293
8459
|
{
|
|
8294
8460
|
bus: panelBus.bus,
|
|
@@ -8309,7 +8475,7 @@ function GeneratorPanelShell({ core, slots }) {
|
|
|
8309
8475
|
}
|
|
8310
8476
|
),
|
|
8311
8477
|
slots?.beforeRows,
|
|
8312
|
-
resolvedCrossfadePairs.map((pair) => /* @__PURE__ */
|
|
8478
|
+
resolvedCrossfadePairs.map((pair) => /* @__PURE__ */ jsx28(
|
|
8313
8479
|
CrossfadeTrackRow,
|
|
8314
8480
|
{
|
|
8315
8481
|
accentColor: identity.transitionAccentColor,
|
|
@@ -8346,7 +8512,7 @@ function GeneratorPanelShell({ core, slots }) {
|
|
|
8346
8512
|
},
|
|
8347
8513
|
pair.groupId
|
|
8348
8514
|
)),
|
|
8349
|
-
resolvedSingleFades.map((fade) => /* @__PURE__ */
|
|
8515
|
+
resolvedSingleFades.map((fade) => /* @__PURE__ */ jsx28(
|
|
8350
8516
|
FadeTrackRow,
|
|
8351
8517
|
{
|
|
8352
8518
|
accentColor: identity.transitionAccentColor,
|
|
@@ -8371,7 +8537,7 @@ function GeneratorPanelShell({ core, slots }) {
|
|
|
8371
8537
|
},
|
|
8372
8538
|
fade.dbId
|
|
8373
8539
|
)),
|
|
8374
|
-
resolvedGroupFades.map((group) => /* @__PURE__ */
|
|
8540
|
+
resolvedGroupFades.map((group) => /* @__PURE__ */ jsx28(
|
|
8375
8541
|
GroupFadeTrackRow,
|
|
8376
8542
|
{
|
|
8377
8543
|
accentColor: identity.transitionAccentColor,
|
|
@@ -8407,20 +8573,20 @@ function GeneratorPanelShell({ core, slots }) {
|
|
|
8407
8573
|
group.groupId
|
|
8408
8574
|
)),
|
|
8409
8575
|
(adapter.groupExtensions ?? []).flatMap(
|
|
8410
|
-
(ext) => (resolvedGenericGroups[ext.metaKey]?.resolved ?? []).filter((group) => !group.members.every((m) => fadeMemberDbIds.has(m.dbId))).map((group) => /* @__PURE__ */
|
|
8576
|
+
(ext) => (resolvedGenericGroups[ext.metaKey]?.resolved ?? []).filter((group) => !group.members.every((m) => fadeMemberDbIds.has(m.dbId))).map((group) => /* @__PURE__ */ jsx28(React23.Fragment, { children: ext.renderGroup(group, groupCtx) }, `${ext.metaKey}:${group.groupId}`))
|
|
8411
8577
|
),
|
|
8412
8578
|
tracks.map((track, index) => {
|
|
8413
8579
|
if (crossfadeMemberDbIds.has(track.handle.dbId) || fadeMemberDbIds.has(track.handle.dbId) || genericGroupMemberDbIds.has(track.handle.dbId)) {
|
|
8414
8580
|
return null;
|
|
8415
8581
|
}
|
|
8416
|
-
return /* @__PURE__ */
|
|
8582
|
+
return /* @__PURE__ */ jsx28(TrackRow, { ...buildRowProps(track, reorder.dragPropsFor(index)) }, track.handle.id);
|
|
8417
8583
|
}),
|
|
8418
8584
|
slots?.afterRows
|
|
8419
8585
|
] })),
|
|
8420
8586
|
features.exportMidi && !designerView && !isLoadingTracks && tracks.length > 0 && (() => {
|
|
8421
8587
|
const hasAnyMidi = tracks.some((t) => t.hasMidi);
|
|
8422
8588
|
const exportDisabled = isExportingMidi || !hasAnyMidi;
|
|
8423
|
-
return /* @__PURE__ */
|
|
8589
|
+
return /* @__PURE__ */ jsx28("div", { className: "pt-2", children: /* @__PURE__ */ jsx28(
|
|
8424
8590
|
"button",
|
|
8425
8591
|
{
|
|
8426
8592
|
"data-testid": "export-midi-tracks-button",
|
|
@@ -8910,7 +9076,7 @@ Your previous ensemble had these problems \u2014 fix them while keeping everythi
|
|
|
8910
9076
|
}
|
|
8911
9077
|
|
|
8912
9078
|
// src/constants/sdk-version.ts
|
|
8913
|
-
var PLUGIN_SDK_VERSION = "2.
|
|
9079
|
+
var PLUGIN_SDK_VERSION = "2.46.0";
|
|
8914
9080
|
|
|
8915
9081
|
// src/utils/format-concurrent-tracks.ts
|
|
8916
9082
|
function formatConcurrentTracks(ctx) {
|
|
@@ -9118,6 +9284,7 @@ export {
|
|
|
9118
9284
|
TRANSITION_DESIGNER_DRAFT_KEY,
|
|
9119
9285
|
TrackDrawer,
|
|
9120
9286
|
TrackExternalFxSection,
|
|
9287
|
+
TrackFreezeSection,
|
|
9121
9288
|
TrackMeterStrip,
|
|
9122
9289
|
TrackRow,
|
|
9123
9290
|
TransitionDesigner,
|
|
@@ -9188,6 +9355,7 @@ export {
|
|
|
9188
9355
|
useSceneState,
|
|
9189
9356
|
useSoundHistory,
|
|
9190
9357
|
useTrackExternalFx,
|
|
9358
|
+
useTrackFreeze,
|
|
9191
9359
|
useTrackLevel,
|
|
9192
9360
|
useTrackLevels,
|
|
9193
9361
|
useTrackMeter,
|