Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
374bb3c
It works!
tomekzaw Nov 13, 2025
4a2927c
Improve first render, assert no children, add basic error handling an…
tomekzaw Nov 14, 2025
519fe59
Add TODO
tomekzaw Nov 14, 2025
774aa54
Do it better
tomekzaw Nov 14, 2025
b4c025c
Do it actually better
tomekzaw Nov 14, 2025
244a026
Better
tomekzaw Nov 14, 2025
04c8cdd
Animate font size
tomekzaw Nov 14, 2025
09093f0
Merge branch 'main' into @tomekzaw/animated-text
tomekzaw Nov 14, 2025
3dea677
Update App.tsx
tomekzaw Nov 14, 2025
d70e4f5
Erase text props for parent component
tomekzaw Nov 14, 2025
66dec0c
Add TODOs
tomekzaw Nov 17, 2025
95395ab
Merge branch 'main' into @tomekzaw/animated-text
tomekzaw Nov 17, 2025
4be0301
Add animated text example and restore original App.tsx
tomekzaw Nov 17, 2025
485fd5a
Add TODOs
tomekzaw Nov 17, 2025
996c3e7
Migrate amount example to `Animated.Text`
tomekzaw Nov 17, 2025
5e4768a
Update TODOs
tomekzaw Nov 17, 2025
74975f1
Add web support
tomekzaw Nov 17, 2025
5df8c5b
Migrate animated keyboard example to `Animated.Text`
tomekzaw Nov 17, 2025
625dc79
Migrate counter example to `Animated.Text`
tomekzaw Nov 17, 2025
3769c4c
Move `AnimatedTextInput` demo from third-party components example to …
tomekzaw Nov 17, 2025
19385e3
Migrate `PerformanceMonitor` to `Animated.Text`
tomekzaw Nov 17, 2025
88cd13c
Migrate pager example to `Animated.Text`
tomekzaw Nov 17, 2025
ab8690e
Migrate FPS example to `Animated.Text`
tomekzaw Nov 17, 2025
6490063
Merge branch 'main' into @tomekzaw/animated-text
tomekzaw Nov 17, 2025
b714cb8
Update TODOs
tomekzaw Nov 17, 2025
73cb172
Fix crash when text animated prop is an empty string
tomekzaw Nov 17, 2025
c3d981a
Add support for nested text
tomekzaw Nov 17, 2025
35934c2
Stringify animated prop text
tomekzaw Nov 17, 2025
add87f8
Add TODO
tomekzaw Nov 18, 2025
5d614c8
Fix `Animated.Text` inside another `Animated.Text`
tomekzaw Nov 18, 2025
eae53bb
Remove TODO
tomekzaw Nov 18, 2025
6003f6a
Update TODOs
tomekzaw Nov 18, 2025
e7b0c09
Remove condition
tomekzaw Nov 18, 2025
c02ddcd
Improve animated text example
tomekzaw Nov 18, 2025
1a07ced
Add TODO
tomekzaw Nov 18, 2025
267bb83
Update animated text input example
tomekzaw Nov 18, 2025
bc0705c
Remove TODO
tomekzaw Nov 18, 2025
69f073a
Migrate circular slider example
tomekzaw Nov 18, 2025
670ef0a
Remove unused `defaultValue` prop
tomekzaw Nov 18, 2025
4050ab8
Change button title
tomekzaw Nov 18, 2025
d54032c
Add docs
tomekzaw Nov 20, 2025
bb9fc57
Add inline prop example
tomekzaw Nov 20, 2025
ec1dff2
Merge branch 'main' into @tomekzaw/animated-text
tomekzaw Nov 20, 2025
669398e
Fix types in `PerformanceMonitor` component
tomekzaw Nov 20, 2025
2db98f3
Fix `PerformanceMonitor` types again
tomekzaw Nov 20, 2025
3c5341f
Add TS support for the text property in animated props
MatiPl01 Nov 19, 2025
a240814
Revert changes in typetests
MatiPl01 Nov 19, 2025
8fc00ad
Add typetests, number support and inline prop support
tomekzaw Nov 20, 2025
0329044
WIP
tomekzaw Nov 23, 2025
e215082
Merge branch 'main' into @tomekzaw/animated-text
tomekzaw Nov 28, 2025
b0238f8
Merge branch 'main' into @tomekzaw/animated-text
tomekzaw Dec 5, 2025
b330a5b
Update docs
tomekzaw Dec 5, 2025
60cff4e
Fix `.at()` in `getSettledUpdates`
tomekzaw Dec 5, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 3 additions & 16 deletions apps/common-app/src/apps/reanimated/examples/AmountExample.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,20 @@
import React, { useCallback } from 'react';
import { Button, StyleSheet, TextInput, View } from 'react-native';
import { Button, StyleSheet, View } from 'react-native';
import Animated, {
useAnimatedProps,
useDerivedValue,
useSharedValue,
withTiming,
} from 'react-native-reanimated';

