remotion 4.0.429 → 4.0.430

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.
@@ -4,6 +4,7 @@ import type { AnyZodObject } from './any-zod-type.js';
4
4
  import type { CalculateMetadataFunction } from './Composition.js';
5
5
  import type { DownloadBehavior } from './download-behavior.js';
6
6
  import type { InferProps, PropsIfHasProps } from './props-if-has-props.js';
7
+ import type { SequenceSchema } from './sequence-field-schema.js';
7
8
  export type TComposition<Schema extends AnyZodObject, Props extends Record<string, unknown>> = {
8
9
  width: number | undefined;
9
10
  height: number | undefined;
@@ -44,8 +45,9 @@ export type LoopDisplay = {
44
45
  durationInFrames: number;
45
46
  };
46
47
  export type SequenceControls = {
47
- schema: AnyZodObject;
48
+ schema: SequenceSchema;
48
49
  currentValue: Record<string, unknown>;
50
+ overrideId: string;
49
51
  };
50
52
  export type TSequence = {
51
53
  from: number;
@@ -0,0 +1,11 @@
1
+ export type PremountContextValue = {
2
+ premountFramesRemaining: number;
3
+ playing: boolean;
4
+ };
5
+ /**
6
+ * @internal
7
+ * Provides premounting state to internal components.
8
+ * - premountFramesRemaining: accumulated frames remaining until premounting ends (0 if not premounting).
9
+ * - playing: whether the player is currently playing. Sticky true: if any parent is playing, this is true.
10
+ */
11
+ export declare const PremountContext: import("react").Context<PremountContextValue>;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PremountContext = void 0;
4
+ const react_1 = require("react");
5
+ /**
6
+ * @internal
7
+ * Provides premounting state to internal components.
8
+ * - premountFramesRemaining: accumulated frames remaining until premounting ends (0 if not premounting).
9
+ * - playing: whether the player is currently playing. Sticky true: if any parent is playing, this is true.
10
+ */
11
+ exports.PremountContext = (0, react_1.createContext)({
12
+ premountFramesRemaining: 0,
13
+ playing: false,
14
+ });
@@ -7,6 +7,7 @@ const react_1 = require("react");
7
7
  const AbsoluteFill_js_1 = require("./AbsoluteFill.js");
8
8
  const freeze_js_1 = require("./freeze.js");
9
9
  const nonce_js_1 = require("./nonce.js");
10
+ const PremountContext_js_1 = require("./PremountContext.js");
10
11
  const SequenceContext_js_1 = require("./SequenceContext.js");
11
12
  const SequenceManager_js_1 = require("./SequenceManager.js");
12
13
  const timeline_position_state_js_1 = require("./timeline-position-state.js");
@@ -201,7 +202,17 @@ const PremountedPostmountedSequenceRefForwardingFunction = (props, ref) => {
201
202
  styleWhilePremounted,
202
203
  styleWhilePostmounted,
203
204
  ]);
204
- return ((0, jsx_runtime_1.jsx)(freeze_js_1.Freeze, { frame: freezeFrame, active: isFreezingActive, children: (0, jsx_runtime_1.jsx)(exports.Sequence, { ref: ref, from: from, durationInFrames: durationInFrames, style: style, _remotionInternalPremountDisplay: premountFor, _remotionInternalPostmountDisplay: postmountFor, _remotionInternalIsPremounting: premountingActive, _remotionInternalIsPostmounting: postmountingActive, ...otherProps }) }));
205
+ const parentPremountContext = (0, react_1.useContext)(PremountContext_js_1.PremountContext);
206
+ const { playing } = (0, react_1.useContext)(TimelineContext_js_1.TimelineContext);
207
+ const premountFramesRemaining = parentPremountContext.premountFramesRemaining +
208
+ (premountingActive ? from - frame : 0);
209
+ const premountContextValue = (0, react_1.useMemo)(() => {
210
+ return {
211
+ premountFramesRemaining,
212
+ playing: parentPremountContext.playing || playing,
213
+ };
214
+ }, [premountFramesRemaining, parentPremountContext.playing, playing]);
215
+ return ((0, jsx_runtime_1.jsx)(PremountContext_js_1.PremountContext.Provider, { value: premountContextValue, children: (0, jsx_runtime_1.jsx)(freeze_js_1.Freeze, { frame: freezeFrame, active: isFreezingActive, children: (0, jsx_runtime_1.jsx)(exports.Sequence, { ref: ref, from: from, durationInFrames: durationInFrames, style: style, _remotionInternalPremountDisplay: premountFor, _remotionInternalPostmountDisplay: postmountFor, _remotionInternalIsPremounting: premountingActive, _remotionInternalIsPostmounting: postmountingActive, ...otherProps }) }) }));
205
216
  };
