Skip to content

Commit 6c91879

Browse files
author
Marvin Frachet
authored
Refacto/animations api (#12)
* Refactoring animation API * Adding custom animation in example folder * Adding shine animation to the project * Refacto documentation * Upgrading to v1.0.0
1 parent c5fdf38 commit 6c91879

File tree

11 files changed

+164
-65
lines changed

11 files changed

+164
-65
lines changed

.eslintrc.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
"rules": {
99
"react/jsx-filename-extension": "off",
1010
"jsx-a11y/img-has-alt": "off",
11-
"jsx-a11y/href-no-hash": "off"
11+
"jsx-a11y/href-no-hash": "off",
12+
"import/no-extraneous-dependencies": "off"
1213
},
1314
"env": {
1415
"jest": true

ANIMATIONS.md

Lines changed: 27 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,37 @@
1-
----------
2-
31
# Animations
42

5-
The project allows transitions between a `loading` and a `loaded` state.
6-
7-
These animations have to expose a specific API to make the project open to extensions and external behaviours.
8-
9-
* <a href="#api">Animations API</a>
103
* <a href="#default">Default animations</a>
114
* <a href="#custom">Custom animations</a>
5+
* <a href="#api">Animations API <span style="color:red">(deprecated in >=v1.0.0)</span></a>
6+
7+
8+
<h2 name="default">Default animations</h2>
9+
10+
The project comes with some default animations located in [src/animation](./src/animation). It simply animates the placeholder with visual effects while waiting the real content to appear.
11+
12+
Adding an animation is possible using the [React Native Animated](https://facebook.github.io/react-native/docs/animations.html) component.
13+
14+
You can contribute by creating your own placeholder animations and submitting a pull request.
15+
16+
17+
<h2 name="custom">Custom animations</h2>
18+
19+
Recently, the project has allowed to use custom animations by using the HoC props : `customAnimate`. It accepts a `React.Component` representing an Animation.
20+
21+
From the [Example Folder](./Example/customAnimation.js), we have created a simple animation based on color transitions.
22+
23+
To use this in the code, simply use a `Placeholder` component with the `customAnimate` props :
24+
25+
```javascript
26+
<Placeholder.Media onReady={this.state.isReadyMedia} customAnimate={CustomAnimation}>
27+
<Text>Media loaded</Text>
28+
</Placeholder.Media>
29+
```
1230

1331
<h2 name="API">Animations API</h2>
1432

33+
<span style="color:red">*This is deprecated since v1.0.0, use component instead of this API while working on version >=v1.0.0*</span>
34+
1535
Here's the constraints needed to use Animations inside of [rn-placeholder](./README.md)
1636

1737
**start**
@@ -63,25 +83,3 @@ export default () => {
6383
};
6484
};
6585
```
66-
67-
<h2 name="default">Default animations</h2>
68-
69-
The project comes with some default animations located in [src/animation](./src/animation). It simply animates the placeholder with visual effects while waiting the real content to appear.
70-
71-
Adding an animation is possible using the [React Native Animated](https://facebook.github.io/react-native/docs/animations.html) component.
72-
73-
You can contribute by creating your own placeholder animations and submitting a pull request.
74-
75-
It doesn't need too much extra code compared to a standard react native animation, except the previous API.
76-
77-
<h2 name="custom">Custom animations</h2>
78-
79-
Recently, the project has allowed to use custom animations, always following the below API by using the HoC props : `customAnimate`. It accepts a `function` representing an Animation. From the [Example Folder](./Example/customAnimation.js), we have created a simple animation based on color transitions.
80-
81-
To use this in the code, simply use a `Placeholder` component with the `customAnimate` props :
82-
83-
```javascript
84-
<Placeholder.Media onReady={this.state.isReadyMedia} customAnimate={CustomAnimation}>
85-
<Text>Media loaded</Text>
86-
</Placeholder.Media>
87-
```

API.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ The project currently supports 4 different placeholder components.
1414

1515
Each of this components are wrapped in a HOC that brings two others (optional) props :
1616

17-
- `animate: String`: An optional animation available in the `src/animations` folder (see also [Animation API](ANIMATIONS.md)
17+
- `animate: String`: An optional animation available in the `src/animations` folder (see also [Animations](ANIMATIONS.md)
1818
- `onReady: any`: A value. If it's different from `null` / `undefined` / `empty string` / `0`, the component children are rendered. This props creates the loading feeling and the component apparition when content is loaded.
19-
- `customAnimate: func`: An animation functions that follows the [Animation API](ANIMATIONS.md) to create your own custom animations
19+
- `customAnimate: React.Component`: A custom animation represented by a `React.Component`
2020

2121

2222
Navigate the API documentation :

Example/components/Card.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ export default function Card({ image, username, content, isLoaded, date }) {
5252
<Placeholder.ImageContent
5353
onReady={isLoaded}
5454
lineNumber={2}
55-
animate="fade"
55+
animate="shine"
5656
lastLineWidth="40%"
5757
>
5858
<View>

Example/customAnimation.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import React from 'react';
2+
import { Animated } from 'react-native';
3+
import PropTypes from 'prop-types';
4+
5+
6+
const Colors = ({ children }) => {
7+
const animation = new Animated.Value(0);
8+
9+
function start() {
10+
return Animated.timing(animation, {
11+
toValue: 100,
12+
duration: 1500,
13+
}).start((e) => {
14+
if (e.finished) {
15+
start();
16+
}
17+
});
18+
}
19+
20+
start();
21+
const backgroundColor = animation.interpolate({
22+
inputRange: [0, 50, 100],
23+
outputRange: ['yellow', 'orange', 'blue'],
24+
});
25+
const style = { backgroundColor };
26+
return (
27+
<Animated.View style={style}>
28+
{children}
29+
</Animated.View>
30+
);
31+
};
32+
33+
Colors.propTypes = {
34+
children: PropTypes.shape({}),
35+
};
36+
37+
Colors.defaultProps = {
38+
children: null,
39+
};
40+
41+
export default Colors;

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ Display some placeholder stuff before rendering your text or media content in Re
2020
- <a href="#usage">How to use it ?</a>
2121
- [Components available](./API.md)
2222
- [Creating a custom component](./API.md#custom)
23-
- [Animation API](./ANIMATIONS.md)
2423
- [Using default animations](./ANIMATIONS.md#default)
2524
- [Using a custom animation](./ANIMATIONS.md#custom)
25+
- [Animation API](./ANIMATIONS.md) <span style="color:red">(deprecated in >=v1.0.0)</span>
2626

2727
<h2 name="#usage">Usage</h2>
2828

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "rn-placeholder",
3-
"version": "0.0.7",
3+
"version": "1.0.0",
44
"private": false,
55
"main": "index.js",
66
"homepage": "https://github.com/mfrachet/rn-placeholder",

src/animation/animations.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import FadeAnimation from './fade';
2+
import ShineAnimation from './shine';
23

34
/**
45
* Animation factory
56
* Get an animation by its name
67
*/
78
export default {
8-
fade: () => new FadeAnimation(),
9+
fade: FadeAnimation,
10+
shine: ShineAnimation,
911
};

src/animation/fade.js

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
1+
import React from 'react';
12
import { Animated } from 'react-native';
3+
import PropTypes from 'prop-types';
24

35
/**
46
* Create a repetitive fadein / fadeout animation
57
*/
6-
export default () => {
8+
const Fade = ({ children }) => {
79
const START_VALUE = 0.5;
810
const animation = new Animated.Value(START_VALUE);
911

1012
function start() {
11-
return Animated.sequence([
13+
Animated.sequence([
1214
Animated.timing(animation, {
1315
toValue: 1,
1416
duration: 500,
@@ -24,11 +26,21 @@ export default () => {
2426
});
2527
}
2628

27-
/**
28-
* The two mandatory properties to return
29-
*/
30-
return {
31-
style: { opacity: animation },
32-
start,
33-
};
29+
start();
30+
const style = { opacity: animation };
31+
return (
32+
<Animated.View style={style}>
33+
{children}
34+
</Animated.View>
35+
);
3436
};
37+
38+
Fade.propTypes = {
39+
children: PropTypes.shape({}),
40+
};
41+
42+
Fade.defaultProps = {
43+
children: null,
44+
};
45+
46+
export default Fade;

src/animation/shine.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import React from 'react';
2+
import { Animated, View, StyleSheet } from 'react-native';
3+
import PropTypes from 'prop-types';
4+
5+
const styles = StyleSheet.create({
6+
shine: {
7+
width: 30,
8+
position: 'absolute',
9+
height: '100%',
10+
backgroundColor: '#ffffff',
11+
opacity: 0.4,
12+
},
13+
});
14+
/**
15+
* Create a repetitive Shine animation
16+
*/
17+
const Shine = ({ children }) => {
18+
const animation = new Animated.Value(0);
19+
20+
function start() {
21+
animation.setValue(0);
22+
Animated.sequence([
23+
Animated.timing(animation, {
24+
toValue: 100,
25+
duration: 750,
26+
}),
27+
]).start(() => {
28+
start();
29+
});
30+
}
31+
32+
start();
33+
34+
const left = animation.interpolate({
35+
inputRange: [0, 100],
36+
outputRange: ['0%', '100%'],
37+
});
38+
39+
return (
40+
<View>
41+
{children}
42+
<Animated.View style={[styles.shine, { left }]} />
43+
</View>
44+
);
45+
};
46+
47+
Shine.propTypes = {
48+
children: PropTypes.shape({}),
49+
};
50+
51+
Shine.defaultProps = {
52+
children: null,
53+
};
54+
55+
export default Shine;

src/placeholderContainer.js

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,18 @@
11
import React from 'react';
22
import PropTypes from 'prop-types';
3-
import { Animated } from 'react-native';
43
import Animations from './animation/animations';
54

6-
const computeStyleForAnimation = (animation) => {
7-
if (!animation.start) {
8-
throw new Error('No method `start` found in the animation');
5+
const renderAnimation = (Animation, Component, props) => {
6+
if (!Animation) {
7+
throw new Error(`${Animation.name} doesnt exist in the current project`);
98
}
10-
11-
if (!animation.style) {
12-
throw new Error('No property `style` found in the animation');
13-
}
14-
animation.start();
15-
return animation.style;
9+
return (
10+
<Animation>
11+
<Component {...props} />
12+
</Animation>
13+
);
1614
};
1715

18-
const renderAnimation = (Component, style, props) => (
19-
<Animated.View style={style}>
20-
<Component {...props} />
21-
</Animated.View>
22-
);
23-
2416
/**
2517
* Higher order component that factors animation and state ready
2618
* @param PlaceholderComponent
@@ -34,13 +26,11 @@ const connect = (PlaceholderComponent) => {
3426
}
3527

3628
if (customAnimate) {
37-
const style = computeStyleForAnimation(customAnimate());
38-
return renderAnimation(PlaceholderComponent, style, props);
29+
return renderAnimation(customAnimate, PlaceholderComponent, props);
3930
}
4031

4132
if (animate) {
42-
const style = computeStyleForAnimation(Animations[animate]());
43-
return renderAnimation(PlaceholderComponent, style, props);
33+
return renderAnimation(Animations[animate], PlaceholderComponent, props);
4434
}
4535
return <PlaceholderComponent {...props} />;
4636
}

0 commit comments

Comments
 (0)