Compare commits

...

67 Commits

Author SHA1 Message Date
zplata
d72e2241e6 chore: release 4.27.1 2026-03-10 18:59:34 +00:00
Zach Plata
881983229f chore: bump js runtime to 2.35.2 2026-03-10 13:08:31 -05:00
Lance Snider
1abd420408 Update supported React versions to include 19.0.0 2026-03-09 11:20:18 -07:00
bodymovin
e7217e5943 chore: release 4.27.0 2026-02-13 17:39:01 +00:00
Hernan Torrisi
e4738c014d rive canvas 2.35.0 2026-02-13 09:31:50 -08:00
bodymovin
e1055c2907 chore: release 4.26.2 2026-01-27 15:02:21 +00:00
Hernan Torrisi
3c1459beb3 bump rive to 2.34.2 2026-01-27 06:55:07 -08:00
HayesGordon
3c59c7a667 chore: release 4.26.1 2026-01-15 07:57:25 +00:00
Hernan Torrisi
2dceda58bf update rive_canvas 2026-01-15 08:55:15 +01:00
avivian
1af00a38c7 chore: release 4.26.0 2026-01-13 12:56:35 +00:00
Arthur Vivian
6ab0496025 chore: bump to 2.34.0 2026-01-13 12:51:04 +00:00
bodymovin
37ced47323 chore: release 4.25.3 2026-01-08 04:11:16 +00:00
Hernan Torrisi
79f1a06df0 update rive to 2.33.3 2026-01-07 20:08:29 -08:00
philter
f0d4c3e6d2 chore: release 4.25.2 2026-01-06 23:23:20 +00:00
Phil Chung
0d3300eca4 Bump rive wasm to 2.33.2 2026-01-06 16:19:09 -07:00
philter
7f6ab5ad10 chore: release 4.25.1 2025-12-20 00:04:31 +00:00
Phil Chung
5df93323ed Bump rive wasm to 2.33.1 2025-12-19 16:59:45 -07:00
HayesGordon
e6bfec7c51 chore: release 4.25.0 2025-12-17 22:01:34 +00:00
CI
770858fb00 chore: auto publish false for release-it 2025-12-17 22:59:26 +01:00
CI
5145a6edb3 chore: ensure latest npm 2025-12-17 22:14:13 +01:00
CI
f74cfbc3d0 chore: bump rive web 2.33.0 2025-12-17 21:34:41 +01:00
CI
925de2fc94 chore: update npm publish workflow with OIDC support 2025-12-17 20:10:39 +01:00
Hernan Torrisi
c7d1d92b9e bump rive wasm to 2.32.1 2025-11-10 19:10:59 -08:00
HayesGordon
19f20268ae chore: release 4.24.0 2025-11-10 13:44:07 +00:00
CI
e6e43564b1 chore: bump rive web 2.32.0 2025-11-10 14:42:06 +01:00
bodymovin
efeee472e6 chore: release 4.23.4 2025-09-23 20:40:08 +00:00
Hernan Torrisi
42d502f452 bump rive to 2.31.6 2025-09-23 09:15:53 -07:00
bodymovin
bd483e0ab7 chore: release 4.23.3 2025-09-04 22:53:16 +00:00
Hernan Torrisi
7c361e4c53 chore: bump rive wasm to 2.31.5 2025-09-04 15:49:34 -07:00
HayesGordon
d80df170aa chore: release 4.23.2 2025-09-04 14:29:04 +00:00
CI
a3118d5984 chore: bump rive wasm to 2.31.4 2025-09-04 16:27:08 +02:00
CI
f732a3b044 docs: update README 2025-09-04 16:27:08 +02:00
bodymovin
57ebc37e3f chore: release 4.23.1 2025-08-13 17:19:55 +00:00
Hernan Torrisi
69a356894d bump rive to 2.31.2 2025-08-13 10:09:58 -07:00
Hernan Torrisi
23d9d7f48b add dependency 2025-08-12 12:27:31 -07:00
Hernan Torrisi
788b7ef68e bump rive canvas to 2.31.1 2025-08-12 12:27:31 -07:00
HayesGordon
69658c204a chore: release 4.23.0 2025-08-08 12:09:50 +00:00
CI
7249fa36e7 chore: bump rive wasm 2.31.0 2025-08-08 12:42:01 +02:00
bodymovin
52dd934e43 chore: release 4.22.1 2025-07-18 14:29:38 +00:00
Hernan Torrisi
c151ee37b5 bump rive to 2.30.4 2025-07-18 07:18:56 -07:00
damzobridge
c660a675c2 chore: release 4.22.0 2025-07-15 20:57:21 +00:00
Adam
74e1d5a5f2 feat: add tests for artboard binding 2025-07-15 12:52:34 -07:00
Adam
963ecc43b8 feat: add useViewModelInstanceArtboard hook 2025-07-15 12:52:34 -07:00
bodymovin
85807f2166 chore: release 4.21.6 2025-07-15 04:51:16 +00:00
Hernan Torrisi
9a33504d3a rive_canvas_2.30.3 2025-07-14 21:48:19 -07:00
HayesGordon
1a4d7e7168 chore: release 4.21.5 2025-07-14 16:12:59 +00:00
CI
b3d0fd4339 chore: bump rive wasm 2.30.2 2025-07-14 17:09:31 +01:00
Adam
c4239ab6b2 fix: lint error with revision 2025-07-07 14:23:22 -07:00
Adam
22f8d5a945 feat: add tests for list property 2025-07-07 14:23:22 -07:00
Adam
721ed786dc feat: add useViewModelInstanceList hook 2025-07-07 14:23:22 -07:00
Adam
eef56fb641 feat: add useViewModelInstanceImage hook 2025-07-07 14:23:22 -07:00
bodymovin
4bc0f496f8 chore: release 4.21.4 2025-06-25 13:39:06 +00:00
Maxwell Talbot
10bb4c69ea fix: update how we use release it with github tokens 2025-06-25 06:26:13 -07:00
Hernan Torrisi
c5b6826996 bump rive to 2.30.1 2025-06-25 06:23:15 -07:00
Adam
ec4875933c refactor: change onLoad to onRiveReady 2025-06-23 11:57:58 -07:00
Adam
d808a8bdea feat: add onLoad callback to useRive 2025-06-23 11:57:58 -07:00
Hernan Torrisi
7b174f7f51 cleanup rive on unmount 2025-06-18 16:25:59 -07:00
bodymovin
eecd0d3c5b chore: release 4.21.3 2025-06-08 17:57:17 +00:00
Hernan Torrisi
6c00364e60 rive react 2.29.3 2025-06-08 10:22:55 -07:00
HayesGordon
d310f1c96d chore: release 4.21.2 2025-06-05 20:43:20 +00:00
CI
68e8fbe46d chore: bump Rive wasm 2.29.2 2025-06-05 22:40:54 +02:00
bodymovin
8ff9a844fe chore: release 4.21.1 2025-05-28 16:15:41 +00:00
Hernan Torrisi
a565795452 bump rive to 2.29.0 2025-05-28 08:10:54 -07:00
HayesGordon
b26280ae12 chore: release 4.21.0 2025-05-23 16:44:06 +00:00
CI
a62e89de94 chore: bump rive wasm 2.28.0 2025-05-23 18:20:22 +02:00
HayesGordon
31255f9746 chore: release 4.20.2 2025-05-23 15:24:28 +00:00
CI
3e768533df chore: bump rive wasm 2.27.5 2025-05-22 14:42:31 +02:00
20 changed files with 992 additions and 38 deletions

