├── .babelrc ├── .eslintrc ├── .gitignore ├── .npmignore ├── README.md ├── modules ├── Bounce │ ├── index.jsx │ └── readme.md ├── Fade │ ├── index.jsx │ └── readme.md ├── Parallax │ ├── index.jsx │ └── readme.md ├── Plate │ ├── index.jsx │ └── readme.md ├── PopUp │ ├── index.jsx │ ├── readme.md │ └── styles.js └── index.js ├── package.json ├── styleguide.config.js └── template.html /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "stage": 0, 3 | "optional": ["es7.decorators"], 4 | "env": { 5 | "development": { 6 | "plugins": [ 7 | "react-transform", 8 | "react-autoprefix" 9 | ], 10 | "extra": { 11 | "react-transform": { 12 | "transforms": [{ 13 | "transform": "react-transform-hmr", 14 | "imports": ["react"], 15 | "locals": ["module"] 16 | }, { 17 | "transform": "react-transform-catch-errors", 18 | "imports": ["react", "redbox-react"] 19 | }] 20 | } 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | parser: "babel-eslint" 2 | 3 | extends: 'airbnb' 4 | 5 | env: 6 | browser: true 7 | node: true 8 | es6: true 9 | mocha: true 10 | 11 | rules: 12 | object-curly-spacing: [2, 'always'] 13 | indent: [2, 'tab'] 14 | semi: [2, 'never'] 15 | jsx-quotes: [2, 'prefer-single'] 16 | id-length: 0 17 | 18 | ecmaFeatures: 19 | jsx: true 20 | module: true 21 | 22 | plugins: 23 | - react 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /lib/ 2 | /build/ 3 | /index.html 4 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /build 2 | /index.html 3 | /styleguide.config.js 4 | /.eslintrc 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-motion-pack 2 | **• work in progress •** 3 | 4 | Library of React animated components 5 | [Demo](http://nitive.github.io/react-motion-pack/) 6 | 7 | ### Main idea: 8 | * Rule behaivor not appearance 9 | * As easy as possible - just wrap your block into component to get animation 10 | 11 | ### Dependences 12 | * [react](https://github.com/facebook/react) 13 | * [react-motion](https://github.com/chenglou/react-motion) 14 | 15 | ### Installation 16 | `npm install --save react-motion-pack react react-motion` 17 | -------------------------------------------------------------------------------- /modules/Bounce/index.jsx: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react' 2 | import { Motion, spring } from 'react-motion' 3 | 4 | export default class Bounce extends React.Component { 5 | 6 | static propTypes = { 7 | children: PropTypes.node.isRequired, 8 | type: PropTypes.oneOf(['in', 'out']), 9 | side: PropTypes.oneOf(['left', 'right', 'up', 'down', 'none']), 10 | offset: PropTypes.number, 11 | } 12 | 13 | static defaultProps = { 14 | type: 'in', 15 | side: 'none', 16 | offset: 0, 17 | } 18 | 19 | render() { 20 | const { type, side, offset, children } = this.props 21 | 22 | const config = { 23 | opacity: [80, 11], 24 | translate: [350, 12], 25 | scale: [300, 8], 26 | } 27 | 28 | const getContent = ({ opacity, translateX, translateY, scaleX, scaleY }) => { 29 | const style = { 30 | opacity, 31 | transform: `scale(${scaleX}, ${scaleY})translate3d(${translateX}px, ${translateY}px, 0)`, 32 | } 33 | return React.cloneElement(children, { style }) 34 | } 35 | 36 | let x = side === 'left' ? -offset : 0 37 | x = side === 'right' ? offset : x 38 | 39 | let y = side === 'up' ? offset : 0 40 | y = side === 'down' ? -offset : y 41 | 42 | 43 | const hideStyle = { 44 | opacity: spring(0), 45 | translateX: spring(x), 46 | translateY: spring(y), 47 | scaleX: spring(0.8), 48 | scaleY: spring(0.8), 49 | } 50 | 51 | const showStyle = { 52 | opacity: spring(1, config.opacity), 53 | translateX: spring(0, config.translate), 54 | translateY: spring(0, config.translate), 55 | scaleX: spring(1, config.scale), 56 | scaleY: spring(1, config.scale), 57 | } 58 | 59 | return ( 60 | 64 | {interpolated => getContent(interpolated)} 65 | 66 | ) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /modules/Bounce/readme.md: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |
5 | 6 | 7 |
8 | 9 |
10 | -------------------------------------------------------------------------------- /modules/Fade/index.jsx: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react' 2 | import { Motion, spring } from 'react-motion' 3 | 4 | export default class Fade extends React.Component { 5 | 6 | static propTypes = { 7 | children: PropTypes.node.isRequired, 8 | type: PropTypes.oneOf(['in', 'out']), 9 | side: PropTypes.oneOf(['left', 'right', 'up', 'down', 'none']), 10 | offset: PropTypes.number, 11 | } 12 | 13 | static defaultProps = { 14 | type: 'in', 15 | side: 'none', 16 | offset: 0, 17 | } 18 | 19 | render() { 20 | const { type, side, offset, children } = this.props 21 | 22 | const getContent = ({ opacity, translateX, translateY }) => { 23 | const style = { 24 | opacity, 25 | transform: `translate3d(${translateX}px, ${translateY}px, 0)`, 26 | } 27 | return React.cloneElement(children, { style }) 28 | } 29 | 30 | let x = side === 'left' ? -offset : 0 31 | x = side === 'right' ? offset : x 32 | 33 | let y = side === 'up' ? offset : 0 34 | y = side === 'down' ? -offset : y 35 | 36 | const hideStyle = { 37 | opacity: spring(0), 38 | translateX: spring(x), 39 | translateY: spring(y), 40 | } 41 | 42 | const showStyle = { 43 | opacity: spring(1, [80, 11]), 44 | translateY: spring(0), 45 | translateX: spring(0), 46 | } 47 | 48 | return ( 49 | 53 | { interpolated => getContent(interpolated) } 54 | 55 | ) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /modules/Fade/readme.md: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | -------------------------------------------------------------------------------- /modules/Parallax/index.jsx: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react' 2 | 3 | export default class Parallax extends React.Component { 4 | 5 | static propTypes = { 6 | children: PropTypes.node.isRequired, 7 | scope: PropTypes.number, 8 | speed: PropTypes.number, 9 | offset: PropTypes.number, 10 | } 11 | 12 | static defaultProps = { 13 | speed: 1, 14 | scope: 100, 15 | offset: 0, 16 | } 17 | 18 | 19 | componentWillMount() { 20 | this.setState({ 21 | position: this.getPosition(), 22 | }) 23 | } 24 | 25 | 26 | componentDidMount() { 27 | const ref = this.refs.node 28 | const node = React.version.slice(0, 4) === '0.13' ? ref.getDOMNode() : ref 29 | this.startOffset = node.offsetTop 30 | window.addEventListener('scroll', this.scrollHandler) 31 | } 32 | 33 | 34 | componentWillUnmount() { 35 | window.removeEventListener('scroll', this.scrollHandler) 36 | } 37 | 38 | getPosition = () => { 39 | const { scope, offset, speed } = this.props 40 | const position = ((window.pageYOffset - this.startOffset) * speed) 41 | return Math.min(-Math.min(scope - offset, position), scope + offset) 42 | } 43 | 44 | scrollHandler = () => { 45 | this.setState({ 46 | position: this.getPosition(), 47 | }) 48 | } 49 | 50 | 51 | render() { 52 | const style = { 53 | transform: `translateY(${this.state.position}px)`, 54 | } 55 | 56 | return React.cloneElement(this.props.children, { style, ref: 'node' }) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /modules/Parallax/readme.md: -------------------------------------------------------------------------------- 1 | 20 | 21 |
22 | 23 |
24 | default 25 |
26 |
27 | 28 |
29 | offset = 200 30 |
31 |
32 | 33 |
34 | scope = 50 35 |
36 |
37 | 38 |
39 | speed = 2 40 |
41 |
42 |
43 | -------------------------------------------------------------------------------- /modules/Plate/index.jsx: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react' 2 | import { Motion, spring } from 'react-motion' 3 | 4 | const configs = { 5 | down: { 6 | origin: 'center top', 7 | axis: 'X', 8 | coef: -1, 9 | }, 10 | up: { 11 | origin: 'center bottom', 12 | axis: 'X', 13 | coef: 1, 14 | }, 15 | left: { 16 | origin: 'left center', 17 | axis: 'Y', 18 | coef: 1, 19 | }, 20 | right: { 21 | origin: 'right center', 22 | axis: 'Y', 23 | coef: -1, 24 | }, 25 | } 26 | 27 | export default class Plate extends React.Component { 28 | 29 | static propTypes = { 30 | children: PropTypes.node.isRequired, 31 | type: PropTypes.oneOf(['in', 'out']), 32 | side: PropTypes.oneOf(['left', 'right', 'up', 'down']), 33 | move: PropTypes.oneOf(['pull', 'push']), 34 | perspective: PropTypes.number, 35 | } 36 | 37 | static defaultProps = { 38 | type: 'in', 39 | side: 'down', 40 | move: 'pull', 41 | perspective: 300, 42 | } 43 | 44 | render() { 45 | const { type, side, move, perspective, children } = this.props 46 | 47 | const config = configs[side] || configs.down 48 | 49 | const getContent = ({ rotate }) => { 50 | const style = { 51 | backfaceVisibility: 'hidden', 52 | transformStyle: 'preserve-3d', 53 | transformOrigin: config.origin, 54 | transform: `perspective(${perspective}px)rotate${config.axis}(${rotate}deg)`, 55 | } 56 | return React.cloneElement(children, { style }) 57 | } 58 | 59 | const hideStyle = { 60 | rotate: spring(120 * config.coef * (move !== 'push' ? 1 : -1)), 61 | } 62 | 63 | const showStyle = { 64 | rotate: spring(0, [80, 6]), 65 | } 66 | 67 | return ( 68 | 72 | {interpolated => getContent(interpolated)} 73 | 74 | ) 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /modules/Plate/readme.md: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |
5 | 6 | 7 |
8 | 9 | 10 |
11 | 12 | 13 |
14 | 15 | 16 |
17 | 18 |
19 | -------------------------------------------------------------------------------- /modules/PopUp/index.jsx: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react' 2 | import { Motion, spring } from 'react-motion' 3 | import { wrapper, content } from './styles' 4 | 5 | 6 | export default class PopUp extends React.Component { 7 | 8 | static propTypes = { 9 | children: PropTypes.node.isRequired, 10 | show: PropTypes.bool, 11 | position: PropTypes.oneOf(['static', 'relative', 'absolute', 'fixed']), 12 | className: PropTypes.string, 13 | style: PropTypes.object, 14 | } 15 | 16 | static defaultProps = { 17 | show: true, 18 | position: 'fixed', 19 | } 20 | 21 | 22 | render() { 23 | const { 24 | show, 25 | style, 26 | className, 27 | position, 28 | } = this.props 29 | 30 | const enterConfig = [120, 11] 31 | const leaveConfig = [300, 28] 32 | 33 | const getContent = interpolated => ( 34 |
35 |
40 | {this.props.children} 41 |
42 |
43 | ) 44 | 45 | return ( 46 | 50 | {interpolated => getContent(interpolated)} 51 | 52 | ) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /modules/PopUp/readme.md: -------------------------------------------------------------------------------- 1 | 44 | 45 | **Basic PopUp:** 46 | Change `show` property to see animation 47 | 48 | 49 | You must specify show property to hide element with animation 50 | instead to disable rendering. Otherwise you will lose animation. 51 | 52 | 53 | 57 |
58 | Lorem ipsum dolor sit amet, consectetur adipisicing elit. 59 | Accusantium ea deleniti alias voluptatum, dolorum ullam eos dolores 60 | itaque harum adipisci maiores praesentium magni beatae officiis 61 | at accusamus facere modi vero. 62 |
63 |
64 | 65 | 66 | 67 | **Fixed PopUp (Default):** 68 | Change `show` property to unhide 69 | 70 | 73 |
74 | Sed ut perspiciatis unde omnis iste natus error sit voluptatem 75 | accusantium doloremque laudantium, totam rem aperiam, eaque ipsa 76 | quae ab illo inventore veritatis et quasi architecto beatae vitae 77 | dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit 78 | aspernatur aut odit aut fugit, sed quia consequuntur magni dolores 79 | eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, 80 | qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, 81 | sed quia non numquam eius modi tempora incidunt ut labore et dolore 82 | magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis 83 | nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut 84 | aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit 85 | qui in ea voluptate velit esse quam nihil molestiae consequatur, 86 | vel illum qui dolorem eum fugiat quo voluptas nulla pariatur? 87 |
88 |
89 | -------------------------------------------------------------------------------- /modules/PopUp/styles.js: -------------------------------------------------------------------------------- 1 | export const content = { 2 | marginRight: 'auto', 3 | marginLeft: 'auto', 4 | backgroundColor: 'initial', 5 | } 6 | 7 | export const wrapper = { 8 | display: 'flex', 9 | flexDirection: 'column', 10 | justifyContent: 'center', 11 | 12 | position: 'fixed', 13 | top: 0, 14 | left: 0, 15 | right: 0, 16 | bottom: 0, 17 | zIndex: 99999, 18 | 19 | height: '100%', 20 | backgroundColor: 'transparent', 21 | pointerEvents: 'none', 22 | } 23 | -------------------------------------------------------------------------------- /modules/index.js: -------------------------------------------------------------------------------- 1 | export PopUp from './PopUp' 2 | export Parallax from './Parallax' 3 | export Fade from './Fade' 4 | export Bounce from './Bounce' 5 | export Plate from './Plate' 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-motion-pack", 3 | "version": "0.1.9", 4 | "description": "Library of react components with beautiful animation", 5 | "main": "lib/index.js", 6 | "scripts": { 7 | "build": "gulp", 8 | "prepublish": "npm run build", 9 | "watch": "gulp watch", 10 | "lint": "eslint modules", 11 | "test": "karma start", 12 | "server": "styleguidist server", 13 | "static": "styleguidist build", 14 | "pages": "git checkout gh-pages; git reset --hard master; npm run static; git add -f index.html build; git commit --allow-empty-message -m ''; git push origin +gh-pages; git checkout master" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/Nitive/react-motion-pack.git" 19 | }, 20 | "keywords": [ 21 | "react", 22 | "react-motion", 23 | "react-component", 24 | "animation" 25 | ], 26 | "author": "Maxim Samoilov ", 27 | "license": "MIT", 28 | "bugs": { 29 | "url": "https://github.com/Nitive/react-motion-pack/issues" 30 | }, 31 | "homepage": "https://github.com/Nitive/react-motion-pack#readme", 32 | "peerDependencies": { 33 | "react": ">=0.13.0", 34 | "react-motion": "^0.3.1" 35 | }, 36 | "devDependencies": { 37 | "babel": "^5.8.23", 38 | "babel-eslint": "^4.1.3", 39 | "eslint": "^1.7.1", 40 | "eslint-config-airbnb": "^0.1.0", 41 | "eslint-plugin-react": "^3.6.0", 42 | "gulp": "^3.9.0", 43 | "gulp-babel": "^5.3.0", 44 | "gulp-watch": "^4.3.5", 45 | "mocha": "^2.3.3", 46 | "react": "^0.13.3", 47 | "react-motion": "^0.3.1", 48 | "react-styleguidist": "^0.2.1", 49 | "webpack": "^1.12.2" 50 | }, 51 | "dependencies": { 52 | "babel-plugin-react-autoprefix": "^0.2.6" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /styleguide.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | title: 'React Motion Pack', 3 | rootDir: './modules', 4 | components: './**/*.jsx', 5 | styleguideDir: '.', 6 | serverPort: 3589, 7 | template: './template.html', 8 | } 9 | -------------------------------------------------------------------------------- /template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {%=o.htmlWebpackPlugin.options.title%} 6 | 7 | 8 | Fork me on GitHub 9 |
10 | 11 | 12 | --------------------------------------------------------------------------------