Compare commits

...

16 Commits

Author SHA1 Message Date
Maxwell Talbot
25afe7d77e adding resize example 2022-07-21 17:00:42 +02:00
Maxwell Talbot
258270b4fc update name 2022-07-21 17:00:21 +02:00
Maxwell Talbot
41962ef864 ensure we re evaluate state machine inputs when we play is triggered, looks like there maybe additional situations where we are going to need this. 2022-07-21 10:17:27 +01:00
Maxwell Talbot
c69fffa5cf update resize behaviour to throttle, add parameters to enable switching modes 2022-07-21 10:08:52 +01:00
zplata
efe28aa5f3 chore: release 3.0.19 2022-07-19 23:48:34 +00:00
Zach Plata
16d836c959 fix tests that were automatically calling the rive load callback to be more controlled 2022-07-19 18:44:20 -05:00
Zach Plata
838ed1abf8 Fix: Add check before setting Rive as state variable on Rive instance load 2022-07-19 18:44:20 -05:00
mjtalbot
d010a55cc0 chore: release 3.0.18 2022-07-14 12:26:10 +00:00
Maxwell Talbot
fd1c00a995 update canvas dimensions to use clientWidth and Height as opposed to BoundingClient, to avoid getting scaled information 2022-07-14 13:22:12 +01:00
mjtalbot
45aec2db1c chore: release 3.0.17 2022-07-14 10:28:50 +00:00
Maxwell Talbot
62b3a1d8dc removed polyfill in favour of DIY appraoch to reduce package size 2022-07-14 11:24:55 +01:00
Maxwell Talbot
5be9d2f874 refactored the IE check into useSize 2022-07-14 11:24:55 +01:00
Maxwell Talbot
49a6b1de11 added additional linting 2022-07-14 11:24:55 +01:00
Zach Plata
ec61a6835d Fix useEffects so they're not in conditional statements 2022-07-14 11:24:55 +01:00
Zach Plata
ac29fa30a7 strip out storybook deploy workflow 2022-07-14 11:24:55 +01:00
Maxwell Talbot
e966316971 add resizeObserver to replace window listeners for all but IE 2022-07-14 11:24:55 +01:00
17 changed files with 460 additions and 110 deletions

View File

@@ -1,29 +1,38 @@
module.exports = {
env: {
browser: true,
es2021: true
es2021: true,
},
extends: ['plugin:react/recommended', 'prettier', 'plugin:storybook/recommended'],
extends: [
'plugin:react/recommended',
'prettier',
'plugin:storybook/recommended',
],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaFeatures: {
jsx: true
jsx: true,
},
ecmaVersion: 12,
sourceType: 'module'
sourceType: 'module',
},
plugins: ['@typescript-eslint', 'prettier'],
plugins: ['@typescript-eslint', 'prettier', 'react-hooks'],
rules: {
'@typescript-eslint/no-unused-vars': 'error',
'prefer-const': ['warn', {
destructuring: 'all'
}],
'prefer-const': [
'warn',
{
destructuring: 'all',
},
],
'no-var': 'error',
eqeqeq: ['error', 'smart']
eqeqeq: ['error', 'smart'],
'react-hooks/rules-of-hooks': 'error', // Checks rules of Hooks
'react-hooks/exhaustive-deps': 'off', // Checks effect dependencies
},
settings: {
react: {
version: 'detect'
}
}
};
version: 'detect',
},
},
};

View File

@@ -1,10 +1,12 @@
name: Deploy Storybook
on:
pull_request:
types: [closed]
branches:
- main
paths: ['src', 'examples/stories/**'] # Trigger the action only when files change in the folders defined here
# Testing to see if this job is causing the race condition
workflow_dispatch:
# pull_request:
# types: [closed]
# branches:
# - main
# paths: ['src', 'examples/stories/**'] # Trigger the action only when files change in the folders defined here
jobs:
build-and-deploy:
runs-on: ubuntu-latest

View File

