@linker-design-plus/timeline-track 2.0.10 → 2.0.11

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
@@ -190,3 +190,4 @@ pnpm exec tsc -p tsconfig.json --noEmit
190
190
  - [docs/interaction-model.md](./docs/interaction-model.md): 指针交互分层和拖拽约束
191
191
  - [docs/refactor-roadmap.md](./docs/refactor-roadmap.md): 主线重构归档与后续收敛方向
192
192
  - [docs/maintenance-audit.md](./docs/maintenance-audit.md): 本轮仓库审计、验证结果和依赖建议
193
+ - [docs/review-remediation-plan.md](./docs/review-remediation-plan.md): 基于审查结论的修复计划与阶段性落地建议
@@ -19,52 +19,39 @@ export interface ClipConfigPanelConfig {
19
19
  theme?: ClipConfigPanelTheme;
20
20
  onClipUpdate?: (clipId: string, updates: Partial<Clip>) => void;
21
21
  }
22
+ export declare const CSS_CLASSES: {
23
+ readonly container: "clip-config-panel";
24
+ readonly tabBar: "clip-config-tab-bar";
25
+ readonly tabButton: "clip-config-tab-button";
26
+ readonly content: "clip-config-content";
27
+ readonly visualPanel: "clip-config-visual-panel";
28
+ readonly audioPanel: "clip-config-audio-panel";
29
+ readonly actionBar: "clip-config-action-bar";
30
+ readonly section: "clip-config-section";
31
+ readonly sectionTitle: "clip-config-section-title";
32
+ readonly row: "clip-config-row";
33
+ readonly label: "clip-config-label";
34
+ readonly slider: "clip-config-slider";
35
+ readonly input: "clip-config-input";
36
+ readonly presetGrid: "clip-config-preset-grid";
37
+ readonly presetButton: "clip-config-preset-button";
38
+ readonly resetButton: "clip-config-reset-button";
39
+ readonly emptyState: "clip-config-empty-state";
40
+ };
22
41
  export declare class ClipConfigPanel {
23
- private container;
24
- private rootElement;
25
- private theme;
26
- private onClipUpdate?;
42
+ private readonly container;
43
+ private readonly theme;
44
+ private readonly renderer;
45
+ private readonly onClipUpdate?;
27
46
  private currentClip;
28
47
  private activeTab;
29
- private iconCache;
30
- private tabBar;
31
- private contentArea;
32
- private visualPanel;
33
- private audioPanel;
34
- private xSlider;
35
- private xInput;
36
- private ySlider;
37
- private yInput;
38
- private scaleSlider;
39
- private scaleInput;
40
- private volumeSlider;
41
- private volumeInput;
48
+ private readonly iconCache;
42
49
  constructor(config: ClipConfigPanelConfig);
43
50
  setClip(clip: Clip | null): void;
44
51
  destroy(): void;
45
- private getAvailableTabs;
46
52
  private render;
47
- private applyBaseTheme;
48
- private renderEmptyState;
49
- private renderPanel;
50
- private renderTabBar;
51
- private updateTabBarState;
52
- private renderContentArea;
53
- private updateContentVisibility;
54
- private renderVisualPanel;
55
- private renderAudioPanel;
56
- private renderActionBar;
57
- private renderPositionControl;
58
- private renderPresetGrid;
59
- private calculatePresetPosition;
60
- private renderScaleControl;
61
- private renderVolumeControl;
62
53
  private handleVolumeChange;
63
- private updateVolumeControls;
64
54
  private clampValue;
65
- private updateUIControls;
66
- private updateSliderAndInput;
67
- private updateSliderVisual;
68
55
  private handleTransformChange;
69
56
  private handleTransformChanges;
70
57
  }
