@hyperframes/studio 0.7.90 → 0.7.92
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/{hyperframes-player-RS9ROX_S.js → hyperframes-player-9qOa08Tv.js} +1 -1
- package/dist/assets/{index-Bi-CwQDX.js → index-Bw4lNdtO.js} +1 -1
- package/dist/assets/{index-CquRJgm-.js → index-CDTN2ZVa.js} +1 -1
- package/dist/assets/index-DIntkrQl.js +428 -0
- package/dist/index.d.ts +20 -16
- package/dist/index.html +1 -1
- package/dist/index.js +6495 -5429
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
- package/src/components/StudioRightPanel.tsx +1 -1
- package/src/components/editor/GsapAnimationList.tsx +84 -0
- package/src/components/editor/GsapAnimationSection.test.tsx +100 -11
- package/src/components/editor/GsapAnimationSection.tsx +11 -41
- package/src/components/editor/PropertyPanel.tsx +1 -1
- package/src/components/editor/PropertyPanelFlat.tsx +29 -26
- package/src/components/editor/gsapAnimationCallbacks.ts +0 -10
- package/src/components/editor/propertyPanelFlatDescriptors.ts +20 -0
- package/src/components/editor/propertyPanelFlatMotionSection.test.tsx +56 -55
- package/src/components/editor/propertyPanelFlatMotionSection.tsx +9 -37
- package/src/components/editor/propertyPanelTypes.ts +1 -1
- package/src/components/nle/useTimelineEditCallbacks.test.tsx +78 -4
- package/src/components/nle/useTimelineEditCallbacks.ts +12 -7
- package/src/components/renders/useRenderQueue.ts +16 -3
- package/src/components/renders/useRenderQueueTelemetry.test.tsx +104 -0
- package/src/contexts/DomEditContext.tsx +1 -1
- package/src/hooks/useDomEditSession.test.tsx +1 -1
- package/src/hooks/useDomEditSession.ts +1 -1
- package/src/hooks/useGsapKeyframeOps.test.tsx +83 -5
- package/src/hooks/useGsapKeyframeOps.ts +20 -9
- package/src/player/components/BeatStrip.test.tsx +374 -0
- package/src/player/components/BeatStrip.tsx +295 -37
- package/src/player/components/KeyframeDiamondContextMenu.test.tsx +16 -1
- package/src/player/components/KeyframeDiamondContextMenu.tsx +6 -5
- package/src/player/components/Timeline.test.ts +2 -3
- package/src/player/components/Timeline.tsx +47 -48
- package/src/player/components/TimelineCanvas.tsx +14 -71
- package/src/player/components/TimelineClip.tsx +6 -3
- package/src/player/components/TimelineClipDiamonds.test.tsx +442 -18
- package/src/player/components/TimelineClipDiamonds.tsx +66 -211
- package/src/player/components/TimelineGestureOverlay.test.tsx +90 -0
- package/src/player/components/TimelineGestureOverlay.tsx +96 -0
- package/src/player/components/TimelineLanes.test.tsx +0 -1
- package/src/player/components/TimelineLanes.tsx +3 -2
- package/src/player/components/TimelineOverlays.test.ts +161 -0
- package/src/player/components/TimelineOverlays.tsx +104 -11
- package/src/player/components/timelineCallbacks.ts +1 -1
- package/src/player/components/timelineClipDragGestureLifecycle.test.ts +18 -3
- package/src/player/components/timelineClipDragGestureLifecycle.ts +199 -51
- package/src/player/components/timelineClipDragPreview.test.ts +33 -0
- package/src/player/components/timelineClipDragPreview.ts +18 -12
- package/src/player/components/timelineClipDragTypes.ts +12 -0
- package/src/player/components/timelineDiamondTypes.ts +5 -15
- package/src/player/components/timelineDragDrop.test.tsx +206 -0
- package/src/player/components/timelineDragDrop.ts +152 -30
- package/src/player/components/timelineLaneProps.ts +0 -1
- package/src/player/components/timelineMarquee.test.ts +73 -25
- package/src/player/components/timelineMarquee.ts +44 -16
- package/src/player/components/timelineTestViewport.ts +13 -0
- package/src/player/components/timelineViewModel.ts +4 -4
- package/src/player/components/useTimelineClipDrag.resize.test.tsx +219 -17
- package/src/player/components/useTimelineClipDrag.ts +112 -70
- package/src/player/components/useTimelineClipRenderWindow.ts +4 -4
- package/src/player/components/useTimelineKeyframeHandlers.test.tsx +43 -7
- package/src/player/components/useTimelineKeyframeHandlers.ts +465 -2
- package/src/player/components/useTimelineLaneMoveRefresh.ts +7 -0
- package/src/player/components/useTimelineRangeSelection.test.tsx +204 -0
- package/src/player/components/useTimelineRangeSelection.ts +202 -69
- package/src/player/components/useTimelineRangeSelectionScrub.test.tsx +3 -2
- package/src/player/components/useTimelineRowVirtualization.ts +11 -4
- package/src/player/components/useTrackGapMenu.test.tsx +64 -0
- package/src/player/components/useTrackGapMenu.ts +32 -9
- package/src/player/store/keyframeSlice.ts +59 -18
- package/src/player/store/playerStore.test.ts +76 -0
- package/src/player/store/playerStore.ts +19 -11
- package/src/telemetry/canary.test.ts +325 -0
- package/src/telemetry/canary.ts +268 -0
- package/src/telemetry/client.test.ts +8 -3
- package/src/telemetry/client.ts +13 -43
- package/src/telemetry/config.ts +16 -2
- package/src/telemetry/distinctId.test.ts +35 -0
- package/src/telemetry/distinctId.ts +11 -2
- package/src/telemetry/policy.test.ts +81 -0
- package/src/telemetry/policy.ts +104 -0
- package/src/utils/studioTelemetry.test.ts +76 -0
- package/src/utils/studioTelemetry.ts +14 -6
- package/dist/assets/index-Cql15Yur.js +0 -428
|
@@ -12,7 +12,7 @@ import { TimelineEmptyState } from "./TimelineEmptyState";
|
|
|
12
12
|
import { TimelineCanvas } from "./TimelineCanvas";
|
|
13
13
|
import { type KeyframeDiamondContextMenuState } from "./KeyframeDiamondContextMenu";
|
|
14
14
|
import { useTimelineClipDrag } from "./useTimelineClipDrag";
|
|
15
|
-
import { TimelineOverlays } from "./TimelineOverlays";
|
|
15
|
+
import { TimelineOverlays, type ClipContextMenuState } from "./TimelineOverlays";
|
|
16
16
|
import { useTimelineEditPinning } from "./useTimelineEditPinning";
|
|
17
17
|
import { useTimelineStackingSync } from "./useTimelineStackingSync";
|
|
18
18
|
import { useTimelineGeometry } from "./useTimelineGeometry";
|
|
@@ -29,7 +29,6 @@ import {
|
|
|
29
29
|
import { useTimelineKeyframeHandlers } from "./useTimelineKeyframeHandlers";
|
|
30
30
|
import { useTrackGapMenu } from "./useTrackGapMenu";
|
|
31
31
|
import { useTimelineGapHighlights } from "./useTimelineGapHighlights";
|
|
32
|
-
import { useStudioPlaybackContextOptional } from "../../contexts/StudioContext";
|
|
33
32
|
import { TimelineRazorGuide, useTimelineRazorInteraction } from "./TimelineRazorInteraction";
|
|
34
33
|
import { useTimelinePerformanceTelemetry } from "./useTimelinePerformanceTelemetry";
|
|
35
34
|
import {
|
|
@@ -45,6 +44,7 @@ import { getTimelineElementIdentity } from "../lib/timelineElementHelpers";
|
|
|
45
44
|
import { useTimelineRowVirtualization } from "./useTimelineRowVirtualization";
|
|
46
45
|
import { useTimelineClipRenderWindow } from "./useTimelineClipRenderWindow";
|
|
47
46
|
import { useTimelineActiveClips } from "./useTimelineActiveClips";
|
|
47
|
+
import { useTimelineLaneMoveRefresh } from "./useTimelineLaneMoveRefresh";
|
|
48
48
|
|
|
49
49
|
export {
|
|
50
50
|
shouldAutoScrollTimeline,
|
|
@@ -106,11 +106,7 @@ export const Timeline = memo(function Timeline({
|
|
|
106
106
|
onSplitElement: onSplitElementOverride,
|
|
107
107
|
});
|
|
108
108
|
const theme = useMemo(() => ({ ...defaultTimelineTheme, ...themeOverrides }), [themeOverrides]);
|
|
109
|
-
const
|
|
110
|
-
const setRefreshKey = playbackContext?.setRefreshKey;
|
|
111
|
-
const refreshAfterLaneMove = useCallback(() => {
|
|
112
|
-
setRefreshKey?.((key) => key + 1);
|
|
113
|
-
}, [setRefreshKey]);
|
|
109
|
+
const refreshAfterLaneMove = useTimelineLaneMoveRefresh();
|
|
114
110
|
useMusicBeatAnalysis();
|
|
115
111
|
const rawElements = usePlayerStore((s) => s.elements);
|
|
116
112
|
const expandedElements = useExpandedTimelineElements();
|
|
@@ -129,14 +125,8 @@ export const Timeline = memo(function Timeline({
|
|
|
129
125
|
const clipRevealRequest = usePlayerStore((s) => s.clipRevealRequest);
|
|
130
126
|
const focusedEaseSegment = usePlayerStore((s) => s.focusedEaseSegment);
|
|
131
127
|
const gsapAnimations = usePlayerStore((s) => s.gsapAnimations);
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
[gsapAnimations],
|
|
135
|
-
);
|
|
136
|
-
const labelMode = hasKeyframedClips;
|
|
137
|
-
// Without the label column the pre-t=0 breathing room is still TRACKS_LEFT_PAD
|
|
138
|
-
// (dropping it would jam clip 0 against the gutter on every non-keyframed
|
|
139
|
-
// composition); in label mode the 232px label column already provides it.
|
|
128
|
+
const labelMode = useMemo(() => hasKeyframedTimelineClips(gsapAnimations), [gsapAnimations]);
|
|
129
|
+
// The label column provides pre-t=0 space; otherwise keep TRACKS_LEFT_PAD after the gutter.
|
|
140
130
|
const contentOrigin = labelMode ? LABEL_COL_W + GUTTER : GUTTER + TRACKS_LEFT_PAD;
|
|
141
131
|
const contentGutter = labelMode ? GUTTER : 0;
|
|
142
132
|
const setSelectedElementId = usePlayerStore((s) => s.setSelectedElementId);
|
|
@@ -151,11 +141,7 @@ export const Timeline = memo(function Timeline({
|
|
|
151
141
|
const shiftHeld = useTimelineShiftModifier();
|
|
152
142
|
const [showPopover, setShowPopover] = useState(false);
|
|
153
143
|
const [kfContextMenu, setKfContextMenu] = useState<KeyframeDiamondContextMenuState | null>(null);
|
|
154
|
-
const [clipContextMenu, setClipContextMenu] = useState<
|
|
155
|
-
x: number;
|
|
156
|
-
y: number;
|
|
157
|
-
element: TimelineElement;
|
|
158
|
-
} | null>(null);
|
|
144
|
+
const [clipContextMenu, setClipContextMenu] = useState<ClipContextMenuState | null>(null);
|
|
159
145
|
const setContainerRef = useCallback((el: HTMLDivElement | null) => {
|
|
160
146
|
containerRef.current = el;
|
|
161
147
|
}, []);
|
|
@@ -236,7 +222,6 @@ export const Timeline = memo(function Timeline({
|
|
|
236
222
|
setResizingClip,
|
|
237
223
|
blockedClipRef,
|
|
238
224
|
suppressClickRef,
|
|
239
|
-
syncClipDragAutoScroll,
|
|
240
225
|
} = useTimelineClipDrag({
|
|
241
226
|
scrollRef,
|
|
242
227
|
ppsRef,
|
|
@@ -253,22 +238,26 @@ export const Timeline = memo(function Timeline({
|
|
|
253
238
|
readZIndex: zSyncEnabled ? readClipZIndex : undefined,
|
|
254
239
|
onStackingPatches: zSyncEnabled ? applyStackingPatches : undefined,
|
|
255
240
|
refreshAfterLaneMove,
|
|
241
|
+
sessionEpoch,
|
|
256
242
|
});
|
|
257
243
|
|
|
258
|
-
const
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
244
|
+
const assetDrop = useTimelineAssetDrop({
|
|
245
|
+
scrollRef,
|
|
246
|
+
ppsRef,
|
|
247
|
+
durationRef,
|
|
248
|
+
trackOrderRef,
|
|
249
|
+
rowGeometryRef,
|
|
250
|
+
contentOrigin,
|
|
251
|
+
onFileDrop: pinnedOnFileDrop,
|
|
252
|
+
onAssetDrop: pinnedOnAssetDrop,
|
|
253
|
+
onBlockDrop: pinnedOnBlockDrop,
|
|
254
|
+
onCompositionDrop: pinnedOnCompositionDrop,
|
|
255
|
+
sessionEpoch,
|
|
256
|
+
});
|
|
271
257
|
const displayLayout = useTimelineDisplayLayout(draggedClip, trackOrder, rowGeometry);
|
|
258
|
+
const resizingElementIds =
|
|
259
|
+
resizingClip?.groupPreview?.map((change) => change.key) ??
|
|
260
|
+
(resizingClip ? [getTimelineElementIdentity(resizingClip.element)] : undefined);
|
|
272
261
|
const { recordTimelineScroll } = useTimelinePerformanceTelemetry({
|
|
273
262
|
totalClipCount: expandedElements.length,
|
|
274
263
|
totalRowCount: displayLayout.displayTrackOrder.length,
|
|
@@ -289,7 +278,7 @@ export const Timeline = memo(function Timeline({
|
|
|
289
278
|
selectedElementId,
|
|
290
279
|
revealElementId: clipRevealRequest?.elementId ?? null,
|
|
291
280
|
draggedRowKey: draggedClip?.started ? draggedClip.previewTrack : undefined,
|
|
292
|
-
|
|
281
|
+
resizingElementIds,
|
|
293
282
|
clipContextMenuRowKey: clipContextMenu?.element.track,
|
|
294
283
|
keyframeContextMenuRowKey: kfContextMenu?.element.track,
|
|
295
284
|
lastScrollLeftRef,
|
|
@@ -332,7 +321,7 @@ export const Timeline = memo(function Timeline({
|
|
|
332
321
|
duration: displayDuration,
|
|
333
322
|
selectedElementId: selectedElementId ?? undefined,
|
|
334
323
|
draggedElementId: draggedClip ? getTimelineElementIdentity(draggedClip.element) : undefined,
|
|
335
|
-
|
|
324
|
+
resizingElementIds,
|
|
336
325
|
revealElementId: clipRevealRequest?.elementId,
|
|
337
326
|
focusedEaseElementId: focusedEaseSegment?.elementId,
|
|
338
327
|
clipContextMenuElementId: clipContextMenu
|
|
@@ -405,6 +394,7 @@ export const Timeline = memo(function Timeline({
|
|
|
405
394
|
handlePointerDown,
|
|
406
395
|
handlePointerMove,
|
|
407
396
|
handlePointerUp,
|
|
397
|
+
handlePointerCancel,
|
|
408
398
|
} = useTimelineRangeSelection({
|
|
409
399
|
scrollRef,
|
|
410
400
|
ppsRef,
|
|
@@ -417,10 +407,11 @@ export const Timeline = memo(function Timeline({
|
|
|
417
407
|
isDragging,
|
|
418
408
|
setShowPopover,
|
|
419
409
|
elementsRef: expandedElementsRef,
|
|
420
|
-
|
|
410
|
+
clipIndex,
|
|
421
411
|
rowGeometryRef,
|
|
422
412
|
onSelectElement,
|
|
423
413
|
contentOrigin,
|
|
414
|
+
sessionEpoch,
|
|
424
415
|
});
|
|
425
416
|
setRangeSelectionRef.current = setRangeSelection; // stable ref consumed by useTimelineClipDrag
|
|
426
417
|
|
|
@@ -443,11 +434,11 @@ export const Timeline = memo(function Timeline({
|
|
|
443
434
|
if (!timelineReady || expandedElements.length === 0) {
|
|
444
435
|
return (
|
|
445
436
|
<TimelineEmptyState
|
|
446
|
-
isDragOver={isDragOver}
|
|
437
|
+
isDragOver={assetDrop.isDragOver}
|
|
447
438
|
onFileDrop={!!onFileDrop}
|
|
448
|
-
onDragOver={handleAssetDragOver}
|
|
449
|
-
onDragLeave={
|
|
450
|
-
onDrop={handleAssetDrop}
|
|
439
|
+
onDragOver={assetDrop.handleAssetDragOver}
|
|
440
|
+
onDragLeave={assetDrop.handleAssetDragLeave}
|
|
441
|
+
onDrop={assetDrop.handleAssetDrop}
|
|
451
442
|
/>
|
|
452
443
|
);
|
|
453
444
|
}
|
|
@@ -457,7 +448,7 @@ export const Timeline = memo(function Timeline({
|
|
|
457
448
|
ref={setContainerRef}
|
|
458
449
|
aria-label="Timeline"
|
|
459
450
|
data-timeline-element-count={expandedElements.length}
|
|
460
|
-
className={`relative border-t select-none h-full overflow-hidden ${isDragOver ? "ring-1 ring-inset ring-studio-accent/60" : ""} ${activeTool === "razor" ? "cursor-crosshair" : shiftHeld ? "cursor-crosshair" : "cursor-default"}`}
|
|
451
|
+
className={`relative border-t select-none h-full overflow-hidden ${assetDrop.isDragOver ? "ring-1 ring-inset ring-studio-accent/60" : ""} ${activeTool === "razor" ? "cursor-crosshair" : shiftHeld ? "cursor-crosshair" : "cursor-default"}`}
|
|
461
452
|
onMouseMove={updateRazorGuide}
|
|
462
453
|
onMouseLeave={clearRazorGuide}
|
|
463
454
|
style={{
|
|
@@ -468,6 +459,7 @@ export const Timeline = memo(function Timeline({
|
|
|
468
459
|
>
|
|
469
460
|
<div
|
|
470
461
|
ref={setScrollRef}
|
|
462
|
+
// Stable owner for gestures that must survive virtual row/clip unmounts.
|
|
471
463
|
data-timeline-scroll-viewport
|
|
472
464
|
data-timeline-auto-scroll-left-inset={labelMode ? LABEL_COL_W : 0}
|
|
473
465
|
tabIndex={-1}
|
|
@@ -478,9 +470,9 @@ export const Timeline = memo(function Timeline({
|
|
|
478
470
|
syncScrollViewport(e.currentTarget, true);
|
|
479
471
|
}}
|
|
480
472
|
{...rowWindow.timelineFocusProps}
|
|
481
|
-
onDragOver={handleAssetDragOver}
|
|
482
|
-
onDragLeave={
|
|
483
|
-
onDrop={handleAssetDrop}
|
|
473
|
+
onDragOver={assetDrop.handleAssetDragOver}
|
|
474
|
+
onDragLeave={assetDrop.handleAssetDragLeave}
|
|
475
|
+
onDrop={assetDrop.handleAssetDrop}
|
|
484
476
|
onPointerDown={(e) => {
|
|
485
477
|
// Let interactive controls (keyframe nav/toggle, caret, inputs) handle
|
|
486
478
|
// their own clicks — scrubbing here would preventDefault and eat them.
|
|
@@ -490,7 +482,8 @@ export const Timeline = memo(function Timeline({
|
|
|
490
482
|
}}
|
|
491
483
|
onPointerMove={handlePointerMove}
|
|
492
484
|
onPointerUp={handlePointerUp}
|
|
493
|
-
|
|
485
|
+
onPointerCancel={handlePointerCancel}
|
|
486
|
+
onLostPointerCapture={handlePointerCancel}
|
|
494
487
|
>
|
|
495
488
|
<TimelineCanvas
|
|
496
489
|
major={major}
|
|
@@ -541,7 +534,6 @@ export const Timeline = memo(function Timeline({
|
|
|
541
534
|
setResizingClip={setResizingClip}
|
|
542
535
|
setDraggedClip={setDraggedClip}
|
|
543
536
|
setSelectedElementId={setSelectedElementId}
|
|
544
|
-
syncClipDragAutoScroll={syncClipDragAutoScroll}
|
|
545
537
|
shiftClickClipRef={shiftClickClipRef}
|
|
546
538
|
getPreviewElement={getPreviewElement}
|
|
547
539
|
getTrackStyle={getTrackStyle}
|
|
@@ -561,7 +553,12 @@ export const Timeline = memo(function Timeline({
|
|
|
561
553
|
setSelectedElementId(el.key ?? el.id);
|
|
562
554
|
onSelectElement?.(el);
|
|
563
555
|
dismissGapMenu();
|
|
564
|
-
setClipContextMenu({
|
|
556
|
+
setClipContextMenu({
|
|
557
|
+
x: e.clientX,
|
|
558
|
+
y: e.clientY,
|
|
559
|
+
element: el,
|
|
560
|
+
sessionEpoch: usePlayerStore.getState().timelineSessionEpoch,
|
|
561
|
+
});
|
|
565
562
|
}}
|
|
566
563
|
onContextMenuLane={(e, track, time) => {
|
|
567
564
|
if (draggedClip?.started || resizingClip) return;
|
|
@@ -572,6 +569,8 @@ export const Timeline = memo(function Timeline({
|
|
|
572
569
|
{activeTool === "razor" && razorGuideX !== null && <TimelineRazorGuide x={razorGuideX} />}
|
|
573
570
|
</div>
|
|
574
571
|
<TimelineOverlays
|
|
572
|
+
elements={expandedElements}
|
|
573
|
+
elementsRef={expandedElementsRef}
|
|
575
574
|
theme={theme}
|
|
576
575
|
showShortcutHint={showShortcutHint}
|
|
577
576
|
showPopover={showPopover}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { memo } from "react";
|
|
2
2
|
import { TimelineRuler } from "./TimelineRuler";
|
|
3
3
|
import { PlayheadIndicator } from "./PlayheadIndicator";
|
|
4
|
-
import {
|
|
5
|
-
import { getRenderedTimelineElement } from "./timelineTheme";
|
|
4
|
+
import type { TimelineRangeSelection } from "./timelineEditing";
|
|
6
5
|
import {
|
|
7
6
|
RULER_H,
|
|
8
7
|
CLIP_Y,
|
|
@@ -19,13 +18,11 @@ import type { ResizingClipState } from "./useTimelineClipDrag";
|
|
|
19
18
|
import { type MultiDragPreviewInput } from "./timelineMultiDragPreview";
|
|
20
19
|
import { useTimelineEditContextOptional } from "../../contexts/TimelineEditContext";
|
|
21
20
|
import type { Rect } from "../../utils/marqueeGeometry";
|
|
22
|
-
import { TimelineClip } from "./TimelineClip";
|
|
23
21
|
import { TimelineLanes } from "./TimelineLanes";
|
|
24
22
|
import type { TimelineLaneBaseProps } from "./timelineLaneProps";
|
|
25
|
-
import { renderClipChildren } from "./timelineClipChildren";
|
|
26
23
|
import type { TimelineLaneGapStrips } from "./useTimelineGapHighlights";
|
|
27
|
-
import { isTimelineClipActive } from "./useTimelineActiveClips";
|
|
28
24
|
import { getTimelineElementIdentity } from "../lib/timelineElementHelpers";
|
|
25
|
+
import { TimelineGestureOverlay } from "./TimelineGestureOverlay";
|
|
29
26
|
|
|
30
27
|
interface TimelineCanvasProps extends TimelineLaneBaseProps {
|
|
31
28
|
major: number[];
|
|
@@ -65,15 +62,6 @@ export const TimelineCanvas = memo(function TimelineCanvas(props: TimelineCanvas
|
|
|
65
62
|
const beatDragging = usePlayerStore((s) => s.beatDragging);
|
|
66
63
|
const draggedElement = draggedClip?.element ?? null;
|
|
67
64
|
const draggedElementIdentity = draggedElement ? getTimelineElementIdentity(draggedElement) : null;
|
|
68
|
-
const activeDraggedElement =
|
|
69
|
-
draggedClip?.started === true && draggedElement && draggedElementIdentity
|
|
70
|
-
? getRenderedTimelineElement({
|
|
71
|
-
element: draggedElement,
|
|
72
|
-
draggedElementId: draggedElementIdentity,
|
|
73
|
-
previewStart: draggedClip.previewStart,
|
|
74
|
-
previewTrack: draggedClip.previewTrack,
|
|
75
|
-
})
|
|
76
|
-
: null;
|
|
77
65
|
// The drag ghost follows the cursor freely (both axes) — CapCut-style. The
|
|
78
66
|
// "magnetic" affordance is a highlight on the destination lane (draggedRowIndex),
|
|
79
67
|
// which flips at the MAGNETIC_TRACK_THRESHOLD point; the clip drops into it.
|
|
@@ -94,22 +82,6 @@ export const TimelineCanvas = memo(function TimelineCanvas(props: TimelineCanvas
|
|
|
94
82
|
selectedKeys: selectedElementIds,
|
|
95
83
|
}
|
|
96
84
|
: null;
|
|
97
|
-
const activeDraggedPosition =
|
|
98
|
-
draggedClip?.started === true && activeDraggedElement && scrollRef.current
|
|
99
|
-
? {
|
|
100
|
-
left:
|
|
101
|
-
draggedClip.pointerClientX -
|
|
102
|
-
scrollRef.current.getBoundingClientRect().left +
|
|
103
|
-
scrollRef.current.scrollLeft -
|
|
104
|
-
draggedClip.pointerOffsetX,
|
|
105
|
-
top:
|
|
106
|
-
draggedClip.pointerClientY -
|
|
107
|
-
scrollRef.current.getBoundingClientRect().top +
|
|
108
|
-
scrollRef.current.scrollTop -
|
|
109
|
-
draggedClip.pointerOffsetY,
|
|
110
|
-
}
|
|
111
|
-
: null;
|
|
112
|
-
|
|
113
85
|
return (
|
|
114
86
|
<div
|
|
115
87
|
className="relative"
|
|
@@ -235,47 +207,18 @@ export const TimelineCanvas = memo(function TimelineCanvas(props: TimelineCanvas
|
|
|
235
207
|
/>
|
|
236
208
|
)}
|
|
237
209
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
<TimelineClip
|
|
251
|
-
el={{ ...activeDraggedElement, start: 0 }}
|
|
252
|
-
pps={props.pps}
|
|
253
|
-
clipY={0}
|
|
254
|
-
isSelected={
|
|
255
|
-
props.selectedElementId === (activeDraggedElement.key ?? activeDraggedElement.id)
|
|
256
|
-
}
|
|
257
|
-
isHovered={false}
|
|
258
|
-
isDragging={true}
|
|
259
|
-
isActive={isTimelineClipActive(activeDraggedElement, props.currentTime)}
|
|
260
|
-
hasCustomContent={!!props.renderClipContent}
|
|
261
|
-
capabilities={getTimelineEditCapabilities(activeDraggedElement)}
|
|
262
|
-
theme={props.theme}
|
|
263
|
-
isComposition={!!activeDraggedElement.compositionSrc}
|
|
264
|
-
onHoverStart={() => {}}
|
|
265
|
-
onHoverEnd={() => {}}
|
|
266
|
-
onResizeStart={() => {}}
|
|
267
|
-
onClick={() => {}}
|
|
268
|
-
onDoubleClick={() => {}}
|
|
269
|
-
>
|
|
270
|
-
{renderClipChildren(
|
|
271
|
-
activeDraggedElement,
|
|
272
|
-
props.getTrackStyle(activeDraggedElement.tag),
|
|
273
|
-
props.renderClipContent,
|
|
274
|
-
props.renderClipOverlay,
|
|
275
|
-
)}
|
|
276
|
-
</TimelineClip>
|
|
277
|
-
</div>
|
|
278
|
-
)}
|
|
210
|
+
<TimelineGestureOverlay
|
|
211
|
+
drag={draggedClip}
|
|
212
|
+
scrollRef={scrollRef}
|
|
213
|
+
pixelsPerSecond={props.pps}
|
|
214
|
+
rowHeight={draggedClipHeight}
|
|
215
|
+
selectedElementId={props.selectedElementId}
|
|
216
|
+
currentTime={props.currentTime}
|
|
217
|
+
theme={props.theme}
|
|
218
|
+
getTrackStyle={props.getTrackStyle}
|
|
219
|
+
renderClipContent={props.renderClipContent}
|
|
220
|
+
renderClipOverlay={props.renderClipOverlay}
|
|
221
|
+
/>
|
|
279
222
|
|
|
280
223
|
{/* Marquee (rubber-band) multi-select rectangle — mirrors the canvas
|
|
281
224
|
MarqueeOverlay look: semi-transparent accent fill + dashed border. */}
|
|
@@ -12,6 +12,7 @@ interface TimelineClipProps {
|
|
|
12
12
|
isSelected: boolean;
|
|
13
13
|
isHovered: boolean;
|
|
14
14
|
isDragging?: boolean;
|
|
15
|
+
isGestureActor?: boolean;
|
|
15
16
|
isActive?: boolean;
|
|
16
17
|
hasCustomContent: boolean;
|
|
17
18
|
capabilities: TimelineEditCapabilities;
|
|
@@ -36,6 +37,7 @@ export const TimelineClip = memo(function TimelineClip({
|
|
|
36
37
|
isSelected,
|
|
37
38
|
isHovered,
|
|
38
39
|
isDragging = false,
|
|
40
|
+
isGestureActor = false,
|
|
39
41
|
isActive = false,
|
|
40
42
|
hasCustomContent,
|
|
41
43
|
capabilities,
|
|
@@ -85,13 +87,14 @@ export const TimelineClip = memo(function TimelineClip({
|
|
|
85
87
|
|
|
86
88
|
return (
|
|
87
89
|
<div
|
|
88
|
-
data-clip="true"
|
|
89
|
-
data-el-id={el.key ?? el.id}
|
|
90
|
+
data-clip={isGestureActor ? undefined : "true"}
|
|
91
|
+
data-el-id={isGestureActor ? undefined : (el.key ?? el.id)}
|
|
90
92
|
data-clip-start={el.start}
|
|
91
93
|
data-clip-end={el.start + el.duration}
|
|
92
94
|
data-clip-hidden={el.hidden ? "true" : undefined}
|
|
93
95
|
data-active={isActive ? "" : undefined}
|
|
94
|
-
|
|
96
|
+
aria-hidden={isGestureActor ? "true" : undefined}
|
|
97
|
+
tabIndex={isGestureActor ? undefined : -1}
|
|
95
98
|
className={clipClassName}
|
|
96
99
|
style={style}
|
|
97
100
|
title={
|