@remotion/studio 4.0.494 → 4.0.496

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 (125) hide show
  1. package/dist/api/get-static-files.d.ts +1 -1
  2. package/dist/components/AssetFileIcon.d.ts +7 -0
  3. package/dist/components/AssetFileIcon.js +24 -0
  4. package/dist/components/AssetSelectorItem.js +20 -14
  5. package/dist/components/Canvas.js +191 -36
  6. package/dist/components/CompositionSelectorItem.js +20 -31
  7. package/dist/components/CurrentAsset.d.ts +1 -0
  8. package/dist/components/CurrentAsset.js +21 -4
  9. package/dist/components/Editor.js +2 -4
  10. package/dist/components/InlineCompositionName.js +1 -1
  11. package/dist/components/InlineEditableTitle.d.ts +1 -0
  12. package/dist/components/InlineEditableTitle.js +56 -11
  13. package/dist/components/InspectorInfoHeader.d.ts +2 -0
  14. package/dist/components/InspectorInfoHeader.js +16 -4
  15. package/dist/components/InspectorLocationCopy.js +2 -2
  16. package/dist/components/InspectorPanel/AssetInspector.d.ts +4 -0
  17. package/dist/components/InspectorPanel/AssetInspector.js +11 -0
  18. package/dist/components/InspectorPanel/{DefaultInspector.d.ts → CompositionInspector.d.ts} +2 -2
  19. package/dist/components/InspectorPanel/CompositionInspector.js +114 -0
  20. package/dist/components/InspectorPanel/CompositionInspectorHeader.d.ts +1 -0
  21. package/dist/components/{CurrentComposition.js → InspectorPanel/CompositionInspectorHeader.js} +26 -21
  22. package/dist/components/InspectorPanel/{CompositionDimensions.d.ts → CompositionMetadata.d.ts} +1 -1
  23. package/dist/components/InspectorPanel/{CompositionDimensions.js → CompositionMetadata.js} +17 -8
  24. package/dist/components/InspectorPanel/ConnectedCompositionsSection.js +2 -2
  25. package/dist/components/InspectorPanel/EasingInspector.js +4 -6
  26. package/dist/components/InspectorPanel/KeyframeInspector.js +7 -8
  27. package/dist/components/InspectorPanel/KeyframeSettings.js +1 -1
  28. package/dist/components/InspectorPanel/SequenceInspectorHeader.js +28 -3
  29. package/dist/components/InspectorPanel/SequenceSelectionInspector.js +34 -1
  30. package/dist/components/InspectorPanel/common.d.ts +12 -2
  31. package/dist/components/InspectorPanel/common.js +45 -22
  32. package/dist/components/InspectorPanel/styles.d.ts +5 -6
  33. package/dist/components/InspectorPanel/styles.js +13 -39
  34. package/dist/components/InspectorPanel/use-composition-actions.d.ts +8 -0
  35. package/dist/components/InspectorPanel/use-composition-actions.js +114 -0
  36. package/dist/components/InspectorPanel.js +11 -2
  37. package/dist/components/InspectorSequenceSection.d.ts +0 -1
  38. package/dist/components/InspectorSequenceSection.js +20 -49
  39. package/dist/components/InspectorSourceLocation.d.ts +1 -0
  40. package/dist/components/InspectorSourceLocation.js +5 -1
  41. package/dist/components/Modals.js +2 -1
  42. package/dist/components/NewComposition/ComboBox.d.ts +2 -1
  43. package/dist/components/NewComposition/ComboBox.js +32 -7
  44. package/dist/components/NewComposition/InputDragger.d.ts +6 -0
  45. package/dist/components/NewComposition/InputDragger.js +26 -13
  46. package/dist/components/NewComposition/NewComposition.js +8 -1
  47. package/dist/components/NewComposition/ValidationMessage.d.ts +1 -1
  48. package/dist/components/PlaybackRateSelector.js +3 -3
  49. package/dist/components/Preview.js +15 -7
  50. package/dist/components/PreviewToolbar.js +3 -3
  51. package/dist/components/RenderButton.d.ts +1 -0
  52. package/dist/components/RenderButton.js +51 -7
  53. package/dist/components/RenderModal/RenderModalOutputName.js +34 -1
  54. package/dist/components/RenderModal/SchemaEditor/ZodDiscriminatedUnionEditor.js +1 -1
  55. package/dist/components/RenderModal/SchemaEditor/ZodEnumEditor.js +1 -1
  56. package/dist/components/RenderModal/SchemaEditor/ZodStaticFileEditor.js +1 -1
  57. package/dist/components/SelectedOutlineOverlay.js +1 -0
  58. package/dist/components/SizeSelector.js +3 -3
  59. package/dist/components/SvgImportDialog.d.ts +7 -0
  60. package/dist/components/SvgImportDialog.js +103 -0
  61. package/dist/components/Timeline/Timeline.js +1 -0
  62. package/dist/components/Timeline/TimelineAssetField.js +1 -1
  63. package/dist/components/Timeline/TimelineClipboardKeybindings.js +8 -1
  64. package/dist/components/Timeline/TimelineEnumField.js +1 -1
  65. package/dist/components/Timeline/TimelineFieldLabel.js +3 -3
  66. package/dist/components/Timeline/TimelineKeyframeControls.js +26 -6
  67. package/dist/components/Timeline/TimelineList.js +9 -4
  68. package/dist/components/Timeline/TimelineRowChrome.js +10 -2
  69. package/dist/components/Timeline/TimelineRowLayoutContext.d.ts +3 -0
  70. package/dist/components/Timeline/TimelineRowLayoutContext.js +6 -0
  71. package/dist/components/Timeline/TimelineSequenceItem.d.ts +2 -1
  72. package/dist/components/Timeline/TimelineSequenceItem.js +19 -11
  73. package/dist/components/Timeline/nest-timeline-tracks.d.ts +8 -0
  74. package/dist/components/Timeline/nest-timeline-tracks.js +25 -0
  75. package/dist/components/Timeline/timeline-scroll-logic.d.ts +8 -4
  76. package/dist/components/Timeline/timeline-scroll-logic.js +29 -15
  77. package/dist/components/import-assets.d.ts +17 -1
  78. package/dist/components/import-assets.js +96 -11
  79. package/dist/components/layout.d.ts +2 -0
  80. package/dist/components/layout.js +3 -1
  81. package/dist/components/open-in-new-window.d.ts +2 -0
  82. package/dist/components/open-in-new-window.js +28 -0
  83. package/dist/components/selected-outline-measurement.d.ts +2 -1
  84. package/dist/components/selected-outline-measurement.js +3 -1
  85. package/dist/esm/{chunk-tdncqycp.js → chunk-0v4n7nkh.js} +8463 -7092
  86. package/dist/esm/internals.mjs +8463 -7092
  87. package/dist/esm/previewEntry.mjs +8613 -7242
  88. package/dist/esm/renderEntry.mjs +1 -1
  89. package/dist/helpers/client-id.js +2 -1
  90. package/dist/helpers/clipboard-figma.d.ts +4 -0
  91. package/dist/helpers/clipboard-figma.js +41 -0
  92. package/dist/helpers/clipboard-images.d.ts +10 -0
  93. package/dist/helpers/clipboard-images.js +77 -0
  94. package/dist/helpers/clipboard-svg.d.ts +3 -0
  95. package/dist/helpers/clipboard-svg.js +47 -0
  96. package/dist/helpers/get-effective-translation.d.ts +2 -1
  97. package/dist/helpers/get-effective-translation.js +15 -7
  98. package/dist/helpers/get-preview-file-type.d.ts +1 -1
  99. package/dist/helpers/get-preview-file-type.js +5 -1
  100. package/dist/helpers/inject-css.js +11 -0
  101. package/dist/helpers/studio-fit-padding.d.ts +41 -0
  102. package/dist/helpers/studio-fit-padding.js +64 -0
  103. package/dist/helpers/use-image-metadata.d.ts +8 -0
  104. package/dist/helpers/use-image-metadata.js +82 -0
  105. package/dist/helpers/use-studio-canvas-dimensions.js +2 -2
  106. package/dist/icons/audio.d.ts +3 -0
  107. package/dist/icons/audio.js +3 -1
  108. package/dist/icons/font.d.ts +4 -0
  109. package/dist/icons/font.js +8 -0
  110. package/dist/icons/frame.d.ts +3 -1
  111. package/dist/icons/frame.js +1 -1
  112. package/dist/icons/json.d.ts +4 -0
  113. package/dist/icons/json.js +8 -0
  114. package/dist/icons/magnet.js +1 -1
  115. package/dist/icons/scissors.d.ts +5 -0
  116. package/dist/icons/scissors.js +8 -0
  117. package/dist/icons/solid.d.ts +5 -0
  118. package/dist/icons/solid.js +8 -0
  119. package/dist/icons/video.d.ts +3 -0
  120. package/dist/icons/video.js +5 -1
  121. package/dist/state/modals.d.ts +8 -1
  122. package/dist/state/timeline-zoom.js +12 -11
  123. package/package.json +11 -11
  124. package/dist/components/CurrentComposition.d.ts +0 -2
  125. package/dist/components/InspectorPanel/DefaultInspector.js +0 -97
