@rive-app/react-native 0.1.1-beta.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -7
- package/android/src/main/java/com/margelo/nitro/rive/BaseHybridViewModelProperty.kt +9 -7
- package/android/src/main/java/com/margelo/nitro/rive/BaseHybridViewModelPropertyImpl.kt +43 -24
- package/android/src/main/java/com/margelo/nitro/rive/HybridRiveFile.kt +0 -1
- package/android/src/main/java/com/margelo/nitro/rive/HybridViewModelBooleanProperty.kt +3 -2
- package/android/src/main/java/com/margelo/nitro/rive/HybridViewModelColorProperty.kt +3 -2
- package/android/src/main/java/com/margelo/nitro/rive/HybridViewModelEnumProperty.kt +3 -2
- package/android/src/main/java/com/margelo/nitro/rive/HybridViewModelImageProperty.kt +3 -2
- package/android/src/main/java/com/margelo/nitro/rive/HybridViewModelInstance.kt +26 -47
- package/android/src/main/java/com/margelo/nitro/rive/HybridViewModelListProperty.kt +64 -0
- package/android/src/main/java/com/margelo/nitro/rive/HybridViewModelNumberProperty.kt +3 -2
- package/android/src/main/java/com/margelo/nitro/rive/HybridViewModelStringProperty.kt +3 -2
- package/android/src/main/java/com/margelo/nitro/rive/HybridViewModelTriggerProperty.kt +3 -2
- package/ios/BaseHybridViewModelProperty.swift +22 -6
- package/ios/HybridViewModel.swift +1 -6
- package/ios/HybridViewModelBooleanProperty.swift +1 -9
- package/ios/HybridViewModelColorProperty.swift +3 -12
- package/ios/HybridViewModelEnumProperty.swift +1 -9
- package/ios/HybridViewModelImageProperty.swift +4 -4
- package/ios/HybridViewModelInstance.swift +6 -6
- package/ios/HybridViewModelListProperty.swift +62 -0
- package/ios/HybridViewModelNumberProperty.swift +2 -13
- package/ios/HybridViewModelStringProperty.swift +1 -9
- package/ios/HybridViewModelTriggerProperty.swift +5 -14
- package/ios/RiveReactNativeView.swift +36 -0
- package/lib/module/hooks/useRiveColor.js +0 -1
- package/lib/module/hooks/useRiveColor.js.map +1 -1
- package/lib/module/hooks/useRiveList.js +71 -0
- package/lib/module/hooks/useRiveList.js.map +1 -0
- package/lib/module/hooks/useRiveProperty.js +6 -12
- package/lib/module/hooks/useRiveProperty.js.map +1 -1
- package/lib/module/hooks/useViewModelInstance.js +139 -0
- package/lib/module/hooks/useViewModelInstance.js.map +1 -0
- package/lib/module/index.js +2 -0
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/hooks/useRiveColor.d.ts +6 -4
- package/lib/typescript/src/hooks/useRiveColor.d.ts.map +1 -1
- package/lib/typescript/src/hooks/useRiveList.d.ts +11 -0
- package/lib/typescript/src/hooks/useRiveList.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useRiveProperty.d.ts +6 -1
- package/lib/typescript/src/hooks/useRiveProperty.d.ts.map +1 -1
- package/lib/typescript/src/hooks/useViewModelInstance.d.ts +86 -0
- package/lib/typescript/src/hooks/useViewModelInstance.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +4 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/specs/ViewModel.nitro.d.ts +39 -15
- package/lib/typescript/src/specs/ViewModel.nitro.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +47 -3
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/nitrogen/generated/android/c++/JHybridViewModelBooleanPropertySpec.cpp +14 -4
- package/nitrogen/generated/android/c++/JHybridViewModelBooleanPropertySpec.hpp +1 -1
- package/nitrogen/generated/android/c++/JHybridViewModelColorPropertySpec.cpp +14 -4
- package/nitrogen/generated/android/c++/JHybridViewModelColorPropertySpec.hpp +1 -1
- package/nitrogen/generated/android/c++/JHybridViewModelEnumPropertySpec.cpp +14 -4
- package/nitrogen/generated/android/c++/JHybridViewModelEnumPropertySpec.hpp +1 -1
- package/nitrogen/generated/android/c++/JHybridViewModelImagePropertySpec.cpp +15 -6
- package/nitrogen/generated/android/c++/JHybridViewModelImagePropertySpec.hpp +1 -1
- package/nitrogen/generated/android/c++/JHybridViewModelInstanceSpec.cpp +9 -0
- package/nitrogen/generated/android/c++/JHybridViewModelInstanceSpec.hpp +1 -0
- package/nitrogen/generated/android/c++/JHybridViewModelListPropertySpec.cpp +102 -0
- package/nitrogen/generated/android/c++/JHybridViewModelListPropertySpec.hpp +73 -0
- package/nitrogen/generated/android/c++/JHybridViewModelNumberPropertySpec.cpp +14 -4
- package/nitrogen/generated/android/c++/JHybridViewModelNumberPropertySpec.hpp +1 -1
- package/nitrogen/generated/android/c++/JHybridViewModelStringPropertySpec.cpp +14 -4
- package/nitrogen/generated/android/c++/JHybridViewModelStringPropertySpec.hpp +1 -1
- package/nitrogen/generated/android/c++/JHybridViewModelTriggerPropertySpec.cpp +12 -3
- package/nitrogen/generated/android/c++/JHybridViewModelTriggerPropertySpec.hpp +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/rive/HybridViewModelBooleanPropertySpec.kt +3 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/rive/HybridViewModelColorPropertySpec.kt +3 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/rive/HybridViewModelEnumPropertySpec.kt +3 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/rive/HybridViewModelImagePropertySpec.kt +3 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/rive/HybridViewModelInstanceSpec.kt +4 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/rive/HybridViewModelListPropertySpec.kt +92 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/rive/HybridViewModelNumberPropertySpec.kt +3 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/rive/HybridViewModelStringPropertySpec.kt +3 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/rive/HybridViewModelTriggerPropertySpec.kt +3 -3
- package/nitrogen/generated/android/rive+autolinking.cmake +2 -0
- package/nitrogen/generated/android/riveOnLoad.cpp +4 -74
- package/nitrogen/generated/ios/RNRive-Swift-Cxx-Bridge.cpp +17 -0
- package/nitrogen/generated/ios/RNRive-Swift-Cxx-Bridge.hpp +53 -0
- package/nitrogen/generated/ios/RNRive-Swift-Cxx-Umbrella.hpp +5 -0
- package/nitrogen/generated/ios/RNRiveAutolinking.mm +0 -72
- package/nitrogen/generated/ios/RNRiveAutolinking.swift +0 -135
- package/nitrogen/generated/ios/c++/HybridViewModelBooleanPropertySpecSwift.hpp +3 -1
- package/nitrogen/generated/ios/c++/HybridViewModelColorPropertySpecSwift.hpp +3 -1
- package/nitrogen/generated/ios/c++/HybridViewModelEnumPropertySpecSwift.hpp +3 -1
- package/nitrogen/generated/ios/c++/HybridViewModelImagePropertySpecSwift.hpp +3 -1
- package/nitrogen/generated/ios/c++/HybridViewModelInstanceSpecSwift.hpp +11 -0
- package/nitrogen/generated/ios/c++/HybridViewModelListPropertySpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridViewModelListPropertySpecSwift.hpp +134 -0
- package/nitrogen/generated/ios/c++/HybridViewModelNumberPropertySpecSwift.hpp +3 -1
- package/nitrogen/generated/ios/c++/HybridViewModelStringPropertySpecSwift.hpp +3 -1
- package/nitrogen/generated/ios/c++/HybridViewModelTriggerPropertySpecSwift.hpp +3 -1
- package/nitrogen/generated/ios/swift/HybridViewModelBooleanPropertySpec.swift +1 -1
- package/nitrogen/generated/ios/swift/HybridViewModelBooleanPropertySpec_cxx.swift +8 -4
- package/nitrogen/generated/ios/swift/HybridViewModelColorPropertySpec.swift +1 -1
- package/nitrogen/generated/ios/swift/HybridViewModelColorPropertySpec_cxx.swift +8 -4
- package/nitrogen/generated/ios/swift/HybridViewModelEnumPropertySpec.swift +1 -1
- package/nitrogen/generated/ios/swift/HybridViewModelEnumPropertySpec_cxx.swift +8 -4
- package/nitrogen/generated/ios/swift/HybridViewModelImagePropertySpec.swift +1 -1
- package/nitrogen/generated/ios/swift/HybridViewModelImagePropertySpec_cxx.swift +8 -4
- package/nitrogen/generated/ios/swift/HybridViewModelInstanceSpec.swift +1 -0
- package/nitrogen/generated/ios/swift/HybridViewModelInstanceSpec_cxx.swift +21 -0
- package/nitrogen/generated/ios/swift/HybridViewModelListPropertySpec.swift +63 -0
- package/nitrogen/generated/ios/swift/HybridViewModelListPropertySpec_cxx.swift +248 -0
- package/nitrogen/generated/ios/swift/HybridViewModelNumberPropertySpec.swift +1 -1
- package/nitrogen/generated/ios/swift/HybridViewModelNumberPropertySpec_cxx.swift +8 -4
- package/nitrogen/generated/ios/swift/HybridViewModelStringPropertySpec.swift +1 -1
- package/nitrogen/generated/ios/swift/HybridViewModelStringPropertySpec_cxx.swift +8 -4
- package/nitrogen/generated/ios/swift/HybridViewModelTriggerPropertySpec.swift +1 -1
- package/nitrogen/generated/ios/swift/HybridViewModelTriggerPropertySpec_cxx.swift +8 -4
- package/nitrogen/generated/shared/c++/HybridViewModelBooleanPropertySpec.hpp +1 -1
- package/nitrogen/generated/shared/c++/HybridViewModelColorPropertySpec.hpp +1 -1
- package/nitrogen/generated/shared/c++/HybridViewModelEnumPropertySpec.hpp +1 -1
- package/nitrogen/generated/shared/c++/HybridViewModelImagePropertySpec.hpp +1 -1
- package/nitrogen/generated/shared/c++/HybridViewModelInstanceSpec.cpp +1 -0
- package/nitrogen/generated/shared/c++/HybridViewModelInstanceSpec.hpp +4 -0
- package/nitrogen/generated/shared/c++/HybridViewModelListPropertySpec.cpp +30 -0
- package/nitrogen/generated/shared/c++/HybridViewModelListPropertySpec.hpp +76 -0
- package/nitrogen/generated/shared/c++/HybridViewModelNumberPropertySpec.hpp +1 -1
- package/nitrogen/generated/shared/c++/HybridViewModelStringPropertySpec.hpp +1 -1
- package/nitrogen/generated/shared/c++/HybridViewModelTriggerPropertySpec.hpp +1 -1
- package/package.json +3 -3
- package/src/hooks/useRiveColor.ts +7 -4
- package/src/hooks/useRiveList.ts +108 -0
- package/src/hooks/useRiveProperty.ts +20 -13
- package/src/hooks/useViewModelInstance.ts +195 -0
- package/src/index.tsx +4 -0
- package/src/specs/ViewModel.nitro.ts +43 -15
- package/src/types.tsx +58 -3
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
///
|
|
2
|
+
/// HybridViewModelListPropertySpec.hpp
|
|
3
|
+
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
|
+
/// https://github.com/mrousavy/nitro
|
|
5
|
+
/// Copyright © 2025 Marc Rousavy @ Margelo
|
|
6
|
+
///
|
|
7
|
+
|
|
8
|
+
#pragma once
|
|
9
|
+
|
|
10
|
+
#if __has_include(<NitroModules/HybridObject.hpp>)
|
|
11
|
+
#include <NitroModules/HybridObject.hpp>
|
|
12
|
+
#else
|
|
13
|
+
#error NitroModules cannot be found! Are you sure you installed NitroModules properly?
|
|
14
|
+
#endif
|
|
15
|
+
|
|
16
|
+
// Forward declaration of `HybridViewModelInstanceSpec` to properly resolve imports.
|
|
17
|
+
namespace margelo::nitro::rive { class HybridViewModelInstanceSpec; }
|
|
18
|
+
// Forward declaration of `HybridViewModelPropertySpec` to properly resolve imports.
|
|
19
|
+
namespace margelo::nitro::rive { class HybridViewModelPropertySpec; }
|
|
20
|
+
|
|
21
|
+
#include <memory>
|
|
22
|
+
#include "HybridViewModelInstanceSpec.hpp"
|
|
23
|
+
#include <optional>
|
|
24
|
+
#include <functional>
|
|
25
|
+
#include "HybridViewModelPropertySpec.hpp"
|
|
26
|
+
|
|
27
|
+
namespace margelo::nitro::rive {
|
|
28
|
+
|
|
29
|
+
using namespace margelo::nitro;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* An abstract base class for `ViewModelListProperty`
|
|
33
|
+
* Inherit this class to create instances of `HybridViewModelListPropertySpec` in C++.
|
|
34
|
+
* You must explicitly call `HybridObject`'s constructor yourself, because it is virtual.
|
|
35
|
+
* @example
|
|
36
|
+
* ```cpp
|
|
37
|
+
* class HybridViewModelListProperty: public HybridViewModelListPropertySpec {
|
|
38
|
+
* public:
|
|
39
|
+
* HybridViewModelListProperty(...): HybridObject(TAG) { ... }
|
|
40
|
+
* // ...
|
|
41
|
+
* };
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
class HybridViewModelListPropertySpec: public virtual HybridObject, public virtual HybridViewModelPropertySpec {
|
|
45
|
+
public:
|
|
46
|
+
// Constructor
|
|
47
|
+
explicit HybridViewModelListPropertySpec(): HybridObject(TAG) { }
|
|
48
|
+
|
|
49
|
+
// Destructor
|
|
50
|
+
~HybridViewModelListPropertySpec() override = default;
|
|
51
|
+
|
|
52
|
+
public:
|
|
53
|
+
// Properties
|
|
54
|
+
virtual double getLength() = 0;
|
|
55
|
+
|
|
56
|
+
public:
|
|
57
|
+
// Methods
|
|
58
|
+
virtual std::optional<std::shared_ptr<HybridViewModelInstanceSpec>> getInstanceAt(double index) = 0;
|
|
59
|
+
virtual void addInstance(const std::shared_ptr<HybridViewModelInstanceSpec>& instance) = 0;
|
|
60
|
+
virtual bool addInstanceAt(const std::shared_ptr<HybridViewModelInstanceSpec>& instance, double index) = 0;
|
|
61
|
+
virtual void removeInstance(const std::shared_ptr<HybridViewModelInstanceSpec>& instance) = 0;
|
|
62
|
+
virtual void removeInstanceAt(double index) = 0;
|
|
63
|
+
virtual bool swap(double index1, double index2) = 0;
|
|
64
|
+
virtual std::function<void()> addListener(const std::function<void()>& onChanged) = 0;
|
|
65
|
+
virtual void removeListeners() = 0;
|
|
66
|
+
|
|
67
|
+
protected:
|
|
68
|
+
// Hybrid Setup
|
|
69
|
+
void loadHybridMethods() override;
|
|
70
|
+
|
|
71
|
+
protected:
|
|
72
|
+
// Tag for logging
|
|
73
|
+
static constexpr auto TAG = "ViewModelListProperty";
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
} // namespace margelo::nitro::rive
|
|
@@ -52,7 +52,7 @@ namespace margelo::nitro::rive {
|
|
|
52
52
|
|
|
53
53
|
public:
|
|
54
54
|
// Methods
|
|
55
|
-
virtual void addListener(const std::function<void(double /* value */)>& onChanged) = 0;
|
|
55
|
+
virtual std::function<void()> addListener(const std::function<void(double /* value */)>& onChanged) = 0;
|
|
56
56
|
virtual void removeListeners() = 0;
|
|
57
57
|
|
|
58
58
|
protected:
|
|
@@ -53,7 +53,7 @@ namespace margelo::nitro::rive {
|
|
|
53
53
|
|
|
54
54
|
public:
|
|
55
55
|
// Methods
|
|
56
|
-
virtual void addListener(const std::function<void(const std::string& /* value */)>& onChanged) = 0;
|
|
56
|
+
virtual std::function<void()> addListener(const std::function<void(const std::string& /* value */)>& onChanged) = 0;
|
|
57
57
|
virtual void removeListeners() = 0;
|
|
58
58
|
|
|
59
59
|
protected:
|
|
@@ -51,7 +51,7 @@ namespace margelo::nitro::rive {
|
|
|
51
51
|
|
|
52
52
|
public:
|
|
53
53
|
// Methods
|
|
54
|
-
virtual void addListener(const std::function<void()>& onChanged) = 0;
|
|
54
|
+
virtual std::function<void()> addListener(const std::function<void()>& onChanged) = 0;
|
|
55
55
|
virtual void trigger() = 0;
|
|
56
56
|
virtual void removeListeners() = 0;
|
|
57
57
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rive-app/react-native",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Rive React Native",
|
|
5
5
|
"main": "./lib/module/index.js",
|
|
6
6
|
"types": "./lib/typescript/src/index.d.ts",
|
|
@@ -64,8 +64,8 @@
|
|
|
64
64
|
},
|
|
65
65
|
"homepage": "https://github.com/rive-app/rive-nitro-react-native#readme",
|
|
66
66
|
"runtimeVersions": {
|
|
67
|
-
"ios": "6.12.
|
|
68
|
-
"android": "10.5.
|
|
67
|
+
"ios": "6.12.3",
|
|
68
|
+
"android": "10.5.3"
|
|
69
69
|
},
|
|
70
70
|
"publishConfig": {
|
|
71
71
|
"registry": "https://registry.npmjs.org/"
|
|
@@ -3,7 +3,6 @@ import type {
|
|
|
3
3
|
ViewModelColorProperty,
|
|
4
4
|
ViewModelInstance,
|
|
5
5
|
} from '../specs/ViewModel.nitro';
|
|
6
|
-
import { type UseRivePropertyResult } from '../types';
|
|
7
6
|
import { useRiveProperty } from './useRiveProperty';
|
|
8
7
|
import { RiveColor } from '../core/RiveColor';
|
|
9
8
|
|
|
@@ -11,6 +10,12 @@ const COLOR_PROPERTY_OPTIONS = {
|
|
|
11
10
|
getProperty: (vmi: ViewModelInstance, p: string) => vmi.colorProperty(p),
|
|
12
11
|
};
|
|
13
12
|
|
|
13
|
+
export interface UseRiveColorResult {
|
|
14
|
+
value: RiveColor | undefined;
|
|
15
|
+
setValue: (value: RiveColor | string) => void;
|
|
16
|
+
error: Error | null;
|
|
17
|
+
}
|
|
18
|
+
|
|
14
19
|
/**
|
|
15
20
|
* Hook for interacting with color ViewModel instance properties.
|
|
16
21
|
*
|
|
@@ -21,9 +26,7 @@ const COLOR_PROPERTY_OPTIONS = {
|
|
|
21
26
|
export function useRiveColor(
|
|
22
27
|
path: string,
|
|
23
28
|
viewModelInstance?: ViewModelInstance | null
|
|
24
|
-
):
|
|
25
|
-
setValue: (value: RiveColor | string) => void;
|
|
26
|
-
} {
|
|
29
|
+
): UseRiveColorResult {
|
|
27
30
|
const [rawValue, setRawValue, error] = useRiveProperty<
|
|
28
31
|
ViewModelColorProperty,
|
|
29
32
|
number
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { useCallback, useEffect, useState, useMemo } from 'react';
|
|
2
|
+
import type { ViewModelInstance } from '../specs/ViewModel.nitro';
|
|
3
|
+
import type { UseRiveListResult } from '../types';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Hook for interacting with list ViewModel instance properties.
|
|
7
|
+
*
|
|
8
|
+
* @param path - The path to the list property
|
|
9
|
+
* @param viewModelInstance - The ViewModelInstance containing the list property
|
|
10
|
+
* @returns An object with list length, manipulation methods, and error state
|
|
11
|
+
*/
|
|
12
|
+
export function useRiveList(
|
|
13
|
+
path: string,
|
|
14
|
+
viewModelInstance?: ViewModelInstance | null
|
|
15
|
+
): UseRiveListResult {
|
|
16
|
+
const [error, setError] = useState<Error | null>(null);
|
|
17
|
+
const [revision, setRevision] = useState(0);
|
|
18
|
+
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
setError(null);
|
|
21
|
+
}, [path, viewModelInstance]);
|
|
22
|
+
|
|
23
|
+
const property = useMemo(() => {
|
|
24
|
+
if (!viewModelInstance) return undefined;
|
|
25
|
+
return viewModelInstance.listProperty(path);
|
|
26
|
+
}, [viewModelInstance, path]);
|
|
27
|
+
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
if (viewModelInstance && !property) {
|
|
30
|
+
setError(
|
|
31
|
+
new Error(`List property "${path}" not found in the ViewModel instance`)
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
}, [viewModelInstance, property, path]);
|
|
35
|
+
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
if (!property) return;
|
|
38
|
+
|
|
39
|
+
const removeListener = property.addListener(() => {
|
|
40
|
+
setRevision((r) => r + 1);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
return () => {
|
|
44
|
+
removeListener();
|
|
45
|
+
property.removeListeners();
|
|
46
|
+
property.dispose();
|
|
47
|
+
};
|
|
48
|
+
}, [property]);
|
|
49
|
+
|
|
50
|
+
const length = useMemo(() => {
|
|
51
|
+
// revision is used to trigger re-computation when list changes
|
|
52
|
+
revision;
|
|
53
|
+
return property?.length ?? 0;
|
|
54
|
+
}, [property, revision]);
|
|
55
|
+
|
|
56
|
+
const getInstanceAt = useCallback(
|
|
57
|
+
(index: number) => {
|
|
58
|
+
return property?.getInstanceAt(index);
|
|
59
|
+
},
|
|
60
|
+
[property]
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
const addInstance = useCallback(
|
|
64
|
+
(instance: ViewModelInstance) => {
|
|
65
|
+
property?.addInstance(instance);
|
|
66
|
+
},
|
|
67
|
+
[property]
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
const addInstanceAt = useCallback(
|
|
71
|
+
(instance: ViewModelInstance, index: number) => {
|
|
72
|
+
return property?.addInstanceAt(instance, index) ?? false;
|
|
73
|
+
},
|
|
74
|
+
[property]
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
const removeInstance = useCallback(
|
|
78
|
+
(instance: ViewModelInstance) => {
|
|
79
|
+
property?.removeInstance(instance);
|
|
80
|
+
},
|
|
81
|
+
[property]
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const removeInstanceAt = useCallback(
|
|
85
|
+
(index: number) => {
|
|
86
|
+
property?.removeInstanceAt(index);
|
|
87
|
+
},
|
|
88
|
+
[property]
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
const swap = useCallback(
|
|
92
|
+
(index1: number, index2: number) => {
|
|
93
|
+
return property?.swap(index1, index2) ?? false;
|
|
94
|
+
},
|
|
95
|
+
[property]
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
length,
|
|
100
|
+
getInstanceAt,
|
|
101
|
+
addInstance,
|
|
102
|
+
addInstanceAt,
|
|
103
|
+
removeInstance,
|
|
104
|
+
removeInstanceAt,
|
|
105
|
+
swap,
|
|
106
|
+
error,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
@@ -28,7 +28,12 @@ export function useRiveProperty<P extends ViewModelProperty, T>(
|
|
|
28
28
|
/** Optional override callback for property events (mainly used by triggers) */
|
|
29
29
|
onPropertyEventOverride?: (...args: any[]) => void;
|
|
30
30
|
}
|
|
31
|
-
): [
|
|
31
|
+
): [
|
|
32
|
+
T | undefined,
|
|
33
|
+
(value: T | ((prevValue: T | undefined) => T)) => void,
|
|
34
|
+
Error | null,
|
|
35
|
+
P | undefined,
|
|
36
|
+
] {
|
|
32
37
|
const [value, setValue] = useState<T | undefined>(undefined);
|
|
33
38
|
const [error, setError] = useState<Error | null>(null);
|
|
34
39
|
|
|
@@ -61,25 +66,21 @@ export function useRiveProperty<P extends ViewModelProperty, T>(
|
|
|
61
66
|
|
|
62
67
|
// If an override callback is provided, use it.
|
|
63
68
|
// Otherwise, use the default callback.
|
|
64
|
-
|
|
65
|
-
property.addListener(options.onPropertyEventOverride)
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
});
|
|
70
|
-
}
|
|
69
|
+
const removeListener = options.onPropertyEventOverride
|
|
70
|
+
? property.addListener(options.onPropertyEventOverride)
|
|
71
|
+
: property.addListener((newValue) => {
|
|
72
|
+
setValue(newValue);
|
|
73
|
+
});
|
|
71
74
|
|
|
72
|
-
// Cleanup: Remove listeners and dispose of the property
|
|
73
|
-
// This ensures proper cleanup of event listeners and resources
|
|
74
75
|
return () => {
|
|
75
|
-
|
|
76
|
+
removeListener();
|
|
76
77
|
property.dispose();
|
|
77
78
|
};
|
|
78
79
|
}, [options, property]);
|
|
79
80
|
|
|
80
81
|
// Set the value of the property
|
|
81
82
|
const setPropertyValue = useCallback(
|
|
82
|
-
(
|
|
83
|
+
(valueOrUpdater: T | ((prevValue: T | undefined) => T)) => {
|
|
83
84
|
if (!property) {
|
|
84
85
|
setError(
|
|
85
86
|
new Error(
|
|
@@ -87,6 +88,12 @@ export function useRiveProperty<P extends ViewModelProperty, T>(
|
|
|
87
88
|
)
|
|
88
89
|
);
|
|
89
90
|
} else {
|
|
91
|
+
const newValue =
|
|
92
|
+
typeof valueOrUpdater === 'function'
|
|
93
|
+
? (valueOrUpdater as (prevValue: T | undefined) => T)(
|
|
94
|
+
property.value
|
|
95
|
+
)
|
|
96
|
+
: valueOrUpdater;
|
|
90
97
|
property.value = newValue;
|
|
91
98
|
}
|
|
92
99
|
},
|
|
@@ -105,6 +112,6 @@ export function useRiveProperty<P extends ViewModelProperty, T>(
|
|
|
105
112
|
interface ObservableViewModelProperty<T>
|
|
106
113
|
extends ViewModelProperty,
|
|
107
114
|
ObservableProperty {
|
|
108
|
-
addListener: (onChanged: (value: T) => void) => void;
|
|
115
|
+
addListener: (onChanged: (value: T) => void) => () => void;
|
|
109
116
|
value: T;
|
|
110
117
|
}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { useMemo, useEffect, useRef } from 'react';
|
|
2
|
+
import type { ViewModel, ViewModelInstance } from '../specs/ViewModel.nitro';
|
|
3
|
+
import type { RiveFile } from '../specs/RiveFile.nitro';
|
|
4
|
+
import type { RiveViewRef } from '../index';
|
|
5
|
+
import { callDispose } from '../core/callDispose';
|
|
6
|
+
|
|
7
|
+
export interface UseViewModelInstanceParams {
|
|
8
|
+
/**
|
|
9
|
+
* Get a specifically named instance from the ViewModel.
|
|
10
|
+
*/
|
|
11
|
+
name?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Create a new (blank) instance from the ViewModel.
|
|
14
|
+
*/
|
|
15
|
+
useNew?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* If true, throws an error when the instance cannot be obtained.
|
|
18
|
+
* This is useful with Error Boundaries and ensures TypeScript knows
|
|
19
|
+
* the return value is non-null.
|
|
20
|
+
*/
|
|
21
|
+
required?: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Called synchronously when a new instance is created, before the hook returns.
|
|
24
|
+
* Use this to set initial values that need to be available immediately.
|
|
25
|
+
* Note: This callback is excluded from deps - changing it won't recreate the instance.
|
|
26
|
+
*/
|
|
27
|
+
onInit?: (instance: ViewModelInstance) => void;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
type ViewModelSource = ViewModel | RiveFile | RiveViewRef;
|
|
31
|
+
|
|
32
|
+
function isRiveViewRef(source: ViewModelSource | null): source is RiveViewRef {
|
|
33
|
+
return (
|
|
34
|
+
source !== null && source !== undefined && 'getViewModelInstance' in source
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function isRiveFile(source: ViewModelSource | null): source is RiveFile {
|
|
39
|
+
return (
|
|
40
|
+
source !== null &&
|
|
41
|
+
source !== undefined &&
|
|
42
|
+
'defaultArtboardViewModel' in source
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function createInstance(
|
|
47
|
+
source: ViewModelSource | null,
|
|
48
|
+
name: string | undefined,
|
|
49
|
+
useNew: boolean
|
|
50
|
+
): { instance: ViewModelInstance | null; needsDispose: boolean } {
|
|
51
|
+
if (!source) {
|
|
52
|
+
return { instance: null, needsDispose: false };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (isRiveViewRef(source)) {
|
|
56
|
+
const vmi = source.getViewModelInstance();
|
|
57
|
+
return { instance: vmi ?? null, needsDispose: false };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (isRiveFile(source)) {
|
|
61
|
+
const viewModel = source.defaultArtboardViewModel();
|
|
62
|
+
const vmi = viewModel?.createDefaultInstance();
|
|
63
|
+
return { instance: vmi ?? null, needsDispose: true };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ViewModel source
|
|
67
|
+
let vmi: ViewModelInstance | undefined;
|
|
68
|
+
if (name) {
|
|
69
|
+
vmi = source.createInstanceByName(name);
|
|
70
|
+
} else if (useNew) {
|
|
71
|
+
vmi = source.createInstance();
|
|
72
|
+
} else {
|
|
73
|
+
vmi = source.createDefaultInstance();
|
|
74
|
+
}
|
|
75
|
+
return { instance: vmi ?? null, needsDispose: true };
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Hook for getting a ViewModelInstance from a RiveFile, ViewModel, or RiveViewRef.
|
|
80
|
+
*
|
|
81
|
+
* @param source - The RiveFile, ViewModel, or RiveViewRef to get an instance from
|
|
82
|
+
* @param params - Configuration for which instance to retrieve (only used with ViewModel)
|
|
83
|
+
* @returns The ViewModelInstance or null if not found
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```tsx
|
|
87
|
+
* // From RiveFile (get default instance)
|
|
88
|
+
* const { riveFile } = useRiveFile(require('./animation.riv'));
|
|
89
|
+
* const instance = useViewModelInstance(riveFile);
|
|
90
|
+
* ```
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* ```tsx
|
|
94
|
+
* // From RiveViewRef (get auto-bound instance)
|
|
95
|
+
* const { riveViewRef, setHybridRef } = useRive();
|
|
96
|
+
* const instance = useViewModelInstance(riveViewRef);
|
|
97
|
+
* ```
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```tsx
|
|
101
|
+
* // From ViewModel
|
|
102
|
+
* const viewModel = file.viewModelByName('main');
|
|
103
|
+
* const instance = useViewModelInstance(viewModel);
|
|
104
|
+
* ```
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```tsx
|
|
108
|
+
* // Create a new blank instance from ViewModel
|
|
109
|
+
* const viewModel = file.viewModelByName('TodoItem');
|
|
110
|
+
* const newInstance = useViewModelInstance(viewModel, { useNew: true });
|
|
111
|
+
* ```
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```tsx
|
|
115
|
+
* // With required: true (throws if null, use with Error Boundary)
|
|
116
|
+
* const instance = useViewModelInstance(riveFile, { required: true });
|
|
117
|
+
* // instance is guaranteed to be non-null here
|
|
118
|
+
* ```
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* ```tsx
|
|
122
|
+
* // With onInit to set initial values synchronously
|
|
123
|
+
* const instance = useViewModelInstance(riveFile, {
|
|
124
|
+
* onInit: (vmi) => {
|
|
125
|
+
* vmi.numberProperty('count').set(initialCount);
|
|
126
|
+
* vmi.stringProperty('name').set(userName);
|
|
127
|
+
* }
|
|
128
|
+
* });
|
|
129
|
+
* // Values are already set here
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
export function useViewModelInstance(
|
|
133
|
+
source: ViewModelSource,
|
|
134
|
+
params: UseViewModelInstanceParams & { required: true }
|
|
135
|
+
): ViewModelInstance;
|
|
136
|
+
export function useViewModelInstance(
|
|
137
|
+
source: ViewModelSource | null,
|
|
138
|
+
params?: UseViewModelInstanceParams
|
|
139
|
+
): ViewModelInstance | null;
|
|
140
|
+
export function useViewModelInstance(
|
|
141
|
+
source: ViewModelSource | null,
|
|
142
|
+
params?: UseViewModelInstanceParams
|
|
143
|
+
): ViewModelInstance | null {
|
|
144
|
+
const name = params?.name;
|
|
145
|
+
const useNew = params?.useNew ?? false;
|
|
146
|
+
const required = params?.required ?? false;
|
|
147
|
+
const onInit = params?.onInit;
|
|
148
|
+
|
|
149
|
+
const prevInstanceRef = useRef<{
|
|
150
|
+
instance: ViewModelInstance | null;
|
|
151
|
+
needsDispose: boolean;
|
|
152
|
+
} | null>(null);
|
|
153
|
+
|
|
154
|
+
const result = useMemo(() => {
|
|
155
|
+
const created = createInstance(source, name, useNew);
|
|
156
|
+
if (created.instance && onInit) {
|
|
157
|
+
onInit(created.instance);
|
|
158
|
+
}
|
|
159
|
+
return created;
|
|
160
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- onInit excluded intentionally
|
|
161
|
+
}, [source, name, useNew]);
|
|
162
|
+
|
|
163
|
+
// Dispose previous instance if it changed and needed disposal
|
|
164
|
+
if (
|
|
165
|
+
prevInstanceRef.current &&
|
|
166
|
+
prevInstanceRef.current.instance !== result.instance &&
|
|
167
|
+
prevInstanceRef.current.needsDispose &&
|
|
168
|
+
prevInstanceRef.current.instance
|
|
169
|
+
) {
|
|
170
|
+
callDispose(prevInstanceRef.current.instance);
|
|
171
|
+
}
|
|
172
|
+
prevInstanceRef.current = result;
|
|
173
|
+
|
|
174
|
+
// Cleanup on unmount
|
|
175
|
+
useEffect(() => {
|
|
176
|
+
return () => {
|
|
177
|
+
if (
|
|
178
|
+
prevInstanceRef.current?.needsDispose &&
|
|
179
|
+
prevInstanceRef.current.instance
|
|
180
|
+
) {
|
|
181
|
+
callDispose(prevInstanceRef.current.instance);
|
|
182
|
+
prevInstanceRef.current = null;
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
}, []);
|
|
186
|
+
|
|
187
|
+
if (required && result.instance === null) {
|
|
188
|
+
throw new Error(
|
|
189
|
+
'useViewModelInstance: Failed to get ViewModelInstance. ' +
|
|
190
|
+
'Ensure the source has a valid ViewModel and instance available.'
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return result.instance;
|
|
195
|
+
}
|
package/src/index.tsx
CHANGED
|
@@ -30,6 +30,7 @@ export type {
|
|
|
30
30
|
ViewModelEnumProperty,
|
|
31
31
|
ViewModelTriggerProperty,
|
|
32
32
|
ViewModelImageProperty,
|
|
33
|
+
ViewModelListProperty,
|
|
33
34
|
} from './specs/ViewModel.nitro';
|
|
34
35
|
export { Fit } from './core/Fit';
|
|
35
36
|
export { Alignment } from './core/Alignment';
|
|
@@ -47,6 +48,9 @@ export { useRiveBoolean } from './hooks/useRiveBoolean';
|
|
|
47
48
|
export { useRiveEnum } from './hooks/useRiveEnum';
|
|
48
49
|
export { useRiveColor } from './hooks/useRiveColor';
|
|
49
50
|
export { useRiveTrigger } from './hooks/useRiveTrigger';
|
|
51
|
+
export { useRiveList } from './hooks/useRiveList';
|
|
52
|
+
export { useViewModelInstance } from './hooks/useViewModelInstance';
|
|
50
53
|
export { useRiveFile } from './hooks/useRiveFile';
|
|
51
54
|
export { type RiveFileInput } from './hooks/useRiveFile';
|
|
55
|
+
export { type SetValueAction } from './types';
|
|
52
56
|
export { DataBindMode };
|
|
@@ -52,13 +52,16 @@ export interface ViewModelInstance
|
|
|
52
52
|
|
|
53
53
|
/** Get an image property from the view model instance at the given path */
|
|
54
54
|
imageProperty(path: string): ViewModelImageProperty | undefined;
|
|
55
|
+
|
|
56
|
+
/** Get a list property from the view model instance at the given path */
|
|
57
|
+
listProperty(path: string): ViewModelListProperty | undefined;
|
|
55
58
|
}
|
|
56
59
|
|
|
57
60
|
export interface ViewModelProperty
|
|
58
61
|
extends HybridObject<{ ios: 'swift'; android: 'kotlin' }> {}
|
|
59
62
|
|
|
60
63
|
export interface ObservableProperty {
|
|
61
|
-
/** Remove all listeners from the
|
|
64
|
+
/** Remove all listeners from the property */
|
|
62
65
|
removeListeners(): void;
|
|
63
66
|
}
|
|
64
67
|
|
|
@@ -67,8 +70,8 @@ export interface ViewModelNumberProperty
|
|
|
67
70
|
ObservableProperty {
|
|
68
71
|
/** The value of the view model number property */
|
|
69
72
|
value: number;
|
|
70
|
-
/** Add a listener to the view model number property */
|
|
71
|
-
addListener(onChanged: (value: number) => void): void;
|
|
73
|
+
/** Add a listener to the view model number property. Returns a function to remove the listener. */
|
|
74
|
+
addListener(onChanged: (value: number) => void): () => void;
|
|
72
75
|
}
|
|
73
76
|
|
|
74
77
|
export interface ViewModelStringProperty
|
|
@@ -76,8 +79,8 @@ export interface ViewModelStringProperty
|
|
|
76
79
|
ObservableProperty {
|
|
77
80
|
/** The value of the view model string property */
|
|
78
81
|
value: string;
|
|
79
|
-
/** Add a listener to the view model string property */
|
|
80
|
-
addListener(onChanged: (value: string) => void): void;
|
|
82
|
+
/** Add a listener to the view model string property. Returns a function to remove the listener. */
|
|
83
|
+
addListener(onChanged: (value: string) => void): () => void;
|
|
81
84
|
}
|
|
82
85
|
|
|
83
86
|
export interface ViewModelBooleanProperty
|
|
@@ -85,8 +88,8 @@ export interface ViewModelBooleanProperty
|
|
|
85
88
|
ObservableProperty {
|
|
86
89
|
/** The value of the view model boolean property */
|
|
87
90
|
value: boolean;
|
|
88
|
-
/** Add a listener to the view model boolean property */
|
|
89
|
-
addListener(onChanged: (value: boolean) => void): void;
|
|
91
|
+
/** Add a listener to the view model boolean property. Returns a function to remove the listener. */
|
|
92
|
+
addListener(onChanged: (value: boolean) => void): () => void;
|
|
90
93
|
}
|
|
91
94
|
|
|
92
95
|
export interface ViewModelColorProperty
|
|
@@ -94,8 +97,8 @@ export interface ViewModelColorProperty
|
|
|
94
97
|
ObservableProperty {
|
|
95
98
|
/** The value of the view model color property */
|
|
96
99
|
value: number;
|
|
97
|
-
/** Add a listener to the view model color property */
|
|
98
|
-
addListener(onChanged: (value: number) => void): void;
|
|
100
|
+
/** Add a listener to the view model color property. Returns a function to remove the listener. */
|
|
101
|
+
addListener(onChanged: (value: number) => void): () => void;
|
|
99
102
|
}
|
|
100
103
|
|
|
101
104
|
export interface ViewModelEnumProperty
|
|
@@ -103,15 +106,15 @@ export interface ViewModelEnumProperty
|
|
|
103
106
|
ObservableProperty {
|
|
104
107
|
/** The value of the view model enum property */
|
|
105
108
|
value: string;
|
|
106
|
-
/** Add a listener to the view model enum property */
|
|
107
|
-
addListener(onChanged: (value: string) => void): void;
|
|
109
|
+
/** Add a listener to the view model enum property. Returns a function to remove the listener. */
|
|
110
|
+
addListener(onChanged: (value: string) => void): () => void;
|
|
108
111
|
}
|
|
109
112
|
|
|
110
113
|
export interface ViewModelTriggerProperty
|
|
111
114
|
extends ViewModelProperty,
|
|
112
115
|
ObservableProperty {
|
|
113
|
-
/** Add a listener to the view model trigger property */
|
|
114
|
-
addListener(onChanged: () => void): void;
|
|
116
|
+
/** Add a listener to the view model trigger property. Returns a function to remove the listener. */
|
|
117
|
+
addListener(onChanged: () => void): () => void;
|
|
115
118
|
/** Trigger the view model trigger property */
|
|
116
119
|
trigger(): void;
|
|
117
120
|
}
|
|
@@ -121,6 +124,31 @@ export interface ViewModelImageProperty
|
|
|
121
124
|
ObservableProperty {
|
|
122
125
|
/** Set the image property value */
|
|
123
126
|
set(image: RiveImage | undefined): void;
|
|
124
|
-
/** Add a listener to the view model image property */
|
|
125
|
-
addListener(onChanged: () => void): void;
|
|
127
|
+
/** Add a listener to the view model image property. Returns a function to remove the listener. */
|
|
128
|
+
addListener(onChanged: () => void): () => void;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* A list property that contains a dynamic collection of {@link ViewModelInstance} objects.
|
|
133
|
+
* @see {@link https://rive.app/docs/runtimes/data-binding#lists Rive Data Binding Lists}
|
|
134
|
+
*/
|
|
135
|
+
export interface ViewModelListProperty
|
|
136
|
+
extends ViewModelProperty,
|
|
137
|
+
ObservableProperty {
|
|
138
|
+
/** The number of instances in the list */
|
|
139
|
+
readonly length: number;
|
|
140
|
+
/** Get the instance at the given index */
|
|
141
|
+
getInstanceAt(index: number): ViewModelInstance | undefined;
|
|
142
|
+
/** Add an instance to the end of the list */
|
|
143
|
+
addInstance(instance: ViewModelInstance): void;
|
|
144
|
+
/** Add an instance at the given index, returns true if successful */
|
|
145
|
+
addInstanceAt(instance: ViewModelInstance, index: number): boolean;
|
|
146
|
+
/** Remove an instance from the list */
|
|
147
|
+
removeInstance(instance: ViewModelInstance): void;
|
|
148
|
+
/** Remove the instance at the given index */
|
|
149
|
+
removeInstanceAt(index: number): void;
|
|
150
|
+
/** Swap the instances at the given indices, returns true if successful */
|
|
151
|
+
swap(index1: number, index2: number): boolean;
|
|
152
|
+
/** Add a listener to be notified when the list changes. Returns a function to remove the listener. */
|
|
153
|
+
addListener(onChanged: () => void): () => void;
|
|
126
154
|
}
|