remotion 4.0.528 → 4.0.530

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 (79) hide show
  1. package/dist/cjs/AbsoluteFill.d.ts +7 -1
  2. package/dist/cjs/AbsoluteFill.js +10 -7
  3. package/dist/cjs/HtmlInCanvas.d.ts +11 -2
  4. package/dist/cjs/HtmlInCanvas.js +62 -17
  5. package/dist/cjs/Img.d.ts +6 -0
  6. package/dist/cjs/Img.js +12 -9
  7. package/dist/cjs/Interactive.d.ts +33 -2
  8. package/dist/cjs/Interactive.js +61 -8
  9. package/dist/cjs/Sequence.d.ts +3 -2
  10. package/dist/cjs/Sequence.js +103 -32
  11. package/dist/cjs/SequenceManager.d.ts +4 -0
  12. package/dist/cjs/SequenceManager.js +6 -1
  13. package/dist/cjs/TimelineContext.d.ts +1 -1
  14. package/dist/cjs/TimelineContext.js +2 -2
  15. package/dist/cjs/animated-image/AnimatedImage.d.ts +6 -0
  16. package/dist/cjs/animated-image/AnimatedImage.js +85 -16
  17. package/dist/cjs/audio/AudioForPreview.js +2 -3
  18. package/dist/cjs/audio/html5-audio.js +18 -6
  19. package/dist/cjs/audio/props.d.ts +5 -0
  20. package/dist/cjs/calculate-media-duration.d.ts +5 -0
  21. package/dist/cjs/calculate-media-duration.js +13 -1
  22. package/dist/cjs/canvas-image/CanvasImage.d.ts +6 -2
  23. package/dist/cjs/canvas-image/CanvasImage.js +10 -8
  24. package/dist/cjs/canvas-image/props.d.ts +0 -5
  25. package/dist/cjs/effects/Solid.d.ts +6 -0
  26. package/dist/cjs/effects/Solid.js +8 -3
  27. package/dist/cjs/effects/canvas-pool.d.ts +5 -1
  28. package/dist/cjs/effects/canvas-pool.js +49 -1
  29. package/dist/cjs/effects/run-effect-chain.d.ts +1 -0
  30. package/dist/cjs/effects/run-effect-chain.js +40 -10
  31. package/dist/cjs/effects/use-effect-chain-state.js +12 -0
  32. package/dist/cjs/effects/use-memoized-effects.js +1 -1
  33. package/dist/cjs/enable-sequence-stack-traces.d.ts +11 -0
  34. package/dist/cjs/enable-sequence-stack-traces.js +24 -1
  35. package/dist/cjs/freeze.d.ts +2 -0
  36. package/dist/cjs/freeze.js +8 -3
  37. package/dist/cjs/get-effective-visual-mode-value.js +3 -2
  38. package/dist/cjs/index.d.ts +1 -1
  39. package/dist/cjs/index.js +2 -1
  40. package/dist/cjs/interactivity-schema.d.ts +44 -1
  41. package/dist/cjs/interactivity-schema.js +18 -1
  42. package/dist/cjs/internals.d.ts +61 -8
  43. package/dist/cjs/internals.js +14 -1
  44. package/dist/cjs/interpolate-keyframed-status.d.ts +7 -1
  45. package/dist/cjs/interpolate-keyframed-status.js +34 -3
  46. package/dist/cjs/interpolate.d.ts +3 -1
  47. package/dist/cjs/interpolate.js +25 -5
  48. package/dist/cjs/loop/index.d.ts +1 -4
  49. package/dist/cjs/loop/index.js +16 -11
  50. package/dist/cjs/loop/loop-context.d.ts +5 -0
  51. package/dist/cjs/loop/loop-context.js +5 -0
  52. package/dist/cjs/no-react.d.ts +6 -0
  53. package/dist/cjs/resolve-sequence-duration.d.ts +8 -0
  54. package/dist/cjs/resolve-sequence-duration.js +18 -0
  55. package/dist/cjs/sequence-order-marker.d.ts +1 -0
  56. package/dist/cjs/sequence-outline.d.ts +11 -0
  57. package/dist/cjs/sequence-outline.js +35 -0
  58. package/dist/cjs/series/index.js +7 -1
  59. package/dist/cjs/timeline-position-state.d.ts +1 -1
  60. package/dist/cjs/timeline-position-state.js +9 -8
  61. package/dist/cjs/use-media-in-timeline.d.ts +3 -5
  62. package/dist/cjs/use-media-in-timeline.js +11 -21
  63. package/dist/cjs/use-schema.d.ts +9 -3
  64. package/dist/cjs/use-schema.js +10 -1
  65. package/dist/cjs/use-sequence-registration.js +5 -3
  66. package/dist/cjs/use-timeline-seek.d.ts +1 -1
  67. package/dist/cjs/use-timeline-seek.js +1 -1
  68. package/dist/cjs/version.d.ts +1 -1
  69. package/dist/cjs/version.js +1 -1
  70. package/dist/cjs/video/OffthreadVideo.js +21 -8
  71. package/dist/cjs/video/VideoForPreview.js +2 -3
  72. package/dist/cjs/video/html5-video.js +18 -6
  73. package/dist/cjs/video/props.d.ts +5 -0
  74. package/dist/cjs/with-interactivity-schema.d.ts +3 -0
  75. package/dist/cjs/with-interactivity-schema.js +10 -2
  76. package/dist/esm/index.mjs +1018 -466
  77. package/dist/esm/no-react.mjs +27 -5
  78. package/dist/esm/version.mjs +1 -1
  79. package/package.json +2 -2
@@ -233,6 +233,12 @@ export declare const absoluteFillSchema: {
233
233
  readonly hiddenFromList: false;
234
234
  readonly keyframable: false;
235
235
  };