View File

@@ -10,23 +10,29 @@ on:
description: 'Minor'
type: boolean
default: false
permissions:
id-token: write # Required for OIDC
contents: read
jobs:
publish_job:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.PAT_GITHUB }}
- name: Setup Git config
run: |
git config --local user.email 'hello@rive.app'
git config --local user.name ${{ github.actor }}
- name: Authenticate with registry
run: npm config set //registry.npmjs.org/:_authToken ${{ secrets.NPM_TOKEN }}
- uses: actions/setup-node@v2
- uses: actions/setup-node@v4
with:
node-version: '16.x'
node-version: '24'
registry-url: 'https://registry.npmjs.org'
- name: Upgrade npm for OIDC support
run: npm install -g npm@latest
- name: Install Modules
run: npm install
- name: Run type check
@@ -38,21 +44,9 @@ jobs:
- if: ${{ inputs.major == true }}
name: Major Release - Bump version number, update changelog, push and tag
run: npm run release:major
env:
GITHUB_TOKEN: ${{ secrets.REPO_TOKEN }}
PAT_GITHUB: ${{ secrets.PAT_GITHUB }}
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- if: ${{inputs.major == false && inputs.minor == true}}
name: Minor release - Bump version number, update changelog, push and tag
run: npm run release:minor
env:
GITHUB_TOKEN: ${{ secrets.REPO_TOKEN }}
PAT_GITHUB: ${{ secrets.PAT_GITHUB }}
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- if: ${{inputs.major == false && inputs.minor == false}}
name: Patch release - Bump version number, update changelog, push and tag
run: npm run release:patch
env:
GITHUB_TOKEN: ${{ secrets.REPO_TOKEN }}
PAT_GITHUB: ${{ secrets.PAT_GITHUB }}
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

View File

