@hyperframes/studio 0.6.0 → 0.6.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.
Files changed (58) hide show
  1. package/dist/assets/hyperframes-player-CzwFysqv.js +418 -0
  2. package/dist/assets/index-hYc4aP7M.js +117 -0
  3. package/dist/index.html +1 -1
  4. package/package.json +4 -4
  5. package/src/App.tsx +2 -13
  6. package/src/captions/components/CaptionOverlay.tsx +13 -246
  7. package/src/captions/components/CaptionOverlayUtils.ts +221 -0
  8. package/src/components/StudioPreviewArea.tsx +6 -2
  9. package/src/components/editor/DomEditOverlay.tsx +88 -1007
  10. package/src/components/editor/EaseCurveEditor.tsx +221 -0
  11. package/src/components/editor/FileTree.tsx +13 -621
  12. package/src/components/editor/FileTreeIcons.tsx +128 -0
  13. package/src/components/editor/FileTreeNodes.tsx +496 -0
  14. package/src/components/editor/MotionPanel.tsx +16 -390
  15. package/src/components/editor/MotionPanelFields.tsx +185 -0
  16. package/src/components/editor/domEditOverlayGeometry.ts +211 -0
  17. package/src/components/editor/domEditOverlayGestures.ts +138 -0
  18. package/src/components/editor/domEditOverlayStartGesture.ts +155 -0
  19. package/src/components/editor/domEditing.ts +44 -1150
  20. package/src/components/editor/domEditingAgentPrompt.ts +97 -0
  21. package/src/components/editor/domEditingDom.ts +266 -0
  22. package/src/components/editor/domEditingElement.ts +329 -0
  23. package/src/components/editor/domEditingLayers.ts +460 -0
  24. package/src/components/editor/domEditingTypes.ts +125 -0
  25. package/src/components/editor/manualEdits.ts +84 -1081
  26. package/src/components/editor/manualEditsDom.ts +436 -0
  27. package/src/components/editor/manualEditsParsing.ts +280 -0
  28. package/src/components/editor/manualEditsSnapshot.ts +333 -0
  29. package/src/components/editor/manualEditsTypes.ts +141 -0
  30. package/src/components/editor/studioMotion.ts +47 -434
  31. package/src/components/editor/studioMotionOps.ts +299 -0
  32. package/src/components/editor/studioMotionTypes.ts +168 -0
  33. package/src/components/editor/useDomEditOverlayGestures.ts +393 -0
  34. package/src/components/editor/useDomEditOverlayRects.ts +207 -0
  35. package/src/components/nle/NLELayout.tsx +60 -144
  36. package/src/components/nle/useCompositionStack.ts +126 -0
  37. package/src/hooks/useToast.ts +20 -0
  38. package/src/player/components/Timeline.tsx +189 -1418
  39. package/src/player/components/TimelineCanvas.tsx +434 -0
  40. package/src/player/components/TimelineEmptyState.tsx +102 -0
  41. package/src/player/components/TimelineRuler.tsx +90 -0
  42. package/src/player/components/timelineIcons.tsx +49 -0
  43. package/src/player/components/timelineLayout.ts +215 -0
  44. package/src/player/components/timelineUtils.ts +211 -0
  45. package/src/player/components/useTimelineClipDrag.ts +388 -0
  46. package/src/player/components/useTimelinePlayhead.ts +200 -0
  47. package/src/player/components/useTimelineRangeSelection.ts +135 -0
  48. package/src/player/hooks/usePlaybackKeyboard.ts +171 -0
  49. package/src/player/hooks/useTimelinePlayer.ts +69 -1372
  50. package/src/player/hooks/useTimelineSyncCallbacks.ts +288 -0
  51. package/src/player/lib/playbackAdapter.ts +145 -0
  52. package/src/player/lib/playbackShortcuts.ts +68 -0
  53. package/src/player/lib/playbackTypes.ts +60 -0
  54. package/src/player/lib/timelineDOM.ts +373 -0
  55. package/src/player/lib/timelineElementHelpers.ts +303 -0
  56. package/src/player/lib/timelineIframeHelpers.ts +269 -0
  57. package/dist/assets/hyperframes-player-DOFETgjy.js +0 -418
  58. package/dist/assets/index-DUqUmaoH.js +0 -117
