Compare commits

..

34 Commits

Author SHA1 Message Date
Adam
dab7a8d6f0 Merge branch 'main' into feature/initial-databinding 2025-05-05 18:21:14 -07:00
Adam
d2ccee1220 feat: add db test 2025-05-05 17:32:36 -07:00
Lance
5bf53fc238 Add onTrigger example 2025-05-05 15:14:01 -06:00
Lance
e49b9ae606 Add stocks data binding example 2025-05-01 23:10:49 -06:00
Lance
fc78d38a0b Merge storybook 2025-05-01 22:27:46 -06:00
lancesnider
04397e658c chore: release 4.19.0 2025-05-01 22:27:46 -06:00
Lance
52519885c6 Fix failing tests 2025-05-01 22:27:46 -06:00
Lance
2ad2df085b Upgrade testing 2025-05-01 22:27:46 -06:00
Lance
c9308db9dc Upgrade React and React DOM 2025-05-01 22:27:46 -06:00
Lance
082b9a6323 Update contributing docs 2025-05-01 22:27:46 -06:00
Lance
6aaee36ff0 Add storybook linter 2025-05-01 22:27:46 -06:00
Lance
b7581e5b25 Call storybook from parent 2025-05-01 22:27:46 -06:00
Lance
4879b95245 General cleanup 2025-05-01 22:27:46 -06:00
Lance
4407dec4fc Remove unnecessary react app stuff 2025-05-01 22:27:46 -06:00
Lance
b73c3f58b2 Storybookk page reloads when the package in the parent changes 2025-05-01 22:27:46 -06:00
Lance
cee7ca5a43 Add examples 2025-05-01 22:27:46 -06:00
Lance
cf1d7c4c1c Remove old storybook and auto docs 2025-05-01 22:27:46 -06:00
philter
c414f143fd chore: release 4.18.9 2025-05-01 22:27:46 -06:00
Phil Chung
1f8afe4635 chore: bump rive web to 2.27.1 2025-05-01 22:27:46 -06:00
bodymovin
469e9073ce chore: release 4.18.8 2025-05-01 22:27:46 -06:00
Hernan Torrisi
43290d1cfd rive canvas 2.27.0 2025-05-01 22:27:46 -06:00
Adam
37763e11c7 fix: use default view model if none provide in useViewModelInstance and useViewModel 2025-05-01 15:58:37 -07:00
Adam
384b62c1b7 fix: unify effects in useViewModelInstance 2025-04-29 17:18:34 -07:00
Adam
d9e61373b3 fix: change useViewModel property hook parameters to match conventions 2025-04-29 17:07:17 -07:00
Adam
66f1ae021c chore: simplify useViewModel 2025-04-29 16:30:09 -07:00
Adam
1fc4fa44e2 fix: avoid rebuilding operations unless necessary 2025-04-28 18:04:19 -07:00
Adam
3866cb9e06 fix: hot reload crash 2025-04-24 15:33:07 -07:00
Adam
bef03fc403 chore: update UseViewModelParameters documentation 2025-04-15 16:46:54 -07:00
Adam
c4da27c7b6 fix: remove viewmodel hooks from initial release 2025-04-15 15:18:38 -07:00
Adam
c2ec32350d chore: update color setter methods to be more explicit 2025-04-15 12:07:27 -07:00
Adam
ead1d8e0e3 fix: lint issue 2025-04-14 14:48:15 -07:00
Adam
26cb0b5dec feat: add instance property hooks 2025-04-13 12:38:27 -07:00
Hernan Torrisi
0e40840e6f hook with generic 2025-04-11 10:19:47 -07:00
Hernan Torrisi
480037c399 inital work for data binding hooks 2025-04-11 10:19:47 -07:00
11 changed files with 555 additions and 550 deletions

30
.github/workflows/storybook.yml vendored Normal file
View File

@@ -0,0 +1,30 @@
name: Deploy Storybook
on:
# 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
if: github.event.pull_request.merged == true
steps:
- name: Checkout 🛎️
uses: actions/checkout@v2
with:
persist-credentials: false
- name: Install and Build 🔧
run: | # Install npm packages and build the Storybook files
npm install
npm run build-storybook
- name: Deploy 🚀
uses: JamesIves/github-pages-deploy-action@3.6.2
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BRANCH: main # The branch the action should deploy to.
FOLDER: docs-build # The folder that the build-storybook script generates files.
CLEAN: true # Automatically remove deleted files from the deploy branch
TARGET_FOLDER: docs # The folder that we serve our Storybook files from

