feat: add useViewModelInstanceList hook

This commit is contained in:
Adam
2025-06-14 14:03:26 -07:00
parent eef56fb641
commit 721ed786dc
2 changed files with 107 additions and 0 deletions

View File

@@ -0,0 +1,65 @@
import { useCallback } from 'react';
import { ViewModelInstance, ViewModelInstanceList } from '@rive-app/canvas';
import { UseViewModelInstanceListResult } from '../types';
import { useViewModelInstanceProperty } from './useViewModelInstanceProperty';
/**
* Hook for interacting with list properties of a ViewModelInstance.
*
* @param path - Path to the property (e.g. "items" or "nested/items")
* @param viewModelInstance - The ViewModelInstance containing the list property
* @returns An object with the list length and manipulation functions
*/
export default function useViewModelInstanceList(
path: string,
viewModelInstance?: ViewModelInstance | null
): UseViewModelInstanceListResult {
const result = useViewModelInstanceProperty<ViewModelInstanceList, number, Omit<UseViewModelInstanceListResult, 'length'>>(
path,
viewModelInstance,
{
getProperty: useCallback((vm, p) => vm.list(p), []),
getValue: useCallback((prop) => prop.length, []),
defaultValue: 0,
buildPropertyOperations: useCallback((safePropertyAccess) => ({
addInstance: (instance: ViewModelInstance) => {
safePropertyAccess(prop => prop.addInstance(instance));
},
addInstanceAt: (instance: ViewModelInstance, index: number): boolean => {
let result = false;
safePropertyAccess(prop => {
result = prop.addInstanceAt(instance, index);
});
return result;
},
removeInstance: (instance: ViewModelInstance) => {
safePropertyAccess(prop => prop.removeInstance(instance));
},
removeInstanceAt: (index: number) => {
safePropertyAccess(prop => prop.removeInstanceAt(index));
},
getInstanceAt: (index: number): ViewModelInstance | null => {
let result: ViewModelInstance | null = null;
safePropertyAccess(prop => {
result = prop.instanceAt(index);
});
return result;
},
swap: (a: number, b: number) => {
safePropertyAccess(prop => prop.swap(a, b));
}
}), [])
}
);
return {
length: result.value ?? 0,
addInstance: result.addInstance,
addInstanceAt: result.addInstanceAt,
removeInstance: result.removeInstance,
removeInstanceAt: result.removeInstanceAt,
getInstanceAt: result.getInstanceAt,
swap: result.swap
};
}

View File

@@ -4,6 +4,7 @@ import {
RiveFile,
RiveFileParameters,
RiveParameters,
ViewModelInstance,
} from '@rive-app/canvas';
import { ComponentProps, RefCallback } from 'react';
@@ -196,4 +197,45 @@ export type UseViewModelInstanceImageResult = {
* @param value - The image to set.
*/
setValue: (value: RiveRenderImage | null) => void;
};
export type UseViewModelInstanceListResult = {
/**
* The current length of the list.
*/
length: number;
/**
* Add an instance to the end of the list.
* @param instance - The ViewModelInstance to add.
*/
addInstance: (instance: ViewModelInstance) => void;
/**
* Add an instance at a specific index in the list.
* @param instance - The ViewModelInstance to add.
* @param index - The index to add the instance at.
* @returns True if the instance was successfully added, false otherwise.
*/
addInstanceAt: (instance: ViewModelInstance, index: number) => boolean;
/**
* Remove an instance from the list.
* @param instance - The ViewModelInstance to remove.
*/
removeInstance: (instance: ViewModelInstance) => void;
/**
* Remove an instance at a specific index from the list.
* @param index - The index to remove the instance from.
*/
removeInstanceAt: (index: number) => void;
/**
* Get an instance at a specific index from the list.
* @param index - The index to get the instance from.
* @returns The ViewModelInstance at the index, or null if not found.
*/
getInstanceAt: (index: number) => ViewModelInstance | null;
/**
* Swap two instances in the list.
* @param a - The first index.
* @param b - The second index.
*/
swap: (a: number, b: number) => void;
};