From 98f155ed3dfcdde94dd840793577fdd85dcbad0a Mon Sep 17 00:00:00 2001 From: kacperkapusciak Date: Mon, 20 Jan 2025 12:12:37 +0100 Subject: [PATCH 1/4] chore: add masked view and linear gradient packages --- example/package.json | 2 ++ yarn.lock | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/example/package.json b/example/package.json index 1eace60..2776698 100644 --- a/example/package.json +++ b/example/package.json @@ -10,7 +10,9 @@ }, "dependencies": { "@expo/metro-runtime": "~4.0.0", + "@react-native-masked-view/masked-view": "0.3.2", "expo": "~52.0.25", + "expo-linear-gradient": "~14.0.2", "expo-status-bar": "~2.0.1", "react": "18.3.1", "react-dom": "18.3.1", diff --git a/yarn.lock b/yarn.lock index 8e459b0..25c7ae5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2906,6 +2906,16 @@ __metadata: languageName: node linkType: hard +"@react-native-masked-view/masked-view@npm:0.3.2": + version: 0.3.2 + resolution: "@react-native-masked-view/masked-view@npm:0.3.2" + peerDependencies: + react: ">=16" + react-native: ">=0.57" + checksum: e35ab882148df3f9b71f04355d2fb1b24d6f2aaf29043f80758f398bdf905eed67734b36b072fa8b934923ff4e3d80ccb5e37d8376cb1825272078b96a21dadc + languageName: node + linkType: hard + "@react-native/assets-registry@npm:0.76.6": version: 0.76.6 resolution: "@react-native/assets-registry@npm:0.76.6" @@ -6546,6 +6556,17 @@ __metadata: languageName: node linkType: hard +"expo-linear-gradient@npm:~14.0.2": + version: 14.0.2 + resolution: "expo-linear-gradient@npm:14.0.2" + peerDependencies: + expo: "*" + react: "*" + react-native: "*" + checksum: 3f318f50fae44b1f2f90becf421a1c7c0c2822e0a381031fa6d893899173b7ecc6f0c4eddde699e6825fd091d5576cf5960ba81046aeaf0300f44de1147bb543 + languageName: node + linkType: hard + "expo-modules-autolinking@npm:2.0.5": version: 2.0.5 resolution: "expo-modules-autolinking@npm:2.0.5" @@ -11785,7 +11806,9 @@ __metadata: dependencies: "@babel/core": ^7.20.0 "@expo/metro-runtime": ~4.0.0 + "@react-native-masked-view/masked-view": 0.3.2 expo: ~52.0.25 + expo-linear-gradient: ~14.0.2 expo-status-bar: ~2.0.1 react: 18.3.1 react-dom: 18.3.1 From cc2fc29e17ad6f689a413548b7216d5d227678fb Mon Sep 17 00:00:00 2001 From: kacperkapusciak Date: Mon, 20 Jan 2025 12:12:53 +0100 Subject: [PATCH 2/4] feat: draft working example on iOS and Android --- example/src/App.tsx | 58 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/example/src/App.tsx b/example/src/App.tsx index c2dd33d..5f25e38 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -1,9 +1,23 @@ +import { bounce, ping, pulse, spin } from 'react-native-css-animations'; + import { SafeAreaView, StyleSheet, Text, View } from 'react-native'; +import { LinearGradient } from 'expo-linear-gradient'; import Animated from 'react-native-reanimated'; import Fontisto from '@expo/vector-icons/Fontisto'; import Entypo from '@expo/vector-icons/Entypo'; import EvilIcons from '@expo/vector-icons/EvilIcons'; -import { bounce, ping, pulse, spin } from 'react-native-css-animations'; +import MaskedView from '@react-native-masked-view/masked-view'; + +const AnimatedLinearGradient = Animated.createAnimatedComponent(LinearGradient); + +const shimmer = { + from: { + transform: [{ translateX: '-25%' }], + }, + to: { + transform: [{ translateX: '25%' }], + }, +}; export default function App() { return ( @@ -35,6 +49,42 @@ export default function App() { + + Skimmer + + + + + + } + > + + + + + ); } @@ -116,4 +166,10 @@ const styles = StyleSheet.create({ justifyContent: 'center', borderColor: '#e2e8f0', }, + shimmerContainer: { + width: '100%', + height: 48, + alignItems: 'center', + justifyContent: 'center', + }, }); From d3161209cce8ae07a97540906f786369c8cff2d3 Mon Sep 17 00:00:00 2001 From: kacperkapusciak Date: Mon, 20 Jan 2025 16:44:41 +0100 Subject: [PATCH 3/4] feat: finish off shimmer --- README.md | 50 +++++++++++++++++++++++- example/src/App.tsx | 95 +++++++++++++++++++++++---------------------- src/index.tsx | 26 +++++++++++++ 3 files changed, 123 insertions(+), 48 deletions(-) diff --git a/README.md b/README.md index 2542648..feedd22 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,5 @@ header - Ready-to-use CSS Animation presets for [React Native Reanimated](https://docs.swmansion.com/react-native-reanimated/) > [!TIP] @@ -75,12 +74,36 @@ function App() { } ``` +### Shimmer + +Add `shimmer` style object to an `Animated` component to make it animate from left to right indefinitely. Great for shimmer loading effect. + +Shimmer animation demo + +> [!NOTE] +> While the `shimmer` style object supports both iOS, Android, and the Web, the example video on the right uses `@react-native-masked-view/masked-view` and `expo-linear-gradient`, and thus doesn't work on the Web. + +```jsx +import { shimmer } from 'react-native-css-animations'; +import Animated from 'react-native-reanimated'; + +function App() { + return ; +} +``` + ## Alternative API The following animations are also available in a form of React Native components. ```jsx -import { Spin, Ping, Pulse, Bounce } from 'react-native-css-animations'; +import { + Spin, + Ping, + Pulse, + Bounce, + Shimmer, +} from 'react-native-css-animations'; function App() { return ( @@ -91,6 +114,29 @@ function App() { } ``` +## Customizing animation presets + +You can customize the animation style objects by overriding the styles like so: + +```diff +import { shimmer } from 'react-native-css-animations'; +import Animated from 'react-native-reanimated'; + +function App() { + return +} +``` + ## Credits - The examples and animations were adopted from [Tailwind CSS](https://tailwindcss.com/docs/animation). diff --git a/example/src/App.tsx b/example/src/App.tsx index 5f25e38..b1e171d 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -1,6 +1,12 @@ -import { bounce, ping, pulse, spin } from 'react-native-css-animations'; +import { + bounce, + ping, + pulse, + shimmer, + spin, +} from 'react-native-css-animations'; -import { SafeAreaView, StyleSheet, Text, View } from 'react-native'; +import { Platform, SafeAreaView, StyleSheet, Text, View } from 'react-native'; import { LinearGradient } from 'expo-linear-gradient'; import Animated from 'react-native-reanimated'; import Fontisto from '@expo/vector-icons/Fontisto'; @@ -10,15 +16,6 @@ import MaskedView from '@react-native-masked-view/masked-view'; const AnimatedLinearGradient = Animated.createAnimatedComponent(LinearGradient); -const shimmer = { - from: { - transform: [{ translateX: '-25%' }], - }, - to: { - transform: [{ translateX: '25%' }], - }, -}; - export default function App() { return ( @@ -46,45 +43,38 @@ export default function App() { Bounce + {/* Bounce animation ⬇️ */} - Skimmer - - - - - - } - > - - - - - + {(Platform.OS === 'ios' || Platform.OS === 'android') && ( + <> + Shimmer + + + + + + } + > + {/* Shimmer animation ⬇️ */} + + + + + + + )} ); } @@ -172,4 +162,17 @@ const styles = StyleSheet.create({ alignItems: 'center', justifyContent: 'center', }, + mask: { + height: 48, + width: 210, + }, + gradientContainer: { + flex: 1, + width: '300%', + marginHorizontal: '-100%', + }, + gradient: { + flex: 1, + width: '100%', + }, }); diff --git a/src/index.tsx b/src/index.tsx index 91207cd..4a141f3 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -123,3 +123,29 @@ export function Bounce({ ); } + +export const shimmer: CSSStyleDeclaration = { + animationName: { + from: { + transform: [{ translateX: '-25%' }], + }, + to: { + transform: [{ translateX: '25%' }], + }, + }, + animationDuration: '1s', + animationIterationCount: 'infinite', + animationTimingFunction: 'linear', +}; + +export function Shimmer({ + style, + children, + ...rest +}: React.PropsWithChildren): JSX.Element { + return ( + + {children} + + ); +} From b8bf977d037fa97eba392d21f638da5fc923413e Mon Sep 17 00:00:00 2001 From: kacperkapusciak Date: Mon, 20 Jan 2025 16:48:09 +0100 Subject: [PATCH 4/4] chore: remove unnecessary code --- example/src/App.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/example/src/App.tsx b/example/src/App.tsx index b1e171d..a0b41fe 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -14,8 +14,6 @@ import Entypo from '@expo/vector-icons/Entypo'; import EvilIcons from '@expo/vector-icons/EvilIcons'; import MaskedView from '@react-native-masked-view/masked-view'; -const AnimatedLinearGradient = Animated.createAnimatedComponent(LinearGradient); - export default function App() { return ( @@ -63,7 +61,7 @@ export default function App() { > {/* Shimmer animation ⬇️ */} -