Files
hyperframes/packages/studio/src/utils/assetPreviewDismiss.ts
T
ukimsanov 54f41b41b6 fix(studio): restore golden-branch timeline behaviors dropped by the stack rebuild
The Studio stack rebuild (#2291) landed the remaining NLE layers but dropped
or regressed several final-wave behaviors from the reviewed studio-dnd stack,
and never repaired the stale timelineZones.ts that #2279 introduced. Restores:

- TimelineRuler: sticky under vertical scroll, full-height gridlines removed
  (beat lines only), frame-number tick labels via a persisted timeDisplayMode
  store preference (PlayerControls toggle now store-backed)
- timelineZones: stable track lanes — lane = authored data-track-index
  ascending; z is paint order only (replaces the stale z-driven lane pack,
  which broke track insert-band commits that contractually depend on it)
- persistTimelineBatchEdit: a batch member whose patch is a no-op (attributes
  already at target values, e.g. in a track-insert renumber) is skipped
  instead of aborting and rolling back the whole batch — this alone made
  new-track creation (incl. the top insert band) fail silently
- useTimelineStackingSync: unresolvable clips read as NaN again so
  timelineStackingSync's Number.isFinite exclusion contract holds (z=0
  fabrications skewed stacking boundaries)
- timelineAssetDrop: drops land on the drop track (no overlap bump to
  max-track+1), data-hf-id stamped, audio gets data-volume
- timing edits: soft-reload the server's rewritten GSAP script instead of a
  full iframe remount (no all-clips flash on move/resize); full reload only
  when no scriptText or the soft path can't apply, and one full reload when a
  group edit touches non-active files (new hooks/timelineTimingSync.ts)
- duration: content-driven grow-AND-shrink on move/resize/delete, synced
  optimistically to the store and the live root data-duration at release
  (was a grow-only ratchet; shrink never updated the readout)

New UX: sidebar asset click opens a compact non-modal preview over the canvas
(dismiss on outside click, Escape, playback, or seek), and clicking an
already-added asset reveals its clip in the timeline (smooth minimal scroll
to its time and lane; vertical-only in fit zoom).

Verified by pointer-driving a real project: sticky ruler + gridline removal,
no iframe remount on move/resize (marker survives, GSAP tween positions
rewritten in place), duration readout 40->37->40 on shrink/stretch, and
top-insert-band track creation renumbering lanes correctly on disk.
2026-07-13 16:48:51 -07:00

30 lines
1.1 KiB
TypeScript

/**
* Dismissal rule for the sidebar asset preview overlay (AssetPreviewOverlay):
* the preview is a transient "look at this asset" state, so any playhead
* activity — starting playback, or seeking/scrubbing away from where the
* playhead sat when the preview opened — hands focus back to the canvas and
* closes it.
*
* Pure — unit-tested. The overlay captures `openedTime` when the preview
* opens and feeds every subsequent player-store snapshot through this.
*/
export interface AssetPreviewDismissSnapshot {
isPlaying: boolean;
currentTime: number;
/** Pending out-of-loop seek request (playerStore.requestedSeekTime). */
requestedSeekTime: number | null;
}
/** Tolerance for float noise in currentTime echoes (well under one frame). */
const TIME_EPSILON_S = 1e-6;
export function shouldDismissAssetPreview(
openedTime: number,
snapshot: AssetPreviewDismissSnapshot,
): boolean {
if (snapshot.isPlaying) return true;
if (snapshot.requestedSeekTime !== null) return true;
return Math.abs(snapshot.currentTime - openedTime) > TIME_EPSILON_S;
}