fix: move ghostLayers decl before useLayoutEffect to fix TDZ

This commit is contained in:
2026-07-27 17:15:04 +07:00
parent 035d75e504
commit 53a27b5af4
2 changed files with 60 additions and 59 deletions
+58 -57
View File
@@ -4612,6 +4612,64 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, activeTracks, onClos
const [isLooping, setIsLooping] = React.useState(false);
const [showGhostNotes, setShowGhostNotes] = React.useState(true);
const [sessionSyncMode, setSessionSyncMode] = React.useState(true);
const allMidiItems = React.useMemo(() => {
const result = [];
(activeTracks || []).forEach(t => {
if (!t.midiItems || !t.midiItems.length) return;
t.midiItems.forEach(m => {
var extended = Object.assign({}, m, { _trackId: t.id, _trackName: t.name });
result.push(extended);
});
});
return result;
}, [activeTracks]);
const ghostLayers = React.useMemo(function() {
if (!activeTracks || !st || !st.target_id) return [];
var fn = window.SonicGhost && window.SonicGhost.extractGhostLayers;
return fn ? fn(activeTracks, st.trackId, st.target_id, parseInt(bpm) || 120) : [];
}, [activeTracks, st.trackId, st.target_id, bpm]);
const secondsPerBar = (60.0 / (parseInt(bpm) || 120)) * 4;
const activeTargetItem = React.useMemo(function() {
if (!activeTracks || !st) return null;
var trk = activeTracks.find(function(t) { return t.id === st.trackId; });
return trk ? (trk.midiItems || []).find(function(m) { return m.id === st.target_id; }) : null;
}, [activeTracks, st.trackId, st.target_id]);
const sessionStartBar = sessionSyncMode && activeTargetItem
? (activeTargetItem.startTime / secondsPerBar) : 0;
const handleSwitchMidiItem = React.useCallback(function(itemId) {
if (itemId === st.target_id) return;
if (st.isDirty) {
onSaveNotes(st.id, st.trackId, st.target_id, notes);
}
var match = allMidiItems.find(function(m) { return m.id === itemId; });
if (!match) return;
var trk = (activeTracks || []).find(function(t) { return t.id === match._trackId; });
setSubTabs(function(prev) {
return prev.map(function(s) {
if (s.id !== st.id) return s;
return Object.assign({}, s, {
trackId: match._trackId,
target_id: match.id,
label: 'Piano Roll: ' + (match.name || 'MIDI'),
notes: match.notes || [],
duration: match.duration || 4,
instrumentProgram: trk ? trk.instrumentProgram : undefined,
instrumentName: trk ? trk.instrumentName : undefined,
note_selection: [],
currentTime: 0,
isDirty: false
});
});
});
setSelectedNoteIds([]);
setLoopStartBeat(null);
setLoopEndBeat(null);
}, [st.id, st.target_id, st.isDirty, allMidiItems, activeTracks, onSaveNotes, notes]);
const rulerDragRef = React.useRef(null);
React.useEffect(() => {
const handler = (e) => {
@@ -5678,63 +5736,6 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, activeTracks, onClos
const [showCC, setShowCC] = React.useState(true);
const [ccHeight, setCcHeight] = React.useState(80);
const allMidiItems = React.useMemo(() => {
const result = [];
(activeTracks || []).forEach(t => {
if (!t.midiItems || !t.midiItems.length) return;
t.midiItems.forEach(m => {
var extended = Object.assign({}, m, { _trackId: t.id, _trackName: t.name });
result.push(extended);
});
});
return result;
}, [activeTracks]);
const ghostLayers = React.useMemo(function() {
if (!activeTracks || !st || !st.target_id) return [];
var fn = window.SonicGhost && window.SonicGhost.extractGhostLayers;
return fn ? fn(activeTracks, st.trackId, st.target_id, parseInt(bpm) || 120) : [];
}, [activeTracks, st.trackId, st.target_id, bpm]);
const secondsPerBar = (60.0 / (parseInt(bpm) || 120)) * 4;
const activeTargetItem = React.useMemo(function() {
if (!activeTracks || !st) return null;
var trk = activeTracks.find(function(t) { return t.id === st.trackId; });
return trk ? (trk.midiItems || []).find(function(m) { return m.id === st.target_id; }) : null;
}, [activeTracks, st.trackId, st.target_id]);
const sessionStartBar = sessionSyncMode && activeTargetItem
? (activeTargetItem.startTime / secondsPerBar) : 0;
const handleSwitchMidiItem = React.useCallback(function(itemId) {
if (itemId === st.target_id) return;
if (st.isDirty) {
onSaveNotes(st.id, st.trackId, st.target_id, notes);
}
var match = allMidiItems.find(function(m) { return m.id === itemId; });
if (!match) return;
var trk = (activeTracks || []).find(function(t) { return t.id === match._trackId; });
setSubTabs(function(prev) {
return prev.map(function(s) {
if (s.id !== st.id) return s;
return Object.assign({}, s, {
trackId: match._trackId,
target_id: match.id,
label: 'Piano Roll: ' + (match.name || 'MIDI'),
notes: match.notes || [],
duration: match.duration || 4,
instrumentProgram: trk ? trk.instrumentProgram : undefined,
instrumentName: trk ? trk.instrumentName : undefined,
note_selection: [],
currentTime: 0,
isDirty: false
});
});
});
setSelectedNoteIds([]);
setLoopStartBeat(null);
setLoopEndBeat(null);
}, [st.id, st.target_id, st.isDirty, allMidiItems, activeTracks, onSaveNotes, notes]);
const snapPitchToScale = (pitch, scale) => {
if (!scale) return pitch;
const octave = Math.floor(pitch / 12);
File diff suppressed because one or more lines are too long