+ ): ViewModelTriggerProperty | undefined;
+
+ enumProperty>(
+ path: P
+ ):
+ | TypedViewModelEnumProperty>
+ | undefined;
+
+ imageProperty(
+ path: VMPropsOfKind
+ ): ViewModelImageProperty | undefined;
+
+ listProperty(
+ path: VMPropsOfKind
+ ): TypedViewModelListProperty | undefined;
+
+ /** Access a nested ViewModel instance; return type is typed to the referenced ViewModel. */
+ viewModel>(
+ path: P
+ ):
+ | TypedViewModelInstance<
+ T,
+ VMRefName & keyof T['viewModels'] & string
+ >
+ | undefined;
+
+ viewModelAsync>(
+ path: P
+ ): Promise<
+ | TypedViewModelInstance<
+ T,
+ VMRefName & keyof T['viewModels'] & string
+ >
+ | undefined
+ >;
+
+ /** Brand that prevents typed instances from matching untyped hook overloads. */
+ readonly __vmBrand: [T, VMName];
+}
+
+/**
+ * A plain ViewModelInstance with no schema type information.
+ * Used in the untyped hook overloads — typed instances are intentionally
+ * excluded so TypeScript picks the typed overload when a schema is known.
+ */
+export type UntypedViewModelInstance = ViewModelInstance & {
+ __vmBrand?: never;
+};
+
+/**
+ * Convenience alias: infer the ViewModel instance type directly from a RiveAsset import.
+ *
+ * @example
+ * import rewardsRiv from './rewards.riv';
+ * type RewardsInstance = TypedViewModelOf;
+ */
+export type TypedViewModelOf<
+ T extends RiveFileSchema | RiveAsset,
+ VMName extends Extract['viewModels'], string>,
+> = TypedViewModelInstance, VMName>;
diff --git a/src/hooks/useRiveBoolean.ts b/src/hooks/useRiveBoolean.ts
index 657d9ad6..f6449aa0 100644
--- a/src/hooks/useRiveBoolean.ts
+++ b/src/hooks/useRiveBoolean.ts
@@ -4,6 +4,12 @@ import {
} from '../specs/ViewModel.nitro';
import type { UseRivePropertyResult } from '../types';
import { useRiveProperty } from './useRiveProperty';
+import type {
+ PathsOfKind,
+ TypedViewModelInstance,
+ UntypedViewModelInstance,
+} from '../core/TypedViewModelInstance';
+import type { RiveFileSchema } from '../core/TypedRiveFile';
const getBooleanProperty = (vmi: ViewModelInstance, p: string) =>
vmi.booleanProperty(p);
@@ -15,6 +21,17 @@ const getBooleanProperty = (vmi: ViewModelInstance, p: string) =>
* @param viewModelInstance - The ViewModelInstance containing the boolean property to operate on
* @returns An object with the boolean value, a setter function, and an error if the property is not found
*/
+export function useRiveBoolean<
+ T extends RiveFileSchema,
+ N extends Extract,
+>(
+ path: PathsOfKind,
+ viewModelInstance?: TypedViewModelInstance | null
+): UseRivePropertyResult;
+export function useRiveBoolean(
+ path: string,
+ viewModelInstance?: UntypedViewModelInstance | null
+): UseRivePropertyResult;
export function useRiveBoolean(
path: string,
viewModelInstance?: ViewModelInstance | null
diff --git a/src/hooks/useRiveColor.ts b/src/hooks/useRiveColor.ts
index bd6ce38e..f16ccfd8 100644
--- a/src/hooks/useRiveColor.ts
+++ b/src/hooks/useRiveColor.ts
@@ -5,6 +5,12 @@ import type {
} from '../specs/ViewModel.nitro';
import { useRiveProperty } from './useRiveProperty';
import { RiveColor } from '../core/RiveColor';
+import type {
+ PathsOfKind,
+ TypedViewModelInstance,
+ UntypedViewModelInstance,
+} from '../core/TypedViewModelInstance';
+import type { RiveFileSchema } from '../core/TypedRiveFile';
const getColorProperty = (vmi: ViewModelInstance, p: string) =>
vmi.colorProperty(p);
@@ -22,6 +28,17 @@ export interface UseRiveColorResult {
* @param viewModelInstance - The ViewModelInstance containing the color property to operate on
* @returns An object with the color value as RGBA, a setter function that accepts either RGBA or hex string, and an error if the property is not found
*/
+export function useRiveColor<
+ T extends RiveFileSchema,
+ N extends Extract,
+>(
+ path: PathsOfKind,
+ viewModelInstance?: TypedViewModelInstance | null
+): UseRiveColorResult;
+export function useRiveColor(
+ path: string,
+ viewModelInstance?: UntypedViewModelInstance | null
+): UseRiveColorResult;
export function useRiveColor(
path: string,
viewModelInstance?: ViewModelInstance | null
diff --git a/src/hooks/useRiveEnum.ts b/src/hooks/useRiveEnum.ts
index ee5d67ba..11ba2b3a 100644
--- a/src/hooks/useRiveEnum.ts
+++ b/src/hooks/useRiveEnum.ts
@@ -3,18 +3,32 @@ import {
type ViewModelInstance,
} from '../specs/ViewModel.nitro';
import type { UseRivePropertyResult } from '../types';
+import type { RiveFileSchema } from '../core/TypedRiveFile';
+import {
+ type EnumValuesOf,
+ type TypedViewModelInstance,
+ type UntypedViewModelInstance,
+ type VMPropsOfKind,
+} from '../core/TypedViewModelInstance';
import { useRiveProperty } from './useRiveProperty';
const getEnumProperty = (vmi: ViewModelInstance, p: string) =>
vmi.enumProperty(p);
-/**
- * Hook for interacting with enum ViewModel instance properties.
- *
- * @param path - The path to the enum property
- * @param viewModelInstance - The ViewModelInstance containing the enum property to operate on
- * @returns An object with the enum value, a setter function, and an error if the property is not found
- */
+export function useRiveEnum<
+ T extends RiveFileSchema,
+ N extends Extract,
+ P extends VMPropsOfKind,
+>(
+ path: P,
+ viewModelInstance?: TypedViewModelInstance | null
+): UseRivePropertyResult>;
+
+export function useRiveEnum(
+ path: string,
+ viewModelInstance?: UntypedViewModelInstance | null
+): UseRivePropertyResult;
+
export function useRiveEnum(
path: string,
viewModelInstance?: ViewModelInstance | null
diff --git a/src/hooks/useRiveFile.ts b/src/hooks/useRiveFile.ts
index b9d5d83e..ea7cc651 100644
--- a/src/hooks/useRiveFile.ts
+++ b/src/hooks/useRiveFile.ts
@@ -12,6 +12,11 @@ import type {
ReferencedAssets,
ResolvedReferencedAssets,
} from '../core/ReferencedAssets';
+import type {
+ RiveAsset,
+ RiveFileSchema,
+ TypedRiveFile,
+} from '../core/TypedRiveFile';
export type { ReferencedAssets, ResolvedReferencedAssets };
export type RiveFileInput = number | { uri: string } | string | ArrayBuffer;
@@ -92,6 +97,17 @@ export type UseRiveFileResult =
| { riveFile: null; isLoading: false; error: Error }
| { riveFile: undefined; isLoading: true; error: null };
+export function useRiveFile(
+ input: RiveAsset,
+ options?: UseRiveFileOptions
+):
+ | { riveFile: TypedRiveFile; isLoading: false; error: null }
+ | { riveFile: null; isLoading: false; error: Error }
+ | { riveFile: undefined; isLoading: true; error: null };
+export function useRiveFile(
+ input: RiveFileInput | undefined,
+ options?: UseRiveFileOptions
+): UseRiveFileResult;
export function useRiveFile(
input: RiveFileInput | undefined,
options: UseRiveFileOptions = {}
diff --git a/src/hooks/useRiveNumber.ts b/src/hooks/useRiveNumber.ts
index 773d30e2..4cda0bb0 100644
--- a/src/hooks/useRiveNumber.ts
+++ b/src/hooks/useRiveNumber.ts
@@ -4,6 +4,12 @@ import {
} from '../specs/ViewModel.nitro';
import type { UseRivePropertyResult } from '../types';
import { useRiveProperty } from './useRiveProperty';
+import type {
+ PathsOfKind,
+ TypedViewModelInstance,
+ UntypedViewModelInstance,
+} from '../core/TypedViewModelInstance';
+import type { RiveFileSchema } from '../core/TypedRiveFile';
const getNumberProperty = (vmi: ViewModelInstance, p: string) =>
vmi.numberProperty(p);
@@ -15,6 +21,17 @@ const getNumberProperty = (vmi: ViewModelInstance, p: string) =>
* @param viewModelInstance - The ViewModelInstance containing the number property to operate on
* @returns An object with the number value, a setter function, and an error if the property is not found
*/
+export function useRiveNumber<
+ T extends RiveFileSchema,
+ N extends Extract,
+>(
+ path: PathsOfKind,
+ viewModelInstance?: TypedViewModelInstance | null
+): UseRivePropertyResult;
+export function useRiveNumber(
+ path: string,
+ viewModelInstance?: UntypedViewModelInstance | null
+): UseRivePropertyResult;
export function useRiveNumber(
path: string,
viewModelInstance?: ViewModelInstance | null
diff --git a/src/hooks/useRiveString.ts b/src/hooks/useRiveString.ts
index e182ddff..c5210e2a 100644
--- a/src/hooks/useRiveString.ts
+++ b/src/hooks/useRiveString.ts
@@ -4,6 +4,12 @@ import {
} from '../specs/ViewModel.nitro';
import type { UseRivePropertyResult } from '../types';
import { useRiveProperty } from './useRiveProperty';
+import type {
+ PathsOfKind,
+ TypedViewModelInstance,
+ UntypedViewModelInstance,
+} from '../core/TypedViewModelInstance';
+import type { RiveFileSchema } from '../core/TypedRiveFile';
const getStringProperty = (vmi: ViewModelInstance, p: string) =>
vmi.stringProperty(p);
@@ -15,6 +21,17 @@ const getStringProperty = (vmi: ViewModelInstance, p: string) =>
* @param viewModelInstance - The ViewModelInstance containing the string property to operate on
* @returns An object with the number value, a setter function, and an error if the property is not found
*/
+export function useRiveString<
+ T extends RiveFileSchema,
+ N extends Extract,
+>(
+ path: PathsOfKind,
+ viewModelInstance?: TypedViewModelInstance | null
+): UseRivePropertyResult;
+export function useRiveString(
+ path: string,
+ viewModelInstance?: UntypedViewModelInstance | null
+): UseRivePropertyResult;
export function useRiveString(
path: string,
viewModelInstance?: ViewModelInstance | null
diff --git a/src/hooks/useRiveTrigger.ts b/src/hooks/useRiveTrigger.ts
index 8f8315c9..9ca2c22d 100644
--- a/src/hooks/useRiveTrigger.ts
+++ b/src/hooks/useRiveTrigger.ts
@@ -8,6 +8,12 @@ import type {
UseViewModelInstanceTriggerParameters,
} from '../types';
import { useDisposableMemo } from './useDisposableMemo';
+import type {
+ PathsOfKind,
+ TypedViewModelInstance,
+ UntypedViewModelInstance,
+} from '../core/TypedViewModelInstance';
+import type { RiveFileSchema } from '../core/TypedRiveFile';
/**
* Hook for interacting with trigger ViewModel instance properties.
@@ -21,6 +27,19 @@ import { useDisposableMemo } from './useDisposableMemo';
* @param params - Optional parameters including onTrigger callback
* @returns A trigger function and any error
*/
+export function useRiveTrigger<
+ T extends RiveFileSchema,
+ N extends Extract,
+>(
+ path: PathsOfKind,
+ viewModelInstance?: TypedViewModelInstance | null,
+ params?: UseViewModelInstanceTriggerParameters
+): UseRiveTriggerResult;
+export function useRiveTrigger(
+ path: string,
+ viewModelInstance?: UntypedViewModelInstance | null,
+ params?: UseViewModelInstanceTriggerParameters
+): UseRiveTriggerResult;
export function useRiveTrigger(
path: string,
viewModelInstance?: ViewModelInstance | null,
diff --git a/src/hooks/useViewModelInstance.ts b/src/hooks/useViewModelInstance.ts
index 20003553..0b558858 100644
--- a/src/hooks/useViewModelInstance.ts
+++ b/src/hooks/useViewModelInstance.ts
@@ -3,6 +3,8 @@
import { useMemo, useRef } from 'react';
import type { ViewModel, ViewModelInstance } from '../specs/ViewModel.nitro';
import type { RiveFile } from '../specs/RiveFile.nitro';
+import type { RiveFileSchema } from '../core/TypedRiveFile';
+import type { TypedViewModelInstance } from '../core/TypedViewModelInstance';
import type { RiveViewRef } from '../index';
import { callDispose } from '../core/callDispose';
import { ArtboardByName } from '../specs/ArtboardBy';
@@ -304,6 +306,19 @@ export type UseViewModelInstanceRequiredResult =
* });
* ```
*/
+// Typed overload: TypedRiveFile + literal viewModelName → TypedViewModelInstance
+export function useViewModelInstance<
+ T extends RiveFileSchema,
+ N extends Extract,
+>(
+ source: (RiveFile & { readonly __schema?: T }) | null | undefined,
+ params: UseViewModelInstanceFileParams & { viewModelName: N }
+):
+ | { instance: TypedViewModelInstance; isLoading: false; error: null }
+ | { instance: null; isLoading: false; error: Error }
+ | { instance: null; isLoading: false; error: null }
+ | { instance: undefined; isLoading: true; error: null };
+
// RiveFile overloads
export function useViewModelInstance(
source: RiveFile,
diff --git a/src/index.tsx b/src/index.tsx
index 92fea083..f7feb6b3 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -20,6 +20,21 @@ export { RiveView, type RiveViewProps } from './core/RiveView';
export type { RiveViewMethods };
export type RiveViewRef = HybridView;
export type { RiveFile } from './specs/RiveFile.nitro';
+export type {
+ RiveAsset,
+ RiveFileSchema,
+ SchemaOf,
+ TypedRiveFile,
+} from './core/TypedRiveFile';
+export type {
+ TypedViewModelInstance,
+ TypedViewModelOf,
+ UntypedViewModelInstance,
+ TypedViewModelListProperty,
+ TypedViewModelEnumProperty,
+ PathsOfKind,
+ EnumValuesOf,
+} from './core/TypedViewModelInstance';
export type {
ViewModel,
ViewModelInstance,
diff --git a/tsconfig.json b/tsconfig.json
index 9a2c358c..eb3b6032 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -24,7 +24,8 @@
"skipLibCheck": true,
"strict": true,
"target": "ESNext",
- "verbatimModuleSyntax": true
+ "verbatimModuleSyntax": true,
+ "allowArbitraryExtensions": true
},
- "exclude": ["expo-example", "expo55-example", "**/*.test-d.ts"]
+"exclude": ["expo-example", "expo55-example", "**/*.test-d.ts", "scripts/__tests__"]
}
diff --git a/yarn.lock b/yarn.lock
index c372c698..032d80c5 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5459,6 +5459,13 @@ __metadata:
languageName: node
linkType: hard
+"@rive-app/canvas@npm:^2.38.0":
+ version: 2.38.0
+ resolution: "@rive-app/canvas@npm:2.38.0"
+ checksum: a75508c461db26c48d3d3daebd9bd2b1a28fd528062640bd99f767f3b0fc32a518e3bffaadccbab93b3819c7f1225f7d1c65e1534c036798482cf271b5d61161
+ languageName: node
+ linkType: hard
+
"@rive-app/react-native@workspace:.":
version: 0.0.0-use.local
resolution: "@rive-app/react-native@workspace:."
@@ -5470,6 +5477,7 @@ __metadata:
"@react-native/babel-preset": 0.79.2
"@react-native/eslint-config": ^0.78.0
"@release-it/conventional-changelog": ^9.0.2
+ "@rive-app/canvas": ^2.38.0
"@testing-library/react-hooks": ^8.0.1
"@testing-library/react-native": ^13.3.3
"@types/jest": ^29.5.5