react-gif-timeline 0.0.2 → 0.1.0
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/index.d.ts +21 -1
- package/dist/index.js +50 -33
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -29,9 +29,29 @@ interface GifTimelineProps<A extends Anchors> extends GifTimelineOptions<A> {
|
|
|
29
29
|
renderError?: (error: string) => ReactNode;
|
|
30
30
|
children?: (result: GifTimelineResult) => ReactNode;
|
|
31
31
|
}
|
|
32
|
+
interface GifFrameOptions<A extends Anchors> {
|
|
33
|
+
src: string | Blob;
|
|
34
|
+
anchors: A;
|
|
35
|
+
activeState: ActiveState<A>;
|
|
36
|
+
speed?: number;
|
|
37
|
+
onTransitionStart?: (fromFrame: number, toFrame: number) => void;
|
|
38
|
+
onTransitionEnd?: (state: ActiveState<A>) => void;
|
|
39
|
+
}
|
|
40
|
+
interface GifFrameResult {
|
|
41
|
+
currentFrame: number;
|
|
42
|
+
totalFrames: number;
|
|
43
|
+
width: number;
|
|
44
|
+
height: number;
|
|
45
|
+
isLoaded: boolean;
|
|
46
|
+
error: string | null;
|
|
47
|
+
isTransitioning: boolean;
|
|
48
|
+
transitionProgress: number;
|
|
49
|
+
}
|
|
32
50
|
|
|
33
51
|
declare function GifTimeline<A extends Anchors>(props: GifTimelineProps<A>): react_jsx_runtime.JSX.Element;
|
|
34
52
|
|
|
53
|
+
declare function useGifFrame<A extends Anchors>(options: GifFrameOptions<A>): GifFrameResult;
|
|
54
|
+
|
|
35
55
|
declare function useGifTimeline<A extends Anchors>(options: GifTimelineOptions<A>): GifTimelineResult;
|
|
36
56
|
|
|
37
|
-
export { type ActiveState, type Anchors, GifTimeline, type GifTimelineOptions, type GifTimelineProps, type GifTimelineResult, useGifTimeline };
|
|
57
|
+
export { type ActiveState, type Anchors, type GifFrameOptions, type GifFrameResult, GifTimeline, type GifTimelineOptions, type GifTimelineProps, type GifTimelineResult, useGifFrame, useGifTimeline };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,26 @@
|
|
|
1
1
|
// src/useGifTimeline.ts
|
|
2
|
+
import { useEffect as useEffect2, useRef as useRef2 } from "react";
|
|
3
|
+
|
|
4
|
+
// src/frameRenderer.ts
|
|
5
|
+
function initCanvas(canvas, width, height) {
|
|
6
|
+
const dpr = window.devicePixelRatio || 1;
|
|
7
|
+
canvas.width = width * dpr;
|
|
8
|
+
canvas.height = height * dpr;
|
|
9
|
+
const ctx = canvas.getContext("2d");
|
|
10
|
+
ctx.scale(dpr, dpr);
|
|
11
|
+
}
|
|
12
|
+
function renderFrame(canvas, frame, width, height) {
|
|
13
|
+
const ctx = canvas.getContext("2d");
|
|
14
|
+
const temp = document.createElement("canvas");
|
|
15
|
+
temp.width = width;
|
|
16
|
+
temp.height = height;
|
|
17
|
+
const tempCtx = temp.getContext("2d");
|
|
18
|
+
tempCtx.putImageData(frame, 0, 0);
|
|
19
|
+
ctx.clearRect(0, 0, width, height);
|
|
20
|
+
ctx.drawImage(temp, 0, 0, width, height);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// src/useGifCore.ts
|
|
2
24
|
import { useEffect, useRef, useState } from "react";
|
|
3
25
|
|
|
4
26
|
// src/animator.ts
|
|
@@ -40,25 +62,6 @@ function animate(fromFrame, toFrame, delays, speed, onFrame, onComplete) {
|
|
|
40
62
|
};
|
|
41
63
|
}
|
|
42
64
|
|
|
43
|
-
// src/frameRenderer.ts
|
|
44
|
-
function initCanvas(canvas, width, height) {
|
|
45
|
-
const dpr = window.devicePixelRatio || 1;
|
|
46
|
-
canvas.width = width * dpr;
|
|
47
|
-
canvas.height = height * dpr;
|
|
48
|
-
const ctx = canvas.getContext("2d");
|
|
49
|
-
ctx.scale(dpr, dpr);
|
|
50
|
-
}
|
|
51
|
-
function renderFrame(canvas, frame, width, height) {
|
|
52
|
-
const ctx = canvas.getContext("2d");
|
|
53
|
-
const temp = document.createElement("canvas");
|
|
54
|
-
temp.width = width;
|
|
55
|
-
temp.height = height;
|
|
56
|
-
const tempCtx = temp.getContext("2d");
|
|
57
|
-
tempCtx.putImageData(frame, 0, 0);
|
|
58
|
-
ctx.clearRect(0, 0, width, height);
|
|
59
|
-
ctx.drawImage(temp, 0, 0, width, height);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
65
|
// src/gifParser.ts
|
|
63
66
|
import { decompressFrames, parseGIF } from "gifuct-js";
|
|
64
67
|
async function parseGifSource(src) {
|
|
@@ -98,16 +101,15 @@ async function parseGifSource(src) {
|
|
|
98
101
|
return { frames, delays, width, height };
|
|
99
102
|
}
|
|
100
103
|
|
|
101
|
-
// src/
|
|
104
|
+
// src/useGifCore.ts
|
|
102
105
|
function resolveAnchorFrame(anchors, activeState) {
|
|
103
106
|
if (Array.isArray(anchors)) {
|
|
104
107
|
return anchors[activeState];
|
|
105
108
|
}
|
|
106
109
|
return anchors[activeState];
|
|
107
110
|
}
|
|
108
|
-
function
|
|
111
|
+
function useGifCore(options) {
|
|
109
112
|
const { src, anchors, activeState, speed = 1, onTransitionStart, onTransitionEnd } = options;
|
|
110
|
-
const canvasRef = useRef(null);
|
|
111
113
|
const gifDataRef = useRef(null);
|
|
112
114
|
const currentFrameRef = useRef(0);
|
|
113
115
|
const animatorRef = useRef(null);
|
|
@@ -132,16 +134,10 @@ function useGifTimeline(options) {
|
|
|
132
134
|
parseGifSource(src).then((data) => {
|
|
133
135
|
if (cancelled) return;
|
|
134
136
|
gifDataRef.current = data;
|
|
135
|
-
if (canvasRef.current) {
|
|
136
|
-
initCanvas(canvasRef.current, data.width, data.height);
|
|
137
|
-
}
|
|
138
137
|
const initialFrame = resolveAnchorFrame(anchorsRef.current, activeStateRef.current);
|
|
139
138
|
const clampedFrame = Math.min(Math.max(0, initialFrame), data.frames.length - 1);
|
|
140
139
|
currentFrameRef.current = clampedFrame;
|
|
141
140
|
setCurrentFrame(clampedFrame);
|
|
142
|
-
if (canvasRef.current) {
|
|
143
|
-
renderFrame(canvasRef.current, data.frames[clampedFrame], data.width, data.height);
|
|
144
|
-
}
|
|
145
141
|
setIsLoaded(true);
|
|
146
142
|
}).catch((err) => {
|
|
147
143
|
if (cancelled) return;
|
|
@@ -183,16 +179,13 @@ function useGifTimeline(options) {
|
|
|
183
179
|
speed,
|
|
184
180
|
(frameIndex) => {
|
|
185
181
|
currentFrameRef.current = frameIndex;
|
|
186
|
-
|
|
187
|
-
renderFrame(canvasRef.current, data.frames[frameIndex], data.width, data.height);
|
|
188
|
-
}
|
|
182
|
+
setCurrentFrame(frameIndex);
|
|
189
183
|
if (frameIndex !== fromFrame) {
|
|
190
184
|
stepsDone++;
|
|
191
185
|
setTransitionProgress(totalSteps > 0 ? stepsDone / totalSteps : 1);
|
|
192
186
|
}
|
|
193
187
|
},
|
|
194
188
|
() => {
|
|
195
|
-
setCurrentFrame(targetFrame);
|
|
196
189
|
setIsTransitioning(false);
|
|
197
190
|
setTransitionProgress(1);
|
|
198
191
|
onTransitionEndRef.current?.(activeStateRef.current);
|
|
@@ -213,7 +206,7 @@ function useGifTimeline(options) {
|
|
|
213
206
|
};
|
|
214
207
|
}, []);
|
|
215
208
|
return {
|
|
216
|
-
|
|
209
|
+
gifDataRef,
|
|
217
210
|
currentFrame,
|
|
218
211
|
totalFrames: gifDataRef.current?.frames.length ?? 0,
|
|
219
212
|
width: gifDataRef.current?.width ?? 0,
|
|
@@ -225,6 +218,23 @@ function useGifTimeline(options) {
|
|
|
225
218
|
};
|
|
226
219
|
}
|
|
227
220
|
|
|
221
|
+
// src/useGifTimeline.ts
|
|
222
|
+
function useGifTimeline(options) {
|
|
223
|
+
const { gifDataRef, ...result } = useGifCore(options);
|
|
224
|
+
const canvasRef = useRef2(null);
|
|
225
|
+
useEffect2(() => {
|
|
226
|
+
const data = gifDataRef.current;
|
|
227
|
+
if (!canvasRef.current || !data || !result.isLoaded) return;
|
|
228
|
+
initCanvas(canvasRef.current, data.width, data.height);
|
|
229
|
+
}, [result.isLoaded]);
|
|
230
|
+
useEffect2(() => {
|
|
231
|
+
const data = gifDataRef.current;
|
|
232
|
+
if (!canvasRef.current || !data) return;
|
|
233
|
+
renderFrame(canvasRef.current, data.frames[result.currentFrame], data.width, data.height);
|
|
234
|
+
}, [result.currentFrame, result.isLoaded]);
|
|
235
|
+
return { ...result, canvasRef };
|
|
236
|
+
}
|
|
237
|
+
|
|
228
238
|
// src/GifTimeline.tsx
|
|
229
239
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
230
240
|
function GifTimeline(props) {
|
|
@@ -268,7 +278,14 @@ function GifTimeline(props) {
|
|
|
268
278
|
result.isLoaded && children?.(result)
|
|
269
279
|
] });
|
|
270
280
|
}
|
|
281
|
+
|
|
282
|
+
// src/useGifFrame.ts
|
|
283
|
+
function useGifFrame(options) {
|
|
284
|
+
const { gifDataRef: _, ...result } = useGifCore(options);
|
|
285
|
+
return result;
|
|
286
|
+
}
|
|
271
287
|
export {
|
|
272
288
|
GifTimeline,
|
|
289
|
+
useGifFrame,
|
|
273
290
|
useGifTimeline
|
|
274
291
|
};
|
package/package.json
CHANGED