@@ -4,9 +4,120 @@ All notable changes to this project will be documented in this file. Dates are d
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
#### [v3.0.16](https://github.com/rive-app/rive-react/compare/v3.0.1...v3.0.16)
#### [v3.0.19](https://github.com/rive-app/rive-react/compare/v3.0.18...v3.0.19)
- Adding more examples [`8ce77f1`](https://github.com/rive-app/rive-react/commit/8ce77f153c6a5d06a20ec4d83a7570e5f6453aa5)
- fix tests that were automatically calling the rive load callback to be more controlled [`16d836c`](https://github.com/rive-app/rive-react/commit/16d836c95928e4294b565ecb444d517653c4988b)
#### [v3.0.18](https://github.com/rive-app/rive-react/compare/v3.0.17...v3.0.18)
> 14 July 2022
- update canvas dimensions to use clientWidth and Height as opposed to BoundingClient, to avoid getting scaled information [`fd1c00a`](https://github.com/rive-app/rive-react/commit/fd1c00a995374634ec8552d20a0f7094fcb04e25)
- chore: release 3.0.18 [`d010a55`](https://github.com/rive-app/rive-react/commit/d010a55cc0c065c353dd5424a6fef8a58f416c61)
#### [v3.0.17](https://github.com/rive-app/rive-react/compare/v3.0.16...v3.0.17)
> 14 July 2022
- add resizeObserver to replace window listeners for all but IE [`e966316`](https://github.com/rive-app/rive-react/commit/e966316971d88a7242651a0b1fa3a1eaff48d276)
- refactored the IE check into `useSize` [`5be9d2f`](https://github.com/rive-app/rive-react/commit/5be9d2f8741224ed7cd291898b1abe88668b3fed)
- Fix useEffects so they're not in conditional statements [`ec61a68`](https://github.com/rive-app/rive-react/commit/ec61a6835d9ca6158538f5d1ac5b6b861c58ac57)
#### [v3.0.16](https://github.com/rive-app/rive-react/compare/v3.0.15...v3.0.16)
> 12 July 2022
- Docs: Condense down README and add CONTRIBUTING guide [`0863835`](https://github.com/rive-app/rive-react/commit/08638359bb817213fb861950a20cae7e7b27111f)
- staged work [`7dbade4`](https://github.com/rive-app/rive-react/commit/7dbade4589ca0524b58f9abbdcc38afa3e3b1866)
- chore: release 3.0.16 [`ae6efc1`](https://github.com/rive-app/rive-react/commit/ae6efc14d46c33b90fe89ee067347296daf865e7)
#### [v3.0.15](https://github.com/rive-app/rive-react/compare/v3.0.14...v3.0.15)
> 28 June 2022
- chore: release 3.0.15 [`8175c4a`](https://github.com/rive-app/rive-react/commit/8175c4a4d406ac80703a6df346f3b5562d2e9311)
- Patch: Bump js runtime dependencies for nested artboard display patch [`795ee53`](https://github.com/rive-app/rive-react/commit/795ee533405ec98457db074d11730849e1be5c88)
#### [v3.0.14](https://github.com/rive-app/rive-react/compare/v3.0.12...v3.0.14)
> 28 June 2022
- Deploying to main from @ 3477afdef166251f35f1778a3143ff6c6efecc58 🚀 [`7aee5cf`](https://github.com/rive-app/rive-react/commit/7aee5cfab4eaca1fc9369742639507a770c4f756)
- Fix: Intake JS runtime patches for starting animation frames [`3477afd`](https://github.com/rive-app/rive-react/commit/3477afdef166251f35f1778a3143ff6c6efecc58)
- chore: release 3.0.14 [`04353db`](https://github.com/rive-app/rive-react/commit/04353db43266f6dcf40f4ef7f3be23afa13c2e0d)
#### [v3.0.12](https://github.com/rive-app/rive-react/compare/v3.0.11...v3.0.12)
> 22 June 2022
- chore: release 3.0.12 [`8b43a82`](https://github.com/rive-app/rive-react/commit/8b43a82c5f56cbb5b1fe7dacfa7ca8457fc6d413)
- Fix: Bump cpp to get nested artboard opacity fix and fill rule patch [`bd49e6a`](https://github.com/rive-app/rive-react/commit/bd49e6a4ee66c68005b60a670700ef69b5322656)
- Bump @rive-app/canvas to take the fillRule bug fix [`1dbb9cd`](https://github.com/rive-app/rive-react/commit/1dbb9cd38d41393b9f354cdf81e88c702aa3ae64)
#### [v3.0.11](https://github.com/rive-app/rive-react/compare/v3.0.10...v3.0.11)
> 22 June 2022
- chore: release 3.0.11 [`aee7407`](https://github.com/rive-app/rive-react/commit/aee7407f7921c515f3c1d9aabf87387baddb4064)
- Docs: Code snippets update to use new React package structure [`b48de9d`](https://github.com/rive-app/rive-react/commit/b48de9db8496be35f29bea87273a7a9fceefdafc)
#### [v3.0.10](https://github.com/rive-app/rive-react/compare/v3.0.8...v3.0.10)
> 20 June 2022
- Deploying to main from @ 5ad5a957a6e8f10abedc23f46033d4792e29dfe5 🚀 [`802648e`](https://github.com/rive-app/rive-react/commit/802648eda8fa0e5a0a35c66af06e476eac59fe9e)
- chore: release 3.0.10 [`6772f16`](https://github.com/rive-app/rive-react/commit/6772f166b7f3e4747ae508a54e2533bb3ea49878)
- Maint: Update docs for storybook link [`5ad5a95`](https://github.com/rive-app/rive-react/commit/5ad5a957a6e8f10abedc23f46033d4792e29dfe5)
#### [v3.0.8](https://github.com/rive-app/rive-react/compare/v3.0.7...v3.0.8)
> 9 June 2022
- Maint: Add GH workflow for deploying storybook to Github Pages [`38625a0`](https://github.com/rive-app/rive-react/commit/38625a00c313192d0edbe1c3a855bea1ec56bd2b)
- chore: release 3.0.8 [`414d6f8`](https://github.com/rive-app/rive-react/commit/414d6f895ac2184876dec90959c17c2b22f6843f)
#### [v3.0.7](https://github.com/rive-app/rive-react/compare/v3.0.6...v3.0.7)
> 8 June 2022
- Feat: Move existing examples into Storybook and add documentation [`ec230fa`](https://github.com/rive-app/rive-react/commit/ec230faa738202cedad14cc866e30c4c03efffd7)
- chore: release 3.0.7 [`bad688d`](https://github.com/rive-app/rive-react/commit/bad688dfa3841ec07e30fa07609a6cb7bb7c1688)
#### [v3.0.6](https://github.com/rive-app/rive-react/compare/v3.0.5...v3.0.6)
> 6 June 2022
- chore: release 3.0.6 [`90c6d1e`](https://github.com/rive-app/rive-react/commit/90c6d1edb1d4bef6250dd4a5101a7cfe04ff9ce9)
- Maint: Roll canvas and webgl dependencies forward to support nested state machines [`0480dc9`](https://github.com/rive-app/rive-react/commit/0480dc92c842265d601d08b60fb49392969cfd9e)
#### [v3.0.5](https://github.com/rive-app/rive-react/compare/v3.0.4...v3.0.5)
> 26 May 2022
- chore: release 3.0.5 [`de24fa5`](https://github.com/rive-app/rive-react/commit/de24fa564117d4acbe60b4cf734abd9e951b30f1)
- Feat: Add stateMachines param to the default Rive component [`84d9730`](https://github.com/rive-app/rive-react/commit/84d9730767a62c63e743d5a04bba5b3d480ea38d)
- Maint: Bump wasm for another listener patch [`805afd5`](https://github.com/rive-app/rive-react/commit/805afd5dff2888294926c32ec07f5e24db804d09)
#### [v3.0.4](https://github.com/rive-app/rive-react/compare/v3.0.3...v3.0.4)
> 23 May 2022
- chore: release 3.0.4 [`9abee34`](https://github.com/rive-app/rive-react/commit/9abee34d12641f845b93febf438df0f77f72153f)
- Maint: Bump rive-wasm dependency for listener patches [`12801b1`](https://github.com/rive-app/rive-react/commit/12801b10cc8980339e5856d71d96da3c612cb291)
#### [v3.0.3](https://github.com/rive-app/rive-react/compare/v3.0.2...v3.0.3)
> 17 May 2022
- Feat: Bump wasm and add examples to support touch feature [`3902948`](https://github.com/rive-app/rive-react/commit/3902948a2ef8af6955ef12124207edee29eb0be8)
- chore: release 3.0.3 [`da11387`](https://github.com/rive-app/rive-react/commit/da1138755861aadb9e7c6cb0028f2120d610a6c5)
#### [v3.0.2](https://github.com/rive-app/rive-react/compare/v3.0.1...v3.0.2)
> 17 May 2022
- chore: release 3.0.2 [`21a17ed`](https://github.com/rive-app/rive-react/commit/21a17ed40ee51263c666dde48b6c55e958eceeb8)
- Maint: Bump wasm dependencies [`f0e7092`](https://github.com/rive-app/rive-react/commit/f0e70924ec9849f45ecddda801ad63e1d87b1bdb)
#### [v3.0.1](https://github.com/rive-app/rive-react/compare/v3.0.0...v3.0.1)

View File

@@ -0,0 +1,32 @@
# To run
This is a basic showcase of a resize issue we have, to test this locally with rive-react changes
1. run `npm start`
2. run `npm run build` for the rive-react project
If you want to also test local wasm changes:
1. update `rive-react`/package.json to a locally checked out version of rive-wasm's canvas_single
`"@rive-app/canvas": "../rive-wasm/js/npm/canvas_single",`
2. cd to `rive-wasm/js` & run `npm run dev` (keep this going as it will watch for changes)
3. run `npm start`
4. run `npm run build` for the rive-react project
# Resize issue:
update parameters in `utils.ts` to see this for yourself.
Resizing from window.resize
- bottom animation moves slower than rest
- cannot deal with the animations container resizing, unless its linked to the window resizing
Resizing from ResizeObserver
- all animations move together super smooth when resizing
- top two animations flicker to white (blank canvas) when resizing
Resizing form ResizeObserver - throttled (current default)
- all animations move "together"
- resizing looks pretty smooth, but everything lags behind a bit.
# Other issues
its also very slow resizing when dev tools is open, its fine when closed though.

View File

@@ -0,0 +1,36 @@
{
"name": "basic-with-hook",
"version": "0.1.0",
"private": true,
"dependencies": {
"@testing-library/jest-dom": "^5.13.0",
"@testing-library/react": "^11.2.7",
"@testing-library/user-event": "^12.8.3",
"react": "file:../../node_modules/react",
"react-dom": "^17.0.2",
"react-scripts": "4.0.3",
"rive-react": "file:../..",
"web-vitals": "^1.1.2"
},
"scripts": {
"start": "SKIP_PREFLIGHT_CHECK=true react-scripts start"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}

View File

@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<title>Rive React - Basic with Hook</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>

View File

Binary file not shown.

View File

Binary file not shown.

View File

@@ -0,0 +1,30 @@
import { useRive } from 'rive-react';
function App() {
const params = {
src: 'poison-loader.riv',
autoplay: true,
};
const { RiveComponent: RiveComponentBasic } = useRive(params);
const { RiveComponent: RiveComponentBasic2 } = useRive(params);
const { RiveComponent: RiveComponentBasic3 } = useRive(params);
return (
<>
<div style={{ width: '100%' }}>
<div style={{ height: '300px', width: '100%' }}>
<RiveComponentBasic />
</div>
<div style={{ height: '300px', width: '100%' }}>
<RiveComponentBasic2 />
</div>
<div style={{ height: '300px', width: '100%' }}>
<RiveComponentBasic3 />
</div>
</div>
</>
);
}
export default App;

View File

@@ -0,0 +1,10 @@
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);

View File

@@ -1,6 +1,6 @@
{
"name": "rive-react",
"version": "3.0.16",
"version": "3.0.19",
"description": "React wrapper around the rive-js library",
"main": "dist/index.js",
"typings": "dist/types/index.d.ts",
@@ -65,6 +65,7 @@
"eslint-plugin-prettier": "^3.4.0",
"eslint-plugin-promise": "^5.1.0",
"eslint-plugin-react": "^7.27.1",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-storybook": "^0.5.12",
"jest": "^27.0.4",
"prettier": "^2.3.1",

View File

@@ -13,7 +13,7 @@ import {
RiveState,
Dimensions,
} from '../types';
import { useWindowSize } from '../utils';
import { useSize } from '../utils';
type RiveComponentProps = {
setContainerRef: RefCallback<HTMLElement>;
@@ -80,6 +80,7 @@ export default function useRive(
): RiveState {
const canvasRef = useRef<HTMLCanvasElement | null>(null);
const containerRef = useRef<HTMLElement | null>(null);
const [rive, setRive] = useState<Rive | null>(null);
const [dimensions, setDimensions] = useState<Dimensions>({
height: 0,
@@ -88,7 +89,7 @@ export default function useRive(
// Listen to changes in the window sizes and update the bounds when changes
// occur.
const windowSize = useWindowSize();
const size = useSize(containerRef);
const isParamsLoaded = Boolean(riveParams);
const options = getOptions(opts);
@@ -103,8 +104,12 @@ export default function useRive(
* @returns Dimensions object.
*/
function getCanvasDimensions() {
const { width, height } =
containerRef.current?.getBoundingClientRect() ?? new DOMRect(0, 0, 0, 0);
// getBoundingClientRect returns the scaled width and height
// this will result in double scaling
// https://developer.mozilla.org/en-US/docs/Web/API/CSS_Object_Model/Determining_the_dimensions_of_elements
const width = containerRef.current?.clientWidth ?? 0;
const height = containerRef.current?.clientHeight ?? 0;
if (rive && options.fitCanvasToArtboardHeight) {
const { maxY, maxX } = rive.bounds;
@@ -155,26 +160,34 @@ export default function useRive(
/**
* Listen to changes on the windowSize and the rive file being loaded
* and update the canvas bounds as needed.
*
* ie does not support ResizeObservers, so we fallback to the window listener there
*/
useEffect(() => {
if (rive) {
updateBounds();
}
}, [rive, windowSize]);
}, [rive, size]);
/**
* Ref callback called when the canvas element mounts and unmounts.
*/
const setCanvasRef: RefCallback<HTMLCanvasElement> = useCallback(
(canvas: HTMLCanvasElement | null) => {
if (canvas && riveParams) {
if (canvas && riveParams && isParamsLoaded) {
const { useOffscreenRenderer } = options;
const r = new Rive({
useOffscreenRenderer,
...riveParams,
canvas,
});
r.on(EventType.Load, () => setRive(r));
r.on(EventType.Load, () => {
// Check if the component/canvas is mounted before setting state to avoid setState
// on an unmounted component in some rare cases
if (canvasRef.current) {
setRive(r);
}
});
} else if (canvas === null && canvasRef.current) {
canvasRef.current.height = 0;
canvasRef.current.width = 0;
@@ -184,7 +197,6 @@ export default function useRive(
},
[isParamsLoaded]
);
/**
* Ref callback called when the container element mounts
*/

View File

@@ -1,5 +1,5 @@
import { useState, useEffect } from 'react';
import { Rive, StateMachineInput } from '@rive-app/canvas';
import { EventType, Rive, StateMachineInput } from '@rive-app/canvas';
/**
* Custom hook for fetching a stateMachine input from a rive file.
@@ -18,21 +18,33 @@ export default function useStateMachineInput(
const [input, setInput] = useState<StateMachineInput | null>(null);
useEffect(() => {
if (!rive || !stateMachineName || !inputName) {
setInput(null);
}
if (rive && stateMachineName && inputName) {
const inputs = rive.stateMachineInputs(stateMachineName);
if (inputs) {
const selectedInput = inputs.find((input) => input.name === inputName);
if (initialValue !== undefined && selectedInput) {
selectedInput.value = initialValue;
}
setInput(selectedInput || null);
function setStateMachineInput() {
if (!rive || !stateMachineName || !inputName) {
setInput(null);
}
} else {
setInput(null);
if (rive && stateMachineName && inputName) {
const inputs = rive.stateMachineInputs(stateMachineName);
if (inputs) {
const selectedInput = inputs.find(
(input) => input.name === inputName
);
if (initialValue !== undefined && selectedInput) {
selectedInput.value = initialValue;
}
setInput(selectedInput || null);
}
} else {
setInput(null);
}
}
setStateMachineInput();
if (rive) {
rive.on(EventType.Play, () => {
// Check if the component/canvas is mounted before setting state to avoid setState
// on an unmounted component in some rare cases
setStateMachineInput();
});
}
}, [rive]);

View File

@@ -1,24 +1,90 @@
import { useState, useEffect } from 'react';
import React, { useState, useEffect, useRef } from 'react';
import { Dimensions } from './types';
export function useWindowSize() {
const [windowSize, setWindowSize] = useState<Dimensions>({
// There are polyfills for this, but they add hundreds of lines of code
class FakeResizeObserver {
observe() {}
unobserve() {}
disconnect() {}
}
function throttle(f: Function, delay: number) {
let timer = 0;
return function (this: Function, ...args: any) {
clearTimeout(timer);
timer = setTimeout(() => f.apply(this, args), delay) as unknown as number;
};
}
const MyResizeObserver = globalThis.ResizeObserver || FakeResizeObserver;
const hasResizeObserver = globalThis.ResizeObserver !== undefined;
const preferResizeObserver = true;
const throttleResizeObserver = true;
const useResizeObserver = hasResizeObserver && preferResizeObserver;
const useWindowListener = !useResizeObserver;
export function useSize(
containerRef: React.MutableRefObject<HTMLElement | null>
) {
const [size, setSize] = useState<Dimensions>({
width: 0,
height: 0,
});
// internet explorer does not support ResizeObservers.
useEffect(() => {
if (typeof window !== 'undefined') {
const handleResize = () => {
setWindowSize({
setSize({
width: window.innerWidth,
height: window.innerHeight,
});
};
window.addEventListener('resize', handleResize);
handleResize();
if (useWindowListener) {
// only pay attention to window size changes when we do not have the resizeObserver (IE only)
handleResize();
window.addEventListener('resize', handleResize);
}
return () => window.removeEventListener('resize', handleResize);
}
}, []);
return windowSize;
const observer = useRef(
new MyResizeObserver(
throttleResizeObserver
? throttle((entries: any) => {
if (useResizeObserver) {
setSize({
width: entries[entries.length - 1].contentRect.width,
height: entries[entries.length - 1].contentRect.height,
});
}
}, 16)
: (entries: any) => {
if (useResizeObserver) {
setSize({
width: entries[entries.length - 1].contentRect.width,
height: entries[entries.length - 1].contentRect.height,
});
}
}
)
);
useEffect(() => {
const current = observer.current;
if (containerRef.current && useResizeObserver) {
current.observe(containerRef.current);
}
return () => {
current.disconnect();
if (containerRef.current && useResizeObserver) {
current.unobserve(containerRef.current);
}
};
}, [containerRef, observer]);
return size;
}

View File

@@ -1,6 +1,6 @@
import React from 'react';
import RiveComponent from '../src/components/Rive';
import {render} from '@testing-library/react'
import { render } from '@testing-library/react';
jest.mock('@rive-app/canvas', () => ({
Rive: jest.fn().mockImplementation(() => ({
@@ -26,7 +26,13 @@ jest.mock('@rive-app/canvas', () => ({
describe('Rive Component', () => {
it('renders the component as a canvas and a div wrapper', () => {
const {container, getByLabelText} = render(<RiveComponent src="foo.riv" className="container-styles" aria-label="Foo label" />);
const { container, getByLabelText } = render(
<RiveComponent
src="foo.riv"
className="container-styles"
aria-label="Foo label"
/>
);
expect(container.firstChild).toHaveClass('container-styles');
expect(getByLabelText('Foo label').tagName).toEqual('CANVAS');
});

View File

@@ -29,6 +29,23 @@ jest.mock('@rive-app/canvas', () => ({
}));
describe('useRive', () => {
let controlledRiveloadCb: () => void;
let baseRiveMock: Partial<rive.Rive>;
beforeEach(() => {
baseRiveMock = {
on: (_: rive.EventType, cb: rive.EventCallback) =>
((controlledRiveloadCb as rive.EventCallback) = cb),
stop: jest.fn(),
stopRendering: jest.fn(),
startRendering: jest.fn(),
};
});
afterEach(() => {
controlledRiveloadCb = () => {};
});
it('returns rive as null if no params are passed', () => {
const { result } = renderHook(() => useRive());
expect(result.current.rive).toBe(null);
@@ -40,23 +57,17 @@ describe('useRive', () => {
src: 'file-src',
};
const riveMock = {
on: (_: string, cb: () => void) => cb(),
stop: jest.fn(),
stopRendering: jest.fn(),
};
// @ts-ignore
mocked(rive.Rive).mockImplementation(() => riveMock);
mocked(rive.Rive).mockImplementation(() => baseRiveMock);
const canvasSpy = document.createElement('canvas');
const { result } = renderHook(() => useRive(params));
await act(async () => {
result.current.setCanvasRef(canvasSpy);
controlledRiveloadCb();
});
expect(result.current.rive).toBe(riveMock);
expect(result.current.rive).toBe(baseRiveMock);
expect(result.current.canvas).toBe(canvasSpy);
});
@@ -68,9 +79,7 @@ describe('useRive', () => {
const resizeToCanvasMock = jest.fn();
const riveMock = {
on: (_: string, cb: () => void) => cb(),
stop: jest.fn(),
stopRendering: jest.fn(),
...baseRiveMock,
resizeToCanvas: resizeToCanvasMock,
};
@@ -84,6 +93,7 @@ describe('useRive', () => {
await act(async () => {
result.current.setCanvasRef(canvasSpy);
result.current.setContainerRef(containerSpy);
controlledRiveloadCb();
});
expect(result.current.rive).toBe(riveMock);
@@ -100,7 +110,7 @@ describe('useRive', () => {
const stopMock = jest.fn();
const riveMock = {
on: (_: string, cb: () => void) => cb(),
...baseRiveMock,
stop: stopMock,
};
@@ -112,6 +122,7 @@ describe('useRive', () => {
await act(async () => {
result.current.setCanvasRef(canvasSpy);
controlledRiveloadCb();
});
unmount();
@@ -126,26 +137,20 @@ describe('useRive', () => {
global.devicePixelRatio = 2;
const riveMock = {
on: (_: string, cb: () => void) => cb(),
stop: jest.fn(),
};
// @ts-ignore
mocked(rive.Rive).mockImplementation(() => riveMock);
mocked(rive.Rive).mockImplementation(() => baseRiveMock);
const canvasSpy = document.createElement('canvas');
const containerSpy = document.createElement('div');
containerSpy.getBoundingClientRect = jest.fn().mockImplementation(() => ({
width: 100,
height: 100,
}));
jest.spyOn(containerSpy, 'clientWidth', 'get').mockReturnValue(100);
jest.spyOn(containerSpy, 'clientHeight', 'get').mockReturnValue(100);
const { result } = renderHook(() => useRive(params));
await act(async () => {
result.current.setCanvasRef(canvasSpy);
result.current.setContainerRef(containerSpy);
controlledRiveloadCb();
});
// Height and width should be 2* the width and height returned from containers
@@ -166,26 +171,20 @@ describe('useRive', () => {
useDevicePixelRatio: false,
};
const riveMock = {
on: (_: string, cb: () => void) => cb(),
stop: jest.fn(),
};
// @ts-ignore
mocked(rive.Rive).mockImplementation(() => riveMock);
mocked(rive.Rive).mockImplementation(() => baseRiveMock);
const canvasSpy = document.createElement('canvas');
const containerSpy = document.createElement('div');
containerSpy.getBoundingClientRect = jest.fn().mockImplementation(() => ({
width: 100,
height: 100,
}));
jest.spyOn(containerSpy, 'clientWidth', 'get').mockReturnValue(100);
jest.spyOn(containerSpy, 'clientHeight', 'get').mockReturnValue(100);
const { result } = renderHook(() => useRive(params, opts));
await act(async () => {
result.current.setCanvasRef(canvasSpy);
result.current.setContainerRef(containerSpy);
controlledRiveloadCb();
});
// Height and width should be same as containers bounding rect
@@ -203,8 +202,7 @@ describe('useRive', () => {
};
const riveMock = {
on: (_: string, cb: () => void) => cb(),
stop: jest.fn(),
...baseRiveMock,
bounds: {
maxX: 100,
maxY: 50,
@@ -216,16 +214,15 @@ describe('useRive', () => {
const canvasSpy = document.createElement('canvas');
const containerSpy = document.createElement('div');
containerSpy.getBoundingClientRect = jest.fn().mockImplementation(() => ({
width: 100,
height: 100,
}));
jest.spyOn(containerSpy, 'clientWidth', 'get').mockReturnValue(100);
jest.spyOn(containerSpy, 'clientHeight', 'get').mockReturnValue(100);
const { result } = renderHook(() => useRive(params, opts));
await act(async () => {
result.current.setContainerRef(containerSpy);
result.current.setCanvasRef(canvasSpy);
controlledRiveloadCb();
});
// Height and width should be same as containers bounding rect
@@ -249,8 +246,7 @@ describe('useRive', () => {
}));
const riveMock = {
on: (_: string, cb: () => void) => cb(),
stop: jest.fn(),
...baseRiveMock,
bounds: {
maxX: 100,
maxY: 50,
@@ -266,6 +262,7 @@ describe('useRive', () => {
await act(async () => {
result.current.setCanvasRef(canvasSpy);
controlledRiveloadCb();
});
expect(observeMock).toBeCalledWith(canvasSpy);
@@ -283,7 +280,7 @@ describe('useRive', () => {
const stopMock = jest.fn();
const riveMock = {
on: (_: string, cb: () => void) => cb(),
...baseRiveMock,
stop: stopMock,
play: playMock,
animationNames: ['light'],
@@ -301,6 +298,7 @@ describe('useRive', () => {
await act(async () => {
result.current.setCanvasRef(canvasSpy);
controlledRiveloadCb();
});
rerender({
@@ -323,7 +321,7 @@ describe('useRive', () => {
const stopMock = jest.fn();
const riveMock = {
on: (_: string, cb: () => void) => cb(),
...baseRiveMock,
stop: stopMock,
play: playMock,
pause: pauseMock,
@@ -343,6 +341,7 @@ describe('useRive', () => {
await act(async () => {
result.current.setCanvasRef(canvasSpy);
controlledRiveloadCb();
});
rerender({
@@ -360,20 +359,15 @@ describe('useRive', () => {
src: 'file-src',
};
const riveMock = {
on: (_: string, cb: () => void) => cb(),
stop: jest.fn(),
stopRendering: jest.fn(),
};
// @ts-ignore
mocked(rive.Rive).mockImplementation(() => riveMock);
mocked(rive.Rive).mockImplementation(() => baseRiveMock);
const canvasSpy = document.createElement('canvas');
const { result } = renderHook(() => useRive(params));
await act(async () => {
result.current.setCanvasRef(canvasSpy);
controlledRiveloadCb();
});
const { RiveComponent: RiveTestComponent } = result.current;

View File

@@ -2,7 +2,7 @@ import { mocked } from 'jest-mock';
import { renderHook } from '@testing-library/react-hooks';
import useStateMachineInput from '../src/hooks/useStateMachineInput';
import {Rive, StateMachineInput} from '@rive-app/canvas';
import { Rive, StateMachineInput } from '@rive-app/canvas';
jest.mock('@rive-app/canvas', () => ({
Rive: jest.fn().mockImplementation(() => ({
@@ -36,7 +36,9 @@ describe('useStateMachineInput', () => {
const riveMock = {};
mocked(Rive).mockImplementation(() => riveMock as Rive);
const { result } = renderHook(() => useStateMachineInput(riveMock as Rive, '', 'testInput'));
const { result } = renderHook(() =>
useStateMachineInput(riveMock as Rive, '', 'testInput')
);
expect(result.current).toBeNull();
});
@@ -44,7 +46,9 @@ describe('useStateMachineInput', () => {
const riveMock = {};
mocked(Rive).mockImplementation(() => riveMock as Rive);
const { result } = renderHook(() => useStateMachineInput(riveMock as Rive, 'smName', ''));
const { result } = renderHook(() =>
useStateMachineInput(riveMock as Rive, 'smName', '')
);
expect(result.current).toBeNull();
});
@@ -55,7 +59,9 @@ describe('useStateMachineInput', () => {
};
mocked(Rive).mockImplementation(() => riveMock as Rive);
const { result } = renderHook(() => useStateMachineInput(riveMock as Rive, 'smName', ''));
const { result } = renderHook(() =>
useStateMachineInput(riveMock as Rive, 'smName', '')
);
expect(result.current).toBeNull();
});
@@ -69,7 +75,9 @@ describe('useStateMachineInput', () => {
};
mocked(Rive).mockImplementation(() => riveMock as Rive);
const { result } = renderHook(() => useStateMachineInput(riveMock as Rive, 'smName', 'numInput'));
const { result } = renderHook(() =>
useStateMachineInput(riveMock as Rive, 'smName', 'numInput')
);
expect(result.current).toBeNull();
});
@@ -83,7 +91,9 @@ describe('useStateMachineInput', () => {
};
mocked(Rive).mockImplementation(() => riveMock as Rive);
const { result } = renderHook(() => useStateMachineInput(riveMock as Rive, 'smName', 'boolInput'));
const { result } = renderHook(() =>
useStateMachineInput(riveMock as Rive, 'smName', 'boolInput')
);
expect(result.current).toBe(smInput);
});
@@ -98,7 +108,9 @@ describe('useStateMachineInput', () => {
};
mocked(Rive).mockImplementation(() => riveMock as Rive);
const { result } = renderHook(() => useStateMachineInput(riveMock as Rive, 'smName', 'boolInput', true));
const { result } = renderHook(() =>
useStateMachineInput(riveMock as Rive, 'smName', 'boolInput', true)
);
expect(result.current).toStrictEqual({
...smInput,
value: true,