@linker-design-plus/timeline-track 2.0.13 → 2.0.14

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/README.md CHANGED
@@ -103,6 +103,9 @@ timeline.on('history_change', (_event, data) => {
103
103
 
104
104
  - 播放 / 暂停:`Space`
105
105
  - 删除片段:`Delete` / `Backspace`
106
+ - 复制片段:`Mod+C`
107
+ - 剪切片段:`Mod+X`
108
+ - 粘贴片段:`Mod+V`
106
109
  - 分离 / 还原音频:`Mod+Alt+A`
107
110
  - 分割片段:`Mod+B`
108
111
  - 撤销:`Mod+Z`
@@ -1,5 +1,6 @@
1
1
  import type { ActiveClipPlaybackInfo, Clip, ClipVisualTransform, PlayState, PreviewAspectRatio, PreviewMediaSource, PreviewSourceResolver, TextPreviewFontConfig, TimeMs } from '../models/types';
2
2
  import type { SourceMediaRegistry } from '../resources/sourceMediaRegistry';
3
+ import type { DiagnosticsCenter, DiagnosticEmitInput } from '../../utils/diagnostics';
3
4
  export interface TimelinePreviewSyncPayload {
4
5
  activeClips: ActiveClipPlaybackInfo[];
5
6
  nextClips: ActiveClipPlaybackInfo[];
@@ -8,6 +9,7 @@ export interface TimelinePreviewSyncPayload {
8
9
  currentTime: TimeMs;
9
10
  playState: PlayState;
10
11
  speed: number;
12
+ interactionMode?: 'steady' | 'seek' | 'scrub';
11
13
  primarySelectedClipId?: string | null;
12
14
  syncRequestId?: number;
13
15
  }
@@ -69,6 +71,8 @@ export interface TimelinePreviewBackendOptions {
69
71
  previewSourceResolver?: PreviewSourceResolver;
70
72
  textPreviewFont?: TextPreviewFontConfig | null;
71
73
  sourceMediaRegistry?: SourceMediaRegistry;
74
+ diagnostics?: DiagnosticsCenter;
75
+ getDiagnosticsContext?: () => Partial<DiagnosticEmitInput>;
72
76
  rootClassName?: string;
73
77
  frameClassName?: string;
74
78
  slotClassNamePrefix?: string;
@@ -2,11 +2,17 @@ import type { TimelineKeyboardShortcutsConfig } from '../models';
2
2
  export interface TimelineKeyboardShortcutsControllerCallbacks {
3
3
  togglePlay(): void;
4
4
  deleteSelectedClips(): void;
5
+ copySelectedClips(): void;
6
+ cutSelectedClips(): void;
7
+ pasteClipboardClips(): Promise<boolean> | boolean;
5
8
  toggleSelectedClipsAudio(): Promise<boolean>;
6
9
  splitCurrentClip(): void;
7
10
  undo(): boolean;
8
11
  redo(): boolean;
9
12
  canDeleteSelectedClips(): boolean;
13
+ canCopySelectedClips(): boolean;
14
+ canCutSelectedClips(): boolean;
15
+ canPasteClipboardClips(): boolean;
10
16
  canSplitSelectedClip(): boolean;
11
17
  canToggleSelectedClipsAudio(): boolean;
12
18
  }
@@ -1,6 +1,7 @@
1
1
  import type { ActiveClipPlaybackInfo, ClipVisualTransform, PlayState, PreviewAspectRatio, PreviewSourceResolver, TextPreviewFontConfig, TimeMs, TrackType } from '../models/types';
2
2
  import type { SourceMediaRegistry } from '../resources/sourceMediaRegistry';
3
3
  import type { PreviewPendingState, PreviewRuntimeState } from './previewBackend';
4
+ import { type DiagnosticEmitInput, type DiagnosticsCenter } from '../../utils/diagnostics';
4
5
  interface TimelinePreviewSessionCallbacks {
5
6
  onBufferingStateChange?: (isBuffering: boolean) => void;
6
7
  onSourceLoadingChange?: (pending: number) => void;
@@ -14,6 +15,8 @@ interface TimelinePreviewSessionDependencies {
14
15
  createMediaElement?: (kind: TrackType, role: 'current' | 'preload') => HTMLMediaElement;
15
16
  createAspectRatioProbe?: () => HTMLVideoElement;
16
17
  createAudioContext?: () => AudioContext | null;
18
+ diagnostics?: DiagnosticsCenter;
19
+ getDiagnosticsContext?: () => Partial<DiagnosticEmitInput>;
17
20
  rootClassName?: string;
18
21
  frameClassName?: string;
19
22
  slotClassNamePrefix?: string;
@@ -29,6 +32,7 @@ export interface TimelinePreviewSyncPayload {
29
32
  currentTime: TimeMs;
30
33
  playState: PlayState;
31
34
  speed: number;
35
+ interactionMode?: 'steady' | 'seek' | 'scrub';
32
36
  primarySelectedClipId?: string | null;
33
37
  syncRequestId?: number;
34
38
  }
@@ -73,8 +77,10 @@ export declare class TimelinePreviewSession {
73
77
  private pendingState;
74
78
  private activeSyncRequestId;
75
79
  private isSyncProjecting;
80
+ private readonly deferredPreloadSlotKeys;
81
+ private deferredPreloadFlushScheduled;
76
82
  constructor(callbacks?: TimelinePreviewSessionCallbacks, dependencies?: TimelinePreviewSessionDependencies);
77
- private logLoadTrace;
83
+ private emitDiagnostic;
78
84
  private buildSlotTraceData;
79
85
  hasPreview(): boolean;
80
86
  attach(container: HTMLElement): void;
@@ -85,6 +91,7 @@ export declare class TimelinePreviewSession {
85
91
  getAspectRatio(): PreviewAspectRatio;
86
92
  private createMediaElement;
87
93
  private createSlot;
94
+ private resetSlotRecoveryTracking;
88
95
  private destroySlot;
89
96
  private getTrackSlots;
90
97
  private swapTrackSlots;
@@ -95,8 +102,24 @@ export declare class TimelinePreviewSession {
95
102
  private slotNeedsRecovery;
96
103
  private recoverSlot;
97
104
  private finishSlotRecovery;
105
+ private getSlotKey;
106
+ private isActiveCurrentSlot;
107
+ private hasBlockingActiveCurrentSlot;
108
+ private shouldDeferPreloadTarget;
109
+ private shouldDeferPreloadRecovery;
110
+ private buildDeferredPreloadTarget;
111
+ private deferPreloadTarget;
112
+ private deferPreloadRecovery;
113
+ private scheduleDeferredPreloadFlush;
114
+ private flushDeferredPreloads;
98
115
  private applyResolvedSlotState;
99
116
  private isCurrentRequest;
117
+ private shouldIgnoreExpectedEmptied;
118
+ private shouldIgnoreExpectedAbort;
119
+ private shouldIgnoreClearedSlotRecoverableEvent;
120
+ private shouldSkipImmediatePreloadRecovery;
121
+ private isBackgroundPreloadSlot;
122
+ private parkPreloadSlot;
100
123
  private failSlot;
101
124
  private configureAudioRouting;
102
125
  private syncCurrentSlot;
@@ -2,6 +2,7 @@ import { type TimelinePreviewBackend } from '../controllers';
2
2
  import { TimelineConfig, Clip, ClipConfig, TimeMs, PlayState, Action, TimelineEvent, EventListener as TimelineEventListener, TimelineExportData, Track as TrackEntity, ThumbnailProvider, TrackInsertionPlacement, TrackType, ActiveClipPlaybackInfo, PreviewAspectRatio, PreviewMountConfig, PreviewBackendType, SelectedClipAudioAction, ClipConfigVoicePanelOptions } from '../models';
3
3
  import type { ResolvedPlaybackPlan } from '../controllers/timelinePlaybackResolver';
4
4
  import { TimelineClipConfigController } from '../controllers/timelineClipConfigController';
5
+ import { type DiagnosticExportPackage, type DiagnosticLiveSnapshot, type DiagnosticsListener, type DiagnosticsLiveListener, type DiagnosticSessionSnapshot } from '../../utils/diagnostics';
5
6
  export declare class TimelineManager {
6
7
  private timeline;
7
8
  private tracks;
@@ -63,13 +64,27 @@ export declare class TimelineManager {
63
64
  private readonly bodyCanvasHostClickListener;
64
65
  private readonly rootWheelListener;
65
66
  private keyboardShortcutsController;
67
+ private clipClipboard;
66
68
  private mountManager;
67
69
  private pendingDraftData;
68
70
  private selectionStore;
69
71
  private multiDragSession;
70
72
  private clipRemovalBatchDepth;
71
73
  private splitOperationDepth;
74
+ private readonly diagnostics;
75
+ private diagnosticsPanel;
76
+ private previewRuntimeState;
77
+ private previewActiveClipIds;
78
+ private playbackAttemptId;
79
+ private lastPreviewSyncedPlayState;
80
+ private previewSyncInteractionMode;
72
81
  constructor(config?: Partial<TimelineConfig>);
82
+ private createPlaybackAttemptId;
83
+ private refreshPlaybackAttempt;
84
+ private emitDiagnostic;
85
+ private buildDiagnosticsRuntimeState;
86
+ private buildPreviewDiagnosticsContext;
87
+ private mountDiagnosticsPanel;
73
88
  private getTimelineStore;
74
89
  private getTimelineCommands;
75
90
  private getTrackCollection;
@@ -141,6 +156,7 @@ export declare class TimelineManager {
141
156
  private getAutoAspectRatioClip;
142
157
  private registerPreviewAutoAspectRatioClip;
143
158
  private syncPreviewSession;
159
+ private syncPreviewPlaybackStateIfNeeded;
144
160
  private beginPendingPreview;
145
161
  updatePendingPreviewState(): void;
146
162
  private buildPreviewPendingState;
@@ -321,9 +337,20 @@ export declare class TimelineManager {
321
337
  private applyGeneratedAudioClipResult;
322
338
  private syncTextClipDurationToAudio;
323
339
  private doesClipOverlapOnTrack;
340
+ private doesClipGroupOverlapOnTrack;
324
341
  private findNearestAvailableTrackForClip;
325
- private relocateGeneratedAudioClipIfNeeded;
342
+ private resolveOverlapRelocationTargetTrackId;
343
+ private relocateClipToAvoidOverlap;
344
+ private buildClipboardPasteGroups;
345
+ private createTracksForTypeBoundary;
346
+ private buildClipboardPasteGroupPlacementClips;
347
+ private ensureClipboardPasteSourceTracks;
348
+ private resolveClipboardPasteTypeGroupAssignments;
349
+ private resolvePreferredTrackIndexForPasteGroup;
350
+ private resolveClipboardPasteTrackAssignments;
351
+ private relocateClipIfNeeded;
326
352
  private regenerateVoiceLinkedAudioClips;
353
+ private getSelectedTextClipsForVoiceGeneration;
327
354
  private handleVoiceGenerateAction;
328
355
  private primeOrLoadClipThumbnails;
329
356
  private markClipThumbnailLoadCompleted;
@@ -383,6 +410,15 @@ export declare class TimelineManager {
383
410
  toggleSelection(clipId: string): void;
384
411
  isClipSelected(clipId: string): boolean;
385
412
  deleteSelectedClips(): void;
413
+ copySelectedClips(): boolean;
414
+ cutSelectedClips(): boolean;
415
+ pasteClipboardClips(): Promise<boolean>;
416
+ private deleteSelectedClipsWithHistoryLabel;
417
+ private captureSelectedClipsToClipboard;
418
+ private cloneClipForClipboard;
419
+ private buildClipboardPasteClipConfig;
420
+ private resolveClipboardPasteTrackId;
421
+ private generateClipId;
386
422
  separateSelectedClipsAudio(): void;
387
423
  selectAllClips(): void;
388
424
  private emitSelectionChangeEvent;
@@ -406,6 +442,9 @@ export declare class TimelineManager {
406
442
  getSelectedClip(): Clip | null;
407
443
  getPrimarySelectedClip(): Clip | null;
408
444
  getSelectedClips(): Clip[];
445
+ canCopySelectedClips(): boolean;
446
+ canCutSelectedClips(): boolean;
447
+ canPasteClipboardClips(): boolean;
409
448
  canDeleteSelectedClips(): boolean;
410
449
  canSplitSelectedClip(): boolean;
411
450
  getSelectedClipAudioAction(): SelectedClipAudioAction;
@@ -421,6 +460,12 @@ export declare class TimelineManager {
421
460
  getPreviewBackendType(): Exclude<PreviewBackendType, 'auto'>;
422
461
  hasAttachedPreview(): boolean;
423
462
  getPreviewAspectRatio(): PreviewAspectRatio;
463
+ getDiagnosticsSnapshot(): DiagnosticSessionSnapshot;
464
+ subscribeDiagnostics(listener: DiagnosticsListener): () => void;
465
+ getDiagnosticsLiveSnapshot(recentEventLimit?: number): DiagnosticLiveSnapshot;
466
+ subscribeDiagnosticsLive(listener: DiagnosticsLiveListener, recentEventLimit?: number): () => void;
467
+ exportDiagnosticsPackage(): DiagnosticExportPackage;
468
+ clearDiagnostics(sessionOnly?: boolean): void;
424
469
  setPreviewAspectRatio(aspectRatio: {
425
470
  width: number;
426
471
  height: number;
@@ -3,6 +3,7 @@ import type { Action, Clip, ClipStateUpdate, Track, TrackRestoreAnchor } from '.
3
3
  export declare class TimelineHistoryRecorder {
4
4
  private readonly history;
5
5
  constructor(history: HistoryManager);
6
+ createAddClipAction(clip: Clip): Action;
6
7
  recordAddClip(clip: Clip): Action;
7
8
  createRemoveClipAction(clip: Clip, sourceTrackId?: string | null, sourceTrackSnapshot?: Track | null, sourceTrackRestoreAnchor?: TrackRestoreAnchor | null): Action;
8
9
  recordRemoveClip(clip: Clip, sourceTrackId?: string | null, sourceTrackSnapshot?: Track | null, sourceTrackRestoreAnchor?: TrackRestoreAnchor | null): Action;
@@ -1,12 +1,8 @@
1
+ export type { DiagnosticEvent, DiagnosticExportPackage, DiagnosticLiveEvent, DiagnosticLiveSnapshot, DiagnosticsConfig, DiagnosticsLiveListener, DiagnosticSessionSnapshot } from '../../utils/diagnostics/types';
2
+ import type { DiagnosticsConfig } from '../../utils/diagnostics/types';
1
3
  export type TrackType = 'video' | 'audio' | 'text';
2
4
  export type PlayState = 'playing' | 'paused';
3
5
  export type TimeMs = number;
4
- export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
5
- export interface LogConfig {
6
- enabled?: boolean;
7
- level?: LogLevel;
8
- moduleLevels?: Record<string, LogLevel>;
9
- }
10
6
  export interface ThumbnailProvider {
11
7
  /**
12
8
  * 获取片段的封面图片
@@ -187,7 +183,7 @@ export type ThemeConfig = Partial<Theme>;
187
183
  export type ResolvedTimelineConfig = Omit<TimelineConfig, 'theme'> & {
188
184
  theme: Theme;
189
185
  };
190
- export type TimelineKeyboardShortcutAction = 'togglePlay' | 'deleteSelectedClips' | 'toggleSelectedClipsAudio' | 'splitCurrentClip' | 'undo' | 'redo';
186
+ export type TimelineKeyboardShortcutAction = 'togglePlay' | 'deleteSelectedClips' | 'copySelectedClips' | 'cutSelectedClips' | 'pasteClipboardClips' | 'toggleSelectedClipsAudio' | 'splitCurrentClip' | 'undo' | 'redo';
191
187
  export type TimelineKeyboardShortcutBindings = Partial<Record<TimelineKeyboardShortcutAction, string | string[]>>;
192
188
  export interface TimelineKeyboardShortcutsConfig {
193
189
  enabled?: boolean;
@@ -203,7 +199,7 @@ export interface TimelineConfig {
203
199
  container?: HTMLElement;
204
200
  theme?: ThemeConfig;
205
201
  timeScaleHeight?: number;
206
- logConfig?: LogConfig;
202
+ diagnostics?: DiagnosticsConfig;
207
203
  speed?: number;
208
204
  dragActivationThreshold?: number;
209
205
  enableClipSnap?: boolean;
@@ -453,7 +449,7 @@ export interface EventListener {
453
449
  export interface TimelineManagerConfig {
454
450
  initialDuration?: TimeMs;
455
451
  initialZoom?: number;
456
- logConfig?: LogConfig;
452
+ diagnostics?: DiagnosticsConfig;
457
453
  thumbnailProvider?: ThumbnailProvider;
458
454
  }
459
455
  export interface TimelineExportData {