@linker-design-plus/timeline-track 2.0.3 → 2.0.5

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.
@@ -1,9 +1,10 @@
1
- import type { ActiveClipPlaybackInfo, ClipVisualTransform, PlayState, PreviewAspectRatio, TimeMs, TrackType } from '../models/types';
2
- import type { PreviewPendingState } from './previewBackend';
1
+ import type { ActiveClipPlaybackInfo, ClipVisualTransform, PlayState, PreviewAspectRatio, PreviewSourceResolver, TimeMs, TrackType } from '../models/types';
2
+ import type { PreviewPendingState, PreviewRuntimeState } from './previewBackend';
3
3
  interface TimelinePreviewSessionCallbacks {
4
4
  onBufferingStateChange?: (isBuffering: boolean) => void;
5
5
  onSourceLoadingChange?: (pending: number) => void;
6
6
  onSyncProcessed?: (syncRequestId?: number) => void;
7
+ onRuntimeStateChange?: (state: PreviewRuntimeState) => void;
7
8
  onAspectRatioChange?: (aspectRatio: PreviewAspectRatio) => void;
8
9
  onVisualTransformCommit?: (clipId: string, visualTransform: ClipVisualTransform) => void;
9
10
  onPendingPreviewRetry?: () => void;
@@ -15,6 +16,7 @@ interface TimelinePreviewSessionDependencies {
15
16
  rootClassName?: string;
16
17
  frameClassName?: string;
17
18
  slotClassNamePrefix?: string;
19
+ previewSourceResolver?: PreviewSourceResolver;
18
20
  }
19
21
  export interface TimelinePreviewSyncPayload {
20
22
  activeClips: ActiveClipPlaybackInfo[];
@@ -24,7 +26,7 @@ export interface TimelinePreviewSyncPayload {
24
26
  currentTime: TimeMs;
25
27
  playState: PlayState;
26
28
  speed: number;
27
- selectedClipId?: string | null;
29
+ primarySelectedClipId?: string | null;
28
30
  syncRequestId?: number;
29
31
  }
30
32
  export declare class TimelinePreviewSession {
@@ -39,9 +41,13 @@ export declare class TimelinePreviewSession {
39
41
  private readonly trackSlots;
40
42
  private audioContext;
41
43
  private masterGainNode;
42
- private isBuffering;
43
44
  private loadingCount;
44
- private selectedClipId;
45
+ private isBuffering;
46
+ private bufferingVisibleTimeoutId;
47
+ private lastRuntimeSignature;
48
+ private lastRuntimeState;
49
+ private lastSettledSyncRequestId;
50
+ private primarySelectedClipId;
45
51
  private transientVisualTransform;
46
52
  private readonly callbacks;
47
53
  private readonly dependencies;
@@ -50,9 +56,14 @@ export declare class TimelinePreviewSession {
50
56
  private resolvedAutoAspectRatio;
51
57
  private aspectRatioProbe;
52
58
  private aspectRatioProbeSrc;
59
+ private aspectRatioProbeResolveToken;
53
60
  private isAspectRatioProbeLoading;
54
61
  private pendingState;
62
+ private activeSyncRequestId;
63
+ private isSyncProjecting;
55
64
  constructor(callbacks?: TimelinePreviewSessionCallbacks, dependencies?: TimelinePreviewSessionDependencies);
65
+ private logLoadTrace;
66
+ private buildSlotTraceData;
56
67
  hasPreview(): boolean;
57
68
  attach(container: HTMLElement): void;
58
69
  detach(): void;
@@ -65,7 +76,15 @@ export declare class TimelinePreviewSession {
65
76
  private destroySlot;
66
77
  private getTrackSlots;
67
78
  private swapTrackSlots;
68
- private assignClipToSlot;
79
+ private applyTrackPlan;
80
+ private applySlotTarget;
81
+ private resolveDesiredSource;
82
+ private slotNeedsRecovery;
83
+ private recoverSlot;
84
+ private finishSlotRecovery;
85
+ private applyResolvedSlotState;
86
+ private isCurrentRequest;
87
+ private failSlot;
69
88
  private configureAudioRouting;
70
89
  private syncCurrentSlot;
71
90
  private preparePreloadSlot;
@@ -75,13 +94,13 @@ export declare class TimelinePreviewSession {
75
94
  private resumeAudioContext;
76
95
  private updateFrameLayout;
77
96
  private maybeResolveAutoAspectRatio;
97
+ private resolveAspectRatioProbeSource;
78
98
  private getAspectRatioProbe;
79
99
  private tryResolveAutoAspectRatioFromSlot;
80
100
  private handleResolvedAutoAspectRatio;
81
- private refreshBufferingState;
82
- private setBufferingState;
83
- private refreshLoadingState;
84
- private setLoadingCount;
101
+ private refreshRuntimeState;
102
+ private syncVisibleBufferingState;
103
+ private clearBufferingVisibleTimeout;
85
104
  private refreshPendingOverlay;
86
105
  private handlePreviewTransformChange;
87
106
  private refreshVisualLayout;
@@ -0,0 +1,53 @@
1
+ import type { TimeMs } from '../models/types';
2
+ import type { PreviewPendingState, PreviewRuntimeState } from './previewBackend';
3
+ export interface TimelinePendingPreviewState {
4
+ mode: 'seek' | 'scrub';
5
+ targetTime: TimeMs;
6
+ resumePlayOnReady: boolean;
7
+ errorMessage: string | null;
8
+ timeoutId: ReturnType<typeof setTimeout> | null;
9
+ awaitingSync: boolean;
10
+ syncRequestId: number;
11
+ }
12
+ interface TimelinePreviewStateControllerCallbacks {
13
+ applyPendingState: (state: PreviewPendingState | null) => void;
14
+ emitBufferingStateChange: (isBuffering: boolean) => void;
15
+ emitSourceLoadingStateChange: () => void;
16
+ resumePlayback: () => void;
17
+ requestPreviewSync: () => void;
18
+ }
19
+ interface TimelinePreviewStateControllerOptions {
20
+ callbacks: TimelinePreviewStateControllerCallbacks;
21
+ pendingTimeoutMs?: number;
22
+ }
23
+ export declare class TimelinePreviewStateController {
24
+ private readonly callbacks;
25
+ private readonly pendingTimeoutMs;
26
+ private _previewSourceLoadingCount;
27
+ private _previewBuffering;
28
+ private _previewAwaitingMedia;
29
+ private _pendingPreviewState;
30
+ private _nextPendingPreviewSyncRequestId;
31
+ constructor(options: TimelinePreviewStateControllerOptions);
32
+ get previewSourceLoadingCount(): number;
33
+ set previewSourceLoadingCount(value: number);
34
+ get previewBuffering(): boolean;
35
+ set previewBuffering(value: boolean);
36
+ get pendingPreviewState(): TimelinePendingPreviewState | null;
37
+ set pendingPreviewState(value: TimelinePendingPreviewState | null);
38
+ get nextPendingPreviewSyncRequestId(): number;
39
+ set nextPendingPreviewSyncRequestId(value: number);
40
+ handleBufferingStateChange(isBuffering: boolean): void;
41
+ handleSourceLoadingChange(pending: number): void;
42
+ handleRuntimeStateChange(state: PreviewRuntimeState): void;
43
+ markSyncProcessed(syncRequestId?: number): void;
44
+ beginPendingPreview(time: TimeMs, mode: 'seek' | 'scrub', resumePlayOnReady: boolean): void;
45
+ buildPreviewPendingState(): PreviewPendingState | null;
46
+ updatePendingPreviewState(): void;
47
+ retryPendingPreview(): void;
48
+ clearPendingPreviewState(): void;
49
+ resetPreviewRuntimeState(): void;
50
+ private ensurePendingPreviewTimeout;
51
+ private clearPendingPreviewTimeout;
52
+ }
53
+ export {};
@@ -4,7 +4,7 @@ export interface SelectedClipSnapshot {
4
4
  hasSelectedClip: boolean;
5
5
  }
6
6
  interface ResolveSelectedClipOptions {
7
- getSelectedClip: () => Clip | null;
7
+ getPrimarySelectedClip: () => Clip | null;
8
8
  findFallbackSelectedClip?: () => Clip | null;
9
9
  }
10
10
  interface EmitSelectedClipChangeOptions {
@@ -1,3 +1,4 @@
1
+ import { type TimelinePreviewBackend } from '../controllers';
1
2
  import { TimelineConfig, Clip, ClipConfig, TimeMs, PlayState, Action, TimelineEvent, EventListener as TimelineEventListener, TimelineExportData, ThumbnailProvider, TrackInsertionPlacement, TrackType, ActiveClipPlaybackInfo, PreviewAspectRatio, PreviewMountConfig, PreviewBackendType } from '../models';
2
3
  import type { ResolvedPlaybackPlan } from '../controllers/timelinePlaybackResolver';
3
4
  import { TimelineClipConfigController } from '../controllers/timelineClipConfigController';
@@ -37,6 +38,7 @@ export declare class TimelineManager {
37
38
  private verticalScrollbar;
38
39
  private isExecutingHistoryAction;
39
40
  private lastTrackDuration;
41
+ private lastEffectiveTrackDuration;
40
42
  private thumbnailProvider;
41
43
  private canPlay;
42
44
  private sourceLoadingCount;
@@ -47,16 +49,12 @@ export declare class TimelineManager {
47
49
  private timelinePresentationAdapter?;
48
50
  private timelineTrackBridge?;
49
51
  private timelinePlaybackResolver?;
50
- private previewSession?;
51
- private previewMountContainer;
52
- private resolvedPreviewBackend;
53
- private runtimePreviewBackendOverride;
52
+ private previewRuntimeController?;
53
+ private previewStateController?;
54
+ private previewPlaybackSuspendedByBuffering;
55
+ private previewPlaybackAutoResume;
56
+ private previewBufferingSuspendTimeoutId;
54
57
  private lastSelectedClipId;
55
- private previewSourceLoadingCount;
56
- private previewBuffering;
57
- private pendingPreviewState;
58
- private nextPendingPreviewSyncRequestId;
59
- private activePreviewCallbackToken;
60
58
  private previewAspectRatio;
61
59
  private readonly bodyViewportScrollListener;
62
60
  private readonly bodyCanvasHostClickListener;
@@ -73,11 +71,29 @@ export declare class TimelineManager {
73
71
  private getTimelinePresentationAdapter;
74
72
  private getTimelineTrackBridge;
75
73
  private getTimelinePlaybackResolver;
74
+ get previewSession(): TimelinePreviewBackend | undefined;
75
+ set previewSession(value: TimelinePreviewBackend | undefined);
76
+ get previewMountContainer(): HTMLElement | null;
77
+ set previewMountContainer(value: HTMLElement | null);
78
+ get resolvedPreviewBackend(): Exclude<PreviewBackendType, 'auto'>;
79
+ set resolvedPreviewBackend(value: Exclude<PreviewBackendType, 'auto'>);
80
+ get runtimePreviewBackendOverride(): Exclude<PreviewBackendType, 'auto'> | null;
81
+ set runtimePreviewBackendOverride(value: Exclude<PreviewBackendType, 'auto'> | null);
82
+ get activePreviewCallbackToken(): number;
83
+ set activePreviewCallbackToken(value: number);
84
+ private get previewSourceLoadingCount();
85
+ private set previewSourceLoadingCount(value);
86
+ get previewBuffering(): boolean;
87
+ set previewBuffering(value: boolean);
88
+ private get pendingPreviewState();
89
+ private set pendingPreviewState(value);
90
+ get nextPendingPreviewSyncRequestId(): number;
91
+ set nextPendingPreviewSyncRequestId(value: number);
92
+ private getPreviewStateController;
93
+ private getPreviewRuntimeController;
76
94
  private resolveConfiguredPreviewBackend;
77
95
  private createPreviewBackendCallbacks;
78
- private createPreviewBackend;
79
96
  private isActivePreviewCallbackToken;
80
- private getPreviewSession;
81
97
  private getEventDispatcher;
82
98
  private getDefaultTrackForHistory;
83
99
  private getTimelineHistoryRecorder;
@@ -120,14 +136,11 @@ export declare class TimelineManager {
120
136
  private registerPreviewAutoAspectRatioClip;
121
137
  private syncPreviewSession;
122
138
  private beginPendingPreview;
123
- private updatePendingPreviewState;
139
+ updatePendingPreviewState(): void;
124
140
  private buildPreviewPendingState;
125
- private ensurePendingPreviewTimeout;
126
- private clearPendingPreviewTimeout;
127
141
  private clearPendingPreviewState;
128
142
  private resetPreviewRuntimeState;
129
143
  private destroyPreviewSession;
130
- private recreateDetachedPreviewSession;
131
144
  private retryPendingPreview;
132
145
  private handlePreviewBackendRuntimeError;
133
146
  init(container: HTMLElement): void;
@@ -171,6 +184,8 @@ export declare class TimelineManager {
171
184
  pause(): void;
172
185
  togglePlay(): void;
173
186
  private animate;
187
+ private syncPlaybackClockToPreviewBuffering;
188
+ private clearPreviewBufferingSuspendTimeout;
174
189
  setCurrentTime(time: TimeMs): void;
175
190
  getCurrentTime(): TimeMs;
176
191
  setEnableClipSnap(enabled: boolean): void;
@@ -255,6 +270,7 @@ export declare class TimelineManager {
255
270
  private getExportComposition;
256
271
  exportTimeline(): TimelineExportData;
257
272
  importTimeline(data: TimelineExportData): Promise<void>;
273
+ private stopPlaybackForImport;
258
274
  getClipsData(): Clip[];
259
275
  /**
260
276
  * 获取插件版本号
@@ -318,12 +334,19 @@ export declare class TimelineManager {
318
334
  * @param clipId 目标片段的 ID
319
335
  */
320
336
  private notifySelectionChange;
337
+ private syncPrimarySelectionFromSelectionStore;
338
+ private getOrderedSelectionClipIds;
339
+ setSelection(clipIds: string[], options?: {
340
+ preferredPrimaryClipId?: string | null;
341
+ selectedClipEventClip?: Clip | null;
342
+ }): void;
321
343
  selectClip(clipId: string, clip?: any): void;
322
344
  /**
323
345
  * 清空所有轨道的选中状态
324
346
  */
325
347
  clearSelection(): void;
326
348
  getSelectedClipIds(): string[];
349
+ getPrimarySelectedClipId(): string | null;
327
350
  addToSelection(clipId: string): void;
328
351
  removeFromSelection(clipId: string): void;
329
352
  toggleSelection(clipId: string): void;
@@ -332,7 +355,6 @@ export declare class TimelineManager {
332
355
  separateSelectedClipsAudio(): void;
333
356
  selectAllClips(): void;
334
357
  private emitSelectionChangeEvent;
335
- private updateAllTracksSelectionVisual;
336
358
  /**
337
359
  * 滚动到指定片段
338
360
  * @param clipId 目标片段的 ID
@@ -351,6 +373,7 @@ export declare class TimelineManager {
351
373
  * @returns 当前选中的 clip,如果没有则返回 null
352
374
  */
353
375
  getSelectedClip(): Clip | null;
376
+ getPrimarySelectedClip(): Clip | null;
354
377
  getSelectedClips(): Clip[];
355
378
  canDeleteSelectedClips(): boolean;
356
379
  getSelectedClipAudioAction(): 'separate' | 'restore' | null;
@@ -364,6 +387,7 @@ export declare class TimelineManager {
364
387
  detachPreview(): void;
365
388
  attachClipConfig(container: HTMLElement): TimelineClipConfigController;
366
389
  getPreviewBackendType(): Exclude<PreviewBackendType, 'auto'>;
390
+ hasAttachedPreview(): boolean;
367
391
  getPreviewAspectRatio(): PreviewAspectRatio;
368
392
  setPreviewAspectRatio(aspectRatio: {
369
393
  width: number;
@@ -378,6 +402,7 @@ export declare class TimelineManager {
378
402
  removeSelectedClips(): boolean;
379
403
  canSeparateClipAudio(clipId: string): boolean;
380
404
  canRestoreClipAudio(clipId: string): boolean;
405
+ private resolvePreferredSeparatedAudioTrackId;
381
406
  separateClipAudio(clipId: string): Promise<string | null>;
382
407
  restoreClipAudio(clipId: string): boolean;
383
408
  private applySelectedClipAudioAction;
@@ -390,8 +415,8 @@ export declare class TimelineManager {
390
415
  moveClipToTrack(clipId: string, targetTrackId: string): boolean;
391
416
  private moveClipToTrackWithHistorySnapshot;
392
417
  /**
393
- * 获取轨道内的总时长(包含空隙)
394
- * @returns 从0到最后一个clip结束时间的总时长(毫秒)
418
+ * 获取轨道内的有效总时长(去除首尾空白)
419
+ * @returns 最早 clip 起点到最晚 clip 终点的时长(毫秒)
395
420
  */
396
421
  getTrackTotalDuration(): TimeMs;
397
422
  destroy(): void;
@@ -20,7 +20,7 @@ export interface ClipVisualTransform {
20
20
  y: number;
21
21
  scale: number;
22
22
  }
23
- export type PreviewBackendType = 'dom' | 'canvas' | 'pixi' | 'auto';
23
+ export type PreviewBackendType = 'dom' | 'canvas' | 'auto';
24
24
  export interface Mp4PreviewMediaSource {
25
25
  url: string;
26
26
  mimeType: string;
@@ -17,6 +17,6 @@ export declare class TimelinePresentationAdapter {
17
17
  syncZoom(timeline: TimelineZoomView | null, playhead: TimelineZoomView | null, tracks: TimelineTrackCollection, zoom: number): void;
18
18
  syncScrollLeft(playhead: TimelineScrollView | null, tracks: TimelineTrackCollection, scrollLeft: number): void;
19
19
  syncScrollTop(panel: TimelineVerticalScrollView | null, scrollbar: TimelineVerticalScrollView | null, scrollTop: number): void;
20
- syncSelection(tracks: TimelineTrackCollection, selectedClipId: string | null, selectedClipIds?: string[]): void;
20
+ syncSelection(tracks: TimelineTrackCollection, selectedClipIds: string[]): void;
21
21
  findSelectedClip(tracks: TimelineTrackCollection): Clip | null;
22
22
  }
@@ -1,11 +1,13 @@
1
1
  export declare class SelectionStore {
2
2
  private selectedClipIds;
3
+ getPrimarySelectedClipId(): string | null;
3
4
  getSelectedClipId(): string | null;
4
5
  getSelectedClipIds(): string[];
5
6
  addToSelection(clipId: string): void;
6
7
  removeFromSelection(clipId: string): void;
7
8
  toggleSelection(clipId: string): void;
8
9
  setSelection(clipIds: string[]): void;
10
+ setPrimarySelection(clipId: string | null): void;
9
11
  setSelectedClipId(clipId: string | null): void;
10
12
  clear(): void;
11
13
  hasSelection(): boolean;
@@ -11,13 +11,18 @@ export interface TimelineStoreInitialState {
11
11
  viewportHeight?: number;
12
12
  contentHeight?: number;
13
13
  selectedClipId?: string | null;
14
+ selectedClipIds?: string[];
14
15
  }
15
16
  export declare class TimelineStore {
16
17
  private readonly selectionStore;
17
18
  private readonly playbackStore;
18
19
  private readonly viewportStore;
19
20
  constructor(initial: TimelineStoreInitialState);
21
+ getPrimarySelectedClipId(): string | null;
20
22
  getSelectedClipId(): string | null;
23
+ getSelectedClipIds(): string[];
24
+ setSelectedClipIds(clipIds: string[]): void;
25
+ setPrimarySelectedClipId(clipId: string | null): void;
21
26
  setSelectedClipId(clipId: string | null): void;
22
27
  clearSelection(): void;
23
28
  hasSelection(): boolean;
@@ -13,10 +13,9 @@ export interface TimelineTrackCollectionItem extends TimelineTrackView {
13
13
  updateClip?(clipId: string, updates: Partial<Clip>): void;
14
14
  updateClipPosition?(clipId: string, newStartTime: TimeMs, isFinal: boolean, previewOffsetY?: number): void;
15
15
  removeClipGaps?(): void;
16
- updateSelectionVisual?(selectedClipId: string | null): void;
16
+ setSelection?(clipIds: string[], preferredClipId?: string | null): void;
17
17
  clearSelection?(): void;
18
- getSelectedClip?(): Clip | null;
19
- selectClip?(clipId: string): void;
18
+ getPrimarySelectedClip?(): Clip | null;
20
19
  setTrackY?(y: number): void;
21
20
  setTrackStackOrder?(order: number): void;
22
21
  setTrackHeight?(height: number): void;
@@ -26,7 +25,6 @@ export interface TimelineTrackCollectionItem extends TimelineTrackView {
26
25
  getTrackGroup?(): {
27
26
  destroy(): void;
28
27
  };
29
- updateClipSelection?(clipId: string, isSelected: boolean): void;
30
28
  }
31
29
  export declare class TimelineTrackCollection {
32
30
  private readonly tracks;
@@ -52,6 +50,8 @@ export declare class TimelineTrackCollection {
52
50
  moveClipToTrack(clip: Clip, sourceTrackId: string, targetTrackId: string): boolean;
53
51
  removeClipGaps(): void;
54
52
  clearSelection(): void;
53
+ syncSelection(clipIds: string[], preferredClipId?: string | null): void;
54
+ findPrimarySelectedClip(): Clip | null;
55
55
  forEach(callback: (track: TimelineTrackCollectionItem) => void): void;
56
56
  private findIndexById;
57
57
  private resolveTrackId;
@@ -14,6 +14,7 @@ export declare class TrackManager {
14
14
  private insertTrack;
15
15
  muteTrack(trackId: string, isMuted: boolean): boolean;
16
16
  isTrackMuted(trackId: string): boolean;
17
+ clearAllTracks(): void;
17
18
  getTrackCount(): number;
18
19
  getTrackCountByType(type: TrackType): number;
19
20
  }