@remotion/studio 4.0.470 → 4.0.471

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 (35) hide show
  1. package/dist/components/ContextMenu.d.ts +7 -2
  2. package/dist/components/ContextMenu.js +50 -10
  3. package/dist/components/Preview.js +2 -1
  4. package/dist/components/SelectedOutlineOverlay.d.ts +31 -0
  5. package/dist/components/SelectedOutlineOverlay.js +100 -35
  6. package/dist/components/Timeline/Timeline.js +76 -1
  7. package/dist/components/Timeline/TimelineDeleteKeybindings.js +15 -0
  8. package/dist/components/Timeline/TimelineDragHandler.js +1 -0
  9. package/dist/components/Timeline/TimelineEffectItem.js +157 -4
  10. package/dist/components/Timeline/TimelineKeyframeControls.js +16 -11
  11. package/dist/components/Timeline/TimelineRowChrome.d.ts +3 -0
  12. package/dist/components/Timeline/TimelineRowChrome.js +3 -3
  13. package/dist/components/Timeline/TimelineSequenceItem.js +91 -1
  14. package/dist/components/Timeline/call-delete-keyframe.d.ts +16 -0
  15. package/dist/components/Timeline/call-delete-keyframe.js +86 -14
  16. package/dist/components/Timeline/delete-selected-keyframe.d.ts +10 -0
  17. package/dist/components/Timeline/delete-selected-keyframe.js +48 -7
  18. package/dist/components/Timeline/delete-selected-timeline-item.js +6 -11
  19. package/dist/components/Timeline/reset-selected-timeline-props.d.ts +38 -0
  20. package/dist/components/Timeline/reset-selected-timeline-props.js +143 -0
  21. package/dist/components/Timeline/sequence-props-subscription-store.d.ts +3 -2
  22. package/dist/components/Timeline/sequence-props-subscription-store.js +2 -1
  23. package/dist/components/Timeline/timeline-scroll-logic.js +3 -3
  24. package/dist/components/Timeline/use-sequence-props-subscription.js +2 -1
  25. package/dist/esm/{chunk-dny42qnq.js → chunk-z0z9d4r0.js} +1704 -962
  26. package/dist/esm/internals.mjs +1704 -962
  27. package/dist/esm/previewEntry.mjs +1711 -967
  28. package/dist/esm/renderEntry.mjs +1 -1
  29. package/dist/helpers/get-left-of-timeline-slider.js +1 -1
  30. package/dist/helpers/get-timeline-sequence-layout.js +10 -11
  31. package/dist/helpers/open-in-editor.d.ts +19 -1
  32. package/dist/helpers/open-in-editor.js +42 -4
  33. package/dist/helpers/use-menu-structure.js +0 -1
  34. package/dist/state/z-index.js +5 -2
  35. package/package.json +10 -10