@@ -5,9 +5,15 @@ const react_1 = require("react");
5
5
  const timeline_row_layout_1 = require("./timeline-row-layout");
6
6
  exports.INSPECTOR_TIMELINE_ROW_LAYOUT = {
7
7
  basePadding: timeline_row_layout_1.INSPECTOR_ROW_BASE_PADDING,
8
+ highlightSelectedLabel: false,
8
9
  keyframeControlsPadding: 0,
10
+ rowBorderRadius: 4,
11
+ rowHorizontalMargin: 4,
9
12
  };
10
13
  exports.TimelineRowLayoutContext = (0, react_1.createContext)({
11
14
  basePadding: timeline_row_layout_1.TIMELINE_ROW_BASE_PADDING,
15
+ highlightSelectedLabel: true,
12
16
  keyframeControlsPadding: timeline_row_layout_1.TIMELINE_ROW_BASE_PADDING,
17
+ rowBorderRadius: 0,
18
+ rowHorizontalMargin: 0,
13
19
  });
@@ -2,11 +2,12 @@ import React from 'react';
2
2
  import type { _InternalTypes, TSequence } from 'remotion';
3
3
  import type { SequenceNodePathInfo } from '../../helpers/get-timeline-sequence-sort-key';
4
4
  export declare const TimelineSequenceItem: React.FC<{
5
+ readonly children: React.ReactNode;
5
6
  readonly sequence: TSequence;
6
7
  readonly connectedCompositions: readonly _InternalTypes['AnyComposition'][];
7
8
  readonly nestedDepth: number;
8
9
  readonly nodePathInfo: SequenceNodePathInfo | null;
9
10
  readonly keyframeDisplayOffset: number;
10
11
  readonly sequenceFrameOffset: number;
11
- readonly trackIndex: number;
12
+ readonly siblingIndex: number;
12
13
  }>;