@@ -0,0 +1,460 @@
1
+ /**
2
+ * Layer items, text fields, capabilities, selection resolution, and patch operations
3
+ * for dom editing.
4
+ */
5
+ import type { PatchOperation } from "../../utils/sourcePatcher";
6
+ import type {
7
+ DomEditCapabilities,
8
+ DomEditContextOptions,
9
+ DomEditLayerItem,
10
+ DomEditSelection,
11
+ DomEditTextField,
12
+ } from "./domEditingTypes";
13
+ import {
14
+ buildStableSelector,
15
+ getCuratedComputedStyles,
16
+ getDataAttributes,
17
+ getInlineStyles,
18
+ getPreferredClassSelector,
19
+ getSelectorIndex,
20
+ getSourceFileForElement,
21
+ humanizeIdentifier,
22
+ isHtmlElement,
23
+ isIdentityTransform,
24
+ isTextBearingTag,
25
+ parsePx,
26
+ } from "./domEditingDom";
27
+ import {
28
+ findElementForSelection,
29
+ getDomLayerPatchTarget,
30
+ getDirectLayerChildren,
31
+ getSelectionCandidate,
32
+ } from "./domEditingElement";
33
+
34
+ // ─── Text fields ────────────────────────────────────────────────────────────
35
+
36
+ export function isEditableTextLeaf(el: HTMLElement): boolean {
37
+ return isTextBearingTag(el.tagName.toLowerCase()) && el.children.length === 0;
38
+ }
39
+
40
+ function getTextFieldLabel(
41
+ _tagName: string,
42
+ index: number,
43
+ total: number,
44
+ source: "self" | "child",
45
+ ): string {
46
+ if (source === "self" || total === 1) return "Content";
47
+ return `Text ${index + 1}`;
48
+ }
49
+
50
+ function buildTextField(
51
+ el: HTMLElement,
52
+ index: number,
53
+ total: number,
54
+ source: "self" | "child",
55
+ ): DomEditTextField {
56
+ const tagName = el.tagName.toLowerCase();
57
+ const key = el.getAttribute("data-hf-text-key") ?? `${source}:${index}:${tagName}`;
58
+ return {
59
+ key,
60
+ label: getTextFieldLabel(tagName, index, total, source),
61
+ value: el.textContent ?? "",
62
+ tagName,
63
+ attributes: Array.from(el.attributes)
64
+ .filter((attribute) => attribute.name !== "style")
65
+ .map((attribute) => ({
66
+ name: attribute.name,
67
+ value: attribute.value,
68
+ })),
69
+ inlineStyles: getInlineStyles(el),
70
+ computedStyles: getCuratedComputedStyles(el),
71
+ source,
72
+ };
73
+ }
74
+
75
+ export function collectDomEditTextFields(el: HTMLElement): DomEditTextField[] {
76
+ const childFields = Array.from(el.children).filter(isHtmlElement).filter(isEditableTextLeaf);
77
+ if (childFields.length > 0) {
78
+ return childFields.map((child, index) =>
79
+ buildTextField(child, index, childFields.length, "child"),
80
+ );
81
+ }
82
+
83
+ if (isEditableTextLeaf(el)) {
84
+ return [buildTextField(el, 0, 1, "self")];
85
+ }
86
+
87
+ return [];
88
+ }
89
+
90
+ function escapeHtmlText(value: string): string {
91
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
92
+ }
93
+
94
+ function serializeTextFieldStyle(field: DomEditTextField): string {
95
+ const entries = Object.entries(field.inlineStyles).filter(([, value]) => Boolean(value));
96
+ if (entries.length === 0) return "";
97
+ return entries.map(([key, value]) => `${key}: ${value}`).join("; ");
98
+ }
99
+
100
+ export function serializeDomEditTextFields(fields: DomEditTextField[]): string {
101
+ return fields
102
+ .filter((field) => field.source === "child")
103
+ .map((field) => {
104
+ const attrs = [
105
+ ...field.attributes.filter((attribute) => attribute.name !== "data-hf-text-key"),
106
+ { name: "data-hf-text-key", value: field.key },
107
+ ]
108
+ .map((attribute) => ` ${attribute.name}="${attribute.value.replace(/"/g, "&quot;")}"`)
109
+ .join("");
110
+ const style = serializeTextFieldStyle(field);
111
+ const styleAttr = style ? ` style="${style.replace(/"/g, "&quot;")}"` : "";
112
+ return `<${field.tagName}${attrs}${styleAttr}>${escapeHtmlText(field.value)}</${field.tagName}>`;
113
+ })
114
+ .join("");
115
+ }
116
+
117
+ export function buildDefaultDomEditTextField(base?: Partial<DomEditTextField>): DomEditTextField {
118
+ return {
119
+ key: `child:new:${Date.now()}`,
120
+ label: "Text",
121
+ value: "New text",
122
+ tagName: "span",
123
+ attributes: [],
124
+ inlineStyles: {
125
+ "font-family": base?.computedStyles?.["font-family"] ?? "inherit",
126
+ "font-size": base?.computedStyles?.["font-size"] ?? "16px",
127
+ "font-weight": base?.computedStyles?.["font-weight"] ?? "400",
128
+ color: base?.computedStyles?.color ?? "inherit",
129
+ },
130
+ computedStyles: {},
131
+ source: "child",
132
+ };
133
+ }
134
+
135
+ // ─── Capabilities ────────────────────────────────────────────────────────────
136
+
137
+ export function resolveDomEditCapabilities(args: {
138
+ selector?: string;
139
+ tagName?: string;
140
+ className?: string;
141
+ inlineStyles: Record<string, string>;
142
+ computedStyles: Record<string, string>;
143
+ isCompositionHost: boolean;
144
+ isMasterView: boolean;
145
+ }): DomEditCapabilities {
146
+ if (!args.selector) {
147
+ return {
148
+ canSelect: false,
149
+ canEditStyles: false,
150
+ canMove: false,
151
+ canResize: false,
152
+ canApplyManualOffset: false,
153
+ canApplyManualSize: false,
154
+ canApplyManualRotation: false,
155
+ reasonIfDisabled: "Studio could not resolve a stable patch target for this element.",
156
+ };
157
+ }
158
+
159
+ const position = args.computedStyles.position;
160
+ const left = parsePx(args.inlineStyles.left) ?? parsePx(args.computedStyles.left);
161
+ const top = parsePx(args.inlineStyles.top) ?? parsePx(args.computedStyles.top);
162
+ const width = parsePx(args.inlineStyles.width) ?? parsePx(args.computedStyles.width);
163
+ const height = parsePx(args.inlineStyles.height) ?? parsePx(args.computedStyles.height);
164
+ const hasTransformDrivenGeometry = !isIdentityTransform(args.computedStyles.transform);
165
+
166
+ const canMove =
167
+ (position === "absolute" || position === "fixed") &&
168
+ left != null &&
169
+ top != null &&
170
+ !hasTransformDrivenGeometry;
171
+
172
+ const canResize = canMove && (width != null || height != null);
173
+ const canApplyManualGeometry = !args.isCompositionHost;
174
+ const canApplyManualOffset = canApplyManualGeometry;
175
+ const canApplyManualSize = canApplyManualGeometry;
176
+ const canApplyManualRotation = canApplyManualGeometry;
177
+ const reasonIfDisabled = canApplyManualGeometry
178
+ ? undefined
179
+ : "Select an internal layer to transform it.";
180
+
181
+ if (args.isCompositionHost && args.isMasterView) {
182
+ return {
183
+ canSelect: true,
184
+ canEditStyles: false,
185
+ canMove,
186
+ canResize,
187
+ canApplyManualOffset,
188
+ canApplyManualSize,
189
+ canApplyManualRotation,
190
+ reasonIfDisabled,
191
+ };
192
+ }
193
+
194
+ return {
195
+ canSelect: true,
196
+ canEditStyles: true,
197
+ canMove,
198
+ canResize,
199
+ canApplyManualOffset,
200
+ canApplyManualSize,
201
+ canApplyManualRotation,
202
+ reasonIfDisabled,
203
+ };
204
+ }
205
+
206
+ // ─── Element label ────────────────────────────────────────────────────────────
207
+
208
+ export function buildElementLabel(el: HTMLElement): string {
209
+ const compositionId = el.getAttribute("data-composition-id");
210
+ if (compositionId && compositionId !== "main") {
211
+ return humanizeIdentifier(compositionId);
212
+ }
213
+
214
+ const compositionSrc =
215
+ el.getAttribute("data-composition-src") ?? el.getAttribute("data-composition-file");
216
+ if (compositionSrc) {
217
+ return humanizeIdentifier(compositionSrc);
218
+ }
219
+
220
+ if (el.id) return humanizeIdentifier(el.id);
221
+
222
+ const preferredClass = getPreferredClassSelector(el);
223
+ if (preferredClass) {
224
+ return humanizeIdentifier(preferredClass.replace(/^\./, ""));
225
+ }
226
+
227
+ const text = (el.textContent ?? "").trim().replace(/\s+/g, " ");
228
+ if (text) return text.length > 40 ? `${text.slice(0, 39)}…` : text;
229
+ return el.tagName.toLowerCase();
230
+ }
231
+
232
+ // ─── Selection resolution ────────────────────────────────────────────────────
233
+
234
+ export function resolveDomEditSelection(
235
+ startEl: HTMLElement | null,
236
+ options: DomEditContextOptions,
237
+ ): DomEditSelection | null {
238
+ if (!startEl) return null;
239
+ const doc = startEl.ownerDocument;
240
+
241
+ let current: HTMLElement | null = getSelectionCandidate(startEl, options);
242
+ while (current && current !== doc.body && current !== doc.documentElement) {
243
+ const selector = buildStableSelector(current);
244
+ if (!selector) {
245
+ current = current.parentElement;
246
+ continue;
247
+ }
248
+
249
+ const { sourceFile, compositionPath } = getSourceFileForElement(
250
+ current,
251
+ options.activeCompositionPath,
252
+ );
253
+ const selectorIndex = getSelectorIndex(
254
+ doc,
255
+ current,
256
+ selector,
257
+ sourceFile,
258
+ options.activeCompositionPath,
259
+ );
260
+ const compositionSrc =
261
+ current.getAttribute("data-composition-src") ??
262
+ current.getAttribute("data-composition-file") ??
263
+ undefined;
264
+ const inlineStyles = getInlineStyles(current);
265
+ const computedStyles = getCuratedComputedStyles(current);
266
+ const textFields = collectDomEditTextFields(current);
267
+ const capabilities = resolveDomEditCapabilities({
268
+ selector,
269
+ tagName: current.tagName.toLowerCase(),
270
+ className: current.className,
271
+ inlineStyles,
272
+ computedStyles,
273
+ isCompositionHost: Boolean(compositionSrc),
274
+ isMasterView: options.isMasterView,
275
+ });
276
+ const rect = current.getBoundingClientRect();
277
+
278
+ return {
279
+ element: current,
280
+ id: current.id || undefined,
281
+ selector,
282
+ selectorIndex,
283
+ sourceFile,
284
+ compositionPath,
285
+ compositionSrc,
286
+ isCompositionHost: Boolean(compositionSrc),
287
+ label: buildElementLabel(current),
288
+ tagName: current.tagName.toLowerCase(),
289
+ boundingBox: {
290
+ x: rect.left,
291
+ y: rect.top,
292
+ width: rect.width,
293
+ height: rect.height,
294
+ },
295
+ textContent: current.textContent?.trim() || null,
296
+ dataAttributes: getDataAttributes(current),
297
+ inlineStyles,
298
+ computedStyles,
299
+ textFields,
300
+ capabilities,
301
+ };
302
+ }
303
+
304
+ return null;
305
+ }
306
+
307
+ export function refreshDomEditSelection(
308
+ selection: DomEditSelection,
309
+ activeCompositionPath: string | null,
310
+ ): DomEditSelection | null {
311
+ const doc = selection.element.ownerDocument;
312
+ const nextElement = findElementForSelection(doc, selection, activeCompositionPath);
313
+ return nextElement
314
+ ? resolveDomEditSelection(nextElement, {
315
+ activeCompositionPath,
316
+ isMasterView: !activeCompositionPath || activeCompositionPath === "index.html",
317
+ })
318
+ : null;
319
+ }
320
+
321
+ // ─── Layer items ─────────────────────────────────────────────────────────────
322
+
323
+ export function getDomEditLayerKey(
324
+ target: Pick<DomEditSelection, "id" | "selector" | "selectorIndex" | "sourceFile">,
325
+ ): string {
326
+ const selectorIndex = target.selectorIndex ?? 0;
327
+ return `${target.sourceFile}:${target.id ?? target.selector ?? "layer"}:${selectorIndex}`;
328
+ }
329
+
330
+ export function countDomEditChildLayers(
331
+ root: HTMLElement | null | undefined,
332
+ options: DomEditContextOptions,
333
+ maxCount = 99,
334
+ ): number {
335
+ if (!root) return 0;
336
+
337
+ let count = 0;
338
+ const visit = (el: HTMLElement) => {
339
+ for (const child of Array.from(el.children)) {
340
+ if (!isHtmlElement(child)) continue;
341
+ if (getDomLayerPatchTarget(child, options.activeCompositionPath)) {
342
+ count += 1;
343
+ if (count >= maxCount) return;
344
+ }
345
+ visit(child);
346
+ if (count >= maxCount) return;
347
+ }
348
+ };
349
+
350
+ visit(root);
351
+ return count;
352
+ }
353
+
354
+ export function collectDomEditLayerItems(
355
+ root: HTMLElement | null | undefined,
356
+ options: DomEditContextOptions,
357
+ maxItems = 80,
358
+ ): DomEditLayerItem[] {
359
+ if (!root) return [];
360
+
361
+ const items: DomEditLayerItem[] = [];
362
+ const visit = (el: HTMLElement, depth: number) => {
363
+ if (items.length >= maxItems) return;
364
+
365
+ const target = getDomLayerPatchTarget(el, options.activeCompositionPath);
366
+ if (target) {
367
+ items.push({
368
+ key: getDomEditLayerKey(target),
369
+ element: el,
370
+ label: buildElementLabel(el),
371
+ tagName: el.tagName.toLowerCase(),
372
+ depth,
373
+ childCount: getDirectLayerChildren(el, options).length,
374
+ id: target.id ?? undefined,
375
+ selector: target.selector ?? undefined,
376
+ selectorIndex: target.selectorIndex,
377
+ sourceFile: target.sourceFile,
378
+ });
379
+ }
380
+
381
+ const nextDepth = target ? depth + 1 : depth;
382
+ for (const child of Array.from(el.children)) {
383
+ if (!isHtmlElement(child)) continue;
384
+ visit(child, nextDepth);
385
+ if (items.length >= maxItems) return;
386
+ }
387
+ };
388
+
389
+ visit(root, 0);
390
+ return items;
391
+ }
392
+
393
+ // ─── Patch operations ────────────────────────────────────────────────────────
394
+
395
+ export function buildDomEditStylePatchOperation(property: string, value: string): PatchOperation {
396
+ return {
397
+ type: "inline-style",
398
+ property,
399
+ value,
400
+ };
401
+ }
402
+
403
+ export function buildDomEditTextPatchOperation(value: string): PatchOperation {
404
+ return {
405
+ type: "text-content",
406
+ property: "text",
407
+ value,
408
+ };
409
+ }
410
+
411
+ // ─── Non-editable reason ─────────────────────────────────────────────────────
412
+
413
+ function hasSupportedDirectEdit(capabilities: DomEditCapabilities): boolean {
414
+ return (
415
+ capabilities.canEditStyles ||
416
+ capabilities.canMove ||
417
+ capabilities.canResize ||
418
+ capabilities.canApplyManualOffset ||
419
+ capabilities.canApplyManualSize ||
420
+ capabilities.canApplyManualRotation
421
+ );
422
+ }
423
+
424
+ export function getDomEditNonEditableReason(
425
+ element: HTMLElement,
426
+ selection: DomEditSelection | null,
427
+ ): string | null {
428
+ if (!selection) {
429
+ return "No stable source target";
430
+ }
431
+
432
+ if (selection.element !== element) {
433
+ return selection.isCompositionHost
434
+ ? "Nested composition boundary"
435
+ : `Selection resolves to ${selection.label}`;
436
+ }
437
+
438
+ if (!hasSupportedDirectEdit(selection.capabilities)) {
439
+ return selection.capabilities.reasonIfDisabled ?? "No supported direct edits";
440
+ }
441
+
442
+ return null;
443
+ }
444
+
445
+ export function getDomEditTargetKey(
446
+ selection: Pick<DomEditSelection, "id" | "selector" | "selectorIndex" | "sourceFile">,
447
+ ): string {
448
+ return [
449
+ selection.sourceFile || "index.html",
450
+ selection.id ?? "",
451
+ selection.selector ?? "",
452
+ selection.selectorIndex ?? "",
453
+ ].join("|");
454
+ }
455
+
456
+ export function isTextEditableSelection(selection: DomEditSelection): boolean {
457
+ return selection.textFields.length > 0 && !selection.isCompositionHost;
458
+ }
459
+
460
+ // buildElementAgentPrompt is in domEditingAgentPrompt.ts
@@ -0,0 +1,125 @@
1
+ import type { PatchTarget } from "../../utils/sourcePatcher";
2
+
3
+ export const CURATED_STYLE_PROPERTIES = [
4
+ "position",
5
+ "display",
6
+ "top",
7
+ "left",
8
+ "right",
9
+ "bottom",
10
+ "inset",
11
+ "width",
12
+ "height",
13
+ "gap",
14
+ "justify-content",
15
+ "align-items",
16
+ "flex-direction",
17
+ "font-size",
18
+ "font-style",
19
+ "font-weight",
20
+ "font-family",
21
+ "line-height",
22
+ "letter-spacing",
23
+ "text-align",
24
+ "text-transform",
25
+ "color",
26
+ "background-color",
27
+ "background-image",
28
+ "opacity",
29
+ "mix-blend-mode",
30
+ "border-radius",
31
+ "border-width",
32
+ "border-style",
33
+ "border-color",
34
+ "border-top-width",
35
+ "border-top-style",
36
+ "border-top-color",
37
+ "outline-color",
38
+ "overflow",
39
+ "clip-path",
40
+ "box-shadow",
41
+ "filter",
42
+ "backdrop-filter",
43
+ "z-index",
44
+ "transform",
45
+ ] as const;
46
+
47
+ export interface DomEditCapabilities {
48
+ canSelect: boolean;
49
+ canEditStyles: boolean;
50
+ /** Directly editable authored left/top style fields. Canvas drag uses manual edits instead. */
51
+ canMove: boolean;
52
+ /** Directly editable authored width/height style fields. Canvas resize uses manual edits instead. */
53
+ canResize: boolean;
54
+ canApplyManualOffset: boolean;
55
+ canApplyManualSize: boolean;
56
+ canApplyManualRotation: boolean;
57
+ reasonIfDisabled?: string;
58
+ }
59
+
60
+ export interface DomEditTextField {
61
+ key: string;
62
+ label: string;
63
+ value: string;
64
+ tagName: string;
65
+ attributes: Array<{ name: string; value: string }>;
66
+ inlineStyles: Record<string, string>;
67
+ computedStyles: Record<string, string>;
68
+ source: "self" | "child";
69
+ }
70
+
71
+ export interface DomEditSelection extends PatchTarget {
72
+ element: HTMLElement;
73
+ label: string;
74
+ tagName: string;
75
+ sourceFile: string;
76
+ compositionPath: string;
77
+ compositionSrc?: string;
78
+ isCompositionHost: boolean;
79
+ boundingBox: { x: number; y: number; width: number; height: number };
80
+ textContent: string | null;
81
+ dataAttributes: Record<string, string>;
82
+ inlineStyles: Record<string, string>;
83
+ computedStyles: Record<string, string>;
84
+ textFields: DomEditTextField[];
85
+ capabilities: DomEditCapabilities;
86
+ }
87
+
88
+ export interface DomEditLayerItem {
89
+ key: string;
90
+ element: HTMLElement;
91
+ label: string;
92
+ tagName: string;
93
+ depth: number;
94
+ childCount: number;
95
+ id?: string;
96
+ selector?: string;
97
+ selectorIndex?: number;
98
+ sourceFile: string;
99
+ }
100
+
101
+ export interface DomEditContextOptions {
102
+ activeCompositionPath: string | null;
103
+ isMasterView: boolean;
104
+ preferClipAncestor?: boolean;
105
+ }
106
+
107
+ export interface DomEditViewport {
108
+ width: number;
109
+ height: number;
110
+ }
111
+
112
+ export interface TimelineElementDomTarget {
113
+ id?: string;
114
+ domId?: string;
115
+ selector?: string;
116
+ selectorIndex?: number;
117
+ sourceFile?: string;
118
+ compositionSrc?: string;
119
+ }
120
+
121
+ export interface TimelineElementDomTargetOptions {
122
+ activeCompositionPath: string | null;
123
+ compIdToSrc?: ReadonlyMap<string, string>;
124
+ isMasterView: boolean;
125
+ }