@@ -7,7 +7,7 @@
"changelog": "npx auto-changelog --stdout --commit-limit false --unreleased --template https://raw.githubusercontent.com/release-it/release-it/master/templates/changelog-compact.hbs"
},
"npm": {
"publish": true
"publish": false
},
"github": {
"release": true,

View File

@@ -4,8 +4,190 @@ 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.27.1](https://github.com/rive-app/rive-react/compare/v4.27.0...v4.27.1)
- chore: bump js runtime to 2.35.2 [`8819832`](https://github.com/rive-app/rive-react/commit/881983229f699de7da516a05cda415158c1517d2)
- Update supported React versions to include 19.0.0 [`1abd420`](https://github.com/rive-app/rive-react/commit/1abd420408b4c06ae172d1f060c2461e7226a3d3)
#### [v4.27.0](https://github.com/rive-app/rive-react/compare/v4.26.2...v4.27.0)
> 13 February 2026
- chore: release 4.27.0 [`e7217e5`](https://github.com/rive-app/rive-react/commit/e7217e5943afa7ab5405d0301465df20ab135c7a)
- rive canvas 2.35.0 [`e4738c0`](https://github.com/rive-app/rive-react/commit/e4738c014de2fa707c3950d2b3b7011bde4624e0)
#### [v4.26.2](https://github.com/rive-app/rive-react/compare/v4.26.1...v4.26.2)
> 27 January 2026
- chore: release 4.26.2 [`e1055c2`](https://github.com/rive-app/rive-react/commit/e1055c2907466a5857ef8880916db30d896f4275)
- bump rive to 2.34.2 [`3c1459b`](https://github.com/rive-app/rive-react/commit/3c1459beb31f68d8a77d0ead405f0c4726cbeb43)
#### [v4.26.1](https://github.com/rive-app/rive-react/compare/v4.26.0...v4.26.1)
> 15 January 2026
- chore: release 4.26.1 [`3c59c7a`](https://github.com/rive-app/rive-react/commit/3c59c7a66736bf1955f38a98e351687df7bd1494)
- update rive_canvas [`2dceda5`](https://github.com/rive-app/rive-react/commit/2dceda58bfc57830fb181796df321789727973cc)
#### [v4.26.0](https://github.com/rive-app/rive-react/compare/v4.25.3...v4.26.0)
> 13 January 2026
- chore: release 4.26.0 [`1af00a3`](https://github.com/rive-app/rive-react/commit/1af00a38c7973141bccca08845e396c59a88c0ba)
- chore: bump to 2.34.0 [`6ab0496`](https://github.com/rive-app/rive-react/commit/6ab0496025739f2d6c78ed84ada0488d6dd58ab2)
#### [v4.25.3](https://github.com/rive-app/rive-react/compare/v4.25.2...v4.25.3)
> 8 January 2026
- chore: release 4.25.3 [`37ced47`](https://github.com/rive-app/rive-react/commit/37ced4732343d6c6076bd018b6e179615df32003)
- update rive to 2.33.3 [`79f1a06`](https://github.com/rive-app/rive-react/commit/79f1a06df09ec95f9bacdc260e7fcabcfb13975e)
#### [v4.25.2](https://github.com/rive-app/rive-react/compare/v4.25.1...v4.25.2)
> 6 January 2026
- chore: release 4.25.2 [`f0d4c3e`](https://github.com/rive-app/rive-react/commit/f0d4c3e6d250527b4cbbda2d0fdbe05058cd1772)
- Bump rive wasm to 2.33.2 [`0d3300e`](https://github.com/rive-app/rive-react/commit/0d3300eca435ca3862cd63ce795dd5f5b561a1a8)
#### [v4.25.1](https://github.com/rive-app/rive-react/compare/v4.25.0...v4.25.1)
> 20 December 2025
- chore: release 4.25.1 [`7f6ab5a`](https://github.com/rive-app/rive-react/commit/7f6ab5ad10a996503e590f362c17cd96ee69ac5d)
- Bump rive wasm to 2.33.1 [`5df9332`](https://github.com/rive-app/rive-react/commit/5df93323eda2e08b64d375e39e57a22f473aab1e)
#### [v4.25.0](https://github.com/rive-app/rive-react/compare/v4.24.0...v4.25.0)
> 17 December 2025
- chore: release 4.25.0 [`e6bfec7`](https://github.com/rive-app/rive-react/commit/e6bfec7c517c5fe001c40476de1bd0d48dd77fd7)
- chore: update npm publish workflow with OIDC support [`925de2f`](https://github.com/rive-app/rive-react/commit/925de2fc94172a306f194f45b628f711fff14d50)
- chore: bump rive web 2.33.0 [`f74cfbc`](https://github.com/rive-app/rive-react/commit/f74cfbc3d04383aeb9707a378d4056be400567c3)
#### [v4.24.0](https://github.com/rive-app/rive-react/compare/v4.23.4...v4.24.0)
> 10 November 2025
- chore: release 4.24.0 [`19f2026`](https://github.com/rive-app/rive-react/commit/19f20268ae1c39d873f9d64cf10a499a4f792970)
- chore: bump rive web 2.32.0 [`e6e4356`](https://github.com/rive-app/rive-react/commit/e6e43564b1af8da608c146a2a76795e29063daf8)
#### [v4.23.4](https://github.com/rive-app/rive-react/compare/v4.23.3...v4.23.4)
> 23 September 2025
- chore: release 4.23.4 [`efeee47`](https://github.com/rive-app/rive-react/commit/efeee472e60946d293f6287e11350fdaf4afe03b)
- bump rive to 2.31.6 [`42d502f`](https://github.com/rive-app/rive-react/commit/42d502f452b6a76cafc332c2cd84bd97e315be77)
#### [v4.23.3](https://github.com/rive-app/rive-react/compare/v4.23.2...v4.23.3)
> 4 September 2025
- chore: release 4.23.3 [`bd483e0`](https://github.com/rive-app/rive-react/commit/bd483e0ab72a99a9c55c7e9fb80bd95827ca54cb)
- chore: bump rive wasm to 2.31.5 [`7c361e4`](https://github.com/rive-app/rive-react/commit/7c361e4c538cf813fdc94f572fac1e4a82258ae8)
#### [v4.23.2](https://github.com/rive-app/rive-react/compare/v4.23.1...v4.23.2)
> 4 September 2025
- chore: release 4.23.2 [`d80df17`](https://github.com/rive-app/rive-react/commit/d80df170aa0d1c575101c8cd1bb76968173c439f)
- docs: update README [`f732a3b`](https://github.com/rive-app/rive-react/commit/f732a3b044e2a56ed0ea178a43d68612423c0548)
- chore: bump rive wasm to 2.31.4 [`a3118d5`](https://github.com/rive-app/rive-react/commit/a3118d59841c45467b46170e3eed7ba3359d4fea)
#### [v4.23.1](https://github.com/rive-app/rive-react/compare/v4.23.0...v4.23.1)
> 13 August 2025
- chore: release 4.23.1 [`57ebc37`](https://github.com/rive-app/rive-react/commit/57ebc37e3f99eb7fd9673e34441f395c990e312b)
- bump rive to 2.31.2 [`69a3568`](https://github.com/rive-app/rive-react/commit/69a356894d3acf44f4d24b708e9f8d8dda5b3046)
- bump rive canvas to 2.31.1 [`788b7ef`](https://github.com/rive-app/rive-react/commit/788b7ef68e9001460175b596f74d7f54616a69d4)
#### [v4.23.0](https://github.com/rive-app/rive-react/compare/v4.22.1...v4.23.0)
> 8 August 2025
- chore: release 4.23.0 [`69658c2`](https://github.com/rive-app/rive-react/commit/69658c204ad1f70a408bab098136c2b23083fd16)
- chore: bump rive wasm 2.31.0 [`7249fa3`](https://github.com/rive-app/rive-react/commit/7249fa36e7b6a2184ec60fb1e34a68f28b4eeb6d)
#### [v4.22.1](https://github.com/rive-app/rive-react/compare/v4.22.0...v4.22.1)
> 18 July 2025
- chore: release 4.22.1 [`52dd934`](https://github.com/rive-app/rive-react/commit/52dd934e439507d079bf4f5009372857dfbb97a6)
- bump rive to 2.30.4 [`c151ee3`](https://github.com/rive-app/rive-react/commit/c151ee37b5482cb7eee258c84f6c52182dbe9db5)
#### [v4.22.0](https://github.com/rive-app/rive-react/compare/v4.21.6...v4.22.0)
> 15 July 2025
- feat: add tests for artboard binding [`74e1d5a`](https://github.com/rive-app/rive-react/commit/74e1d5a5f29f14f46be3af3d052bb51c3d833799)
- feat: add useViewModelInstanceArtboard hook [`963ecc4`](https://github.com/rive-app/rive-react/commit/963ecc43b80e6465d159621d014b70b8cbfee9d4)
- chore: release 4.22.0 [`c660a67`](https://github.com/rive-app/rive-react/commit/c660a675c246af9fca50795ff88b7935c2d2a101)
#### [v4.21.6](https://github.com/rive-app/rive-react/compare/v4.21.5...v4.21.6)
> 15 July 2025
- chore: release 4.21.6 [`85807f2`](https://github.com/rive-app/rive-react/commit/85807f2166fcfba01e4556ac346b769d6fa08341)
- rive_canvas_2.30.3 [`9a33504`](https://github.com/rive-app/rive-react/commit/9a33504d3a315ce2f3dff753192b0ae491a56a04)
#### [v4.21.5](https://github.com/rive-app/rive-react/compare/v4.21.4...v4.21.5)
> 14 July 2025
- feat: add tests for list property [`22f8d5a`](https://github.com/rive-app/rive-react/commit/22f8d5a945c74974b7dabcfe16aaa019f6141326)
- feat: add useViewModelInstanceImage hook [`eef56fb`](https://github.com/rive-app/rive-react/commit/eef56fb641839b55806296873186aa53b3e1d068)
- feat: add useViewModelInstanceList hook [`721ed78`](https://github.com/rive-app/rive-react/commit/721ed786dc43a526eafb54108bfb54f353d7430d)
#### [v4.21.4](https://github.com/rive-app/rive-react/compare/v4.21.3...v4.21.4)
> 25 June 2025
- chore: release 4.21.4 [`4bc0f49`](https://github.com/rive-app/rive-react/commit/4bc0f496f87a54ffda673acb7b9be4b7a8b311c0)
- cleanup rive on unmount [`7b174f7`](https://github.com/rive-app/rive-react/commit/7b174f7f5106b1b863969bd7318a8a6cb1a12b67)
- refactor: change onLoad to onRiveReady [`ec48759`](https://github.com/rive-app/rive-react/commit/ec4875933cad45a3d338290951d55ac9c72df9d0)
#### [v4.21.3](https://github.com/rive-app/rive-react/compare/v4.21.2...v4.21.3)
> 8 June 2025
- chore: release 4.21.3 [`eecd0d3`](https://github.com/rive-app/rive-react/commit/eecd0d3c5be011fe9865e45b05435fbd45e7395d)
- rive react 2.29.3 [`6c00364`](https://github.com/rive-app/rive-react/commit/6c00364e60e91a7a6556e763ebf9ebee4793b336)
#### [v4.21.2](https://github.com/rive-app/rive-react/compare/v4.21.1...v4.21.2)
> 5 June 2025
- chore: release 4.21.2 [`d310f1c`](https://github.com/rive-app/rive-react/commit/d310f1c96dbff6cbb7397d4bea2687c8d3f271f4)
- chore: bump Rive wasm 2.29.2 [`68e8fbe`](https://github.com/rive-app/rive-react/commit/68e8fbe46d4f1824a6228ce2ea0a02735dced5ba)
#### [v4.21.1](https://github.com/rive-app/rive-react/compare/v4.21.0...v4.21.1)
> 28 May 2025
- chore: release 4.21.1 [`8ff9a84`](https://github.com/rive-app/rive-react/commit/8ff9a844fe5b02a2eb1964cf01814479f6c72248)
- bump rive to 2.29.0 [`a565795`](https://github.com/rive-app/rive-react/commit/a565795452444205e88083cba272bc8ca6c9968f)
#### [v4.21.0](https://github.com/rive-app/rive-react/compare/v4.20.2...v4.21.0)
> 23 May 2025
- chore: release 4.21.0 [`b26280a`](https://github.com/rive-app/rive-react/commit/b26280ae125173b52dd9a6147833f45631c2252f)
- 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)

View File

@@ -6,9 +6,16 @@
![Rive hero image](https://cdn.rive.app/rive_logo_dark_bg.png)
A React runtime library for [Rive](https://rive.app).
[Rive](https://rive.app) combines an interactive design tool, a new stateful graphics format, a lightweight multi-platform runtime, and a blazing-fast vector renderer. This end-to-end pipeline guarantees that what you build in the Rive Editor is exactly what ships in your apps, games, and websites.
This library is a wrapper around the [JS/Wasm runtime](https://github.com/rive-app/rive-wasm), giving full control over the js runtime while providing components and hooks for React applications.
This library is a wrapper around the [JS/Wasm runtime](https://github.com/rive-app/rive-wasm), giving full control over the JS/Wasm runtime while providing components and hooks for React applications.
For more information, check out the following resources:
- [Homepage](https://rive.app/)
- [General Docs](https://rive.app/docs/)
- [React Docs](https://rive.app/docs/runtimes/react/react)
- [Rive Community / Support](https://community.rive.app/c/support/)
## Table of contents
@@ -48,7 +55,7 @@ For more information, see the Runtime sections of the Rive help documentation:
## Supported versions
This library supports React versions `^16.8.0` through `^18.0.0`.
This library supports React versions `^16.8.0` through `^19.0.0`.
## Examples

View File

Binary file not shown.

View File

Binary file not shown.

View File

Binary file not shown.

View File

@@ -2,7 +2,7 @@ import React, { useEffect } from 'react';
import type { Meta, StoryObj } from '@storybook/react';
import { within, expect, waitFor, userEvent } from '@storybook/test';
import { StringPropertyTest, NumberPropertyTest, BooleanPropertyTest, ColorPropertyTest, EnumPropertyTest, NestedViewModelTest, TriggerPropertyTest, PersonForm, PersonInstances } from './DataBindingTests';
import { StringPropertyTest, NumberPropertyTest, BooleanPropertyTest, ColorPropertyTest, EnumPropertyTest, NestedViewModelTest, TriggerPropertyTest, PersonForm, PersonInstances, ImagePropertyTest, TodoListTest, ArtboardPropertyTest } from './DataBindingTests';
const meta: Meta = {
title: 'Tests/DataBinding',
@@ -345,4 +345,183 @@ export const PersonFormStory: StoryObj = {
};
export const ImagePropertyStory: StoryObj = {
name: 'Image Property',
render: () => <ImagePropertyTest src="image_db_test.riv" />,
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
// Wait for the Rive file to load
await waitFor(() => {
expect(canvas.getByTestId('load-random-image')).toBeTruthy();
expect(canvas.getByTestId('clear-image')).toBeTruthy();
}, { timeout: 3000 });
const loadImageButton = canvas.getByTestId('load-random-image');
const clearImageButton = canvas.getByTestId('clear-image');
expect(canvas.queryByTestId('current-image-url')).toBeNull();
// Load a random image
await userEvent.click(loadImageButton);
// Wait for the image to load and URL to appear
await waitFor(() => {
expect(canvas.getByTestId('current-image-url')).toBeTruthy();
}, { timeout: 5000 });
// Verify the image URL is displayed
const imageUrlElement = canvas.getByTestId('current-image-url');
expect(imageUrlElement.textContent).toContain('Current image: https://picsum.photos');
// Clear the image
await userEvent.click(clearImageButton);
// Load another image to test it works multiple times
await userEvent.click(loadImageButton);
// Wait for the new image to load
await waitFor(() => {
expect(canvas.getByTestId('current-image-url')).toBeTruthy();
}, { timeout: 5000 });
}
};
export const TodoListStory: StoryObj = {
name: 'Todo List Property',
render: () => <TodoListTest src="db_list_test.riv" />,
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
// Wait for the Rive file to load
await waitFor(() => {
expect(canvas.getByTestId('list-length')).toBeTruthy();
}, { timeout: 3000 });
const initialLengthText = canvas.getByTestId('list-length').textContent;
const initialCount = parseInt(initialLengthText?.match(/Items: (\d+)/)?.[1] || '0');
// Test 1: addInstance - Add item to end
const addButton = canvas.getByTestId('add-item-button');
await userEvent.click(addButton);
await waitFor(() => {
expect(canvas.getByTestId('list-length').textContent).toContain(`Items: ${initialCount + 1}`);
});
// Test 2: addInstanceAt - Add item at specific index (if we have items)
if (initialCount > 0) {
const addAtButton = canvas.getByTestId('add-item-at-button');
await userEvent.click(addAtButton);
await waitFor(() => {
expect(canvas.getByTestId('list-length').textContent).toContain(`Items: ${initialCount + 2}`);
});
}
// Test 3: getInstanceAt - Interact with specific items
const currentCount = initialCount + (initialCount > 0 ? 2 : 1);
if (currentCount > 0) {
await waitFor(() => {
expect(canvas.getByTestId('todo-item-0')).toBeTruthy();
});
// Edit the first item
const todoText = canvas.getByTestId('todo-text-0');
await userEvent.clear(todoText);
// Wait for the input to be cleared to avoid issues with autocomplete
await waitFor(() => {
expect((todoText as HTMLInputElement).value).toBe('');
}, { timeout: 2000 });
await userEvent.click(todoText);
await userEvent.paste('Test Item');
await waitFor(() => {
expect(canvas.getByTestId('todo-text-value-0').textContent).toContain('Test Item');
}, { timeout: 3000 });
}
// Test 4: swap - Swap first two items
if (currentCount >= 2) {
const firstText = canvas.getByTestId<HTMLInputElement>('todo-text-0').value;
const secondText = canvas.getByTestId<HTMLInputElement>('todo-text-1').value;
const swapButton = canvas.getByTestId('swap-button');
await userEvent.click(swapButton);
await waitFor(() => {
expect(canvas.getByTestId('todo-text-0')).toHaveValue(secondText);
expect(canvas.getByTestId('todo-text-1')).toHaveValue(firstText);
}, { timeout: 3000 });
}
// Test 5: removeInstance - Remove by instance reference
if (currentCount > 0) {
const removeInstanceButton = canvas.getByTestId('remove-instance-button');
await userEvent.click(removeInstanceButton);
await waitFor(() => {
expect(canvas.getByTestId('list-length').textContent).toContain(`Items: ${currentCount - 1}`);
}, { timeout: 3000 });
}
// Test 6: removeInstanceAt - Remove by index
const afterRemoveInstance = currentCount > 0 ? currentCount - 1 : 0;
if (afterRemoveInstance > 0) {
const removeIndexButton = canvas.getByTestId('remove-index-button');
await userEvent.click(removeIndexButton);
await waitFor(() => {
expect(canvas.getByTestId('list-length').textContent).toContain(`Items: ${afterRemoveInstance - 1}`);
}, { timeout: 3000 });
}
}
};
export const ArtboardPropertyStory: StoryObj = {
name: 'Artboard Property',
render: () => <ArtboardPropertyTest src="artboard_db_test.riv" />,
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
// Wait for the Rive file to load
await waitFor(() => {
expect(canvas.getByTestId('set-artboard1-blue')).toBeTruthy();
expect(canvas.getByTestId('set-artboard1-red')).toBeTruthy();
expect(canvas.getByTestId('set-artboard1-green')).toBeTruthy();
}, { timeout: 3000 });
// Initially should show None
expect(canvas.getByTestId('artboard1-current').textContent).toBe('Current: None');
expect(canvas.getByTestId('artboard2-current').textContent).toBe('Current: None');
// Set artboard 1 to blue
await userEvent.click(canvas.getByTestId('set-artboard1-blue'));
await waitFor(() => {
expect(canvas.getByTestId('artboard1-current').textContent).toBe('Current: ArtboardBlue');
});
// Set artboard 2 to red
await userEvent.click(canvas.getByTestId('set-artboard2-red'));
await waitFor(() => {
expect(canvas.getByTestId('artboard2-current').textContent).toBe('Current: ArtboardRed');
});
// Switch artboard 1 to green
await userEvent.click(canvas.getByTestId('set-artboard1-green'));
await waitFor(() => {
expect(canvas.getByTestId('artboard1-current').textContent).toBe('Current: ArtboardGreen');
});
// Switch artboard 2 to blue
await userEvent.click(canvas.getByTestId('set-artboard2-blue'));
await waitFor(() => {
expect(canvas.getByTestId('artboard2-current').textContent).toBe('Current: ArtboardBlue');
});
}
};

View File

@@ -9,7 +9,12 @@ import Rive, {
useViewModelInstanceNumber,
useViewModelInstanceEnum,
useViewModelInstanceColor,
useViewModelInstanceTrigger
useViewModelInstanceTrigger,
useViewModelInstanceImage,
decodeImage,
ViewModelInstance,
useViewModelInstanceList,
useViewModelInstanceArtboard
} from '@rive-app/react-webgl2';
@@ -522,3 +527,355 @@ export const PersonInstances = ({ src }: { src: string }) => {
</div>
);
};
export const ImagePropertyTest = ({ src }: { src: string }) => {
const [currentImageUrl, setCurrentImageUrl] = useState<string>('');
const [isLoading, setIsLoading] = useState<boolean>(false);
const { rive, RiveComponent } = useRive({
src,
artboard: "Artboard",
stateMachines: "State Machine 1",
autoplay: true,
autoBind: false,
});
const viewModel = useViewModel(rive, { name: 'Post' });
const viewModelInstance = useViewModelInstance(viewModel, { rive });
const { setValue: setImage } = useViewModelInstanceImage(
'image',
viewModelInstance
);
const loadRandomImage = async () => {
if (!setImage) return;
setIsLoading(true);
try {
const imageUrl = `https://picsum.photos/400/300?random=${Date.now()}`;
setCurrentImageUrl(imageUrl);
const response = await fetch(imageUrl);
const imageBuffer = await response.arrayBuffer();
const decodedImage = await decodeImage(new Uint8Array(imageBuffer));
setImage(decodedImage);
decodedImage.unref();
} catch (error) {
console.error('Failed to load image:', error);
} finally {
setIsLoading(false);
}
};
const clearImage = () => {
if (setImage) {
setImage(null);
setCurrentImageUrl('');
}
};
return (
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '20px' }}>
<div style={{ width: '400px', height: '300px', border: '1px solid #ccc' }}>
<RiveComponent />
</div>
{rive === null ? (
<div data-testid="loading-text">Loading</div>
) : (
<div style={{ display: 'flex', gap: '10px', alignItems: 'center' }}>
<button
onClick={loadRandomImage}
disabled={isLoading}
data-testid="load-random-image"
>
{isLoading ? 'Loading...' : 'Load Random Image'}
</button>
<button
onClick={clearImage}
disabled={isLoading}
data-testid="clear-image"
>
Clear Image
</button>
</div>
)}
{currentImageUrl && (
<div style={{ fontSize: '12px', color: '#666' }}>
<span data-testid="current-image-url">Current image: {currentImageUrl}</span>
</div>
)}
</div>
);
};
// List Property Test
const TodoItemComponent = ({
index,
todoItem
}: {
index: number;
todoItem: ViewModelInstance | null;
}) => {
const { value: text, setValue: setText } = useViewModelInstanceString('text', todoItem);
const { value: isDone, setValue: setIsDone } = useViewModelInstanceBoolean('isDone', todoItem);
if (!todoItem) {
return <div data-testid={`todo-item-${index}`}>Item not found</div>;
}
return (
<div data-testid={`todo-item-${index}`} style={{
display: 'flex',
alignItems: 'center',
gap: '10px',
padding: '8px',
border: '1px solid #ccc',
marginBottom: '4px'
}}>
<input
data-testid={`todo-checkbox-${index}`}
type="checkbox"
checked={isDone ?? false}
onChange={(e) => setIsDone(e.target.checked)}
/>
<input
data-testid={`todo-text-${index}`}
type="text"
value={text || ''}
onChange={(e) => setText(e.target.value)}
style={{ flex: 1 }}
/>
<div data-testid={`todo-text-value-${index}`} style={{ fontSize: '12px', color: '#666' }}>
Text: {text}
</div>
<div data-testid={`todo-done-value-${index}`} style={{ fontSize: '12px', color: '#666' }}>
Done: {isDone ? 'true' : 'false'}
</div>
</div>
);
};
export const TodoListTest = ({ src }: { src: string }) => {
const { rive, RiveComponent } = useRive({
src,
autoplay: true,
artboard: "Artboard",
autoBind: false,
stateMachines: "State Machine 1",
});
const viewModel = useViewModel(rive, { name: 'TodoList' });
const viewModelInstance = useViewModelInstance(viewModel, { rive });
const {
length,
addInstance,
addInstanceAt,
removeInstance,
removeInstanceAt,
getInstanceAt,
swap
} = useViewModelInstanceList('items', viewModelInstance);
const handleAddItem = () => {
const todoItemViewModel = rive?.viewModelByName?.('TodoItem');
if (todoItemViewModel) {
const newTodoItem = todoItemViewModel.instance?.();
if (newTodoItem) {
addInstance(newTodoItem);
}
}
};
const handleAddItemAt = () => {
const todoItemViewModel = rive?.viewModelByName?.('TodoItem');
if (todoItemViewModel && length > 0) {
const newTodoItem = todoItemViewModel.instance?.();
if (newTodoItem) {
addInstanceAt(newTodoItem, 1);
}
}
};
const handleRemoveFirstInstance = () => {
const firstInstance = getInstanceAt(0);
if (firstInstance) {
removeInstance(firstInstance);
}
};
const handleRemoveFirstByIndex = () => {
if (length > 0) {
removeInstanceAt(0);
}
};
const handleSwapItems = () => {
if (length >= 2) {
swap(0, 1);
}
};
return (
<div>
<RiveComponent style={{ width: '400px', height: '400px' }} />
{rive === null ? (
<div data-testid="loading-text">Loading</div>
) : (
<div>
<div data-testid="list-length">Items: {length}</div>
<div style={{ marginBottom: '10px', display: 'flex', gap: '8px', flexWrap: 'wrap' }}>
<button
data-testid="add-item-button"
onClick={handleAddItem}
>
Add Item (End)
</button>
<button
data-testid="add-item-at-button"
onClick={handleAddItemAt}
disabled={length === 0}
>
Add Item at Index 1
</button>
<button
data-testid="remove-instance-button"
onClick={handleRemoveFirstInstance}
disabled={length === 0}
>
Remove First (by Instance)
</button>
<button
data-testid="remove-index-button"
onClick={handleRemoveFirstByIndex}
disabled={length === 0}
>
Remove First (by Index)
</button>
<button
data-testid="swap-button"
onClick={handleSwapItems}
disabled={length < 2}
>
Swap First Two
</button>
</div>
<div data-testid="todo-items">
{Array.from({ length }, (_, index) => (
<TodoItemComponent
key={index}
index={index}
todoItem={getInstanceAt(index)}
/>
))}
</div>
</div>
)}
</div>
);
};
export const ArtboardPropertyTest = ({ src }: { src: string }) => {
const [currentArtboard1, setCurrentArtboard1] = useState<string>('None');
const [currentArtboard2, setCurrentArtboard2] = useState<string>('None');
const { rive, RiveComponent } = useRive({
src,
autoplay: true,
artboard: "Main",
autoBind: true,
stateMachines: "State Machine 1",
});
const { setValue: setArtboard1 } = useViewModelInstanceArtboard('artboard_1', rive?.viewModelInstance);
const { setValue: setArtboard2 } = useViewModelInstanceArtboard('artboard_2', rive?.viewModelInstance);
const handleSetArtboard1 = (artboardName: string) => {
if (rive) {
const artboard = rive.getArtboard(artboardName);
setArtboard1(artboard);
setCurrentArtboard1(artboardName);
}
};
const handleSetArtboard2 = (artboardName: string) => {
if (rive) {
const artboard = rive.getArtboard(artboardName);
setArtboard2(artboard);
setCurrentArtboard2(artboardName);
}
};
return (
<div>
<RiveComponent style={{ width: '400px', height: '400px' }} />
{(rive === null) ? <div data-testid="loading-text">Loading</div> : (
<div>
<div style={{ marginBottom: '20px' }}>
<h4>Artboard 1:</h4>
<div style={{ display: 'flex', gap: '10px', marginBottom: '10px' }}>
<button
data-testid="set-artboard1-blue"
onClick={() => handleSetArtboard1('ArtboardBlue')}
>
Set Blue Artboard
</button>
<button
data-testid="set-artboard1-red"
onClick={() => handleSetArtboard1('ArtboardRed')}
>
Set Red Artboard
</button>
<button
data-testid="set-artboard1-green"
onClick={() => handleSetArtboard1('ArtboardGreen')}
>
Set Green Artboard
</button>
</div>
<div data-testid="artboard1-current">Current: {currentArtboard1}</div>
</div>
<div>
<h4>Artboard 2:</h4>
<div style={{ display: 'flex', gap: '10px', marginBottom: '10px' }}>
<button
data-testid="set-artboard2-blue"
onClick={() => handleSetArtboard2('ArtboardBlue')}
>
Set Blue Artboard
</button>
<button
data-testid="set-artboard2-red"
onClick={() => handleSetArtboard2('ArtboardRed')}
>
Set Red Artboard
</button>
<button
data-testid="set-artboard2-green"
onClick={() => handleSetArtboard2('ArtboardGreen')}
>
Set Green Artboard
</button>
</div>
<div data-testid="artboard2-current">Current: {currentArtboard2}</div>
</div>
</div>
)}
</div>
);
};

View File

@@ -1,6 +1,6 @@
{
"name": "@rive-app/react-canvas-lite",
"version": "4.20.1",
"version": "4.27.1",
"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.27.3"
"@rive-app/canvas-lite": "2.35.2"
},
"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.20.1",
"version": "4.27.1",
"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.27.3"
"@rive-app/canvas": "2.35.2"
},
"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.20.1",
"version": "4.27.1",
"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.27.3"
"@rive-app/webgl": "2.35.2"
},
"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.20.1",
"version": "4.27.1",
"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.27.3"
"@rive-app/webgl2": "2.35.2"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0"

View File

@@ -1,6 +1,6 @@
{
"name": "rive-react",
"version": "4.20.1",
"version": "4.27.1",
"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.27.3",
"@rive-app/canvas-lite": "2.27.3",
"@rive-app/webgl": "2.27.3",
"@rive-app/webgl2": "2.27.3"
"@rive-app/canvas": "2.35.2",
"@rive-app/canvas-lite": "2.35.2",
"@rive-app/webgl": "2.35.2",
"@rive-app/webgl2": "2.35.2"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0"
@@ -48,6 +48,7 @@
"@testing-library/jest-dom": "^5.13.0",
"@testing-library/react": "^16.3.0",
"@types/jest": "^27.0.3",
"@types/node": "^18.17.0",
"@types/offscreencanvas": "^2019.6.4",
"@types/react": "^18.0.0",
"@types/testing-library__jest-dom": "^5.9.5",

View File

@@ -69,6 +69,7 @@ export default function useRive(
): RiveState {
const [canvasElem, setCanvasElem] = useState<HTMLCanvasElement | null>(null);
const containerRef = useRef<HTMLElement | null>(null);
const riveRef = useRef<Rive | null>(null);
const [rive, setRive] = useState<Rive | null>(null);
@@ -130,13 +131,23 @@ export default function useRive(
let r: Rive | null;
if (rive == null) {
const { useOffscreenRenderer } = options;
const { onRiveReady, ...restRiveParams } = riveParams;
r = new Rive({
useOffscreenRenderer,
...riveParams,
...restRiveParams,
canvas: canvasElem,
});
if (riveRef.current != null) {
riveRef.current!.cleanup();
}
riveRef.current = r;
r.on(EventType.Load, () => {
isLoaded = true;
if (onRiveReady) {
onRiveReady(r!);
}
// Check if the component/canvas is mounted before setting state to avoid setState
// on an unmounted component in some rare cases
if (canvasElem) {
@@ -237,6 +248,14 @@ export default function useRive(
};
}, [rive, canvasElem]);
useEffect(() => {
return () => {
if (riveRef.current != null) {
riveRef.current!.cleanup();
}
};
}, []);
/**
* Listen for changes in the animations params
*/

View File

@@ -0,0 +1,35 @@
import { useCallback } from 'react';
import { ViewModelInstance, ViewModelInstanceArtboard } from '@rive-app/canvas';
import { UseViewModelInstanceArtboardResult } from '../types';
import { useViewModelInstanceProperty } from './useViewModelInstanceProperty';
/**
* Hook for interacting with artboard properties of a ViewModelInstance.
*
* @param path - Path to the artboard property (e.g. "targetArtboard" or "group/artboard")
* @param viewModelInstance - The ViewModelInstance containing the artboard property
* @returns An object with a setter function
*/
export default function useViewModelInstanceArtboard(
path: string,
viewModelInstance?: ViewModelInstance | null
): UseViewModelInstanceArtboardResult {
const result = useViewModelInstanceProperty<ViewModelInstanceArtboard, undefined, UseViewModelInstanceArtboardResult>(
path,
viewModelInstance,
{
getProperty: useCallback((vm, p) => vm.artboard(p), []),
getValue: useCallback(() => undefined, []), // Artboards properties don't currently have a readable value
defaultValue: null,
buildPropertyOperations: useCallback((safePropertyAccess) => ({
setValue: (newValue) => {
safePropertyAccess(prop => { prop.value = newValue; });
}
}), [])
}
);
return {
setValue: result.setValue
};
}

View File

@@ -0,0 +1,35 @@
import { useCallback } from 'react';
import { ViewModelInstance, ViewModelInstanceAssetImage } from '@rive-app/canvas';
import { UseViewModelInstanceImageResult, RiveRenderImage } from '../types';
import { useViewModelInstanceProperty } from './useViewModelInstanceProperty';
/**
* Hook for interacting with image properties of a ViewModelInstance.
*
* @param path - Path to the image property (e.g. "profileImage" or "group/avatar")
* @param viewModelInstance - The ViewModelInstance containing the image property
* @returns An object with a setter function
*/
export default function useViewModelInstanceImage(
path: string,
viewModelInstance?: ViewModelInstance | null
): UseViewModelInstanceImageResult {
const result = useViewModelInstanceProperty<ViewModelInstanceAssetImage, undefined, UseViewModelInstanceImageResult>(
path,
viewModelInstance,
{
getProperty: useCallback((vm, p) => vm.image(p), []),
getValue: useCallback(() => undefined, []), // Images don't have a readable value
defaultValue: null,
buildPropertyOperations: useCallback((safePropertyAccess) => ({
setValue: (newValue: RiveRenderImage | null) => {
safePropertyAccess(prop => { prop.value = newValue; });
}
}), [])
}
);
return {
setValue: result.setValue
};
}

View File

@@ -0,0 +1,75 @@
import { useCallback, useState } from 'react';
import { ViewModelInstance, ViewModelInstanceList } from '@rive-app/canvas';
import { UseViewModelInstanceListResult } from '../types';
import { useViewModelInstanceProperty } from './useViewModelInstanceProperty';
/**
* Hook for interacting with list properties of a ViewModelInstance.
*
* @param path - Path to the property (e.g. "items" or "nested/items")
* @param viewModelInstance - The ViewModelInstance containing the list property
* @returns An object with the list length and manipulation functions
*/
export default function useViewModelInstanceList(
path: string,
viewModelInstance?: ViewModelInstance | null
): UseViewModelInstanceListResult {
// We track revision to trigger re-renders on list manipulation (e.g. addInstance, removeInstance, etc).
// This is mostly important for things like the swap function which wouldn't trigger a re-render otherwise because it doesn't change the length of the list.
// For example, if the user swaps two items in the list and we don't trigger a re-render, the user will see the old items if they were using the getInstanceAt function.
// It also accounts for changes that happen within the Rive file itself rather than through the hook.
const [, setRevision] = useState(0);
const result = useViewModelInstanceProperty<ViewModelInstanceList, number, Omit<UseViewModelInstanceListResult, 'length'>>(
path,
viewModelInstance,
{
getProperty: useCallback((vm, p) => vm.list(p), []),
getValue: useCallback((prop) => prop.length, []),
defaultValue: null,
onPropertyEvent: () => {
// This fires when the list changes in Rive
setRevision(prev => prev + 1);
},
buildPropertyOperations: useCallback((safePropertyAccess) => ({
addInstance: (instance: ViewModelInstance) => {
safePropertyAccess(prop => prop.addInstance(instance));
},
addInstanceAt: (instance: ViewModelInstance, index: number): boolean => {
let result = false;
safePropertyAccess(prop => {
result = prop.addInstanceAt(instance, index);
});
return result;
},
removeInstance: (instance: ViewModelInstance) => {
safePropertyAccess(prop => prop.removeInstance(instance));
},
removeInstanceAt: (index: number) => {
safePropertyAccess(prop => prop.removeInstanceAt(index));
},
getInstanceAt: (index: number): ViewModelInstance | null => {
let result: ViewModelInstance | null = null;
safePropertyAccess(prop => {
result = prop.instanceAt(index);
});
return result;
},
swap: (a: number, b: number) => {
safePropertyAccess(prop => prop.swap(a, b));
}
}), [])
}
);
return {
length: result.value ?? 0,
addInstance: result.addInstance,
addInstanceAt: result.addInstanceAt,
removeInstance: result.removeInstance,
removeInstanceAt: result.removeInstanceAt,
getInstanceAt: result.getInstanceAt,
swap: result.swap
};
}

View File

@@ -9,8 +9,11 @@ import useViewModelInstanceBoolean from './hooks/useViewModelInstanceBoolean';
import useViewModelInstanceColor from './hooks/useViewModelInstanceColor';
import useViewModelInstanceEnum from './hooks/useViewModelInstanceEnum';
import useViewModelInstanceTrigger from './hooks/useViewModelInstanceTrigger';
import useViewModelInstanceImage from './hooks/useViewModelInstanceImage';
import useViewModelInstanceList from './hooks/useViewModelInstanceList';
import useResizeCanvas from './hooks/useResizeCanvas';
import useRiveFile from './hooks/useRiveFile';
import useViewModelInstanceArtboard from './hooks/useViewModelInstanceArtboard';
export default Rive;
export {
@@ -26,6 +29,9 @@ export {
useViewModelInstanceColor,
useViewModelInstanceEnum,
useViewModelInstanceTrigger,
useViewModelInstanceImage,
useViewModelInstanceList,
useViewModelInstanceArtboard,
RiveProps,
};
export {

View File

@@ -1,12 +1,17 @@
import {
type decodeImage,
Rive,
RiveFile,
RiveFileParameters,
RiveParameters,
ViewModelInstance,
ViewModelInstanceArtboard,
} from '@rive-app/canvas';
import { ComponentProps, RefCallback } from 'react';
export type UseRiveParameters = Partial<Omit<RiveParameters, 'canvas'>> | null;
export type UseRiveParameters = Partial<Omit<RiveParameters, 'canvas'>> & {
onRiveReady?: (rive: Rive) => void;
} | null;
export type UseRiveOptions = {
useDevicePixelRatio: boolean;
@@ -183,4 +188,63 @@ export type UseViewModelInstanceTriggerResult = {
* Fires the property trigger.
*/
trigger: () => void;
};
export type RiveRenderImage = Awaited<ReturnType<typeof decodeImage>>;
export type UseViewModelInstanceImageResult = {
/**
* Set the value of the image.
* @param value - The image to set.
*/
setValue: (value: RiveRenderImage | null) => void;
};
export type UseViewModelInstanceListResult = {
/**
* The current length of the list.
*/
length: number;
/**
* Add an instance to the end of the list.
* @param instance - The ViewModelInstance to add.
*/
addInstance: (instance: ViewModelInstance) => void;
/**
* Add an instance at a specific index in the list.
* @param instance - The ViewModelInstance to add.
* @param index - The index to add the instance at.
* @returns True if the instance was successfully added, false otherwise.
*/
addInstanceAt: (instance: ViewModelInstance, index: number) => boolean;
/**
* Remove an instance from the list.
* @param instance - The ViewModelInstance to remove.
*/
removeInstance: (instance: ViewModelInstance) => void;
/**
* Remove an instance at a specific index from the list.
* @param index - The index to remove the instance from.
*/
removeInstanceAt: (index: number) => void;
/**
* Get an instance at a specific index from the list.
* @param index - The index to get the instance from.
* @returns The ViewModelInstance at the index, or null if not found.
*/
getInstanceAt: (index: number) => ViewModelInstance | null;
/**
* Swap two instances in the list.
* @param a - The first index.
* @param b - The second index.
*/
swap: (a: number, b: number) => void;
};
export type UseViewModelInstanceArtboardResult = {
/**
* Set the value of the artboard.
* @param value - The artboard to set.
*/
setValue: (value: ViewModelInstanceArtboard extends { value: infer T } ? T : never) => void;
};