@@ -115,6 +115,14 @@ const sequenceReorderLineBase = {
115
115
  right: 0,
116
116
  zIndex: 1,
117
117
  };
118
+ const sequenceReorderAfterLineWrapper = {
119
+ height: 0,
120
+ position: 'relative',
121
+ };
122
+ const sequenceReorderAfterLine = {
123
+ ...sequenceReorderLineBase,
124
+ top: -1,
125
+ };
118
126
  const sequenceReorderRejectionStyle = {
119
127
  backgroundColor: colors_1.BLACK_ALPHA_85,
120
128
  border: colors_1.BORDER_WHITE_ALPHA_20,
@@ -147,7 +155,7 @@ const getSequenceReorderDragData = (dataTransfer) => {
147
155
  try {
148
156
  const parsed = JSON.parse(value);
149
157
  if (typeof parsed.nodePathKey === 'string' &&
150
- typeof parsed.trackIndex === 'number' &&
158
+ typeof parsed.siblingIndex === 'number' &&
151
159
  (typeof parsed.parentId === 'string' || parsed.parentId === null) &&
152
160
  typeof parsed.fileName === 'string' &&
153
161
  parsed.nodePath &&
@@ -163,7 +171,7 @@ const getSequenceReorderDragData = (dataTransfer) => {
163
171
  const getDestinationIndex = ({ fromIndex, insertionIndex, }) => {
164
172
  return insertionIndex > fromIndex ? insertionIndex - 1 : insertionIndex;
165
173
  };
166
- const TimelineSequenceItem = ({ connectedCompositions, nestedDepth, sequence, nodePathInfo, keyframeDisplayOffset, sequenceFrameOffset, trackIndex, }) => {
174
+ const TimelineSequenceItem = ({ children, connectedCompositions, nestedDepth, sequence, nodePathInfo, keyframeDisplayOffset, sequenceFrameOffset, siblingIndex, }) => {
167
175
  var _a, _b, _c;
168
176
  var _d, _e, _f;
169
177
  const nodePath = (_d = nodePathInfo === null || nodePathInfo === void 0 ? void 0 : nodePathInfo.sequenceSubscriptionKey) !== null && _d !== void 0 ? _d : null;
@@ -328,12 +336,12 @@ const TimelineSequenceItem = ({ connectedCompositions, nestedDepth, sequence, no
328
336
  }
329
337
  const rect = e.currentTarget.getBoundingClientRect();
330
338
  const before = e.clientY < rect.top + rect.height / 2;
331
- const insertionIndex = before ? trackIndex : trackIndex + 1;
339
+ const insertionIndex = before ? siblingIndex : siblingIndex + 1;
332
340
  const toIndex = getDestinationIndex({
333
- fromIndex: dragData.trackIndex,
341
+ fromIndex: dragData.siblingIndex,
334
342
  insertionIndex,
335
343
  });
336
- if (toIndex === dragData.trackIndex) {
344
+ if (toIndex === dragData.siblingIndex) {
337
345
  return {
338
346
  type: 'invalid',
339
347
  reason: 'This sequence is already in that position.',
@@ -349,7 +357,7 @@ const TimelineSequenceItem = ({ connectedCompositions, nestedDepth, sequence, no
349
357
  nodePathInfo === null || nodePathInfo === void 0 ? void 0 : nodePathInfo.numberOfSequencesWithThisNodePath,
350
358
  nodePathKey,
351
359
  parentId,
352
- trackIndex,
360
+ siblingIndex,
353
361
  validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source,
354
362
  ]);
355
363
  const onSequenceDragStart = (0, react_1.useCallback)((e) => {
@@ -363,7 +371,7 @@ const TimelineSequenceItem = ({ connectedCompositions, nestedDepth, sequence, no
363
371
  const dragData = {
364
372
  nodePath,
365
373
  nodePathKey,
366
- trackIndex,
374
+ siblingIndex,
367
375
  parentId,
368
376
  fileName: validatedLocation.source,
369
377
  };
@@ -376,7 +384,7 @@ const TimelineSequenceItem = ({ connectedCompositions, nestedDepth, sequence, no
376
384
  nodePath,
377
385
  nodePathKey,
378
386
  parentId,
379
- trackIndex,
387
+ siblingIndex,
380
388
  validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source,
381
389
  ]);
382
390
  const onSequenceDragEnd = (0, react_1.useCallback)(() => {
@@ -747,12 +755,12 @@ const TimelineSequenceItem = ({ connectedCompositions, nestedDepth, sequence, no
747
755
  validatedLocation !== null &&
748
756
  ((_c = sequence.controls) === null || _c === void 0 ? void 0 : _c.supportsEffects) === true;
749
757
  const sequenceReorderLineStyle = (0, react_1.useMemo)(() => {
750
- if (!sequenceDropIndicator) {
758
+ if (sequenceDropIndicator !== 'before') {
751
759
  return null;
752
760
  }
753
761
  return {
754
762
  ...sequenceReorderLineBase,
755
- ...(sequenceDropIndicator === 'before' ? { top: -1 } : { bottom: -1 }),
763
+ top: -1,
756
764
  };
757
765
  }, [sequenceDropIndicator]);
758
766
  const onEffectDragOver = (0, react_1.useCallback)((e) => {
@@ -813,6 +821,6 @@ const TimelineSequenceItem = ({ connectedCompositions, nestedDepth, sequence, no
813
821
  isExpanded &&
814
822
  hasExpandableContent &&
815
823
  nodePathInfo &&
816
- validatedLocation ? (jsx_runtime_1.jsx(TimelineExpandedSection_1.TimelineExpandedSection, { sequence: sequence, validatedLocation: validatedLocation, nodePathInfo: nodePathInfo, nestedDepth: nestedDepth, keyframeDisplayOffset: keyframeDisplayOffset })) : null] }));
824
+ validatedLocation ? (jsx_runtime_1.jsx(TimelineExpandedSection_1.TimelineExpandedSection, { sequence: sequence, validatedLocation: validatedLocation, nodePathInfo: nodePathInfo, nestedDepth: nestedDepth, keyframeDisplayOffset: keyframeDisplayOffset })) : null, children, sequenceDropIndicator === 'after' ? (jsx_runtime_1.jsx("div", { style: sequenceReorderAfterLineWrapper, children: jsx_runtime_1.jsx("div", { style: sequenceReorderAfterLine }) })) : null] }));
817
825
  };
818
826
  exports.TimelineSequenceItem = TimelineSequenceItem;
@@ -0,0 +1,8 @@
1
+ export type NestedTimelineTrack<T> = {
2
+ readonly track: T;
3
+ readonly siblingIndex: number;
4
+ readonly children: NestedTimelineTrack<T>[];
5
+ };
6
+ export declare const nestTimelineTracks: <T extends {
7
+ readonly depth: number;
8
+ }>(timeline: readonly T[]) => NestedTimelineTrack<T>[];
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.nestTimelineTracks = void 0;
4
+ const nestTimelineTracks = (timeline) => {
5
+ const roots = [];
6
+ const stack = [];
7
+ for (let trackIndex = 0; trackIndex < timeline.length; trackIndex++) {
8
+ const track = timeline[trackIndex];
9
+ while (stack.length > 0 &&
10
+ stack[stack.length - 1].track.depth >= track.depth) {
11
+ stack.pop();
12
+ }
13
+ const parent = stack[stack.length - 1];
14
+ const siblings = parent ? parent.children : roots;
15
+ const nestedTrack = {
16
+ track,
17
+ siblingIndex: siblings.length,
18
+ children: [],
19
+ };
20
+ siblings.push(nestedTrack);
21
+ stack.push(nestedTrack);
22
+ }
23
+ return roots;
24
+ };
25
+ exports.nestTimelineTracks = nestTimelineTracks;
@@ -44,12 +44,16 @@ export declare const viewportClientXToScrollContentX: ({ clientX, scrollEl, }: {
44
44
  clientX: number;
45
45
  scrollEl: HTMLDivElement;
46
46
  }) => number;
47
- export declare const zoomAndPreserveCursor: ({ oldZoom, newZoom, currentFrame, currentDurationInFrames, anchorFrame, anchorContentX, }: {
48
- oldZoom: number;
49
- newZoom: number;
47
+ export declare const getScrollLeftToKeepCursorInPlace: ({ anchorContentX, oldScrollLeft, oldTimelineWidth, newTimelineWidth, }: {
48
+ anchorContentX: number;
49
+ oldScrollLeft: number;
50
+ oldTimelineWidth: number;
51
+ newTimelineWidth: number;
52
+ }) => number;
53
+ export declare const prepareToPreserveTimelineCursor: ({ currentFrame, currentDurationInFrames, anchorFrame, anchorContentX, }: {
50
54
  currentFrame: number;
51
55
  currentDurationInFrames: number;
52
56
  anchorFrame: number | null;
53
57
  /** Prefer this over `anchorFrame` when not null (subpixel-accurate anchor). */
54
58
  anchorContentX: number | null;
55
- }) => void;
59
+ }) => () => void;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.zoomAndPreserveCursor = exports.viewportClientXToScrollContentX = exports.getFrameFromX = exports.getFrameWhileScrollingRight = exports.getFrameIncrementFromWidth = exports.getScrollPositionForCursorOnRightEdge = exports.getScrollPositionForCursorOnLeftEdge = exports.scrollToTimelineXOffset = exports.ensureFrameIsInViewport = exports.isCursorInViewport = exports.getFrameWhileScrollingLeft = exports.canScrollTimelineIntoDirection = void 0;
3
+ exports.prepareToPreserveTimelineCursor = exports.getScrollLeftToKeepCursorInPlace = exports.viewportClientXToScrollContentX = exports.getFrameFromX = exports.getFrameWhileScrollingRight = exports.getFrameIncrementFromWidth = exports.getScrollPositionForCursorOnRightEdge = exports.getScrollPositionForCursorOnLeftEdge = exports.scrollToTimelineXOffset = exports.ensureFrameIsInViewport = exports.isCursorInViewport = exports.getFrameWhileScrollingLeft = exports.canScrollTimelineIntoDirection = void 0;
4
4
  const remotion_1 = require("remotion");
5
5
  const timeline_layout_1 = require("../../helpers/timeline-layout");
6
6
  const timeline_refs_1 = require("./timeline-refs");
@@ -214,24 +214,38 @@ const viewportClientXToScrollContentX = ({ clientX, scrollEl, }) => {
214
214
  return clampedClientX + scrollEl.scrollLeft - rect.left;
215
215
  };
216
216
  exports.viewportClientXToScrollContentX = viewportClientXToScrollContentX;
217
- const zoomAndPreserveCursor = ({ oldZoom, newZoom, currentFrame, currentDurationInFrames, anchorFrame, anchorContentX, }) => {
218
- const ratio = newZoom / oldZoom;
219
- if (ratio === 1) {
220
- return;
221
- }
217
+ const getScrollLeftToKeepCursorInPlace = ({ anchorContentX, oldScrollLeft, oldTimelineWidth, newTimelineWidth, }) => {
218
+ const oldUsableWidth = getUsableTimelineWidth(oldTimelineWidth);
219
+ const newUsableWidth = getUsableTimelineWidth(newTimelineWidth);
220
+ const clampedAnchorContentX = Math.min(Math.max(anchorContentX, timeline_layout_1.TIMELINE_PADDING), timeline_layout_1.TIMELINE_PADDING + oldUsableWidth);
221
+ const cursorX = clampedAnchorContentX - oldScrollLeft;
222
+ const anchorInUsableWidth = clampedAnchorContentX - timeline_layout_1.TIMELINE_PADDING;
223
+ const newAnchorContentX = timeline_layout_1.TIMELINE_PADDING + (anchorInUsableWidth / oldUsableWidth) * newUsableWidth;
224
+ return newAnchorContentX - cursorX;
225
+ };
226
+ exports.getScrollLeftToKeepCursorInPlace = getScrollLeftToKeepCursorInPlace;
227
+ const prepareToPreserveTimelineCursor = ({ currentFrame, currentDurationInFrames, anchorFrame, anchorContentX, }) => {
222
228
  const { current } = timeline_refs_1.scrollableRef;
223
229
  if (!current) {
224
- return;
230
+ return () => undefined;
225
231
  }
226
- const frameIncrement = getFrameIncrement(currentDurationInFrames);
232
+ const oldTimelineWidth = current.scrollWidth;
233
+ const oldScrollLeft = current.scrollLeft;
234
+ const frameIncrement = (0, exports.getFrameIncrementFromWidth)(currentDurationInFrames, oldTimelineWidth);
227
235
  const frameForScroll = anchorFrame !== null && anchorFrame !== void 0 ? anchorFrame : currentFrame;
228
236
  const prevCursorPosition = anchorContentX !== null
229
- ? Math.min(Math.max(anchorContentX, 0), current.scrollWidth)
237
+ ? anchorContentX
230
238
  : frameIncrement * frameForScroll + timeline_layout_1.TIMELINE_PADDING;
231
- const newCursorPosition = ratio * (prevCursorPosition - timeline_layout_1.TIMELINE_PADDING) + timeline_layout_1.TIMELINE_PADDING;
232
- current.scrollLeft += newCursorPosition - prevCursorPosition;
233
- // Playhead position is synced in `TimelineSlider` `useLayoutEffect` using
234
- // measured `sliderAreaRef.clientWidth` so it matches layout after zoom
235
- // (avoids fighting React `style` with stale `timelineWidth` during pinch).
239
+ return () => {
240
+ if (timeline_refs_1.scrollableRef.current !== current) {
241
+ return;
242
+ }
243
+ current.scrollLeft = (0, exports.getScrollLeftToKeepCursorInPlace)({
244
+ anchorContentX: prevCursorPosition,
245
+ oldScrollLeft,
246
+ oldTimelineWidth,
247
+ newTimelineWidth: current.scrollWidth,
248
+ });
249
+ };
236
250
  };
237
- exports.zoomAndPreserveCursor = zoomAndPreserveCursor;
251
+ exports.prepareToPreserveTimelineCursor = prepareToPreserveTimelineCursor;
@@ -43,6 +43,7 @@ export declare const getAssetElementForDroppedFile: ({ fileType, src, }: {
43
43
  } | null;
44
44
  position: InsertableCompositionElementPosition | null;
45
45
  } | null;
46
+ export declare const hasSvgFile: (files: File[]) => boolean;
46
47
  export declare const getElementPositionForDrop: ({ dimensions, dropPosition, }: {
47
48
  dimensions: Dimensions | null;
48
49
  dropPosition: InsertElementDropPosition | null;
@@ -67,12 +68,27 @@ export declare const getComponentDimensions: (component: {
67
68
  export declare const pickFilesToImport: ({ multiple, }?: {
68
69
  readonly multiple?: boolean | undefined;
69
70
  }) => Promise<File[]>;
70
- export declare const importAssets: ({ compositionFile, compositionId, destinationDimensions, dropPosition, files, }: {
71
+ export declare const importAssets: ({ compositionFile, compositionId, destinationDimensions, dropPosition, files, svgImportMode, }: {
71
72
  compositionFile: string;
72
73
  compositionId: string;
73
74
  destinationDimensions: Dimensions | null;
74
75
  dropPosition: InsertElementDropPosition | null;
75
76
  files: File[];
77
+ svgImportMode: "image" | "inline";
78
+ }) => Promise<void>;
79
+ export declare const importFigmaClipboard: ({ compositionFile, compositionId, destinationDimensions, dropPosition, html, }: {
80
+ compositionFile: string;
81
+ compositionId: string;
82
+ destinationDimensions: Dimensions | null;
83
+ dropPosition: InsertElementDropPosition | null;
84
+ html: string;
85
+ }) => Promise<void>;
86
+ export declare const insertSvgMarkup: ({ compositionFile, compositionId, destinationDimensions, dropPosition, markup, }: {
87
+ compositionFile: string;
88
+ compositionId: string;
89
+ destinationDimensions: Dimensions | null;
90
+ dropPosition: InsertElementDropPosition | null;
91
+ markup: string;
76
92
  }) => Promise<void>;
77
93
  export declare const importRemoteAsset: ({ compositionFile, compositionId, destinationDimensions, dropPosition, url, }: {
78
94
  compositionFile: string;
@@ -1,12 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.insertElement = exports.insertComposition = exports.insertComponent = exports.insertExistingAssets = exports.insertRemoteAudio = exports.importRemoteAsset = exports.importAssets = exports.pickFilesToImport = exports.getComponentDimensions = exports.getAssetPositionForDrop = exports.getCompositionPositionForDrop = exports.getElementPositionForDrop = exports.getAssetElementForDroppedFile = exports.getAssetElementFromPath = exports.getAssetElement = void 0;
3
+ exports.insertElement = exports.insertComposition = exports.insertComponent = exports.insertExistingAssets = exports.insertRemoteAudio = exports.importRemoteAsset = exports.insertSvgMarkup = exports.importFigmaClipboard = exports.importAssets = exports.pickFilesToImport = exports.getComponentDimensions = exports.getAssetPositionForDrop = exports.getCompositionPositionForDrop = exports.getElementPositionForDrop = exports.hasSvgFile = exports.getAssetElementForDroppedFile = exports.getAssetElementFromPath = exports.getAssetElement = void 0;
4
4
  const media_utils_1 = require("@remotion/media-utils");
5
5
  const studio_shared_1 = require("@remotion/studio-shared");
6
6
  const remotion_1 = require("remotion");
7
7
  const no_react_1 = require("remotion/no-react");
8
8
  const get_static_files_1 = require("../api/get-static-files");
9
9
  const write_static_file_1 = require("../api/write-static-file");
10
+ const clipboard_figma_1 = require("../helpers/clipboard-figma");
10
11
  const install_required_package_1 = require("../helpers/install-required-package");
11
12
  const call_api_1 = require("./call-api");
12
13
  const NotificationCenter_1 = require("./Notifications/NotificationCenter");
@@ -156,12 +157,15 @@ const getAssetElementForDroppedFile = ({ fileType, src, }) => {
156
157
  return (0, exports.getAssetElementFromPath)(src);
157
158
  };
158
159
  exports.getAssetElementForDroppedFile = getAssetElementForDroppedFile;
160
+ const isSvgFile = (file) => file.name.toLowerCase().endsWith('.svg');
161
+ const hasSvgFile = (files) => files.some(isSvgFile);
162
+ exports.hasSvgFile = hasSvgFile;
159
163
  const getAssetLabel = (element) => {
160
164
  if (element.type !== 'asset') {
161
165
  throw new Error('Expected asset element');
162
166
  }
163
167
  if (element.assetType === 'image') {
164
- return '<Img>';
168
+ return '<CanvasImage>';
165
169
  }
166
170
  if (element.assetType === 'video') {
167
171
  return '<Video>';
@@ -406,7 +410,7 @@ const notifyUnsupportedFiles = (unsupportedFiles) => {
406
410
  (0, NotificationCenter_1.showNotification)(`Skipped ${unsupportedFiles.length} unsupported files`, 3000);
407
411
  }
408
412
  };
409
- const insertAssetElement = async ({ compositionFile, compositionId, element, }) => {
413
+ const insertCompositionElement = async ({ compositionFile, compositionId, element, }) => {
410
414
  const requiredPackage = (0, studio_shared_1.getRequiredPackageForInsertableElement)(element);
411
415
  await (0, install_required_package_1.installRequiredPackages)(requiredPackage ? [requiredPackage] : []);
412
416
  const result = await (0, call_api_1.callApi)('/api/insert-jsx-element', {
@@ -423,13 +427,16 @@ const insertAssetElement = async ({ compositionFile, compositionId, element, })
423
427
  const downloadRemoteAsset = (url) => {
424
428
  return (0, call_api_1.callApi)('/api/download-remote-asset', { url });
425
429
  };
426
- const importAssets = async ({ compositionFile, compositionId, destinationDimensions, dropPosition, files, }) => {
430
+ const importAssets = async ({ compositionFile, compositionId, destinationDimensions, dropPosition, files, svgImportMode, }) => {
427
431
  var _a;
428
432
  if (files.length === 0) {
429
433
  return;
430
434
  }
431
435
  const staticFiles = (0, get_static_files_1.getStaticFiles)();
432
436
  const differentExistingFile = files.find((file) => {
437
+ if (isSvgFile(file) && svgImportMode === 'inline') {
438
+ return false;
439
+ }
433
440
  return staticFiles.some((existingStaticFile) => existingStaticFile.name === file.name &&
434
441
  existingStaticFile.sizeInBytes !== file.size);
435
442
  });
@@ -453,6 +460,28 @@ const importAssets = async ({ compositionFile, compositionId, destinationDimensi
453
460
  for (const file of files) {
454
461
  const contents = await file.arrayBuffer();
455
462
  const fileType = (0, studio_shared_1.detectFileType)(new Uint8Array(contents));
463
+ const dimensions = await getFileDimensionsOrNull({ file, fileType });
464
+ if (isSvgFile(file) && svgImportMode === 'inline') {
465
+ const svgInserted = await insertCompositionElement({
466
+ compositionFile,
467
+ compositionId,
468
+ element: {
469
+ type: 'svg',
470
+ markup: new TextDecoder().decode(contents),
471
+ position: (0, exports.getAssetPositionForDrop)({
472
+ assetDimensions: dimensions,
473
+ destinationDimensions,
474
+ dropPosition,
475
+ }),
476
+ },
477
+ });
478
+ if (!svgInserted) {
479
+ notifyAddedStaticFiles();
480
+ return;
481
+ }
482
+ insertedLabels.push('<Interactive.Svg>');
483
+ continue;
484
+ }
456
485
  const element = (0, exports.getAssetElementForDroppedFile)({
457
486
  fileType,
458
487
  src: file.name,
@@ -470,9 +499,8 @@ const importAssets = async ({ compositionFile, compositionId, destinationDimensi
470
499
  });
471
500
  addedStaticFiles.push(file.name);
472
501
  }
473
- const dimensions = await getFileDimensionsOrNull({ file, fileType });
474
502
  const resolvedDimensions = (_a = element.dimensions) !== null && _a !== void 0 ? _a : dimensions;
475
- const inserted = await insertAssetElement({
503
+ const inserted = await insertCompositionElement({
476
504
  compositionFile,
477
505
  compositionId,
478
506
  element: {
@@ -500,6 +528,63 @@ const importAssets = async ({ compositionFile, compositionId, destinationDimensi
500
528
  }
501
529
  };
502
530
  exports.importAssets = importAssets;
531
+ const importFigmaClipboard = async ({ compositionFile, compositionId, destinationDimensions, dropPosition, html, }) => {
532
+ try {
533
+ const converted = await (0, call_api_1.callApi)('/api/convert-figma-clipboard-to-svg', {
534
+ html,
535
+ });
536
+ if (!converted.success) {
537
+ (0, NotificationCenter_1.showNotification)((0, clipboard_figma_1.formatFigmaClipboardErrorNotification)(converted.reason), 8000);
538
+ return;
539
+ }
540
+ await (0, exports.insertSvgMarkup)({
541
+ compositionFile,
542
+ compositionId,
543
+ destinationDimensions,
544
+ dropPosition,
545
+ markup: converted.svg,
546
+ });
547
+ }
548
+ catch (error) {
549
+ (0, NotificationCenter_1.showNotification)((0, clipboard_figma_1.formatFigmaClipboardErrorNotification)(error instanceof Error ? error.message : String(error)), 8000);
550
+ }
551
+ };
552
+ exports.importFigmaClipboard = importFigmaClipboard;
553
+ const insertSvgMarkup = async ({ compositionFile, compositionId, destinationDimensions, dropPosition, markup, }) => {
554
+ try {
555
+ const objectUrl = URL.createObjectURL(new Blob([markup], { type: 'image/svg+xml' }));
556
+ let dimensions = null;
557
+ try {
558
+ dimensions = await getImageDimensions({
559
+ revokeObjectUrl: true,
560
+ src: objectUrl,
561
+ });
562
+ }
563
+ catch (_a) {
564
+ dimensions = null;
565
+ }
566
+ const inserted = await insertCompositionElement({
567
+ compositionFile,
568
+ compositionId,
569
+ element: {
570
+ type: 'svg',
571
+ markup,
572
+ position: (0, exports.getAssetPositionForDrop)({
573
+ assetDimensions: dimensions,
574
+ destinationDimensions,
575
+ dropPosition,
576
+ }),
577
+ },
578
+ });
579
+ if (inserted) {
580
+ notifyInsertedAssets(['<Interactive.Svg>']);
581
+ }
582
+ }
583
+ catch (error) {
584
+ (0, NotificationCenter_1.showNotification)(`Could not add SVG: ${error instanceof Error ? error.message : String(error)}`, 4000);
585
+ }
586
+ };
587
+ exports.insertSvgMarkup = insertSvgMarkup;
503
588
  const importRemoteAsset = async ({ compositionFile, compositionId, destinationDimensions, dropPosition, url, }) => {
504
589
  try {
505
590
  const { assetPath, created, element } = await downloadRemoteAsset(url);
@@ -510,7 +595,7 @@ const importRemoteAsset = async ({ compositionFile, compositionId, destinationDi
510
595
  (0, NotificationCenter_1.showNotification)('Cannot add remote asset: Unsupported asset type', 3000);
511
596
  return;
512
597
  }
513
- const inserted = await insertAssetElement({
598
+ const inserted = await insertCompositionElement({
514
599
  compositionFile,
515
600
  compositionId,
516
601
  element: {
@@ -546,7 +631,7 @@ const insertRemoteAudio = async ({ compositionFile, compositionId, url, }) => {
546
631
  position: null,
547
632
  };
548
633
  try {
549
- const inserted = await insertAssetElement({
634
+ const inserted = await insertCompositionElement({
550
635
  compositionFile,
551
636
  compositionId,
552
637
  element,
@@ -576,7 +661,7 @@ const insertExistingAssets = async ({ assetPaths, compositionFile, compositionId
576
661
  continue;
577
662
  }
578
663
  const dimensions = (_a = element.dimensions) !== null && _a !== void 0 ? _a : (await getStaticAssetDimensionsOrNull(assetPath));
579
- const inserted = await insertAssetElement({
664
+ const inserted = await insertCompositionElement({
580
665
  compositionFile,
581
666
  compositionId,
582
667
  element: {
@@ -604,7 +689,7 @@ const insertExistingAssets = async ({ assetPaths, compositionFile, compositionId
604
689
  exports.insertExistingAssets = insertExistingAssets;
605
690
  const insertComponent = async ({ component, compositionFile, compositionId, dropPosition, }) => {
606
691
  try {
607
- const inserted = await insertAssetElement({
692
+ const inserted = await insertCompositionElement({
608
693
  compositionFile,
609
694
  compositionId,
610
695
  element: {
@@ -655,7 +740,7 @@ const insertComposition = async ({ composition, compositionFile, compositionId,
655
740
  width: calculated.width,
656
741
  height: calculated.height,
657
742
  };
658
- const inserted = await insertAssetElement({
743
+ const inserted = await insertCompositionElement({
659
744
  compositionFile,
660
745
  compositionId,
661
746
  element: {
@@ -1,6 +1,8 @@
1
1
  import type { HTMLAttributes } from 'react';
2
2
  import React from 'react';
3
3
  export declare const SPACING_UNIT = 8;
4
+ export declare const COMPACT_CONTROL_ROW_HEIGHT = 28;
5
+ export declare const COMPACT_INLINE_ROW_HEIGHT = 22;
4
6
  export declare const Spacing: React.FC<{
5
7
  readonly x?: number;
6
8
  readonly y?: number;
@@ -1,9 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Column = exports.Row = exports.Flex = exports.Spacing = exports.SPACING_UNIT = void 0;
3
+ exports.Column = exports.Row = exports.Flex = exports.Spacing = exports.COMPACT_INLINE_ROW_HEIGHT = exports.COMPACT_CONTROL_ROW_HEIGHT = exports.SPACING_UNIT = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_1 = require("react");
6
6
  exports.SPACING_UNIT = 8;
7
+ exports.COMPACT_CONTROL_ROW_HEIGHT = 28;
8
+ exports.COMPACT_INLINE_ROW_HEIGHT = 22;
7
9
  const Spacing = ({ x = 0, y = 0, block = false }) => {
8
10
  const style = (0, react_1.useMemo)(() => {
9
11
  return {
@@ -0,0 +1,2 @@
1
+ import type { SelectionItem } from './NewComposition/ComboBox';
2
+ export declare const getOpenInNewWindowMenuItem: (route: string) => SelectionItem;
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getOpenInNewWindowMenuItem = void 0;
4
+ const url_state_1 = require("../helpers/url-state");
5
+ const getOpenInNewWindowMenuItem = (route) => {
6
+ return {
7
+ id: 'open-in-new-window',
8
+ keyHint: null,
9
+ label: 'Open in new window',
10
+ leftItem: null,
11
+ onClick: () => {
12
+ var _a, _b;
13
+ const screen = window.screen;
14
+ const width = Math.min(1200, Math.floor(screen.availWidth * 0.8));
15
+ const height = Math.min(800, Math.floor(screen.availHeight * 0.8));
16
+ const displayLeft = (_a = screen.availLeft) !== null && _a !== void 0 ? _a : 0;
17
+ const displayTop = (_b = screen.availTop) !== null && _b !== void 0 ? _b : 0;
18
+ const left = Math.round(Math.min(Math.max(window.screenX + (window.outerWidth - width) / 2, displayLeft), displayLeft + screen.availWidth - width));
19
+ const top = Math.round(Math.min(Math.max(window.screenY + (window.outerHeight - height) / 2, displayTop), displayTop + screen.availHeight - height));
20
+ window.open((0, url_state_1.getUrlForRoute)(route), '_blank', `popup,width=${width},height=${height},left=${left},top=${top}`);
21
+ },
22
+ quickSwitcherLabel: null,
23
+ subMenu: null,
24
+ type: 'item',
25
+ value: 'open-in-new-window',
26
+ };
27
+ };
28
+ exports.getOpenInNewWindowMenuItem = getOpenInNewWindowMenuItem;
@@ -58,10 +58,11 @@ type SelectedTransformOriginInfo = {
58
58
  readonly displayFrame: number | null;
59
59
  };
60
60
  export declare const getSelectedTransformOriginInfo: (selectedItems: readonly TimelineSelection[]) => SelectedTransformOriginInfo | null;
61
- export declare const getSequencesWithSelectableOutlines: ({ sequences, overrideIdsToNodePaths, compositions, }: {
61
+ export declare const getSequencesWithSelectableOutlines: ({ sequences, overrideIdsToNodePaths, compositions, timelinePosition, }: {
62
62
  readonly sequences: readonly TSequence[];
63
63
  readonly overrideIdsToNodePaths: OverrideIdToNodePaths;
64
64
  readonly compositions?: readonly import("remotion").AnyComposition[] | undefined;
65
+ readonly timelinePosition: number;
65
66
  }) => SequenceWithSelectedOutline[];
66
67
  export declare const measureOutlines: (container: SVGSVGElement, targets: readonly SelectedOutlineTarget[]) => SelectedOutline[];
67
68
  export declare const outlinesAreEqual: (a: readonly SelectedOutline[], b: readonly SelectedOutline[]) => boolean;
@@ -306,7 +306,7 @@ const getSelectedTransformOriginInfo = (selectedItems) => {
306
306
  };
307
307
  };
308
308
  exports.getSelectedTransformOriginInfo = getSelectedTransformOriginInfo;
309
- const getSequencesWithSelectableOutlines = ({ sequences, overrideIdsToNodePaths, compositions = [], }) => {
309
+ const getSequencesWithSelectableOutlines = ({ sequences, overrideIdsToNodePaths, compositions = [], timelinePosition, }) => {
310
310
  return (0, calculate_timeline_1.calculateTimeline)({
311
311
  sequences: [...sequences],
312
312
  overrideIdsToNodePaths,
@@ -317,6 +317,8 @@ const getSequencesWithSelectableOutlines = ({ sequences, overrideIdsToNodePaths,
317
317
  return false;
318
318
  }
319
319
  return (track.sequence.showInTimeline &&
320
+ timelinePosition >= track.sequence.from &&
321
+ timelinePosition < track.sequence.from + track.sequence.duration &&
320
322
  track.nodePathInfo.auxiliaryKeys.length === 0);
321
323
  })
322
324
  .filter((track) => track.sequence.refForOutline !== null)