@linker-design-plus/timeline-track 2.2.0 → 2.2.2

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.
@@ -27,6 +27,7 @@ export interface TimelinePreviewBackendCallbacks {
27
27
  layoutWidth: number;
28
28
  layoutHeight: number;
29
29
  }) => void;
30
+ onTextLayoutResolved?: (clipId: string, layout: import('../models/types').TextClipResolvedLayout) => void;
30
31
  onPendingPreviewRetry?: () => void;
31
32
  onRuntimeError?: (error: unknown) => void;
32
33
  /** 预览层文字交互(点击字幕或文字变换控件)时若时间线处于播放中,用于请求暂停 */
@@ -349,6 +349,7 @@ export declare class TimelineManager {
349
349
  private clearTimelineClipMediaStatus;
350
350
  private getFailedPreviewClipIds;
351
351
  private getExportComposition;
352
+ private resolveTextClipExportLayout;
352
353
  private getExportCoverUrl;
353
354
  exportTimeline(): TimelineExportData;
354
355
  importTimeline(data: TimelineExportData): Promise<void>;
@@ -641,6 +642,7 @@ export declare class TimelineManager {
641
642
  private resolveSelectionChangeData;
642
643
  private commitPreviewVisualTransform;
643
644
  private commitPreviewTextLayout;
645
+ private commitPreviewTextResolvedLayout;
644
646
  private commitPreviewTextFontSize;
645
647
  private commitPreviewTextRotation;
646
648
  clearAllTracksAndClips(): void;
@@ -32,6 +32,26 @@ export interface TextClipStyle {
32
32
  }
33
33
  export declare const DEFAULT_TEXT_CLIP_STYLE: TextClipStyle;
34
34
  export declare function resolveTextClipStyle(style?: Partial<TextClipStyle> | null): TextClipStyle;
35
+ export type TextClipLayoutMode = 'auto' | 'manual';
36
+ /** 预览层布局完成后的归一化快照,供导出与后端渲染。 */
37
+ export interface TextClipResolvedLayout {
38
+ /** 与 export composition 一致的 baseline 画布尺寸(短边 720)。 */
39
+ compositionWidth: number;
40
+ compositionHeight: number;
41
+ /** 文本框宽(baseline 参考画布 px,非最终成片 px)。 */
42
+ layoutWidth: number;
43
+ /** 文本框高(baseline 参考画布 px,非最终成片 px)。 */
44
+ layoutHeight: number;
45
+ /** layoutWidth / compositionWidth */
46
+ layoutWidthRatio: number;
47
+ /** layoutHeight / compositionHeight */
48
+ layoutHeightRatio: number;
49
+ /** 框中心锚点,画幅归一化 0–1(已从 legacy 底锚迁移)。 */
50
+ centerX: number;
51
+ centerY: number;
52
+ layoutMode: TextClipLayoutMode;
53
+ anchorVersion: 1;
54
+ }
35
55
  export type PreviewBackendType = 'dom' | 'canvas' | 'auto';
36
56
  export interface Mp4PreviewMediaSource {
37
57
  url: string;
@@ -108,6 +128,7 @@ export interface ClipConfig {
108
128
  volume?: number;
109
129
  textContent?: string;
110
130
  textStyle?: Partial<TextClipStyle>;
131
+ textResolvedLayout?: TextClipResolvedLayout;
111
132
  ttsSourceTextClipId?: string;
112
133
  ttsVoiceId?: string;
113
134
  ttsVoiceName?: string;
@@ -136,6 +157,7 @@ export interface ClipEntity {
136
157
  volume?: number;
137
158
  textContent?: string;
138
159
  textStyle?: TextClipStyle;
160
+ textResolvedLayout?: TextClipResolvedLayout;
139
161
  ttsSourceTextClipId?: string;
140
162
  ttsVoiceId?: string;
141
163
  ttsVoiceName?: string;
@@ -518,6 +540,7 @@ export interface TimelineCompositionExportData {
518
540
  height: number;
519
541
  aspectRatio: string;
520
542
  mode: PreviewAspectRatioMode;
543
+ textPreviewFont?: TextPreviewFontConfig;
521
544
  }
522
545
  export interface TrackExportData {
523
546
  id: string;
@@ -548,6 +571,7 @@ export interface ClipExportData {
548
571
  volume?: number;
549
572
  textContent?: string;
550
573
  textStyle?: TextClipStyle;
574
+ textResolvedLayout?: TextClipResolvedLayout;
551
575
  ttsSourceTextClipId?: string;
552
576
  ttsVoiceId?: string;
553
577
  ttsVoiceName?: string;
@@ -22,3 +22,6 @@ export declare function getMediaDebugState(element: HTMLMediaElement): Diagnosti
22
22
  export declare function doesSlotSourceMatchDesired(configuredSource: string | null, assignedSource: string | null, desiredSource: string | null): boolean;
23
23
  export declare function getSlotSeekThresholdSeconds(role: 'current' | 'preload', playbackRate: number): number;
24
24
  export declare function buildPreviewSourceCacheKey(clip: ActiveClipPlaybackInfo['clip']): string;
25
+ export declare function buildObjectUrlHolderId(clipId: string | undefined | null): string | null;
26
+ export declare function isBlobObjectUrl(url: string | null | undefined): url is string;
27
+ export declare function resolveBlobObjectUrl(objectUrl: string | null | undefined, playbackUrl: string): string | null;
@@ -1,13 +1,14 @@
1
1
  import type { ActiveClipPlaybackInfo, PreviewAspectRatio } from '../models/types';
2
2
  import { resolveClipVisualTransform, type PreviewFrameSize } from '../controllers/previewTransformMath';
3
3
  import { PreviewTransformOverlay, type PreviewTransformOverlayState } from '../controllers/previewTransformOverlay';
4
- import { type TextLayoutStyleOverride } from './textPreviewLayout';
4
+ import { type TextLayoutStyleOverride, type TextPreviewBoxLayout } from './textPreviewLayout';
5
5
  import type { PreviewPlaybackSlot } from './previewPlaybackSlot';
6
6
  export declare class PreviewDomCompositor {
7
7
  private container;
8
8
  private rootElement;
9
9
  private frameElement;
10
10
  private resizeObserver;
11
+ private onFrameLayoutChange;
11
12
  private requestedAspectRatio;
12
13
  private resolvedAutoAspectRatio;
13
14
  readonly transformOverlay: PreviewTransformOverlay;
@@ -15,6 +16,7 @@ export declare class PreviewDomCompositor {
15
16
  attach(container: HTMLElement, options: {
16
17
  rootClassName?: string;
17
18
  frameClassName?: string;
19
+ onFrameLayoutChange?: () => void;
18
20
  }): void;
19
21
  detach(): void;
20
22
  getFrameElement(): HTMLDivElement | null;
@@ -29,6 +31,7 @@ export declare class PreviewDomCompositor {
29
31
  entry: ActiveClipPlaybackInfo;
30
32
  element: HTMLElement;
31
33
  } | undefined;
34
+ getLayout?: (clipId: string) => TextPreviewBoxLayout | null;
32
35
  getTransientFontSize: (clipId: string) => number | null;
33
36
  getTransientRotation: (clipId: string) => number | null;
34
37
  getTextLayoutOverride?: (clipId: string) => TextLayoutStyleOverride | null;
@@ -60,6 +60,8 @@ export declare class PreviewEngine {
60
60
  get lastRuntimeState(): PreviewRuntimeState;
61
61
  refreshRuntimeState(): void;
62
62
  private applyTrackPlan;
63
+ private readonly releaseTrackedObjectUrl;
64
+ private rememberSlotObjectUrl;
63
65
  private getTrackSlots;
64
66
  private collectSlots;
65
67
  private buildLoadingState;
@@ -76,6 +78,7 @@ export declare class PreviewEngine {
76
78
  private getTextLayoutOptions;
77
79
  private handlePreviewTransformChange;
78
80
  refreshVisualLayout(): void;
81
+ private refreshTextSelectionOverlay;
79
82
  private refreshPendingOverlay;
80
83
  private syncLoadingProbe;
81
84
  private syncClockProbe;
@@ -21,6 +21,11 @@ export declare class PreviewPlaybackSlot implements PlaybackSlotState {
21
21
  boundStableKey: string | null;
22
22
  desiredSource: string | null;
23
23
  objectUrl: string | null;
24
+ objectUrlHolderId: string | null;
25
+ takeTrackedObjectUrl(): {
26
+ url: string | null;
27
+ holderId: string | null;
28
+ };
24
29
  requestedPlayState: PlayState;
25
30
  isActive: boolean;
26
31
  isLoading: boolean;
@@ -32,6 +37,7 @@ export declare class PreviewPlaybackSlot implements PlaybackSlotState {
32
37
  hasReadyEventSinceSourceChange: boolean;
33
38
  pendingClockAlignmentMediaTime: number | null;
34
39
  sourceGen: number;
40
+ private loadSourceGen;
35
41
  sourceNode: MediaElementAudioSourceNode | null;
36
42
  gainNode: GainNode | null;
37
43
  audioRoutingFailed: boolean;
@@ -48,7 +54,7 @@ export declare class PreviewPlaybackSlot implements PlaybackSlotState {
48
54
  applyPlayback(entry: ActiveClipPlaybackInfo, playState: PlayState, speed: number, visible: boolean, zIndex: number): void;
49
55
  sourceMatchesDesired(): boolean;
50
56
  maybeResumePlayback(reason: 'canplay' | 'seeked' | 'runtime-check'): void;
51
- destroy(releaseObjectUrl: (url: string | null) => void): void;
57
+ destroy(releaseObjectUrl: (url: string | null, holderId: string | null) => void): void;
52
58
  private syncCurrentPlayback;
53
59
  private preparePreload;
54
60
  private setVisible;
@@ -10,7 +10,7 @@ export interface PreviewSourceServiceDependencies {
10
10
  }
11
11
  export declare class PreviewSourceService {
12
12
  private readonly dependencies;
13
- private readonly pendingRuntime;
13
+ private readonly pendingCacheRuntime;
14
14
  constructor(dependencies?: PreviewSourceServiceDependencies);
15
15
  resolve(entry: ActiveClipPlaybackInfo, options: {
16
16
  sourceGen: number;
@@ -18,7 +18,6 @@ export declare class PreviewSourceService {
18
18
  reuse?: ResolvedSlotSource | null;
19
19
  }): Promise<ResolvedSlotSource | null> | ResolvedSlotSource | null;
20
20
  getReusableSource(boundStableKey: string | null, stableSourceUrl: string | null, desiredSource: string | null, objectUrl: string | null, entry: ActiveClipPlaybackInfo): ResolvedSlotSource | null;
21
- revokeObjectUrl(objectUrl: string | null | undefined): void;
22
21
  private resolvePlayable;
23
22
  private normalizeCachedResult;
24
23
  private emit;
@@ -12,7 +12,7 @@ export interface PreviewSyncCoordinatorOptions {
12
12
  onAsyncWorkStarted: () => void;
13
13
  onAsyncWorkFinished: () => void;
14
14
  onStateChange: () => void;
15
- releaseObjectUrl: (url: string | null) => void;
15
+ releaseObjectUrl: (url: string | null, holderId: string | null) => void;
16
16
  rememberObjectUrl: (slot: PreviewPlaybackSlot, url: string | null) => void;
17
17
  configureAudio: (slot: PreviewPlaybackSlot, entry: ActiveClipPlaybackInfo) => void;
18
18
  syncClockAlignment: (slot: PreviewPlaybackSlot, target: PreviewSlotTarget, clipChanged: boolean) => void;
@@ -19,6 +19,7 @@ export declare class PreviewTextLayer {
19
19
  private textPreviewFont;
20
20
  private readonly compositor;
21
21
  private readonly callbacks;
22
+ private autoRemeasureScheduled;
22
23
  constructor(compositor: PreviewDomCompositor, callbacks: PreviewTextLayer['callbacks']);
23
24
  mount(frameElement: HTMLDivElement): HTMLDivElement;
24
25
  destroy(): void;
@@ -36,6 +37,12 @@ export declare class PreviewTextLayer {
36
37
  private reapplyAllContent;
37
38
  private applyBoxLayout;
38
39
  private applyContent;
40
+ private usesManualTextLayout;
41
+ private emitResolvedLayout;
42
+ private finalizeTextBoxLayout;
43
+ private applyManualTextBoxLayout;
44
+ private applyAutoTextBoxLayout;
45
+ private scheduleAutoRemeasure;
39
46
  private getFontFamily;
40
47
  private ensureFontReady;
41
48
  private resetFontState;
@@ -0,0 +1,5 @@
1
+ import type { Clip, TextClipResolvedLayout, TextPreviewFontConfig } from '../models/types';
2
+ export declare function measureTextClipResolvedLayoutForExport(clip: Pick<Clip, 'textContent' | 'textStyle' | 'visualTransform' | 'name'>, composition: {
3
+ width: number;
4
+ height: number;
5
+ }, textPreviewFont?: TextPreviewFontConfig | null): TextClipResolvedLayout | null;
@@ -1,4 +1,4 @@
1
- import type { ClipVisualTransform, TextClipStyle } from '../models/types';
1
+ import type { ClipVisualTransform, TextClipLayoutMode, TextClipResolvedLayout, TextClipStyle } from '../models/types';
2
2
  import { type PreviewFrameSize, type PreviewRect } from '../controllers/previewTransformMath';
3
3
  /** 文本 visualTransform 使用框中心锚点。 */
4
4
  export declare const TEXT_CLIP_ANCHOR_VERSION_CENTER = 1;
@@ -33,8 +33,13 @@ export declare function resolveTextEntryMaxWidthPx(frameWidth: number, baselineS
33
33
  export declare function estimateTextLayoutHeightBaseline(fontSize: number, contentText: string, layoutWidthBaseline: number, paddingX: number): number;
34
34
  export declare function resolveDefaultTextCenterTransform(frameSize: PreviewFrameSize, layoutHeightBaseline: number, baselineScale: number): ClipVisualTransform;
35
35
  export declare function resolveDefaultTextCenterTransformForBaselineFrame(baselineFrameHeight: number, layoutHeightBaseline?: number): ClipVisualTransform;
36
+ export declare function usesLegacyBottomAnchorY(textStyle: TextClipStyle, transformY: number): boolean;
37
+ export declare function resolveTextBoxCenterY(frameSize: PreviewFrameSize, transform: ClipVisualTransform, textStyle: TextClipStyle, displayHeightPx: number): number;
36
38
  export declare function migrateBottomAnchorTransformToCenter(transform: ClipVisualTransform, frameSize: PreviewFrameSize, displayHeightPx: number): ClipVisualTransform;
37
39
  export declare function resolveTextVisualTransformForPreview(transform: Partial<ClipVisualTransform> | null | undefined, textStyle: TextClipStyle, frameSize: PreviewFrameSize, displayHeightPx: number): ClipVisualTransform;
40
+ /** clip 已持久化 layoutHeight 表示用户手动调整过文本框,预览应固定高度并截断溢出。 */
41
+ export declare function hasManualTextLayoutSize(textStyle: TextClipStyle): boolean;
42
+ export declare function resolveTextClipLayoutMode(textStyle?: Partial<TextClipStyle> | null): TextClipLayoutMode;
38
43
  export declare function resolveTextLayoutDimensions(input: ComputeTextPreviewBoxInput): {
39
44
  layoutWidth: number;
40
45
  layoutHeight: number;
@@ -53,3 +58,22 @@ export declare function buildTextPreviewBoxForEntry(entry: {
53
58
  visualTransform?: Partial<ClipVisualTransform> | null;
54
59
  };
55
60
  }, frameSize: PreviewFrameSize, baselineScale: number, styleOverride?: TextLayoutStyleOverride | null): TextPreviewBoxLayout;
61
+ export interface BuildTextClipResolvedLayoutInput {
62
+ frameSize: PreviewFrameSize;
63
+ composition: {
64
+ width: number;
65
+ height: number;
66
+ };
67
+ lastLayout: TextPreviewBoxLayout;
68
+ layoutMode: TextClipLayoutMode;
69
+ }
70
+ export declare function buildAutoMeasuredTextPreviewBoxLayout(input: {
71
+ layout: TextPreviewBoxLayout;
72
+ frameSize: PreviewFrameSize;
73
+ baselineScale: number;
74
+ visualTransform: ClipVisualTransform;
75
+ textStyle: TextClipStyle;
76
+ measuredHeightPx: number;
77
+ }): TextPreviewBoxLayout;
78
+ export declare function buildTextClipResolvedLayout(input: BuildTextClipResolvedLayoutInput): TextClipResolvedLayout;
79
+ export declare function areTextClipResolvedLayoutsEqual(left?: TextClipResolvedLayout | null, right?: TextClipResolvedLayout | null, epsilon?: number): boolean;
@@ -59,6 +59,7 @@ export interface PreviewEngineCallbacks {
59
59
  layoutWidth: number;
60
60
  layoutHeight: number;
61
61
  }) => void;
62
+ onTextLayoutResolved?: (clipId: string, layout: import('../models/types').TextClipResolvedLayout) => void;
62
63
  onPendingPreviewRetry?: () => void;
63
64
  onPauseIfPlaying?: () => void;
64
65
  }
@@ -19,11 +19,18 @@ export declare class ResourceCacheManager {
19
19
  private readonly cacheKeyBuilder;
20
20
  private readonly onEvent?;
21
21
  private readonly objectUrls;
22
+ private readonly objectUrlByCacheKey;
23
+ private readonly cacheKeyByObjectUrl;
24
+ private readonly objectUrlHolders;
22
25
  private readonly inflightDownloads;
23
26
  constructor(dependencies?: ResourceCacheManagerDependencies);
24
27
  resolve(input: ResolveResourceInput): Promise<ResolvedCachedResource>;
25
28
  resolvePlayableUrl(input: ResolveResourceInput): Promise<ResolvedCachedResource>;
29
+ retainObjectUrl(url: string, holderId: string): void;
30
+ releaseObjectUrl(url: string, holderId: string): void;
31
+ /** @deprecated Prefer releaseObjectUrl with a clip holder id. */
26
32
  revokeObjectUrl(url: string): void;
33
+ forceRevokeObjectUrl(url: string): void;
27
34
  cleanupExpired(): Promise<void>;
28
35
  clear(): Promise<void>;
29
36
  getStats(): Promise<ResourceCacheStats>;
@@ -34,6 +41,9 @@ export declare class ResourceCacheManager {
34
41
  private downloadAndStore;
35
42
  private evictForWrite;
36
43
  private deleteEntry;
44
+ private registerObjectUrl;
45
+ private revokeTrackedObjectUrl;
37
46
  private blobResult;
47
+ private toResolvedBlob;
38
48
  private emitEvent;
39
49
  }