206
217
  const PremountedPostmountedSequence = (0, react_1.forwardRef)(PremountedPostmountedSequenceRefForwardingFunction);
207
218
  const SequenceRefForwardingFunction = (props, ref) => {
@@ -1,2 +1,2 @@
1
- export declare const enableSequenceStackTraces: () => void;
1
+ export declare const getComponentsToAddStacksTo: () => unknown[];
2
2
  export declare const addSequenceStackTraces: (component: unknown) => void;
@@ -1,44 +1,10 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.addSequenceStackTraces = exports.enableSequenceStackTraces = void 0;
7
- const react_1 = __importDefault(require("react"));
8
- const jsx_runtime_1 = __importDefault(require("react/jsx-runtime"));
9
- const get_remotion_environment_1 = require("./get-remotion-environment");
10
- const originalCreateElement = react_1.default.createElement;
11
- const originalJsx = jsx_runtime_1.default.jsx;
3
+ exports.addSequenceStackTraces = exports.getComponentsToAddStacksTo = void 0;
12
4
  const componentsToAddStacksTo = [];
13
- const enableProxy = (api) => {
14
- return new Proxy(api, {
15
- apply(target, thisArg, argArray) {
16
- if (componentsToAddStacksTo.includes(argArray[0])) {
17
- const [first, props, ...rest] = argArray;
18
- const newProps = props.stack
19
- ? props
20
- : {
21
- ...(props !== null && props !== void 0 ? props : {}),
22
- stack: new Error().stack,
23
- };
24
- return Reflect.apply(target, thisArg, [first, newProps, ...rest]);
25
- }
26
- return Reflect.apply(target, thisArg, argArray);
27
- },
28
- });
29
- };
30
- // Gets called when a new component is added,
31
- // also when the Studio is mounted
32
- const enableSequenceStackTraces = () => {
33
- if (!(0, get_remotion_environment_1.getRemotionEnvironment)().isStudio) {
34
- return;
35
- }
36
- react_1.default.createElement = enableProxy(originalCreateElement);
37
- jsx_runtime_1.default.jsx = enableProxy(originalJsx);
38
- };
39
- exports.enableSequenceStackTraces = enableSequenceStackTraces;
5
+ const getComponentsToAddStacksTo = () => componentsToAddStacksTo;
6
+ exports.getComponentsToAddStacksTo = getComponentsToAddStacksTo;
40
7
  const addSequenceStackTraces = (component) => {
41
8
  componentsToAddStacksTo.push(component);
42
- (0, exports.enableSequenceStackTraces)();
43
9
  };
44
10
  exports.addSequenceStackTraces = addSequenceStackTraces;
@@ -7,6 +7,7 @@ import type { StaticFile } from './get-static-files.js';
7
7
  import type { LogLevel } from './log.js';
8
8
  import type { ProResProfile } from './prores-profile.js';
9
9
  import type { PixelFormat, VideoImageFormat } from './render-types.js';
10
+ import type { SequenceFieldSchema, SequenceSchema } from './sequence-field-schema.js';
10
11
  import type { UseBufferState } from './use-buffer-state';
11
12
  import type { VideoConfig } from './video-config.js';
12
13
  export type VideoConfigWithSerializedProps = Omit<VideoConfig, 'defaultProps' | 'props'> & {
@@ -158,4 +159,4 @@ export type _InternalTypes = {
158
159
  TRenderAsset: TRenderAsset;
159
160
  ProResProfile: ProResProfile;
160
161
  };
161
- export type { AnyComposition, DelayRenderScope, LoopDisplay, SequenceControls, UseBufferState, };
162
+ export type { AnyComposition, DelayRenderScope, LoopDisplay, SequenceControls, SequenceFieldSchema, SequenceSchema, UseBufferState, };
package/dist/cjs/index.js CHANGED
@@ -128,4 +128,5 @@ exports.Config = new Proxy(proxyObj, {
128
128
  };
129
129
  },
130
130
  });