const AnimatedTextInput = Animated.createAnimatedComponent(TextInput);

const DELTAS = [-100, -10, -1, 1, 10, 100];

export default function AmountExample() {
const ref = React.useRef(10);

const sv = useSharedValue(ref.current);

const text = useDerivedValue(() => {
return `$${sv.value.toFixed(2)}`;
});

const animatedProps = useAnimatedProps(() => {
return { text: text.value, defaultValue: text.value };
return { text: `$${sv.value.toFixed(2)}` };
});

const setValue = useCallback(
Expand All @@ -36,12 +29,7 @@ export default function AmountExample() {

return (
<View style={styles.container}>
<AnimatedTextInput
animatedProps={animatedProps}
style={styles.text}
editable={false}
underlineColorAndroid="transparent"
/>
<Animated.Text animatedProps={animatedProps} style={styles.text} />
<View style={styles.row}>
{DELTAS.map((delta) => (
<Button
Expand All @@ -65,7 +53,6 @@ const styles = StyleSheet.create({
fontSize: 80,
fontWeight: 'bold',
fontVariant: ['tabular-nums'],
textAlign: 'center',
},
row: {
flexDirection: 'row',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ import Animated, {
useAnimatedStyle,
} from 'react-native-reanimated';

const AnimatedTextInput = Animated.createAnimatedComponent(TextInput);

const KeyboardStateNames = {
[KeyboardState.UNKNOWN]: 'UNKNOWN',
[KeyboardState.OPENING]: 'OPENING',
Expand Down Expand Up @@ -57,13 +55,15 @@ export default function AnimatedKeyboardExample() {
});

const animatedHeightProps = useAnimatedProps(() => {
const text = `Keyboard height: ${keyboard.height.value}`;
return { text, defaultValue: text };
return {
text: `Keyboard height: ${keyboard.height.value}`,
};
});

const animatedStateProps = useAnimatedProps(() => {
const text = `Keyboard state: ${KeyboardStateNames[keyboard.state.value]} - ${keyboard.state.value}`;
return { text, defaultValue: text };
return {
text: `Keyboard state: ${KeyboardStateNames[keyboard.state.value]} - ${keyboard.state.value}`,
};
});

return (
Expand Down Expand Up @@ -98,14 +98,12 @@ export default function AnimatedKeyboardExample() {
</TouchableOpacity>
</Animated.View>
<View style={styles.infoContainer}>
<AnimatedTextInput
<Animated.Text
style={styles.infoText}
editable={false}
animatedProps={animatedHeightProps}
/>
<AnimatedTextInput
<Animated.Text
style={styles.infoText}
editable={false}
animatedProps={animatedStateProps}
/>
</View>
Expand All @@ -127,7 +125,6 @@ const styles = StyleSheet.create({
},
infoText: {
fontWeight: '700',
width: '100%',
},
accessoryBar: {
position: 'absolute',
Expand Down
216 changes: 216 additions & 0 deletions apps/common-app/src/apps/reanimated/examples/AnimatedTextExample.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
import React, { useEffect, useState } from 'react';
import { Button, ScrollView, StyleSheet, Text, View } from 'react-native';
import Animated, {
interpolate,
useAnimatedProps,
useAnimatedStyle,
useDerivedValue,
useSharedValue,
withRepeat,
withTiming,
} from 'react-native-reanimated';

// TODO: add support for the following syntax: <Animated.Text>{sharedValue}</Animated.Text>
// TODO: add support for the following syntax: <Animated.Text>Before {sharedValue} After</Animated.Text>
// TODO: add TypeScript validation that allows <Animated.Text> to either have children or have `text` animated prop
// TODO: add gauges example
// TODO: sync `text` prop updates back to React as `children` prop
// TODO: add docs about Animated.Text
// TODO: convert docs examples from AnimatedTextInput to Animated.Text

export default function AnimatedTextExample() {
const sv = useSharedValue(0);

useEffect(() => {
sv.value = 0;
sv.value = withRepeat(withTiming(1, { duration: 1000 }), -1, true);
}, [sv]);

const textSv = useDerivedValue(() => {
return String(Math.round(sv.value * 100));
});

const stringAnimatedProps = useAnimatedProps(() => {
return {
text: `${Math.round(sv.value * 100)}%`, // string
};
});

const numberAnimatedProps = useAnimatedProps(() => {
return {
text: Math.round(sv.value * 100), // number
};
});

const emptyAnimatedProps = useAnimatedProps(() => {
return {
text: sv.value > 0.5 ? 'Blink' : '', // empty string sometimes
};
});

const animatedStyle = useAnimatedStyle(() => {
return {
fontSize: interpolate(sv.value, [0, 1], [10, 20]),
};
});

const [show, setShow] = useState(false);

return (
<ScrollView contentContainerStyle={styles.container}>
{/* Animated text is an inline prop */}
{/* TODO: fix this example not working after fast refresh */}
<View style={styles.row}>
<Text>Before</Text>
<Animated.Text
text={textSv}
style={[styles.tabularNums, styles.color0]}
/>
<Text>After</Text>
</View>

{/* Animated text is a string */}
<View style={styles.row}>
<Text>Before</Text>
<Animated.Text
animatedProps={stringAnimatedProps}
style={[styles.tabularNums, styles.color1]}
/>
<Text>After</Text>
</View>

{/* Animated text is a number */}
<View style={styles.row}>
<Text>Before</Text>
<Animated.Text
animatedProps={numberAnimatedProps}
style={[styles.tabularNums, styles.color2]}
/>
<Text>After</Text>
</View>

{/* Animated text is an empty string during first render */}
<View style={styles.row}>
<Text>Before</Text>
<Animated.Text
animatedProps={emptyAnimatedProps}
style={[styles.tabularNums, styles.color3]}
/>
<Text>After</Text>
</View>

{/* With animated style */}
<View style={styles.row}>
<Text>Before</Text>
<Animated.Text
animatedProps={numberAnimatedProps}
style={[styles.tabularNums, styles.color4, animatedStyle]}
/>
<Text>After</Text>
</View>

{/* Inside another Text component */}
<View style={styles.row}>
<Text style={styles.italic}>
Before
<Animated.Text
animatedProps={numberAnimatedProps}
style={[styles.tabularNums, styles.color5]}
/>
After
</Text>
</View>

{/* Inside another Animated.Text */}
<View style={styles.row}>
<Animated.Text style={styles.italic}>
Before
<Animated.Text
animatedProps={numberAnimatedProps}
style={[styles.tabularNums, styles.color6]}
/>
After
</Animated.Text>
</View>

{/* Inside another Animated.Text with animatedStyle */}
<View style={styles.row}>
<Animated.Text style={[styles.italic, animatedStyle]}>
Before
<Animated.Text
animatedProps={numberAnimatedProps}
style={[styles.tabularNums, styles.color7]}
/>
After
</Animated.Text>
</View>

{/* Non-empty Animated.Text */}
<View style={styles.row}>
<Animated.Text>Lorem ipsum</Animated.Text>
</View>

{/* Non-empty Animated.Text with animated style */}
<View style={styles.row}>
<Animated.Text style={animatedStyle}>Lorem ipsum</Animated.Text>
</View>

{/* Non-empty Animated.Text with animated text (throws an error) */}
<View style={styles.row}>
{show && (
// @ts-expect-error We don't want to accept text in animatedProps when children are present
<Animated.Text animatedProps={stringAnimatedProps}>
Lorem ipsum
</Animated.Text>
)}
<Button
title="Render non-empty Animated.Text with animated text (throws an error)"
onPress={() => setShow(true)}
/>
</View>
</ScrollView>
);
}

const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
row: {
flexDirection: 'row',
alignItems: 'baseline',
marginBottom: 30,
},
tabularNums: {
fontVariant: ['tabular-nums'],
},
italic: {
fontStyle: 'italic',
},
color0: {
backgroundColor: 'burlywood',
},
color1: {
backgroundColor: 'pink',
},
color2: {
backgroundColor: 'peachpuff',
},
color3: {
backgroundColor: 'khaki',
},
color4: {
backgroundColor: 'palegreen',
},
color5: {
backgroundColor: 'lightskyblue',
},
color6: {
backgroundColor: 'lightsteelblue',
},
color7: {
backgroundColor: 'thistle',
},
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React, { useEffect } from 'react';
import { StyleSheet, TextInput, View } from 'react-native';
import Animated, {
useAnimatedProps,
useSharedValue,
withRepeat,
withTiming,
} from 'react-native-reanimated';

// NOTE: It is recommended to use <Animated.Text> component instead of AnimatedTextInput for text animations.

const AnimatedTextInput = Animated.createAnimatedComponent(TextInput);

export default function AnimatedTextInputExample() {
const sv = useSharedValue(0);

useEffect(() => {
sv.value = 0;
sv.value = withRepeat(withTiming(100, { duration: 1500 }), -1, true);
}, [sv]);

const animatedProps = useAnimatedProps(() => {
return {
text: `${Math.round(sv.value)}`,
defaultValue: `${Math.round(sv.value)}`,
};
});

return (
<View style={styles.container}>
<AnimatedTextInput
animatedProps={animatedProps}
style={styles.input}
editable={false}
underlineColorAndroid="transparent"
/>
</View>
);
}

const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
},
input: {
fontSize: 100,
textAlign: 'center',
fontVariant: ['tabular-nums'],
},
});
Loading
Loading