From 0e0a2bd972ea6cf6df094232d55096a853424db0 Mon Sep 17 00:00:00 2001 From: Hernan Torrisi Date: Thu, 23 May 2024 18:56:02 -0700 Subject: [PATCH] add status handling --- src/hooks/useRiveFile.ts | 22 +++++++++++++++++----- src/types.ts | 28 ++++++++++++++++++++++------ test/useRiveFile.test.tsx | 5 +++++ 3 files changed, 44 insertions(+), 11 deletions(-) diff --git a/src/hooks/useRiveFile.ts b/src/hooks/useRiveFile.ts index 6ff9b4d..dd289d0 100644 --- a/src/hooks/useRiveFile.ts +++ b/src/hooks/useRiveFile.ts @@ -1,6 +1,10 @@ import { useState, useEffect } from 'react'; -import type { UseRiveFileParameters } from '../types'; -import { RiveFile } from '@rive-app/canvas'; +import type { + UseRiveFileParameters, + RiveFileState, + FileStatus, +} from '../types'; +import { EventType, RiveFile } from '@rive-app/canvas'; /** * Custom hook for initializing and managing a RiveFile instance within a component. @@ -11,14 +15,23 @@ import { RiveFile } from '@rive-app/canvas'; * * @returns {RiveFile} Contains the active RiveFile instance (`riveFile`). */ -function useRiveFile(params: UseRiveFileParameters) { +function useRiveFile(params: UseRiveFileParameters): RiveFileState { const [riveFile, setRiveFile] = useState(null); + const [status, setStatus] = useState('idle'); useEffect(() => { let file: RiveFile | null = null; const loadRiveFile = async () => { + setStatus('loading'); file = new RiveFile(params); + file.on(EventType.Load, () => { + setRiveFile(file); + setStatus('success'); + }); + file.on(EventType.LoadError, () => { + setStatus('failed'); + }); setRiveFile(file); }; @@ -31,8 +44,7 @@ function useRiveFile(params: UseRiveFileParameters) { }; }, [params.src, params.buffer]); - - return { riveFile }; + return { riveFile, status }; } export default useRiveFile; diff --git a/src/types.ts b/src/types.ts index c7d9210..f5c6c50 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,5 +1,10 @@ -import { RefCallback, ComponentProps } from 'react'; -import { Rive, RiveParameters, RiveFileParameters } from '@rive-app/canvas'; +import { + Rive, + RiveFile, + RiveFileParameters, + RiveParameters, +} from '@rive-app/canvas'; +import { ComponentProps, RefCallback } from 'react'; export type UseRiveParameters = Partial> | null; @@ -22,9 +27,9 @@ export type Dimensions = { * @property canvas - Canvas element the Rive Animation is attached to. * @property container - Container element of the canvas. * @property setCanvasRef - Ref callback to be passed to the canvas element. - * @property setContainerRef - Ref callback to be passed to the container element - * of the canvas. This is optional, however if not used then the hook will - * not take care of automatically resizing the canvas to it's outer + * @property setContainerRef - Ref callback to be passed to the container + * element of the canvas. This is optional, however if not used then the hook + * will not take care of automatically resizing the canvas to it's outer * container if the window resizes. * @property rive - The loaded Rive Animation */ @@ -37,5 +42,16 @@ export type RiveState = { RiveComponent: (props: ComponentProps<'canvas'>) => JSX.Element; }; +export type UseRiveFileParameters = RiveFileParameters; -export type UseRiveFileParameters = RiveFileParameters; \ No newline at end of file +export type FileStatus = 'idle' | 'loading' | 'failed' | 'success'; + +/** + * @typedef RiveFileState + * @property data - The RiveFile instance + * @property status - The status of the file + */ +export type RiveFileState = { + riveFile: RiveFile | null; + status: FileStatus; +}; diff --git a/test/useRiveFile.test.tsx b/test/useRiveFile.test.tsx index 1483541..1bcd880 100644 --- a/test/useRiveFile.test.tsx +++ b/test/useRiveFile.test.tsx @@ -7,7 +7,12 @@ import { RiveFile } from '@rive-app/canvas'; jest.mock('@rive-app/canvas', () => ({ RiveFile: jest.fn().mockImplementation(() => ({ cleanup: jest.fn(), + on: jest.fn(), })), + EventType: { + Load: 'load', + loadError: 'loadError', + }, }));