@shopify/react-native-skia
Version:
High-performance React Native Graphics using Skia
90 lines (81 loc) • 1.98 kB
text/typescript
import type { ExtrapolationType, SharedValue } from "react-native-reanimated";
import { useMemo } from "react";
import type { SkPath, SkPoint } from "../../skia/types";
import { interpolatePaths, interpolateVector } from "../../animation";
import { Skia } from "../../skia";
import {
useAnimatedReaction,
useFrameCallback,
useSharedValue,
} from "./moduleWrapper";
export const notifyChange = (value: SharedValue<unknown>) => {
"worklet";
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(value as any)._value = value.value;
};
export const useClock = () => {
const clock = useSharedValue(0);
useFrameCallback((info) => {
clock.value = info.timeSinceFirstFrame;
});
return clock;
};
/**
* @worklet
*/
type Interpolator<T> = (
value: number,
input: number[],
output: T[],
options: ExtrapolationType,
result: T
) => T;
const useInterpolator = <T>(
factory: () => T,
value: SharedValue<number>,
interpolator: Interpolator<T>,
input: number[],
output: T[],
options?: ExtrapolationType
) => {
// eslint-disable-next-line react-hooks/exhaustive-deps
const init = useMemo(() => factory(), []);
const result = useSharedValue(init);
useAnimatedReaction(
() => value.value,
(val) => {
result.value = interpolator(val, input, output, options, result.value);
notifyChange(result);
},
[input, output, options]
);
return result;
};
export const usePathInterpolation = (
value: SharedValue<number>,
input: number[],
outputRange: SkPath[],
options?: ExtrapolationType
) =>
useInterpolator(
() => Skia.Path.Make(),
value,
interpolatePaths,
input,
outputRange,
options
);
export const useVectorInterpolation = (
value: SharedValue<number>,
input: number[],
outputRange: SkPoint[],
options?: ExtrapolationType
) =>
useInterpolator(
() => Skia.Point(0, 0),
value,
interpolateVector,
input,
outputRange,
options
);