236
+ readonly loop: {
237
+ readonly type: "boolean";
238
+ readonly default: false;
239
+ readonly description: "Loop";
240
+ readonly keyframable: false;
241
+ };
236
242
  readonly freeze: {
237
243
  readonly type: "number";
238
244
  readonly default: null;
@@ -243,7 +249,7 @@ export declare const absoluteFillSchema: {
243
249
  readonly name: import("./interactivity-schema.js").HiddenFieldSchema;
244
250
  readonly showInTimeline: import("./interactivity-schema.js").HiddenFieldSchema;
245
251
  };
246
- export declare const AbsoluteFill: React.ComponentType<Omit<AbsoluteFillElementProps, "durationInFrames" | "freeze" | "from" | "hidden" | "name" | "playbackRate" | "showInTimeline" | "trimBefore"> & InteractiveBaseProps & InteractivePremountProps & {
252
+ export declare const AbsoluteFill: React.ComponentType<Omit<AbsoluteFillElementProps, "durationInFrames" | "freeze" | "from" | "hidden" | "loop" | "name" | "playbackRate" | "showInTimeline" | "trimBefore"> & InteractiveBaseProps & InteractivePremountProps & {
247
253
  /**
248
254
  * @deprecated For internal use only
249
255
  */
@@ -7,6 +7,7 @@ const AbsoluteFillElement_js_1 = require("./AbsoluteFillElement.js");
7
7
  const enable_sequence_stack_traces_js_1 = require("./enable-sequence-stack-traces.js");
8
8
  const freeze_js_1 = require("./freeze.js");
9
9
  const interactivity_schema_js_1 = require("./interactivity-schema.js");
10
+ const resolve_sequence_duration_js_1 = require("./resolve-sequence-duration.js");
10
11
  const Sequence_js_1 = require("./Sequence.js");
11
12
  const use_premounting_js_1 = require("./use-premounting.js");
12
13
  const use_unsafe_video_config_js_1 = require("./use-unsafe-video-config.js");
@@ -29,11 +30,15 @@ const setRef = (ref, value) => {
29
30
  ref.current = value;
30
31
  }
31
32
  };
32
- const AbsoluteFillWithTiming = ({ ref: callbackRef, outlineRef: refForOutline, from, premountFor, postmountFor, styleWhilePremounted, styleWhilePostmounted, trimBefore, playbackRate, freeze, durationInFrames, hidden, name, showInTimeline, stack, controls, children, ...divProps }) => {
33
+ const AbsoluteFillWithTiming = ({ ref: callbackRef, from, premountFor, postmountFor, styleWhilePremounted, styleWhilePostmounted, trimBefore, playbackRate, loop, freeze, durationInFrames, hidden, name, showInTimeline, stack, controls, children, ...divProps }) => {
33
34
  var _a;
34
35
  const { effectivePremountFor, effectivePostmountFor, freezeFrame, isPremountingOrPostmounting, premountingActive, postmountingActive, premountingStyle, } = (0, use_premounting_js_1.usePremounting)({
35
36
  from: from !== null && from !== void 0 ? from : 0,
36
- durationInFrames: durationInFrames !== null && durationInFrames !== void 0 ? durationInFrames : Infinity,
37
+ durationInFrames: (0, resolve_sequence_duration_js_1.resolveSequenceDuration)({
38
+ durationInFrames,
39
+ playbackRate,
40
+ loop,
41
+ }),
37
42
  premountFor: premountFor !== null && premountFor !== void 0 ? premountFor : null,
38
43
  postmountFor: postmountFor !== null && postmountFor !== void 0 ? postmountFor : null,
39
44
  style: (_a = divProps.style) !== null && _a !== void 0 ? _a : null,
@@ -41,19 +46,17 @@ const AbsoluteFillWithTiming = ({ ref: callbackRef, outlineRef: refForOutline, f
41
46
  styleWhilePostmounted: styleWhilePostmounted !== null && styleWhilePostmounted !== void 0 ? styleWhilePostmounted : null,
42
47
  hideWhilePremounted: 'opacity',
43
48
  });
44
- return (jsx_runtime_1.jsx(freeze_js_1.Freeze, { frame: freezeFrame, active: isPremountingOrPostmounting, children: jsx_runtime_1.jsx(Sequence_js_1.Sequence, { layout: "none", from: from !== null && from !== void 0 ? from : 0, trimBefore: trimBefore, playbackRate: playbackRate, freeze: freeze, durationInFrames: durationInFrames !== null && durationInFrames !== void 0 ? durationInFrames : Infinity, hidden: hidden, name: name !== null && name !== void 0 ? name : '<AbsoluteFill>', showInTimeline: showInTimeline !== null && showInTimeline !== void 0 ? showInTimeline : true, controls: controls, _remotionInternalStack: stack, _remotionInternalDocumentationLink: "https://www.remotion.dev/docs/absolute-fill", outlineRef: refForOutline, _remotionInternalPremountDisplay: effectivePremountFor || null, _remotionInternalPostmountDisplay: effectivePostmountFor || null, _remotionInternalIsPremounting: premountingActive, _remotionInternalIsPostmounting: postmountingActive, children: jsx_runtime_1.jsx(AbsoluteFillElement_js_1.AbsoluteFillElement, { ref: callbackRef, ...divProps, style: premountingStyle !== null && premountingStyle !== void 0 ? premountingStyle : undefined, children: children }) }) }));
49
+ return (jsx_runtime_1.jsx(freeze_js_1.Freeze, { frame: freezeFrame, active: isPremountingOrPostmounting, _remotionInternalIsPremounting: premountingActive, children: jsx_runtime_1.jsx(Sequence_js_1.Sequence, { layout: "none", from: from !== null && from !== void 0 ? from : 0, trimBefore: trimBefore, playbackRate: playbackRate, loop: loop, freeze: freeze, durationInFrames: durationInFrames, hidden: hidden, name: name !== null && name !== void 0 ? name : '<AbsoluteFill>', showInTimeline: showInTimeline !== null && showInTimeline !== void 0 ? showInTimeline : true, controls: controls, _remotionInternalStack: stack, _remotionInternalDocumentationLink: "https://www.remotion.dev/docs/absolute-fill", _remotionInternalPremountDisplay: effectivePremountFor || null, _remotionInternalPostmountDisplay: effectivePostmountFor || null, _remotionInternalIsPremounting: premountingActive, _remotionInternalIsPostmounting: postmountingActive, children: jsx_runtime_1.jsx(AbsoluteFillElement_js_1.AbsoluteFillElement, { ref: callbackRef, ...divProps, style: premountingStyle !== null && premountingStyle !== void 0 ? premountingStyle : undefined, children: children }) }) }));
45
50
  };
46
- const AbsoluteFillInner = ({ ref, from, premountFor, postmountFor, styleWhilePremounted, styleWhilePostmounted, trimBefore, playbackRate, freeze, durationInFrames, hidden, name, showInTimeline, stack, controls, children, ...divProps }) => {
51
+ const AbsoluteFillInner = ({ ref, from, premountFor, postmountFor, styleWhilePremounted, styleWhilePostmounted, trimBefore, playbackRate, loop, freeze, durationInFrames, hidden, name, showInTimeline, stack, controls, children, ...divProps }) => {
47
52
  const videoConfig = (0, use_unsafe_video_config_js_1.useUnsafeVideoConfig)();
48
- const refForOutline = (0, react_1.useRef)(null);
49
53
  const callbackRef = (0, react_1.useCallback)((element) => {
50
- refForOutline.current = element;
51
54
  setRef(ref, element);
52
55
  }, [ref]);
53
56
  if (videoConfig === null) {
54
57
  return hidden ? null : (jsx_runtime_1.jsx(AbsoluteFillElement_js_1.AbsoluteFillElement, { ref: callbackRef, ...divProps, children: children }));
55
58
  }
56
- return (jsx_runtime_1.jsx(AbsoluteFillWithTiming, { ...divProps, ref: callbackRef, outlineRef: refForOutline, from: from, premountFor: premountFor, postmountFor: postmountFor, styleWhilePremounted: styleWhilePremounted, styleWhilePostmounted: styleWhilePostmounted, trimBefore: trimBefore, playbackRate: playbackRate, freeze: freeze, durationInFrames: durationInFrames, hidden: hidden, name: name, showInTimeline: showInTimeline, stack: stack, controls: controls, children: children }));
59
+ return (jsx_runtime_1.jsx(AbsoluteFillWithTiming, { ...divProps, ref: callbackRef, from: from, premountFor: premountFor, postmountFor: postmountFor, styleWhilePremounted: styleWhilePremounted, styleWhilePostmounted: styleWhilePostmounted, trimBefore: trimBefore, playbackRate: playbackRate, loop: loop, freeze: freeze, durationInFrames: durationInFrames, hidden: hidden, name: name, showInTimeline: showInTimeline, stack: stack, controls: controls, children: children }));
57
60
  };
58
61
  /*
59
62
  * @description A helper component which renders an absolutely positioned <div> element with full width, height, and flex display suited for content layering.
@@ -48,8 +48,9 @@ export type HtmlInCanvasOnPaintParams = {
48
48
  readonly pixelDensity: number;
49
49
  };
50
50
  export declare const isHtmlInCanvasSupported: () => boolean;
51
- /** Shown when {@link isHtmlInCanvasSupported} is false: APIs are absent (old Chrome and/or flag off). */
52
- export declare const HTML_IN_CANVAS_UNSUPPORTED_MESSAGE = "HTML in Canvas is not supported. Two common causes: Chrome is older than version 148 (update Chrome), or the HTML-in-Canvas flag is disabled at chrome://flags/#canvas-draw-element (enable it and restart Chrome).";
51
+ /** Generic fallback for consumers that cannot inspect the current browser. */
52
+ export declare const HTML_IN_CANVAS_UNSUPPORTED_MESSAGE = "HTML in Canvas requires Chrome 149 or newer with Canvas Draw Element enabled at chrome://flags/#canvas-draw-element.";
53
+ export declare const getHtmlInCanvasUnsupportedMessage: () => string;
53
54
  export type HtmlInCanvasOnPaint = (params: HtmlInCanvasOnPaintParams) => void | Promise<void>;
54
55
  export type HtmlInCanvasOnInitCleanup = () => void;
55
56
  export type HtmlInCanvasOnInit = (params: HtmlInCanvasOnPaintParams) => HtmlInCanvasOnInitCleanup | Promise<HtmlInCanvasOnInitCleanup>;
@@ -63,6 +64,7 @@ export type HtmlInCanvasProps = Omit<InteractiveBaseProps, 'children'> & Interac
63
64
  readonly onPaint?: HtmlInCanvasOnPaint;
64
65
  readonly onInit?: HtmlInCanvasOnInit;
65
66
  readonly pixelDensity?: HtmlInCanvasPixelDensity;
67
+ readonly _remotionInternalCanvasSiblings?: React.ReactNode;
66
68
  };
67
69
  export declare const htmlInCanvasSchema: {
68
70
  readonly 'style.transformOrigin': {
@@ -262,6 +264,12 @@ export declare const htmlInCanvasSchema: {
262
264
  readonly hiddenFromList: false;
263
265
  readonly keyframable: false;
264
266
  };
267
+ readonly loop: {
268
+ readonly type: "boolean";
269
+ readonly default: false;
270
+ readonly description: "Loop";
271
+ readonly keyframable: false;
272
+ };
265
273
  readonly freeze: {
266
274
  readonly type: "number";
267
275
  readonly default: null;
@@ -290,6 +298,7 @@ export declare const HtmlInCanvas: React.ForwardRefExoticComponent<Omit<Interact
290
298
  readonly onPaint?: HtmlInCanvasOnPaint | undefined;
291
299
  readonly onInit?: HtmlInCanvasOnInit | undefined;
292
300
  readonly pixelDensity?: number | undefined;
301
+ readonly _remotionInternalCanvasSiblings?: React.ReactNode;
293
302
  } & React.RefAttributes<HTMLCanvasElement>> & {
294
303
  readonly isSupported: () => boolean;
295
304
  };
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.HtmlInCanvas = exports.htmlInCanvasSchema = exports.HTML_IN_CANVAS_UNSUPPORTED_MESSAGE = exports.isHtmlInCanvasSupported = void 0;
3
+ exports.HtmlInCanvas = exports.htmlInCanvasSchema = exports.getHtmlInCanvasUnsupportedMessage = exports.HTML_IN_CANVAS_UNSUPPORTED_MESSAGE = exports.isHtmlInCanvasSupported = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_1 = require("react");
6
6
  const run_effect_chain_js_1 = require("./effects/run-effect-chain.js");
@@ -9,6 +9,7 @@ const use_memoized_effects_js_1 = require("./effects/use-memoized-effects.js");
9
9
  const enable_sequence_stack_traces_js_1 = require("./enable-sequence-stack-traces.js");
10
10
  const freeze_js_1 = require("./freeze.js");
11
11
  const interactivity_schema_js_1 = require("./interactivity-schema.js");
12
+ const resolve_sequence_duration_js_1 = require("./resolve-sequence-duration.js");
12
13
  const Sequence_js_1 = require("./Sequence.js");
13
14
  const use_crop_style_js_1 = require("./use-crop-style.js");
14
15
  const use_delay_render_js_1 = require("./use-delay-render.js");
@@ -53,8 +54,43 @@ const isHtmlInCanvasSupported = () => {
53
54
  return cachedSupport;
54
55
  };
55
56
  exports.isHtmlInCanvasSupported = isHtmlInCanvasSupported;
56
- /** Shown when {@link isHtmlInCanvasSupported} is false: APIs are absent (old Chrome and/or flag off). */
57
- exports.HTML_IN_CANVAS_UNSUPPORTED_MESSAGE = 'HTML in Canvas is not supported. Two common causes: Chrome is older than version 148 (update Chrome), or the HTML-in-Canvas flag is disabled at chrome://flags/#canvas-draw-element (enable it and restart Chrome).';
57
+ /** Generic fallback for consumers that cannot inspect the current browser. */
58
+ exports.HTML_IN_CANVAS_UNSUPPORTED_MESSAGE = 'HTML in Canvas requires Chrome 149 or newer with Canvas Draw Element enabled at chrome://flags/#canvas-draw-element.';
59
+ const getHtmlInCanvasUnsupportedMessage = () => {
60
+ var _a;
61
+ if (typeof document === 'undefined') {
62
+ return `HTML in Canvas is unavailable because there is no browser document. ${exports.HTML_IN_CANVAS_UNSUPPORTED_MESSAGE}`;
63
+ }
64
+ const userAgent = typeof navigator === 'undefined' ? '' : navigator.userAgent;
65
+ const chromiumVersion = (_a = userAgent.match(/(?:Chrome|Chromium)\/(\d+)/)) === null || _a === void 0 ? void 0 : _a[1];
66
+ let browser = 'this browser';
67
+ if (userAgent.includes('Edg/')) {
68
+ browser = 'Microsoft Edge';
69
+ }
70
+ else if (userAgent.includes('Chromium/')) {
71
+ browser = 'Chromium';
72
+ }
73
+ else if (chromiumVersion) {
74
+ browser = 'Chrome';
75
+ }
76
+ else if (userAgent.includes('Firefox/')) {
77
+ browser = 'Firefox';
78
+ }
79
+ else if (userAgent.includes('Safari/')) {
80
+ browser = 'Safari';
81
+ }
82
+ if (chromiumVersion && Number(chromiumVersion) >= 149) {
83
+ const flagUrl = browser === 'Microsoft Edge'
84
+ ? 'edge://flags/#canvas-draw-element'
85
+ : 'chrome://flags/#canvas-draw-element';
86
+ return `HTML in Canvas is unavailable. Enable Canvas Draw Element at ${flagUrl} and fully restart ${browser}.`;
87
+ }
88
+ if (chromiumVersion) {
89
+ return `HTML in Canvas is not supported in ${browser} ${chromiumVersion}. Use a Chromium-based browser running version 149 or newer.`;
90
+ }
91
+ return `HTML in Canvas is not supported in ${browser}. Use Chrome 149 or newer.`;
92
+ };
93
+ exports.getHtmlInCanvasUnsupportedMessage = getHtmlInCanvasUnsupportedMessage;
58
94
  function assertHtmlInCanvasDimensions(width, height) {
59
95
  if (typeof width !== 'number' || typeof height !== 'number') {
60
96
  throw new Error(`HtmlInCanvas: \`width\` and \`height\` must be numbers. Received width=${String(width)}, height=${String(height)}.`);
@@ -100,7 +136,7 @@ const defaultOnPaint = ({ canvas, element, elementImage, }) => {
100
136
  };
101
137
  /* eslint-enable react/require-default-props */
102
138
  const HtmlInCanvasAncestorContext = (0, react_1.createContext)(false);
103
- const HtmlInCanvasContent = (0, react_1.forwardRef)(({ width, height, effects, children, onPaint, onInit, pixelDensity, controls, style, }, ref) => {
139
+ const HtmlInCanvasContent = (0, react_1.forwardRef)(({ width, height, effects, children, canvasSiblings, onPaint, onInit, pixelDensity, controls, style, }, ref) => {
104
140
  var _a;
105
141
  const isInsideAncestorHtmlInCanvas = (0, react_1.useContext)(HtmlInCanvasAncestorContext);
106
142
  assertHtmlInCanvasDimensions(width, height);
@@ -115,7 +151,7 @@ const HtmlInCanvasContent = (0, react_1.forwardRef)(({ width, height, effects, c
115
151
  const canRetryMissingPaintRecord = !isRendering || isClientSideRendering;
116
152
  const usesDirectLayoutCanvas = onPaint === undefined && onInit === undefined;
117
153
  if (!(0, exports.isHtmlInCanvasSupported)()) {
118
- cancelRender(new Error(exports.HTML_IN_CANVAS_UNSUPPORTED_MESSAGE));
154
+ cancelRender(new Error((0, exports.getHtmlInCanvasUnsupportedMessage)()));
119
155
  }
120
156
  const canvas2dRef = (0, react_1.useRef)(null);
121
157
  const paintTargetRef = (0, react_1.useRef)(null);
@@ -258,14 +294,18 @@ const HtmlInCanvasContent = (0, react_1.forwardRef)(({ width, height, effects, c
258
294
  pixelDensity: resolvedPixelDensity,
259
295
  });
260
296
  }
261
- await (0, run_effect_chain_js_1.runEffectChain)({
262
- state: chainState.get(canvasWidth, canvasHeight),
263
- source: paintTarget,
264
- effects: effectsRef.current,
265
- output: paintTarget,
266
- width: canvasWidth,
267
- height: canvasHeight,
268
- });
297
+ // `null` once unmounted, e.g. when an async `onPaint` resolves late.
298
+ const state = chainState.get(canvasWidth, canvasHeight);
299
+ if (state) {
300
+ await (0, run_effect_chain_js_1.runEffectChain)({
301
+ state,
302
+ source: paintTarget,
303
+ effects: effectsRef.current,
304
+ output: paintTarget,
305
+ width: canvasWidth,
306
+ height: canvasHeight,
307
+ });
308
+ }
269
309
  }
270
310
  finally {
271
311
  elImage.close();
@@ -360,10 +400,11 @@ const HtmlInCanvasContent = (0, react_1.forwardRef)(({ width, height, effects, c
360
400
  ...(style !== null && style !== void 0 ? style : {}),
361
401
  };
362
402
  }, [height, style, width]);
363
- return (jsx_runtime_1.jsx(HtmlInCanvasAncestorContext.Provider, { value: true, children: jsx_runtime_1.jsx("canvas", { ref: setLayoutCanvasRef, width: canvasWidth, height: canvasHeight, style: canvasStyle, children: jsx_runtime_1.jsx("div", { ref: divRef, style: innerStyle, children: children }) }, canvasSizeKey) }));
403
+ return (jsx_runtime_1.jsx(HtmlInCanvasAncestorContext.Provider, { value: true, children: jsx_runtime_1.jsxs("canvas", { ref: setLayoutCanvasRef, width: canvasWidth, height: canvasHeight, style: canvasStyle, children: [
404
+ jsx_runtime_1.jsx("div", { ref: divRef, style: innerStyle, children: children }), canvasSiblings] }, canvasSizeKey) }));
364
405
  });
365
406
  HtmlInCanvasContent.displayName = 'HtmlInCanvasContent';
366
- const HtmlInCanvasInner = (0, react_1.forwardRef)(({ width, height, effects = [], children, onPaint, onInit, pixelDensity, controls, style, cropLeft, cropRight, cropTop, cropBottom, durationInFrames, premountFor, postmountFor, styleWhilePremounted, styleWhilePostmounted, name, ...sequenceProps }, ref) => {
407
+ const HtmlInCanvasInner = (0, react_1.forwardRef)(({ width, height, effects = [], children, onPaint, onInit, pixelDensity, _remotionInternalCanvasSiblings, controls, style, cropLeft, cropRight, cropTop, cropBottom, durationInFrames, premountFor, postmountFor, styleWhilePremounted, styleWhilePostmounted, name, ...sequenceProps }, ref) => {
367
408
  var _a;
368
409
  const memoizedEffectDefinitions = (0, use_memoized_effects_js_1.useMemoizedEffectDefinitions)(effects);
369
410
  const actualRef = (0, react_1.useRef)(null);
@@ -378,7 +419,11 @@ const HtmlInCanvasInner = (0, react_1.forwardRef)(({ width, height, effects = []
378
419
  }, [ref]);
379
420
  const { effectivePremountFor, effectivePostmountFor, freezeFrame, isPremountingOrPostmounting, premountingActive, postmountingActive, premountingStyle, } = (0, use_premounting_js_1.usePremounting)({
380
421
  from: (_a = sequenceProps.from) !== null && _a !== void 0 ? _a : 0,
381
- durationInFrames: durationInFrames !== null && durationInFrames !== void 0 ? durationInFrames : Infinity,
422
+ durationInFrames: (0, resolve_sequence_duration_js_1.resolveSequenceDuration)({
423
+ durationInFrames,
424
+ playbackRate: sequenceProps.playbackRate,
425
+ loop: sequenceProps.loop,
426
+ }),
382
427
  premountFor: premountFor !== null && premountFor !== void 0 ? premountFor : null,
383
428
  postmountFor: postmountFor !== null && postmountFor !== void 0 ? postmountFor : null,
384
429
  style: style !== null && style !== void 0 ? style : null,
@@ -394,7 +439,7 @@ const HtmlInCanvasInner = (0, react_1.forwardRef)(({ width, height, effects = []
394
439
  style: premountingStyle,
395
440
  componentName: '<HtmlInCanvas />',
396
441
  });
397
- return (jsx_runtime_1.jsx(freeze_js_1.Freeze, { frame: freezeFrame, active: isPremountingOrPostmounting, children: jsx_runtime_1.jsx(Sequence_js_1.Sequence, { layout: "none", durationInFrames: durationInFrames, name: name !== null && name !== void 0 ? name : '<HtmlInCanvas>', _remotionInternalDocumentationLink: "https://www.remotion.dev/docs/remotion/html-in-canvas", controls: controls, _remotionInternalEffects: memoizedEffectDefinitions, outlineRef: actualRef, ...sequenceProps, _remotionInternalPremountDisplay: effectivePremountFor || null, _remotionInternalPostmountDisplay: effectivePostmountFor || null, _remotionInternalIsPremounting: premountingActive, _remotionInternalIsPostmounting: postmountingActive, children: jsx_runtime_1.jsx(HtmlInCanvasContent, { ref: setCanvasRef, width: width, height: height, effects: effects, onPaint: onPaint, onInit: onInit, pixelDensity: pixelDensity, controls: controls, style: croppedStyle !== null && croppedStyle !== void 0 ? croppedStyle : undefined, children: children }) }) }));
442
+ return (jsx_runtime_1.jsx(freeze_js_1.Freeze, { frame: freezeFrame, active: isPremountingOrPostmounting, _remotionInternalIsPremounting: premountingActive, children: jsx_runtime_1.jsx(Sequence_js_1.Sequence, { layout: "none", durationInFrames: durationInFrames, name: name !== null && name !== void 0 ? name : '<HtmlInCanvas>', _remotionInternalDocumentationLink: "https://www.remotion.dev/docs/remotion/html-in-canvas", controls: controls, _remotionInternalEffects: memoizedEffectDefinitions, ...sequenceProps, _remotionInternalPremountDisplay: effectivePremountFor || null, _remotionInternalPostmountDisplay: effectivePostmountFor || null, _remotionInternalIsPremounting: premountingActive, _remotionInternalIsPostmounting: postmountingActive, children: jsx_runtime_1.jsx(HtmlInCanvasContent, { ref: setCanvasRef, width: width, height: height, effects: effects, onPaint: onPaint, onInit: onInit, pixelDensity: pixelDensity, canvasSiblings: _remotionInternalCanvasSiblings !== null && _remotionInternalCanvasSiblings !== void 0 ? _remotionInternalCanvasSiblings : null, controls: controls, style: croppedStyle !== null && croppedStyle !== void 0 ? croppedStyle : undefined, children: children }) }) }));
398
443
  });
399
444
  HtmlInCanvasInner.displayName = 'HtmlInCanvas';
400
445
  exports.htmlInCanvasSchema = {
package/dist/cjs/Img.d.ts CHANGED
@@ -203,6 +203,12 @@ export declare const imgSchema: {
203
203
  readonly step: 1;
204
204
  readonly hiddenFromList: true;
205
205
  };
206
+ readonly loop: {
207
+ readonly type: "boolean";
208
+ readonly default: false;
209
+ readonly description: "Loop";
210
+ readonly keyframable: false;
211
+ };
206
212
  readonly freeze: {
207
213
  readonly type: "number";
208
214
  readonly default: null;
package/dist/cjs/Img.js CHANGED
@@ -9,6 +9,7 @@ const freeze_js_1 = require("./freeze.js");
9
9
  const get_cross_origin_value_js_1 = require("./get-cross-origin-value.js");
10
10
  const interactivity_schema_js_1 = require("./interactivity-schema.js");
11
11
  const prefetch_js_1 = require("./prefetch.js");
12
+ const resolve_sequence_duration_js_1 = require("./resolve-sequence-duration.js");
12
13
  const Sequence_js_1 = require("./Sequence.js");
13
14
  const SequenceContext_js_1 = require("./SequenceContext.js");
14
15
  const truncate_src_for_label_js_1 = require("./truncate-src-for-label.js");
@@ -22,7 +23,7 @@ const with_interactivity_schema_js_1 = require("./with-interactivity-schema.js")
22
23
  function exponentialBackoff(errorCount) {
23
24
  return 1000 * 2 ** (errorCount - 1);
24
25
  }
25
- const ImgContent = ({ onError, onImageError, maxRetries = 2, src, pauseWhenLoading, delayRenderRetries, delayRenderTimeoutInMilliseconds, onImageFrame, crossOrigin, decoding, ref, refForOutline, ...props }) => {
26
+ const ImgContent = ({ onError, onImageError, maxRetries = 2, src, pauseWhenLoading, delayRenderRetries, delayRenderTimeoutInMilliseconds, onImageFrame, crossOrigin, decoding, ref, ...props }) => {
26
27
  const imageRef = (0, react_1.useRef)(null);
27
28
  const errors = (0, react_1.useRef)({});
28
29
  const { delayPlayback } = (0, use_buffer_state_js_1.useBufferState)();
@@ -34,14 +35,13 @@ const ImgContent = ({ onError, onImageError, maxRetries = 2, src, pauseWhenLoadi
34
35
  }
35
36
  const imageCallbackRef = (0, react_1.useCallback)((img) => {
36
37
  imageRef.current = img;
37
- refForOutline.current = img;
38
38
  if (typeof ref === 'function') {
39
39
  ref(img);
40
40
  }
41
41
  else if (ref) {
42
42
  ref.current = img;
43
43
  }
44
- }, [ref, refForOutline]);
44
+ }, [ref]);
45
45
  const actualSrc = (0, prefetch_js_1.usePreload)(src);
46
46
  const retryIn = (0, react_1.useCallback)((timeout) => {
47
47
  if (!imageRef.current) {
@@ -198,7 +198,7 @@ const ImgContent = ({ onError, onImageError, maxRetries = 2, src, pauseWhenLoadi
198
198
  // blocks frame rendering.
199
199
  return (jsx_runtime_1.jsx("img", { ...props, ref: imageCallbackRef, crossOrigin: crossOriginValue, onError: didGetError, decoding: isRendering ? 'sync' : decoding }));
200
200
  };
201
- const NativeImgInner = ({ hidden, name, showInTimeline, src, from, trimBefore, durationInFrames, freeze, premountFor, postmountFor, style, styleWhilePremounted, styleWhilePostmounted, cropLeft, cropRight, cropTop, cropBottom, controls, outlineRef: refForOutline, ...props }) => {
201
+ const NativeImgInner = ({ hidden, name, showInTimeline, src, from, trimBefore, loop, durationInFrames, freeze, premountFor, postmountFor, style, styleWhilePremounted, styleWhilePostmounted, cropLeft, cropRight, cropTop, cropBottom, controls, ...props }) => {
202
202
  if (!src) {
203
203
  throw new Error('No "src" prop was passed to <Img>.');
204
204
  }
@@ -208,7 +208,11 @@ const NativeImgInner = ({ hidden, name, showInTimeline, src, from, trimBefore, d
208
208
  }), [src]);
209
209
  const { effectivePostmountFor, effectivePremountFor, freezeFrame, isPremountingOrPostmounting, postmountingActive, premountingActive, premountingStyle, } = (0, use_premounting_js_1.usePremounting)({
210
210
  from: from !== null && from !== void 0 ? from : 0,
211
- durationInFrames: durationInFrames !== null && durationInFrames !== void 0 ? durationInFrames : Infinity,
211
+ durationInFrames: (0, resolve_sequence_duration_js_1.resolveSequenceDuration)({
212
+ durationInFrames,
213
+ playbackRate: undefined,
214
+ loop,
215
+ }),
212
216
  premountFor: premountFor !== null && premountFor !== void 0 ? premountFor : null,
213
217
  postmountFor: postmountFor !== null && postmountFor !== void 0 ? postmountFor : null,
214
218
  style: style !== null && style !== void 0 ? style : null,
@@ -224,7 +228,7 @@ const NativeImgInner = ({ hidden, name, showInTimeline, src, from, trimBefore, d
224
228
  style: premountingStyle,
225
229
  componentName: '<Img />',
226
230
  });
227
- return (jsx_runtime_1.jsx(freeze_js_1.Freeze, { frame: freezeFrame, active: isPremountingOrPostmounting, children: jsx_runtime_1.jsx(Sequence_js_1.Sequence, { layout: "none", from: from !== null && from !== void 0 ? from : 0, trimBefore: trimBefore, durationInFrames: durationInFrames !== null && durationInFrames !== void 0 ? durationInFrames : Infinity, freeze: freeze, _remotionInternalDocumentationLink: "https://www.remotion.dev/docs/img", _remotionInternalIsMedia: isMedia, _remotionInternalPremountDisplay: effectivePremountFor || null, _remotionInternalPostmountDisplay: effectivePostmountFor || null, _remotionInternalIsPremounting: premountingActive, _remotionInternalIsPostmounting: postmountingActive, name: name !== null && name !== void 0 ? name : '<Img>', controls: controls, showInTimeline: showInTimeline !== null && showInTimeline !== void 0 ? showInTimeline : true, hidden: hidden, outlineRef: refForOutline, children: jsx_runtime_1.jsx(ImgContent, { src: src, refForOutline: refForOutline, style: croppedStyle !== null && croppedStyle !== void 0 ? croppedStyle : undefined, ...props }) }) }));
231
+ return (jsx_runtime_1.jsx(freeze_js_1.Freeze, { frame: freezeFrame, active: isPremountingOrPostmounting, _remotionInternalIsPremounting: premountingActive, children: jsx_runtime_1.jsx(Sequence_js_1.Sequence, { layout: "none", from: from !== null && from !== void 0 ? from : 0, trimBefore: trimBefore, loop: loop, durationInFrames: durationInFrames, freeze: freeze, _remotionInternalDocumentationLink: "https://www.remotion.dev/docs/img", _remotionInternalIsMedia: isMedia, _remotionInternalPremountDisplay: effectivePremountFor || null, _remotionInternalPostmountDisplay: effectivePostmountFor || null, _remotionInternalIsPremounting: premountingActive, _remotionInternalIsPostmounting: postmountingActive, name: name !== null && name !== void 0 ? name : '<Img>', controls: controls, showInTimeline: showInTimeline !== null && showInTimeline !== void 0 ? showInTimeline : true, hidden: hidden, children: jsx_runtime_1.jsx(ImgContent, { src: src, style: croppedStyle !== null && croppedStyle !== void 0 ? croppedStyle : undefined, ...props }) }) }));
228
232
  };
229
233
  const CanvasImageWithPrivateProps = index_js_1.CanvasImage;
230
234
  exports.imgSchema = {
@@ -283,10 +287,9 @@ const getFitFromObjectFit = (style) => {
283
287
  };
284
288
  const ImgInner = ({ effects = [], ref, hidden, name, showInTimeline, src, from, trimBefore, durationInFrames, freeze, premountFor, postmountFor, styleWhilePremounted, styleWhilePostmounted, controls, width, height, className, style, cropLeft, cropRight, cropTop, cropBottom, id, pauseWhenLoading, maxRetries, delayRenderRetries, delayRenderTimeoutInMilliseconds, onImageError, ...props }) => {
285
289
  var _a;
286
- const refForOutline = (0, react_1.useRef)(null);
287
290
  const shouldPauseWhenLoading = (0, v5_flag_js_1.resolveV5Default)(pauseWhenLoading);
288
291
  if (effects.length === 0) {
289
- return (jsx_runtime_1.jsx(NativeImgInner, { ...props, ref: ref, hidden: hidden, name: name, showInTimeline: showInTimeline, src: src, from: from, trimBefore: trimBefore, durationInFrames: durationInFrames, freeze: freeze, premountFor: premountFor, postmountFor: postmountFor, styleWhilePremounted: styleWhilePremounted, styleWhilePostmounted: styleWhilePostmounted, controls: controls, width: width, height: height, className: className, style: style, cropLeft: cropLeft, cropRight: cropRight, cropTop: cropTop, cropBottom: cropBottom, id: id, pauseWhenLoading: shouldPauseWhenLoading, maxRetries: maxRetries, delayRenderRetries: delayRenderRetries, delayRenderTimeoutInMilliseconds: delayRenderTimeoutInMilliseconds, onImageError: onImageError, outlineRef: refForOutline }));
292
+ return (jsx_runtime_1.jsx(NativeImgInner, { ...props, ref: ref, hidden: hidden, name: name, showInTimeline: showInTimeline, src: src, from: from, trimBefore: trimBefore, durationInFrames: durationInFrames, freeze: freeze, premountFor: premountFor, postmountFor: postmountFor, styleWhilePremounted: styleWhilePremounted, styleWhilePostmounted: styleWhilePostmounted, controls: controls, width: width, height: height, className: className, style: style, cropLeft: cropLeft, cropRight: cropRight, cropTop: cropTop, cropBottom: cropBottom, id: id, pauseWhenLoading: shouldPauseWhenLoading, maxRetries: maxRetries, delayRenderRetries: delayRenderRetries, delayRenderTimeoutInMilliseconds: delayRenderTimeoutInMilliseconds, onImageError: onImageError }));
290
293
  }
291
294
  if (!src) {
292
295
  throw new Error('No "src" prop was passed to <Img>.');
@@ -301,7 +304,7 @@ const ImgInner = ({ effects = [], ref, hidden, name, showInTimeline, src, from,
301
304
  const canvasHeight = typeof height === 'number' ? height : undefined;
302
305
  const canvasProps = props;
303
306
  const canvasFit = (_a = getFitFromObjectFit(style)) !== null && _a !== void 0 ? _a : 'fill';
304
- return (jsx_runtime_1.jsx(CanvasImageWithPrivateProps, { src: src, width: canvasWidth, height: canvasHeight, fit: canvasFit, effects: effects, className: className, style: style, cropLeft: cropLeft, cropRight: cropRight, cropTop: cropTop, cropBottom: cropBottom, id: id, onError: onImageError, pauseWhenLoading: shouldPauseWhenLoading, maxRetries: maxRetries, delayRenderRetries: delayRenderRetries, delayRenderTimeoutInMilliseconds: delayRenderTimeoutInMilliseconds, from: from, trimBefore: trimBefore, durationInFrames: durationInFrames, freeze: freeze, premountFor: premountFor, postmountFor: postmountFor, styleWhilePremounted: styleWhilePremounted, styleWhilePostmounted: styleWhilePostmounted, hidden: hidden, name: name !== null && name !== void 0 ? name : '<Img>', showInTimeline: showInTimeline, _remotionInternalDocumentationLink: "https://www.remotion.dev/docs/img", _remotionInternalCropComponentName: "<Img />", controls: controls, outlineRef: refForOutline, ...canvasProps }));
307
+ return (jsx_runtime_1.jsx(CanvasImageWithPrivateProps, { src: src, width: canvasWidth, height: canvasHeight, fit: canvasFit, effects: effects, className: className, style: style, cropLeft: cropLeft, cropRight: cropRight, cropTop: cropTop, cropBottom: cropBottom, id: id, onError: onImageError, pauseWhenLoading: shouldPauseWhenLoading, maxRetries: maxRetries, delayRenderRetries: delayRenderRetries, delayRenderTimeoutInMilliseconds: delayRenderTimeoutInMilliseconds, from: from, trimBefore: trimBefore, durationInFrames: durationInFrames, freeze: freeze, premountFor: premountFor, postmountFor: postmountFor, styleWhilePremounted: styleWhilePremounted, styleWhilePostmounted: styleWhilePostmounted, hidden: hidden, name: name !== null && name !== void 0 ? name : '<Img>', showInTimeline: showInTimeline, _remotionInternalDocumentationLink: "https://www.remotion.dev/docs/img", _remotionInternalCropComponentName: "<Img />", controls: controls, ...canvasProps }));
305
308
  };
306
309
  /*
307
310
  * @description Works just like a regular HTML img tag. When you use the <Img> tag, Remotion will ensure that the image is loaded before rendering the frame.
@@ -6,7 +6,7 @@ type InteractiveHtmlTag = 'a' | 'article' | 'aside' | 'button' | 'code' | 'div'
6
6
  type InteractiveSvgTag = 'circle' | 'ellipse' | 'g' | 'line' | 'path' | 'rect' | 'svg' | 'text';
7
7
  type InteractiveTag = InteractiveHtmlTag | InteractiveSvgTag;
8
8
  type ElementForTag<Tag extends InteractiveTag> = Tag extends keyof HTMLElementTagNameMap ? HTMLElementTagNameMap[Tag] : Tag extends keyof SVGElementTagNameMap ? SVGElementTagNameMap[Tag] : Element;
9
- export type InteractiveBaseProps = Pick<SequenceProps, 'durationInFrames' | 'from' | 'trimBefore' | 'playbackRate' | 'freeze' | 'hidden' | 'name' | 'showInTimeline'>;
9
+ export type InteractiveBaseProps = Pick<SequenceProps, 'durationInFrames' | 'from' | 'trimBefore' | 'playbackRate' | 'loop' | 'freeze' | 'hidden' | 'name' | 'showInTimeline'>;
10
10
  export type InteractiveTransformProps = Pick<AbsoluteFillLayout, 'style'>;
11
11
  export type InteractiveCropProps = Pick<SequenceProps, 'cropLeft' | 'cropRight' | 'cropTop' | 'cropBottom'>;
12
12
  export type InteractivePremountProps = Pick<AbsoluteFillLayout, 'premountFor' | 'postmountFor' | 'styleWhilePremounted' | 'styleWhilePostmounted'>;
@@ -14,6 +14,25 @@ type InteractiveManagedProps = InteractiveBaseProps & InteractiveCropProps & Int
14
14
  type InteractiveElementProps<Tag extends InteractiveTag> = Omit<React.ComponentPropsWithoutRef<Tag>, keyof InteractiveManagedProps> & InteractiveManagedProps;
15
15
  type InteractiveElementComponent<Tag extends InteractiveTag> = React.ComponentType<InteractiveElementProps<Tag> & React.RefAttributes<ElementForTag<Tag>>>;
16
16
  type RemotionComponentIdentityPackage = 'remotion' | `@remotion/${string}`;
17
+ type NonIntrinsicComponent<Component extends React.ElementType> = Component & React.ComponentType<React.ComponentProps<Component>>;
18
+ type KeysOfUnion<Props> = Props extends unknown ? keyof Props : never;
19
+ type ComponentWithoutReservedProps<Component extends React.ElementType, ReservedKey extends PropertyKey> = NonIntrinsicComponent<Component> & (Extract<KeysOfUnion<React.ComponentPropsWithoutRef<Component>>, ReservedKey> extends never ? unknown : never);
20
+ type WithSchemaReservedKey = keyof InteractiveBaseProps | keyof InteractiveCropProps | keyof InteractivePremountProps | 'controls';
21
+ type IsAny<Value> = 0 extends 1 & Value ? true : false;
22
+ type StyleMemberAcceptsCssProperties<Style> = IsAny<Style> extends true ? true : Style extends unknown ? [Style] extends [null | undefined] ? false : Exclude<keyof React.CSSProperties, keyof Style> extends never ? React.CSSProperties extends Style ? true : false : false : never;
23
+ type StyleAcceptsCssProperties<Style> = true extends StyleMemberAcceptsCssProperties<Style> ? true : false;
24
+ type PropsBranchAcceptsStyle<Props> = Props extends unknown ? 'style' extends keyof Props ? StyleAcceptsCssProperties<Props[Extract<'style', keyof Props>]> : false : never;
25
+ type EveryPropsBranchAcceptsStyle<Props> = [Props] extends [never] ? false : false extends PropsBranchAcceptsStyle<Props> ? false : true;
26
+ type ComponentAcceptingStyle<Component extends React.ElementType, ReservedKey extends PropertyKey> = ComponentWithoutReservedProps<Component, ReservedKey> & (EveryPropsBranchAcceptsStyle<React.ComponentPropsWithoutRef<Component>> extends true ? unknown : never);
27
+ type WithSchema = {
28
+ <S extends InteractivitySchema, Component extends React.ElementType>(options: Omit<WithInteractivitySchemaOptions<S, React.ComponentPropsWithoutRef<Component>>, 'Component' | 'supportsEffects'> & {
29
+ readonly Component: ComponentAcceptingStyle<Component, WithSchemaReservedKey>;
30
+ readonly wrapInSequence: true;
31
+ }): React.FC<React.ComponentPropsWithRef<Component> & InteractiveBaseProps & InteractivePremountProps & InteractiveCropProps>;
32
+ <S extends InteractivitySchema, Props extends object>(options: WithInteractivitySchemaOptions<S, Props> & {
33
+ readonly wrapInSequence?: false;
34
+ }): React.ComponentType<Props>;
35
+ };
17
36
  /**
18
37
  * @description HTML and SVG elements that are registered in the Remotion Studio timeline and can be visually edited.
19
38
  */
@@ -48,6 +67,12 @@ export declare const Interactive: {
48
67
  readonly hiddenFromList: false;
49
68
  readonly keyframable: false;
50
69
  };
70
+ readonly loop: {
71
+ readonly type: "boolean";
72
+ readonly default: false;
73
+ readonly description: "Loop";
74
+ readonly keyframable: false;
75
+ };
51
76
  readonly freeze: {
52
77
  readonly type: "number";
53
78
  readonly default: null;
@@ -385,6 +410,12 @@ export declare const Interactive: {
385
410
  readonly hiddenFromList: false;
386
411
  readonly keyframable: false;
387
412
  };
413
+ readonly loop: {
414
+ readonly type: "boolean";
415
+ readonly default: false;
416
+ readonly description: "Loop";
417
+ readonly keyframable: false;
418
+ };
388
419
  readonly freeze: {
389
420
  readonly type: "number";
390
421
  readonly default: null;
@@ -573,7 +604,7 @@ export declare const Interactive: {
573
604
  };
574
605
  };
575
606
  };
576
- withSchema: <S extends InteractivitySchema, Props extends object>(options: WithInteractivitySchemaOptions<S, Props>) => React.ComponentType<Props>;
607
+ withSchema: WithSchema;
577
608
  _internalMakeRemotionComponentIdentity: ({ packageName, componentName, }: {
578
609
  readonly packageName: RemotionComponentIdentityPackage;
579
610
  readonly componentName: string;
@@ -39,6 +39,7 @@ const react_1 = __importStar(require("react"));
39
39
  const enable_sequence_stack_traces_js_1 = require("./enable-sequence-stack-traces.js");
40
40
  const freeze_js_1 = require("./freeze.js");
41
41
  const interactivity_schema_js_1 = require("./interactivity-schema.js");
42
+ const resolve_sequence_duration_js_1 = require("./resolve-sequence-duration.js");
42
43
  const Sequence_js_1 = require("./Sequence.js");
43
44
  const use_crop_style_js_1 = require("./use-crop-style.js");
44
45
  const use_premounting_js_1 = require("./use-premounting.js");
@@ -94,7 +95,7 @@ const interactiveSvgPathElementSchema = {
94
95
  type: 'svg-path',
95
96
  default: undefined,
96
97
  description: 'Path',
97
- keyframable: false,
98
+ keyframable: true,
98
99
  },
99
100
  };
100
101
  const interactiveSvgStrokeElementSchema = {
@@ -113,17 +114,71 @@ const setRef = (ref, value) => {
113
114
  ref.current = value;
114
115
  }
115
116
  };
116
- const withSchema = (options) => {
117
- const Wrapped = (0, with_interactivity_schema_js_1.withInteractivitySchema)(options);
117
+ const withSchema = (untypedOptions) => {
118
+ const options = untypedOptions;
119
+ if (!options.wrapInSequence) {
120
+ const LegacyWrapped = (0, with_interactivity_schema_js_1.withInteractivitySchema)(options);
121
+ (0, enable_sequence_stack_traces_js_1.addSequenceStackTraces)(LegacyWrapped);
122
+ return LegacyWrapped;
123
+ }
124
+ const { Component, componentName, schema, wrapInSequence: _, ...rest } = options;
125
+ const ComponentWrappedInSequence = (0, react_1.forwardRef)((props, ref) => {
126
+ const { durationInFrames, from, trimBefore, playbackRate, loop, freeze, hidden, name, showInTimeline, controls, premountFor, postmountFor, styleWhilePremounted, styleWhilePostmounted, ...componentProps } = props;
127
+ const { cropLeft, cropRight, cropTop, cropBottom, style, ...componentPropsWithoutCropping } = componentProps;
128
+ const { effectivePremountFor, effectivePostmountFor, freezeFrame, isPremountingOrPostmounting, premountingActive, postmountingActive, premountingStyle, } = (0, use_premounting_js_1.usePremounting)({
129
+ from: from !== null && from !== void 0 ? from : 0,
130
+ durationInFrames: (0, resolve_sequence_duration_js_1.resolveSequenceDuration)({
131
+ durationInFrames,
132
+ playbackRate,
133
+ loop,
134
+ }),
135
+ premountFor: premountFor !== null && premountFor !== void 0 ? premountFor : null,
136
+ postmountFor: postmountFor !== null && postmountFor !== void 0 ? postmountFor : null,
137
+ style: style !== null && style !== void 0 ? style : null,
138
+ styleWhilePremounted: styleWhilePremounted !== null && styleWhilePremounted !== void 0 ? styleWhilePremounted : null,
139
+ styleWhilePostmounted: styleWhilePostmounted !== null && styleWhilePostmounted !== void 0 ? styleWhilePostmounted : null,
140
+ hideWhilePremounted: 'opacity',
141
+ });
142
+ const croppedStyle = (0, use_crop_style_js_1.useCropStyle)({
143
+ cropLeft,
144
+ cropRight,
145
+ cropTop,
146
+ cropBottom,
147
+ style: premountingStyle,
148
+ componentName,
149
+ });
150
+ return (jsx_runtime_1.jsx(freeze_js_1.Freeze, { frame: freezeFrame, active: isPremountingOrPostmounting, children: jsx_runtime_1.jsx(Sequence_js_1.SequenceWithoutSchema, { layout: "none", durationInFrames: durationInFrames, from: from, trimBefore: trimBefore, playbackRate: playbackRate, loop: loop, freeze: freeze, hidden: hidden, name: name !== null && name !== void 0 ? name : componentName, showInTimeline: showInTimeline, controls: controls, _remotionInternalPremountDisplay: effectivePremountFor || null, _remotionInternalPostmountDisplay: effectivePostmountFor || null, _remotionInternalIsPremounting: premountingActive, _remotionInternalIsPostmounting: postmountingActive, children: react_1.default.createElement(Component, {
151
+ ...componentPropsWithoutCropping,
152
+ style: croppedStyle !== null && croppedStyle !== void 0 ? croppedStyle : undefined,
153
+ ref,
154
+ }) }) }));
155
+ });
156
+ const Wrapped = (0, with_interactivity_schema_js_1.withInteractivitySchema)({
157
+ ...rest,
158
+ Component: ComponentWrappedInSequence,
159
+ componentName,
160
+ schema: {
161
+ ...schema,
162
+ ...interactivity_schema_js_1.transformSchema,
163
+ ...interactivity_schema_js_1.baseSchema,
164
+ ...interactivity_schema_js_1.premountSchema,
165
+ ...interactivity_schema_js_1.cropSchema,
166
+ },
167
+ supportsEffects: false,
168
+ });
118
169
  (0, enable_sequence_stack_traces_js_1.addSequenceStackTraces)(Wrapped);
119
170
  return Wrapped;
120
171
  };
121
172
  const makeInteractiveElement = (tag, displayName, schema) => {
122
173
  const Inner = (0, react_1.forwardRef)((propsWithControls, ref) => {
123
- const { durationInFrames, from, premountFor, postmountFor, styleWhilePremounted, styleWhilePostmounted, trimBefore, playbackRate, freeze, hidden, name, showInTimeline, controls, cropLeft, cropRight, cropTop, cropBottom, style, ...props } = propsWithControls;
174
+ const { durationInFrames, from, premountFor, postmountFor, styleWhilePremounted, styleWhilePostmounted, trimBefore, playbackRate, loop, freeze, hidden, name, showInTimeline, controls, cropLeft, cropRight, cropTop, cropBottom, style, ...props } = propsWithControls;
124
175
  const { effectivePremountFor, effectivePostmountFor, freezeFrame, isPremountingOrPostmounting, premountingActive, postmountingActive, premountingStyle, } = (0, use_premounting_js_1.usePremounting)({
125
176
  from: from !== null && from !== void 0 ? from : 0,
126
- durationInFrames: durationInFrames !== null && durationInFrames !== void 0 ? durationInFrames : Infinity,
177
+ durationInFrames: (0, resolve_sequence_duration_js_1.resolveSequenceDuration)({
178
+ durationInFrames,
179
+ playbackRate,
180
+ loop,
181
+ }),
127
182
  premountFor: premountFor !== null && premountFor !== void 0 ? premountFor : null,
128
183
  postmountFor: postmountFor !== null && postmountFor !== void 0 ? postmountFor : null,
129
184
  style: style !== null && style !== void 0 ? style : null,
@@ -139,12 +194,10 @@ const makeInteractiveElement = (tag, displayName, schema) => {
139
194
  style: premountingStyle,
140
195
  componentName: displayName,
141
196
  });
142
- const refForOutline = (0, react_1.useRef)(null);
143
197
  const callbackRef = (0, react_1.useCallback)((element) => {
144
- refForOutline.current = element;
145
198
  setRef(ref, element);
146
199
  }, [ref]);
147
- return (jsx_runtime_1.jsx(freeze_js_1.Freeze, { frame: freezeFrame, active: isPremountingOrPostmounting, children: jsx_runtime_1.jsx(Sequence_js_1.Sequence, { layout: "none", from: from !== null && from !== void 0 ? from : 0, trimBefore: trimBefore, playbackRate: playbackRate, durationInFrames: durationInFrames !== null && durationInFrames !== void 0 ? durationInFrames : Infinity, freeze: freeze, hidden: hidden, name: name !== null && name !== void 0 ? name : displayName, showInTimeline: showInTimeline !== null && showInTimeline !== void 0 ? showInTimeline : true, controls: controls, _remotionInternalDocumentationLink: "https://www.remotion.dev/docs/interactive", outlineRef: refForOutline, _remotionInternalPremountDisplay: effectivePremountFor || null, _remotionInternalPostmountDisplay: effectivePostmountFor || null, _remotionInternalIsPremounting: premountingActive, _remotionInternalIsPostmounting: postmountingActive, children: react_1.default.createElement(tag, {
200
+ return (jsx_runtime_1.jsx(freeze_js_1.Freeze, { frame: freezeFrame, active: isPremountingOrPostmounting, _remotionInternalIsPremounting: premountingActive, children: jsx_runtime_1.jsx(Sequence_js_1.Sequence, { layout: "none", from: from !== null && from !== void 0 ? from : 0, trimBefore: trimBefore, playbackRate: playbackRate, loop: loop, durationInFrames: durationInFrames, freeze: freeze, hidden: hidden, name: name !== null && name !== void 0 ? name : displayName, showInTimeline: showInTimeline !== null && showInTimeline !== void 0 ? showInTimeline : true, controls: controls, _remotionInternalDocumentationLink: "https://www.remotion.dev/docs/interactive", _remotionInternalPremountDisplay: effectivePremountFor || null, _remotionInternalPostmountDisplay: effectivePostmountFor || null, _remotionInternalIsPremounting: premountingActive, _remotionInternalIsPostmounting: postmountingActive, children: react_1.default.createElement(tag, {
148
201
  ...props,
149
202
  style: croppedStyle !== null && croppedStyle !== void 0 ? croppedStyle : undefined,
150
203
  ref: callbackRef,
@@ -25,6 +25,7 @@ export type SequencePropsWithoutDuration = {
25
25
  readonly from?: number;
26
26
  readonly trimBefore?: number;
27
27
  readonly playbackRate?: number;
28
+ readonly loop?: boolean;
28
29
  readonly freeze?: number | null;
29
30
  readonly name?: string;
30
31
  readonly showInTimeline?: boolean;
@@ -74,8 +75,8 @@ export type SequencePropsWithoutDuration = {
74
75
  src: string;
75
76
  };
76
77
  /**
77
- * A React ref pointing to the element that Remotion Studio should use for
78
- * drawing the selection outline in the preview.
78
+ * @deprecated Remotion Studio discovers rendered elements automatically.
79
+ * Remove this prop.
79
80
  */
80
81
  readonly outlineRef?: React.RefObject<Element | null> | null;
81
82
  } & LayoutAndStyle;