@remotion/gif 4.0.529 → 4.0.531

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.
package/dist/cjs/Gif.js CHANGED
@@ -1,14 +1,15 @@
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
3
  exports.Gif = exports.gifSchema = void 0;
7
4
  const jsx_runtime_1 = require("react/jsx-runtime");
8
- const react_1 = __importDefault(require("react"));
5
+ const react_1 = require("react");
6
+ const react_2 = require("react");
9
7
  const remotion_1 = require("remotion");
8
+ const get_gif_duration_in_seconds_1 = require("./get-gif-duration-in-seconds");
10
9
  const GifForDevelopment_1 = require("./GifForDevelopment");
11
10
  const GifForRendering_1 = require("./GifForRendering");
11
+ const request_init_1 = require("./request-init");
12
+ const resolve_gif_source_1 = require("./resolve-gif-source");
12
13
  const { useMemoizedEffectDefinitions, useMemoizedEffects } = remotion_1.Internals;
13
14
  /*
14
15
  * @description Displays a GIF that synchronizes with Remotions useCurrentFrame().
@@ -16,6 +17,12 @@ const { useMemoizedEffectDefinitions, useMemoizedEffects } = remotion_1.Internal
16
17
  */
17
18
  exports.gifSchema = {
18
19
  ...remotion_1.Internals.baseSchema,
20
+ loop: {
21
+ type: 'boolean',
22
+ default: false,
23
+ description: 'Loop',
24
+ keyframable: false,
25
+ },
19
26
  ...remotion_1.Internals.premountSchema,
20
27
  ...remotion_1.Internals.transformSchema,
21
28
  ...remotion_1.Interactive.backgroundSchema,
@@ -26,10 +33,13 @@ exports.gifSchema = {
26
33
  const GifInner = ({ src, width, height, onLoad, onError, fit, playbackRate, loopBehavior, id, delayRenderTimeoutInMilliseconds, requestInit, durationInFrames, from, premountFor, postmountFor, styleWhilePremounted, styleWhilePostmounted, style, cropLeft, cropRight, cropTop, cropBottom, controls, effects = [], ref, ...sequenceProps }) => {
27
34
  var _a;
28
35
  const env = (0, remotion_1.useRemotionEnvironment)();
29
- const refForOutline = react_1.default.useRef(null);
30
36
  const { effectivePostmountFor, effectivePremountFor, freezeFrame, isPremountingOrPostmounting, postmountingActive, premountingActive, premountingStyle, } = remotion_1.Internals.usePremounting({
31
37
  from: from !== null && from !== void 0 ? from : 0,
32
- durationInFrames: durationInFrames !== null && durationInFrames !== void 0 ? durationInFrames : Infinity,
38
+ durationInFrames: remotion_1.Internals.resolveSequenceDuration({
39
+ durationInFrames,
40
+ playbackRate,
41
+ loop: sequenceProps.loop,
42
+ }),
33
43
  premountFor: premountFor !== null && premountFor !== void 0 ? premountFor : null,
34
44
  postmountFor: postmountFor !== null && postmountFor !== void 0 ? postmountFor : null,
35
45
  style: style !== null && style !== void 0 ? style : null,
@@ -64,11 +74,71 @@ const GifInner = ({ src, width, height, onLoad, onError, fit, playbackRate, loop
64
74
  style: croppedStyle !== null && croppedStyle !== void 0 ? croppedStyle : undefined,
65
75
  effects: memoizedEffects,
66
76
  };
67
- const inner = env.isRendering ? (jsx_runtime_1.jsx(GifForRendering_1.GifForRendering, { ...gifProps, ref: ref })) : (jsx_runtime_1.jsx(GifForDevelopment_1.GifForDevelopment, { ...gifProps, ref: ref, refForOutline: refForOutline }));
68
- return (jsx_runtime_1.jsx(remotion_1.Freeze, { frame: freezeFrame, active: isPremountingOrPostmounting, children: jsx_runtime_1.jsx(remotion_1.Sequence, { layout: "none", from: from !== null && from !== void 0 ? from : 0, playbackRate: playbackRate, durationInFrames: durationInFrames !== null && durationInFrames !== void 0 ? durationInFrames : Infinity, name: "<Gif>", _remotionInternalDocumentationLink: "https://www.remotion.dev/docs/gif/gif", controls: controls, _remotionInternalEffects: memoizedEffectDefinitions, _remotionInternalPremountDisplay: effectivePremountFor || null, _remotionInternalPostmountDisplay: effectivePostmountFor || null, _remotionInternalIsPremounting: premountingActive, _remotionInternalIsPostmounting: postmountingActive, ...sequenceProps, outlineRef: refForOutline, children: inner }) }));
77
+ const inner = env.isRendering ? (jsx_runtime_1.jsx(GifForRendering_1.GifForRendering, { ...gifProps, ref: ref })) : (jsx_runtime_1.jsx(GifForDevelopment_1.GifForDevelopment, { ...gifProps, ref: ref }));
78
+ return (jsx_runtime_1.jsx(remotion_1.Freeze, { frame: freezeFrame, active: isPremountingOrPostmounting, children: jsx_runtime_1.jsx(remotion_1.Sequence, { layout: "none", from: from !== null && from !== void 0 ? from : 0, playbackRate: playbackRate, durationInFrames: durationInFrames, name: "<Gif>", _remotionInternalDocumentationLink: "https://www.remotion.dev/docs/gif/gif", controls: controls, _remotionInternalEffects: memoizedEffectDefinitions, _remotionInternalPremountDisplay: effectivePremountFor || null, _remotionInternalPostmountDisplay: effectivePostmountFor || null, _remotionInternalIsPremounting: premountingActive, _remotionInternalIsPostmounting: postmountingActive, ...sequenceProps, children: inner }) }));
79
+ };
80
+ const GifWithIntrinsicDuration = (props) => {
81
+ const { fps } = (0, remotion_1.useVideoConfig)();
82
+ const { delayRender, continueRender, cancelRender } = (0, remotion_1.useDelayRender)();
83
+ const { src, requestInit, trimBefore } = props;
84
+ const onErrorRef = (0, react_2.useRef)(props.onError);
85
+ onErrorRef.current = props.onError;
86
+ const requestInitRef = (0, react_2.useRef)(requestInit);
87
+ requestInitRef.current = requestInit;
88
+ const [handle] = (0, react_2.useState)(() => delayRender(`Finding duration of <Gif src="${src}" />`, {
89
+ timeoutInMilliseconds: props.delayRenderTimeoutInMilliseconds,
90
+ }));
91
+ const [durationInFrames, setDurationInFrames] = (0, react_2.useState)(null);
92
+ const [failed, setFailed] = (0, react_2.useState)(false);
93
+ (0, react_2.useEffect)(() => {
94
+ let cancelled = false;
95
+ (0, get_gif_duration_in_seconds_1.getGifDurationInSeconds)(src, { requestInit: requestInitRef.current })
96
+ .then((duration) => {
97
+ if (!cancelled) {
98
+ setDurationInFrames(Math.ceil(duration * fps) - (trimBefore !== null && trimBefore !== void 0 ? trimBefore : 0));
99
+ }
100
+ })
101
+ .catch((error) => {
102
+ if (cancelled) {
103
+ return;
104
+ }
105
+ if (onErrorRef.current) {
106
+ onErrorRef.current(error);
107
+ setFailed(true);
108
+ }
109
+ else {
110
+ cancelRender(error);
111
+ }
112
+ });
113
+ return () => {
114
+ cancelled = true;
115
+ continueRender(handle);
116
+ };
117
+ }, [cancelRender, continueRender, fps, handle, src, trimBefore]);
118
+ (0, react_2.useEffect)(() => {
119
+ if (durationInFrames !== null || failed) {
120
+ continueRender(handle);
121
+ }
122
+ }, [continueRender, durationInFrames, failed, handle]);
123
+ if (durationInFrames === null || failed) {
124
+ return null;
125
+ }
126
+ return jsx_runtime_1.jsx(GifInner, { ...props, durationInFrames: durationInFrames });
127
+ };
128
+ const GifComponent = (props) => {
129
+ var _a;
130
+ if (props.loop && props.durationInFrames === undefined) {
131
+ const resolvedSrc = (0, resolve_gif_source_1.resolveGifSource)(props.src);
132
+ const cacheKey = (0, request_init_1.getGifCacheKey)({
133
+ resolvedSrc,
134
+ requestInit: props.requestInit,
135
+ });
136
+ return (react_1.createElement(GifWithIntrinsicDuration, { ...props, key: `${cacheKey}-${(_a = props.trimBefore) !== null && _a !== void 0 ? _a : 0}` }));
137
+ }
138
+ return jsx_runtime_1.jsx(GifInner, { ...props });
69
139
  };
70
140
  exports.Gif = remotion_1.Interactive.withSchema({
71
- Component: GifInner,
141
+ Component: GifComponent,
72
142
  componentName: '<Gif>',
73
143
  componentIdentity: 'dev.remotion.gif.Gif',
74
144
  schema: exports.gifSchema,
@@ -1,7 +1,5 @@
1
- import { type RefObject } from 'react';
2
1
  import type { EffectDefinitionAndStack } from 'remotion';
3
2
  import type { RemotionGifProps } from './props';
4
3
  export declare const GifForDevelopment: import("react").ForwardRefExoticComponent<RemotionGifProps & {
5
4
  readonly effects: EffectDefinitionAndStack<unknown>[];
6
- readonly refForOutline: RefObject<HTMLElement | null>;
7
5
  } & import("react").RefAttributes<HTMLCanvasElement>>;
@@ -11,7 +11,7 @@ const react_tools_1 = require("./react-tools");
11
11
  const request_init_1 = require("./request-init");
12
12
  const resolve_gif_source_1 = require("./resolve-gif-source");
13
13
  const useCurrentGifIndex_1 = require("./useCurrentGifIndex");
14
- exports.GifForDevelopment = (0, react_1.forwardRef)(({ src, width, height, onError, loopBehavior = 'loop', playbackRate = 1, onLoad, fit = 'fill', requestInit, effects, refForOutline, ...props }, ref) => {
14
+ exports.GifForDevelopment = (0, react_1.forwardRef)(({ src, width, height, onError, loopBehavior = 'loop', playbackRate = 1, onLoad, fit = 'fill', requestInit, effects, ...props }, ref) => {
15
15
  const resolvedSrc = (0, resolve_gif_source_1.resolveGifSource)(src);
16
16
  const requestInitRef = (0, react_1.useRef)(requestInit);
17
17
  requestInitRef.current = requestInit;
@@ -91,5 +91,5 @@ exports.GifForDevelopment = (0, react_1.forwardRef)(({ src, width, height, onErr
91
91
  if (index === -1) {
92
92
  return null;
93
93
  }
94
- return (jsx_runtime_1.jsx(canvas_1.Canvas, { fit: fit, index: index, frames: state.frames, width: width, height: height, effects: effects, refForOutline: refForOutline, ...props, ref: ref }));
94
+ return (jsx_runtime_1.jsx(canvas_1.Canvas, { fit: fit, index: index, frames: state.frames, width: width, height: height, effects: effects, ...props, ref: ref }));
95
95
  });
@@ -1,4 +1,3 @@
1
- import { type RefObject } from 'react';
2
1
  import type { EffectDefinitionAndStack } from 'remotion';
3
2
  import type { GifFillMode } from './props';
4
3
  type Props = {
@@ -10,7 +9,6 @@ type Props = {
10
9
  readonly className?: string;
11
10
  readonly style?: React.CSSProperties;
12
11
  readonly effects: EffectDefinitionAndStack<unknown>[];
13
- readonly refForOutline?: RefObject<HTMLElement | null>;
14
12
  };
15
13
  export declare const Canvas: import("react").ForwardRefExoticComponent<Props & import("react").RefAttributes<unknown>>;
16
14
  export {};
@@ -65,7 +65,7 @@ const makeCanvas = () => {
65
65
  canvas.height = 0;
66
66
  return ctx;
67
67
  };
68
- exports.Canvas = (0, react_1.forwardRef)(({ index, frames, width, height, fit, className, style, effects, refForOutline, }, ref) => {
68
+ exports.Canvas = (0, react_1.forwardRef)(({ index, frames, width, height, fit, className, style, effects }, ref) => {
69
69
  const canvasRef = (0, react_1.useRef)(null);
70
70
  const [tempCtx] = (0, react_1.useState)(() => {
71
71
  return makeCanvas();
@@ -88,12 +88,6 @@ exports.Canvas = (0, react_1.forwardRef)(({ index, frames, width, height, fit, c
88
88
  (0, react_1.useImperativeHandle)(ref, () => {
89
89
  return canvasRef.current;
90
90
  }, []);
91
- const canvasCallbackRef = (0, react_1.useCallback)((canvas) => {
92
- canvasRef.current = canvas;
93
- if (refForOutline) {
94
- refForOutline.current = canvas;
95
- }
96
- }, [refForOutline]);
97
91
  (0, react_1.useEffect)(() => {
98
92
  if (!size) {
99
93
  return;
@@ -202,5 +196,5 @@ exports.Canvas = (0, react_1.forwardRef)(({ index, frames, width, height, fit, c
202
196
  continueRender,
203
197
  cancelRender,
204
198
  ]);
205
- return (jsx_runtime_1.jsx("canvas", { ref: canvasCallbackRef, className: className, style: style, width: width !== null && width !== void 0 ? width : size === null || size === void 0 ? void 0 : size.width, height: height !== null && height !== void 0 ? height : size === null || size === void 0 ? void 0 : size.height }));
199
+ return (jsx_runtime_1.jsx("canvas", { ref: canvasRef, className: className, style: style, width: width !== null && width !== void 0 ? width : size === null || size === void 0 ? void 0 : size.width, height: height !== null && height !== void 0 ? height : size === null || size === void 0 ? void 0 : size.height }));
206
200
  });
@@ -872,13 +872,15 @@ var getGifDurationInSeconds = async (src2, options) => {
872
872
  return calcDuration(parsed);
873
873
  };
874
874
  // src/Gif.tsx
875
- import React from "react";
875
+ import React, { useEffect as useEffect5, useRef as useRef4, useState as useState5 } from "react";
876
876
  import {
877
877
  Freeze,
878
878
  Internals as Internals3,
879
879
  Interactive,
880
880
  Sequence,
881
- useRemotionEnvironment
881
+ useDelayRender as useDelayRender3,
882
+ useRemotionEnvironment,
883
+ useVideoConfig as useVideoConfig2
882
884
  } from "remotion";
883
885
 
884
886
  // src/GifForDevelopment.tsx
@@ -887,7 +889,6 @@ import { forwardRef as forwardRef2, useEffect as useEffect3, useRef as useRef2,
887
889
  // src/canvas.tsx
888
890
  import {
889
891
  forwardRef,
890
- useCallback as useCallback2,
891
892
  useEffect as useEffect2,
892
893
  useImperativeHandle,
893
894
  useMemo as useMemo2,
@@ -1020,17 +1021,7 @@ var makeCanvas = () => {
1020
1021
  canvas.height = 0;
1021
1022
  return ctx;
1022
1023
  };
1023
- var Canvas = forwardRef(({
1024
- index,
1025
- frames,
1026
- width,
1027
- height,
1028
- fit,
1029
- className,
1030
- style,
1031
- effects,
1032
- refForOutline
1033
- }, ref) => {
1024
+ var Canvas = forwardRef(({ index, frames, width, height, fit, className, style, effects }, ref) => {
1034
1025
  const canvasRef = useRef(null);
1035
1026
  const [tempCtx] = useState2(() => {
1036
1027
  return makeCanvas();
@@ -1053,12 +1044,6 @@ var Canvas = forwardRef(({
1053
1044
  useImperativeHandle(ref, () => {
1054
1045
  return canvasRef.current;
1055
1046
  }, []);
1056
- const canvasCallbackRef = useCallback2((canvas) => {
1057
- canvasRef.current = canvas;
1058
- if (refForOutline) {
1059
- refForOutline.current = canvas;
1060
- }
1061
- }, [refForOutline]);
1062
1047
  useEffect2(() => {
1063
1048
  if (!size) {
1064
1049
  return;
@@ -1160,7 +1145,7 @@ var Canvas = forwardRef(({
1160
1145
  cancelRender
1161
1146
  ]);
1162
1147
  return /* @__PURE__ */ jsx("canvas", {
1163
- ref: canvasCallbackRef,
1148
+ ref: canvasRef,
1164
1149
  className,
1165
1150
  style,
1166
1151
  width: width ?? size?.width,
@@ -1224,7 +1209,6 @@ var GifForDevelopment = forwardRef2(({
1224
1209
  fit = "fill",
1225
1210
  requestInit,
1226
1211
  effects,
1227
- refForOutline,
1228
1212
  ...props
1229
1213
  }, ref) => {
1230
1214
  const resolvedSrc = resolveGifSource(src2);
@@ -1306,7 +1290,6 @@ var GifForDevelopment = forwardRef2(({
1306
1290
  width,
1307
1291
  height,
1308
1292
  effects,
1309
- refForOutline,
1310
1293
  ...props,
1311
1294
  ref
1312
1295
  });
@@ -1440,9 +1423,16 @@ var GifForRendering = forwardRef3(({
1440
1423
 
1441
1424
  // src/Gif.tsx
1442
1425
  import { jsx as jsx4 } from "react/jsx-runtime";
1426
+ import { createElement } from "react";
1443
1427
  var { useMemoizedEffectDefinitions, useMemoizedEffects } = Internals3;
1444
1428
  var gifSchema = {
1445
1429
  ...Internals3.baseSchema,
1430
+ loop: {
1431
+ type: "boolean",
1432
+ default: false,
1433
+ description: "Loop",
1434
+ keyframable: false
1435
+ },
1446
1436
  ...Internals3.premountSchema,
1447
1437
  ...Internals3.transformSchema,
1448
1438
  ...Interactive.backgroundSchema,
@@ -1479,7 +1469,6 @@ var GifInner = ({
1479
1469
  ...sequenceProps
1480
1470
  }) => {
1481
1471
  const env = useRemotionEnvironment();
1482
- const refForOutline = React.useRef(null);
1483
1472
  const {
1484
1473
  effectivePostmountFor,
1485
1474
  effectivePremountFor,
@@ -1490,7 +1479,11 @@ var GifInner = ({
1490
1479
  premountingStyle
1491
1480
  } = Internals3.usePremounting({
1492
1481
  from: from ?? 0,
1493
- durationInFrames: durationInFrames ?? Infinity,
1482
+ durationInFrames: Internals3.resolveSequenceDuration({
1483
+ durationInFrames,
1484
+ playbackRate,
1485
+ loop: sequenceProps.loop
1486
+ }),
1494
1487
  premountFor: premountFor ?? null,
1495
1488
  postmountFor: postmountFor ?? null,
1496
1489
  style: style ?? null,
@@ -1530,8 +1523,7 @@ var GifInner = ({
1530
1523
  ref
1531
1524
  }) : /* @__PURE__ */ jsx4(GifForDevelopment, {
1532
1525
  ...gifProps,
1533
- ref,
1534
- refForOutline
1526
+ ref
1535
1527
  });
1536
1528
  return /* @__PURE__ */ jsx4(Freeze, {
1537
1529
  frame: freezeFrame,
@@ -1540,7 +1532,7 @@ var GifInner = ({
1540
1532
  layout: "none",
1541
1533
  from: from ?? 0,
1542
1534
  playbackRate,
1543
- durationInFrames: durationInFrames ?? Infinity,
1535
+ durationInFrames,
1544
1536
  name: "<Gif>",
1545
1537
  _remotionInternalDocumentationLink: "https://www.remotion.dev/docs/gif/gif",
1546
1538
  controls,
@@ -1550,13 +1542,76 @@ var GifInner = ({
1550
1542
  _remotionInternalIsPremounting: premountingActive,
1551
1543
  _remotionInternalIsPostmounting: postmountingActive,
1552
1544
  ...sequenceProps,
1553
- outlineRef: refForOutline,
1554
1545
  children: inner
1555
1546
  })
1556
1547
  });
1557
1548
  };
1549
+ var GifWithIntrinsicDuration = (props) => {
1550
+ const { fps } = useVideoConfig2();
1551
+ const { delayRender, continueRender, cancelRender } = useDelayRender3();
1552
+ const { src: src2, requestInit, trimBefore } = props;
1553
+ const onErrorRef = useRef4(props.onError);
1554
+ onErrorRef.current = props.onError;
1555
+ const requestInitRef = useRef4(requestInit);
1556
+ requestInitRef.current = requestInit;
1557
+ const [handle] = useState5(() => delayRender(`Finding duration of <Gif src="${src2}" />`, {
1558
+ timeoutInMilliseconds: props.delayRenderTimeoutInMilliseconds
1559
+ }));
1560
+ const [durationInFrames, setDurationInFrames] = useState5(null);
1561
+ const [failed, setFailed] = useState5(false);
1562
+ useEffect5(() => {
1563
+ let cancelled = false;
1564
+ getGifDurationInSeconds(src2, { requestInit: requestInitRef.current }).then((duration) => {
1565
+ if (!cancelled) {
1566
+ setDurationInFrames(Math.ceil(duration * fps) - (trimBefore ?? 0));
1567
+ }
1568
+ }).catch((error) => {
1569
+ if (cancelled) {
1570
+ return;
1571
+ }
1572
+ if (onErrorRef.current) {
1573
+ onErrorRef.current(error);
1574
+ setFailed(true);
1575
+ } else {
1576
+ cancelRender(error);
1577
+ }
1578
+ });
1579
+ return () => {
1580
+ cancelled = true;
1581
+ continueRender(handle);
1582
+ };
1583
+ }, [cancelRender, continueRender, fps, handle, src2, trimBefore]);
1584
+ useEffect5(() => {
1585
+ if (durationInFrames !== null || failed) {
1586
+ continueRender(handle);
1587
+ }
1588
+ }, [continueRender, durationInFrames, failed, handle]);
1589
+ if (durationInFrames === null || failed) {
1590
+ return null;
1591
+ }
1592
+ return /* @__PURE__ */ jsx4(GifInner, {
1593
+ ...props,
1594
+ durationInFrames
1595
+ });
1596
+ };
1597
+ var GifComponent = (props) => {
1598
+ if (props.loop && props.durationInFrames === undefined) {
1599
+ const resolvedSrc = resolveGifSource(props.src);
1600
+ const cacheKey = getGifCacheKey({
1601
+ resolvedSrc,
1602
+ requestInit: props.requestInit
1603
+ });
1604
+ return /* @__PURE__ */ createElement(GifWithIntrinsicDuration, {
1605
+ ...props,
1606
+ key: `${cacheKey}-${props.trimBefore ?? 0}`
1607
+ });
1608
+ }
1609
+ return /* @__PURE__ */ jsx4(GifInner, {
1610
+ ...props
1611
+ });
1612
+ };
1558
1613
  var Gif = Interactive.withSchema({
1559
- Component: GifInner,
1614
+ Component: GifComponent,
1560
1615
  componentName: "<Gif>",
1561
1616
  componentIdentity: "dev.remotion.gif.Gif",
1562
1617
  schema: gifSchema,
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "url": "https://github.com/remotion-dev/remotion/tree/main/packages/gif"
4
4
  },
5
5
  "name": "@remotion/gif",
6
- "version": "4.0.529",
6
+ "version": "4.0.531",
7
7
  "description": "Embed GIFs in a Remotion video",
8
8
  "bugs": {
9
9
  "url": "https://github.com/remotion-dev/remotion/issues"
@@ -30,7 +30,7 @@
30
30
  }
31
31
  },
32
32
  "dependencies": {
33
- "remotion": "4.0.529"
33
+ "remotion": "4.0.531"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@testing-library/react": "16.1.0",
@@ -38,7 +38,7 @@
38
38
  "react": "19.2.3",
39
39
  "react-dom": "19.2.3",
40
40
  "webpack": "5.105.0",
41
- "@remotion/eslint-config-internal": "4.0.529",
41
+ "@remotion/eslint-config-internal": "4.0.531",
42
42
  "eslint": "9.19.0",
43
43
  "@typescript/native-preview": "7.0.0-dev.20260217.1"
44
44
  },