Skip to content

Commit a62725b

Browse files
committed
feat: add functional updater support to setValue in property hooks
1 parent c13c702 commit a62725b

4 files changed

Lines changed: 52 additions & 15 deletions

File tree

src/hooks/useRiveColor.ts

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,24 @@ import type {
33
ViewModelColorProperty,
44
ViewModelInstance,
55
} from '../specs/ViewModel.nitro';
6-
import { type UseRivePropertyResult } from '../types';
76
import { useRiveProperty } from './useRiveProperty';
87
import { RiveColor } from '../core/RiveColor';
98

109
const COLOR_PROPERTY_OPTIONS = {
1110
getProperty: (vmi: ViewModelInstance, p: string) => vmi.colorProperty(p),
1211
};
1312

13+
type ColorInput = RiveColor | string;
14+
type ColorSetValueAction =
15+
| ColorInput
16+
| ((prevValue: RiveColor | undefined) => ColorInput);
17+
18+
export interface UseRiveColorResult {
19+
value: RiveColor | undefined;
20+
setValue: (value: ColorSetValueAction) => void;
21+
error: Error | null;
22+
}
23+
1424
/**
1525
* Hook for interacting with color ViewModel instance properties.
1626
*
@@ -21,9 +31,7 @@ const COLOR_PROPERTY_OPTIONS = {
2131
export function useRiveColor(
2232
path: string,
2333
viewModelInstance?: ViewModelInstance | null
24-
): UseRivePropertyResult<RiveColor> & {
25-
setValue: (value: RiveColor | string) => void;
26-
} {
34+
): UseRiveColorResult {
2735
const [rawValue, setRawValue, error] = useRiveProperty<
2836
ViewModelColorProperty,
2937
number
@@ -33,12 +41,20 @@ export function useRiveColor(
3341
rawValue !== undefined ? RiveColor.fromInt(rawValue) : undefined;
3442

3543
const setValue = useCallback(
36-
(newValue: RiveColor | string) => {
37-
const color =
38-
typeof newValue === 'string'
39-
? RiveColor.fromHexString(newValue)
40-
: newValue;
41-
setRawValue(color.toInt());
44+
(valueOrUpdater: ColorSetValueAction) => {
45+
setRawValue((prevRaw: number | undefined) => {
46+
const prevColor =
47+
prevRaw !== undefined ? RiveColor.fromInt(prevRaw) : undefined;
48+
const newColorInput =
49+
typeof valueOrUpdater === 'function'
50+
? valueOrUpdater(prevColor)
51+
: valueOrUpdater;
52+
const color =
53+
typeof newColorInput === 'string'
54+
? RiveColor.fromHexString(newColorInput)
55+
: newColorInput;
56+
return color.toInt();
57+
});
4258
},
4359
[setRawValue]
4460
);

src/hooks/useRiveProperty.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,12 @@ export function useRiveProperty<P extends ViewModelProperty, T>(
2828
/** Optional override callback for property events (mainly used by triggers) */
2929
onPropertyEventOverride?: (...args: any[]) => void;
3030
}
31-
): [T | undefined, (value: T) => void, Error | null, P | undefined] {
31+
): [
32+
T | undefined,
33+
(value: T | ((prevValue: T | undefined) => T)) => void,
34+
Error | null,
35+
P | undefined,
36+
] {
3237
const [value, setValue] = useState<T | undefined>(undefined);
3338
const [error, setError] = useState<Error | null>(null);
3439

@@ -79,14 +84,20 @@ export function useRiveProperty<P extends ViewModelProperty, T>(
7984

8085
// Set the value of the property
8186
const setPropertyValue = useCallback(
82-
(newValue: T) => {
87+
(valueOrUpdater: T | ((prevValue: T | undefined) => T)) => {
8388
if (!property) {
8489
setError(
8590
new Error(
8691
`Cannot set value for property "${path}" because it was not found. Your view model instance may be undefined, or the path may be incorrect.`
8792
)
8893
);
8994
} else {
95+
const newValue =
96+
typeof valueOrUpdater === 'function'
97+
? (valueOrUpdater as (prevValue: T | undefined) => T)(
98+
property.value
99+
)
100+
: valueOrUpdater;
90101
property.value = newValue;
91102
}
92103
},

src/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,5 @@ export { useRiveList } from './hooks/useRiveList';
5252
export { useViewModelInstance } from './hooks/useViewModelInstance';
5353
export { useRiveFile } from './hooks/useRiveFile';
5454
export { type RiveFileInput } from './hooks/useRiveFile';
55+
export { type SetValueAction } from './types';
5556
export { DataBindMode };

src/types.tsx

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,22 @@
1+
/**
2+
* A value or a function that computes a new value from the previous value.
3+
* Similar to React's SetStateAction pattern.
4+
*/
5+
export type SetValueAction<T> = T | ((prevValue: T | undefined) => T);
6+
17
export interface UseRivePropertyResult<T> {
28
/**
39
* The current value of the property.
410
*/
511
value: T | undefined;
612
/**
7-
* Set the value of the property.
8-
* @param value - The value to set the property to.
13+
* Set the value of the property. Accepts either a direct value or
14+
* a function that receives the previous value and returns the new value.
15+
* @example
16+
* setValue(10) // Set to 10
17+
* setValue((prev) => (prev ?? 0) + 5) // Increment by 5
918
*/
10-
setValue: (value: T) => void;
19+
setValue: (value: SetValueAction<T>) => void;
1120
/**
1221
* The error if the property is not found.
1322
*/

0 commit comments

Comments
 (0)