@linker-design-plus/timeline-track 2.1.3 → 2.1.4
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/components/track/Track.d.ts +3 -1
- package/dist/core/controllers/timelinePlaybackViewportFollow.d.ts +16 -0
- package/dist/core/controllers/timelineStructureSession.d.ts +1 -0
- package/dist/core/facade/timelineManager.d.ts +19 -0
- package/dist/core/history/history.d.ts +2 -1
- package/dist/core/history/timelineHistoryExecutor.d.ts +1 -0
- package/dist/core/history/timelineHistoryRecorder.d.ts +1 -0
- package/dist/core/models/types.d.ts +12 -1
- package/dist/core/tracks/timelineTrackBridge.d.ts +2 -1
- package/dist/index.cjs.js +6 -6
- package/dist/index.es.js +1181 -880
- package/package.json +1 -1
|
@@ -35,6 +35,7 @@ export declare class Track {
|
|
|
35
35
|
private onClipSelect;
|
|
36
36
|
private onTimeJump;
|
|
37
37
|
private onClipOverlap?;
|
|
38
|
+
private onPrimaryTrackMagnetMove?;
|
|
38
39
|
private hasBoundGlobalPointerListenersForDrag;
|
|
39
40
|
private hasLockedGlobalCursor;
|
|
40
41
|
private edgeAutoScrollAnimationFrameId;
|
|
@@ -56,7 +57,7 @@ export declare class Track {
|
|
|
56
57
|
private handleGlobalPointerMove;
|
|
57
58
|
private handleGlobalPointerEnd;
|
|
58
59
|
private handleWindowBlur;
|
|
59
|
-
constructor(layer: Konva.Layer, config: TrackConfig, trackType: TrackType, zoom: number, trackY: number, trackHeight: number, theme: Theme, onClipUpdate: (clip: ClipType, originalClip?: ClipType, clipUpdates?: ClipStateUpdate[]) => void, onClipAdd: (clip: ClipType) => void, onClipRemove: (clipId: string) => void, onClipSplit: (clip1: ClipType, clip2: ClipType) => void, onClipSelect: (clip: ClipType) => void, onTimeJump: (time: TimeMs) => void, onHorizontalDragAutoScroll?: (nextScrollLeft: number) => number, onClipOverlap?: (clip: ClipType, currentTrackId: string, originalClip?: ClipType | null) => void, onClipCrossTrackPreview?: (clip: ClipType, targetTrackY: number, currentTrackId: string) => 'self' | 'external' | 'clear', onClipCrossTrack?: (clip: ClipType, originalClip: ClipType | null, targetTrackY: number, currentTrackId: string) => boolean | void, onClearDropPreview?: () => void, onClearSelection?: () => void, onSnapGuideChange?: (guideTime: TimeMs | null) => void, onClipToggleSelection?: (clipId: string) => void, onSetSingleSelection?: (clipId: string) => void, getMultiDragClipIds?: (clipId: string) => string[] | null, onMultiDragMove?: (request: MultiDragMoveRequest) => boolean | void, onMultiDragInteractionEnd?: () => void, dragActivationThreshold?: number, enableClipSnap?: boolean, clipSnapThreshold?: number);
|
|
60
|
+
constructor(layer: Konva.Layer, config: TrackConfig, trackType: TrackType, zoom: number, trackY: number, trackHeight: number, theme: Theme, onClipUpdate: (clip: ClipType, originalClip?: ClipType, clipUpdates?: ClipStateUpdate[]) => void, onClipAdd: (clip: ClipType) => void, onClipRemove: (clipId: string) => void, onClipSplit: (clip1: ClipType, clip2: ClipType) => void, onClipSelect: (clip: ClipType) => void, onTimeJump: (time: TimeMs) => void, onHorizontalDragAutoScroll?: (nextScrollLeft: number) => number, onClipOverlap?: (clip: ClipType, currentTrackId: string, originalClip?: ClipType | null) => void, onPrimaryTrackMagnetMove?: (clip: ClipType, originalClip: ClipType | null, peerClips: ClipType[], currentTrackId: string) => boolean | void, onClipCrossTrackPreview?: (clip: ClipType, targetTrackY: number, currentTrackId: string) => 'self' | 'external' | 'clear', onClipCrossTrack?: (clip: ClipType, originalClip: ClipType | null, targetTrackY: number, currentTrackId: string) => boolean | void, onClearDropPreview?: () => void, onClearSelection?: () => void, onSnapGuideChange?: (guideTime: TimeMs | null) => void, onClipToggleSelection?: (clipId: string) => void, onSetSingleSelection?: (clipId: string) => void, getMultiDragClipIds?: (clipId: string) => string[] | null, onMultiDragMove?: (request: MultiDragMoveRequest) => boolean | void, onMultiDragInteractionEnd?: () => void, dragActivationThreshold?: number, enableClipSnap?: boolean, clipSnapThreshold?: number);
|
|
60
61
|
private initClips;
|
|
61
62
|
private ensureDropPreviewGroup;
|
|
62
63
|
private createDropPreviewRect;
|
|
@@ -83,6 +84,7 @@ export declare class Track {
|
|
|
83
84
|
private resolveDraggedClipForInteraction;
|
|
84
85
|
private applyInteractionTransition;
|
|
85
86
|
private handleClipMoveEnd;
|
|
87
|
+
private compactPrimaryTrackClips;
|
|
86
88
|
private updateAllClips;
|
|
87
89
|
private buildAndSendUpdates;
|
|
88
90
|
private updateHoverCursor;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { TimeMs } from '../models/types';
|
|
2
|
+
export declare const PLAYBACK_VIEWPORT_FOLLOW_MARGIN_PX = 48;
|
|
3
|
+
export declare function getPlayheadScreenX(time: TimeMs, zoom: number, scrollLeft: number): number;
|
|
4
|
+
export interface PlaybackViewportFollowInput {
|
|
5
|
+
time: TimeMs;
|
|
6
|
+
zoom: number;
|
|
7
|
+
scrollLeft: number;
|
|
8
|
+
viewportWidth: number;
|
|
9
|
+
contentWidth: number;
|
|
10
|
+
margin?: number;
|
|
11
|
+
}
|
|
12
|
+
export declare function clampScrollLeft(scrollLeft: number, viewportWidth: number, contentWidth: number): number;
|
|
13
|
+
/**
|
|
14
|
+
* 播放边距跟随:播放头超出左右安全边距时返回目标 scrollLeft,否则返回 null。
|
|
15
|
+
*/
|
|
16
|
+
export declare function resolveScrollLeftForPlaybackFollow(input: PlaybackViewportFollowInput): number | null;
|
|
@@ -20,6 +20,7 @@ interface TimelineStructureSessionOptions {
|
|
|
20
20
|
trackCollection: TimelineTrackCollection;
|
|
21
21
|
ensureTrackFromHistorySnapshot: (trackSnapshot: Track, restoreAnchor?: TrackRestoreAnchor | null) => string | null;
|
|
22
22
|
removeClipGaps: () => void;
|
|
23
|
+
setPrimaryTrackMagnetEnabled: (enabled: boolean) => void;
|
|
23
24
|
loadClipThumbnails?: (clip: Clip) => Promise<boolean> | void;
|
|
24
25
|
addClipToTrack?: (trackId: string, clip: Clip) => boolean;
|
|
25
26
|
removeClip?: (clipId: string) => void;
|
|
@@ -89,6 +89,8 @@ export declare class TimelineManager {
|
|
|
89
89
|
private activeStructureSession;
|
|
90
90
|
private structureSessionDepth;
|
|
91
91
|
private preserveEmptyTracksDepth;
|
|
92
|
+
private playbackViewportFollowSuspended;
|
|
93
|
+
private isProgrammaticScrollChange;
|
|
92
94
|
constructor(config?: Partial<TimelineConfig>);
|
|
93
95
|
private createPlaybackAttemptId;
|
|
94
96
|
private refreshPlaybackAttempt;
|
|
@@ -134,6 +136,10 @@ export declare class TimelineManager {
|
|
|
134
136
|
private get selectedClipId();
|
|
135
137
|
private set selectedClipId(value);
|
|
136
138
|
private ensureConfigState;
|
|
139
|
+
private isPlaybackViewportFollowEnabled;
|
|
140
|
+
private suspendPlaybackViewportFollowIfUserScrolling;
|
|
141
|
+
private runProgrammaticScrollChange;
|
|
142
|
+
private followPlaybackViewportIfNeeded;
|
|
137
143
|
private getCurrentTimeState;
|
|
138
144
|
private getPlayStateState;
|
|
139
145
|
private setPlayStateState;
|
|
@@ -247,6 +253,17 @@ export declare class TimelineManager {
|
|
|
247
253
|
getCurrentTime(): TimeMs;
|
|
248
254
|
setEnableClipSnap(enabled: boolean): void;
|
|
249
255
|
getEnableClipSnap(): boolean;
|
|
256
|
+
setEnablePrimaryTrackMagnet(enabled: boolean): void;
|
|
257
|
+
getEnablePrimaryTrackMagnet(): boolean;
|
|
258
|
+
private setPrimaryTrackMagnetEnabledFromHistory;
|
|
259
|
+
private setPrimaryTrackMagnetEnabledState;
|
|
260
|
+
private getPrimaryTrackId;
|
|
261
|
+
private isPrimaryTrackId;
|
|
262
|
+
private shouldNormalizePrimaryTrackForTrackIds;
|
|
263
|
+
private getStableStartOrderedClips;
|
|
264
|
+
private buildPrimaryTrackContinuousClips;
|
|
265
|
+
private buildPrimaryTrackMultiDragOrderedClips;
|
|
266
|
+
private normalizePrimaryTrackInSession;
|
|
250
267
|
setZoom(zoom: number): void;
|
|
251
268
|
/**
|
|
252
269
|
* 以游标(playhead)为中心设置缩放,用于外置 slider 等非幕布上的缩放操作
|
|
@@ -415,6 +432,7 @@ export declare class TimelineManager {
|
|
|
415
432
|
private emitSelectedClipChangeIfNeeded;
|
|
416
433
|
private beginSourceLoading;
|
|
417
434
|
private endSourceLoading;
|
|
435
|
+
private handlePrimaryTrackMagnetMove;
|
|
418
436
|
private handleClipOverlap;
|
|
419
437
|
private handleClipCrossTrackPreview;
|
|
420
438
|
private handleClipCrossTrack;
|
|
@@ -586,6 +604,7 @@ export declare class TimelineManager {
|
|
|
586
604
|
private resolveMultiDragOverlapTargetTrackId;
|
|
587
605
|
private commitMultiDragPlacements;
|
|
588
606
|
private finalizeMultiDragSameTrack;
|
|
607
|
+
private compactPrimaryTrackAfterMultiDrag;
|
|
589
608
|
private previewMultiDragCrossTrack;
|
|
590
609
|
private finalizeMultiDragCrossTrack;
|
|
591
610
|
private resolveTrackIndexDelta;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Action, Clip, ClipStateUpdate, CompoundAction, HistoryState, MoveClipBetweenTracksAction, MoveClipAction, MultiClipUpdateAction, RemoveClipAction, RemoveGapsAction, RestoreClipAudioAction, ResizeClipAction, SeparateClipAudioAction, SetTimeAction, SplitClipAction, Track, TrackRestoreAnchor, TrackHistoryReference, UpdateClipAction, AddClipAction } from '../models/types';
|
|
1
|
+
import { Action, Clip, ClipStateUpdate, CompoundAction, HistoryState, MoveClipBetweenTracksAction, MoveClipAction, MultiClipUpdateAction, RemoveClipAction, RemoveGapsAction, RestoreClipAudioAction, ResizeClipAction, SeparateClipAudioAction, SetPrimaryTrackMagnetAction, SetTimeAction, SplitClipAction, Track, TrackRestoreAnchor, TrackHistoryReference, UpdateClipAction, AddClipAction } from '../models/types';
|
|
2
2
|
export declare class HistoryManager {
|
|
3
3
|
private state;
|
|
4
4
|
private maxHistorySize;
|
|
@@ -77,5 +77,6 @@ export declare class HistoryManager {
|
|
|
77
77
|
createMoveClipBetweenTracksAction(clipId: string, sourceTrackId: string, targetTrackId: string, clipBefore: Clip, clipAfter: Clip, sourceTrackSnapshot: Track | null, targetTrackSnapshot: Track | null, sourceTrackRestoreAnchor?: TrackRestoreAnchor | null, targetTrackRestoreAnchor?: TrackRestoreAnchor | null): MoveClipBetweenTracksAction;
|
|
78
78
|
createSeparateClipAudioAction(videoClipBefore: Clip, videoClipAfter: Clip, audioClip: Clip | null, audioTrackId: string | null): SeparateClipAudioAction;
|
|
79
79
|
createRestoreClipAudioAction(videoClipBefore: Clip, videoClipAfter: Clip, audioClip: Clip | null, audioTrackId: string | null): RestoreClipAudioAction;
|
|
80
|
+
createSetPrimaryTrackMagnetAction(previousEnabled: boolean, nextEnabled: boolean): SetPrimaryTrackMagnetAction;
|
|
80
81
|
createCompoundAction(actions: Action[], label?: string): CompoundAction;
|
|
81
82
|
}
|
|
@@ -7,6 +7,7 @@ export interface TimelineHistoryExecutionTarget {
|
|
|
7
7
|
addClipToTrack(trackId: string, clip: Clip): boolean;
|
|
8
8
|
updateClip(clipId: string, updates: Partial<Clip>): void;
|
|
9
9
|
moveClipToTrack(clipId: string, targetTrackId: string): boolean;
|
|
10
|
+
setPrimaryTrackMagnetEnabled?(enabled: boolean): void;
|
|
10
11
|
ensureTrackFromHistorySnapshot(trackSnapshot: Track, restoreAnchor?: TrackRestoreAnchor | null): string | null;
|
|
11
12
|
removeClipGaps(): void;
|
|
12
13
|
getClips(): Clip[];
|
|
@@ -16,6 +16,7 @@ export declare class TimelineHistoryRecorder {
|
|
|
16
16
|
recordRestoreClipAudio(videoClipBefore: Clip, videoClipAfter: Clip, audioClip: Clip | null, audioTrackId: string | null): Action;
|
|
17
17
|
createSeparateClipAudioAction(videoClipBefore: Clip, videoClipAfter: Clip, audioClip: Clip | null, audioTrackId: string | null): Action;
|
|
18
18
|
createRestoreClipAudioAction(videoClipBefore: Clip, videoClipAfter: Clip, audioClip: Clip | null, audioTrackId: string | null): Action;
|
|
19
|
+
recordSetPrimaryTrackMagnet(previousEnabled: boolean, nextEnabled: boolean): Action;
|
|
19
20
|
recordCompoundAction(actions: Action[], label?: string): Action | null;
|
|
20
21
|
createClipUpdateAction(clip: Clip, originalClip?: Clip, clipUpdates?: ClipStateUpdate[]): Action | null;
|
|
21
22
|
withTransaction<T>(label: string | undefined, callback: () => T): T;
|
|
@@ -223,6 +223,7 @@ export interface TimelineConfig {
|
|
|
223
223
|
speed?: number;
|
|
224
224
|
dragActivationThreshold?: number;
|
|
225
225
|
enableClipSnap?: boolean;
|
|
226
|
+
enablePrimaryTrackMagnet?: boolean;
|
|
226
227
|
clipSnapThreshold?: number;
|
|
227
228
|
thumbnailProvider?: ThumbnailProvider;
|
|
228
229
|
previewBackend?: PreviewBackendType;
|
|
@@ -231,6 +232,8 @@ export interface TimelineConfig {
|
|
|
231
232
|
textPreviewFont?: TextPreviewFontConfig | null;
|
|
232
233
|
draftData?: TimelineExportData;
|
|
233
234
|
keyboardShortcuts?: false | TimelineKeyboardShortcutsConfig;
|
|
235
|
+
/** 播放时自动横向滚动以保持播放头在可视安全区内;默认开启 */
|
|
236
|
+
playbackViewportFollow?: boolean;
|
|
234
237
|
}
|
|
235
238
|
export type PreviewAspectRatioMode = 'auto-first-added-video' | 'auto-first-video' | 'manual';
|
|
236
239
|
export interface PreviewAspectRatio {
|
|
@@ -405,6 +408,14 @@ export interface RestoreClipAudioAction {
|
|
|
405
408
|
};
|
|
406
409
|
timestamp: number;
|
|
407
410
|
}
|
|
411
|
+
export interface SetPrimaryTrackMagnetAction {
|
|
412
|
+
type: 'set_primary_track_magnet';
|
|
413
|
+
data: {
|
|
414
|
+
previousEnabled: boolean;
|
|
415
|
+
nextEnabled: boolean;
|
|
416
|
+
};
|
|
417
|
+
timestamp: number;
|
|
418
|
+
}
|
|
408
419
|
export interface CompoundAction {
|
|
409
420
|
type: 'compound';
|
|
410
421
|
data: {
|
|
@@ -413,7 +424,7 @@ export interface CompoundAction {
|
|
|
413
424
|
};
|
|
414
425
|
timestamp: number;
|
|
415
426
|
}
|
|
416
|
-
export type Action = AddClipAction | RemoveClipAction | UpdateClipAction | SplitClipAction | MoveClipAction | ResizeClipAction | SetTimeAction | RemoveGapsAction | MultiClipUpdateAction | MoveClipBetweenTracksAction | SeparateClipAudioAction | RestoreClipAudioAction | CompoundAction;
|
|
427
|
+
export type Action = AddClipAction | RemoveClipAction | UpdateClipAction | SplitClipAction | MoveClipAction | ResizeClipAction | SetTimeAction | RemoveGapsAction | MultiClipUpdateAction | MoveClipBetweenTracksAction | SeparateClipAudioAction | RestoreClipAudioAction | SetPrimaryTrackMagnetAction | CompoundAction;
|
|
417
428
|
export type ActionType = Action['type'];
|
|
418
429
|
export interface Position {
|
|
419
430
|
x: number;
|
|
@@ -18,6 +18,7 @@ export interface TimelineTrackBridgeHandlers {
|
|
|
18
18
|
onTimeJump: (time: TimeMs) => void;
|
|
19
19
|
onHorizontalDragAutoScroll?: (nextScrollLeft: number) => number;
|
|
20
20
|
onClipOverlap?: (clip: Clip, currentTrackId: string, originalClip?: Clip | null) => void;
|
|
21
|
+
onPrimaryTrackMagnetMove?: (clip: Clip, originalClip: Clip | null, peerClips: Clip[], currentTrackId: string) => boolean | void;
|
|
21
22
|
onClipCrossTrackPreview?: (clip: Clip, targetTrackY: number, currentTrackId: string) => 'self' | 'external' | 'clear';
|
|
22
23
|
onClipCrossTrack?: (clip: Clip, originalClip: Clip | null, targetTrackY: number, currentTrackId: string) => boolean | void;
|
|
23
24
|
onClearDropPreview?: () => void;
|
|
@@ -41,7 +42,7 @@ export interface TimelineTrackBridgeCreateOptions {
|
|
|
41
42
|
enableClipSnap?: boolean;
|
|
42
43
|
clipSnapThreshold?: number;
|
|
43
44
|
}
|
|
44
|
-
export type TimelineTrackConstructor<TTrack = Track> = new (layer: Konva.Layer, config: TrackConfig, trackType: TrackType, zoom: number, trackY: number, trackHeight: number, theme: Theme, onClipUpdate: (clip: Clip, originalClip?: Clip, clipUpdates?: ClipStateUpdate[]) => void, onClipAdd: (clip: Clip) => void, onClipRemove: (clipId: string) => void, onClipSplit: (clip1: Clip, clip2: Clip) => void, onClipSelect: (clip: Clip) => void, onTimeJump: (time: TimeMs) => void, onHorizontalDragAutoScroll?: (nextScrollLeft: number) => number, onClipOverlap?: (clip: Clip, currentTrackId: string, originalClip?: Clip | null) => void, onClipCrossTrackPreview?: (clip: Clip, targetTrackY: number, currentTrackId: string) => 'self' | 'external' | 'clear', onClipCrossTrack?: (clip: Clip, originalClip: Clip | null, targetTrackY: number, currentTrackId: string) => boolean | void, onClearDropPreview?: () => void, onClearSelection?: () => void, onSnapGuideChange?: (guideTime: TimeMs | null) => void, onClipToggleSelection?: (clipId: string) => void, onSetSingleSelection?: (clipId: string) => void, getMultiDragClipIds?: (clipId: string) => string[] | null, onMultiDragMove?: (request: MultiDragMoveRequest) => boolean | void, onMultiDragInteractionEnd?: () => void, dragActivationThreshold?: number, enableClipSnap?: boolean, clipSnapThreshold?: number) => TTrack;
|
|
45
|
+
export type TimelineTrackConstructor<TTrack = Track> = new (layer: Konva.Layer, config: TrackConfig, trackType: TrackType, zoom: number, trackY: number, trackHeight: number, theme: Theme, onClipUpdate: (clip: Clip, originalClip?: Clip, clipUpdates?: ClipStateUpdate[]) => void, onClipAdd: (clip: Clip) => void, onClipRemove: (clipId: string) => void, onClipSplit: (clip1: Clip, clip2: Clip) => void, onClipSelect: (clip: Clip) => void, onTimeJump: (time: TimeMs) => void, onHorizontalDragAutoScroll?: (nextScrollLeft: number) => number, onClipOverlap?: (clip: Clip, currentTrackId: string, originalClip?: Clip | null) => void, onPrimaryTrackMagnetMove?: (clip: Clip, originalClip: Clip | null, peerClips: Clip[], currentTrackId: string) => boolean | void, onClipCrossTrackPreview?: (clip: Clip, targetTrackY: number, currentTrackId: string) => 'self' | 'external' | 'clear', onClipCrossTrack?: (clip: Clip, originalClip: Clip | null, targetTrackY: number, currentTrackId: string) => boolean | void, onClearDropPreview?: () => void, onClearSelection?: () => void, onSnapGuideChange?: (guideTime: TimeMs | null) => void, onClipToggleSelection?: (clipId: string) => void, onSetSingleSelection?: (clipId: string) => void, getMultiDragClipIds?: (clipId: string) => string[] | null, onMultiDragMove?: (request: MultiDragMoveRequest) => boolean | void, onMultiDragInteractionEnd?: () => void, dragActivationThreshold?: number, enableClipSnap?: boolean, clipSnapThreshold?: number) => TTrack;
|
|
45
46
|
export declare class TimelineTrackBridge<TTrack = Track> {
|
|
46
47
|
private readonly handlers;
|
|
47
48
|
private readonly TrackCtor;
|