mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-11 23:00:03 +00:00
feat(studio): unify timeline vertical reorder with z-index stacking
Timeline rows now order by scoped stacking (z-index per stacking context) instead of data-track-index, and dragging a clip up/down commits a targeted z-index change through the same shared path the layers panel uses. Both panels stay consistent and moving a clip actually changes front/back. data-track-index is demoted to time-overlap layout only; no bulk z-index injection (#958 intact). Also restores beat-snapping on keyframe retiming (re-wires snapKeyframePctToBeat, orphaned when keyframe dragging was removed) which surfaced while unifying the model. Extracts pure track-ordering logic to timelineTrackOrder.ts, the stacking reorder commit + deleteSelectedKeyframes to timelineEditingHelpers.ts, to keep StudioApp / the timeline hook / Timeline under the studio 600-LOC cap. U3: scoped stacking row order in the timeline U4: vertical drag commits z-index via the shared reorder commit U8: restore keyframe beat-snap on retime
This commit is contained in:
@@ -11,6 +11,7 @@ import { usePanelLayout } from "./hooks/usePanelLayout";
|
||||
import { useFileManager } from "./hooks/useFileManager";
|
||||
import { usePreviewPersistence } from "./hooks/usePreviewPersistence";
|
||||
import { useTimelineEditing } from "./hooks/useTimelineEditing";
|
||||
import type { TimelineZIndexReorderCommit } from "./hooks/useTimelineEditingTypes";
|
||||
import type { BlockPreviewInfo } from "./components/sidebar/BlocksTab";
|
||||
import { useDomEditSession } from "./hooks/useDomEditSession";
|
||||
import { useSdkSession } from "./hooks/useSdkSession";
|
||||
@@ -19,7 +20,7 @@ import { useBlockHandlers } from "./hooks/useBlockHandlers";
|
||||
import { useAppHotkeys } from "./hooks/useAppHotkeys";
|
||||
import { useClipboard } from "./hooks/useClipboard";
|
||||
import { readStudioUiPreferences, writeStudioUiPreferences } from "./utils/studioUiPreferences";
|
||||
import { selectedKeyframePercentagesForElement } from "./utils/keyframeSelection";
|
||||
import { deleteSelectedKeyframes } from "./hooks/timelineEditingHelpers";
|
||||
import { useCaptionDetection } from "./hooks/useCaptionDetection";
|
||||
import { useRenderClipContent } from "./hooks/useRenderClipContent";
|
||||
import { useConsoleErrorCapture } from "./hooks/useConsoleErrorCapture";
|
||||
@@ -140,6 +141,7 @@ export function StudioApp() {
|
||||
});
|
||||
const editHistory = usePersistentEditHistory({ projectId });
|
||||
const domEditSaveTimestampRef = useRef(0);
|
||||
const handleDomZIndexReorderCommitRef = useRef<TimelineZIndexReorderCommit | null>(null);
|
||||
const pendingTimelineEditPathRef = useRef(new Set<string>());
|
||||
const isGestureRecordingRef = useRef(false);
|
||||
const reloadPreview = useCallback(() => setRefreshKey((k) => k + 1), []);
|
||||
@@ -188,6 +190,7 @@ export function StudioApp() {
|
||||
isRecordingRef: isGestureRecordingRef,
|
||||
sdkSession: sdkHandle.session,
|
||||
forceReloadSdkSession: sdkHandle.forceReload,
|
||||
handleDomZIndexReorderCommitRef,
|
||||
});
|
||||
const {
|
||||
activeBlockParams,
|
||||
@@ -306,19 +309,12 @@ export function StudioApp() {
|
||||
forceReloadSdkSession: sdkHandle.forceReload,
|
||||
});
|
||||
domEditSelectionBridgeRef.current = domEditSession.domEditSelection;
|
||||
handleDomZIndexReorderCommitRef.current = domEditSession.handleDomZIndexReorderCommit;
|
||||
clearDomSelectionRef.current = domEditSession.clearDomSelection;
|
||||
handleDomEditElementDeleteRef.current = domEditSession.handleDomEditElementDelete;
|
||||
resetKeyframesRef.current = domEditSession.handleResetSelectedElementKeyframes;
|
||||
invalidateGsapCacheRef.current = domEditSession.invalidateGsapCache;
|
||||
deleteSelectedKeyframesRef.current = () => {
|
||||
const { selectedKeyframes, selectedElementId } = usePlayerStore.getState();
|
||||
const a = domEditSession.selectedGsapAnimations.find((x) => x.keyframes);
|
||||
if (!a) return;
|
||||
// Only the active element's keyframes; a stale cross-element selection must not delete here.
|
||||
for (const p of selectedKeyframePercentagesForElement(selectedKeyframes, selectedElementId)) {
|
||||
domEditSession.handleGsapRemoveKeyframe(a.id, p);
|
||||
}
|
||||
};
|
||||
deleteSelectedKeyframesRef.current = () => deleteSelectedKeyframes(domEditSession);
|
||||
useSdkSelectionSync(
|
||||
sdkHandle.session,
|
||||
domEditSession.domEditSelection,
|
||||
|
||||
Reference in New Issue
Block a user