View File

@@ -4,43 +4,8 @@ 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).
#### [v4.21.0](https://github.com/rive-app/rive-react/compare/v4.20.2...v4.21.0)
- chore: bump rive wasm 2.28.0 [`a62e89d`](https://github.com/rive-app/rive-react/commit/a62e89de9436360e439896a1aa11623e3574897e)
#### [v4.20.2](https://github.com/rive-app/rive-react/compare/v4.20.1...v4.20.2)
> 23 May 2025
- chore: release 4.20.2 [`31255f9`](https://github.com/rive-app/rive-react/commit/31255f974635278aea211dcf827e3a0cd0cc138e)
- chore: bump rive wasm 2.27.5 [`3e76853`](https://github.com/rive-app/rive-react/commit/3e768533df747da69acd392332495303077fa8c6)
#### [v4.20.1](https://github.com/rive-app/rive-react/compare/v4.20.0...v4.20.1)
> 14 May 2025
- chore: release 4.20.1 [`c790e66`](https://github.com/rive-app/rive-react/commit/c790e6672389ea68ee222140a49bcb7e4a7d3ca3)
- rive canvas 2.27.3 [`ab89793`](https://github.com/rive-app/rive-react/commit/ab89793032bcadf58f680610cea2e15fcd76d0b2)
#### [v4.20.0](https://github.com/rive-app/rive-react/compare/v4.19.1...v4.20.0)
> 12 May 2025
- feat: add db test [`46e1987`](https://github.com/rive-app/rive-react/commit/46e19874a2ec5893b5d3365f61db871400327087)
- fix: hot reload crash [`6d76e9f`](https://github.com/rive-app/rive-react/commit/6d76e9f85d949ec1e0e4d29458676efbe1c24d1d)
- inital work for data binding hooks [`452eb89`](https://github.com/rive-app/rive-react/commit/452eb89e72ffb73f837917fd969a51ed238a6d05)
#### [v4.19.1](https://github.com/rive-app/rive-react/compare/v4.19.0...v4.19.1)
> 8 May 2025
- chore: release 4.19.1 [`d303e8c`](https://github.com/rive-app/rive-react/commit/d303e8c96f70fa8886d96aba35afd911f0fcef50)
- chore: rive-wasm -> 2.27.2 [`479d534`](https://github.com/rive-app/rive-react/commit/479d5340e87f5335a2525b547e690be60ebafc00)
#### [v4.19.0](https://github.com/rive-app/rive-react/compare/v4.18.9...v4.19.0)
> 29 April 2025
- Add examples [`5354d1f`](https://github.com/rive-app/rive-react/commit/5354d1f69bfe91dc67c39cee80a6ea00c4c70cb1)
- Storybookk page reloads when the package in the parent changes [`7277ed2`](https://github.com/rive-app/rive-react/commit/7277ed2f0d877150637a69f2ff9122db1b151686)
- Upgrade React and React DOM [`a9a98fe`](https://github.com/rive-app/rive-react/commit/a9a98fece2caf727e941ce645be2f031efaf8a89)

View File

@@ -1,4 +1,5 @@
![Build Status](https://github.com/rive-app/rive-react/actions/workflows/tests.yml/badge.svg)
[![Storybook](https://cdn.jsdelivr.net/gh/storybookjs/brand@main/badge/badge-storybook.svg)](https://rive-app.github.io/rive-react)
![Discord badge](https://img.shields.io/discord/532365473602600965)
![Twitter handle](https://img.shields.io/twitter/follow/rive_app.svg?style=social&label=Follow)
@@ -54,6 +55,8 @@ This library supports React versions `^16.8.0` through `^18.0.0`.
Check out our Storybook instance that shows how to use the library in small examples, along with code snippets! This includes examples using the basic component, as well as the convenient hooks exported to take advantage of state machines.
- [Example page](https://rive-app.github.io/rive-react)
- [Login screen w/ input tracking](https://rive-app.github.io/rive-use-cases/?path=/story/example-loginformcomponent--primary)
- [Mouse tracking](https://codesandbox.io/s/rive-mouse-track-test-t0y965?file=/src/App.js)
- [Accessibility concerns](https://rive.app/blog/accesible-web-animations-aria-live-regions)

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "@rive-app/react-canvas-lite",
"version": "4.21.0",
"version": "4.19.0",
"description": "React wrapper around the @rive-app/canvas-lite library",
"main": "dist/index.js",
"typings": "dist/types/index.d.ts",
@@ -18,7 +18,7 @@
},
"homepage": "https://github.com/rive-app/rive-react#readme",
"dependencies": {
"@rive-app/canvas-lite": "2.28.0"
"@rive-app/canvas-lite": "2.27.1"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0"

View File

@@ -1,6 +1,6 @@
{
"name": "@rive-app/react-canvas",
"version": "4.21.0",
"version": "4.19.0",
"description": "React wrapper around the @rive-app/canvas library",
"main": "dist/index.js",
"typings": "dist/types/index.d.ts",
@@ -18,7 +18,7 @@
},
"homepage": "https://github.com/rive-app/rive-react#readme",
"dependencies": {
"@rive-app/canvas": "2.28.0"
"@rive-app/canvas": "2.27.1"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0"

View File

@@ -1,6 +1,6 @@
{
"name": "@rive-app/react-webgl",
"version": "4.21.0",
"version": "4.19.0",
"description": "React wrapper around the @rive-app/webgl library",
"main": "dist/index.js",
"typings": "dist/types/index.d.ts",
@@ -18,7 +18,7 @@
},
"homepage": "https://github.com/rive-app/rive-react#readme",
"dependencies": {
"@rive-app/webgl": "2.28.0"
"@rive-app/webgl": "2.27.1"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0"

View File

@@ -1,6 +1,6 @@
{
"name": "@rive-app/react-webgl2",
"version": "4.21.0",
"version": "4.19.0",
"description": "React wrapper around the @rive-app/webgl2 library",
"main": "dist/index.js",
"typings": "dist/types/index.d.ts",
@@ -18,7 +18,7 @@
},
"homepage": "https://github.com/rive-app/rive-react#readme",
"dependencies": {
"@rive-app/webgl2": "2.28.0"
"@rive-app/webgl2": "2.27.1"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0"

View File

@@ -1,6 +1,6 @@
{
"name": "rive-react",
"version": "4.21.0",
"version": "4.19.0",
"description": "React wrapper around the rive-js library",
"main": "dist/index.js",
"typings": "dist/types/index.d.ts",
@@ -35,10 +35,10 @@
},
"homepage": "https://github.com/rive-app/rive-react#readme",
"dependencies": {
"@rive-app/canvas": "2.28.0",
"@rive-app/canvas-lite": "2.28.0",
"@rive-app/webgl": "2.28.0",
"@rive-app/webgl2": "2.28.0"
"@rive-app/canvas": "2.27.1",
"@rive-app/canvas-lite": "2.27.1",
"@rive-app/webgl": "2.27.1",
"@rive-app/webgl2": "2.27.1"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0"

View File

@@ -1,7 +1,26 @@
import { useState, useEffect } from 'react';
import { useState, useEffect, useRef } from 'react';
import { Rive, ViewModel, EventType } from '@rive-app/canvas';
import { UseViewModelParameters } from '../types';
function areParamsEqual(
prev?: UseViewModelParameters,
next?: UseViewModelParameters
): boolean {
if (prev === next) return true;
if (!prev || !next) return prev === next;
if ('name' in prev && 'name' in next) {
return prev.name === next.name;
}
if ('useDefault' in prev && 'useDefault' in next) {
return prev.useDefault === next.useDefault;
}
return false;
}
/**
* Hook for fetching a ViewModel from a Rive instance.
*
@@ -16,37 +35,57 @@ export default function useViewModel(
params?: UseViewModelParameters
): ViewModel | null {
const { name, useDefault = false } = params ?? {};
const riveRef = useRef<Rive | null>(null);
const paramsRef = useRef<UseViewModelParameters | undefined>(params);
const [viewModel, setViewModel] = useState<ViewModel | null>(null);
const shouldUpdate = useRef(true);
useEffect(() => {
const isRiveChanged = riveRef.current !== rive;
const areParamsChanged = !areParamsEqual(paramsRef.current, params);
shouldUpdate.current = isRiveChanged || areParamsChanged;
riveRef.current = rive;
paramsRef.current = params;
if (!shouldUpdate.current && viewModel) {
return;
}
function fetchViewModel() {
if (!rive) {
const currentRive = riveRef.current;
const currentParams = paramsRef.current;
if (!currentRive) {
setViewModel(null);
return;
}
let model: ViewModel | null = null;
if (name != null) {
model = rive.viewModelByName?.(name) || null;
} else if (useDefault) {
model = rive.defaultViewModel() || null;
if (currentParams?.name != null) {
model = currentRive.viewModelByName?.(currentParams.name) || null;
} else if (currentParams?.useDefault) {
model = currentRive.defaultViewModel() || null;
} else {
model = rive.defaultViewModel() || null;
model = currentRive.defaultViewModel() || null;
}
setViewModel(model);
shouldUpdate.current = false;
}
fetchViewModel();
if (rive) {
rive.on(EventType.Load, fetchViewModel);
const currentRive = riveRef.current;
if (currentRive) {
currentRive.on(EventType.Load, fetchViewModel);
}
return () => {
if (rive) {
rive.off(EventType.Load, fetchViewModel);
if (currentRive) {
currentRive.off(EventType.Load, fetchViewModel);
}
};
}, [rive, name, useDefault]);

View File

@@ -1,7 +1,30 @@
import { useState, useEffect } from 'react';
import { useState, useEffect, useRef } from 'react';
import { ViewModel, ViewModelInstance } from '@rive-app/canvas';
import { UseViewModelInstanceParameters } from '../types';
function areParamsEqual(
prev?: UseViewModelInstanceParameters,
next?: UseViewModelInstanceParameters
): boolean {
if (prev === next) return true;
if (!prev || !next) return prev === next;
if ('name' in prev && 'name' in next) {
return prev.name === next.name;
}
if ('useDefault' in prev && 'useDefault' in next) {
return prev.useDefault === next.useDefault;
}
if ('useNew' in prev && 'useNew' in next) {
return prev.useNew === next.useNew;
}
return false;
}
/**
* Hook for fetching a ViewModelInstance from a ViewModel.
*
@@ -20,26 +43,50 @@ export default function useViewModelInstance(
const { name, useDefault = false, useNew = false, rive } = params ?? {};
const [instance, setInstance] = useState<ViewModelInstance | null>(null);
const viewModelRef = useRef<ViewModel | null>(viewModel);
const paramsRef = useRef<UseViewModelInstanceParameters | undefined>(params);
const instanceRef = useRef<ViewModelInstance | null>(null);
const shouldUpdate = useRef(true);
useEffect(() => {
if (!viewModel) {
const isViewModelChanged = viewModelRef.current !== viewModel;
const areParamsChanged = !areParamsEqual(paramsRef.current, params);
shouldUpdate.current = isViewModelChanged || areParamsChanged;
viewModelRef.current = viewModel;
paramsRef.current = params;
if (!shouldUpdate.current && instanceRef.current) {
return;
}
const currentViewModel = viewModelRef.current;
const currentParams = paramsRef.current;
if (!currentViewModel) {
setInstance(null);
instanceRef.current = null;
return;
}
let result: ViewModelInstance | null = null;
if (name != null) {
result = viewModel.instanceByName(name) || null;
} else if (useDefault) {
result = viewModel.defaultInstance?.() || null;
} else if (useNew) {
result = viewModel.instance?.() || null;
if (currentParams?.name != null) {
result = currentViewModel.instanceByName(currentParams.name) || null;
} else if (currentParams?.useDefault) {
result = currentViewModel.defaultInstance?.() || null;
} else if (currentParams?.useNew) {
result = currentViewModel.instance?.() || null;
} else {
result = viewModel.defaultInstance?.() || null;
result = currentViewModel.defaultInstance?.() || null;
}
instanceRef.current = result;
setInstance(result);
shouldUpdate.current = false;
// Bind instance to Rive if needed
if (rive && result && rive.viewModelInstance !== result) {
rive.bindViewModelInstance(result);
}