@linker-design-plus/timeline-track 2.0.20 → 2.0.22
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 +3 -3
- package/dist/components/panel/ClipConfigPanel.d.ts +15 -1
- package/dist/components/panel/ClipConfigPanelRenderer.d.ts +5 -3
- package/dist/components/track/Track.d.ts +1 -34
- package/dist/core/controllers/previewBackend.d.ts +2 -0
- package/dist/core/controllers/previewTransformOverlay.d.ts +11 -0
- package/dist/core/controllers/timelineClipConfigController.d.ts +4 -0
- package/dist/core/controllers/timelinePreviewSession.d.ts +4 -0
- package/dist/core/facade/timelineManager.d.ts +4 -1
- package/dist/core/layout/timelineManagerDom.d.ts +1 -1
- package/dist/index.cjs.js +255 -215
- package/dist/index.d.ts +0 -2
- package/dist/index.es.js +3715 -3947
- package/dist/utils/rendering/KonvaUtils.d.ts +0 -4
- package/package.json +1 -1
- package/dist/components/timeline/Playhead.d.ts +0 -27
- package/dist/components/timeline/Timeline.d.ts +0 -91
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @linker-design-plus/timeline-track
|
|
2
2
|
|
|
3
|
-
基于 TypeScript、Konva 和 Vue demo 的时间线编辑组件库,对外以 `TimelineManager`
|
|
3
|
+
基于 TypeScript、Konva 和 Vue demo 的时间线编辑组件库,对外以 `TimelineManager` 为统一入口,提供多轨片段编辑、拖拽/拉伸/分割、撤销重做、选中态同步、封面渲染和预览挂载能力。时间轴主体仍由 Konva 驱动,播放指针使用独立的 SVG/DOM 覆盖层渲染。
|
|
4
4
|
|
|
5
5
|
## 当前状态
|
|
6
6
|
|
|
@@ -188,7 +188,7 @@ flowchart TB
|
|
|
188
188
|
FACADE --> TRACKS["Tracks\nTrackManager / Bridge / Collection"]
|
|
189
189
|
FACADE --> PRESENTATION["Presentation\nTimelinePresentationAdapter"]
|
|
190
190
|
FACADE --> PREVIEW["Preview\nDomPreviewBackend"]
|
|
191
|
-
FACADE --> COMPONENTS["
|
|
191
|
+
FACADE --> COMPONENTS["Presentation Views\nTimeline / Track / Clip / Panels / ManagedPlayhead"]
|
|
192
192
|
```
|
|
193
193
|
|
|
194
194
|
当前最值得关注的热点:
|
|
@@ -202,7 +202,7 @@ flowchart TB
|
|
|
202
202
|
|
|
203
203
|
```text
|
|
204
204
|
src/
|
|
205
|
-
components/
|
|
205
|
+
components/ 时间轴视图、SVG/DOM 覆盖层与交互 helper
|
|
206
206
|
core/ stores / commands / controllers / facade / models
|
|
207
207
|
utils/ 渲染、时间和日志工具
|
|
208
208
|
styles/ 样式入口
|
|
@@ -13,6 +13,17 @@ export interface ClipConfigPanelTheme {
|
|
|
13
13
|
buttonActiveBorder: string;
|
|
14
14
|
buttonActiveText: string;
|
|
15
15
|
}
|
|
16
|
+
export type ClipConfigPanelGroupKind = 'video' | 'audio' | 'text' | 'mixed' | 'empty';
|
|
17
|
+
export interface ClipConfigPanelSelectionState {
|
|
18
|
+
primaryClip: Clip | null;
|
|
19
|
+
selectedClips: Clip[];
|
|
20
|
+
selectionCount: number;
|
|
21
|
+
groupKind: ClipConfigPanelGroupKind;
|
|
22
|
+
supportsVoiceBatch: boolean;
|
|
23
|
+
supportsTextContentBatch: boolean;
|
|
24
|
+
supportsVisualBatch: boolean;
|
|
25
|
+
supportsVolumeBatch: boolean;
|
|
26
|
+
}
|
|
16
27
|
export declare const defaultDarkTheme: ClipConfigPanelTheme;
|
|
17
28
|
export interface ClipConfigPanelConfig {
|
|
18
29
|
container: HTMLElement;
|
|
@@ -75,6 +86,7 @@ export declare class ClipConfigPanel {
|
|
|
75
86
|
private readonly onGenerateVoice?;
|
|
76
87
|
private readonly voiceCatalog;
|
|
77
88
|
private currentClip;
|
|
89
|
+
private selectionState;
|
|
78
90
|
private activeTab;
|
|
79
91
|
private readonly iconCache;
|
|
80
92
|
private pendingPreferredTab;
|
|
@@ -91,13 +103,15 @@ export declare class ClipConfigPanel {
|
|
|
91
103
|
private previewingVoiceId;
|
|
92
104
|
constructor(config: ClipConfigPanelConfig);
|
|
93
105
|
setClip(clip: Clip | null): void;
|
|
106
|
+
setSelectionState(selectionState: ClipConfigPanelSelectionState): void;
|
|
94
107
|
setPreferredTab(tab: 'voice' | null): void;
|
|
95
108
|
setVoiceGenerationBusy(isBusy: boolean): void;
|
|
96
109
|
destroy(): void;
|
|
97
110
|
private render;
|
|
98
111
|
private getAvailableTabs;
|
|
112
|
+
private getEmptyStateMessage;
|
|
99
113
|
private resetVoiceState;
|
|
100
|
-
private
|
|
114
|
+
private syncVoiceStateForSelection;
|
|
101
115
|
private syncActiveTab;
|
|
102
116
|
private supportsVoicePanel;
|
|
103
117
|
private ensureVoiceFilters;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type TemplateResult } from 'lit';
|
|
2
2
|
import { type Clip, type VoiceOption } from '../../core/models';
|
|
3
3
|
import { LitDomRenderer } from '../../core/renderers/domRenderer';
|
|
4
|
-
import type { ClipConfigPanelTheme } from './ClipConfigPanel';
|
|
4
|
+
import type { ClipConfigPanelSelectionState, ClipConfigPanelTheme } from './ClipConfigPanel';
|
|
5
5
|
export type ClipConfigPanelTabKey = 'visual' | 'audio' | 'text' | 'voice';
|
|
6
6
|
export interface ClipConfigPanelCallbacks {
|
|
7
7
|
onTabChange: (tab: ClipConfigPanelTabKey) => void;
|
|
@@ -18,9 +18,12 @@ export interface ClipConfigPanelCallbacks {
|
|
|
18
18
|
}
|
|
19
19
|
export interface ClipConfigPanelViewModel {
|
|
20
20
|
clip: Clip | null;
|
|
21
|
+
selectionState: ClipConfigPanelSelectionState;
|
|
21
22
|
activeTab: ClipConfigPanelTabKey;
|
|
23
|
+
availableTabs: ClipConfigPanelTabKey[];
|
|
22
24
|
theme: ClipConfigPanelTheme;
|
|
23
|
-
|
|
25
|
+
emptyStateMessage: string | null;
|
|
26
|
+
isTextContentEditable: boolean;
|
|
24
27
|
loadingIconSvg: string;
|
|
25
28
|
selectedIconSvg: string;
|
|
26
29
|
textDraftContent: string;
|
|
@@ -107,7 +110,6 @@ export declare class ClipConfigPanelRenderer extends LitDomRenderer<ClipConfigPa
|
|
|
107
110
|
private renderLabeledNumberInput;
|
|
108
111
|
private getContainerStyle;
|
|
109
112
|
private getSliderStyle;
|
|
110
|
-
private getAvailableTabs;
|
|
111
113
|
private supportsVoicePanel;
|
|
112
114
|
private getTransform;
|
|
113
115
|
private calculatePresetPosition;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import Konva from 'konva';
|
|
2
2
|
import { Clip as ClipType, ClipStateUpdate, TrackConfig, TimeMs, Theme, TrackType } from '../../core/models';
|
|
3
|
-
import { type TrackPointerOperation } from './trackInteractionState';
|
|
4
3
|
import type { MultiDragMoveRequest } from '../../core/tracks/timelineTrackBridge';
|
|
5
4
|
export declare class Track {
|
|
6
5
|
private static readonly DEFAULT_DRAG_ACTIVATION_THRESHOLD;
|
|
@@ -28,7 +27,6 @@ export declare class Track {
|
|
|
28
27
|
private multiDragOriginalPositions;
|
|
29
28
|
private promotedClipParents;
|
|
30
29
|
private interactionState;
|
|
31
|
-
private legacyInteractionSnapshot?;
|
|
32
30
|
private isVisualUpdate;
|
|
33
31
|
private onClipUpdate;
|
|
34
32
|
private onClipAdd;
|
|
@@ -58,37 +56,8 @@ export declare class Track {
|
|
|
58
56
|
private handleGlobalPointerMove;
|
|
59
57
|
private handleGlobalPointerEnd;
|
|
60
58
|
private handleWindowBlur;
|
|
61
|
-
get hasDragMoved(): boolean;
|
|
62
|
-
set hasDragMoved(value: boolean);
|
|
63
|
-
get activePointerOperation(): TrackPointerOperation | null;
|
|
64
|
-
set activePointerOperation(value: TrackPointerOperation | null);
|
|
65
|
-
get originalClipsState(): ClipType[];
|
|
66
|
-
set originalClipsState(value: ClipType[]);
|
|
67
|
-
get nonDraggedClips(): ClipType[];
|
|
68
|
-
set nonDraggedClips(value: ClipType[]);
|
|
69
|
-
get snapCandidateClips(): ClipType[];
|
|
70
|
-
set snapCandidateClips(value: ClipType[]);
|
|
71
|
-
get dragStartY(): number;
|
|
72
|
-
set dragStartY(value: number);
|
|
73
|
-
get dragTargetTrackY(): number;
|
|
74
|
-
set dragTargetTrackY(value: number);
|
|
75
|
-
get crossTrackDragOffsetY(): number;
|
|
76
|
-
set crossTrackDragOffsetY(value: number);
|
|
77
|
-
get crossTrackDragStartX(): number;
|
|
78
|
-
set crossTrackDragStartX(value: number);
|
|
79
|
-
get dragStartScrollLeft(): number;
|
|
80
|
-
set dragStartScrollLeft(value: number);
|
|
81
|
-
get dragGestureStartClientX(): number | null;
|
|
82
|
-
set dragGestureStartClientX(value: number | null);
|
|
83
|
-
get dragGestureStartClientY(): number | null;
|
|
84
|
-
set dragGestureStartClientY(value: number | null);
|
|
85
|
-
get lastDragClientX(): number | null;
|
|
86
|
-
set lastDragClientX(value: number | null);
|
|
87
|
-
get lastDragClientY(): number | null;
|
|
88
|
-
set lastDragClientY(value: number | null);
|
|
89
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);
|
|
90
60
|
private initClips;
|
|
91
|
-
private getLegacyInteractionSnapshot;
|
|
92
61
|
private ensureDropPreviewGroup;
|
|
93
62
|
private createDropPreviewRect;
|
|
94
63
|
private showDropPreview;
|
|
@@ -113,8 +82,6 @@ export declare class Track {
|
|
|
113
82
|
private finishPointerInteraction;
|
|
114
83
|
private resolveDraggedClipForInteraction;
|
|
115
84
|
private applyInteractionTransition;
|
|
116
|
-
private resolveInteractionState;
|
|
117
|
-
private syncLegacyInteractionMirror;
|
|
118
85
|
private handleClipMoveEnd;
|
|
119
86
|
private updateAllClips;
|
|
120
87
|
private buildAndSendUpdates;
|
|
@@ -166,7 +133,7 @@ export declare class Track {
|
|
|
166
133
|
private buildPreviewClip;
|
|
167
134
|
private constrainResizePreviewToTrackBounds;
|
|
168
135
|
private getResizeLeftBoundaryStart;
|
|
169
|
-
private
|
|
136
|
+
private computeResizeRightPushFollowers;
|
|
170
137
|
private buildResizeLeftPreviewClip;
|
|
171
138
|
private buildResizeRightPreviewClip;
|
|
172
139
|
private applyClipSnap;
|
|
@@ -22,6 +22,8 @@ export interface TimelinePreviewBackendCallbacks {
|
|
|
22
22
|
onAspectRatioChange?: (aspectRatio: PreviewAspectRatio) => void;
|
|
23
23
|
onPreviewClipSelect?: (clipId: string) => void;
|
|
24
24
|
onVisualTransformCommit?: (clipId: string, visualTransform: ClipVisualTransform) => void;
|
|
25
|
+
onTextFontSizeCommit?: (clipId: string, fontSize: number) => void;
|
|
26
|
+
onTextRotationCommit?: (clipId: string, rotation: number) => void;
|
|
25
27
|
onPendingPreviewRetry?: () => void;
|
|
26
28
|
onRuntimeError?: (error: unknown) => void;
|
|
27
29
|
}
|
|
@@ -6,15 +6,24 @@ export interface PreviewTransformOverlayState {
|
|
|
6
6
|
frameSize: PreviewFrameSize;
|
|
7
7
|
baseRect: PreviewRect;
|
|
8
8
|
displayRect: PreviewRect;
|
|
9
|
+
clipType?: 'text' | 'video';
|
|
10
|
+
currentFontSize?: number;
|
|
11
|
+
currentRotation?: number;
|
|
9
12
|
}
|
|
10
13
|
interface PreviewTransformOverlayCallbacks {
|
|
11
14
|
onPreviewTransformChange?: (clipId: string, transform: ClipVisualTransform | null) => void;
|
|
12
15
|
onPreviewTransformCommit?: (clipId: string, transform: ClipVisualTransform) => void;
|
|
16
|
+
onFontSizeChange?: (clipId: string, fontSize: number | null) => void;
|
|
17
|
+
onFontSizeCommit?: (clipId: string, fontSize: number) => void;
|
|
18
|
+
onRotationChange?: (clipId: string, rotation: number | null) => void;
|
|
19
|
+
onRotationCommit?: (clipId: string, rotation: number) => void;
|
|
13
20
|
}
|
|
14
21
|
export declare class PreviewTransformOverlay {
|
|
15
22
|
private frameElement;
|
|
16
23
|
private overlayElement;
|
|
17
24
|
private boxElement;
|
|
25
|
+
private rotateHandleElement;
|
|
26
|
+
private rotateHandlePointerDownHandler;
|
|
18
27
|
private readonly handleElements;
|
|
19
28
|
private readonly handlePointerDownHandlers;
|
|
20
29
|
private state;
|
|
@@ -28,6 +37,8 @@ export declare class PreviewTransformOverlay {
|
|
|
28
37
|
attach(frameElement: HTMLElement): void;
|
|
29
38
|
detach(): void;
|
|
30
39
|
sync(state: PreviewTransformOverlayState | null): void;
|
|
40
|
+
private createRotateHandle;
|
|
41
|
+
private getRotateHandlePointerDown;
|
|
31
42
|
private createHandle;
|
|
32
43
|
private readonly handleMovePointerDown;
|
|
33
44
|
private getHandlePointerDown;
|
|
@@ -3,6 +3,7 @@ export interface TimelineClipConfigControllerConfig {
|
|
|
3
3
|
container: HTMLElement;
|
|
4
4
|
theme: Theme;
|
|
5
5
|
getPrimarySelectedClip: () => Clip | null;
|
|
6
|
+
getSelectedClips: () => Clip[];
|
|
6
7
|
voiceCatalog: VoiceOption[];
|
|
7
8
|
updateClip: (clipId: string, updates: Partial<Clip>) => void;
|
|
8
9
|
onGenerateVoice?: (clip: Clip, voice: VoiceOption, followTextUpdates: boolean) => Promise<void>;
|
|
@@ -10,6 +11,7 @@ export interface TimelineClipConfigControllerConfig {
|
|
|
10
11
|
export declare class TimelineClipConfigController {
|
|
11
12
|
private panel;
|
|
12
13
|
private config;
|
|
14
|
+
private currentSelectionState;
|
|
13
15
|
private isInternalUpdate;
|
|
14
16
|
init(config: TimelineClipConfigControllerConfig): void;
|
|
15
17
|
update(): void;
|
|
@@ -17,5 +19,7 @@ export declare class TimelineClipConfigController {
|
|
|
17
19
|
destroy(): void;
|
|
18
20
|
setPreferredTab(tab: 'voice' | null): void;
|
|
19
21
|
setVoiceGenerationBusy(isBusy: boolean): void;
|
|
22
|
+
private buildSelectionState;
|
|
23
|
+
private resolveUpdateTargets;
|
|
20
24
|
private convertTheme;
|
|
21
25
|
}
|
|
@@ -11,6 +11,8 @@ interface TimelinePreviewSessionCallbacks {
|
|
|
11
11
|
onAspectRatioChange?: (aspectRatio: PreviewAspectRatio) => void;
|
|
12
12
|
onPreviewClipSelect?: (clipId: string) => void;
|
|
13
13
|
onVisualTransformCommit?: (clipId: string, visualTransform: ClipVisualTransform) => void;
|
|
14
|
+
onTextFontSizeCommit?: (clipId: string, fontSize: number) => void;
|
|
15
|
+
onTextRotationCommit?: (clipId: string, rotation: number) => void;
|
|
14
16
|
onPendingPreviewRetry?: () => void;
|
|
15
17
|
}
|
|
16
18
|
interface TimelinePreviewSessionDependencies {
|
|
@@ -59,6 +61,8 @@ export declare class TimelinePreviewSession {
|
|
|
59
61
|
private lastSettledSyncRequestId;
|
|
60
62
|
private primarySelectedClipId;
|
|
61
63
|
private transientVisualTransform;
|
|
64
|
+
private transientFontSize;
|
|
65
|
+
private transientRotation;
|
|
62
66
|
private textPreviewDragState;
|
|
63
67
|
private textPreviewFontStyleElement;
|
|
64
68
|
private textPreviewFontSignature;
|
|
@@ -81,6 +81,7 @@ export declare class TimelineManager {
|
|
|
81
81
|
private lastSteadyPlaybackPreviewSyncAt;
|
|
82
82
|
private previewSyncInteractionMode;
|
|
83
83
|
private readonly resourceCacheManager;
|
|
84
|
+
private voiceLinkedTextRegenerationTimer;
|
|
84
85
|
constructor(config?: Partial<TimelineConfig>);
|
|
85
86
|
private createPlaybackAttemptId;
|
|
86
87
|
private refreshPlaybackAttempt;
|
|
@@ -176,7 +177,6 @@ export declare class TimelineManager {
|
|
|
176
177
|
removeTrack(trackId: string): boolean;
|
|
177
178
|
renameTrack(trackId: string, newName: string): boolean;
|
|
178
179
|
getTracks(): any[];
|
|
179
|
-
initTrackInfoPanel(container: HTMLElement): void;
|
|
180
180
|
updateTrackInfoPanel(): void;
|
|
181
181
|
muteTrack(trackId: string, isMuted: boolean): boolean;
|
|
182
182
|
isTrackMuted(trackId: string): boolean;
|
|
@@ -357,6 +357,7 @@ export declare class TimelineManager {
|
|
|
357
357
|
private relocateClipIfNeeded;
|
|
358
358
|
private regenerateVoiceLinkedAudioClips;
|
|
359
359
|
private getSelectedTextClipsForVoiceGeneration;
|
|
360
|
+
private getSelectedTtsAudioClipsForVoiceGeneration;
|
|
360
361
|
private handleVoiceGenerateAction;
|
|
361
362
|
private primeOrLoadClipThumbnails;
|
|
362
363
|
private markClipThumbnailLoadCompleted;
|
|
@@ -575,5 +576,7 @@ export declare class TimelineManager {
|
|
|
575
576
|
private resolveSelectedClipSnapshot;
|
|
576
577
|
private resolveSelectionChangeData;
|
|
577
578
|
private commitPreviewVisualTransform;
|
|
579
|
+
private commitPreviewTextFontSize;
|
|
580
|
+
private commitPreviewTextRotation;
|
|
578
581
|
clearAllTracksAndClips(): void;
|
|
579
582
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Theme } from '../models/types';
|
|
2
2
|
import { type TimelineManagerLayoutElements } from './TimelineManagerLayoutRenderer';
|
|
3
|
-
export declare const TIMELINE_MANAGER_LEFT_PANEL_WIDTH =
|
|
3
|
+
export declare const TIMELINE_MANAGER_LEFT_PANEL_WIDTH = 80;
|
|
4
4
|
export declare const TIMELINE_MANAGER_SCROLLBAR_SIZE = 8;
|
|
5
5
|
export type { TimelineManagerLayoutElements };
|
|
6
6
|
export interface CreateTimelineManagerLayoutOptions {
|