131
+ Sequence_js_1.Sequence.displayName = 'Sequence';
131
132
  (0, enable_sequence_stack_traces_js_1.addSequenceStackTraces)(Sequence_js_1.Sequence);
@@ -5,6 +5,7 @@ import * as CSSUtils from './default-css.js';
5
5
  import type { SerializedJSONWithCustomFields } from './input-props-serialization.js';
6
6
  import type { LoggingContextValue } from './log-level-context.js';
7
7
  import type { RemotionEnvironment } from './remotion-environment-context.js';
8
+ import type { SequenceFieldSchema, SequenceSchema } from './sequence-field-schema.js';
8
9
  import * as TimelinePosition from './timeline-position-state.js';
9
10
  import { type SetTimelineContextValue, type TimelineContextValue } from './TimelineContext.js';
10
11
  import { truthy } from './truthy.js';
@@ -73,6 +74,10 @@ export declare const Internals: {
73
74
  readonly SequenceControlOverrideContext: import("react").Context<import("./SequenceManager.js").SequenceControlOverrideState>;
74
75
  readonly SequenceManager: import("react").Context<import("./SequenceManager.js").SequenceManagerContext>;
75
76
  readonly SequenceVisibilityToggleContext: import("react").Context<import("./SequenceManager.js").SequenceVisibilityToggleState>;
77
+ readonly useSchema: <T extends Record<string, unknown>>(schema: SequenceSchema | null, currentValue: T | null) => {
78
+ controls: import("./CompositionManager.js").SequenceControls | undefined;
79
+ values: T;
80
+ };
76
81
  readonly useSequenceControlOverride: (key: string) => unknown | undefined;
77
82
  readonly RemotionRootContexts: import("react").FC<{
78
83
  readonly children: React.ReactNode;
@@ -120,6 +125,7 @@ export declare const Internals: {
120
125
  }) | import("react").ComponentType<Props>;
121
126
  readonly truthy: typeof truthy;
122
127
  readonly SequenceContext: import("react").Context<import("./SequenceContext.js").SequenceContextType | null>;
128
+ readonly PremountContext: import("react").Context<import("./PremountContext.js").PremountContextValue>;
123
129
  readonly useRemotionContexts: typeof useRemotionContexts;
124
130
  readonly RemotionContextProvider: (props: import("./wrap-remotion-context.js").RemotionContextProviderProps) => import("react/jsx-runtime.js").JSX.Element;
125
131
  readonly CSSUtils: typeof CSSUtils;
@@ -282,7 +288,7 @@ export declare const Internals: {
282
288
  };
283
289
  buffering: React.MutableRefObject<boolean>;
284
290
  } | null>;
285
- readonly enableSequenceStackTraces: () => void;
291
+ readonly getComponentsToAddStacksTo: () => unknown[];
286
292
  readonly CurrentScaleContext: import("react").Context<import("./use-current-scale.js").CurrentScaleContextType | null>;
287
293
  readonly PreviewSizeContext: import("react").Context<import("./use-current-scale.js").PreviewSizeCtx>;
