mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-11 23:00:03 +00:00
feat(studio): timeline track = stacking layer (NLE-style layering)
Re-architect the timeline row model from data-track-index rows to stacking layers. Rows represent stacking layers per context: explicit-z clips merge onto one track when they share a z and don't overlap in time; auto-z clips stay one row each (DOM order); audio is pulled into its own bottom lanes. Rows keyed by a stable layer id, not data-track-index. Vertical drag always writes z-index, never track: drop onto a layer joins it (same z), between layers interpolates a new z, past the ends creates a new front/back layer. data-track-index is never rewritten; #958 holds. Adds hasExplicitZIndex capture (computed z != auto). L1: hasExplicitZIndex on the element model L2: buildStackingTimelineLayers (layer-based rows) L3: layer-aware vertical drag (join / interpolate / new-extreme)
This commit is contained in:
@@ -2,12 +2,14 @@ import { useCallback, useState, type RefObject } from "react";
|
||||
import { TIMELINE_ASSET_MIME, TIMELINE_BLOCK_MIME } from "../../utils/timelineAssetDrop";
|
||||
import { TRACK_H, resolveTimelineAssetDrop } from "./timelineLayout";
|
||||
import type { TimelineDropCallbacks } from "./timelineCallbacks";
|
||||
import type { StackingTimelineLayer, TimelineLayerId } from "./timelineTrackOrder";
|
||||
|
||||
interface UseTimelineAssetDropOptions extends TimelineDropCallbacks {
|
||||
scrollRef: RefObject<HTMLDivElement | null>;
|
||||
ppsRef: RefObject<number>;
|
||||
durationRef: RefObject<number>;
|
||||
trackOrderRef: RefObject<number[]>;
|
||||
trackOrderRef: RefObject<TimelineLayerId[]>;
|
||||
timelineLayersRef: RefObject<StackingTimelineLayer[]>;
|
||||
}
|
||||
|
||||
export function useTimelineAssetDrop({
|
||||
@@ -15,6 +17,7 @@ export function useTimelineAssetDrop({
|
||||
ppsRef,
|
||||
durationRef,
|
||||
trackOrderRef,
|
||||
timelineLayersRef,
|
||||
onFileDrop,
|
||||
onAssetDrop,
|
||||
onBlockDrop,
|
||||
@@ -39,6 +42,10 @@ export function useTimelineAssetDrop({
|
||||
setIsDragOver(false);
|
||||
const scroll = scrollRef.current;
|
||||
const rect = scroll?.getBoundingClientRect();
|
||||
const layerById = new Map(timelineLayersRef.current.map((layer) => [layer.id, layer]));
|
||||
const trackOrder = trackOrderRef.current
|
||||
.map((id) => layerById.get(id)?.placementTrack)
|
||||
.filter((track): track is number => track != null);
|
||||
const dropInput = {
|
||||
rectLeft: rect?.left ?? 0,
|
||||
rectTop: rect?.top ?? 0,
|
||||
@@ -47,7 +54,7 @@ export function useTimelineAssetDrop({
|
||||
pixelsPerSecond: ppsRef.current,
|
||||
duration: durationRef.current,
|
||||
trackHeight: TRACK_H,
|
||||
trackOrder: trackOrderRef.current,
|
||||
trackOrder,
|
||||
};
|
||||
if (onFileDrop && e.dataTransfer.files.length > 0) {
|
||||
void onFileDrop(
|
||||
@@ -84,7 +91,16 @@ export function useTimelineAssetDrop({
|
||||
}
|
||||
}
|
||||
},
|
||||
[onAssetDrop, onBlockDrop, onFileDrop, scrollRef, ppsRef, durationRef, trackOrderRef],
|
||||
[
|
||||
onAssetDrop,
|
||||
onBlockDrop,
|
||||
onFileDrop,
|
||||
scrollRef,
|
||||
ppsRef,
|
||||
durationRef,
|
||||
trackOrderRef,
|
||||
timelineLayersRef,
|
||||
],
|
||||
);
|
||||
|
||||
return { isDragOver, setIsDragOver, handleAssetDragOver, handleAssetDrop };
|
||||
|
||||
Reference in New Issue
Block a user