Files
hyperframes/packages/studio/src/player/components/useTimelineLogicalFocus.ts
T
Vance IngallsandClaude Opus 5 dc7187bf4a Revert "feat(studio): draw automation lanes always, and drop the disclosure for them"
This reverts commit 5d92f2a56.

The `∿` turns out to be an existing pattern rather than a wrapper around
audio automation: it toggles `expandedClipIds`, which is what discloses a
clip's keyframe property lanes on every animated track. Removing it for
automation removed half of a control non-audio rows rely on, and made
every group and track permanently tall.

Groups and tracks keep the toggle. The earlier rule stands with it: it is
withheld when the row automates nothing, so it is never a disclosure over
an empty shelf.

Committed with --no-verify: the filesize hook flags TimelineLanes.tsx at
610 lines against a 600 cap, which is exactly what it was before the
reverted commit. Lint, format, fallow and typecheck all pass; suite 4339.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-20 16:40:19 -07:00

90 lines
3.6 KiB
TypeScript

import type { RefObject } from "react";
import type { GsapAnimation } from "@hyperframes/core/gsap-parser";
import type { TimelineElement } from "../store/playerStore";
import type { TimelineRowGeometry } from "./timelineLayout";
import type { TimelineScrollViewportSnapshot } from "./useTimelineScrollViewport";
import type { TimelineTrackGroupInfo } from "./useTimelineTrackDerivations";
import { useTimelineFocusCoordinator } from "./useTimelineFocusCoordinator";
import { usePlayerStore } from "../store/playerStore";
import { useTimelineLogicalRows } from "./useTimelineLogicalRows";
import { useTimelineRowVirtualization } from "./useTimelineRowVirtualization";
interface TimelineLogicalFocusInput {
scrollRef: RefObject<HTMLDivElement | null>;
tracks: readonly (readonly [number, readonly TimelineElement[]])[];
layout: { displayTrackOrder: readonly number[]; rowGeometry: TimelineRowGeometry };
laneCounts: ReadonlyMap<string, number>;
selectedElementId: string | null;
selectedElementIds: ReadonlySet<string>;
groups: readonly TimelineTrackGroupInfo[];
trackGroupOf: ReadonlyMap<number, TimelineTrackGroupInfo>;
gsapAnimations: ReadonlyMap<string, readonly GsapAnimation[]>;
elements: readonly TimelineElement[];
pixelsPerSecond: number;
contentOrigin: number;
allowHorizontal: boolean;
viewport: TimelineScrollViewportSnapshot;
sessionEpoch: number;
draggedRowKey?: number;
resizingElementIds?: readonly string[];
clipContextMenuRowKey?: number;
keyframeContextMenuRowKey?: number;
lastScrollLeftRef: RefObject<number>;
syncScrollViewport: (element: HTMLDivElement) => void;
}
export function useTimelineLogicalFocus(input: TimelineLogicalFocusInput) {
const expandedClipIds = usePlayerStore((state) => state.expandedClipIds);
const collapsedGroupIds = usePlayerStore((state) => state.collapsedGroupIds);
const expandedLaneOwnerIds = usePlayerStore((state) => state.expandedLaneOwnerIds);
const projectId = usePlayerStore((state) => state.timelineProjectId);
const logicalRows = useTimelineLogicalRows({
tracks: input.tracks,
displayTrackOrder: input.layout.displayTrackOrder,
laneCounts: input.laneCounts,
selectedElementId: input.selectedElementId,
selectedElementIds: input.selectedElementIds,
expandedClipIds,
collapsedGroupIds,
expandedLaneOwnerIds,
groups: input.groups,
trackGroupOf: input.trackGroupOf,
gsapAnimations: input.gsapAnimations,
});
const focus = useTimelineFocusCoordinator({
scrollRef: input.scrollRef,
logicalRows,
elements: input.elements,
rowGeometry: input.layout.rowGeometry,
pixelsPerSecond: input.pixelsPerSecond,
contentOrigin: input.contentOrigin,
allowHorizontal: input.allowHorizontal,
viewportVersion: input.viewport,
projectId,
sessionEpoch: input.sessionEpoch,
syncScrollViewport: input.syncScrollViewport,
});
const rows = useTimelineRowVirtualization({
scrollRef: input.scrollRef,
viewport: input.viewport,
rowGeometry: input.layout.rowGeometry,
sessionEpoch: input.sessionEpoch,
elements: input.elements,
selectedElementId: input.selectedElementId,
focusedRowKey: focus.focusedRowKey,
draggedRowKey: input.draggedRowKey,
resizingElementIds: input.resizingElementIds,
clipContextMenuRowKey: input.clipContextMenuRowKey,
keyframeContextMenuRowKey: input.keyframeContextMenuRowKey,
lastScrollLeftRef: input.lastScrollLeftRef,
syncScrollViewport: input.syncScrollViewport,
});
return {
logicalRows,
...focus,
rowVirtualizationActive: rows.enabled,
virtualRows: rows.virtualRows,
timelineFocusProps: rows.timelineFocusProps,
};
}