288
294
  readonly calculateScale: ({ canvasSize, compositionHeight, compositionWidth, previewSize, }: {
@@ -421,4 +427,4 @@ export declare const Internals: {
421
427
  collectAssets: null | React.RefObject<import("./RenderAssetManager.js").CollectAssetsRef | null>;
422
428
  }>;
423
429
  };
424
- export type { CompositionManagerContext, CompProps, LoggingContextValue, MediaVolumeContextValue, RemotionEnvironment, SerializedJSONWithCustomFields, SetMediaVolumeContextValue, SetTimelineContextValue, TCompMetadata, TComposition, TimelineContextValue, TRenderAsset, TSequence, WatchRemotionStaticFilesPayload, };
430
+ export type { CompositionManagerContext, CompProps, LoggingContextValue, MediaVolumeContextValue, RemotionEnvironment, SequenceFieldSchema, SequenceSchema, SerializedJSONWithCustomFields, SetMediaVolumeContextValue, SetTimelineContextValue, TCompMetadata, TComposition, TimelineContextValue, TRenderAsset, TSequence, WatchRemotionStaticFilesPayload, };
@@ -61,6 +61,7 @@ const playback_logging_js_1 = require("./playback-logging.js");
61
61
  const portal_node_js_1 = require("./portal-node.js");
62
62
  const prefetch_state_js_1 = require("./prefetch-state.js");
63
63
  const prefetch_js_1 = require("./prefetch.js");
64
+ const PremountContext_js_1 = require("./PremountContext.js");
64
65
  const register_root_js_1 = require("./register-root.js");
65
66
  const remotion_environment_context_js_1 = require("./remotion-environment-context.js");
66
67
  const RemotionRoot_js_1 = require("./RemotionRoot.js");
@@ -79,6 +80,7 @@ const use_delay_render_js_1 = require("./use-delay-render.js");
79
80
  const use_lazy_component_js_1 = require("./use-lazy-component.js");
80
81
  const use_media_enabled_js_1 = require("./use-media-enabled.js");
81
82
  const use_media_in_timeline_js_1 = require("./use-media-in-timeline.js");
83
+ const use_schema_js_1 = require("./use-schema.js");
82
84
  const use_sequence_control_override_js_1 = require("./use-sequence-control-override.js");
83
85
  const use_unsafe_video_config_js_1 = require("./use-unsafe-video-config.js");
84
86
  const use_video_js_1 = require("./use-video.js");
@@ -116,6 +118,7 @@ exports.Internals = {
116
118
  SequenceControlOverrideContext: SequenceManager_js_1.SequenceControlOverrideContext,
117
119
  SequenceManager: SequenceManager_js_1.SequenceManager,
118
120
  SequenceVisibilityToggleContext: SequenceManager_js_1.SequenceVisibilityToggleContext,
121
+ useSchema: use_schema_js_1.useSchema,
119
122
  useSequenceControlOverride: use_sequence_control_override_js_1.useSequenceControlOverride,
120
123
  RemotionRootContexts: RemotionRoot_js_1.RemotionRootContexts,
121
124
  CompositionManagerProvider: CompositionManagerProvider_js_1.CompositionManagerProvider,
@@ -127,6 +130,7 @@ exports.Internals = {
127
130
  useLazyComponent: use_lazy_component_js_1.useLazyComponent,
128
131
  truthy: truthy_js_1.truthy,
129
132
  SequenceContext: SequenceContext_js_1.SequenceContext,
133
+ PremountContext: PremountContext_js_1.PremountContext,
130
134
  useRemotionContexts: wrap_remotion_context_js_1.useRemotionContexts,
131
135
  RemotionContextProvider: wrap_remotion_context_js_1.RemotionContextProvider,
132
136
  CSSUtils,
@@ -169,7 +173,7 @@ exports.Internals = {
169
173
  useMediaStartsAt: use_audio_frame_js_1.useMediaStartsAt,
170
174
  BufferingProvider: buffering_js_1.BufferingProvider,
171
175
  BufferingContextReact: buffering_js_1.BufferingContextReact,
172
- enableSequenceStackTraces: enable_sequence_stack_traces_js_1.enableSequenceStackTraces,
176
+ getComponentsToAddStacksTo: enable_sequence_stack_traces_js_1.getComponentsToAddStacksTo,
173
177
  CurrentScaleContext: use_current_scale_js_1.CurrentScaleContext,
174
178
  PreviewSizeContext: use_current_scale_js_1.PreviewSizeContext,
175
179
  calculateScale: use_current_scale_js_1.calculateScale,
@@ -0,0 +1,15 @@
1
+ export type NumberFieldSchema = {
2
+ type: 'number';
3
+ min?: number;
4
+ max?: number;
5
+ step?: number;
6
+ default?: number;
7
+ description?: string;
8
+ };
9
+ export type BooleanFieldSchema = {
10
+ type: 'boolean';
11
+ default?: boolean;
12
+ description?: string;
13
+ };
14
+ export type SequenceFieldSchema = NumberFieldSchema | BooleanFieldSchema;
15
+ export type SequenceSchema = Record<string, SequenceFieldSchema>;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ export type ResolvedStackLocation = {
3
+ line: number | null;
4
+ column: number | null;
5
+ source: string | null;
6
+ };
7
+ export type SequenceStackTracesContextType = {
8
+ resolvedStacks: Record<string, ResolvedStackLocation | null>;
9
+ };
10
+ export declare const SequenceStackTracesContext: React.Context<SequenceStackTracesContextType>;
11
+ export type UpdateResolvedStackTraceFn = (stack: string, location: ResolvedStackLocation | null) => void;
12
+ export declare const SequenceStackTracesUpdateContext: React.Context<UpdateResolvedStackTraceFn>;
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.SequenceStackTracesUpdateContext = exports.SequenceStackTracesContext = void 0;
7
+ const react_1 = __importDefault(require("react"));
8
+ exports.SequenceStackTracesContext = react_1.default.createContext({
9
+ resolvedStacks: {},
10
+ });
11
+ exports.SequenceStackTracesUpdateContext = react_1.default.createContext(() => { });
@@ -37,6 +37,27 @@ exports.useLazyComponent = void 0;
37
37
  const react_1 = __importStar(require("react"));
38
38
  // Expected, it can be any component props
39
39
  const useLazyComponent = ({ compProps, componentName, noSuspense, }) => {
40
+ // Why a ref + stable wrapper instead of returning compProps.component directly?
41
+ //
42
+ // When a user edits their component and saves, React Fast Refresh re-executes
43
+ // the module, giving compProps.component a new function reference.
44
+ // Previously, this new reference flowed into useMemo (which depended on
45
+ // compProps.component), producing a new `lazy` value. Composition.tsx then
46
+ // rendered `<Comp />` where Comp had a different identity, so React unmounted
47
+ // the old tree and mounted a fresh one — losing all component state.
48
+ //
49
+ // To fix this, we store the latest component in a ref (updated every render)
50
+ // and return a stable Wrapper from useMemo (created once). React sees the same
51
+ // Wrapper component across Fast Refresh updates, preserves the tree and state,
52
+ // while the ref ensures the Wrapper always delegates to the latest code.
53
+ //
54
+ // To reproduce: use packages/example/src/NewVideo.tsx, edit Component
55
+ // (e.g. change volume={1} to volume={2}) and save. Without this fix,
56
+ // Component would fully remount instead of fast-refreshing in place.
57
+ const componentRef = (0, react_1.useRef)(null);
58
+ if ('component' in compProps) {
59
+ componentRef.current = compProps.component;
60
+ }
40
61
  const lazy = (0, react_1.useMemo)(() => {
41
62
  if ('component' in compProps) {
42
63
  // In SSR, suspense is not yet supported, we cannot use React.lazy
@@ -46,7 +67,11 @@ const useLazyComponent = ({ compProps, componentName, noSuspense, }) => {
46
67
  if (typeof compProps.component === 'undefined') {
47
68
  throw new Error(`A value of \`undefined\` was passed to the \`component\` prop. Check the value you are passing to the <${componentName}/> component.`);
48
69
  }
49
- return compProps.component;
70
+ const Wrapper = (props) => {
71
+ const Comp = componentRef.current;
72
+ return react_1.default.createElement(Comp, props);
73
+ };
74
+ return Wrapper;
50
75
  }
51
76
  if ('lazyComponent' in compProps &&
52
77
  typeof compProps.lazyComponent !== 'undefined') {
@@ -58,9 +83,11 @@ const useLazyComponent = ({ compProps, componentName, noSuspense, }) => {
58
83
  throw new Error("You must pass either 'component' or 'lazyComponent'");
59
84
  // Very important to leave the dependencies as they are, or instead
60
85
  // the player will remount on every frame.
86
+ // For the 'component' case, we intentionally do NOT depend on
87
+ // compProps.component — the stable wrapper reads from componentRef instead.
61
88
  // @ts-expect-error
62
89
  // eslint-disable-next-line react-hooks/exhaustive-deps
63
- }, [compProps.component, compProps.lazyComponent]);
90
+ }, [compProps.lazyComponent]);
64
91
  return lazy;
65
92
  };
66
93
  exports.useLazyComponent = useLazyComponent;
@@ -0,0 +1,6 @@
1
+ import type { SequenceControls } from './CompositionManager.js';
2
+ import type { SequenceSchema } from './sequence-field-schema.js';
3
+ export declare const useSchema: <T extends Record<string, unknown>>(schema: SequenceSchema | null, currentValue: T | null) => {
4
+ controls: SequenceControls | undefined;
5
+ values: T;
6
+ };
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useSchema = void 0;
4
+ /* eslint-disable react-hooks/rules-of-hooks */
5
+ const react_1 = require("react");
6
+ const SequenceManager_js_1 = require("./SequenceManager.js");
7
+ const use_remotion_environment_js_1 = require("./use-remotion-environment.js");
8
+ const useSchema = (schema, currentValue) => {
9
+ const env = (0, use_remotion_environment_js_1.useRemotionEnvironment)();
10
+ const earlyReturn = (0, react_1.useMemo)(() => {
11
+ if (!env.isStudio || env.isReadOnlyStudio) {
12
+ return {
13
+ controls: undefined,
14
+ values: (currentValue !== null && currentValue !== void 0 ? currentValue : {}),
15
+ };
16
+ }
17
+ return undefined;
18
+ }, [env.isStudio, env.isReadOnlyStudio, currentValue]);
19
+ if (earlyReturn) {
20
+ return earlyReturn;
21
+ }
22
+ // Intentional conditional hook call, useRemotionEnvironment is stable.
23
+ const [overrideId] = (0, react_1.useState)(() => String(Math.random()));
24
+ const { overrides } = (0, react_1.useContext)(SequenceManager_js_1.SequenceControlOverrideContext);
25
+ return (0, react_1.useMemo)(() => {
26
+ var _a;
27
+ if (schema === null || currentValue === null) {
28
+ return {
29
+ controls: undefined,
30
+ values: (currentValue !== null && currentValue !== void 0 ? currentValue : {}),
31
+ };
32
+ }
33
+ const overrideValues = (_a = overrides[overrideId]) !== null && _a !== void 0 ? _a : {};
34
+ const merged = { ...currentValue };
35
+ for (const key of Object.keys(overrideValues)) {
36
+ if (key in merged) {
37
+ merged[key] = overrideValues[key];
38
+ }
39
+ }
40
+ return {
41
+ controls: {
42
+ schema,
43
+ currentValue,
44
+ overrideId,
45
+ },
46
+ values: merged,
47
+ };
48
+ }, [schema, currentValue, overrides, overrideId]);
49
+ };
50
+ exports.useSchema = useSchema;
@@ -3,4 +3,4 @@
3
3
  * @see [Documentation](https://remotion.dev/docs/version)
4
4
  * @returns {string} The current version of the remotion package
5
5
  */
6
- export declare const VERSION = "4.0.429";
6
+ export declare const VERSION = "4.0.430";
@@ -7,4 +7,4 @@ exports.VERSION = void 0;
7
7
  * @see [Documentation](https://remotion.dev/docs/version)
8
8
  * @returns {string} The current version of the remotion package
9
9
  */
10
- exports.VERSION = '4.0.429';
10
+ exports.VERSION = '4.0.430';