react-native-reanimated#useAnimatedProps TypeScript Examples
The following examples show how to use
react-native-reanimated#useAnimatedProps.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: useAnimatedPath.ts From react-native-wagmi-charts with MIT License | 6 votes |
export default function useAnimatedPath({
enabled = true,
path,
}: {
enabled?: boolean;
path: string;
}) {
const transition = useSharedValue(0);
const previousPath = usePrevious(path);
useAnimatedReaction(
() => {
return path;
},
(_, previous) => {
if (previous) {
transition.value = 0;
transition.value = withTiming(1);
}
},
[path]
);
const animatedProps = useAnimatedProps(() => {
let d = path || '';
if (previousPath && enabled) {
const pathInterpolator = interpolatePath(previousPath, path, null);
d = pathInterpolator(transition.value);
}
return {
d,
};
});
return { animatedProps };
}
Example #2
Source File: AnimatedText.tsx From react-native-wagmi-charts with MIT License | 6 votes |
AnimatedText = ({ text, style }: AnimatedTextProps) => {
const inputRef = React.useRef<any>(null); // eslint-disable-line @typescript-eslint/no-explicit-any
if (Platform.OS === 'web') {
// For some reason, the worklet reaction evaluates upfront regardless of any
// conditionals within it, causing Android to crash upon the invokation of `setNativeProps`.
// We are going to break the rules of hooks here so it doesn't invoke `useAnimatedReaction`
// for platforms outside of the web.
// eslint-disable-next-line react-hooks/rules-of-hooks
useAnimatedReaction(
() => {
return text.value;
},
(data, prevData) => {
if (data !== prevData && inputRef.current) {
inputRef.current.value = data;
}
}
);
}
const animatedProps = useAnimatedProps(() => {
return {
text: text.value,
// Here we use any because the text prop is not available in the type
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} as any;
});
return (
<AnimatedTextInput
underlineColorAndroid="transparent"
editable={false}
ref={Platform.select({ web: inputRef })}
value={text.value}
style={[styles.text, style]}
animatedProps={animatedProps}
/>
);
}
Example #3
Source File: animated-stroke.tsx From react-native-checkbox-reanimated with MIT License | 6 votes |
AnimatedStroke = ({ progress, ...pathProps }: AnimatedStrokeProps) => {
const [length, setLength] = useState(0)
const ref = useRef<typeof AnimatedPath>(null)
const animatedProps = useAnimatedProps(() => ({
strokeDashoffset: Math.max(
0,
length - length * Easing.bezierFn(0.37, 0, 0.63, 1)(progress.value) - 0.1
)
}))
return (
<AnimatedPath
animatedProps={animatedProps}
// @ts-ignore
onLayout={() => setLength(ref.current!.getTotalLength())}
// @ts-ignore
ref={ref}
strokeDasharray={length}
{...pathProps}
/>
)
}
Example #4
Source File: ReText.tsx From jellyfin-audio-player with MIT License | 6 votes |
ReText = (props: TextProps) => {
const { text, style } = { style: {}, ...props };
const defaultStyles = useDefaultStyles();
const animatedProps = useAnimatedProps(() => {
return {
text: text.value,
// Here we use any because the text prop is not available in the type
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} as any;
});
return (
<AnimatedTextInput
underlineColorAndroid="transparent"
editable={false}
value={text.value}
style={[styles.baseStyle, defaultStyles.text, style]}
{...{ animatedProps }}
/>
);
}
Example #5
Source File: HorizontalLine.tsx From react-native-wagmi-charts with MIT License | 5 votes |
export function LineChartHorizontalLine({
color = 'gray',
lineProps = {},
at = { index: 0 },
offsetY = 0,
}: HorizontalLineProps) {
const { width, path, height, gutter } = React.useContext(
LineChartDimensionsContext
);
const { data, yDomain } = useLineChart();
const parsedPath = React.useMemo(() => parse(path), [path]);
const pointWidth = React.useMemo(
() => width / data.length,
[data.length, width]
);
const y = useDerivedValue(() => {
if (typeof at === 'number' || at.index != null) {
const index = typeof at === 'number' ? at : at.index;
const yForX = getYForX(parsedPath!, pointWidth * index) || 0;
return withTiming(yForX + offsetY);
}
/**
* <gutter>
* | ---------- | <- yDomain.max |
* | | | offsetTop
* | | <- value |
* | |
* | | <- yDomain.min
* <gutter>
*/
const offsetTop = yDomain.max - at.value;
const percentageOffsetTop = offsetTop / (yDomain.max - yDomain.min);
const heightBetweenGutters = height - gutter * 2;
const offsetTopPixels = gutter + percentageOffsetTop * heightBetweenGutters;
return withTiming(offsetTopPixels + offsetY);
});
const lineAnimatedProps = useAnimatedProps(() => ({
x1: 0,
x2: width,
y1: y.value,
y2: y.value,
}));
return (
<AnimatedLine
animatedProps={lineAnimatedProps}
strokeWidth={2}
stroke={color}
strokeDasharray="3 3"
{...lineProps}
/>
);
}
Example #6
Source File: index.tsx From react-native-checkbox-reanimated with MIT License | 5 votes |
AnimatedCheckbox = (props: Props) => {
const { checked, checkmarkColor, highlightColor, boxOutlineColor } = props
const progress = useSharedValue(0)
useEffect(() => {
progress.value = withTiming(checked ? 1 : 0, {
duration: checked ? 300 : 100,
easing: Easing.linear
})
}, [checked])
const animatedBoxProps = useAnimatedProps(
() => ({
stroke: interpolateColor(
Easing.bezierFn(0.16, 1, 0.3, 1)(progress.value),
[0, 1],
[boxOutlineColor, highlightColor],
'RGB'
),
fill: interpolateColor(
Easing.bezierFn(0.16, 1, 0.3, 1)(progress.value),
[0, 1],
['#00000000', highlightColor],
'RGB'
)
}),
[highlightColor, boxOutlineColor]
)
return (
<Svg
viewBox={[-MARGIN, -MARGIN, vWidth + MARGIN, vHeight + MARGIN].join(' ')}
>
<Defs>
<ClipPath id="clipPath">
<Path
fill="white"
stroke="gray"
strokeLinejoin="round"
strokeLinecap="round"
d={outlineBoxPath}
/>
</ClipPath>
</Defs>
<AnimatedStroke
progress={progress}
d={checkMarkPath}
stroke={highlightColor}
strokeWidth={10}
strokeLinejoin="round"
strokeLinecap="round"
strokeOpacity={checked || false ? 1 : 0}
/>
<AnimatedPath
d={outlineBoxPath}
strokeWidth={7}
strokeLinejoin="round"
strokeLinecap="round"
animatedProps={animatedBoxProps}
/>
<G clipPath="url(#clipPath)">
<AnimatedStroke
progress={progress}
d={checkMarkPath}
stroke={checkmarkColor}
strokeWidth={10}
strokeLinejoin="round"
strokeLinecap="round"
strokeOpacity={checked || false ? 1 : 0}
/>
</G>
</Svg>
)
}
Example #7
Source File: CurvedTabBar.tsx From curved-bottom-navigation-bar with MIT License | 4 votes |
CurvedTabBarComponent = (props: TabBarViewProps) => {
// props
const {
routes,
selectedIndex,
barWidth,
duration,
dotColor,
tabBarColor,
titleShown,
isRtl,
navigationIndex,
dotSize: SIZE_DOT,
barHeight = TAB_BAR_HEIGHT,
} = props;
// state
const {bottom} = useSafeAreaInsets();
const {width} = useSafeAreaFrame();
const actualBarWidth = useMemo<number>(
() => barWidth || width,
[barWidth, width],
);
const widthTab = useMemo(
() => actualBarWidth / routes.length,
[routes, actualBarWidth],
);
const inputRange = useMemo(
() =>
isRtl
? routes.map((_: any, index: number) => index).reverse()
: routes.map((_: any, index: number) => index),
[isRtl, routes],
);
const outputRange = useMemo(
() =>
routes.map(
(_: any, index: number) => (index / routes.length) * actualBarWidth,
),
[routes, actualBarWidth],
);
const actualBarHeight = useMemo<number>(
() => barHeight + bottom,
[barHeight, bottom],
);
const indexAnimated = useDerivedValue(() =>
sharedTiming(selectedIndex.value, {duration}),
);
// func
const renderButtonTab = useCallback(
({key, title, ...configs}: TabRoute, index: number) => {
return (
<ButtonTab
focused={index === selectedIndex.value}
width={actualBarWidth}
key={key}
title={title}
titleShown={titleShown}
indexAnimated={indexAnimated}
countTab={routes.length}
selectedIndex={selectedIndex}
index={index}
{...configs}
/>
);
},
[indexAnimated, routes.length, selectedIndex, titleShown, actualBarWidth],
);
// reanimated
const progress = withSharedTransition(sharedEq(selectedIndex, indexAnimated));
const xPath = useInterpolate(indexAnimated, inputRange, outputRange);
// path
const pathProps = useAnimatedProps<PathProps>(() => {
const centerHoleX = xPath.value + widthTab / 2;
return {
d: `M0,0 L${centerHoleX - SIZE_DOT},0
C${centerHoleX - SIZE_DOT * 0.5},0 ${
centerHoleX - SIZE_DOT * 0.75
},${HEIGHT_HOLE} ${centerHoleX},${HEIGHT_HOLE}
C${centerHoleX + SIZE_DOT * 0.75},${HEIGHT_HOLE} ${
centerHoleX + SIZE_DOT * 0.5
},0 ${centerHoleX + SIZE_DOT} 0
L${actualBarWidth * 2},0 L ${
actualBarWidth * 2
},${actualBarHeight} L 0,${actualBarHeight} Z
`,
};
}, [actualBarWidth, widthTab, SIZE_DOT, actualBarHeight]);
// style
const containerStyle = useMemo<StyleProp<ViewStyle>>(
() => [
{
height: actualBarHeight,
width: actualBarWidth,
},
],
[actualBarHeight, actualBarWidth],
);
const rowTab = useMemo<StyleProp<ViewStyle>>(
() => [
{
width: actualBarWidth,
height: actualBarHeight,
},
],
[actualBarHeight, actualBarWidth],
);
return (
<>
<RNShadow style={[styles.container, containerStyle]}>
<Svg
width={actualBarWidth}
height={actualBarHeight}
style={[styles.svg]}>
<AnimatedPath
animatedProps={pathProps}
translateY={3}
fill={tabBarColor}
stroke={'transparent'}
strokeWidth={0}
/>
</Svg>
</RNShadow>
<View style={[styles.rowTab, rowTab]}>
<Dot
navigationIndex={navigationIndex}
isRtl={isRtl}
dotColor={dotColor}
dotSize={SIZE_DOT}
barHeight={actualBarHeight}
width={actualBarWidth}
selectedIndex={indexAnimated}
routes={routes}
progress={progress}
/>
{routes.map(renderButtonTab)}
</View>
</>
);
}
Example #8
Source File: CurvedTabBar.tsx From curved-bottom-navigation-bar with MIT License | 4 votes |
CurvedTabBarComponent = (props: TabBarViewProps) => {
// props
const {
routes,
selectedIndex,
barWidth,
duration,
dotColor,
tabBarColor,
titleShown,
isRtl,
navigationIndex,
dotSize: SIZE_DOT,
barHeight = TAB_BAR_HEIGHT,
} = props;
// state
const { bottom } = useSafeAreaInsets();
const { width } = useSafeAreaFrame();
const actualBarWidth = useMemo<number>(
() => barWidth || width,
[barWidth, width]
);
const widthTab = useMemo(
() => actualBarWidth / routes.length,
[routes, actualBarWidth]
);
const inputRange = useMemo(
() =>
isRtl
? routes.map((_: any, index: number) => index).reverse()
: routes.map((_: any, index: number) => index),
[isRtl, routes]
);
const outputRange = useMemo(
() =>
routes.map(
(_: any, index: number) => (index / routes.length) * actualBarWidth
),
[routes, actualBarWidth]
);
const actualBarHeight = useMemo<number>(
() => barHeight + bottom,
[barHeight, bottom]
);
const indexAnimated = useDerivedValue(() =>
sharedTiming(selectedIndex.value, { duration })
);
// func
const renderButtonTab = useCallback(
({ key, title, ...configs }: TabRoute, index: number) => {
return (
<ButtonTab
focused={index === selectedIndex.value}
width={actualBarWidth}
key={key}
title={title}
titleShown={titleShown}
indexAnimated={indexAnimated}
countTab={routes.length}
selectedIndex={selectedIndex}
index={index}
{...configs}
/>
);
},
[indexAnimated, routes.length, selectedIndex, titleShown, actualBarWidth]
);
// reanimated
const progress = withSharedTransition(sharedEq(selectedIndex, indexAnimated));
const xPath = useInterpolate(indexAnimated, inputRange, outputRange);
// path
const pathProps = useAnimatedProps<PathProps>(() => {
const centerHoleX = xPath.value + widthTab / 2;
return {
d: `M0,0 L${centerHoleX - SIZE_DOT},0
C${centerHoleX - SIZE_DOT * 0.5},0 ${
centerHoleX - SIZE_DOT * 0.75
},${HEIGHT_HOLE} ${centerHoleX},${HEIGHT_HOLE}
C${centerHoleX + SIZE_DOT * 0.75},${HEIGHT_HOLE} ${
centerHoleX + SIZE_DOT * 0.5
},0 ${centerHoleX + SIZE_DOT} 0
L${actualBarWidth * 2},0 L ${
actualBarWidth * 2
},${actualBarHeight} L 0,${actualBarHeight} Z
`,
};
}, [actualBarWidth, widthTab, SIZE_DOT, actualBarHeight]);
// style
const containerStyle = useMemo<StyleProp<ViewStyle>>(
() => [
{
height: actualBarHeight,
width: actualBarWidth,
},
],
[actualBarHeight, actualBarWidth]
);
const rowTab = useMemo<StyleProp<ViewStyle>>(
() => [
{
width: actualBarWidth,
height: actualBarHeight,
},
],
[actualBarHeight, actualBarWidth]
);
return (
<>
<RNShadow style={[styles.container, containerStyle]}>
<Svg
width={actualBarWidth}
height={actualBarHeight}
style={[styles.svg]}
>
<AnimatedPath
animatedProps={pathProps}
translateY={3}
fill={tabBarColor}
stroke={'transparent'}
strokeWidth={0}
/>
</Svg>
</RNShadow>
<View style={[styles.rowTab, rowTab]}>
<Dot
navigationIndex={navigationIndex}
isRtl={isRtl}
dotColor={dotColor}
dotSize={SIZE_DOT}
barHeight={actualBarHeight}
width={actualBarWidth}
selectedIndex={indexAnimated}
routes={routes}
progress={progress}
/>
{routes.map(renderButtonTab)}
</View>
</>
);
}
Example #9
Source File: Candle.tsx From react-native-wagmi-charts with MIT License | 4 votes |
CandlestickChartCandle = ({
candle,
maxHeight,
domain,
margin = 2,
positiveColor = '#10b981',
negativeColor = '#ef4444',
rectProps: overrideRectProps,
lineProps: overrideLineProps,
index,
width,
useAnimations = true,
renderLine = (props) =>
props.useAnimations ? <AnimatedLine {...props} /> : <Line {...props} />,
renderRect = (props) =>
props.useAnimations ? <AnimatedRect {...props} /> : <Rect {...props} />,
}: CandlestickChartCandleProps) => {
const { close, open, high, low } = candle;
const isPositive = close > open;
const fill = isPositive ? positiveColor : negativeColor;
const x = index * width;
const max = Math.max(open, close);
const min = Math.min(open, close);
const lineProps = React.useMemo(
() => ({
stroke: fill,
strokeWidth: 1,
direction: isPositive ? 'positive' : 'negative',
x1: x + width / 2,
y1: getY({ maxHeight, value: low, domain }),
x2: x + width / 2,
y2: getY({ maxHeight, value: high, domain }),
...overrideLineProps,
}),
[
domain,
fill,
high,
isPositive,
low,
maxHeight,
overrideLineProps,
width,
x,
]
);
const animatedLineProps = useAnimatedProps(() => ({
x1: withTiming(x + width / 2),
y1: withTiming(getY({ maxHeight, value: low, domain })),
x2: withTiming(x + width / 2),
y2: withTiming(getY({ maxHeight, value: high, domain })),
}));
const rectProps = React.useMemo(
() => ({
width: width - margin * 2,
fill: fill,
direction: isPositive ? 'positive' : 'negative',
x: x + margin,
y: getY({ maxHeight, value: max, domain }),
height: getHeight({ maxHeight, value: max - min, domain }),
...overrideRectProps,
}),
[
domain,
fill,
isPositive,
margin,
max,
maxHeight,
min,
overrideRectProps,
width,
x,
]
);
const animatedRectProps = useAnimatedProps(() => ({
x: withTiming(x + margin),
y: withTiming(getY({ maxHeight, value: max, domain })),
height: withTiming(getHeight({ maxHeight, value: max - min, domain })),
}));
return (
<>
{renderLine({
...lineProps,
useAnimations,
...(useAnimations ? { animatedProps: animatedLineProps } : {}),
})}
{renderRect({
...rectProps,
useAnimations,
...(useAnimations ? { animatedProps: animatedRectProps } : {}),
})}
</>
);
}
Example #10
Source File: ChartPath.tsx From react-native-wagmi-charts with MIT License | 4 votes |
export function LineChartPathWrapper({
animationDuration = 300,
animationProps = {},
children,
color = 'black',
inactiveColor,
width: strokeWidth = 3,
widthOffset = 20,
pathProps = {},
showInactivePath = true,
animateOnMount,
mountAnimationDuration = animationDuration,
mountAnimationProps = animationProps,
}: LineChartPathWrapperProps) {
const { height, pathWidth, width } = React.useContext(
LineChartDimensionsContext
);
const { currentX, isActive } = useLineChart();
const isMounted = useSharedValue(false);
const hasMountedAnimation = useSharedValue(false);
React.useEffect(() => {
isMounted.value = true;
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
////////////////////////////////////////////////
const svgProps = useAnimatedProps(() => {
const shouldAnimateOnMount = animateOnMount === 'foreground';
const inactiveWidth =
!isMounted.value && shouldAnimateOnMount ? 0 : pathWidth;
let duration =
shouldAnimateOnMount && !hasMountedAnimation.value
? mountAnimationDuration
: animationDuration;
const props =
shouldAnimateOnMount && !hasMountedAnimation.value
? mountAnimationProps
: animationProps;
if (isActive.value) {
duration = 0;
}
return {
width: withTiming(
isActive.value
? // on Web, <svg /> elements don't support negative widths
// https://github.com/coinjar/react-native-wagmi-charts/issues/24#issuecomment-955789904
Math.max(currentX.value, 0)
: inactiveWidth + widthOffset,
Object.assign({ duration }, props),
() => {
hasMountedAnimation.value = true;
}
),
};
});
const viewSize = React.useMemo(() => ({ width, height }), [width, height]);
////////////////////////////////////////////////
let backgroundChildren;
let foregroundChildren;
if (children) {
const iterableChildren = flattenChildren(children);
backgroundChildren = iterableChildren.filter((child) =>
// @ts-ignore
BACKGROUND_COMPONENTS.includes(child?.type?.displayName)
);
foregroundChildren = iterableChildren.filter((child) =>
// @ts-ignore
FOREGROUND_COMPONENTS.includes(child?.type?.displayName)
);
}
////////////////////////////////////////////////
return (
<>
<LineChartPathContext.Provider
value={{
color,
isInactive: showInactivePath,
isTransitionEnabled: pathProps.isTransitionEnabled ?? true,
}}
>
<View style={viewSize}>
<Svg width={width} height={height}>
<LineChartPath
color={color}
inactiveColor={inactiveColor}
width={strokeWidth}
{...pathProps}
/>
{backgroundChildren}
</Svg>
</View>
</LineChartPathContext.Provider>
<LineChartPathContext.Provider
value={{
color,
isInactive: false,
isTransitionEnabled: pathProps.isTransitionEnabled ?? true,
}}
>
<View style={StyleSheet.absoluteFill}>
<AnimatedSVG animatedProps={svgProps} height={height}>
<LineChartPath color={color} width={strokeWidth} {...pathProps} />
{foregroundChildren}
</AnimatedSVG>
</View>
</LineChartPathContext.Provider>
</>
);
}
Example #11
Source File: Dot.tsx From react-native-wagmi-charts with MIT License | 4 votes |
export function LineChartDot({
at,
color: defaultColor = 'black',
dotProps,
hasOuterDot: defaultHasOuterDot = false,
hasPulse = false,
inactiveColor,
outerDotProps,
pulseBehaviour = 'while-inactive',
pulseDurationMs = 800,
showInactiveColor = true,
size = 4,
outerSize = size * 4,
}: LineChartDotProps) {
const { data, isActive } = useLineChart();
const { path, pathWidth: width } = React.useContext(
LineChartDimensionsContext
);
////////////////////////////////////////////////////////////
const { isInactive: _isInactive } = React.useContext(LineChartPathContext);
const isInactive = showInactiveColor && _isInactive;
const color = isInactive ? inactiveColor || defaultColor : defaultColor;
const opacity = isInactive && !inactiveColor ? 0.5 : 1;
const hasOuterDot = defaultHasOuterDot || hasPulse;
////////////////////////////////////////////////////////////
const parsedPath = React.useMemo(() => parse(path), [path]);
////////////////////////////////////////////////////////////
const pointWidth = React.useMemo(
() => width / (data.length - 1),
[data.length, width]
);
////////////////////////////////////////////////////////////
const x = useDerivedValue(() => withTiming(pointWidth * at));
const y = useDerivedValue(() =>
withTiming(getYForX(parsedPath!, x.value) || 0)
);
////////////////////////////////////////////////////////////
const animatedDotProps = useAnimatedProps(() => ({
cx: x.value,
cy: y.value,
}));
const animatedOuterDotProps = useAnimatedProps(() => {
let defaultProps = {
cx: x.value,
cy: y.value,
opacity: 0.1,
r: outerSize,
};
if (!hasPulse) {
return defaultProps;
}
if (isActive.value && pulseBehaviour === 'while-inactive') {
return {
...defaultProps,
r: 0,
};
}
const easing = Easing.out(Easing.sin);
const animatedOpacity = withRepeat(
withSequence(
withTiming(0.8),
withTiming(0, {
duration: pulseDurationMs,
easing,
})
),
-1,
false
);
const scale = withRepeat(
withSequence(
withTiming(0),
withTiming(outerSize, {
duration: pulseDurationMs,
easing,
})
),
-1,
false
);
if (pulseBehaviour === 'while-inactive') {
return {
...defaultProps,
opacity: isActive.value ? withTiming(0) : animatedOpacity,
r: isActive.value ? withTiming(0) : scale,
};
}
return {
...defaultProps,
opacity: animatedOpacity,
r: scale,
};
}, [outerSize]);
////////////////////////////////////////////////////////////
return (
<>
<AnimatedCircle
animatedProps={animatedDotProps}
r={size}
fill={color}
opacity={opacity}
{...dotProps}
/>
{hasOuterDot && (
<AnimatedCircle
animatedProps={animatedOuterDotProps}
fill={color}
{...outerDotProps}
/>
)}
</>
);
}