@@ -0,0 +1,58 @@
1
+ import { type TemplateResult } from 'lit';
2
+ import type { Clip } from '../../core/models';
3
+ import { LitDomRenderer } from '../../core/renderers/domRenderer';
4
+ import type { ClipConfigPanelTheme } from './ClipConfigPanel';
5
+ export type ClipConfigPanelTabKey = 'visual' | 'audio';
6
+ export interface ClipConfigPanelCallbacks {
7
+ onTabChange: (tab: ClipConfigPanelTabKey) => void;
8
+ onTransformChange: (property: 'x' | 'y' | 'scale', value: number) => void;
9
+ onPresetSelect: (x: number, y: number) => void;
10
+ onVolumeChange: (value: number) => void;
11
+ }
12
+ export interface ClipConfigPanelViewModel {
13
+ clip: Clip | null;
14
+ activeTab: ClipConfigPanelTabKey;
15
+ theme: ClipConfigPanelTheme;
16
+ emptyStateIconSvg: string;
17
+ callbacks: ClipConfigPanelCallbacks;
18
+ }
19
+ export declare const CLIP_CONFIG_CSS_CLASSES: {
20
+ readonly container: "clip-config-panel";
21
+ readonly tabBar: "clip-config-tab-bar";
22
+ readonly tabButton: "clip-config-tab-button";
23
+ readonly content: "clip-config-content";
24
+ readonly visualPanel: "clip-config-visual-panel";
25
+ readonly audioPanel: "clip-config-audio-panel";
26
+ readonly actionBar: "clip-config-action-bar";
27
+ readonly section: "clip-config-section";
28
+ readonly sectionTitle: "clip-config-section-title";
29
+ readonly row: "clip-config-row";
30
+ readonly label: "clip-config-label";
31
+ readonly slider: "clip-config-slider";
32
+ readonly input: "clip-config-input";
33
+ readonly presetGrid: "clip-config-preset-grid";
34
+ readonly presetButton: "clip-config-preset-button";
35
+ readonly resetButton: "clip-config-reset-button";
36
+ readonly emptyState: "clip-config-empty-state";
37
+ };
38
+ export declare class ClipConfigPanelRenderer extends LitDomRenderer<ClipConfigPanelViewModel> {
39
+ protected renderTemplate(viewModel: ClipConfigPanelViewModel): TemplateResult;
40
+ private renderEmptyState;
41
+ private renderPanel;
42
+ private renderTabBar;
43
+ private renderVisualPanel;
44
+ private renderPositionSection;
45
+ private renderScaleSection;
46
+ private renderAudioPanel;
47
+ private renderPositionControl;
48
+ private renderPresetGrid;
49
+ private renderSectionTitle;
50
+ private renderRangeInput;
51
+ private renderNumberInput;
52
+ private getContainerStyle;
53
+ private getSliderStyle;
54
+ private getAvailableTabs;
55
+ private getTransform;
56
+ private calculatePresetPosition;
57
+ private resizeSvg;
58
+ }
@@ -20,8 +20,9 @@ export declare class TrackInfoPanel {
20
20
  private width;
21
21
  private timeScaleHeight;
22
22
  private includeTimeScaleSpacer;
23
- private trackList;
24
- private iconCache;
23
+ private scrollTop;
24
+ private readonly renderer;
25
+ private readonly iconCache;
25
26
  private onMuteTrack?;
26
27
  constructor(config: TrackInfoPanelConfig, _onRenameTrack?: (trackId: string, newName: string) => void, _onDeleteTrack?: (trackId: string) => void, onMuteTrack?: (trackId: string, isMuted: boolean) => void);
27
28
  private init;
@@ -29,6 +30,5 @@ export declare class TrackInfoPanel {
29
30
  getTracks(): Track[];
30
31
  render(): void;
31
32
  setScrollTop(scrollTop: number): void;
32
- private createTrackItem;
33
33
  destroy(): void;
34
34
  }
@@ -0,0 +1,30 @@
1
+ import { type TemplateResult } from 'lit';
2
+ import { Track } from '../../core/models';
3
+ import { LitDomRenderer } from '../../core/renderers/domRenderer';
4
+ export interface TrackInfoPanelTheme {
5
+ background: string;
6
+ border: string;
7
+ text: string;
8
+ buttonBackground: string;
9
+ buttonHover: string;
10
+ buttonDanger: string;
11
+ }
12
+ export interface TrackInfoPanelViewModel {
13
+ tracks: Track[];
14
+ scrollTop: number;
15
+ theme: TrackInfoPanelTheme;
16
+ timeScaleHeight: number;
17
+ includeTimeScaleSpacer: boolean;
18
+ onMuteTrack?: (trackId: string, isMuted: boolean) => void;
19
+ icons: {
20
+ videoTrack: string;
21
+ audioTrack: string;
22
+ volume: string;
23
+ volumeMuted: string;
24
+ };
25
+ }
26
+ export declare class TrackInfoPanelRenderer extends LitDomRenderer<TrackInfoPanelViewModel> {
27
+ protected renderTemplate(viewModel: TrackInfoPanelViewModel): TemplateResult;
28
+ private renderTrackItem;
29
+ private resizeSvg;
30
+ }
@@ -61,6 +61,7 @@ export type TrackPlacementCommandResult = {
61
61
  status: 'create_track';
62
62
  trackType: TrackType;
63
63
  suggestedTrackName: string;
64
+ insertionPlacement: TrackInsertionPlacement;
64
65
  };
65
66
  export type CrossTrackMoveCommandResult = {
66
67
  status: 'missing_target_track_by_position';
@@ -1,4 +1,5 @@
1
1
  import type { ActiveClipPlaybackInfo, Clip, ClipVisualTransform, PlayState, PreviewAspectRatio, PreviewMediaSource, PreviewSourceResolver, TimeMs } from '../models/types';
2
+ import type { SourceMediaRegistry } from '../resources/sourceMediaRegistry';
2
3
  export interface TimelinePreviewSyncPayload {
3
4
  activeClips: ActiveClipPlaybackInfo[];
4
5
  nextClips: ActiveClipPlaybackInfo[];
@@ -66,6 +67,7 @@ export interface PreviewBackendClockState {
66
67
  export interface TimelinePreviewBackendOptions {
67
68
  callbacks?: TimelinePreviewBackendCallbacks;
68
69
  previewSourceResolver?: PreviewSourceResolver;
70
+ sourceMediaRegistry?: SourceMediaRegistry;
69
71
  rootClassName?: string;
70
72
  frameClassName?: string;
71
73
  slotClassNamePrefix?: string;
@@ -0,0 +1,17 @@
1
+ import type { PreviewPendingState, PreviewRuntimeState } from './previewBackend';
2
+ import type { DomRenderer } from '../renderers/domRenderer';
3
+ export interface PreviewPendingOverlayViewModel {
4
+ pendingState: PreviewPendingState | null;
5
+ runtimeState: PreviewRuntimeState;
6
+ }
7
+ export declare class PreviewPendingOverlayRenderer implements DomRenderer<PreviewPendingOverlayViewModel> {
8
+ private container;
9
+ private statusElement;
10
+ private detailElement;
11
+ private actionElement;
12
+ private readonly onRetry;
13
+ constructor(onRetry: () => void);
14
+ mount(container: HTMLElement): void;
15
+ update(viewModel: PreviewPendingOverlayViewModel): void;
16
+ destroy(): void;
17
+ }
@@ -1,6 +1,7 @@
1
1
  import type { Clip, PlayState } from '../models/types';
2
2
  export interface ClipMutationEffectHandlers {
3
3
  notifySelectionChange: () => void;
4
+ emitSelectionChangeEvent?: () => void;
4
5
  emitSelectedClipChangeIfNeeded: () => void;
5
6
  handleClipChange: () => void;
6
7
  checkTrackDurationChange?: () => void;
@@ -1,4 +1,5 @@
1
1
  import type { ActiveClipPlaybackInfo, ClipVisualTransform, PlayState, PreviewAspectRatio, PreviewSourceResolver, TimeMs, TrackType } from '../models/types';
2
+ import type { SourceMediaRegistry } from '../resources/sourceMediaRegistry';
2
3
  import type { PreviewPendingState, PreviewRuntimeState } from './previewBackend';
3
4
  interface TimelinePreviewSessionCallbacks {
4
5
  onBufferingStateChange?: (isBuffering: boolean) => void;
@@ -17,6 +18,7 @@ interface TimelinePreviewSessionDependencies {
17
18
  frameClassName?: string;
18
19
  slotClassNamePrefix?: string;
19
20
  previewSourceResolver?: PreviewSourceResolver;
21
+ sourceMediaRegistry?: SourceMediaRegistry;
20
22
  }
21
23
  export interface TimelinePreviewSyncPayload {
22
24
  activeClips: ActiveClipPlaybackInfo[];
@@ -34,9 +36,7 @@ export declare class TimelinePreviewSession {
34
36
  private rootElement;
35
37
  private frameElement;
36
38
  private pendingOverlayElement;
37
- private pendingOverlayStatusElement;
38
- private pendingOverlayDetailElement;
39
- private pendingOverlayActionElement;
39
+ private readonly pendingOverlayRenderer;
40
40
  private resizeObserver;
41
41
  private readonly trackSlots;
42
42
  private audioContext;
@@ -96,6 +96,7 @@ export declare class TimelinePreviewSession {
96
96
  private updateFrameLayout;
97
97
  private maybeResolveAutoAspectRatio;
98
98
  private resolveAspectRatioProbeSource;
99
+ private buildPreviewSourceCacheKey;
99
100
  private getAspectRatioProbe;
100
101
  private tryResolveAutoAspectRatioFromSlot;
101
102
  private handleResolvedAutoAspectRatio;
@@ -1,4 +1,4 @@
1
- import type { Clip } from '../models/types';
1
+ import type { Clip, SelectedClipAudioAction, SelectionChangeData } from '../models/types';
2
2
  export interface SelectedClipSnapshot {
3
3
  clip: Clip | null;
4
4
  hasSelectedClip: boolean;
@@ -7,11 +7,17 @@ interface ResolveSelectedClipOptions {
7
7
  getPrimarySelectedClip: () => Clip | null;
8
8
  findFallbackSelectedClip?: () => Clip | null;
9
9
  }
10
+ interface ResolveSelectionChangeOptions extends ResolveSelectedClipOptions {
11
+ getSelectedClipIds: () => string[];
12
+ canSplitSelectedClip: () => boolean;
13
+ getSelectedClipAudioAction: () => SelectedClipAudioAction;
14
+ }
10
15
  interface EmitSelectedClipChangeOptions {
11
16
  lastSelectedClipId: string | null;
12
17
  resolveSelectedClip: () => SelectedClipSnapshot;
13
18
  emitSelectedClipChange: (payload: SelectedClipSnapshot) => void;
14
19
  }
15
20
  export declare function resolveSelectedClipSnapshot(options: ResolveSelectedClipOptions): SelectedClipSnapshot;
21
+ export declare function resolveSelectionChangeData(options: ResolveSelectionChangeOptions): SelectionChangeData;
16
22
  export declare function emitSelectedClipChangeIfNeeded(options: EmitSelectedClipChangeOptions): string | null;
17
23
  export {};
@@ -1,8 +1,8 @@
1
1
  import type { MoveClipToTrackCommandResult, RemoveClipCommandResult, TrackPlacementCommandResult } from '../commands/timelineCommands';
2
- import type { Clip, TrackType } from '../models/types';
2
+ import type { Clip, TrackInsertionPlacement, TrackType } from '../models/types';
3
3
  import type { TimelineTrackCollection } from '../tracks/timelineTrackCollection';
4
4
  interface CreateTrackHandler {
5
- (type: TrackType, name?: string): string;
5
+ (type: TrackType, name?: string, insertionPlacement?: TrackInsertionPlacement, referenceTrackId?: string): string;
6
6
  }
7
7
  interface ApplyClipPlacementOptions {
8
8
  clip: Clip;
@@ -1,5 +1,5 @@
1
1
  import { type TimelinePreviewBackend } from '../controllers';
2
- import { TimelineConfig, Clip, ClipConfig, TimeMs, PlayState, Action, TimelineEvent, EventListener as TimelineEventListener, TimelineExportData, Track as TrackEntity, ThumbnailProvider, TrackInsertionPlacement, TrackType, ActiveClipPlaybackInfo, PreviewAspectRatio, PreviewMountConfig, PreviewBackendType } from '../models';
2
+ import { TimelineConfig, Clip, ClipConfig, TimeMs, PlayState, Action, TimelineEvent, EventListener as TimelineEventListener, TimelineExportData, Track as TrackEntity, ThumbnailProvider, TrackInsertionPlacement, TrackType, ActiveClipPlaybackInfo, PreviewAspectRatio, PreviewMountConfig, PreviewBackendType, SelectedClipAudioAction } from '../models';
3
3
  import type { ResolvedPlaybackPlan } from '../controllers/timelinePlaybackResolver';
4
4
  import { TimelineClipConfigController } from '../controllers/timelineClipConfigController';
5
5
  export declare class TimelineManager {
@@ -38,8 +38,10 @@ export declare class TimelineManager {
38
38
  private verticalScrollbar;
39
39
  private isExecutingHistoryAction;
40
40
  private lastTrackDuration;
41
- private lastEffectiveTrackDuration;
41
+ private lastReportedTrackDuration;
42
42
  private thumbnailProvider;
43
+ private clipThumbnailLoadStates;
44
+ private sourceMediaRegistry;
43
45
  private canPlay;
44
46
  private sourceLoadingCount;
45
47
  private timelineStore?;
@@ -64,6 +66,7 @@ export declare class TimelineManager {
64
66
  private selectionStore;
65
67
  private multiDragSession;
66
68
  private clipRemovalBatchDepth;
69
+ private splitOperationDepth;
67
70
  constructor(config?: Partial<TimelineConfig>);
68
71
  private getTimelineStore;
69
72
  private getTimelineCommands;
@@ -261,6 +264,9 @@ export declare class TimelineManager {
261
264
  * 批量添加片段。批量模式下仅维护一段连续的视频源加载状态。
262
265
  */
263
266
  addClips(clipConfigs: ClipConfig[]): Promise<string[]>;
267
+ private resolveBatchClipConfig;
268
+ private resolveBatchAppendTrackId;
269
+ private getTrackTimelineExtentById;
264
270
  private addClipInternal;
265
271
  removeClip(clipId: string): void;
266
272
  removeClipsByExternalId(externalId: string): boolean;
@@ -269,6 +275,7 @@ export declare class TimelineManager {
269
275
  splitCurrentClip(): void;
270
276
  getClips(): Clip[];
271
277
  private getExportComposition;
278
+ private getExportCoverUrl;
272
279
  exportTimeline(): TimelineExportData;
273
280
  importTimeline(data: TimelineExportData): Promise<void>;
274
281
  private resolveImportedTrackRoles;
@@ -304,6 +311,14 @@ export declare class TimelineManager {
304
311
  * 更新 canPlay 状态
305
312
  */
306
313
  private updateCanPlayState;
314
+ private findClipById;
315
+ private primeOrLoadClipThumbnails;
316
+ private markClipThumbnailLoadCompleted;
317
+ private buildClipThumbnailLoadSignature;
318
+ private buildSourceMediaKey;
319
+ private buildClipThumbnailResourceKey;
320
+ private isClipThumbnailLoadCurrent;
321
+ private areThumbnailArraysEqual;
307
322
  private handleClipSplit;
308
323
  private handleClipSelect;
309
324
  private handleActionUndo;
@@ -379,7 +394,8 @@ export declare class TimelineManager {
379
394
  getPrimarySelectedClip(): Clip | null;
380
395
  getSelectedClips(): Clip[];
381
396
  canDeleteSelectedClips(): boolean;
382
- getSelectedClipAudioAction(): 'separate' | 'restore' | null;
397
+ canSplitSelectedClip(): boolean;
398
+ getSelectedClipAudioAction(): SelectedClipAudioAction;
383
399
  canToggleSelectedClipsAudio(): boolean;
384
400
  toggleSelectedClipsAudio(): Promise<boolean>;
385
401
  getCurrentActiveClips(): ActiveClipPlaybackInfo[];
@@ -418,8 +434,8 @@ export declare class TimelineManager {
418
434
  moveClipToTrack(clipId: string, targetTrackId: string): boolean;
419
435
  private moveClipToTrackWithHistorySnapshot;
420
436
  /**
421
- * 获取轨道内的有效总时长(去除首尾空白)
422
- * @returns 最早 clip 起点到最晚 clip 终点的时长(毫秒)
437
+ * 获取时间轴总时长
438
+ * @returns 0 到最后一个音视频 clip 终点的时长(毫秒)
423
439
  */
424
440
  getTrackTotalDuration(): TimeMs;
425
441
  destroy(): void;
@@ -427,6 +443,7 @@ export declare class TimelineManager {
427
443
  clearHistory(): void;
428
444
  private handleClipChange;
429
445
  private withClipRemovalBatch;
446
+ private withSplitOperation;
430
447
  private resolveClipIdsForExternalIdRemoval;
431
448
  private shouldClearSelectionForClipIds;
432
449
  private resolveSelectedClipAtTime;
@@ -479,6 +496,7 @@ export declare class TimelineManager {
479
496
  */
480
497
  private checkTrackDurationChange;
481
498
  private resolveSelectedClipSnapshot;
499
+ private resolveSelectionChangeData;
482
500
  private commitPreviewVisualTransform;
483
501
  clearAllTracksAndClips(): void;
484
502
  }
@@ -0,0 +1,25 @@
1
+ import type { Theme } from '../models/types';
2
+ export interface TimelineManagerLayoutElements {
3
+ headerCorner: HTMLDivElement;
4
+ headerViewport: HTMLDivElement;
5
+ headerCanvasHost: HTMLDivElement;
6
+ trackInfoViewport: HTMLDivElement;
7
+ bodyViewport: HTMLDivElement;
8
+ bodyCanvasHost: HTMLDivElement;
9
+ verticalScrollbarCanvasHost: HTMLDivElement;
10
+ horizontalScrollbarCanvasHost: HTMLDivElement;
11
+ playheadOverlay: HTMLDivElement;
12
+ }
13
+ export interface CreateTimelineManagerLayoutOptions {
14
+ theme: Theme;
15
+ timeScaleHeight: number;
16
+ leftPanelWidth: number;
17
+ scrollbarSize: number;
18
+ }
19
+ export declare class TimelineManagerLayoutRenderer {
20
+ private container;
21
+ mount(container: HTMLElement, options: CreateTimelineManagerLayoutOptions): TimelineManagerLayoutElements;
22
+ destroy(): void;
23
+ private renderTemplate;
24
+ private requireElement;
25
+ }
@@ -1,17 +1,8 @@
1
1
  import type { Theme } from '../models/types';
2
+ import { type TimelineManagerLayoutElements } from './TimelineManagerLayoutRenderer';
2
3
  export declare const TIMELINE_MANAGER_LEFT_PANEL_WIDTH = 200;
3
4
  export declare const TIMELINE_MANAGER_SCROLLBAR_SIZE = 8;
4
- export interface TimelineManagerLayoutElements {
5
- headerCorner: HTMLDivElement;
6
- headerViewport: HTMLDivElement;
7
- headerCanvasHost: HTMLDivElement;
8
- trackInfoViewport: HTMLDivElement;
9
- bodyViewport: HTMLDivElement;
10
- bodyCanvasHost: HTMLDivElement;
11
- verticalScrollbarCanvasHost: HTMLDivElement;
12
- horizontalScrollbarCanvasHost: HTMLDivElement;
13
- playheadOverlay: HTMLDivElement;
14
- }
5
+ export type { TimelineManagerLayoutElements };
15
6
  export interface CreateTimelineManagerLayoutOptions {
16
7
  theme: Theme;
17
8
  timeScaleHeight: number;
@@ -347,6 +347,16 @@ export interface SelectedClipChangeData {
347
347
  clip: Clip | null;
348
348
  hasSelectedClip: boolean;
349
349
  }
350
+ export type SelectedClipAudioAction = 'separate' | 'restore' | null;
351
+ export interface SelectionChangeData {
352
+ clip: Clip | null;
353
+ hasSelectedClip: boolean;
354
+ selectedClipIds: string[];
355
+ canDeleteSelectedClips: boolean;
356
+ canSplitSelectedClip: boolean;
357
+ selectedClipAudioAction: SelectedClipAudioAction;
358
+ canToggleSelectedClipsAudio: boolean;
359
+ }
350
360
  export interface ClipRemovedEventData {
351
361
  clipId: string;
352
362
  }
@@ -0,0 +1,17 @@
1
+ import { type TemplateResult } from 'lit';
2
+ export interface DomRenderer<TViewModel> {
3
+ mount(container: HTMLElement): void;
4
+ update(viewModel: TViewModel): void;
5
+ destroy(): void;
6
+ }
7
+ export declare abstract class LitDomRenderer<TViewModel> implements DomRenderer<TViewModel> {
8
+ private container;
9
+ private viewModel;
10
+ mount(container: HTMLElement): void;
11
+ update(viewModel: TViewModel): void;
12
+ destroy(): void;
13
+ protected get mountedContainer(): HTMLElement | null;
14
+ protected abstract renderTemplate(viewModel: TViewModel): TemplateResult;
15
+ protected afterRender(_container: HTMLElement, _viewModel: TViewModel): void;
16
+ private renderCurrent;
17
+ }
@@ -0,0 +1,24 @@
1
+ import type { Clip, ClipConfig, PreviewMediaSource } from '../models/types';
2
+ type SourceLike = Pick<Clip, 'src' | 'externalId'> | Pick<ClipConfig, 'src' | 'externalId'>;
3
+ type ThumbnailLike = Pick<Clip, 'src' | 'externalId' | 'startTimeAtSource' | 'endTimeAtSource' | 'duration' | 'type'>;
4
+ export declare class SourceMediaRegistry {
5
+ private readonly durationCache;
6
+ private readonly thumbnailCache;
7
+ private readonly previewSourceCache;
8
+ static buildSourceKey(source: SourceLike): string;
9
+ static buildThumbnailKey(clip: ThumbnailLike): string;
10
+ getDuration(sourceKey: string, loader: () => Promise<number>, options?: {
11
+ force?: boolean;
12
+ }): Promise<number>;
13
+ primeDuration(sourceKey: string, duration: number): void;
14
+ getThumbnails(thumbnailKey: string, loader: () => Promise<string[]>, options?: {
15
+ force?: boolean;
16
+ }): Promise<string[]>;
17
+ primeThumbnails(thumbnailKey: string, thumbnails: string[]): void;
18
+ clearThumbnailCache(): void;
19
+ getPreviewSource(sourceKey: string, loader: () => PreviewMediaSource | null | Promise<PreviewMediaSource | null>, options?: {
20
+ force?: boolean;
21
+ }): PreviewMediaSource | null | Promise<PreviewMediaSource | null>;
22
+ primePreviewSource(sourceKey: string, value: PreviewMediaSource | null): void;
23
+ }
24
+ export {};
@@ -0,0 +1,150 @@
1
+ export declare const SHARED_COLOR_TOKENS: {
2
+ readonly transparent: "transparent";
3
+ readonly white: "#ffffff";
4
+ readonly black: "#000000";
5
+ readonly panelSurface: "#0f0f0f";
6
+ readonly panelSurfaceAlt: "#1e1e1e";
7
+ readonly audioTrackSurface: "#252525";
8
+ readonly buttonSurface: "#2a2a2a";
9
+ readonly inputSurface: "#2d2d2d";
10
+ readonly clipSurface: "#2e2e2e";
11
+ readonly selectedTrackSurface: "#292929";
12
+ readonly borderStrong: "#333333";
13
+ readonly borderMedium: "#444444";
14
+ readonly borderSubtle: "#555555";
15
+ readonly textPrimary: "#ffffff";
16
+ readonly textSecondary: "#e0e0e0";
17
+ readonly textMuted: "#cccccc";
18
+ readonly textSubtle: "#aaaaaa";
19
+ readonly textHint: "#999999";
20
+ readonly textAudio: "#d0d0d0";
21
+ readonly textInactive: "#b5b6bf";
22
+ readonly accentFocus: "#409eff";
23
+ readonly accentSelectedFill: "#b5baff";
24
+ readonly accentSelectedBorder: "#50E3C2";
25
+ readonly accentSelectionBox: "#5082e6";
26
+ readonly accentAction: "#4c8dff";
27
+ readonly accentDanger: "#dc3545";
28
+ readonly accentPlayheadGrip: "#8c90ff";
29
+ readonly accentCoverFallback: "#FFF2A0";
30
+ readonly accentAudioPreview: "#b5baff";
31
+ readonly activeTabBackground: "#595A5D";
32
+ readonly gridLine: "#E0E0E0";
33
+ readonly playheadMarker: "#FF0000";
34
+ readonly overlayPreview: "rgba(0, 0, 0, 0.56)";
35
+ readonly overlayShadow: "rgba(0, 0, 0, 0.22)";
36
+ readonly overlayTransformHandle: "rgba(80, 227, 194, 0.95)";
37
+ readonly overlaySelectionBoxFill: "rgba(80, 130, 230, 0.15)";
38
+ readonly overlayVideoDropPreview: "rgba(80, 227, 194, 0.18)";
39
+ readonly overlayAudioDropPreview: "rgba(181, 186, 255, 0.18)";
40
+ readonly overlayHitArea: "rgba(0, 0, 0, 0.001)";
41
+ readonly sliderFillStart: "#f6f8ff";
42
+ readonly sliderFillEnd: "#dfe4f2";
43
+ readonly sliderRoad: "rgba(116, 128, 163, 0.26)";
44
+ readonly sliderThumbBorder: "rgba(230, 236, 250, 0.96)";
45
+ readonly sliderThumbGlowStart: "#ffffff";
46
+ readonly sliderThumbGlowEnd: "#eef2fb";
47
+ readonly sliderThumbInnerShadow: "rgba(255, 255, 255, 0.92)";
48
+ readonly sliderThumbShadow: "rgba(8, 24, 56, 0.24)";
49
+ readonly demoSliderThumbShadow: "rgba(8, 24, 56, 0.18)";
50
+ };
51
+ export declare const TIMELINE_DEFAULT_THEME_COLORS: {
52
+ readonly background: "#000000";
53
+ readonly border: "#333333";
54
+ readonly timeTick: "#e0e0e0";
55
+ readonly timeText: "#aaaaaa";
56
+ readonly trackBackground: "#000000";
57
+ readonly trackSelectedBackground: "#292929";
58
+ readonly trackBorder: "#333333";
59
+ readonly clipBackground: "#2e2e2e";
60
+ readonly clipBorder: "#000000";
61
+ readonly clipName: "#ffffff";
62
+ readonly clipDuration: "#cccccc";
63
+ readonly clipHandle: "#ffffff";
64
+ readonly clipSelectedBackground: "#b5baff";
65
+ readonly clipSelectedBorder: "#50E3C2";
66
+ readonly clipSelectedName: "#ffffff";
67
+ readonly clipSelectedDuration: "#ffffff";
68
+ readonly clipSelectedHandle: "#ffffff";
69
+ readonly clipSelectedCoverBackground: "#444444";
70
+ readonly clipCoverBackground: "#333333";
71
+ readonly audioClipBackground: "#252525";
72
+ readonly audioClipText: "#d0d0d0";
73
+ readonly audioClipAccent: "#b8b8c0";
74
+ readonly playhead: "#ffffff";
75
+ readonly grid: "#333333";
76
+ readonly snapGuideLineColor: "#50E3C2";
77
+ readonly scrollbarBackground: "#333333";
78
+ readonly scrollbarBorder: "#555555";
79
+ readonly scrollbarThumb: "#444444";
80
+ };
81
+ export declare const CLIP_CONFIG_PANEL_DEFAULT_THEME: {
82
+ readonly backgroundColor: "#0f0f0f";
83
+ readonly borderColor: "#333333";
84
+ readonly textColor: "#e0e0e0";
85
+ readonly labelColor: "#999999";
86
+ readonly inputBackground: "#2d2d2d";
87
+ readonly inputBorder: "#444444";
88
+ readonly inputFocusBorder: "#409eff";
89
+ readonly buttonBackground: "#2d2d2d";
90
+ readonly buttonBorder: "#444444";
91
+ readonly buttonActiveBackground: "#409eff";
92
+ readonly buttonActiveBorder: "#409eff";
93
+ readonly buttonActiveText: "#ffffff";
94
+ };
95
+ export declare const TRACK_INFO_PANEL_DEFAULT_THEME: {
96
+ readonly background: "#0f0f0f";
97
+ readonly border: "#333333";
98
+ readonly text: "#ffffff";
99
+ readonly buttonBackground: "#2a2a2a";
100
+ readonly buttonHover: "#3a3a3a";
101
+ readonly buttonDanger: "#dc3545";
102
+ };
103
+ export declare const SCROLLBAR_DEFAULT_COLORS: {
104
+ readonly background: "#333333";
105
+ readonly border: "#555555";
106
+ readonly thumb: "#444444";
107
+ readonly hitArea: "rgba(0, 0, 0, 0.001)";
108
+ };
109
+ export declare const KONVA_DEFAULT_COLORS: {
110
+ readonly fill: "#ffffff";
111
+ readonly stroke: "#000000";
112
+ readonly text: "#000000";
113
+ };
114
+ export declare const CLIP_CONFIG_PANEL_RENDERER_COLORS: {
115
+ readonly tabBarBackground: "#2a2a2a";
116
+ readonly actionBarBackground: "#2a2a2a";
117
+ readonly activeTabBackground: "#595A5D";
118
+ readonly activeTabText: "#ffffff";
119
+ readonly inactiveTabText: "#b5b6bf";
120
+ readonly sliderThumbShadow: "0 8px 20px rgba(8, 24, 56, 0.24)";
121
+ readonly sliderThumbInnerShadow: "inset 0 1px 1px rgba(255, 255, 255, 0.92)";
122
+ };
123
+ export declare const PLAYHEAD_DEFAULT_COLORS: {
124
+ readonly grip: "#8c90ff";
125
+ readonly shadow: "rgba(0, 0, 0, 0.22)";
126
+ readonly marker: "#FF0000";
127
+ };
128
+ export declare const PREVIEW_PENDING_OVERLAY_COLORS: {
129
+ readonly background: "rgba(0, 0, 0, 0.56)";
130
+ readonly text: "#ffffff";
131
+ readonly actionBackground: "#4c8dff";
132
+ readonly actionText: "#ffffff";
133
+ };
134
+ export declare const PREVIEW_TRANSFORM_OVERLAY_COLORS: {
135
+ readonly border: "rgba(80, 227, 194, 0.95)";
136
+ readonly handleBackground: "#000000";
137
+ };
138
+ export declare const SELECTION_BOX_COLORS: {
139
+ readonly fill: "rgba(80, 130, 230, 0.15)";
140
+ readonly stroke: "#5082e6";
141
+ };
142
+ export declare const DROP_PREVIEW_COLORS: {
143
+ readonly videoFill: "rgba(80, 227, 194, 0.18)";
144
+ readonly videoStroke: "#50E3C2";
145
+ readonly audioFill: "rgba(181, 186, 255, 0.18)";
146
+ readonly audioStroke: "#b5baff";
147
+ };
148
+ export declare const GRID_DEFAULT_COLORS: {
149
+ readonly line: "#E0E0E0";
150
+ };