@@ -209,7 +209,7 @@ var renderContent = (Root) => {
209
209
  renderToDOM(/* @__PURE__ */ jsx("div", {
210
210
  children: /* @__PURE__ */ jsx(DelayedSpinner, {})
211
211
  }));
212
- import("./chunk-dny42qnq.js").then(({ StudioInternals }) => {
212
+ import("./chunk-z0z9d4r0.js").then(({ StudioInternals }) => {
213
213
  window.remotion_isStudio = true;
214
214
  window.remotion_isReadOnlyStudio = true;
215
215
  window.remotion_inputProps = "{}";
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getXPositionOfItemInTimelineImperatively = void 0;
4
4
  const timeline_layout_1 = require("./timeline-layout");
5
5
  const getXPositionOfItemInTimelineImperatively = (frame, duration, width) => {
6
- const proportion = frame / (duration - 1);
6
+ const proportion = frame / duration;
7
7
  return proportion * (width - timeline_layout_1.TIMELINE_PADDING * 2) + timeline_layout_1.TIMELINE_PADDING;
8
8
  };
9
9
  exports.getXPositionOfItemInTimelineImperatively = getXPositionOfItemInTimelineImperatively;
@@ -3,35 +3,34 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getTimelineSequenceLayout = exports.SEQUENCE_BORDER_WIDTH = void 0;
4
4
  const timeline_layout_1 = require("./timeline-layout");
5
5
  exports.SEQUENCE_BORDER_WIDTH = 1;
6
- const getWidthOfTrack = ({ durationInFrames, lastFrame, windowWidth, spatialDuration, nonNegativeMarginLeft, }) => {
6
+ const getWidthOfTrack = ({ durationInFrames, timelineDuration, windowWidth, spatialDuration, nonNegativeMarginLeft, }) => {
7
7
  const fullWidth = windowWidth - timeline_layout_1.TIMELINE_PADDING * 2;
8
- const base = durationInFrames === Infinity || lastFrame === 0
8
+ const base = durationInFrames === Infinity || timelineDuration <= 0
9
9
  ? fullWidth
10
- : (spatialDuration / lastFrame) * fullWidth;
10
+ : (spatialDuration / timelineDuration) * fullWidth;
11
11
  return Math.max(0, base - exports.SEQUENCE_BORDER_WIDTH + nonNegativeMarginLeft);
12
12
  };
13
13
  const getTimelineSequenceLayout = ({ durationInFrames, startFrom, maxMediaDuration, startFromMedia, video, windowWidth, premountDisplay, postmountDisplay, }) => {
14
14
  var _a;
15
15
  const maxMediaSequenceDuration = (maxMediaDuration !== null && maxMediaDuration !== void 0 ? maxMediaDuration : Infinity) - startFromMedia;
16
16
  const timelineDuration = (_a = video.durationInFrames) !== null && _a !== void 0 ? _a : 1;
17
- const lastFrame = timelineDuration - 1;
18
17
  const spatialDuration = Math.max(0, Math.min(maxMediaSequenceDuration, durationInFrames, timelineDuration - startFrom));
19
- // Unclipped spatial duration: without the lastFrame - startFrom constraint
18
+ // Unclipped spatial duration: without the timeline-end constraint
20
19
  const naturalSpatialDuration = Math.max(0, Math.min(maxMediaSequenceDuration, durationInFrames));
21
- const marginLeft = lastFrame === 0
20
+ const marginLeft = timelineDuration <= 0
22
21
  ? 0
23
- : (startFrom / lastFrame) * (windowWidth - timeline_layout_1.TIMELINE_PADDING * 2);
22
+ : (startFrom / timelineDuration) * (windowWidth - timeline_layout_1.TIMELINE_PADDING * 2);
24
23
  const nonNegativeMarginLeft = Math.min(marginLeft, 0);
25
24
  const width = getWidthOfTrack({
26
25
  durationInFrames,
27
- lastFrame,
26
+ timelineDuration,
28
27
  nonNegativeMarginLeft,
29
28
  spatialDuration,
30
29
  windowWidth,
31
30
  });
32
31
  const naturalWidth = getWidthOfTrack({
33
32
  durationInFrames,
34
- lastFrame,
33
+ timelineDuration,
35
34
  nonNegativeMarginLeft,
36
35
  spatialDuration: naturalSpatialDuration,
37
36
  windowWidth,
@@ -39,7 +38,7 @@ const getTimelineSequenceLayout = ({ durationInFrames, startFrom, maxMediaDurati
39
38
  const premountWidth = premountDisplay
40
39
  ? getWidthOfTrack({
41
40
  durationInFrames: premountDisplay,
42
- lastFrame,
41
+ timelineDuration,
43
42
  nonNegativeMarginLeft,
44
43
  spatialDuration: premountDisplay,
45
44
  windowWidth,
@@ -48,7 +47,7 @@ const getTimelineSequenceLayout = ({ durationInFrames, startFrom, maxMediaDurati
48
47
  const postmountWidth = postmountDisplay
49
48
  ? getWidthOfTrack({
50
49
  durationInFrames: postmountDisplay,
51
- lastFrame,
50
+ timelineDuration,
52
51
  nonNegativeMarginLeft,
53
52
  spatialDuration: postmountDisplay,
54
53
  windowWidth,
@@ -1,7 +1,24 @@
1
- import type { SymbolicatedStackFrame } from '@remotion/studio-shared';
1
+ import type { CompositionComponentInfoResponse, SymbolicatedStackFrame } from '@remotion/studio-shared';
2
2
  import type { OriginalPosition } from '../error-overlay/react-overlay/utils/get-source-map';
3
3
  export declare const openInEditor: (stack: SymbolicatedStackFrame) => Promise<import("@remotion/studio-shared").OpenInEditorResponse>;
4
4
  export declare const openOriginalPositionInEditor: (originalPosition: OriginalPosition) => Promise<void>;
5
+ type ResolvedCompositionComponentInfo = {
6
+ location: CompositionComponentInfoResponse['location'];
7
+ canAddSequence: boolean;
8
+ };
9
+ export declare const subscribeToCompositionComponentInfo: (listener: () => void) => () => void;
10
+ export declare const getCachedCompositionComponentInfo: ({ compositionFile, compositionId, }: {
11
+ compositionFile: string;
12
+ compositionId: string;
13
+ }) => ResolvedCompositionComponentInfo | null;
14
+ export declare const useCachedCompositionComponentInfo: ({ compositionFile, compositionId, }: {
15
+ compositionFile: string | null;
16
+ compositionId: string | null;
17
+ }) => ResolvedCompositionComponentInfo | null;
18
+ export declare const loadCompositionComponentInfo: ({ compositionFile, compositionId, }: {
19
+ compositionFile: string;
20
+ compositionId: string;
21
+ }) => Promise<ResolvedCompositionComponentInfo>;
5
22
  export declare const preloadCompositionComponentInfo: ({ compositionFile, compositionId, }: {
6
23
  compositionFile: string;
7
24
  compositionId: string;
@@ -10,3 +27,4 @@ export declare const openCompositionComponentInEditor: ({ compositionFile, compo
10
27
  compositionFile: string;
11
28
  compositionId: string;
12
29
  }) => Promise<void>;
30
+ export {};
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.openCompositionComponentInEditor = exports.preloadCompositionComponentInfo = exports.openOriginalPositionInEditor = exports.openInEditor = void 0;
3
+ exports.openCompositionComponentInEditor = exports.preloadCompositionComponentInfo = exports.loadCompositionComponentInfo = exports.useCachedCompositionComponentInfo = exports.getCachedCompositionComponentInfo = exports.subscribeToCompositionComponentInfo = exports.openOriginalPositionInEditor = exports.openInEditor = void 0;
4
+ const react_1 = require("react");
4
5
  const call_api_1 = require("../components/call-api");
5
6
  const openInEditor = (stack) => {
6
7
  const { originalFileName, originalLineNumber, originalColumnNumber, originalFunctionName, originalScriptCode, } = stack;
@@ -26,9 +27,40 @@ const openOriginalPositionInEditor = async (originalPosition) => {
26
27
  };
27
28
  exports.openOriginalPositionInEditor = openOriginalPositionInEditor;
28
29
  const componentResolutionCache = new Map();
30
+ const componentResolutionResults = new Map();
31
+ const componentResolutionListeners = new Set();
29
32
  const getComponentResolutionCacheKey = ({ compositionFile, compositionId, }) => {
30
33
  return `${compositionFile}::${compositionId}`;
31
34
  };
35
+ const notifyComponentResolutionListeners = () => {
36
+ for (const listener of componentResolutionListeners) {
37
+ listener();
38
+ }
39
+ };
40
+ const subscribeToCompositionComponentInfo = (listener) => {
41
+ componentResolutionListeners.add(listener);
42
+ return () => {
43
+ componentResolutionListeners.delete(listener);
44
+ };
45
+ };
46
+ exports.subscribeToCompositionComponentInfo = subscribeToCompositionComponentInfo;
47
+ const getCachedCompositionComponentInfo = ({ compositionFile, compositionId, }) => {
48
+ var _a;
49
+ return ((_a = componentResolutionResults.get(getComponentResolutionCacheKey({ compositionFile, compositionId }))) !== null && _a !== void 0 ? _a : null);
50
+ };
51
+ exports.getCachedCompositionComponentInfo = getCachedCompositionComponentInfo;
52
+ const useCachedCompositionComponentInfo = ({ compositionFile, compositionId, }) => {
53
+ return (0, react_1.useSyncExternalStore)(exports.subscribeToCompositionComponentInfo, () => {
54
+ if (compositionFile === null || compositionId === null) {
55
+ return null;
56
+ }
57
+ return (0, exports.getCachedCompositionComponentInfo)({
58
+ compositionFile,
59
+ compositionId,
60
+ });
61
+ }, () => null);
62
+ };
63
+ exports.useCachedCompositionComponentInfo = useCachedCompositionComponentInfo;
32
64
  const loadCompositionComponentInfo = async ({ compositionFile, compositionId, }) => {
33
65
  const cacheKey = getComponentResolutionCacheKey({
34
66
  compositionFile,
@@ -43,10 +75,13 @@ const loadCompositionComponentInfo = async ({ compositionFile, compositionId, })
43
75
  compositionFile,
44
76
  compositionId,
45
77
  });
46
- return {
78
+ const result = {
47
79
  location: body.location,
48
80
  canAddSequence: body.canAddSequence,
49
81
  };
82
+ componentResolutionResults.set(cacheKey, result);
83
+ notifyComponentResolutionListeners();
84
+ return result;
50
85
  })();
51
86
  componentResolutionCache.set(cacheKey, promise);
52
87
  try {
@@ -54,18 +89,21 @@ const loadCompositionComponentInfo = async ({ compositionFile, compositionId, })
54
89
  }
55
90
  catch (err) {
56
91
  componentResolutionCache.delete(cacheKey);
92
+ componentResolutionResults.delete(cacheKey);
93
+ notifyComponentResolutionListeners();
57
94
  throw err;
58
95
  }
59
96
  };
97
+ exports.loadCompositionComponentInfo = loadCompositionComponentInfo;
60
98
  const preloadCompositionComponentInfo = ({ compositionFile, compositionId, }) => {
61
- loadCompositionComponentInfo({
99
+ (0, exports.loadCompositionComponentInfo)({
62
100
  compositionFile,
63
101
  compositionId,
64
102
  }).catch(() => undefined);
65
103
  };
66
104
  exports.preloadCompositionComponentInfo = preloadCompositionComponentInfo;
67
105
  const openCompositionComponentInEditor = async ({ compositionFile, compositionId, }) => {
68
- const info = await loadCompositionComponentInfo({
106
+ const info = await (0, exports.loadCompositionComponentInfo)({
69
107
  compositionFile,
70
108
  compositionId,
71
109
  });
@@ -171,7 +171,6 @@ const useMenuStructure = (closeMenu, readOnlyStudio) => {
171
171
  const resolvedCompositionLocation = (0, use_resolved_stack_1.useResolvedStack)((_a = currentComposition === null || currentComposition === void 0 ? void 0 : currentComposition.stack) !== null && _a !== void 0 ? _a : null);
172
172
  (0, react_1.useEffect)(() => {
173
173
  if (type !== 'connected' ||
174
- !window.remotion_editorName ||
175
174
  !currentComposition ||
176
175
  !(resolvedCompositionLocation === null || resolvedCompositionLocation === void 0 ? void 0 : resolvedCompositionLocation.source)) {
177
176
  return;
@@ -70,7 +70,10 @@ const HigherZIndex = ({ children, onEscape, onOutsideClick, disabled }) => {
70
70
  // If a menu is opened, then this component will also still receive the pointerdown event.
71
71
  // However we may not interpret it as a outside click, so we need to wait for the next tick
72
72
  requestAnimationFrame(() => {
73
- window.addEventListener('pointerdown', listener);
73
+ // The third argument `true` registers a capture-phase listener. Some Studio
74
+ // elements stop pointerdown propagation while still being outside the menu,
75
+ // so bubbling listeners would miss those clicks and keep the menu open.
76
+ window.addEventListener('pointerdown', listener, true);
74
77
  });
75
78
  return () => {
76
79
  if (onUp) {
@@ -78,7 +81,7 @@ const HigherZIndex = ({ children, onEscape, onOutsideClick, disabled }) => {
78
81
  window.removeEventListener('pointerup', onUp, { once: true });
79
82
  }
80
83
  onUp = null;
81
- return window.removeEventListener('pointerdown', listener);
84
+ return window.removeEventListener('pointerdown', listener, true);
82
85
  };
83
86
  }, [currentIndex, disabled, highestContext.highestIndex, onOutsideClick]);
84
87
  const value = (0, react_1.useMemo)(() => {
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "url": "https://github.com/remotion-dev/remotion/tree/main/packages/studio"
4
4
  },
5
5
  "name": "@remotion/studio",
6
- "version": "4.0.470",
6
+ "version": "4.0.471",
7
7
  "description": "APIs for interacting with the Remotion Studio",
8
8
  "main": "dist",
9
9
  "scripts": {
@@ -25,14 +25,14 @@
25
25
  },
26
26
  "dependencies": {
27
27
  "semver": "7.5.3",
28
- "remotion": "4.0.470",
29
- "@remotion/player": "4.0.470",
30
- "@remotion/media-utils": "4.0.470",
31
- "@remotion/renderer": "4.0.470",
32
- "@remotion/web-renderer": "4.0.470",
33
- "@remotion/studio-shared": "4.0.470",
34
- "@remotion/timeline-utils": "4.0.470",
35
- "@remotion/zod-types": "4.0.470",
28
+ "remotion": "4.0.471",
29
+ "@remotion/player": "4.0.471",
30
+ "@remotion/media-utils": "4.0.471",
31
+ "@remotion/renderer": "4.0.471",
32
+ "@remotion/web-renderer": "4.0.471",
33
+ "@remotion/studio-shared": "4.0.471",
34
+ "@remotion/timeline-utils": "4.0.471",
35
+ "@remotion/zod-types": "4.0.471",
36
36
  "@jridgewell/trace-mapping": "0.3.31",
37
37
  "mediabunny": "1.45.0",
38
38
  "memfs": "3.4.3",
@@ -43,7 +43,7 @@
43
43
  "react": "19.2.3",
44
44
  "react-dom": "19.2.3",
45
45
  "@types/semver": "7.5.3",
46
- "@remotion/eslint-config-internal": "4.0.470",
46
+ "@remotion/eslint-config-internal": "4.0.471",
47
47
  "eslint": "9.19.0",
48
48
  "@typescript/native-preview": "7.0.0-dev.20260217.1"
49
49
  },