From a3642bd1b3836e0479568abcfdc23b42f677d035 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikl=C3=B3s=20Fazekas?= Date: Fri, 8 May 2026 18:13:19 +0200 Subject: [PATCH 1/3] setup: native iOS coverage with react-native-harness fork Adds coverage-ios dependency and portal resolutions pointing to the local react-native-harness fork (feat/native-ios-coverage branch). --- example/package.json | 1 + example/rn-harness.config.mjs | 8 + package.json | 14 +- yarn.lock | 456 +++++----------------------------- 4 files changed, 90 insertions(+), 389 deletions(-) diff --git a/example/package.json b/example/package.json index 5139471f..cd3400c6 100644 --- a/example/package.json +++ b/example/package.json @@ -34,6 +34,7 @@ "@react-native-community/cli": "18.0.0", "@react-native-community/cli-platform-android": "18.0.0", "@react-native-community/cli-platform-ios": "18.0.0", + "@react-native-harness/coverage-ios": "file:/Users/boga/Work/Margelo/react-native-harness/packages/coverage-ios", "@react-native-harness/platform-android": "1.0.0", "@react-native-harness/platform-apple": "1.0.0", "@react-native/babel-preset": "0.79.2", diff --git a/example/rn-harness.config.mjs b/example/rn-harness.config.mjs index 07e71e45..3d4d44ed 100644 --- a/example/rn-harness.config.mjs +++ b/example/rn-harness.config.mjs @@ -24,4 +24,12 @@ export default { }), ], defaultRunner: 'ios', + + coverage: { + native: { + ios: { + pods: ['RNRive', 'RiveRuntime'], + }, + }, + }, }; diff --git a/package.json b/package.json index a086f296..3d48a3c7 100644 --- a/package.json +++ b/package.json @@ -196,6 +196,18 @@ }, "resolutions": { "core-js-compat": "^3.40.0", - "browserslist": "^4.24.4" + "browserslist": "^4.24.4", + "@react-native-harness/config": "portal:/Users/boga/Work/Margelo/react-native-harness/packages/config", + "@react-native-harness/platforms": "portal:/Users/boga/Work/Margelo/react-native-harness/packages/platforms", + "@react-native-harness/platform-apple": "portal:/Users/boga/Work/Margelo/react-native-harness/packages/platform-ios", + "@react-native-harness/jest": "portal:/Users/boga/Work/Margelo/react-native-harness/packages/jest", + "@react-native-harness/tools": "portal:/Users/boga/Work/Margelo/react-native-harness/packages/tools", + "@react-native-harness/plugins": "portal:/Users/boga/Work/Margelo/react-native-harness/packages/plugins", + "@react-native-harness/bridge": "portal:/Users/boga/Work/Margelo/react-native-harness/packages/bridge", + "@react-native-harness/bundler-metro": "portal:/Users/boga/Work/Margelo/react-native-harness/packages/bundler-metro", + "@react-native-harness/cli": "portal:/Users/boga/Work/Margelo/react-native-harness/packages/cli", + "@react-native-harness/runtime": "portal:/Users/boga/Work/Margelo/react-native-harness/packages/runtime", + "@react-native-harness/babel-preset": "portal:/Users/boga/Work/Margelo/react-native-harness/packages/babel-preset", + "react-native-harness": "portal:/Users/boga/Work/Margelo/react-native-harness/packages/cli" } } diff --git a/yarn.lock b/yarn.lock index f1ef36b1..69deab60 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3147,20 +3147,6 @@ __metadata: languageName: node linkType: hard -"@jest/console@npm:30.2.0": - version: 30.2.0 - resolution: "@jest/console@npm:30.2.0" - dependencies: - "@jest/types": 30.2.0 - "@types/node": "*" - chalk: ^4.1.2 - jest-message-util: 30.2.0 - jest-util: 30.2.0 - slash: ^3.0.0 - checksum: 624645c28946c06a5ae6d225fade5c60ecb2bbdb7717d18cf5355ecba967e455f579d0d964a8fbf17de7e2e6dc02382d538ed109075b96d5717637dcc94d309d - languageName: node - linkType: hard - "@jest/console@npm:^29.7.0": version: 29.7.0 resolution: "@jest/console@npm:29.7.0" @@ -3296,16 +3282,6 @@ __metadata: languageName: node linkType: hard -"@jest/pattern@npm:30.0.1": - version: 30.0.1 - resolution: "@jest/pattern@npm:30.0.1" - dependencies: - "@types/node": "*" - jest-regex-util: 30.0.1 - checksum: 1a1857df19be87e714786c3ab36862702bf8ed1e2665044b2ce5ffa787b5ab74c876f1756e83d3b09737dd98c1e980e259059b65b9b0f49b03716634463a8f9e - languageName: node - linkType: hard - "@jest/reporters@npm:^29.7.0": version: 29.7.0 resolution: "@jest/reporters@npm:29.7.0" @@ -3384,18 +3360,6 @@ __metadata: languageName: node linkType: hard -"@jest/test-result@npm:^30.2.0": - version: 30.2.0 - resolution: "@jest/test-result@npm:30.2.0" - dependencies: - "@jest/console": 30.2.0 - "@jest/types": 30.2.0 - "@types/istanbul-lib-coverage": ^2.0.6 - collect-v8-coverage: ^1.0.2 - checksum: 75151d0dc93a4adbf5e8c6309c5c8913698493357c840f7d112c0be2162846f753ac654377567737102ec8e2f6d458238a98d58aa2348959bd345da5aaab15b1 - languageName: node - linkType: hard - "@jest/test-sequencer@npm:^29.7.0": version: 29.7.0 resolution: "@jest/test-sequencer@npm:29.7.0" @@ -3431,21 +3395,6 @@ __metadata: languageName: node linkType: hard -"@jest/types@npm:30.2.0": - version: 30.2.0 - resolution: "@jest/types@npm:30.2.0" - dependencies: - "@jest/pattern": 30.0.1 - "@jest/schemas": 30.0.5 - "@types/istanbul-lib-coverage": ^2.0.6 - "@types/istanbul-reports": ^3.0.4 - "@types/node": "*" - "@types/yargs": ^17.0.33 - chalk: ^4.1.2 - checksum: e92a2c954f0e1e2703b16632c79428c50c891e50434b682234f310b9f0d292ae5a5da49ae625249f5103cbe34f7a396dfc8237edf5b73f7fe70b57d6295fa01b - languageName: node - linkType: hard - "@jest/types@npm:^26.6.2": version: 26.6.2 resolution: "@jest/types@npm:26.6.2" @@ -4359,109 +4308,40 @@ __metadata: languageName: node linkType: hard -"@react-native-harness/babel-preset@npm:1.0.0": - version: 1.0.0 - resolution: "@react-native-harness/babel-preset@npm:1.0.0" - dependencies: - "@babel/plugin-transform-class-static-block": ^7.27.1 - babel-plugin-istanbul: ^7.0.1 - peerDependencies: - "@babel/core": ^7.22.0 - "@babel/plugin-transform-react-jsx": "*" - checksum: 77f95a3adc252d1188ddbd1ed09552b7861052bbfb3c9f03950176f00df31327a8ffa0a63b2b5801852e357e126a6e89133f8a60380d9bc1712d1baa9a6743c3 - languageName: node - linkType: hard - -"@react-native-harness/bridge@npm:1.0.0": - version: 1.0.0 - resolution: "@react-native-harness/bridge@npm:1.0.0" +"@react-native-harness/bridge@portal:/Users/boga/Work/Margelo/react-native-harness/packages/bridge::locator=%40rive-app%2Freact-native%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@react-native-harness/bridge@portal:/Users/boga/Work/Margelo/react-native-harness/packages/bridge::locator=%40rive-app%2Freact-native%40workspace%3A." dependencies: - "@react-native-harness/platforms": 1.0.0 - "@react-native-harness/tools": 1.0.0 + "@react-native-harness/platforms": "workspace:*" + "@react-native-harness/tools": "workspace:*" birpc: ^2.4.0 pixelmatch: ^7.1.0 pngjs: ^7.0.0 ssim.js: ^3.5.0 tslib: ^2.3.0 ws: ^8.18.2 - checksum: 523c65a0e8da19a4d280a50f1d5835ef4a77fe8a069eb41f8a8857bb7ed3f6c0e3c964a30e0a1db9ed6b241f4f61fe0657a63a53ab1db8012a16cda58ee6dda9 - languageName: node - linkType: hard - -"@react-native-harness/bundler-metro@npm:1.0.0": - version: 1.0.0 - resolution: "@react-native-harness/bundler-metro@npm:1.0.0" - dependencies: - "@react-native-harness/config": 1.0.0 - "@react-native-harness/metro": 1.0.0 - "@react-native-harness/tools": 1.0.0 - connect: ^3.7.0 - nocache: ^4.0.0 - tslib: ^2.3.0 - peerDependencies: - metro: "*" - metro-config: "*" - checksum: 3dc8794bd978a9eb77b710304d54a0e4283fcb522b0a97002a4746d92632b52aad96f936e122f62335dc00183fd9301c37e4c34a8efcd8f3d1e39ada201ed159 - languageName: node - linkType: hard - -"@react-native-harness/cli@npm:1.0.0": - version: 1.0.0 - resolution: "@react-native-harness/cli@npm:1.0.0" - dependencies: - "@react-native-harness/bridge": 1.0.0 - "@react-native-harness/config": 1.0.0 - "@react-native-harness/platforms": 1.0.0 - "@react-native-harness/tools": 1.0.0 - tslib: ^2.3.0 - peerDependencies: - jest-cli: "*" - checksum: e14b1566caea7c4d8c63aed9ca69030a1455f5fe3979ff756c7d17b9db8d058c3b19d501d3eefc33209838879c23fd2d3729da498ee2fc3385d32908089e93fe languageName: node - linkType: hard + linkType: soft -"@react-native-harness/config@npm:1.0.0": - version: 1.0.0 - resolution: "@react-native-harness/config@npm:1.0.0" +"@react-native-harness/config@portal:/Users/boga/Work/Margelo/react-native-harness/packages/config::locator=%40rive-app%2Freact-native%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@react-native-harness/config@portal:/Users/boga/Work/Margelo/react-native-harness/packages/config::locator=%40rive-app%2Freact-native%40workspace%3A." dependencies: - "@react-native-harness/tools": 1.0.0 + "@react-native-harness/plugins": "workspace:*" + "@react-native-harness/tools": "workspace:*" tslib: ^2.3.0 zod: ^3.25.67 - checksum: c63c3b757a007b6ecb969e90011554e2d092ea103eb87ba83d6b98aa08624b5b602ec897b4e97dae3e7354689ab8e9182d4cbcb278c28420f3038619c233fda2 languageName: node - linkType: hard - -"@react-native-harness/jest@npm:1.0.0": - version: 1.0.0 - resolution: "@react-native-harness/jest@npm:1.0.0" - dependencies: - "@jest/test-result": ^30.2.0 - "@react-native-harness/bridge": 1.0.0 - "@react-native-harness/bundler-metro": 1.0.0 - "@react-native-harness/config": 1.0.0 - "@react-native-harness/platforms": 1.0.0 - "@react-native-harness/tools": 1.0.0 - chalk: ^4.1.2 - jest-message-util: ^30.2.0 - jest-util: ^30.2.0 - p-limit: ^7.1.1 - tslib: ^2.3.0 - yargs: ^17.7.2 - checksum: 81a1a13eb335d4ae284f4c218ab6616cb192e545e2509735726440012098c585d9e06789fc0c7ee44554905ca65be460b0d02221d0e10e01ea1ba9761f54143f - languageName: node - linkType: hard + linkType: soft -"@react-native-harness/metro@npm:1.0.0": +"@react-native-harness/coverage-ios@file:/Users/boga/Work/Margelo/react-native-harness/packages/coverage-ios::locator=react-native-rive-example%40workspace%3Aexample": version: 1.0.0 - resolution: "@react-native-harness/metro@npm:1.0.0" + resolution: "@react-native-harness/coverage-ios@file:/Users/boga/Work/Margelo/react-native-harness/packages/coverage-ios#/Users/boga/Work/Margelo/react-native-harness/packages/coverage-ios::hash=57b47b&locator=react-native-rive-example%40workspace%3Aexample" dependencies: - "@react-native-harness/babel-preset": 1.0.0 - "@react-native-harness/config": 1.0.0 tslib: ^2.3.0 peerDependencies: - "@react-native-harness/runtime": 1.0.0 - metro: "*" - checksum: 7eb5f8fb50f25d0ce7f56bcadbab63a01ca40149e4f6b15071f237dd2f4853f89c5a2b3de8b624a76f2a601c1f8a6df7ea70891fb4ca8c6107a95f8e1e00288e + react-native: "*" + checksum: dd0575341ed3c710b2c6f472a331d95aba0d9d7eb7277178a759836999af2d53dd05beb4e53fcfc240c9e1ccf8f5aa0ca53064ad55dfdfc2187db8b4a9b90bb5 languageName: node linkType: hard @@ -4478,59 +4358,50 @@ __metadata: languageName: node linkType: hard -"@react-native-harness/platform-apple@npm:1.0.0": - version: 1.0.0 - resolution: "@react-native-harness/platform-apple@npm:1.0.0" +"@react-native-harness/platform-apple@portal:/Users/boga/Work/Margelo/react-native-harness/packages/platform-ios::locator=%40rive-app%2Freact-native%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@react-native-harness/platform-apple@portal:/Users/boga/Work/Margelo/react-native-harness/packages/platform-ios::locator=%40rive-app%2Freact-native%40workspace%3A." dependencies: - "@react-native-harness/platforms": 1.0.0 - "@react-native-harness/tools": 1.0.0 + "@react-native-harness/config": "workspace:*" + "@react-native-harness/platforms": "workspace:*" + "@react-native-harness/tools": "workspace:*" tslib: ^2.3.0 zod: ^3.25.67 - checksum: 30393748eaf9d7ef5aed5e0c9fdd1e758ad901b76387f3b659b2e74cc21dc6bf0a4535b49e397794e34d5f34da1fd230009fba8908dbcc1dce57d9f438a461f1 languageName: node - linkType: hard + linkType: soft -"@react-native-harness/platforms@npm:1.0.0": - version: 1.0.0 - resolution: "@react-native-harness/platforms@npm:1.0.0" +"@react-native-harness/platforms@portal:/Users/boga/Work/Margelo/react-native-harness/packages/platforms::locator=%40rive-app%2Freact-native%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@react-native-harness/platforms@portal:/Users/boga/Work/Margelo/react-native-harness/packages/platforms::locator=%40rive-app%2Freact-native%40workspace%3A." dependencies: tslib: ^2.3.0 - checksum: 4bdf3d164481d6192b7bdd2c1436e15a9e9c14a7b05598ab301fc37ac6979153be5ac718dddcdae1ea879b65ddf047267bd4927a5fa758602569d51bd3c401b2 languageName: node - linkType: hard + linkType: soft -"@react-native-harness/runtime@npm:1.0.0": - version: 1.0.0 - resolution: "@react-native-harness/runtime@npm:1.0.0" +"@react-native-harness/plugins@portal:/Users/boga/Work/Margelo/react-native-harness/packages/plugins::locator=%40rive-app%2Freact-native%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@react-native-harness/plugins@portal:/Users/boga/Work/Margelo/react-native-harness/packages/plugins::locator=%40rive-app%2Freact-native%40workspace%3A." dependencies: - "@react-native-harness/bridge": 1.0.0 - "@vitest/expect": 4.0.16 - "@vitest/spy": 4.0.16 - chai: ^6.2.2 - event-target-shim: ^6.0.2 - use-sync-external-store: ^1.6.0 - zustand: ^5.0.5 - peerDependencies: - react: "*" - react-native: "*" - checksum: ab7a15e0581e2d604e2bb3032fbfd8a81dc387c1914ccde3fbd24fb4783e71251916f41aa748782529cd47dd7df9061a0a08db0ff1aef55b859b3fb9a334fb0a + "@react-native-harness/bridge": "workspace:*" + "@react-native-harness/platforms": "workspace:*" + "@react-native-harness/tools": "workspace:*" + hookable: ^6.1.0 + tslib: ^2.3.0 languageName: node - linkType: hard + linkType: soft -"@react-native-harness/tools@npm:1.0.0": - version: 1.0.0 - resolution: "@react-native-harness/tools@npm:1.0.0" +"@react-native-harness/tools@portal:/Users/boga/Work/Margelo/react-native-harness/packages/tools::locator=%40rive-app%2Freact-native%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@react-native-harness/tools@portal:/Users/boga/Work/Margelo/react-native-harness/packages/tools::locator=%40rive-app%2Freact-native%40workspace%3A." dependencies: "@clack/prompts": 1.0.0-alpha.9 - is-unicode-supported: ^0.1.0 nano-spawn: ^1.0.2 picocolors: ^1.1.1 tslib: ^2.3.0 peerDependencies: react-native: "*" - checksum: 3c897820164918f0fc18b90b8e02507d4006f93c4c3d2934d3bf9d829588a72fa99545be95df5b275648ebf2e871dd04295dbac9b41f64a1913eb37d865dd7de languageName: node - linkType: hard + linkType: soft "@react-native-picker/picker@npm:^2.11.4": version: 2.11.4 @@ -5547,13 +5418,6 @@ __metadata: languageName: node linkType: hard -"@standard-schema/spec@npm:^1.0.0": - version: 1.1.0 - resolution: "@standard-schema/spec@npm:1.1.0" - checksum: 6245ebef5e698bb04752a22e996a7cc40406a404d9f68a9d4e1a7a10f2422da287247508e7b495a2f32bb38f3d57b4daf2c9ab4bf22d9bca13e20a3dc5ec575e - languageName: node - linkType: hard - "@testing-library/react-hooks@npm:^8.0.1": version: 8.0.1 resolution: "@testing-library/react-hooks@npm:8.0.1" @@ -5664,16 +5528,6 @@ __metadata: languageName: node linkType: hard -"@types/chai@npm:^5.2.2": - version: 5.2.3 - resolution: "@types/chai@npm:5.2.3" - dependencies: - "@types/deep-eql": "*" - assertion-error: ^2.0.1 - checksum: eb4c2da9ec38b474a983f39bfb5ec4fbcceb5e5d76d184094d2cbc4c41357973eb5769c8972cedac665a233251b0ed754f1e338fcf408d381968af85cdecc596 - languageName: node - linkType: hard - "@types/conventional-commits-parser@npm:^5.0.0": version: 5.0.2 resolution: "@types/conventional-commits-parser@npm:5.0.2" @@ -5683,13 +5537,6 @@ __metadata: languageName: node linkType: hard -"@types/deep-eql@npm:*": - version: 4.0.2 - resolution: "@types/deep-eql@npm:4.0.2" - checksum: 249a27b0bb22f6aa28461db56afa21ec044fa0e303221a62dff81831b20c8530502175f1a49060f7099e7be06181078548ac47c668de79ff9880241968d43d0c - languageName: node - linkType: hard - "@types/deep-equal@npm:^1.0.4": version: 1.0.4 resolution: "@types/deep-equal@npm:1.0.4" @@ -5720,7 +5567,7 @@ __metadata: languageName: node linkType: hard -"@types/istanbul-lib-coverage@npm:*, @types/istanbul-lib-coverage@npm:^2.0.0, @types/istanbul-lib-coverage@npm:^2.0.1, @types/istanbul-lib-coverage@npm:^2.0.6": +"@types/istanbul-lib-coverage@npm:*, @types/istanbul-lib-coverage@npm:^2.0.0, @types/istanbul-lib-coverage@npm:^2.0.1": version: 2.0.6 resolution: "@types/istanbul-lib-coverage@npm:2.0.6" checksum: 3feac423fd3e5449485afac999dcfcb3d44a37c830af898b689fadc65d26526460bedb889db278e0d4d815a670331796494d073a10ee6e3a6526301fe7415778 @@ -5736,7 +5583,7 @@ __metadata: languageName: node linkType: hard -"@types/istanbul-reports@npm:^3.0.0, @types/istanbul-reports@npm:^3.0.4": +"@types/istanbul-reports@npm:^3.0.0": version: 3.0.4 resolution: "@types/istanbul-reports@npm:3.0.4" dependencies: @@ -5826,7 +5673,7 @@ __metadata: languageName: node linkType: hard -"@types/stack-utils@npm:^2.0.0, @types/stack-utils@npm:^2.0.3": +"@types/stack-utils@npm:^2.0.0": version: 2.0.3 resolution: "@types/stack-utils@npm:2.0.3" checksum: 72576cc1522090fe497337c2b99d9838e320659ac57fa5560fcbdcbafcf5d0216c6b3a0a8a4ee4fdb3b1f5e3420aa4f6223ab57b82fef3578bec3206425c6cf5 @@ -5849,15 +5696,6 @@ __metadata: languageName: node linkType: hard -"@types/yargs@npm:^17.0.33": - version: 17.0.35 - resolution: "@types/yargs@npm:17.0.35" - dependencies: - "@types/yargs-parser": "*" - checksum: ebf1f5373388cfcbf9cfb5e56ce7a77c0ba2450420f26f3701010ca92df48cce7e14e4245ed1f17178a38ff8702467a6f4047742775b8e2fd06dec8f4f3501ce - languageName: node - linkType: hard - "@types/yargs@npm:^17.0.8": version: 17.0.34 resolution: "@types/yargs@npm:17.0.34" @@ -6349,46 +6187,6 @@ __metadata: languageName: node linkType: hard -"@vitest/expect@npm:4.0.16": - version: 4.0.16 - resolution: "@vitest/expect@npm:4.0.16" - dependencies: - "@standard-schema/spec": ^1.0.0 - "@types/chai": ^5.2.2 - "@vitest/spy": 4.0.16 - "@vitest/utils": 4.0.16 - chai: ^6.2.1 - tinyrainbow: ^3.0.3 - checksum: cbd3a9e41ea3c8023cd0b02d0950e127f631e46960e84112e2a46984a8c530eb178d12f832e1abdb25854fe21d19770f08c2f4d0044fe9eaf2140ef0744b1972 - languageName: node - linkType: hard - -"@vitest/pretty-format@npm:4.0.16": - version: 4.0.16 - resolution: "@vitest/pretty-format@npm:4.0.16" - dependencies: - tinyrainbow: ^3.0.3 - checksum: cb457b056b1b1ba64d9b2a4d92edda9c7e437b705e048bfee054982e907c9838602193c60f98879d2c9a0f47efc000f5bc4ebda11aa983366bee9677883ad02e - languageName: node - linkType: hard - -"@vitest/spy@npm:4.0.16": - version: 4.0.16 - resolution: "@vitest/spy@npm:4.0.16" - checksum: ed729fe478b1fb8663c4d0e42c11a8cb85e49eff54f3b23790ff6d59158b6836c5b0733dcd77e235122d8f9a42ed9415a5a6861681373aacee824f5a73986a8e - languageName: node - linkType: hard - -"@vitest/utils@npm:4.0.16": - version: 4.0.16 - resolution: "@vitest/utils@npm:4.0.16" - dependencies: - "@vitest/pretty-format": 4.0.16 - tinyrainbow: ^3.0.3 - checksum: a7579d85bf7ae8ddec5c826008bfb7f4d702acb29432e20bb498643bafa3baa76c9ad7141de1e6a296092ff6661d3f3756922c31d2131721c7aafe3ad0dc06d8 - languageName: node - linkType: hard - "@vscode/sudo-prompt@npm:^9.0.0": version: 9.3.1 resolution: "@vscode/sudo-prompt@npm:9.3.1" @@ -6827,13 +6625,6 @@ __metadata: languageName: node linkType: hard -"assertion-error@npm:^2.0.1": - version: 2.0.1 - resolution: "assertion-error@npm:2.0.1" - checksum: a0789dd882211b87116e81e2648ccb7f60340b34f19877dd020b39ebb4714e475eb943e14ba3e22201c221ef6645b7bfe10297e76b6ac95b48a9898c1211ce66 - languageName: node - linkType: hard - "ast-types@npm:^0.13.4": version: 0.13.4 resolution: "ast-types@npm:0.13.4" @@ -6929,19 +6720,6 @@ __metadata: languageName: node linkType: hard -"babel-plugin-istanbul@npm:^7.0.1": - version: 7.0.1 - resolution: "babel-plugin-istanbul@npm:7.0.1" - dependencies: - "@babel/helper-plugin-utils": ^7.0.0 - "@istanbuljs/load-nyc-config": ^1.0.0 - "@istanbuljs/schema": ^0.1.3 - istanbul-lib-instrument: ^6.0.2 - test-exclude: ^6.0.0 - checksum: 06195af9022a1a2dad23bc4f2f9c226d053304889ae2be23a32aa3df821d2e61055a8eb533f204b10ee9899120e4f52bef6f0c4ab84a960cb2211cf638174aa2 - languageName: node - linkType: hard - "babel-plugin-jest-hoist@npm:^29.6.3": version: 29.6.3 resolution: "babel-plugin-jest-hoist@npm:29.6.3" @@ -7538,13 +7316,6 @@ __metadata: languageName: node linkType: hard -"chai@npm:^6.2.1, chai@npm:^6.2.2": - version: 6.2.2 - resolution: "chai@npm:6.2.2" - checksum: c8c94857745b673dae22a7b25053a41a931848e2c20d1acb6838cf99b7d57b0e66b9eb878c6308534b2965c11ae1a66f8c58066f368c91a07797bb8ee881a733 - languageName: node - linkType: hard - "chalk@npm:5.4.1": version: 5.4.1 resolution: "chalk@npm:5.4.1" @@ -7643,7 +7414,7 @@ __metadata: languageName: node linkType: hard -"ci-info@npm:^4.1.0, ci-info@npm:^4.2.0": +"ci-info@npm:^4.1.0": version: 4.3.1 resolution: "ci-info@npm:4.3.1" checksum: 66c159d92648e8a07acab0a3a0681bff6ccc39aa44916263208c4d97bbbeedbbc886d7611fd30c21df1aa624ce3c6fcdfde982e74689e3e014e064e1d0805f94 @@ -7782,7 +7553,7 @@ __metadata: languageName: node linkType: hard -"collect-v8-coverage@npm:^1.0.0, collect-v8-coverage@npm:^1.0.2": +"collect-v8-coverage@npm:^1.0.0": version: 1.0.3 resolution: "collect-v8-coverage@npm:1.0.3" checksum: ed1d1ebc9c05e7263fffa3ad6440031db6a1fdd9f574435aa689effcdfe9f2b93aba8ec600f9c7b99124cd6ff5d9415c17961d84ae829a72251a4fe668a49b63 @@ -9579,13 +9350,6 @@ __metadata: languageName: node linkType: hard -"event-target-shim@npm:^6.0.2": - version: 6.0.2 - resolution: "event-target-shim@npm:6.0.2" - checksum: 9be93437e5b84056a7dc70af8b8962f4ef7f6fd41a988efcd39dfa2853e33242a4058e0dac9cc589cb16ed7409010590ac8cbcc2e3f823100cd337e13be953a0 - languageName: node - linkType: hard - "exec-async@npm:^2.2.0": version: 2.2.0 resolution: "exec-async@npm:2.2.0" @@ -11340,6 +11104,13 @@ __metadata: languageName: node linkType: hard +"hookable@npm:^6.1.0": + version: 6.1.1 + resolution: "hookable@npm:6.1.1" + checksum: 552a61daa49e89767142f52f9a3f82243a9ef5e1e8cf18d92b9b4b4c9facd31fee053b030bed5a221e7f33c69a8f5be96a700c28b0b068ae729c5a31f9e12b3b + languageName: node + linkType: hard + "hosted-git-info@npm:^4.0.1": version: 4.1.0 resolution: "hosted-git-info@npm:4.1.0" @@ -12243,7 +12014,7 @@ __metadata: languageName: node linkType: hard -"istanbul-lib-instrument@npm:^6.0.0, istanbul-lib-instrument@npm:^6.0.2": +"istanbul-lib-instrument@npm:^6.0.0": version: 6.0.3 resolution: "istanbul-lib-instrument@npm:6.0.3" dependencies: @@ -12542,23 +12313,6 @@ __metadata: languageName: node linkType: hard -"jest-message-util@npm:30.2.0, jest-message-util@npm:^30.2.0": - version: 30.2.0 - resolution: "jest-message-util@npm:30.2.0" - dependencies: - "@babel/code-frame": ^7.27.1 - "@jest/types": 30.2.0 - "@types/stack-utils": ^2.0.3 - chalk: ^4.1.2 - graceful-fs: ^4.2.11 - micromatch: ^4.0.8 - pretty-format: 30.2.0 - slash: ^3.0.0 - stack-utils: ^2.0.6 - checksum: e1e2df36f77fc5245506ca304a8a558dea997aced255b3fdf1bc4be8807c837ab3f5f29b95a3c3e0d6ff9121109939319891f445cbacd9e8c23e6160f107b483 - languageName: node - linkType: hard - "jest-message-util@npm:^29.7.0": version: 29.7.0 resolution: "jest-message-util@npm:29.7.0" @@ -12599,13 +12353,6 @@ __metadata: languageName: node linkType: hard -"jest-regex-util@npm:30.0.1": - version: 30.0.1 - resolution: "jest-regex-util@npm:30.0.1" - checksum: fa8dac80c3e94db20d5e1e51d1bdf101cf5ede8f4e0b8f395ba8b8ea81e71804ffd747452a6bb6413032865de98ac656ef8ae43eddd18d980b6442a2764ed562 - languageName: node - linkType: hard - "jest-regex-util@npm:^29.6.3": version: 29.6.3 resolution: "jest-regex-util@npm:29.6.3" @@ -12727,20 +12474,6 @@ __metadata: languageName: node linkType: hard -"jest-util@npm:30.2.0, jest-util@npm:^30.2.0": - version: 30.2.0 - resolution: "jest-util@npm:30.2.0" - dependencies: - "@jest/types": 30.2.0 - "@types/node": "*" - chalk: ^4.1.2 - ci-info: ^4.2.0 - graceful-fs: ^4.2.11 - picomatch: ^4.0.2 - checksum: 58d22fc71f1bd3926766dbbefca1292401127e6a2e2c369965f941c525a63e01f349ddd94d1e3fbd3670907a02bbe93b333cf3ed95bc830d28ecdafb3560f535 - languageName: node - linkType: hard - "jest-util@npm:^29.7.0": version: 29.7.0 resolution: "jest-util@npm:29.7.0" @@ -14900,13 +14633,6 @@ __metadata: languageName: node linkType: hard -"nocache@npm:^4.0.0": - version: 4.0.0 - resolution: "nocache@npm:4.0.0" - checksum: ba317f7a5b837069c3bf8616c9a25f61bd5ec63ad7aa2ce83e8425116df402ab5b4914bbdfb1ba54893c0f859886cb3ad9a375f1c45ba7a72a9712cf31392292 - languageName: node - linkType: hard - "node-fetch@npm:^2.7.0": version: 2.7.0 resolution: "node-fetch@npm:2.7.0" @@ -15411,15 +15137,6 @@ __metadata: languageName: node linkType: hard -"p-limit@npm:^7.1.1": - version: 7.2.0 - resolution: "p-limit@npm:7.2.0" - dependencies: - yocto-queue: ^1.2.1 - checksum: 6e9e5cc3e9fb41745e566cd16d02ac9f3a88e116f5c2df79b8a5e575e94aa8f3b8135b2de598116b31ea187b5d05b07d112094cc79bf085dfaa3deaa2afa9d15 - languageName: node - linkType: hard - "p-locate@npm:^4.1.0": version: 4.1.0 resolution: "p-locate@npm:4.1.0" @@ -15704,7 +15421,7 @@ __metadata: languageName: node linkType: hard -"picomatch@npm:^4.0.2, picomatch@npm:^4.0.3": +"picomatch@npm:^4.0.3": version: 4.0.3 resolution: "picomatch@npm:4.0.3" checksum: 6817fb74eb745a71445debe1029768de55fd59a42b75606f478ee1d0dc1aa6e78b711d041a7c9d5550e042642029b7f373dc1a43b224c4b7f12d23436735dba0 @@ -16213,22 +15930,19 @@ __metadata: languageName: node linkType: hard -"react-native-harness@npm:1.0.0": - version: 1.0.0 - resolution: "react-native-harness@npm:1.0.0" +"react-native-harness@portal:/Users/boga/Work/Margelo/react-native-harness/packages/cli::locator=%40rive-app%2Freact-native%40workspace%3A.": + version: 0.0.0-use.local + resolution: "react-native-harness@portal:/Users/boga/Work/Margelo/react-native-harness/packages/cli::locator=%40rive-app%2Freact-native%40workspace%3A." dependencies: - "@react-native-harness/babel-preset": 1.0.0 - "@react-native-harness/cli": 1.0.0 - "@react-native-harness/jest": 1.0.0 - "@react-native-harness/metro": 1.0.0 - "@react-native-harness/runtime": 1.0.0 + "@react-native-harness/bridge": "workspace:*" + "@react-native-harness/config": "workspace:*" + "@react-native-harness/platforms": "workspace:*" + "@react-native-harness/tools": "workspace:*" tslib: ^2.3.0 - bin: - harness: bin.js - react-native-harness: bin.js - checksum: 737f1a13554cf1dcb199c93584c648703f47d15033b395c266cb611e2d09da7cefb7dbcc1501220eb2891097524d67d083cb197ec3d54e443452dfe56ba8decf + peerDependencies: + jest-cli: "*" languageName: node - linkType: hard + linkType: soft "react-native-is-edge-to-edge@npm:1.2.1, react-native-is-edge-to-edge@npm:^1.1.6, react-native-is-edge-to-edge@npm:^1.2.1": version: 1.2.1 @@ -16310,6 +16024,7 @@ __metadata: "@react-native-community/cli": 18.0.0 "@react-native-community/cli-platform-android": 18.0.0 "@react-native-community/cli-platform-ios": 18.0.0 + "@react-native-harness/coverage-ios": "file:/Users/boga/Work/Margelo/react-native-harness/packages/coverage-ios" "@react-native-harness/platform-android": 1.0.0 "@react-native-harness/platform-apple": 1.0.0 "@react-native-picker/picker": ^2.11.4 @@ -17751,7 +17466,7 @@ __metadata: languageName: node linkType: hard -"stack-utils@npm:^2.0.3, stack-utils@npm:^2.0.6": +"stack-utils@npm:^2.0.3": version: 2.0.6 resolution: "stack-utils@npm:2.0.6" dependencies: @@ -18253,13 +17968,6 @@ __metadata: languageName: node linkType: hard -"tinyrainbow@npm:^3.0.3": - version: 3.0.3 - resolution: "tinyrainbow@npm:3.0.3" - checksum: e1de26bd599703a6ee5c69e8b66384fa1ef05b26cbb005ad438169f1858d199c98946fb5ec4b7862313bfcf9affd9fb8aaf8c0a42cc953acba8bbcbe739b016c - languageName: node - linkType: hard - "tmp@npm:^0.0.33": version: 0.0.33 resolution: "tmp@npm:0.0.33" @@ -18896,7 +18604,7 @@ __metadata: languageName: node linkType: hard -"use-sync-external-store@npm:^1.5.0, use-sync-external-store@npm:^1.6.0": +"use-sync-external-store@npm:^1.5.0": version: 1.6.0 resolution: "use-sync-external-store@npm:1.6.0" peerDependencies: @@ -19449,7 +19157,7 @@ __metadata: languageName: node linkType: hard -"yargs@npm:^17.0.0, yargs@npm:^17.3.1, yargs@npm:^17.5.1, yargs@npm:^17.6.2, yargs@npm:^17.7.2": +"yargs@npm:^17.0.0, yargs@npm:^17.3.1, yargs@npm:^17.5.1, yargs@npm:^17.6.2": version: 17.7.2 resolution: "yargs@npm:17.7.2" dependencies: @@ -19492,13 +19200,6 @@ __metadata: languageName: node linkType: hard -"yocto-queue@npm:^1.2.1": - version: 1.2.2 - resolution: "yocto-queue@npm:1.2.2" - checksum: 92dd9880c324dbc94ff4b677b7d350ba8d835619062b7102f577add7a59ab4d87f40edc5a03d77d369dfa9d11175b1b2ec4a06a6f8a5d8ce5d1306713f66ee41 - languageName: node - linkType: hard - "yoctocolors-cjs@npm:^2.1.1": version: 2.1.3 resolution: "yoctocolors-cjs@npm:2.1.3" @@ -19528,24 +19229,3 @@ __metadata: checksum: 91174acc7d2ca5572ad522643474ddd60640cf6877b5d76e5d583eb25e3c4072c6f5eb92ab94f231ec5ce61c6acdfc3e0166de45fb1005b1ea54986b026b765f languageName: node linkType: hard - -"zustand@npm:^5.0.5": - version: 5.0.10 - resolution: "zustand@npm:5.0.10" - peerDependencies: - "@types/react": ">=18.0.0" - immer: ">=9.0.6" - react: ">=18.0.0" - use-sync-external-store: ">=1.2.0" - peerDependenciesMeta: - "@types/react": - optional: true - immer: - optional: true - react: - optional: true - use-sync-external-store: - optional: true - checksum: 52d39ad5a0a496a443ced50e773a47df4bda4f718c96e45a08c92675e45d7ac77ce75903b8e3754f17a2e99c71f5864ae8c2b2477aeb4c6f5c2a19e3e64e57ba - languageName: node - linkType: hard From 5013891683210d3b8e9078f83181c8cbde71e91c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikl=C3=B3s=20Fazekas?= Date: Mon, 11 May 2026 10:34:48 +0200 Subject: [PATCH 2/3] feat: add properties enumeration to ViewModel and ViewModelInstance Adds getPropertiesAsync() to ViewModel and ViewModelInstance for runtime introspection. Returns ViewModelPropertyInfo[] with name and type for each property. --- .../com/margelo/nitro/rive/HybridViewModel.kt | 4 + .../nitro/rive/HybridViewModelInstance.kt | 4 + .../com/margelo/nitro/rive/HybridViewModel.kt | 28 + .../nitro/rive/HybridViewModelInstance.kt | 12 + example/package.json | 1 - example/rn-harness.config.mjs | 8 - ios/legacy/HybridViewModel.swift | 6 +- ios/legacy/HybridViewModelInstance.swift | 4 + ios/new/HybridViewModel.swift | 36 +- ios/new/HybridViewModelInstance.swift | 16 +- .../c++/JHybridViewModelInstanceSpec.cpp | 38 +- .../c++/JHybridViewModelInstanceSpec.hpp | 1 + .../android/c++/JHybridViewModelSpec.cpp | 34 ++ .../android/c++/JHybridViewModelSpec.hpp | 1 + .../android/c++/JViewModelPropertyInfo.hpp | 63 +++ .../android/c++/JViewModelPropertyType.hpp | 97 ++++ .../nitro/rive/HybridViewModelInstanceSpec.kt | 4 + .../margelo/nitro/rive/HybridViewModelSpec.kt | 4 + .../nitro/rive/ViewModelPropertyInfo.kt | 41 ++ .../nitro/rive/ViewModelPropertyType.kt | 36 ++ .../generated/ios/RNRive-Swift-Cxx-Bridge.cpp | 8 + .../generated/ios/RNRive-Swift-Cxx-Bridge.hpp | 60 +++ .../ios/RNRive-Swift-Cxx-Umbrella.hpp | 6 + .../c++/HybridViewModelInstanceSpecSwift.hpp | 17 +- .../ios/c++/HybridViewModelSpecSwift.hpp | 15 + ...d_std__vector_ViewModelPropertyInfo_.swift | 46 ++ .../swift/HybridViewModelInstanceSpec.swift | 1 + .../HybridViewModelInstanceSpec_cxx.swift | 25 + .../ios/swift/HybridViewModelSpec.swift | 1 + .../ios/swift/HybridViewModelSpec_cxx.swift | 25 + .../ios/swift/ViewModelPropertyInfo.swift | 34 ++ .../ios/swift/ViewModelPropertyType.swift | 92 ++++ .../c++/HybridViewModelInstanceSpec.cpp | 1 + .../c++/HybridViewModelInstanceSpec.hpp | 7 +- .../shared/c++/HybridViewModelSpec.cpp | 1 + .../shared/c++/HybridViewModelSpec.hpp | 5 + .../shared/c++/ViewModelPropertyInfo.hpp | 89 ++++ .../shared/c++/ViewModelPropertyType.hpp | 128 +++++ package.json | 14 +- src/index.tsx | 2 + src/specs/ViewModel.nitro.ts | 26 + yarn.lock | 502 +++++++++++++++--- 42 files changed, 1436 insertions(+), 107 deletions(-) create mode 100644 nitrogen/generated/android/c++/JViewModelPropertyInfo.hpp create mode 100644 nitrogen/generated/android/c++/JViewModelPropertyType.hpp create mode 100644 nitrogen/generated/android/kotlin/com/margelo/nitro/rive/ViewModelPropertyInfo.kt create mode 100644 nitrogen/generated/android/kotlin/com/margelo/nitro/rive/ViewModelPropertyType.kt create mode 100644 nitrogen/generated/ios/swift/Func_void_std__vector_ViewModelPropertyInfo_.swift create mode 100644 nitrogen/generated/ios/swift/ViewModelPropertyInfo.swift create mode 100644 nitrogen/generated/ios/swift/ViewModelPropertyType.swift create mode 100644 nitrogen/generated/shared/c++/ViewModelPropertyInfo.hpp create mode 100644 nitrogen/generated/shared/c++/ViewModelPropertyType.hpp diff --git a/android/src/legacy/java/com/margelo/nitro/rive/HybridViewModel.kt b/android/src/legacy/java/com/margelo/nitro/rive/HybridViewModel.kt index 0222cd40..906eeab9 100644 --- a/android/src/legacy/java/com/margelo/nitro/rive/HybridViewModel.kt +++ b/android/src/legacy/java/com/margelo/nitro/rive/HybridViewModel.kt @@ -53,6 +53,10 @@ class HybridViewModel(private val viewModel: ViewModel) : HybridViewModelSpec() } } + override fun getPropertiesAsync(): Promise> { + return Promise.rejected(UnsupportedOperationException("getPropertiesAsync is not supported on the legacy backend")) + } + override fun getPropertyCountAsync(): Promise { return Promise.async { propertyCount } } diff --git a/android/src/legacy/java/com/margelo/nitro/rive/HybridViewModelInstance.kt b/android/src/legacy/java/com/margelo/nitro/rive/HybridViewModelInstance.kt index b8bba139..0d90553f 100644 --- a/android/src/legacy/java/com/margelo/nitro/rive/HybridViewModelInstance.kt +++ b/android/src/legacy/java/com/margelo/nitro/rive/HybridViewModelInstance.kt @@ -12,6 +12,10 @@ class HybridViewModelInstance(val viewModelInstance: ViewModelInstance) : Hybrid override val instanceName: String get() = viewModelInstance.name + override fun getPropertiesAsync(): Promise> { + return Promise.rejected(UnsupportedOperationException("getPropertiesAsync is not supported on the legacy backend")) + } + // Returns null if ViewModelException is thrown for iOS parity // (iOS SDK returns nil when property not found, Android SDK throws) private inline fun getPropertyOrNull(block: () -> T): T? { diff --git a/android/src/new/java/com/margelo/nitro/rive/HybridViewModel.kt b/android/src/new/java/com/margelo/nitro/rive/HybridViewModel.kt index b82f45f7..928889b5 100644 --- a/android/src/new/java/com/margelo/nitro/rive/HybridViewModel.kt +++ b/android/src/new/java/com/margelo/nitro/rive/HybridViewModel.kt @@ -5,6 +5,7 @@ import app.rive.RiveFile import app.rive.ViewModelInstance import app.rive.ViewModelSource import app.rive.core.CommandQueue +import app.rive.runtime.kotlin.core.ViewModel import com.facebook.proguard.annotations.DoNotStrip import com.margelo.nitro.core.Promise import kotlinx.coroutines.runBlocking @@ -22,6 +23,17 @@ class HybridViewModel( private const val TAG = "HybridViewModel" } + override fun getPropertiesAsync(): Promise> { + val name = viewModelName ?: return Promise.resolved(emptyArray()) + return Promise.async { + riveFile + .getViewModelProperties(name) + .map { prop -> + ViewModelPropertyInfo(name = prop.name, type = mapPropertyType(prop.type)) + }.toTypedArray() + } + } + override val propertyCount: Double get() { DeprecationWarning.warn("propertyCount", "getPropertyCountAsync") @@ -147,3 +159,19 @@ class HybridViewModel( } } } + +internal fun mapPropertyType(type: ViewModel.PropertyDataType): ViewModelPropertyType = when (type) { + ViewModel.PropertyDataType.NONE -> ViewModelPropertyType.NONE + ViewModel.PropertyDataType.STRING -> ViewModelPropertyType.STRING + ViewModel.PropertyDataType.NUMBER -> ViewModelPropertyType.NUMBER + ViewModel.PropertyDataType.BOOLEAN -> ViewModelPropertyType.BOOLEAN + ViewModel.PropertyDataType.COLOR -> ViewModelPropertyType.COLOR + ViewModel.PropertyDataType.LIST -> ViewModelPropertyType.LIST + ViewModel.PropertyDataType.ENUM -> ViewModelPropertyType.ENUM + ViewModel.PropertyDataType.TRIGGER -> ViewModelPropertyType.TRIGGER + ViewModel.PropertyDataType.VIEW_MODEL -> ViewModelPropertyType.VIEWMODEL + ViewModel.PropertyDataType.INTEGER -> ViewModelPropertyType.INTEGER + ViewModel.PropertyDataType.SYMBOL_LIST_INDEX -> ViewModelPropertyType.SYMBOLLISTINDEX + ViewModel.PropertyDataType.ASSET_IMAGE -> ViewModelPropertyType.ASSETIMAGE + ViewModel.PropertyDataType.ARTBOARD -> ViewModelPropertyType.ARTBOARD +} diff --git a/android/src/new/java/com/margelo/nitro/rive/HybridViewModelInstance.kt b/android/src/new/java/com/margelo/nitro/rive/HybridViewModelInstance.kt index 98622bf8..d6a562d1 100644 --- a/android/src/new/java/com/margelo/nitro/rive/HybridViewModelInstance.kt +++ b/android/src/new/java/com/margelo/nitro/rive/HybridViewModelInstance.kt @@ -44,6 +44,18 @@ class HybridViewModelInstance( override val instanceName: String get() = _instanceName ?: "" + override fun getPropertiesAsync(): Promise> { + val name = viewModelName ?: return Promise.resolved(emptyArray()) + val file = parentFile.riveFile ?: return Promise.resolved(emptyArray()) + return Promise.async { + file + .getViewModelProperties(name) + .map { prop -> + ViewModelPropertyInfo(name = prop.name, type = mapPropertyType(prop.type)) + }.toTypedArray() + } + } + override fun numberProperty(path: String): HybridViewModelNumberPropertySpec? { return try { runBlocking { viewModelInstance.getNumberFlow(path).first() } diff --git a/example/package.json b/example/package.json index cd3400c6..5139471f 100644 --- a/example/package.json +++ b/example/package.json @@ -34,7 +34,6 @@ "@react-native-community/cli": "18.0.0", "@react-native-community/cli-platform-android": "18.0.0", "@react-native-community/cli-platform-ios": "18.0.0", - "@react-native-harness/coverage-ios": "file:/Users/boga/Work/Margelo/react-native-harness/packages/coverage-ios", "@react-native-harness/platform-android": "1.0.0", "@react-native-harness/platform-apple": "1.0.0", "@react-native/babel-preset": "0.79.2", diff --git a/example/rn-harness.config.mjs b/example/rn-harness.config.mjs index 3d4d44ed..07e71e45 100644 --- a/example/rn-harness.config.mjs +++ b/example/rn-harness.config.mjs @@ -24,12 +24,4 @@ export default { }), ], defaultRunner: 'ios', - - coverage: { - native: { - ios: { - pods: ['RNRive', 'RiveRuntime'], - }, - }, - }, }; diff --git a/ios/legacy/HybridViewModel.swift b/ios/legacy/HybridViewModel.swift index bc5e2d11..12ec3316 100644 --- a/ios/legacy/HybridViewModel.swift +++ b/ios/legacy/HybridViewModel.swift @@ -13,7 +13,11 @@ class HybridViewModel: HybridViewModelSpec { var instanceCount: Double { Double(viewModel?.instanceCount ?? 0) } var modelName: String { viewModel?.name ?? "" } - + + func getPropertiesAsync() throws -> Promise<[ViewModelPropertyInfo]> { + throw RuntimeError.error(withMessage: "getPropertiesAsync is not supported on the legacy backend") + } + func createInstanceByIndex(index: Double) throws -> (any HybridViewModelInstanceSpec)? { guard index >= 0 else { return nil } guard let viewModel = viewModel, diff --git a/ios/legacy/HybridViewModelInstance.swift b/ios/legacy/HybridViewModelInstance.swift index 8185165f..b292adad 100644 --- a/ios/legacy/HybridViewModelInstance.swift +++ b/ios/legacy/HybridViewModelInstance.swift @@ -10,6 +10,10 @@ class HybridViewModelInstance: HybridViewModelInstanceSpec { var instanceName: String { viewModelInstance?.name ?? "" } + func getPropertiesAsync() throws -> Promise<[ViewModelPropertyInfo]> { + throw RuntimeError.error(withMessage: "getPropertiesAsync is not supported on the legacy backend") + } + func numberProperty(path: String) throws -> (any HybridViewModelNumberPropertySpec)? { guard let property = viewModelInstance?.numberProperty(fromPath: path) else { return nil } return HybridViewModelNumberProperty(property: property) diff --git a/ios/new/HybridViewModel.swift b/ios/new/HybridViewModel.swift index 3dc50bd7..17a2598b 100644 --- a/ios/new/HybridViewModel.swift +++ b/ios/new/HybridViewModel.swift @@ -34,6 +34,13 @@ class HybridViewModel: HybridViewModelSpec { } } + func getPropertiesAsync() throws -> Promise<[ViewModelPropertyInfo]> { + return Promise.async { + let props = try await self.file.getProperties(of: self.vmName) + return props.map { ViewModelPropertyInfo(name: $0.name, type: mapPropertyType($0.type)) } + } + } + func getPropertyCountAsync() throws -> Promise { return Promise.async { Double(try await self.file.getProperties(of: self.vmName).count) @@ -48,7 +55,7 @@ class HybridViewModel: HybridViewModelSpec { private func createDefaultInstanceImpl() async throws -> (any HybridViewModelInstanceSpec)? { let vmi = try await self.file.createViewModelInstance(.viewModelDefault(from: .name(self.vmName))) - return HybridViewModelInstance(viewModelInstance: vmi, worker: self.worker) + return HybridViewModelInstance(viewModelInstance: vmi, worker: self.worker, file: self.file, vmName: self.vmName) } private func createInstanceByIndexImpl(index: Double) async throws -> (any HybridViewModelInstanceSpec)? { @@ -57,7 +64,7 @@ class HybridViewModel: HybridViewModelSpec { guard idx >= 0 && idx < names.count else { return nil } let name = names[idx] let vmi = try await self.file.createViewModelInstance(.name(name, from: .name(self.vmName))) - return HybridViewModelInstance(viewModelInstance: vmi, worker: self.worker, instanceName: name) + return HybridViewModelInstance(viewModelInstance: vmi, worker: self.worker, instanceName: name, file: self.file, vmName: self.vmName) } // Deprecated: Use createInstanceByNameAsync instead @@ -68,7 +75,7 @@ class HybridViewModel: HybridViewModelSpec { private func createInstanceByNameImpl(name: String) async throws -> (any HybridViewModelInstanceSpec)? { let vmi = try await self.file.createViewModelInstance(.name(name, from: .name(self.vmName))) - return HybridViewModelInstance(viewModelInstance: vmi, worker: self.worker, instanceName: name) + return HybridViewModelInstance(viewModelInstance: vmi, worker: self.worker, instanceName: name, file: self.file, vmName: self.vmName) } // Deprecated: Use createInstanceByNameAsync instead @@ -93,7 +100,7 @@ class HybridViewModel: HybridViewModelSpec { private func createInstanceImpl() async throws -> (any HybridViewModelInstanceSpec)? { let vmi = try await self.file.createViewModelInstance(.blank(from: .name(self.vmName))) - return HybridViewModelInstance(viewModelInstance: vmi, worker: self.worker) + return HybridViewModelInstance(viewModelInstance: vmi, worker: self.worker, file: self.file, vmName: self.vmName) } // Deprecated: Use createBlankInstanceAsync instead @@ -106,3 +113,24 @@ class HybridViewModel: HybridViewModelSpec { return Promise.async { try await self.createInstanceImpl() } } } + +func mapPropertyType(_ type: RiveRuntime.ViewModelProperty.DataType) -> ViewModelPropertyType { + switch type { + case .none: return .none + case .string: return .string + case .number: return .number + case .boolean: return .boolean + case .color: return .color + case .list: return .list + case .enum: return .enum + case .trigger: return .trigger + case .viewModel: return .viewmodel + case .integer: return .integer + case .symbolListIndex: return .symbollistindex + case .assetImage: return .assetimage + case .artboard: return .artboard + case .input: return .input + case .any: return .any + @unknown default: return .none + } +} diff --git a/ios/new/HybridViewModelInstance.swift b/ios/new/HybridViewModelInstance.swift index df7d5263..494dc2f7 100644 --- a/ios/new/HybridViewModelInstance.swift +++ b/ios/new/HybridViewModelInstance.swift @@ -5,17 +5,27 @@ class HybridViewModelInstance: HybridViewModelInstanceSpec { let viewModelInstance: ViewModelInstance let worker: Worker private let _instanceName: String + private let file: File? + private let vmName: String? - init(viewModelInstance: ViewModelInstance, worker: Worker, instanceName: String = "") { + init(viewModelInstance: ViewModelInstance, worker: Worker, instanceName: String = "", file: File? = nil, vmName: String? = nil) { self.viewModelInstance = viewModelInstance self.worker = worker self._instanceName = instanceName + self.file = file + self.vmName = vmName } - // TODO: Workaround — rive-ios experimental SDK doesn't expose ViewModelInstance.name. - // Only works when caller knows the name (createInstanceByName). Falls back to "" otherwise. var instanceName: String { _instanceName } + func getPropertiesAsync() throws -> Promise<[ViewModelPropertyInfo]> { + guard let file = file, let vmName = vmName else { return Promise.resolved(withResult: []) } + return Promise.async { + let props = try await file.getProperties(of: vmName) + return props.map { ViewModelPropertyInfo(name: $0.name, type: mapPropertyType($0.type)) } + } + } + // Note: Unlike legacy API, experimental API can't sync-validate if property exists // Non-existent properties return wrapper objects that fail on getValue() // This is a known limitation documented in EXPERIMENTAL_IOS_API.md diff --git a/nitrogen/generated/android/c++/JHybridViewModelInstanceSpec.cpp b/nitrogen/generated/android/c++/JHybridViewModelInstanceSpec.cpp index 6cdef82f..29dbc83c 100644 --- a/nitrogen/generated/android/c++/JHybridViewModelInstanceSpec.cpp +++ b/nitrogen/generated/android/c++/JHybridViewModelInstanceSpec.cpp @@ -7,6 +7,10 @@ #include "JHybridViewModelInstanceSpec.hpp" +// Forward declaration of `ViewModelPropertyInfo` to properly resolve imports. +namespace margelo::nitro::rive { struct ViewModelPropertyInfo; } +// Forward declaration of `ViewModelPropertyType` to properly resolve imports. +namespace margelo::nitro::rive { enum class ViewModelPropertyType; } // Forward declaration of `HybridViewModelNumberPropertySpec` to properly resolve imports. namespace margelo::nitro::rive { class HybridViewModelNumberPropertySpec; } // Forward declaration of `HybridViewModelStringPropertySpec` to properly resolve imports. @@ -29,6 +33,13 @@ namespace margelo::nitro::rive { class HybridViewModelArtboardPropertySpec; } namespace margelo::nitro::rive { class HybridViewModelInstanceSpec; } #include +#include "ViewModelPropertyInfo.hpp" +#include +#include +#include +#include "JViewModelPropertyInfo.hpp" +#include "ViewModelPropertyType.hpp" +#include "JViewModelPropertyType.hpp" #include #include "HybridViewModelNumberPropertySpec.hpp" #include @@ -51,8 +62,6 @@ namespace margelo::nitro::rive { class HybridViewModelInstanceSpec; } #include "JHybridViewModelArtboardPropertySpec.hpp" #include "HybridViewModelInstanceSpec.hpp" #include "JHybridViewModelInstanceSpec.hpp" -#include -#include namespace margelo::nitro::rive { @@ -91,6 +100,31 @@ namespace margelo::nitro::rive { } // Methods + std::shared_ptr>> JHybridViewModelInstanceSpec::getPropertiesAsync() { + static const auto method = _javaPart->javaClassStatic()->getMethod()>("getPropertiesAsync"); + auto __result = method(_javaPart); + return [&]() { + auto __promise = Promise>::create(); + __result->cthis()->addOnResolvedListener([=](const jni::alias_ref& __boxedResult) { + auto __result = jni::static_ref_cast>(__boxedResult); + __promise->resolve([&]() { + size_t __size = __result->size(); + std::vector __vector; + __vector.reserve(__size); + for (size_t __i = 0; __i < __size; __i++) { + auto __element = __result->getElement(__i); + __vector.push_back(__element->toCpp()); + } + return __vector; + }()); + }); + __result->cthis()->addOnRejectedListener([=](const jni::alias_ref& __throwable) { + jni::JniException __jniError(__throwable); + __promise->reject(std::make_exception_ptr(__jniError)); + }); + return __promise; + }(); + } std::optional> JHybridViewModelInstanceSpec::numberProperty(const std::string& path) { static const auto method = _javaPart->javaClassStatic()->getMethod(jni::alias_ref /* path */)>("numberProperty"); auto __result = method(_javaPart, jni::make_jstring(path)); diff --git a/nitrogen/generated/android/c++/JHybridViewModelInstanceSpec.hpp b/nitrogen/generated/android/c++/JHybridViewModelInstanceSpec.hpp index b5b36233..1fc897f3 100644 --- a/nitrogen/generated/android/c++/JHybridViewModelInstanceSpec.hpp +++ b/nitrogen/generated/android/c++/JHybridViewModelInstanceSpec.hpp @@ -54,6 +54,7 @@ namespace margelo::nitro::rive { public: // Methods + std::shared_ptr>> getPropertiesAsync() override; std::optional> numberProperty(const std::string& path) override; std::optional> stringProperty(const std::string& path) override; std::optional> booleanProperty(const std::string& path) override; diff --git a/nitrogen/generated/android/c++/JHybridViewModelSpec.cpp b/nitrogen/generated/android/c++/JHybridViewModelSpec.cpp index 66512d85..0946422b 100644 --- a/nitrogen/generated/android/c++/JHybridViewModelSpec.cpp +++ b/nitrogen/generated/android/c++/JHybridViewModelSpec.cpp @@ -7,12 +7,21 @@ #include "JHybridViewModelSpec.hpp" +// Forward declaration of `ViewModelPropertyInfo` to properly resolve imports. +namespace margelo::nitro::rive { struct ViewModelPropertyInfo; } +// Forward declaration of `ViewModelPropertyType` to properly resolve imports. +namespace margelo::nitro::rive { enum class ViewModelPropertyType; } // Forward declaration of `HybridViewModelInstanceSpec` to properly resolve imports. namespace margelo::nitro::rive { class HybridViewModelInstanceSpec; } #include +#include "ViewModelPropertyInfo.hpp" +#include #include #include +#include "JViewModelPropertyInfo.hpp" +#include "ViewModelPropertyType.hpp" +#include "JViewModelPropertyType.hpp" #include #include "HybridViewModelInstanceSpec.hpp" #include @@ -65,6 +74,31 @@ namespace margelo::nitro::rive { } // Methods + std::shared_ptr>> JHybridViewModelSpec::getPropertiesAsync() { + static const auto method = _javaPart->javaClassStatic()->getMethod()>("getPropertiesAsync"); + auto __result = method(_javaPart); + return [&]() { + auto __promise = Promise>::create(); + __result->cthis()->addOnResolvedListener([=](const jni::alias_ref& __boxedResult) { + auto __result = jni::static_ref_cast>(__boxedResult); + __promise->resolve([&]() { + size_t __size = __result->size(); + std::vector __vector; + __vector.reserve(__size); + for (size_t __i = 0; __i < __size; __i++) { + auto __element = __result->getElement(__i); + __vector.push_back(__element->toCpp()); + } + return __vector; + }()); + }); + __result->cthis()->addOnRejectedListener([=](const jni::alias_ref& __throwable) { + jni::JniException __jniError(__throwable); + __promise->reject(std::make_exception_ptr(__jniError)); + }); + return __promise; + }(); + } std::shared_ptr> JHybridViewModelSpec::getPropertyCountAsync() { static const auto method = _javaPart->javaClassStatic()->getMethod()>("getPropertyCountAsync"); auto __result = method(_javaPart); diff --git a/nitrogen/generated/android/c++/JHybridViewModelSpec.hpp b/nitrogen/generated/android/c++/JHybridViewModelSpec.hpp index ad4583da..340ebcc2 100644 --- a/nitrogen/generated/android/c++/JHybridViewModelSpec.hpp +++ b/nitrogen/generated/android/c++/JHybridViewModelSpec.hpp @@ -56,6 +56,7 @@ namespace margelo::nitro::rive { public: // Methods + std::shared_ptr>> getPropertiesAsync() override; std::shared_ptr> getPropertyCountAsync() override; std::shared_ptr> getInstanceCountAsync() override; std::optional> createInstanceByIndex(double index) override; diff --git a/nitrogen/generated/android/c++/JViewModelPropertyInfo.hpp b/nitrogen/generated/android/c++/JViewModelPropertyInfo.hpp new file mode 100644 index 00000000..f791ae80 --- /dev/null +++ b/nitrogen/generated/android/c++/JViewModelPropertyInfo.hpp @@ -0,0 +1,63 @@ +/// +/// JViewModelPropertyInfo.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +#pragma once + +#include +#include "ViewModelPropertyInfo.hpp" + +#include "JViewModelPropertyType.hpp" +#include "ViewModelPropertyType.hpp" +#include + +namespace margelo::nitro::rive { + + using namespace facebook; + + /** + * The C++ JNI bridge between the C++ struct "ViewModelPropertyInfo" and the the Kotlin data class "ViewModelPropertyInfo". + */ + struct JViewModelPropertyInfo final: public jni::JavaClass { + public: + static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/rive/ViewModelPropertyInfo;"; + + public: + /** + * Convert this Java/Kotlin-based struct to the C++ struct ViewModelPropertyInfo by copying all values to C++. + */ + [[maybe_unused]] + [[nodiscard]] + ViewModelPropertyInfo toCpp() const { + static const auto clazz = javaClassStatic(); + static const auto fieldName = clazz->getField("name"); + jni::local_ref name = this->getFieldValue(fieldName); + static const auto fieldType = clazz->getField("type"); + jni::local_ref type = this->getFieldValue(fieldType); + return ViewModelPropertyInfo( + name->toStdString(), + type->toCpp() + ); + } + + public: + /** + * Create a Java/Kotlin-based struct by copying all values from the given C++ struct to Java. + */ + [[maybe_unused]] + static jni::local_ref fromCpp(const ViewModelPropertyInfo& value) { + using JSignature = JViewModelPropertyInfo(jni::alias_ref, jni::alias_ref); + static const auto clazz = javaClassStatic(); + static const auto create = clazz->getStaticMethod("fromCpp"); + return create( + clazz, + jni::make_jstring(value.name), + JViewModelPropertyType::fromCpp(value.type) + ); + } + }; + +} // namespace margelo::nitro::rive diff --git a/nitrogen/generated/android/c++/JViewModelPropertyType.hpp b/nitrogen/generated/android/c++/JViewModelPropertyType.hpp new file mode 100644 index 00000000..9ef32283 --- /dev/null +++ b/nitrogen/generated/android/c++/JViewModelPropertyType.hpp @@ -0,0 +1,97 @@ +/// +/// JViewModelPropertyType.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +#pragma once + +#include +#include "ViewModelPropertyType.hpp" + +namespace margelo::nitro::rive { + + using namespace facebook; + + /** + * The C++ JNI bridge between the C++ enum "ViewModelPropertyType" and the the Kotlin enum "ViewModelPropertyType". + */ + struct JViewModelPropertyType final: public jni::JavaClass { + public: + static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/rive/ViewModelPropertyType;"; + + public: + /** + * Convert this Java/Kotlin-based enum to the C++ enum ViewModelPropertyType. + */ + [[maybe_unused]] + [[nodiscard]] + ViewModelPropertyType toCpp() const { + static const auto clazz = javaClassStatic(); + static const auto fieldOrdinal = clazz->getField("value"); + int ordinal = this->getFieldValue(fieldOrdinal); + return static_cast(ordinal); + } + + public: + /** + * Create a Java/Kotlin-based enum with the given C++ enum's value. + */ + [[maybe_unused]] + static jni::alias_ref fromCpp(ViewModelPropertyType value) { + static const auto clazz = javaClassStatic(); + switch (value) { + case ViewModelPropertyType::STRING: + static const auto fieldSTRING = clazz->getStaticField("STRING"); + return clazz->getStaticFieldValue(fieldSTRING); + case ViewModelPropertyType::NUMBER: + static const auto fieldNUMBER = clazz->getStaticField("NUMBER"); + return clazz->getStaticFieldValue(fieldNUMBER); + case ViewModelPropertyType::BOOLEAN: + static const auto fieldBOOLEAN = clazz->getStaticField("BOOLEAN"); + return clazz->getStaticFieldValue(fieldBOOLEAN); + case ViewModelPropertyType::NONE: + static const auto fieldNONE = clazz->getStaticField("NONE"); + return clazz->getStaticFieldValue(fieldNONE); + case ViewModelPropertyType::COLOR: + static const auto fieldCOLOR = clazz->getStaticField("COLOR"); + return clazz->getStaticFieldValue(fieldCOLOR); + case ViewModelPropertyType::LIST: + static const auto fieldLIST = clazz->getStaticField("LIST"); + return clazz->getStaticFieldValue(fieldLIST); + case ViewModelPropertyType::ENUM: + static const auto fieldENUM = clazz->getStaticField("ENUM"); + return clazz->getStaticFieldValue(fieldENUM); + case ViewModelPropertyType::TRIGGER: + static const auto fieldTRIGGER = clazz->getStaticField("TRIGGER"); + return clazz->getStaticFieldValue(fieldTRIGGER); + case ViewModelPropertyType::VIEWMODEL: + static const auto fieldVIEWMODEL = clazz->getStaticField("VIEWMODEL"); + return clazz->getStaticFieldValue(fieldVIEWMODEL); + case ViewModelPropertyType::INTEGER: + static const auto fieldINTEGER = clazz->getStaticField("INTEGER"); + return clazz->getStaticFieldValue(fieldINTEGER); + case ViewModelPropertyType::SYMBOLLISTINDEX: + static const auto fieldSYMBOLLISTINDEX = clazz->getStaticField("SYMBOLLISTINDEX"); + return clazz->getStaticFieldValue(fieldSYMBOLLISTINDEX); + case ViewModelPropertyType::ASSETIMAGE: + static const auto fieldASSETIMAGE = clazz->getStaticField("ASSETIMAGE"); + return clazz->getStaticFieldValue(fieldASSETIMAGE); + case ViewModelPropertyType::ARTBOARD: + static const auto fieldARTBOARD = clazz->getStaticField("ARTBOARD"); + return clazz->getStaticFieldValue(fieldARTBOARD); + case ViewModelPropertyType::INPUT: + static const auto fieldINPUT = clazz->getStaticField("INPUT"); + return clazz->getStaticFieldValue(fieldINPUT); + case ViewModelPropertyType::ANY: + static const auto fieldANY = clazz->getStaticField("ANY"); + return clazz->getStaticFieldValue(fieldANY); + default: + std::string stringValue = std::to_string(static_cast(value)); + throw std::invalid_argument("Invalid enum value (" + stringValue + "!"); + } + } + }; + +} // namespace margelo::nitro::rive diff --git a/nitrogen/generated/android/kotlin/com/margelo/nitro/rive/HybridViewModelInstanceSpec.kt b/nitrogen/generated/android/kotlin/com/margelo/nitro/rive/HybridViewModelInstanceSpec.kt index dd360e91..3907b537 100644 --- a/nitrogen/generated/android/kotlin/com/margelo/nitro/rive/HybridViewModelInstanceSpec.kt +++ b/nitrogen/generated/android/kotlin/com/margelo/nitro/rive/HybridViewModelInstanceSpec.kt @@ -31,6 +31,10 @@ abstract class HybridViewModelInstanceSpec: HybridObject() { abstract val instanceName: String // Methods + @DoNotStrip + @Keep + abstract fun getPropertiesAsync(): Promise> + @DoNotStrip @Keep abstract fun numberProperty(path: String): HybridViewModelNumberPropertySpec? diff --git a/nitrogen/generated/android/kotlin/com/margelo/nitro/rive/HybridViewModelSpec.kt b/nitrogen/generated/android/kotlin/com/margelo/nitro/rive/HybridViewModelSpec.kt index 087a3e82..1e8f63ac 100644 --- a/nitrogen/generated/android/kotlin/com/margelo/nitro/rive/HybridViewModelSpec.kt +++ b/nitrogen/generated/android/kotlin/com/margelo/nitro/rive/HybridViewModelSpec.kt @@ -39,6 +39,10 @@ abstract class HybridViewModelSpec: HybridObject() { abstract val modelName: String // Methods + @DoNotStrip + @Keep + abstract fun getPropertiesAsync(): Promise> + @DoNotStrip @Keep abstract fun getPropertyCountAsync(): Promise diff --git a/nitrogen/generated/android/kotlin/com/margelo/nitro/rive/ViewModelPropertyInfo.kt b/nitrogen/generated/android/kotlin/com/margelo/nitro/rive/ViewModelPropertyInfo.kt new file mode 100644 index 00000000..506a8e2f --- /dev/null +++ b/nitrogen/generated/android/kotlin/com/margelo/nitro/rive/ViewModelPropertyInfo.kt @@ -0,0 +1,41 @@ +/// +/// ViewModelPropertyInfo.kt +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +package com.margelo.nitro.rive + +import androidx.annotation.Keep +import com.facebook.proguard.annotations.DoNotStrip + + +/** + * Represents the JavaScript object/struct "ViewModelPropertyInfo". + */ +@DoNotStrip +@Keep +data class ViewModelPropertyInfo( + @DoNotStrip + @Keep + val name: String, + @DoNotStrip + @Keep + val type: ViewModelPropertyType +) { + /* primary constructor */ + + companion object { + /** + * Constructor called from C++ + */ + @DoNotStrip + @Keep + @Suppress("unused") + @JvmStatic + private fun fromCpp(name: String, type: ViewModelPropertyType): ViewModelPropertyInfo { + return ViewModelPropertyInfo(name, type) + } + } +} diff --git a/nitrogen/generated/android/kotlin/com/margelo/nitro/rive/ViewModelPropertyType.kt b/nitrogen/generated/android/kotlin/com/margelo/nitro/rive/ViewModelPropertyType.kt new file mode 100644 index 00000000..5840a61e --- /dev/null +++ b/nitrogen/generated/android/kotlin/com/margelo/nitro/rive/ViewModelPropertyType.kt @@ -0,0 +1,36 @@ +/// +/// ViewModelPropertyType.kt +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +package com.margelo.nitro.rive + +import androidx.annotation.Keep +import com.facebook.proguard.annotations.DoNotStrip + +/** + * Represents the JavaScript enum/union "ViewModelPropertyType". + */ +@DoNotStrip +@Keep +enum class ViewModelPropertyType(@DoNotStrip @Keep val value: Int) { + STRING(0), + NUMBER(1), + BOOLEAN(2), + NONE(3), + COLOR(4), + LIST(5), + ENUM(6), + TRIGGER(7), + VIEWMODEL(8), + INTEGER(9), + SYMBOLLISTINDEX(10), + ASSETIMAGE(11), + ARTBOARD(12), + INPUT(13), + ANY(14); + + companion object +} diff --git a/nitrogen/generated/ios/RNRive-Swift-Cxx-Bridge.cpp b/nitrogen/generated/ios/RNRive-Swift-Cxx-Bridge.cpp index 414fce11..7e007657 100644 --- a/nitrogen/generated/ios/RNRive-Swift-Cxx-Bridge.cpp +++ b/nitrogen/generated/ios/RNRive-Swift-Cxx-Bridge.cpp @@ -331,6 +331,14 @@ namespace margelo::nitro::rive::bridge::swift { return swiftPart.toUnsafe(); } + // pragma MARK: std::function& /* result */)> + Func_void_std__vector_ViewModelPropertyInfo_ create_Func_void_std__vector_ViewModelPropertyInfo_(void* NON_NULL swiftClosureWrapper) noexcept { + auto swiftClosure = RNRive::Func_void_std__vector_ViewModelPropertyInfo_::fromUnsafe(swiftClosureWrapper); + return [swiftClosure = std::move(swiftClosure)](const std::vector& result) mutable -> void { + swiftClosure.call(result); + }; + } + // pragma MARK: std::function>& /* result */)> Func_void_std__optional_std__shared_ptr_HybridViewModelInstanceSpec__ create_Func_void_std__optional_std__shared_ptr_HybridViewModelInstanceSpec__(void* NON_NULL swiftClosureWrapper) noexcept { auto swiftClosure = RNRive::Func_void_std__optional_std__shared_ptr_HybridViewModelInstanceSpec__::fromUnsafe(swiftClosureWrapper); diff --git a/nitrogen/generated/ios/RNRive-Swift-Cxx-Bridge.hpp b/nitrogen/generated/ios/RNRive-Swift-Cxx-Bridge.hpp index 64cd2eab..3be060dd 100644 --- a/nitrogen/generated/ios/RNRive-Swift-Cxx-Bridge.hpp +++ b/nitrogen/generated/ios/RNRive-Swift-Cxx-Bridge.hpp @@ -80,6 +80,10 @@ namespace margelo::nitro::rive { struct RiveError; } namespace margelo::nitro::rive { enum class RiveEventType; } // Forward declaration of `UnifiedRiveEvent` to properly resolve imports. namespace margelo::nitro::rive { struct UnifiedRiveEvent; } +// Forward declaration of `ViewModelPropertyInfo` to properly resolve imports. +namespace margelo::nitro::rive { struct ViewModelPropertyInfo; } +// Forward declaration of `ViewModelPropertyType` to properly resolve imports. +namespace margelo::nitro::rive { enum class ViewModelPropertyType; } // Forward declarations of Swift defined types // Forward declaration of `HybridBindableArtboardSpec_cxx` to properly resolve imports. @@ -164,6 +168,8 @@ namespace RNRive { class HybridViewModelTriggerPropertySpec_cxx; } #include "RiveErrorType.hpp" #include "RiveEventType.hpp" #include "UnifiedRiveEvent.hpp" +#include "ViewModelPropertyInfo.hpp" +#include "ViewModelPropertyType.hpp" #include #include #include @@ -1236,6 +1242,51 @@ namespace margelo::nitro::rive::bridge::swift { return Result::withError(error); } + // pragma MARK: std::vector + /** + * Specialized version of `std::vector`. + */ + using std__vector_ViewModelPropertyInfo_ = std::vector; + inline std::vector create_std__vector_ViewModelPropertyInfo_(size_t size) noexcept { + std::vector vector; + vector.reserve(size); + return vector; + } + + // pragma MARK: std::shared_ptr>> + /** + * Specialized version of `std::shared_ptr>>`. + */ + using std__shared_ptr_Promise_std__vector_ViewModelPropertyInfo___ = std::shared_ptr>>; + inline std::shared_ptr>> create_std__shared_ptr_Promise_std__vector_ViewModelPropertyInfo___() noexcept { + return Promise>::create(); + } + inline PromiseHolder> wrap_std__shared_ptr_Promise_std__vector_ViewModelPropertyInfo___(std::shared_ptr>> promise) noexcept { + return PromiseHolder>(std::move(promise)); + } + + // pragma MARK: std::function& /* result */)> + /** + * Specialized version of `std::function&)>`. + */ + using Func_void_std__vector_ViewModelPropertyInfo_ = std::function& /* result */)>; + /** + * Wrapper class for a `std::function& / * result * /)>`, this can be used from Swift. + */ + class Func_void_std__vector_ViewModelPropertyInfo__Wrapper final { + public: + explicit Func_void_std__vector_ViewModelPropertyInfo__Wrapper(std::function& /* result */)>&& func): _function(std::make_unique& /* result */)>>(std::move(func))) {} + inline void call(std::vector result) const noexcept { + _function->operator()(result); + } + private: + std::unique_ptr& /* result */)>> _function; + } SWIFT_NONCOPYABLE; + Func_void_std__vector_ViewModelPropertyInfo_ create_Func_void_std__vector_ViewModelPropertyInfo_(void* NON_NULL swiftClosureWrapper) noexcept; + inline Func_void_std__vector_ViewModelPropertyInfo__Wrapper wrap_Func_void_std__vector_ViewModelPropertyInfo_(Func_void_std__vector_ViewModelPropertyInfo_ value) noexcept { + return Func_void_std__vector_ViewModelPropertyInfo__Wrapper(std::move(value)); + } + // pragma MARK: std::shared_ptr>>> /** * Specialized version of `std::shared_ptr>>>`. @@ -1270,6 +1321,15 @@ namespace margelo::nitro::rive::bridge::swift { return Func_void_std__optional_std__shared_ptr_HybridViewModelInstanceSpec___Wrapper(std::move(value)); } + // pragma MARK: Result>>> + using Result_std__shared_ptr_Promise_std__vector_ViewModelPropertyInfo____ = Result>>>; + inline Result_std__shared_ptr_Promise_std__vector_ViewModelPropertyInfo____ create_Result_std__shared_ptr_Promise_std__vector_ViewModelPropertyInfo____(const std::shared_ptr>>& value) noexcept { + return Result>>>::withValue(value); + } + inline Result_std__shared_ptr_Promise_std__vector_ViewModelPropertyInfo____ create_Result_std__shared_ptr_Promise_std__vector_ViewModelPropertyInfo____(const std::exception_ptr& error) noexcept { + return Result>>>::withError(error); + } + // pragma MARK: Result>>>> using Result_std__shared_ptr_Promise_std__optional_std__shared_ptr_HybridViewModelInstanceSpec_____ = Result>>>>; inline Result_std__shared_ptr_Promise_std__optional_std__shared_ptr_HybridViewModelInstanceSpec_____ create_Result_std__shared_ptr_Promise_std__optional_std__shared_ptr_HybridViewModelInstanceSpec_____(const std::shared_ptr>>>& value) noexcept { diff --git a/nitrogen/generated/ios/RNRive-Swift-Cxx-Umbrella.hpp b/nitrogen/generated/ios/RNRive-Swift-Cxx-Umbrella.hpp index 520fe707..a58cf37e 100644 --- a/nitrogen/generated/ios/RNRive-Swift-Cxx-Umbrella.hpp +++ b/nitrogen/generated/ios/RNRive-Swift-Cxx-Umbrella.hpp @@ -80,6 +80,10 @@ namespace margelo::nitro::rive { struct RiveError; } namespace margelo::nitro::rive { enum class RiveEventType; } // Forward declaration of `UnifiedRiveEvent` to properly resolve imports. namespace margelo::nitro::rive { struct UnifiedRiveEvent; } +// Forward declaration of `ViewModelPropertyInfo` to properly resolve imports. +namespace margelo::nitro::rive { struct ViewModelPropertyInfo; } +// Forward declaration of `ViewModelPropertyType` to properly resolve imports. +namespace margelo::nitro::rive { enum class ViewModelPropertyType; } // Include C++ defined types #include "Alignment.hpp" @@ -118,6 +122,8 @@ namespace margelo::nitro::rive { struct UnifiedRiveEvent; } #include "RiveErrorType.hpp" #include "RiveEventType.hpp" #include "UnifiedRiveEvent.hpp" +#include "ViewModelPropertyInfo.hpp" +#include "ViewModelPropertyType.hpp" #include #include #include diff --git a/nitrogen/generated/ios/c++/HybridViewModelInstanceSpecSwift.hpp b/nitrogen/generated/ios/c++/HybridViewModelInstanceSpecSwift.hpp index 1d0e86ff..ecd4fd85 100644 --- a/nitrogen/generated/ios/c++/HybridViewModelInstanceSpecSwift.hpp +++ b/nitrogen/generated/ios/c++/HybridViewModelInstanceSpecSwift.hpp @@ -12,6 +12,10 @@ // Forward declaration of `HybridViewModelInstanceSpec_cxx` to properly resolve imports. namespace RNRive { class HybridViewModelInstanceSpec_cxx; } +// Forward declaration of `ViewModelPropertyInfo` to properly resolve imports. +namespace margelo::nitro::rive { struct ViewModelPropertyInfo; } +// Forward declaration of `ViewModelPropertyType` to properly resolve imports. +namespace margelo::nitro::rive { enum class ViewModelPropertyType; } // Forward declaration of `HybridViewModelNumberPropertySpec` to properly resolve imports. namespace margelo::nitro::rive { class HybridViewModelNumberPropertySpec; } // Forward declaration of `HybridViewModelStringPropertySpec` to properly resolve imports. @@ -34,6 +38,10 @@ namespace margelo::nitro::rive { class HybridViewModelArtboardPropertySpec; } namespace margelo::nitro::rive { class HybridViewModelInstanceSpec; } #include +#include "ViewModelPropertyInfo.hpp" +#include +#include +#include "ViewModelPropertyType.hpp" #include #include "HybridViewModelNumberPropertySpec.hpp" #include @@ -46,7 +54,6 @@ namespace margelo::nitro::rive { class HybridViewModelInstanceSpec; } #include "HybridViewModelListPropertySpec.hpp" #include "HybridViewModelArtboardPropertySpec.hpp" #include "HybridViewModelInstanceSpec.hpp" -#include #include "RNRive-Swift-Cxx-Umbrella.hpp" @@ -101,6 +108,14 @@ namespace margelo::nitro::rive { public: // Methods + inline std::shared_ptr>> getPropertiesAsync() override { + auto __result = _swiftPart.getPropertiesAsync(); + if (__result.hasError()) [[unlikely]] { + std::rethrow_exception(__result.error()); + } + auto __value = std::move(__result.value()); + return __value; + } inline std::optional> numberProperty(const std::string& path) override { auto __result = _swiftPart.numberProperty(path); if (__result.hasError()) [[unlikely]] { diff --git a/nitrogen/generated/ios/c++/HybridViewModelSpecSwift.hpp b/nitrogen/generated/ios/c++/HybridViewModelSpecSwift.hpp index be193603..dabb7f20 100644 --- a/nitrogen/generated/ios/c++/HybridViewModelSpecSwift.hpp +++ b/nitrogen/generated/ios/c++/HybridViewModelSpecSwift.hpp @@ -12,11 +12,18 @@ // Forward declaration of `HybridViewModelSpec_cxx` to properly resolve imports. namespace RNRive { class HybridViewModelSpec_cxx; } +// Forward declaration of `ViewModelPropertyInfo` to properly resolve imports. +namespace margelo::nitro::rive { struct ViewModelPropertyInfo; } +// Forward declaration of `ViewModelPropertyType` to properly resolve imports. +namespace margelo::nitro::rive { enum class ViewModelPropertyType; } // Forward declaration of `HybridViewModelInstanceSpec` to properly resolve imports. namespace margelo::nitro::rive { class HybridViewModelInstanceSpec; } #include +#include "ViewModelPropertyInfo.hpp" +#include #include +#include "ViewModelPropertyType.hpp" #include #include "HybridViewModelInstanceSpec.hpp" #include @@ -80,6 +87,14 @@ namespace margelo::nitro::rive { public: // Methods + inline std::shared_ptr>> getPropertiesAsync() override { + auto __result = _swiftPart.getPropertiesAsync(); + if (__result.hasError()) [[unlikely]] { + std::rethrow_exception(__result.error()); + } + auto __value = std::move(__result.value()); + return __value; + } inline std::shared_ptr> getPropertyCountAsync() override { auto __result = _swiftPart.getPropertyCountAsync(); if (__result.hasError()) [[unlikely]] { diff --git a/nitrogen/generated/ios/swift/Func_void_std__vector_ViewModelPropertyInfo_.swift b/nitrogen/generated/ios/swift/Func_void_std__vector_ViewModelPropertyInfo_.swift new file mode 100644 index 00000000..d2735035 --- /dev/null +++ b/nitrogen/generated/ios/swift/Func_void_std__vector_ViewModelPropertyInfo_.swift @@ -0,0 +1,46 @@ +/// +/// Func_void_std__vector_ViewModelPropertyInfo_.swift +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +import NitroModules + +/** + * Wraps a Swift `(_ value: [ViewModelPropertyInfo]) -> Void` as a class. + * This class can be used from C++, e.g. to wrap the Swift closure as a `std::function`. + */ +public final class Func_void_std__vector_ViewModelPropertyInfo_ { + public typealias bridge = margelo.nitro.rive.bridge.swift + + private let closure: (_ value: [ViewModelPropertyInfo]) -> Void + + public init(_ closure: @escaping (_ value: [ViewModelPropertyInfo]) -> Void) { + self.closure = closure + } + + @inline(__always) + public func call(value: bridge.std__vector_ViewModelPropertyInfo_) -> Void { + self.closure(value.map({ __item in __item })) + } + + /** + * Casts this instance to a retained unsafe raw pointer. + * This acquires one additional strong reference on the object! + */ + @inline(__always) + public func toUnsafe() -> UnsafeMutableRawPointer { + return Unmanaged.passRetained(self).toOpaque() + } + + /** + * Casts an unsafe pointer to a `Func_void_std__vector_ViewModelPropertyInfo_`. + * The pointer has to be a retained opaque `Unmanaged`. + * This removes one strong reference from the object! + */ + @inline(__always) + public static func fromUnsafe(_ pointer: UnsafeMutableRawPointer) -> Func_void_std__vector_ViewModelPropertyInfo_ { + return Unmanaged.fromOpaque(pointer).takeRetainedValue() + } +} diff --git a/nitrogen/generated/ios/swift/HybridViewModelInstanceSpec.swift b/nitrogen/generated/ios/swift/HybridViewModelInstanceSpec.swift index aaa8e9ca..76df4286 100644 --- a/nitrogen/generated/ios/swift/HybridViewModelInstanceSpec.swift +++ b/nitrogen/generated/ios/swift/HybridViewModelInstanceSpec.swift @@ -13,6 +13,7 @@ public protocol HybridViewModelInstanceSpec_protocol: HybridObject { var instanceName: String { get } // Methods + func getPropertiesAsync() throws -> Promise<[ViewModelPropertyInfo]> func numberProperty(path: String) throws -> (any HybridViewModelNumberPropertySpec)? func stringProperty(path: String) throws -> (any HybridViewModelStringPropertySpec)? func booleanProperty(path: String) throws -> (any HybridViewModelBooleanPropertySpec)? diff --git a/nitrogen/generated/ios/swift/HybridViewModelInstanceSpec_cxx.swift b/nitrogen/generated/ios/swift/HybridViewModelInstanceSpec_cxx.swift index 48fcb568..3f380ede 100644 --- a/nitrogen/generated/ios/swift/HybridViewModelInstanceSpec_cxx.swift +++ b/nitrogen/generated/ios/swift/HybridViewModelInstanceSpec_cxx.swift @@ -129,6 +129,31 @@ open class HybridViewModelInstanceSpec_cxx { } // Methods + @inline(__always) + public final func getPropertiesAsync() -> bridge.Result_std__shared_ptr_Promise_std__vector_ViewModelPropertyInfo____ { + do { + let __result = try self.__implementation.getPropertiesAsync() + let __resultCpp = { () -> bridge.std__shared_ptr_Promise_std__vector_ViewModelPropertyInfo___ in + let __promise = bridge.create_std__shared_ptr_Promise_std__vector_ViewModelPropertyInfo___() + let __promiseHolder = bridge.wrap_std__shared_ptr_Promise_std__vector_ViewModelPropertyInfo___(__promise) + __result + .then({ __result in __promiseHolder.resolve({ () -> bridge.std__vector_ViewModelPropertyInfo_ in + var __vector = bridge.create_std__vector_ViewModelPropertyInfo_(__result.count) + for __item in __result { + __vector.push_back(__item) + } + return __vector + }()) }) + .catch({ __error in __promiseHolder.reject(__error.toCpp()) }) + return __promise + }() + return bridge.create_Result_std__shared_ptr_Promise_std__vector_ViewModelPropertyInfo____(__resultCpp) + } catch (let __error) { + let __exceptionPtr = __error.toCpp() + return bridge.create_Result_std__shared_ptr_Promise_std__vector_ViewModelPropertyInfo____(__exceptionPtr) + } + } + @inline(__always) public final func numberProperty(path: std.string) -> bridge.Result_std__optional_std__shared_ptr_HybridViewModelNumberPropertySpec___ { do { diff --git a/nitrogen/generated/ios/swift/HybridViewModelSpec.swift b/nitrogen/generated/ios/swift/HybridViewModelSpec.swift index 0bcb3cc4..dbe38c72 100644 --- a/nitrogen/generated/ios/swift/HybridViewModelSpec.swift +++ b/nitrogen/generated/ios/swift/HybridViewModelSpec.swift @@ -15,6 +15,7 @@ public protocol HybridViewModelSpec_protocol: HybridObject { var modelName: String { get } // Methods + func getPropertiesAsync() throws -> Promise<[ViewModelPropertyInfo]> func getPropertyCountAsync() throws -> Promise func getInstanceCountAsync() throws -> Promise func createInstanceByIndex(index: Double) throws -> (any HybridViewModelInstanceSpec)? diff --git a/nitrogen/generated/ios/swift/HybridViewModelSpec_cxx.swift b/nitrogen/generated/ios/swift/HybridViewModelSpec_cxx.swift index c963c12a..05abaa94 100644 --- a/nitrogen/generated/ios/swift/HybridViewModelSpec_cxx.swift +++ b/nitrogen/generated/ios/swift/HybridViewModelSpec_cxx.swift @@ -143,6 +143,31 @@ open class HybridViewModelSpec_cxx { } // Methods + @inline(__always) + public final func getPropertiesAsync() -> bridge.Result_std__shared_ptr_Promise_std__vector_ViewModelPropertyInfo____ { + do { + let __result = try self.__implementation.getPropertiesAsync() + let __resultCpp = { () -> bridge.std__shared_ptr_Promise_std__vector_ViewModelPropertyInfo___ in + let __promise = bridge.create_std__shared_ptr_Promise_std__vector_ViewModelPropertyInfo___() + let __promiseHolder = bridge.wrap_std__shared_ptr_Promise_std__vector_ViewModelPropertyInfo___(__promise) + __result + .then({ __result in __promiseHolder.resolve({ () -> bridge.std__vector_ViewModelPropertyInfo_ in + var __vector = bridge.create_std__vector_ViewModelPropertyInfo_(__result.count) + for __item in __result { + __vector.push_back(__item) + } + return __vector + }()) }) + .catch({ __error in __promiseHolder.reject(__error.toCpp()) }) + return __promise + }() + return bridge.create_Result_std__shared_ptr_Promise_std__vector_ViewModelPropertyInfo____(__resultCpp) + } catch (let __error) { + let __exceptionPtr = __error.toCpp() + return bridge.create_Result_std__shared_ptr_Promise_std__vector_ViewModelPropertyInfo____(__exceptionPtr) + } + } + @inline(__always) public final func getPropertyCountAsync() -> bridge.Result_std__shared_ptr_Promise_double___ { do { diff --git a/nitrogen/generated/ios/swift/ViewModelPropertyInfo.swift b/nitrogen/generated/ios/swift/ViewModelPropertyInfo.swift new file mode 100644 index 00000000..e81a5300 --- /dev/null +++ b/nitrogen/generated/ios/swift/ViewModelPropertyInfo.swift @@ -0,0 +1,34 @@ +/// +/// ViewModelPropertyInfo.swift +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +import NitroModules + +/** + * Represents an instance of `ViewModelPropertyInfo`, backed by a C++ struct. + */ +public typealias ViewModelPropertyInfo = margelo.nitro.rive.ViewModelPropertyInfo + +public extension ViewModelPropertyInfo { + private typealias bridge = margelo.nitro.rive.bridge.swift + + /** + * Create a new instance of `ViewModelPropertyInfo`. + */ + init(name: String, type: ViewModelPropertyType) { + self.init(std.string(name), type) + } + + @inline(__always) + var name: String { + return String(self.__name) + } + + @inline(__always) + var type: ViewModelPropertyType { + return self.__type + } +} diff --git a/nitrogen/generated/ios/swift/ViewModelPropertyType.swift b/nitrogen/generated/ios/swift/ViewModelPropertyType.swift new file mode 100644 index 00000000..9538c3b7 --- /dev/null +++ b/nitrogen/generated/ios/swift/ViewModelPropertyType.swift @@ -0,0 +1,92 @@ +/// +/// ViewModelPropertyType.swift +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +/** + * Represents the JS union `ViewModelPropertyType`, backed by a C++ enum. + */ +public typealias ViewModelPropertyType = margelo.nitro.rive.ViewModelPropertyType + +public extension ViewModelPropertyType { + /** + * Get a ViewModelPropertyType for the given String value, or + * return `nil` if the given value was invalid/unknown. + */ + init?(fromString string: String) { + switch string { + case "string": + self = .string + case "number": + self = .number + case "boolean": + self = .boolean + case "none": + self = .none + case "color": + self = .color + case "list": + self = .list + case "enum": + self = .enum + case "trigger": + self = .trigger + case "viewModel": + self = .viewmodel + case "integer": + self = .integer + case "symbolListIndex": + self = .symbollistindex + case "assetImage": + self = .assetimage + case "artboard": + self = .artboard + case "input": + self = .input + case "any": + self = .any + default: + return nil + } + } + + /** + * Get the String value this ViewModelPropertyType represents. + */ + var stringValue: String { + switch self { + case .string: + return "string" + case .number: + return "number" + case .boolean: + return "boolean" + case .none: + return "none" + case .color: + return "color" + case .list: + return "list" + case .enum: + return "enum" + case .trigger: + return "trigger" + case .viewmodel: + return "viewModel" + case .integer: + return "integer" + case .symbollistindex: + return "symbolListIndex" + case .assetimage: + return "assetImage" + case .artboard: + return "artboard" + case .input: + return "input" + case .any: + return "any" + } + } +} diff --git a/nitrogen/generated/shared/c++/HybridViewModelInstanceSpec.cpp b/nitrogen/generated/shared/c++/HybridViewModelInstanceSpec.cpp index 961edebf..830eae4b 100644 --- a/nitrogen/generated/shared/c++/HybridViewModelInstanceSpec.cpp +++ b/nitrogen/generated/shared/c++/HybridViewModelInstanceSpec.cpp @@ -15,6 +15,7 @@ namespace margelo::nitro::rive { // load custom methods/properties registerHybrids(this, [](Prototype& prototype) { prototype.registerHybridGetter("instanceName", &HybridViewModelInstanceSpec::getInstanceName); + prototype.registerHybridMethod("getPropertiesAsync", &HybridViewModelInstanceSpec::getPropertiesAsync); prototype.registerHybridMethod("numberProperty", &HybridViewModelInstanceSpec::numberProperty); prototype.registerHybridMethod("stringProperty", &HybridViewModelInstanceSpec::stringProperty); prototype.registerHybridMethod("booleanProperty", &HybridViewModelInstanceSpec::booleanProperty); diff --git a/nitrogen/generated/shared/c++/HybridViewModelInstanceSpec.hpp b/nitrogen/generated/shared/c++/HybridViewModelInstanceSpec.hpp index 9fa31918..4bc9443e 100644 --- a/nitrogen/generated/shared/c++/HybridViewModelInstanceSpec.hpp +++ b/nitrogen/generated/shared/c++/HybridViewModelInstanceSpec.hpp @@ -13,6 +13,8 @@ #error NitroModules cannot be found! Are you sure you installed NitroModules properly? #endif +// Forward declaration of `ViewModelPropertyInfo` to properly resolve imports. +namespace margelo::nitro::rive { struct ViewModelPropertyInfo; } // Forward declaration of `HybridViewModelNumberPropertySpec` to properly resolve imports. namespace margelo::nitro::rive { class HybridViewModelNumberPropertySpec; } // Forward declaration of `HybridViewModelStringPropertySpec` to properly resolve imports. @@ -35,6 +37,9 @@ namespace margelo::nitro::rive { class HybridViewModelArtboardPropertySpec; } namespace margelo::nitro::rive { class HybridViewModelInstanceSpec; } #include +#include "ViewModelPropertyInfo.hpp" +#include +#include #include #include "HybridViewModelNumberPropertySpec.hpp" #include @@ -47,7 +52,6 @@ namespace margelo::nitro::rive { class HybridViewModelInstanceSpec; } #include "HybridViewModelListPropertySpec.hpp" #include "HybridViewModelArtboardPropertySpec.hpp" #include "HybridViewModelInstanceSpec.hpp" -#include namespace margelo::nitro::rive { @@ -80,6 +84,7 @@ namespace margelo::nitro::rive { public: // Methods + virtual std::shared_ptr>> getPropertiesAsync() = 0; virtual std::optional> numberProperty(const std::string& path) = 0; virtual std::optional> stringProperty(const std::string& path) = 0; virtual std::optional> booleanProperty(const std::string& path) = 0; diff --git a/nitrogen/generated/shared/c++/HybridViewModelSpec.cpp b/nitrogen/generated/shared/c++/HybridViewModelSpec.cpp index f6605533..17b7631e 100644 --- a/nitrogen/generated/shared/c++/HybridViewModelSpec.cpp +++ b/nitrogen/generated/shared/c++/HybridViewModelSpec.cpp @@ -17,6 +17,7 @@ namespace margelo::nitro::rive { prototype.registerHybridGetter("propertyCount", &HybridViewModelSpec::getPropertyCount); prototype.registerHybridGetter("instanceCount", &HybridViewModelSpec::getInstanceCount); prototype.registerHybridGetter("modelName", &HybridViewModelSpec::getModelName); + prototype.registerHybridMethod("getPropertiesAsync", &HybridViewModelSpec::getPropertiesAsync); prototype.registerHybridMethod("getPropertyCountAsync", &HybridViewModelSpec::getPropertyCountAsync); prototype.registerHybridMethod("getInstanceCountAsync", &HybridViewModelSpec::getInstanceCountAsync); prototype.registerHybridMethod("createInstanceByIndex", &HybridViewModelSpec::createInstanceByIndex); diff --git a/nitrogen/generated/shared/c++/HybridViewModelSpec.hpp b/nitrogen/generated/shared/c++/HybridViewModelSpec.hpp index 5564cc5c..34d39eb4 100644 --- a/nitrogen/generated/shared/c++/HybridViewModelSpec.hpp +++ b/nitrogen/generated/shared/c++/HybridViewModelSpec.hpp @@ -13,10 +13,14 @@ #error NitroModules cannot be found! Are you sure you installed NitroModules properly? #endif +// Forward declaration of `ViewModelPropertyInfo` to properly resolve imports. +namespace margelo::nitro::rive { struct ViewModelPropertyInfo; } // Forward declaration of `HybridViewModelInstanceSpec` to properly resolve imports. namespace margelo::nitro::rive { class HybridViewModelInstanceSpec; } #include +#include "ViewModelPropertyInfo.hpp" +#include #include #include #include "HybridViewModelInstanceSpec.hpp" @@ -55,6 +59,7 @@ namespace margelo::nitro::rive { public: // Methods + virtual std::shared_ptr>> getPropertiesAsync() = 0; virtual std::shared_ptr> getPropertyCountAsync() = 0; virtual std::shared_ptr> getInstanceCountAsync() = 0; virtual std::optional> createInstanceByIndex(double index) = 0; diff --git a/nitrogen/generated/shared/c++/ViewModelPropertyInfo.hpp b/nitrogen/generated/shared/c++/ViewModelPropertyInfo.hpp new file mode 100644 index 00000000..13116f43 --- /dev/null +++ b/nitrogen/generated/shared/c++/ViewModelPropertyInfo.hpp @@ -0,0 +1,89 @@ +/// +/// ViewModelPropertyInfo.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +#pragma once + +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif + +// Forward declaration of `ViewModelPropertyType` to properly resolve imports. +namespace margelo::nitro::rive { enum class ViewModelPropertyType; } + +#include +#include "ViewModelPropertyType.hpp" + +namespace margelo::nitro::rive { + + /** + * A struct which can be represented as a JavaScript object (ViewModelPropertyInfo). + */ + struct ViewModelPropertyInfo final { + public: + std::string name SWIFT_PRIVATE; + ViewModelPropertyType type SWIFT_PRIVATE; + + public: + ViewModelPropertyInfo() = default; + explicit ViewModelPropertyInfo(std::string name, ViewModelPropertyType type): name(name), type(type) {} + + public: + friend bool operator==(const ViewModelPropertyInfo& lhs, const ViewModelPropertyInfo& rhs) = default; + }; + +} // namespace margelo::nitro::rive + +namespace margelo::nitro { + + // C++ ViewModelPropertyInfo <> JS ViewModelPropertyInfo (object) + template <> + struct JSIConverter final { + static inline margelo::nitro::rive::ViewModelPropertyInfo fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) { + jsi::Object obj = arg.asObject(runtime); + return margelo::nitro::rive::ViewModelPropertyInfo( + JSIConverter::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "name"))), + JSIConverter::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "type"))) + ); + } + static inline jsi::Value toJSI(jsi::Runtime& runtime, const margelo::nitro::rive::ViewModelPropertyInfo& arg) { + jsi::Object obj(runtime); + obj.setProperty(runtime, PropNameIDCache::get(runtime, "name"), JSIConverter::toJSI(runtime, arg.name)); + obj.setProperty(runtime, PropNameIDCache::get(runtime, "type"), JSIConverter::toJSI(runtime, arg.type)); + return obj; + } + static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) { + if (!value.isObject()) { + return false; + } + jsi::Object obj = value.getObject(runtime); + if (!nitro::isPlainObject(runtime, obj)) { + return false; + } + if (!JSIConverter::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "name")))) return false; + if (!JSIConverter::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "type")))) return false; + return true; + } + }; + +} // namespace margelo::nitro diff --git a/nitrogen/generated/shared/c++/ViewModelPropertyType.hpp b/nitrogen/generated/shared/c++/ViewModelPropertyType.hpp new file mode 100644 index 00000000..09dfd55e --- /dev/null +++ b/nitrogen/generated/shared/c++/ViewModelPropertyType.hpp @@ -0,0 +1,128 @@ +/// +/// ViewModelPropertyType.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +#pragma once + +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif + +namespace margelo::nitro::rive { + + /** + * An enum which can be represented as a JavaScript union (ViewModelPropertyType). + */ + enum class ViewModelPropertyType { + STRING SWIFT_NAME(string) = 0, + NUMBER SWIFT_NAME(number) = 1, + BOOLEAN SWIFT_NAME(boolean) = 2, + NONE SWIFT_NAME(none) = 3, + COLOR SWIFT_NAME(color) = 4, + LIST SWIFT_NAME(list) = 5, + ENUM SWIFT_NAME(enum) = 6, + TRIGGER SWIFT_NAME(trigger) = 7, + VIEWMODEL SWIFT_NAME(viewmodel) = 8, + INTEGER SWIFT_NAME(integer) = 9, + SYMBOLLISTINDEX SWIFT_NAME(symbollistindex) = 10, + ASSETIMAGE SWIFT_NAME(assetimage) = 11, + ARTBOARD SWIFT_NAME(artboard) = 12, + INPUT SWIFT_NAME(input) = 13, + ANY SWIFT_NAME(any) = 14, + } CLOSED_ENUM; + +} // namespace margelo::nitro::rive + +namespace margelo::nitro { + + // C++ ViewModelPropertyType <> JS ViewModelPropertyType (union) + template <> + struct JSIConverter final { + static inline margelo::nitro::rive::ViewModelPropertyType fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) { + std::string unionValue = JSIConverter::fromJSI(runtime, arg); + switch (hashString(unionValue.c_str(), unionValue.size())) { + case hashString("string"): return margelo::nitro::rive::ViewModelPropertyType::STRING; + case hashString("number"): return margelo::nitro::rive::ViewModelPropertyType::NUMBER; + case hashString("boolean"): return margelo::nitro::rive::ViewModelPropertyType::BOOLEAN; + case hashString("none"): return margelo::nitro::rive::ViewModelPropertyType::NONE; + case hashString("color"): return margelo::nitro::rive::ViewModelPropertyType::COLOR; + case hashString("list"): return margelo::nitro::rive::ViewModelPropertyType::LIST; + case hashString("enum"): return margelo::nitro::rive::ViewModelPropertyType::ENUM; + case hashString("trigger"): return margelo::nitro::rive::ViewModelPropertyType::TRIGGER; + case hashString("viewModel"): return margelo::nitro::rive::ViewModelPropertyType::VIEWMODEL; + case hashString("integer"): return margelo::nitro::rive::ViewModelPropertyType::INTEGER; + case hashString("symbolListIndex"): return margelo::nitro::rive::ViewModelPropertyType::SYMBOLLISTINDEX; + case hashString("assetImage"): return margelo::nitro::rive::ViewModelPropertyType::ASSETIMAGE; + case hashString("artboard"): return margelo::nitro::rive::ViewModelPropertyType::ARTBOARD; + case hashString("input"): return margelo::nitro::rive::ViewModelPropertyType::INPUT; + case hashString("any"): return margelo::nitro::rive::ViewModelPropertyType::ANY; + default: [[unlikely]] + throw std::invalid_argument("Cannot convert \"" + unionValue + "\" to enum ViewModelPropertyType - invalid value!"); + } + } + static inline jsi::Value toJSI(jsi::Runtime& runtime, margelo::nitro::rive::ViewModelPropertyType arg) { + switch (arg) { + case margelo::nitro::rive::ViewModelPropertyType::STRING: return JSIConverter::toJSI(runtime, "string"); + case margelo::nitro::rive::ViewModelPropertyType::NUMBER: return JSIConverter::toJSI(runtime, "number"); + case margelo::nitro::rive::ViewModelPropertyType::BOOLEAN: return JSIConverter::toJSI(runtime, "boolean"); + case margelo::nitro::rive::ViewModelPropertyType::NONE: return JSIConverter::toJSI(runtime, "none"); + case margelo::nitro::rive::ViewModelPropertyType::COLOR: return JSIConverter::toJSI(runtime, "color"); + case margelo::nitro::rive::ViewModelPropertyType::LIST: return JSIConverter::toJSI(runtime, "list"); + case margelo::nitro::rive::ViewModelPropertyType::ENUM: return JSIConverter::toJSI(runtime, "enum"); + case margelo::nitro::rive::ViewModelPropertyType::TRIGGER: return JSIConverter::toJSI(runtime, "trigger"); + case margelo::nitro::rive::ViewModelPropertyType::VIEWMODEL: return JSIConverter::toJSI(runtime, "viewModel"); + case margelo::nitro::rive::ViewModelPropertyType::INTEGER: return JSIConverter::toJSI(runtime, "integer"); + case margelo::nitro::rive::ViewModelPropertyType::SYMBOLLISTINDEX: return JSIConverter::toJSI(runtime, "symbolListIndex"); + case margelo::nitro::rive::ViewModelPropertyType::ASSETIMAGE: return JSIConverter::toJSI(runtime, "assetImage"); + case margelo::nitro::rive::ViewModelPropertyType::ARTBOARD: return JSIConverter::toJSI(runtime, "artboard"); + case margelo::nitro::rive::ViewModelPropertyType::INPUT: return JSIConverter::toJSI(runtime, "input"); + case margelo::nitro::rive::ViewModelPropertyType::ANY: return JSIConverter::toJSI(runtime, "any"); + default: [[unlikely]] + throw std::invalid_argument("Cannot convert ViewModelPropertyType to JS - invalid value: " + + std::to_string(static_cast(arg)) + "!"); + } + } + static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) { + if (!value.isString()) { + return false; + } + std::string unionValue = JSIConverter::fromJSI(runtime, value); + switch (hashString(unionValue.c_str(), unionValue.size())) { + case hashString("string"): + case hashString("number"): + case hashString("boolean"): + case hashString("none"): + case hashString("color"): + case hashString("list"): + case hashString("enum"): + case hashString("trigger"): + case hashString("viewModel"): + case hashString("integer"): + case hashString("symbolListIndex"): + case hashString("assetImage"): + case hashString("artboard"): + case hashString("input"): + case hashString("any"): + return true; + default: + return false; + } + } + }; + +} // namespace margelo::nitro diff --git a/package.json b/package.json index 3d48a3c7..a086f296 100644 --- a/package.json +++ b/package.json @@ -196,18 +196,6 @@ }, "resolutions": { "core-js-compat": "^3.40.0", - "browserslist": "^4.24.4", - "@react-native-harness/config": "portal:/Users/boga/Work/Margelo/react-native-harness/packages/config", - "@react-native-harness/platforms": "portal:/Users/boga/Work/Margelo/react-native-harness/packages/platforms", - "@react-native-harness/platform-apple": "portal:/Users/boga/Work/Margelo/react-native-harness/packages/platform-ios", - "@react-native-harness/jest": "portal:/Users/boga/Work/Margelo/react-native-harness/packages/jest", - "@react-native-harness/tools": "portal:/Users/boga/Work/Margelo/react-native-harness/packages/tools", - "@react-native-harness/plugins": "portal:/Users/boga/Work/Margelo/react-native-harness/packages/plugins", - "@react-native-harness/bridge": "portal:/Users/boga/Work/Margelo/react-native-harness/packages/bridge", - "@react-native-harness/bundler-metro": "portal:/Users/boga/Work/Margelo/react-native-harness/packages/bundler-metro", - "@react-native-harness/cli": "portal:/Users/boga/Work/Margelo/react-native-harness/packages/cli", - "@react-native-harness/runtime": "portal:/Users/boga/Work/Margelo/react-native-harness/packages/runtime", - "@react-native-harness/babel-preset": "portal:/Users/boga/Work/Margelo/react-native-harness/packages/babel-preset", - "react-native-harness": "portal:/Users/boga/Work/Margelo/react-native-harness/packages/cli" + "browserslist": "^4.24.4" } } diff --git a/src/index.tsx b/src/index.tsx index d1e5d126..062b44ce 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -32,6 +32,8 @@ export type { ViewModelImageProperty, ViewModelListProperty, ViewModelArtboardProperty, + ViewModelPropertyType, + ViewModelPropertyInfo, } from './specs/ViewModel.nitro'; export type { BindableArtboard } from './specs/BindableArtboard.nitro'; export { Fit } from './core/Fit'; diff --git a/src/specs/ViewModel.nitro.ts b/src/specs/ViewModel.nitro.ts index 8ef459d4..a90577ad 100644 --- a/src/specs/ViewModel.nitro.ts +++ b/src/specs/ViewModel.nitro.ts @@ -2,6 +2,28 @@ import type { HybridObject } from 'react-native-nitro-modules'; import type { RiveImage } from './RiveImage.nitro'; import type { BindableArtboard } from './BindableArtboard.nitro'; +export type ViewModelPropertyType = + | 'none' + | 'string' + | 'number' + | 'boolean' + | 'color' + | 'list' + | 'enum' + | 'trigger' + | 'viewModel' + | 'integer' + | 'symbolListIndex' + | 'assetImage' + | 'artboard' + | 'input' + | 'any'; + +export interface ViewModelPropertyInfo { + readonly name: string; + readonly type: ViewModelPropertyType; +} + /** * A Rive View Model as created in the Rive editor. * @see {@link https://rive.app/docs/runtimes/data-binding Rive Data Binding Documentation} @@ -14,6 +36,8 @@ export interface ViewModel readonly instanceCount: number; /** The name of the view model */ readonly modelName: string; + /** All properties defined on this view model */ + getPropertiesAsync(): Promise; /** The number of properties in the view model */ getPropertyCountAsync(): Promise; /** The number of view model instances in the view model */ @@ -46,6 +70,8 @@ export interface ViewModelInstance extends HybridObject<{ ios: 'swift'; android: 'kotlin' }> { /** The name of the view model instance */ readonly instanceName: string; + /** All properties available on this view model instance */ + getPropertiesAsync(): Promise; /** Get a number property from the view model instance at the given path */ numberProperty(path: string): ViewModelNumberProperty | undefined; diff --git a/yarn.lock b/yarn.lock index 69deab60..6d507750 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3147,6 +3147,20 @@ __metadata: languageName: node linkType: hard +"@jest/console@npm:30.4.1": + version: 30.4.1 + resolution: "@jest/console@npm:30.4.1" + dependencies: + "@jest/types": 30.4.1 + "@types/node": "*" + chalk: ^4.1.2 + jest-message-util: 30.4.1 + jest-util: 30.4.1 + slash: ^3.0.0 + checksum: 21d179fb96a17a622b1b15c3d2ced4c83ae9b3912012505e4720701383f8e0e0d32c41b4c6adeeaaadd193b821d5759425cd1a774ba8ab4924213f218bd50125 + languageName: node + linkType: hard + "@jest/console@npm:^29.7.0": version: 29.7.0 resolution: "@jest/console@npm:29.7.0" @@ -3282,6 +3296,16 @@ __metadata: languageName: node linkType: hard +"@jest/pattern@npm:30.4.0": + version: 30.4.0 + resolution: "@jest/pattern@npm:30.4.0" + dependencies: + "@types/node": "*" + jest-regex-util: 30.4.0 + checksum: d0877dc7034cb59e9eafb8fedd6b977a1cd91191d7ac2574c0c0d046074ef7c895f0952af1586898469dcceb0153230a32b67a45bc4dd1ee2ae66df371b95363 + languageName: node + linkType: hard + "@jest/reporters@npm:^29.7.0": version: 29.7.0 resolution: "@jest/reporters@npm:29.7.0" @@ -3328,6 +3352,15 @@ __metadata: languageName: node linkType: hard +"@jest/schemas@npm:30.4.1": + version: 30.4.1 + resolution: "@jest/schemas@npm:30.4.1" + dependencies: + "@sinclair/typebox": ^0.34.0 + checksum: 25d0db478805adff276e02f9e1b5a90d5962e51020503eede22edee432de3958654edddca0e66988c515fa7bc06461f5220826de9f76fcc89c5824e88d624842 + languageName: node + linkType: hard + "@jest/schemas@npm:^29.6.3": version: 29.6.3 resolution: "@jest/schemas@npm:29.6.3" @@ -3360,6 +3393,18 @@ __metadata: languageName: node linkType: hard +"@jest/test-result@npm:^30.2.0": + version: 30.4.1 + resolution: "@jest/test-result@npm:30.4.1" + dependencies: + "@jest/console": 30.4.1 + "@jest/types": 30.4.1 + "@types/istanbul-lib-coverage": ^2.0.6 + collect-v8-coverage: ^1.0.2 + checksum: 2db40181451f21b7dcc8295fb132a1172dd7487a1d63bf105263225bec2a0d973f764b0a424f9b5a2db2ceb9d0f507c27261834bb1867d5e3eecd9e6c824243c + languageName: node + linkType: hard + "@jest/test-sequencer@npm:^29.7.0": version: 29.7.0 resolution: "@jest/test-sequencer@npm:29.7.0" @@ -3395,6 +3440,21 @@ __metadata: languageName: node linkType: hard +"@jest/types@npm:30.4.1": + version: 30.4.1 + resolution: "@jest/types@npm:30.4.1" + dependencies: + "@jest/pattern": 30.4.0 + "@jest/schemas": 30.4.1 + "@types/istanbul-lib-coverage": ^2.0.6 + "@types/istanbul-reports": ^3.0.4 + "@types/node": "*" + "@types/yargs": ^17.0.33 + chalk: ^4.1.2 + checksum: 746fbb96609c8cc2638a59b23e1d0e590527a301909a22728bc6dab35593ec967f45664fbd00b51fb48a53934d9be2f5df625db7a741c5caae734746d7b41046 + languageName: node + linkType: hard + "@jest/types@npm:^26.6.2": version: 26.6.2 resolution: "@jest/types@npm:26.6.2" @@ -4308,40 +4368,109 @@ __metadata: languageName: node linkType: hard -"@react-native-harness/bridge@portal:/Users/boga/Work/Margelo/react-native-harness/packages/bridge::locator=%40rive-app%2Freact-native%40workspace%3A.": - version: 0.0.0-use.local - resolution: "@react-native-harness/bridge@portal:/Users/boga/Work/Margelo/react-native-harness/packages/bridge::locator=%40rive-app%2Freact-native%40workspace%3A." +"@react-native-harness/babel-preset@npm:1.0.0": + version: 1.0.0 + resolution: "@react-native-harness/babel-preset@npm:1.0.0" dependencies: - "@react-native-harness/platforms": "workspace:*" - "@react-native-harness/tools": "workspace:*" + "@babel/plugin-transform-class-static-block": ^7.27.1 + babel-plugin-istanbul: ^7.0.1 + peerDependencies: + "@babel/core": ^7.22.0 + "@babel/plugin-transform-react-jsx": "*" + checksum: 77f95a3adc252d1188ddbd1ed09552b7861052bbfb3c9f03950176f00df31327a8ffa0a63b2b5801852e357e126a6e89133f8a60380d9bc1712d1baa9a6743c3 + languageName: node + linkType: hard + +"@react-native-harness/bridge@npm:1.0.0": + version: 1.0.0 + resolution: "@react-native-harness/bridge@npm:1.0.0" + dependencies: + "@react-native-harness/platforms": 1.0.0 + "@react-native-harness/tools": 1.0.0 birpc: ^2.4.0 pixelmatch: ^7.1.0 pngjs: ^7.0.0 ssim.js: ^3.5.0 tslib: ^2.3.0 ws: ^8.18.2 + checksum: 523c65a0e8da19a4d280a50f1d5835ef4a77fe8a069eb41f8a8857bb7ed3f6c0e3c964a30e0a1db9ed6b241f4f61fe0657a63a53ab1db8012a16cda58ee6dda9 languageName: node - linkType: soft + linkType: hard -"@react-native-harness/config@portal:/Users/boga/Work/Margelo/react-native-harness/packages/config::locator=%40rive-app%2Freact-native%40workspace%3A.": - version: 0.0.0-use.local - resolution: "@react-native-harness/config@portal:/Users/boga/Work/Margelo/react-native-harness/packages/config::locator=%40rive-app%2Freact-native%40workspace%3A." +"@react-native-harness/bundler-metro@npm:1.0.0": + version: 1.0.0 + resolution: "@react-native-harness/bundler-metro@npm:1.0.0" + dependencies: + "@react-native-harness/config": 1.0.0 + "@react-native-harness/metro": 1.0.0 + "@react-native-harness/tools": 1.0.0 + connect: ^3.7.0 + nocache: ^4.0.0 + tslib: ^2.3.0 + peerDependencies: + metro: "*" + metro-config: "*" + checksum: 3dc8794bd978a9eb77b710304d54a0e4283fcb522b0a97002a4746d92632b52aad96f936e122f62335dc00183fd9301c37e4c34a8efcd8f3d1e39ada201ed159 + languageName: node + linkType: hard + +"@react-native-harness/cli@npm:1.0.0": + version: 1.0.0 + resolution: "@react-native-harness/cli@npm:1.0.0" + dependencies: + "@react-native-harness/bridge": 1.0.0 + "@react-native-harness/config": 1.0.0 + "@react-native-harness/platforms": 1.0.0 + "@react-native-harness/tools": 1.0.0 + tslib: ^2.3.0 + peerDependencies: + jest-cli: "*" + checksum: e14b1566caea7c4d8c63aed9ca69030a1455f5fe3979ff756c7d17b9db8d058c3b19d501d3eefc33209838879c23fd2d3729da498ee2fc3385d32908089e93fe + languageName: node + linkType: hard + +"@react-native-harness/config@npm:1.0.0": + version: 1.0.0 + resolution: "@react-native-harness/config@npm:1.0.0" dependencies: - "@react-native-harness/plugins": "workspace:*" - "@react-native-harness/tools": "workspace:*" + "@react-native-harness/tools": 1.0.0 tslib: ^2.3.0 zod: ^3.25.67 + checksum: c63c3b757a007b6ecb969e90011554e2d092ea103eb87ba83d6b98aa08624b5b602ec897b4e97dae3e7354689ab8e9182d4cbcb278c28420f3038619c233fda2 languageName: node - linkType: soft + linkType: hard + +"@react-native-harness/jest@npm:1.0.0": + version: 1.0.0 + resolution: "@react-native-harness/jest@npm:1.0.0" + dependencies: + "@jest/test-result": ^30.2.0 + "@react-native-harness/bridge": 1.0.0 + "@react-native-harness/bundler-metro": 1.0.0 + "@react-native-harness/config": 1.0.0 + "@react-native-harness/platforms": 1.0.0 + "@react-native-harness/tools": 1.0.0 + chalk: ^4.1.2 + jest-message-util: ^30.2.0 + jest-util: ^30.2.0 + p-limit: ^7.1.1 + tslib: ^2.3.0 + yargs: ^17.7.2 + checksum: 81a1a13eb335d4ae284f4c218ab6616cb192e545e2509735726440012098c585d9e06789fc0c7ee44554905ca65be460b0d02221d0e10e01ea1ba9761f54143f + languageName: node + linkType: hard -"@react-native-harness/coverage-ios@file:/Users/boga/Work/Margelo/react-native-harness/packages/coverage-ios::locator=react-native-rive-example%40workspace%3Aexample": +"@react-native-harness/metro@npm:1.0.0": version: 1.0.0 - resolution: "@react-native-harness/coverage-ios@file:/Users/boga/Work/Margelo/react-native-harness/packages/coverage-ios#/Users/boga/Work/Margelo/react-native-harness/packages/coverage-ios::hash=57b47b&locator=react-native-rive-example%40workspace%3Aexample" + resolution: "@react-native-harness/metro@npm:1.0.0" dependencies: + "@react-native-harness/babel-preset": 1.0.0 + "@react-native-harness/config": 1.0.0 tslib: ^2.3.0 peerDependencies: - react-native: "*" - checksum: dd0575341ed3c710b2c6f472a331d95aba0d9d7eb7277178a759836999af2d53dd05beb4e53fcfc240c9e1ccf8f5aa0ca53064ad55dfdfc2187db8b4a9b90bb5 + "@react-native-harness/runtime": 1.0.0 + metro: "*" + checksum: 7eb5f8fb50f25d0ce7f56bcadbab63a01ca40149e4f6b15071f237dd2f4853f89c5a2b3de8b624a76f2a601c1f8a6df7ea70891fb4ca8c6107a95f8e1e00288e languageName: node linkType: hard @@ -4358,50 +4487,59 @@ __metadata: languageName: node linkType: hard -"@react-native-harness/platform-apple@portal:/Users/boga/Work/Margelo/react-native-harness/packages/platform-ios::locator=%40rive-app%2Freact-native%40workspace%3A.": - version: 0.0.0-use.local - resolution: "@react-native-harness/platform-apple@portal:/Users/boga/Work/Margelo/react-native-harness/packages/platform-ios::locator=%40rive-app%2Freact-native%40workspace%3A." +"@react-native-harness/platform-apple@npm:1.0.0": + version: 1.0.0 + resolution: "@react-native-harness/platform-apple@npm:1.0.0" dependencies: - "@react-native-harness/config": "workspace:*" - "@react-native-harness/platforms": "workspace:*" - "@react-native-harness/tools": "workspace:*" + "@react-native-harness/platforms": 1.0.0 + "@react-native-harness/tools": 1.0.0 tslib: ^2.3.0 zod: ^3.25.67 + checksum: 30393748eaf9d7ef5aed5e0c9fdd1e758ad901b76387f3b659b2e74cc21dc6bf0a4535b49e397794e34d5f34da1fd230009fba8908dbcc1dce57d9f438a461f1 languageName: node - linkType: soft + linkType: hard -"@react-native-harness/platforms@portal:/Users/boga/Work/Margelo/react-native-harness/packages/platforms::locator=%40rive-app%2Freact-native%40workspace%3A.": - version: 0.0.0-use.local - resolution: "@react-native-harness/platforms@portal:/Users/boga/Work/Margelo/react-native-harness/packages/platforms::locator=%40rive-app%2Freact-native%40workspace%3A." +"@react-native-harness/platforms@npm:1.0.0": + version: 1.0.0 + resolution: "@react-native-harness/platforms@npm:1.0.0" dependencies: tslib: ^2.3.0 + checksum: 4bdf3d164481d6192b7bdd2c1436e15a9e9c14a7b05598ab301fc37ac6979153be5ac718dddcdae1ea879b65ddf047267bd4927a5fa758602569d51bd3c401b2 languageName: node - linkType: soft + linkType: hard -"@react-native-harness/plugins@portal:/Users/boga/Work/Margelo/react-native-harness/packages/plugins::locator=%40rive-app%2Freact-native%40workspace%3A.": - version: 0.0.0-use.local - resolution: "@react-native-harness/plugins@portal:/Users/boga/Work/Margelo/react-native-harness/packages/plugins::locator=%40rive-app%2Freact-native%40workspace%3A." +"@react-native-harness/runtime@npm:1.0.0": + version: 1.0.0 + resolution: "@react-native-harness/runtime@npm:1.0.0" dependencies: - "@react-native-harness/bridge": "workspace:*" - "@react-native-harness/platforms": "workspace:*" - "@react-native-harness/tools": "workspace:*" - hookable: ^6.1.0 - tslib: ^2.3.0 + "@react-native-harness/bridge": 1.0.0 + "@vitest/expect": 4.0.16 + "@vitest/spy": 4.0.16 + chai: ^6.2.2 + event-target-shim: ^6.0.2 + use-sync-external-store: ^1.6.0 + zustand: ^5.0.5 + peerDependencies: + react: "*" + react-native: "*" + checksum: ab7a15e0581e2d604e2bb3032fbfd8a81dc387c1914ccde3fbd24fb4783e71251916f41aa748782529cd47dd7df9061a0a08db0ff1aef55b859b3fb9a334fb0a languageName: node - linkType: soft + linkType: hard -"@react-native-harness/tools@portal:/Users/boga/Work/Margelo/react-native-harness/packages/tools::locator=%40rive-app%2Freact-native%40workspace%3A.": - version: 0.0.0-use.local - resolution: "@react-native-harness/tools@portal:/Users/boga/Work/Margelo/react-native-harness/packages/tools::locator=%40rive-app%2Freact-native%40workspace%3A." +"@react-native-harness/tools@npm:1.0.0": + version: 1.0.0 + resolution: "@react-native-harness/tools@npm:1.0.0" dependencies: "@clack/prompts": 1.0.0-alpha.9 + is-unicode-supported: ^0.1.0 nano-spawn: ^1.0.2 picocolors: ^1.1.1 tslib: ^2.3.0 peerDependencies: react-native: "*" + checksum: 3c897820164918f0fc18b90b8e02507d4006f93c4c3d2934d3bf9d829588a72fa99545be95df5b275648ebf2e871dd04295dbac9b41f64a1913eb37d865dd7de languageName: node - linkType: soft + linkType: hard "@react-native-picker/picker@npm:^2.11.4": version: 2.11.4 @@ -5418,6 +5556,13 @@ __metadata: languageName: node linkType: hard +"@standard-schema/spec@npm:^1.0.0": + version: 1.1.0 + resolution: "@standard-schema/spec@npm:1.1.0" + checksum: 6245ebef5e698bb04752a22e996a7cc40406a404d9f68a9d4e1a7a10f2422da287247508e7b495a2f32bb38f3d57b4daf2c9ab4bf22d9bca13e20a3dc5ec575e + languageName: node + linkType: hard + "@testing-library/react-hooks@npm:^8.0.1": version: 8.0.1 resolution: "@testing-library/react-hooks@npm:8.0.1" @@ -5528,6 +5673,16 @@ __metadata: languageName: node linkType: hard +"@types/chai@npm:^5.2.2": + version: 5.2.3 + resolution: "@types/chai@npm:5.2.3" + dependencies: + "@types/deep-eql": "*" + assertion-error: ^2.0.1 + checksum: eb4c2da9ec38b474a983f39bfb5ec4fbcceb5e5d76d184094d2cbc4c41357973eb5769c8972cedac665a233251b0ed754f1e338fcf408d381968af85cdecc596 + languageName: node + linkType: hard + "@types/conventional-commits-parser@npm:^5.0.0": version: 5.0.2 resolution: "@types/conventional-commits-parser@npm:5.0.2" @@ -5537,6 +5692,13 @@ __metadata: languageName: node linkType: hard +"@types/deep-eql@npm:*": + version: 4.0.2 + resolution: "@types/deep-eql@npm:4.0.2" + checksum: 249a27b0bb22f6aa28461db56afa21ec044fa0e303221a62dff81831b20c8530502175f1a49060f7099e7be06181078548ac47c668de79ff9880241968d43d0c + languageName: node + linkType: hard + "@types/deep-equal@npm:^1.0.4": version: 1.0.4 resolution: "@types/deep-equal@npm:1.0.4" @@ -5567,7 +5729,7 @@ __metadata: languageName: node linkType: hard -"@types/istanbul-lib-coverage@npm:*, @types/istanbul-lib-coverage@npm:^2.0.0, @types/istanbul-lib-coverage@npm:^2.0.1": +"@types/istanbul-lib-coverage@npm:*, @types/istanbul-lib-coverage@npm:^2.0.0, @types/istanbul-lib-coverage@npm:^2.0.1, @types/istanbul-lib-coverage@npm:^2.0.6": version: 2.0.6 resolution: "@types/istanbul-lib-coverage@npm:2.0.6" checksum: 3feac423fd3e5449485afac999dcfcb3d44a37c830af898b689fadc65d26526460bedb889db278e0d4d815a670331796494d073a10ee6e3a6526301fe7415778 @@ -5583,7 +5745,7 @@ __metadata: languageName: node linkType: hard -"@types/istanbul-reports@npm:^3.0.0": +"@types/istanbul-reports@npm:^3.0.0, @types/istanbul-reports@npm:^3.0.4": version: 3.0.4 resolution: "@types/istanbul-reports@npm:3.0.4" dependencies: @@ -5673,7 +5835,7 @@ __metadata: languageName: node linkType: hard -"@types/stack-utils@npm:^2.0.0": +"@types/stack-utils@npm:^2.0.0, @types/stack-utils@npm:^2.0.3": version: 2.0.3 resolution: "@types/stack-utils@npm:2.0.3" checksum: 72576cc1522090fe497337c2b99d9838e320659ac57fa5560fcbdcbafcf5d0216c6b3a0a8a4ee4fdb3b1f5e3420aa4f6223ab57b82fef3578bec3206425c6cf5 @@ -5696,6 +5858,15 @@ __metadata: languageName: node linkType: hard +"@types/yargs@npm:^17.0.33": + version: 17.0.35 + resolution: "@types/yargs@npm:17.0.35" + dependencies: + "@types/yargs-parser": "*" + checksum: ebf1f5373388cfcbf9cfb5e56ce7a77c0ba2450420f26f3701010ca92df48cce7e14e4245ed1f17178a38ff8702467a6f4047742775b8e2fd06dec8f4f3501ce + languageName: node + linkType: hard + "@types/yargs@npm:^17.0.8": version: 17.0.34 resolution: "@types/yargs@npm:17.0.34" @@ -6187,6 +6358,46 @@ __metadata: languageName: node linkType: hard +"@vitest/expect@npm:4.0.16": + version: 4.0.16 + resolution: "@vitest/expect@npm:4.0.16" + dependencies: + "@standard-schema/spec": ^1.0.0 + "@types/chai": ^5.2.2 + "@vitest/spy": 4.0.16 + "@vitest/utils": 4.0.16 + chai: ^6.2.1 + tinyrainbow: ^3.0.3 + checksum: cbd3a9e41ea3c8023cd0b02d0950e127f631e46960e84112e2a46984a8c530eb178d12f832e1abdb25854fe21d19770f08c2f4d0044fe9eaf2140ef0744b1972 + languageName: node + linkType: hard + +"@vitest/pretty-format@npm:4.0.16": + version: 4.0.16 + resolution: "@vitest/pretty-format@npm:4.0.16" + dependencies: + tinyrainbow: ^3.0.3 + checksum: cb457b056b1b1ba64d9b2a4d92edda9c7e437b705e048bfee054982e907c9838602193c60f98879d2c9a0f47efc000f5bc4ebda11aa983366bee9677883ad02e + languageName: node + linkType: hard + +"@vitest/spy@npm:4.0.16": + version: 4.0.16 + resolution: "@vitest/spy@npm:4.0.16" + checksum: ed729fe478b1fb8663c4d0e42c11a8cb85e49eff54f3b23790ff6d59158b6836c5b0733dcd77e235122d8f9a42ed9415a5a6861681373aacee824f5a73986a8e + languageName: node + linkType: hard + +"@vitest/utils@npm:4.0.16": + version: 4.0.16 + resolution: "@vitest/utils@npm:4.0.16" + dependencies: + "@vitest/pretty-format": 4.0.16 + tinyrainbow: ^3.0.3 + checksum: a7579d85bf7ae8ddec5c826008bfb7f4d702acb29432e20bb498643bafa3baa76c9ad7141de1e6a296092ff6661d3f3756922c31d2131721c7aafe3ad0dc06d8 + languageName: node + linkType: hard + "@vscode/sudo-prompt@npm:^9.0.0": version: 9.3.1 resolution: "@vscode/sudo-prompt@npm:9.3.1" @@ -6625,6 +6836,13 @@ __metadata: languageName: node linkType: hard +"assertion-error@npm:^2.0.1": + version: 2.0.1 + resolution: "assertion-error@npm:2.0.1" + checksum: a0789dd882211b87116e81e2648ccb7f60340b34f19877dd020b39ebb4714e475eb943e14ba3e22201c221ef6645b7bfe10297e76b6ac95b48a9898c1211ce66 + languageName: node + linkType: hard + "ast-types@npm:^0.13.4": version: 0.13.4 resolution: "ast-types@npm:0.13.4" @@ -6720,6 +6938,19 @@ __metadata: languageName: node linkType: hard +"babel-plugin-istanbul@npm:^7.0.1": + version: 7.0.1 + resolution: "babel-plugin-istanbul@npm:7.0.1" + dependencies: + "@babel/helper-plugin-utils": ^7.0.0 + "@istanbuljs/load-nyc-config": ^1.0.0 + "@istanbuljs/schema": ^0.1.3 + istanbul-lib-instrument: ^6.0.2 + test-exclude: ^6.0.0 + checksum: 06195af9022a1a2dad23bc4f2f9c226d053304889ae2be23a32aa3df821d2e61055a8eb533f204b10ee9899120e4f52bef6f0c4ab84a960cb2211cf638174aa2 + languageName: node + linkType: hard + "babel-plugin-jest-hoist@npm:^29.6.3": version: 29.6.3 resolution: "babel-plugin-jest-hoist@npm:29.6.3" @@ -7316,6 +7547,13 @@ __metadata: languageName: node linkType: hard +"chai@npm:^6.2.1, chai@npm:^6.2.2": + version: 6.2.2 + resolution: "chai@npm:6.2.2" + checksum: c8c94857745b673dae22a7b25053a41a931848e2c20d1acb6838cf99b7d57b0e66b9eb878c6308534b2965c11ae1a66f8c58066f368c91a07797bb8ee881a733 + languageName: node + linkType: hard + "chalk@npm:5.4.1": version: 5.4.1 resolution: "chalk@npm:5.4.1" @@ -7421,6 +7659,13 @@ __metadata: languageName: node linkType: hard +"ci-info@npm:^4.2.0": + version: 4.4.0 + resolution: "ci-info@npm:4.4.0" + checksum: 3418954c9ca192d4ab7f88637835f8463a327dfcb1d9fdd2434f0aba2715d8b2b0e79fd1a4297cc4a35efc5728f8fd74f3b31cb741c948469a4c07dfe8df3675 + languageName: node + linkType: hard + "cjs-module-lexer@npm:^1.0.0": version: 1.4.3 resolution: "cjs-module-lexer@npm:1.4.3" @@ -7553,7 +7798,7 @@ __metadata: languageName: node linkType: hard -"collect-v8-coverage@npm:^1.0.0": +"collect-v8-coverage@npm:^1.0.0, collect-v8-coverage@npm:^1.0.2": version: 1.0.3 resolution: "collect-v8-coverage@npm:1.0.3" checksum: ed1d1ebc9c05e7263fffa3ad6440031db6a1fdd9f574435aa689effcdfe9f2b93aba8ec600f9c7b99124cd6ff5d9415c17961d84ae829a72251a4fe668a49b63 @@ -9350,6 +9595,13 @@ __metadata: languageName: node linkType: hard +"event-target-shim@npm:^6.0.2": + version: 6.0.2 + resolution: "event-target-shim@npm:6.0.2" + checksum: 9be93437e5b84056a7dc70af8b8962f4ef7f6fd41a988efcd39dfa2853e33242a4058e0dac9cc589cb16ed7409010590ac8cbcc2e3f823100cd337e13be953a0 + languageName: node + linkType: hard + "exec-async@npm:^2.2.0": version: 2.2.0 resolution: "exec-async@npm:2.2.0" @@ -11104,13 +11356,6 @@ __metadata: languageName: node linkType: hard -"hookable@npm:^6.1.0": - version: 6.1.1 - resolution: "hookable@npm:6.1.1" - checksum: 552a61daa49e89767142f52f9a3f82243a9ef5e1e8cf18d92b9b4b4c9facd31fee053b030bed5a221e7f33c69a8f5be96a700c28b0b068ae729c5a31f9e12b3b - languageName: node - linkType: hard - "hosted-git-info@npm:^4.0.1": version: 4.1.0 resolution: "hosted-git-info@npm:4.1.0" @@ -12014,7 +12259,7 @@ __metadata: languageName: node linkType: hard -"istanbul-lib-instrument@npm:^6.0.0": +"istanbul-lib-instrument@npm:^6.0.0, istanbul-lib-instrument@npm:^6.0.2": version: 6.0.3 resolution: "istanbul-lib-instrument@npm:6.0.3" dependencies: @@ -12313,6 +12558,24 @@ __metadata: languageName: node linkType: hard +"jest-message-util@npm:30.4.1, jest-message-util@npm:^30.2.0": + version: 30.4.1 + resolution: "jest-message-util@npm:30.4.1" + dependencies: + "@babel/code-frame": ^7.27.1 + "@jest/types": 30.4.1 + "@types/stack-utils": ^2.0.3 + chalk: ^4.1.2 + graceful-fs: ^4.2.11 + jest-util: 30.4.1 + picomatch: ^4.0.3 + pretty-format: 30.4.1 + slash: ^3.0.0 + stack-utils: ^2.0.6 + checksum: 0361571c976e046d19569fa4d4617d1ef5926ed81710212869888059c5dd98ca13e77af2260fad2e756fe7041e1cf10f192cc0c38594b360643075dd42fa61c6 + languageName: node + linkType: hard + "jest-message-util@npm:^29.7.0": version: 29.7.0 resolution: "jest-message-util@npm:29.7.0" @@ -12353,6 +12616,13 @@ __metadata: languageName: node linkType: hard +"jest-regex-util@npm:30.4.0": + version: 30.4.0 + resolution: "jest-regex-util@npm:30.4.0" + checksum: 8664fcc1d07c8236a3bd012c0f06ae9d14d96e758b32ee340a3a7c4c326d0b5052d8c4ae4f4c4184f08bf78723d905352f22923647df9658ace3604f03bf074f + languageName: node + linkType: hard + "jest-regex-util@npm:^29.6.3": version: 29.6.3 resolution: "jest-regex-util@npm:29.6.3" @@ -12474,6 +12744,20 @@ __metadata: languageName: node linkType: hard +"jest-util@npm:30.4.1, jest-util@npm:^30.2.0": + version: 30.4.1 + resolution: "jest-util@npm:30.4.1" + dependencies: + "@jest/types": 30.4.1 + "@types/node": "*" + chalk: ^4.1.2 + ci-info: ^4.2.0 + graceful-fs: ^4.2.11 + picomatch: ^4.0.3 + checksum: 5b1b3e5cca87151f31dc9636a74ef2e78823f0bcd7e636a1bdc3e57645bf5970c01ff476db9156dea198984bd67415520c068bc5b3eddd464a2e6e9696308ecf + languageName: node + linkType: hard + "jest-util@npm:^29.7.0": version: 29.7.0 resolution: "jest-util@npm:29.7.0" @@ -14633,6 +14917,13 @@ __metadata: languageName: node linkType: hard +"nocache@npm:^4.0.0": + version: 4.0.0 + resolution: "nocache@npm:4.0.0" + checksum: ba317f7a5b837069c3bf8616c9a25f61bd5ec63ad7aa2ce83e8425116df402ab5b4914bbdfb1ba54893c0f859886cb3ad9a375f1c45ba7a72a9712cf31392292 + languageName: node + linkType: hard + "node-fetch@npm:^2.7.0": version: 2.7.0 resolution: "node-fetch@npm:2.7.0" @@ -15137,6 +15428,15 @@ __metadata: languageName: node linkType: hard +"p-limit@npm:^7.1.1": + version: 7.3.0 + resolution: "p-limit@npm:7.3.0" + dependencies: + yocto-queue: ^1.2.1 + checksum: bd3f3487ec84401e2cbf243122eef11813edacb621a27808e60a425646d0e75a79514acc2c01e39c41911550dbae5ef0f0ab01caa61cfc1c541cd17a19e8f01b + languageName: node + linkType: hard + "p-locate@npm:^4.1.0": version: 4.1.0 resolution: "p-locate@npm:4.1.0" @@ -15548,6 +15848,18 @@ __metadata: languageName: node linkType: hard +"pretty-format@npm:30.4.1": + version: 30.4.1 + resolution: "pretty-format@npm:30.4.1" + dependencies: + "@jest/schemas": 30.4.1 + ansi-styles: ^5.2.0 + react-is-18: "npm:react-is@^18.3.1" + react-is-19: "npm:react-is@^19.2.5" + checksum: 9602635027892d7a2f430b0a51972780226d30ce4072643349ad376ccee967539eb8180a656976976c0673d550604847da638b992eefc95c84bab7cebdf9faba + languageName: node + linkType: hard + "pretty-format@npm:^26.6.2": version: 26.6.2 resolution: "pretty-format@npm:26.6.2" @@ -15856,6 +16168,20 @@ __metadata: languageName: node linkType: hard +"react-is-18@npm:react-is@^18.3.1, react-is@npm:^18.0.0, react-is@npm:^18.3.1": + version: 18.3.1 + resolution: "react-is@npm:18.3.1" + checksum: e20fe84c86ff172fc8d898251b7cc2c43645d108bf96d0b8edf39b98f9a2cae97b40520ee7ed8ee0085ccc94736c4886294456033304151c3f94978cec03df21 + languageName: node + linkType: hard + +"react-is-19@npm:react-is@^19.2.5": + version: 19.2.6 + resolution: "react-is@npm:19.2.6" + checksum: aad99621b2e5c47ea715ab719a3caae60b6d2be828374dc5ad663372f4603ab26bde5f0c9f3efd6107ed9152dfff5f8f3df044121967a3280e00796e4c560635 + languageName: node + linkType: hard + "react-is@npm:^16.13.1, react-is@npm:^16.7.0": version: 16.13.1 resolution: "react-is@npm:16.13.1" @@ -15870,13 +16196,6 @@ __metadata: languageName: node linkType: hard -"react-is@npm:^18.0.0, react-is@npm:^18.3.1": - version: 18.3.1 - resolution: "react-is@npm:18.3.1" - checksum: e20fe84c86ff172fc8d898251b7cc2c43645d108bf96d0b8edf39b98f9a2cae97b40520ee7ed8ee0085ccc94736c4886294456033304151c3f94978cec03df21 - languageName: node - linkType: hard - "react-is@npm:^19.0.0, react-is@npm:^19.1.0": version: 19.2.0 resolution: "react-is@npm:19.2.0" @@ -15930,19 +16249,22 @@ __metadata: languageName: node linkType: hard -"react-native-harness@portal:/Users/boga/Work/Margelo/react-native-harness/packages/cli::locator=%40rive-app%2Freact-native%40workspace%3A.": - version: 0.0.0-use.local - resolution: "react-native-harness@portal:/Users/boga/Work/Margelo/react-native-harness/packages/cli::locator=%40rive-app%2Freact-native%40workspace%3A." +"react-native-harness@npm:1.0.0": + version: 1.0.0 + resolution: "react-native-harness@npm:1.0.0" dependencies: - "@react-native-harness/bridge": "workspace:*" - "@react-native-harness/config": "workspace:*" - "@react-native-harness/platforms": "workspace:*" - "@react-native-harness/tools": "workspace:*" + "@react-native-harness/babel-preset": 1.0.0 + "@react-native-harness/cli": 1.0.0 + "@react-native-harness/jest": 1.0.0 + "@react-native-harness/metro": 1.0.0 + "@react-native-harness/runtime": 1.0.0 tslib: ^2.3.0 - peerDependencies: - jest-cli: "*" + bin: + harness: bin.js + react-native-harness: bin.js + checksum: 737f1a13554cf1dcb199c93584c648703f47d15033b395c266cb611e2d09da7cefb7dbcc1501220eb2891097524d67d083cb197ec3d54e443452dfe56ba8decf languageName: node - linkType: soft + linkType: hard "react-native-is-edge-to-edge@npm:1.2.1, react-native-is-edge-to-edge@npm:^1.1.6, react-native-is-edge-to-edge@npm:^1.2.1": version: 1.2.1 @@ -16024,7 +16346,6 @@ __metadata: "@react-native-community/cli": 18.0.0 "@react-native-community/cli-platform-android": 18.0.0 "@react-native-community/cli-platform-ios": 18.0.0 - "@react-native-harness/coverage-ios": "file:/Users/boga/Work/Margelo/react-native-harness/packages/coverage-ios" "@react-native-harness/platform-android": 1.0.0 "@react-native-harness/platform-apple": 1.0.0 "@react-native-picker/picker": ^2.11.4 @@ -17466,7 +17787,7 @@ __metadata: languageName: node linkType: hard -"stack-utils@npm:^2.0.3": +"stack-utils@npm:^2.0.3, stack-utils@npm:^2.0.6": version: 2.0.6 resolution: "stack-utils@npm:2.0.6" dependencies: @@ -17968,6 +18289,13 @@ __metadata: languageName: node linkType: hard +"tinyrainbow@npm:^3.0.3": + version: 3.1.0 + resolution: "tinyrainbow@npm:3.1.0" + checksum: dbb16b4aa5dc7398d2501c6ee216471b01f5f1a3c372233113254625d190b08eb2cfb532f1bb46d2cce7deb1bc3d418945949898b7f95e32e09167f5c797cf0a + languageName: node + linkType: hard + "tmp@npm:^0.0.33": version: 0.0.33 resolution: "tmp@npm:0.0.33" @@ -18604,7 +18932,7 @@ __metadata: languageName: node linkType: hard -"use-sync-external-store@npm:^1.5.0": +"use-sync-external-store@npm:^1.5.0, use-sync-external-store@npm:^1.6.0": version: 1.6.0 resolution: "use-sync-external-store@npm:1.6.0" peerDependencies: @@ -19157,7 +19485,7 @@ __metadata: languageName: node linkType: hard -"yargs@npm:^17.0.0, yargs@npm:^17.3.1, yargs@npm:^17.5.1, yargs@npm:^17.6.2": +"yargs@npm:^17.0.0, yargs@npm:^17.3.1, yargs@npm:^17.5.1, yargs@npm:^17.6.2, yargs@npm:^17.7.2": version: 17.7.2 resolution: "yargs@npm:17.7.2" dependencies: @@ -19200,6 +19528,13 @@ __metadata: languageName: node linkType: hard +"yocto-queue@npm:^1.2.1": + version: 1.2.2 + resolution: "yocto-queue@npm:1.2.2" + checksum: 92dd9880c324dbc94ff4b677b7d350ba8d835619062b7102f577add7a59ab4d87f40edc5a03d77d369dfa9d11175b1b2ec4a06a6f8a5d8ce5d1306713f66ee41 + languageName: node + linkType: hard + "yoctocolors-cjs@npm:^2.1.1": version: 2.1.3 resolution: "yoctocolors-cjs@npm:2.1.3" @@ -19229,3 +19564,24 @@ __metadata: checksum: 91174acc7d2ca5572ad522643474ddd60640cf6877b5d76e5d583eb25e3c4072c6f5eb92ab94f231ec5ce61c6acdfc3e0166de45fb1005b1ea54986b026b765f languageName: node linkType: hard + +"zustand@npm:^5.0.5": + version: 5.0.13 + resolution: "zustand@npm:5.0.13" + peerDependencies: + "@types/react": ">=18.0.0" + immer: ">=9.0.6" + react: ">=18.0.0" + use-sync-external-store: ">=1.2.0" + peerDependenciesMeta: + "@types/react": + optional: true + immer: + optional: true + react: + optional: true + use-sync-external-store: + optional: true + checksum: 37f9c1eb888fc6c570f80a182a54844752ffe05dca75356273038effad642892df3a839f16733636a2dd4a49f68c02be27a37b9ba767af03515ef1f8d97468de + languageName: node + linkType: hard From 0d051d75cd5ef1e2b84af7110e22db993ffffa33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikl=C3=B3s=20Fazekas?= Date: Tue, 12 May 2026 09:12:44 +0200 Subject: [PATCH 3/3] feat: add worklet bridge for Reanimated shared value support Port from rive-app/rive-nitro-react-native#79. Adds RiveWorkletBridge HybridObject that installs Nitro's dispatcher on Reanimated's UI runtime, enabling ViewModel property listeners to drive SharedValues on the UI thread without blocking when JS is busy. Also bumps rive-ios to 6.20.2 and adds bouncing ball exerciser demo. --- RNRive.podspec | 8 +- android/CMakeLists.txt | 5 +- .../src/main/cpp/JRiveWorkletDispatcher.cpp | 81 +++++ .../src/main/cpp/JRiveWorkletDispatcher.hpp | 49 +++ android/src/main/cpp/cpp-adapter.cpp | 5 +- .../nitro/rive/RiveWorkletDispatcher.kt | 49 +++ cpp/HybridRiveWorkletBridge.hpp | 73 +++++ example/ios/Podfile.lock | 36 +- .../exercisers/RiveToReactNativeExample.tsx | 307 ++++++++++++++++++ nitro.json | 3 + .../generated/android/rive+autolinking.cmake | 1 + nitrogen/generated/android/riveOnLoad.cpp | 10 + nitrogen/generated/ios/RNRiveAutolinking.mm | 10 + .../c++/HybridRiveWorkletBridgeSpec.cpp | 21 ++ .../c++/HybridRiveWorkletBridgeSpec.hpp | 62 ++++ package.json | 2 +- src/core/WorkletBridge.ts | 44 +++ src/index.tsx | 2 + src/specs/RiveWorkletBridge.nitro.ts | 6 + 19 files changed, 738 insertions(+), 36 deletions(-) create mode 100644 android/src/main/cpp/JRiveWorkletDispatcher.cpp create mode 100644 android/src/main/cpp/JRiveWorkletDispatcher.hpp create mode 100644 android/src/main/java/com/margelo/nitro/rive/RiveWorkletDispatcher.kt create mode 100644 cpp/HybridRiveWorkletBridge.hpp create mode 100644 example/src/exercisers/RiveToReactNativeExample.tsx create mode 100644 nitrogen/generated/shared/c++/HybridRiveWorkletBridgeSpec.cpp create mode 100644 nitrogen/generated/shared/c++/HybridRiveWorkletBridgeSpec.hpp create mode 100644 src/core/WorkletBridge.ts create mode 100644 src/specs/RiveWorkletBridge.nitro.ts diff --git a/RNRive.podspec b/RNRive.podspec index d9fc63e3..5b281c2f 100644 --- a/RNRive.podspec +++ b/RNRive.podspec @@ -49,7 +49,7 @@ Pod::Spec.new do |s| s.platforms = { :ios => min_ios_version_supported } s.source = { :git => "https://github.com/rive-app/rive-nitro-react-native.git", :tag => "#{s.version}" } - s.source_files = "ios/**/*.{h,m,mm,swift}" + s.source_files = "ios/**/*.{h,m,mm,swift}", "cpp/**/*.{hpp,cpp}" if use_legacy s.exclude_files = ["ios/new/**"] @@ -58,6 +58,12 @@ Pod::Spec.new do |s| end s.public_header_files = ['ios/RCTSwiftLog.h'] + s.private_header_files = ['cpp/**/*.hpp'] + + s.pod_target_xcconfig = { + 'HEADER_SEARCH_PATHS' => '"$(PODS_TARGET_SRCROOT)/cpp"' + } + load 'nitrogen/generated/ios/RNRive+autolinking.rb' add_nitrogen_files(s) diff --git a/android/CMakeLists.txt b/android/CMakeLists.txt index 038c7a6e..8bbf93e1 100644 --- a/android/CMakeLists.txt +++ b/android/CMakeLists.txt @@ -6,7 +6,10 @@ set(CMAKE_VERBOSE_MAKEFILE ON) set(CMAKE_CXX_STANDARD 20) # Define C++ library and add all sources -add_library(${PACKAGE_NAME} SHARED src/main/cpp/cpp-adapter.cpp) +add_library(${PACKAGE_NAME} SHARED + src/main/cpp/cpp-adapter.cpp + src/main/cpp/JRiveWorkletDispatcher.cpp +) # Add Nitrogen specs :) include(${CMAKE_SOURCE_DIR}/../nitrogen/generated/android/rive+autolinking.cmake) diff --git a/android/src/main/cpp/JRiveWorkletDispatcher.cpp b/android/src/main/cpp/JRiveWorkletDispatcher.cpp new file mode 100644 index 00000000..f0745bfa --- /dev/null +++ b/android/src/main/cpp/JRiveWorkletDispatcher.cpp @@ -0,0 +1,81 @@ +#include "JRiveWorkletDispatcher.hpp" +#include + +namespace margelo::nitro::rive { + +using namespace facebook; + +JRiveWorkletDispatcher::JRiveWorkletDispatcher( + jni::alias_ref jThis) + : _javaPart(jni::make_global(jThis)) {} + +jni::local_ref JRiveWorkletDispatcher::initHybrid( + jni::alias_ref jThis) { + return makeCxxInstance(jThis); +} + +jni::local_ref JRiveWorkletDispatcher::create() { + return newObjectJavaArgs(); +} + +void JRiveWorkletDispatcher::trigger() { + std::unique_lock lock(_mutex); + while (!_jobs.empty()) { + auto job = std::move(_jobs.front()); + _jobs.pop(); + lock.unlock(); + job(); + lock.lock(); + } +} + +void JRiveWorkletDispatcher::scheduleTrigger() { + static const auto method = _javaPart->getClass()->getMethod("scheduleTrigger"); + method(_javaPart.get()); +} + +void JRiveWorkletDispatcher::runAsync(std::function&& function) { + std::unique_lock lock(_mutex); + _jobs.push(std::move(function)); + lock.unlock(); + scheduleTrigger(); +} + +void JRiveWorkletDispatcher::runSync(std::function&& function) { + std::mutex mtx; + std::condition_variable cv; + bool done = false; + + runAsync([&]() { + function(); + { + std::lock_guard lock(mtx); + done = true; + } + cv.notify_one(); + }); + + std::unique_lock lock(mtx); + cv.wait(lock, [&]{ return done; }); +} + +void JRiveWorkletDispatcher::registerNatives() { + registerHybrid({ + makeNativeMethod("initHybrid", JRiveWorkletDispatcher::initHybrid), + makeNativeMethod("trigger", JRiveWorkletDispatcher::trigger), + }); +} + +AndroidMainThreadDispatcher::AndroidMainThreadDispatcher( + jni::local_ref javaDispatcher) + : _javaDispatcher(jni::make_global(javaDispatcher)) {} + +void AndroidMainThreadDispatcher::runAsync(std::function&& function) { + _javaDispatcher->cthis()->runAsync(std::move(function)); +} + +void AndroidMainThreadDispatcher::runSync(std::function&& function) { + _javaDispatcher->cthis()->runSync(std::move(function)); +} + +} // namespace margelo::nitro::rive diff --git a/android/src/main/cpp/JRiveWorkletDispatcher.hpp b/android/src/main/cpp/JRiveWorkletDispatcher.hpp new file mode 100644 index 00000000..280d1dd4 --- /dev/null +++ b/android/src/main/cpp/JRiveWorkletDispatcher.hpp @@ -0,0 +1,49 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace margelo::nitro::rive { + +using namespace facebook; + +class JRiveWorkletDispatcher : public jni::HybridClass { +public: + static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/rive/RiveWorkletDispatcher;"; + + static jni::local_ref initHybrid(jni::alias_ref jThis); + static void registerNatives(); + + static jni::local_ref create(); + + void runAsync(std::function&& function); + void runSync(std::function&& function); + +private: + friend HybridBase; + + void trigger(); + void scheduleTrigger(); + + jni::global_ref _javaPart; + std::queue> _jobs; + std::recursive_mutex _mutex; + + explicit JRiveWorkletDispatcher(jni::alias_ref jThis); +}; + +class AndroidMainThreadDispatcher : public Dispatcher { +public: + explicit AndroidMainThreadDispatcher(jni::local_ref javaDispatcher); + + void runAsync(std::function&& function) override; + void runSync(std::function&& function) override; + +private: + jni::global_ref _javaDispatcher; +}; + +} // namespace margelo::nitro::rive diff --git a/android/src/main/cpp/cpp-adapter.cpp b/android/src/main/cpp/cpp-adapter.cpp index 5116d53c..4c5af328 100644 --- a/android/src/main/cpp/cpp-adapter.cpp +++ b/android/src/main/cpp/cpp-adapter.cpp @@ -1,6 +1,9 @@ #include #include "riveOnLoad.hpp" +#include "JRiveWorkletDispatcher.hpp" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) { - return margelo::nitro::rive::initialize(vm); + auto result = margelo::nitro::rive::initialize(vm); + margelo::nitro::rive::JRiveWorkletDispatcher::registerNatives(); + return result; } diff --git a/android/src/main/java/com/margelo/nitro/rive/RiveWorkletDispatcher.kt b/android/src/main/java/com/margelo/nitro/rive/RiveWorkletDispatcher.kt new file mode 100644 index 00000000..d6f08688 --- /dev/null +++ b/android/src/main/java/com/margelo/nitro/rive/RiveWorkletDispatcher.kt @@ -0,0 +1,49 @@ +package com.margelo.nitro.rive + +import android.os.Handler +import android.os.Looper +import androidx.annotation.Keep +import com.facebook.jni.HybridData +import com.facebook.proguard.annotations.DoNotStrip +import java.util.concurrent.atomic.AtomicBoolean + +@Suppress("JavaJniMissingFunction") +@Keep +@DoNotStrip +class RiveWorkletDispatcher { + @DoNotStrip + @Suppress("unused") + private val mHybridData: HybridData = initHybrid() + + private val mainHandler = Handler(Looper.getMainLooper()) + private val active = AtomicBoolean(true) + + private val triggerRunnable = Runnable { + synchronized(active) { + if (active.get()) { + trigger() + } + } + } + + private external fun initHybrid(): HybridData + private external fun trigger() + + @DoNotStrip + @Suppress("unused") + private fun scheduleTrigger() { + mainHandler.post(triggerRunnable) + } + + fun deactivate() { + synchronized(active) { + active.set(false) + } + } + + companion object { + init { + System.loadLibrary("rive") + } + } +} diff --git a/cpp/HybridRiveWorkletBridge.hpp b/cpp/HybridRiveWorkletBridge.hpp new file mode 100644 index 00000000..c9858f97 --- /dev/null +++ b/cpp/HybridRiveWorkletBridge.hpp @@ -0,0 +1,73 @@ +#pragma once + +#include "HybridRiveWorkletBridgeSpec.hpp" +#include + +#if __APPLE__ +#include +#include +#elif __ANDROID__ +#include "JRiveWorkletDispatcher.hpp" +#endif + +namespace margelo::nitro::rive { + +#if __APPLE__ + +class MainThreadDispatcher : public Dispatcher { +public: + void runAsync(std::function&& function) override { + __block auto func = std::move(function); + dispatch_async(dispatch_get_main_queue(), ^{ + func(); + }); + } + + void runSync(std::function&& function) override { + if (pthread_main_np() != 0) { + function(); + } else { + __block auto func = std::move(function); + dispatch_sync(dispatch_get_main_queue(), ^{ + func(); + }); + } + } +}; + +#endif + +class HybridRiveWorkletBridge : public HybridRiveWorkletBridgeSpec { +public: + HybridRiveWorkletBridge() : HybridObject(TAG) {} + + void install() override { + throw std::runtime_error("install() requires runtime access - use raw method"); + } + +protected: + void loadHybridMethods() override { + HybridObject::loadHybridMethods(); + registerHybrids(this, [](Prototype& prototype) { + prototype.registerRawHybridMethod("install", 0, &HybridRiveWorkletBridge::installRaw); + }); + } + +private: + jsi::Value installRaw(jsi::Runtime& runtime, + const jsi::Value& thisValue, + const jsi::Value* args, + size_t count) { +#if __APPLE__ + auto dispatcher = std::make_shared(); + Dispatcher::installRuntimeGlobalDispatcher(runtime, dispatcher); +#elif __ANDROID__ + auto javaDispatcher = JRiveWorkletDispatcher::create(); + auto dispatcher = std::make_shared(javaDispatcher); + Dispatcher::installRuntimeGlobalDispatcher(runtime, dispatcher); +#endif + return jsi::Value::undefined(); + } +}; + +} // namespace margelo::nitro::rive diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 55309244..9ad72999 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -5,30 +5,6 @@ PODS: - FBLazyVector (0.79.2) - fmt (11.0.2) - glog (0.3.5) - - HarnessCoverage (1.0.0): - - DoubleConversion - - glog - - hermes-engine - - RCT-Folly (= 2024.11.18.00) - - RCTRequired - - RCTTypeSafety - - React-Core - - React-debug - - React-Fabric - - React-featureflags - - React-graphics - - React-hermes - - React-ImageManager - - React-jsi - - React-NativeModulesApple - - React-RCTFabric - - React-renderercss - - React-rendererdebug - - React-utils - - ReactCodegen - - ReactCommon/turbomodule/bridging - - ReactCommon/turbomodule/core - - Yoga - hermes-engine (0.79.2): - hermes-engine/Pre-built (= 0.79.2) - hermes-engine/Pre-built (0.79.2) @@ -1778,7 +1754,7 @@ PODS: - React-logger (= 0.79.2) - React-perflogger (= 0.79.2) - React-utils (= 0.79.2) - - RiveRuntime (6.20.0) + - RiveRuntime (6.20.2) - RNCAsyncStorage (2.2.0): - DoubleConversion - glog @@ -1952,7 +1928,7 @@ PODS: - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - RiveRuntime (= 6.20.0) + - RiveRuntime (= 6.20.2) - Yoga - RNScreens (4.18.0): - DoubleConversion @@ -2089,7 +2065,6 @@ DEPENDENCIES: - FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`) - fmt (from `../node_modules/react-native/third-party-podspecs/fmt.podspec`) - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`) - - "HarnessCoverage (from `../node_modules/@react-native-harness/coverage-ios`)" - hermes-engine (from `../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`) - NitroModules (from `../node_modules/react-native-nitro-modules`) - RCT-Folly (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`) @@ -2184,8 +2159,6 @@ EXTERNAL SOURCES: :podspec: "../node_modules/react-native/third-party-podspecs/fmt.podspec" glog: :podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec" - HarnessCoverage: - :path: "../node_modules/@react-native-harness/coverage-ios" hermes-engine: :podspec: "../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec" :tag: hermes-2025-03-03-RNv0.79.0-bc17d964d03743424823d7dd1a9f37633459c5c5 @@ -2341,7 +2314,6 @@ SPEC CHECKSUMS: FBLazyVector: 84b955f7b4da8b895faf5946f73748267347c975 fmt: a40bb5bd0294ea969aaaba240a927bd33d878cdd glog: 5683914934d5b6e4240e497e0f4a3b42d1854183 - HarnessCoverage: d3740d6a473a386e0aee01211139f0fe3f8a2cb0 hermes-engine: 314be5250afa5692b57b4dd1705959e1973a8ebe NitroModules: b0d4f5ca592f60889181c15f82cca77d62e44a08 RCT-Folly: 36fe2295e44b10d831836cc0d1daec5f8abcf809 @@ -2407,12 +2379,12 @@ SPEC CHECKSUMS: ReactAppDependencyProvider: 04d5eb15eb46be6720e17a4a7fa92940a776e584 ReactCodegen: c63eda03ba1d94353fb97b031fc84f75a0d125ba ReactCommon: 76d2dc87136d0a667678668b86f0fca0c16fdeb0 - RiveRuntime: 12f860505e052a8b48c580f35f1d5d5cad6709b7 + RiveRuntime: 1ebd6b5f43d53e62639ebb7c4c66f3071630de53 RNCAsyncStorage: a1c8cc8a99c32de1244a9cf707bf9d83d0de0f71 RNCPicker: 28c076ae12a1056269ec0305fe35fac3086c477d RNGestureHandler: 6b39f4e43e4b3a0fb86de9531d090ff205a011d5 RNReanimated: 66b68ebe3baf7ec9e716bd059d700726f250d344 - RNRive: 9da1409806521455260c8b78b6ab401afdd3df3f + RNRive: bd6209e790de3978d6aee4e30ded1a9cfacbc1ec RNScreens: f38464ec1e83bda5820c3b05ccf4908e3841c5cc RNWorklets: b1faafefb82d9f29c4018404a0fb33974b494a7b SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748 diff --git a/example/src/exercisers/RiveToReactNativeExample.tsx b/example/src/exercisers/RiveToReactNativeExample.tsx new file mode 100644 index 00000000..6eec4f5a --- /dev/null +++ b/example/src/exercisers/RiveToReactNativeExample.tsx @@ -0,0 +1,307 @@ +import { + View, + Text, + StyleSheet, + ActivityIndicator, + Pressable, + Switch, +} from 'react-native'; +import { useEffect, useMemo, useState } from 'react'; +import Animated, { + runOnUI, + useSharedValue, + useAnimatedStyle, + type SharedValue, +} from 'react-native-reanimated'; +import { NitroModules } from 'react-native-nitro-modules'; +import { + Fit, + RiveView, + useRiveFile, + installWorkletDispatcher, + type RiveFile, + type ViewModelInstance, + type ViewModelNumberProperty, +} from '@rive-app/react-native'; +import { type Metadata } from '../shared/metadata'; + +declare global { + var __callMicrotasks: () => void; +} + +installWorkletDispatcher(runOnUI); + +function useRiveNumberListener( + property: ViewModelNumberProperty | undefined, + sharedValue: SharedValue, + useUIThread: boolean +) { + useEffect(() => { + if (!property) return; + + if (useUIThread) { + const boxedProperty = NitroModules.box(property); + const sv = sharedValue; + + runOnUI(() => { + 'worklet'; + const prop = boxedProperty.unbox(); + prop.addListener((value: number) => { + 'worklet'; + sv.value = value; + global.__callMicrotasks(); + }); + })(); + + return () => { + property.removeListeners(); + }; + } else { + const removeListener = property.addListener((value: number) => { + sharedValue.value = value; + }); + + return removeListener; + } + }, [property, sharedValue, useUIThread]); +} + +export default function RiveToReactNativeExample() { + const { riveFile, isLoading, error } = useRiveFile( + require('../../assets/rive/bouncing_ball.riv') + ); + + return ( + + {isLoading ? ( + + ) : riveFile ? ( + + ) : ( + {error?.message || 'Unexpected error'} + )} + + ); +} + +function WithViewModelSetup({ file }: { file: RiveFile }) { + const viewModel = useMemo(() => file.defaultArtboardViewModel(), [file]); + const instance = useMemo( + () => viewModel?.createDefaultInstance(), + [viewModel] + ); + const [useUIThread, setUseUIThread] = useState(true); + + if (!instance || !viewModel) { + return ( + + + {!viewModel + ? 'No view model found.' + : 'Failed to create view model instance'} + + + ); + } + + return ( + + ); +} + +function BouncingBallTracker({ + instance, + file, + useUIThread, + onToggle, +}: { + instance: ViewModelInstance; + file: RiveFile; + useUIThread: boolean; + onToggle: (value: boolean) => void; +}) { + const pointerY = useSharedValue(0); + + const yposProperty = useMemo( + () => instance.numberProperty('ypos'), + [instance] + ); + + useRiveNumberListener(yposProperty, pointerY, useUIThread); + + const pointerStyle = useAnimatedStyle(() => ({ + transform: [{ translateY: pointerY.value }], + })); + + if (!yposProperty) { + return ( + + Property "ypos" not found + + ); + } + + return ( + + + Rive drives the ball position via data binding.{'\n'}React Native tracks + it with the blue pointer using addListener. + + + + JS Thread + + UI Thread + + + + + + + RN + + + + + + ); +} + +function BlockJSThreadButton() { + const [isBlocking, setIsBlocking] = useState(false); + + const handlePress = () => { + setIsBlocking(true); + setTimeout(() => { + const start = Date.now(); + while (Date.now() - start < 2000) { + // Busy poll - blocks JS thread for 2 seconds + } + setIsBlocking(false); + }, 50); + }; + + return ( + + + {isBlocking ? 'JS Thread Blocked...' : 'Block JS Thread (2s)'} + + + ); +} + +RiveToReactNativeExample.metadata = { + name: 'Rive to React Native', + description: + 'Rive animation driving React Native UI via data binding listeners with Reanimated SharedValues', +} satisfies Metadata; + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: '#fff', + alignItems: 'center', + }, + errorContainer: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + padding: 20, + }, + subtitle: { + fontSize: 14, + color: '#666', + textAlign: 'center', + marginVertical: 10, + paddingHorizontal: 20, + }, + switchContainer: { + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'center', + gap: 10, + marginBottom: 10, + }, + switchLabel: { + fontSize: 14, + color: '#333', + }, + contentContainer: { + position: 'relative', + height: 600, + width: 200, + alignItems: 'center', + justifyContent: 'center', + borderWidth: 1, + borderColor: '#ccc', + }, + rive: { + width: 100, + height: 600, + }, + pointer: { + position: 'absolute', + top: -10, + right: 40, + flexDirection: 'row', + alignItems: 'center', + }, + pointerArrow: { + width: 0, + height: 0, + borderTopWidth: 10, + borderBottomWidth: 10, + borderRightWidth: 15, + borderTopColor: 'transparent', + borderBottomColor: 'transparent', + borderRightColor: '#007AFF', + }, + pointerText: { + backgroundColor: '#007AFF', + color: '#fff', + fontSize: 12, + fontWeight: 'bold', + paddingHorizontal: 6, + paddingVertical: 4, + borderTopRightRadius: 4, + borderBottomRightRadius: 4, + }, + errorText: { + color: 'red', + textAlign: 'center', + fontSize: 16, + fontWeight: 'bold', + marginBottom: 10, + }, + blockButton: { + backgroundColor: '#4CAF50', + paddingHorizontal: 20, + paddingVertical: 12, + borderRadius: 8, + marginTop: 20, + alignSelf: 'center', + }, + blockButtonActive: { + backgroundColor: '#f44336', + }, + blockButtonText: { + color: '#fff', + fontSize: 16, + fontWeight: 'bold', + }, +}); diff --git a/nitro.json b/nitro.json index 2eef00ab..c086f80c 100644 --- a/nitro.json +++ b/nitro.json @@ -36,6 +36,9 @@ "RiveLogger": { "swift": "HybridRiveLogger", "kotlin": "HybridRiveLogger" + }, + "RiveWorkletBridge": { + "cpp": "HybridRiveWorkletBridge" } }, "ignorePaths": ["node_modules"] diff --git a/nitrogen/generated/android/rive+autolinking.cmake b/nitrogen/generated/android/rive+autolinking.cmake index ffe01178..0ebd3875 100644 --- a/nitrogen/generated/android/rive+autolinking.cmake +++ b/nitrogen/generated/android/rive+autolinking.cmake @@ -56,6 +56,7 @@ target_sources( ../nitrogen/generated/shared/c++/HybridViewModelImagePropertySpec.cpp ../nitrogen/generated/shared/c++/HybridViewModelListPropertySpec.cpp ../nitrogen/generated/shared/c++/HybridViewModelArtboardPropertySpec.cpp + ../nitrogen/generated/shared/c++/HybridRiveWorkletBridgeSpec.cpp # Android-specific Nitrogen C++ sources ../nitrogen/generated/android/c++/JHybridBindableArtboardSpec.cpp ../nitrogen/generated/android/c++/JHybridRiveFileSpec.cpp diff --git a/nitrogen/generated/android/riveOnLoad.cpp b/nitrogen/generated/android/riveOnLoad.cpp index e98e5b0c..b0164edd 100644 --- a/nitrogen/generated/android/riveOnLoad.cpp +++ b/nitrogen/generated/android/riveOnLoad.cpp @@ -45,6 +45,7 @@ #include "JHybridViewModelImagePropertySpec.hpp" #include "JHybridViewModelListPropertySpec.hpp" #include "JHybridViewModelArtboardPropertySpec.hpp" +#include "HybridRiveWorkletBridge.hpp" #include namespace margelo::nitro::rive { @@ -191,6 +192,15 @@ void registerAllNatives() { return JHybridRiveLoggerSpecImpl::create(); } ); + HybridObjectRegistry::registerHybridObjectConstructor( + "RiveWorkletBridge", + []() -> std::shared_ptr { + static_assert(std::is_default_constructible_v, + "The HybridObject \"HybridRiveWorkletBridge\" is not default-constructible! " + "Create a public constructor that takes zero arguments to be able to autolink this HybridObject."); + return std::make_shared(); + } + ); } } // namespace margelo::nitro::rive diff --git a/nitrogen/generated/ios/RNRiveAutolinking.mm b/nitrogen/generated/ios/RNRiveAutolinking.mm index e753f6dc..7e2ccf0a 100644 --- a/nitrogen/generated/ios/RNRiveAutolinking.mm +++ b/nitrogen/generated/ios/RNRiveAutolinking.mm @@ -17,6 +17,7 @@ #include "HybridRiveImageFactorySpecSwift.hpp" #include "HybridRiveRuntimeSpecSwift.hpp" #include "HybridRiveLoggerSpecSwift.hpp" +#include "HybridRiveWorkletBridge.hpp" @interface RNRiveAutolinking : NSObject @end @@ -76,6 +77,15 @@ + (void) load { return hybridObject; } ); + HybridObjectRegistry::registerHybridObjectConstructor( + "RiveWorkletBridge", + []() -> std::shared_ptr { + static_assert(std::is_default_constructible_v, + "The HybridObject \"HybridRiveWorkletBridge\" is not default-constructible! " + "Create a public constructor that takes zero arguments to be able to autolink this HybridObject."); + return std::make_shared(); + } + ); } @end diff --git a/nitrogen/generated/shared/c++/HybridRiveWorkletBridgeSpec.cpp b/nitrogen/generated/shared/c++/HybridRiveWorkletBridgeSpec.cpp new file mode 100644 index 00000000..aa30c195 --- /dev/null +++ b/nitrogen/generated/shared/c++/HybridRiveWorkletBridgeSpec.cpp @@ -0,0 +1,21 @@ +/// +/// HybridRiveWorkletBridgeSpec.cpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +#include "HybridRiveWorkletBridgeSpec.hpp" + +namespace margelo::nitro::rive { + + void HybridRiveWorkletBridgeSpec::loadHybridMethods() { + // load base methods/properties + HybridObject::loadHybridMethods(); + // load custom methods/properties + registerHybrids(this, [](Prototype& prototype) { + prototype.registerHybridMethod("install", &HybridRiveWorkletBridgeSpec::install); + }); + } + +} // namespace margelo::nitro::rive diff --git a/nitrogen/generated/shared/c++/HybridRiveWorkletBridgeSpec.hpp b/nitrogen/generated/shared/c++/HybridRiveWorkletBridgeSpec.hpp new file mode 100644 index 00000000..014acec2 --- /dev/null +++ b/nitrogen/generated/shared/c++/HybridRiveWorkletBridgeSpec.hpp @@ -0,0 +1,62 @@ +/// +/// HybridRiveWorkletBridgeSpec.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +#pragma once + +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif + + + + + +namespace margelo::nitro::rive { + + using namespace margelo::nitro; + + /** + * An abstract base class for `RiveWorkletBridge` + * Inherit this class to create instances of `HybridRiveWorkletBridgeSpec` in C++. + * You must explicitly call `HybridObject`'s constructor yourself, because it is virtual. + * @example + * ```cpp + * class HybridRiveWorkletBridge: public HybridRiveWorkletBridgeSpec { + * public: + * HybridRiveWorkletBridge(...): HybridObject(TAG) { ... } + * // ... + * }; + * ``` + */ + class HybridRiveWorkletBridgeSpec: public virtual HybridObject { + public: + // Constructor + explicit HybridRiveWorkletBridgeSpec(): HybridObject(TAG) { } + + // Destructor + ~HybridRiveWorkletBridgeSpec() override = default; + + public: + // Properties + + + public: + // Methods + virtual void install() = 0; + + protected: + // Hybrid Setup + void loadHybridMethods() override; + + protected: + // Tag for logging + static constexpr auto TAG = "RiveWorkletBridge"; + }; + +} // namespace margelo::nitro::rive diff --git a/package.json b/package.json index a086f296..cb019e0b 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ }, "homepage": "https://github.com/rive-app/rive-nitro-react-native#readme", "runtimeVersions": { - "ios": "6.20.0", + "ios": "6.20.2", "android": "11.4.1" }, "publishConfig": { diff --git a/src/core/WorkletBridge.ts b/src/core/WorkletBridge.ts new file mode 100644 index 00000000..29bc45a8 --- /dev/null +++ b/src/core/WorkletBridge.ts @@ -0,0 +1,44 @@ +import { NitroModules } from 'react-native-nitro-modules'; +import type { RiveWorkletBridge } from '../specs/RiveWorkletBridge.nitro'; + +let isInstalled = false; + +/** + * Install the Nitro Dispatcher on Reanimated's UI runtime. + * This enables using HybridObject callbacks (like addListener) from worklets + * and having shared value updates trigger useAnimatedStyle. + * + * Call this once at app startup. It will schedule the installation on the UI thread. + * + * @param runOnUI - The runOnUI function from react-native-reanimated + * + * @example + * ```tsx + * import { installWorkletDispatcher } from '@rive-app/react-native'; + * import { runOnUI } from 'react-native-reanimated'; + * + * // Call once at app startup + * installWorkletDispatcher(runOnUI); + * ``` + */ +export function installWorkletDispatcher( + runOnUI: ( + worklet: (...args: Args) => ReturnValue + ) => (...args: Args) => void +): void { + if (isInstalled) { + return; + } + isInstalled = true; + + const bridge = + NitroModules.createHybridObject('RiveWorkletBridge'); + + const boxedBridge = NitroModules.box(bridge); + + runOnUI(() => { + 'worklet'; + const b = boxedBridge.unbox(); + b.install(); + })(); +} diff --git a/src/index.tsx b/src/index.tsx index 062b44ce..de61f470 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -70,3 +70,5 @@ export { type SetValueAction } from './types'; export { RiveRuntime } from './core/RiveRuntime'; export { RiveLog, type RiveLogLevel } from './core/RiveLogger'; export { DataBindMode }; +export { installWorkletDispatcher } from './core/WorkletBridge'; +export type { RiveWorkletBridge } from './specs/RiveWorkletBridge.nitro'; diff --git a/src/specs/RiveWorkletBridge.nitro.ts b/src/specs/RiveWorkletBridge.nitro.ts new file mode 100644 index 00000000..9124cffc --- /dev/null +++ b/src/specs/RiveWorkletBridge.nitro.ts @@ -0,0 +1,6 @@ +import type { HybridObject } from 'react-native-nitro-modules'; + +export interface RiveWorkletBridge + extends HybridObject<{ ios: 'c++'; android: 'c++' }> { + install(): void; +}