├── .babelrc
├── .eslintrc
├── .gitignore
├── README.md
├── dev.js
├── example
├── app.js
├── entry.js
├── index.html
└── reset.css
├── lib
├── components.js
├── ease.js
├── index.js
└── native.js
├── package.json
├── src
├── components.js
├── ease.js
├── index.js
└── native.js
└── webpack.config.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "stage": 0
3 | }
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "rules" :{
4 | "quotes": [1, "single"],
5 | "no-unused-vars": [1, {"vars": "all", "args": "all"}],
6 | "strict": true
7 | },
8 | "env":{
9 | "browser": true,
10 | "node" : true
11 | }
12 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # osx noise
2 | .DS_Store
3 | profile
4 |
5 | # xcode noise
6 | build/*
7 | *.mode1
8 | *.mode1v3
9 | *.mode2v3
10 | *.perspective
11 | *.perspectivev3
12 | *.pbxuser
13 | *.xcworkspace
14 | xcuserdata
15 |
16 | # svn & cvs
17 | .svn
18 | CVS
19 | node_modules
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | (work in progress, looking for feedback)
2 |
3 | react-ease
4 | ---
5 |
6 | back to first principles
7 |
8 | `npm install react-ease react --save`
9 |
10 | canned animations for [react](https://facebook.github.io/react/)/[react-native](https://facebook.github.io/react-native/)
11 |
12 | (if you're looking for something more dynamic, consider [react-springs](https://github.com/threepointone/react-springs))
13 |
14 | ```js
15 | // output floats from 0 to 100 over 0.5 seconds
16 |
17 | {val => {val}
} // yes, children is a function
18 |
19 |
20 | // you can tell when it's done
21 |
22 | {(val, done) => animation {done ? 'over!' : 'running...'}
}
23 |
24 |
25 | // you can ease multiple values at once
26 |
27 | {val => move it, move it
}
28 |
29 |
30 | // or if you want more control over each value
31 | {x =>
32 | {y =>
33 | not bad!
}
34 | }
35 |
36 |
37 | // finally, you can chain a bunch of them together
38 | done && console.log('done!')}
43 | repeat={5}>
44 | {(val, done) => sweet!
}
45 |
46 |
47 |
48 | ```
49 |
50 | Ease::props
51 | ---
52 |
53 | - from: *number*/*object*
54 | - to: *number*/*object*
55 | - duration: *number* (ms)
56 | - ease: *string*/*function* `./src.js` has a list of available easing functions, or pass in your own
57 | - delay: *number* (ms)
58 | - onProgress: *function* - optional callback called on every 'movement'. 'returns' the current value, and a `done` flag
59 | - repeat: *number*
60 |
61 | Chain::props
62 | ---
63 |
64 | - sequence: *array*
65 | - repeat: *number*
66 |
67 | thanks
68 | ---
69 | - [ease-sential](https://github.com/WebReflection/ease-sential), of which react-ease contains a tweaked port
70 |
71 |
--------------------------------------------------------------------------------
/dev.js:
--------------------------------------------------------------------------------
1 | import webpack from 'webpack';
2 | import WebpackDevServer from 'webpack-dev-server';
3 | import config from './webpack.config';
4 |
5 | const isHot = !!process.env.HOT;
6 |
7 | new WebpackDevServer(webpack(config), {
8 | publicPath: config.output.publicPath,
9 | hot: isHot,
10 | historyApiFallback: true
11 | }).listen(3000, 'localhost', err => console.log(err || 'webpack at localhost:3000'));
12 |
--------------------------------------------------------------------------------
/example/app.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Ease, Chain} from '../src';
3 |
4 | let styles = {};
5 |
6 | styles.app = {
7 | box: {
8 | width: 100,
9 | height: 100,
10 | left: 0,
11 | top: 0,
12 | position: 'absolute',
13 | backgroundColor: 'red'
14 | }
15 | };
16 |
17 | export const App = React.createClass({
18 | render() {
19 | return (
20 |
21 |
22 | {val => }
23 |
24 |
25 |
26 | );
27 | }
28 | });
29 |
30 | styles.chained = {
31 | box: {
32 | width: 100,
33 | height: 100,
34 | left: 0,
35 | top: 0,
36 | position: 'absolute',
37 | backgroundColor: 'blue'
38 | }
39 | };
40 |
41 |
42 | export const Chained = React.createClass({
43 | render() {
44 | return (
45 |
46 |
51 | {(val, done) => sweet! {done ? 'done!' :
{JSON.stringify(val, null, ' ')}
}
}
52 |
53 |
54 | );
55 | }
56 | });
57 |
58 |
59 |
--------------------------------------------------------------------------------
/example/entry.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {App} from './app';
3 | React.render(, document.getElementById('container'));
4 | window.React = React;
5 |
--------------------------------------------------------------------------------
/example/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | react-ease
5 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/example/reset.css:
--------------------------------------------------------------------------------
1 | /*! normalize.css v3.0.1 | MIT License | git.io/normalize */
2 |
3 | // * 1. Set default font family to sans-serif.
4 | // * 2. Prevent iOS text size adjust after orientation change, without disabling user zoom.
5 | html {
6 | font-family: sans-serif;
7 | -ms-text-size-adjust: 100%;
8 | -webkit-text-size-adjust: 100%;
9 | }
10 |
11 | // Remove default margin.
12 | body { margin: 0 }
13 |
14 | // HTML5 display definitions ==========================================================================
15 | // * Correct `block` display not defined for any HTML5 element in IE 8/9.
16 | // * Correct `block` display not defined for `details` or `summary` in IE 10/11 and Firefox.
17 | // * Correct `block` display not defined for `main` in IE 11.
18 | article,
19 | aside,
20 | details,
21 | figcaption,
22 | figure,
23 | footer,
24 | header,
25 | hgroup,
26 | main,
27 | nav,
28 | section,
29 | summary {
30 | display: block;
31 | }
32 |
33 | // * 1. Correct `inline-block` display not defined in IE 8/9.
34 | // * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
35 | audio,
36 | canvas,
37 | progress,
38 | video {
39 | display: inline-block;
40 | vertical-align: baseline;
41 | }
42 |
43 | // * Prevent modern browsers from displaying `audio` without controls.
44 | // * Remove excess height in iOS 5 devices.
45 | audio:not([controls]) {
46 | display: none;
47 | height: 0;
48 | }
49 |
50 | // * Address `[hidden]` styling not present in IE 8/9/10.
51 | // * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22.
52 | [hidden],
53 | template {
54 | display: none;
55 | }
56 |
57 | // Links ==========================================================================
58 | // * Remove the gray background color from active links in IE 10.
59 | a {
60 | background: transparent;
61 | // * Improve readability when focused and also mouse hovered in all browsers.
62 | &:active,
63 | &:hover {
64 | outline: 0;
65 | }
66 | }
67 |
68 | // Text-level semantics ==========================================================================
69 |
70 | // * Address styling not present in IE 8/9/10/11, Safari, and Chrome.
71 | abbr[title] { border-bottom: 1px dotted; }
72 |
73 | // * Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
74 | b,
75 | strong {
76 | font-weight: bold;
77 | }
78 |
79 | // * Address styling not present in Safari and Chrome.
80 | dfn { font-style: italic; }
81 |
82 | // * Address variable `h1` font-size and margin within `section` and `article` contexts in Firefox 4+, Safari, and Chrome.
83 | h1 {
84 | font-size: 2em;
85 | margin: 0.67em 0;
86 | }
87 |
88 | // * Address styling not present in IE 8/9.
89 | mark {
90 | background: #ff0;
91 | color: #000;
92 | }
93 |
94 | // * Address inconsistent and variable font size in all browsers.
95 | small { font-size: 80%; }
96 |
97 | // * Prevent `sub` and `sup` affecting `line-height` in all browsers.
98 | sub,
99 | sup {
100 | font-size: 75%;
101 | line-height: 0;
102 | position: relative;
103 | vertical-align: baseline;
104 | }
105 |
106 | sup { top: -0.5em; }
107 | sub { bottom: -0.25em; }
108 |
109 | // Embedded content ==========================================================================
110 | // * Remove border when inside `a` element in IE 8/9/10.
111 | img { border: 0; }
112 |
113 | // * Correct overflow not hidden in IE 9/10/11.
114 | svg:not(:root) { overflow: hidden; }
115 |
116 | // Grouping content ==========================================================================
117 | // * Address margin not present in IE 8/9 and Safari.
118 | figure { margin: 1em 40px; }
119 |
120 | // * Address differences between Firefox and other browsers.
121 | hr {
122 | -moz-box-sizing: content-box;
123 | box-sizing: content-box;
124 | height: 0;
125 | }
126 |
127 | // * Contain overflow in all browsers.
128 | pre { overflow: auto; }
129 |
130 | // * Address odd `em`-unit font size rendering in all browsers.
131 | code,
132 | kbd,
133 | pre,
134 | samp {
135 | font-family: monospace, monospace;
136 | font-size: 1em;
137 | }
138 |
139 | // Forms ==========================================================================
140 | // * Known limitation: by default, Chrome and Safari on OS X allow very limited
141 | // * styling of `select`, unless a `border` property is set.
142 |
143 | // * 1. Correct color not being inherited.
144 | // * Known issue: affects color of disabled elements.
145 | // * 2. Correct font properties not being inherited.
146 | // * 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
147 | button,
148 | input,
149 | optgroup,
150 | select,
151 | textarea {
152 | color: inherit;
153 | font: inherit;
154 | margin: 0;
155 | }
156 |
157 | // * Address `overflow` set to `hidden` in IE 8/9/10/11.
158 | button { overflow: visible;}
159 |
160 | // * Address inconsistent `text-transform` inheritance for `button` and `select`.
161 | // * All other form control elements do not inherit `text-transform` values.
162 | // * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
163 | // * Correct `select` style inheritance in Firefox.
164 | button,
165 | select {
166 | text-transform: none;
167 | }
168 |
169 | // * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` and `video` controls.
170 | // * 2. Correct inability to style clickable `input` types in iOS.
171 | // * 3. Improve usability and consistency of cursor style between image-type `input` and others.
172 | button,
173 | html input[type="button"] {
174 | -webkit-appearance: button;
175 | cursor: pointer;
176 | }
177 |
178 | // * Re-set default cursor for disabled elements.
179 | button[disabled],
180 | html input[disabled] {
181 | cursor: default;
182 | }
183 |
184 | // * Remove inner padding and border in Firefox 4+.
185 | button
186 | input {
187 | &::-moz-focus-inner {
188 | border: 0;
189 | padding: 0;
190 | }
191 | }
192 |
193 | // * Address Firefox 4+ setting `line-height` on `input` using `!important` in the UA stylesheet.
194 | input {
195 | line-height: normal;
196 | &[type="reset"],
197 | &[type="submit"] {
198 | -webkit-appearance: button;
199 | cursor: pointer;
200 | }
201 |
202 | // * It's recommended that you don't attempt to style these elements.
203 | // * Firefox's implementation doesn't respect box-sizing, padding, or width.
204 | // * 1. Address box sizing set to `content-box` in IE 8/9/10.
205 | // * 2. Remove excess padding in IE 8/9/10.
206 | &[type="checkbox"],
207 | &[type="radio"] {
208 | box-sizing: border-box;
209 | padding: 0;
210 | }
211 |
212 | // * Fix the cursor style for Chrome's increment/decrement buttons. For certain
213 | // * `font-size` values of the `input`, it causes the cursor style of the
214 | // * decrement button to change from `default` to `text`.
215 | &[type="number"] {
216 | &::-webkit-inner-spin-button,
217 | &::-webkit-outer-spin-button {
218 | height: auto;
219 | }
220 | }
221 |
222 | // * 1. Address `appearance` set to `searchfield` in Safari and Chrome.
223 | // * 2. Address `box-sizing` set to `border-box` in Safari and Chrome (include `-moz` to future-proof).
224 | &[type="search"] {
225 | -webkit-appearance: textfield;
226 | -moz-box-sizing: content-box;
227 | -webkit-box-sizing: content-box;
228 | box-sizing: content-box;
229 |
230 | // * Remove inner padding and search cancel button in Safari and Chrome on OS X.
231 | // * Safari (but not Chrome) clips the cancel button when the search input has
232 | // * padding (and `textfield` appearance).
233 | &::-webkit-search-cancel-button,
234 | &::-webkit-search-decoration {
235 | -webkit-appearance: none;
236 | }
237 | }
238 |
239 | }
240 |
241 | // * Define consistent border, margin, and padding.
242 | fieldset {
243 | border: 1px solid #c0c0c0;
244 | margin: 0 2px;
245 | padding: 0.35em 0.625em 0.75em;
246 | }
247 |
248 | // * 1. Correct `color` not being inherited in IE 8/9/10/11.
249 | // * 2. Remove padding so people aren't caught out if they zero out fieldsets.
250 | legend {
251 | border: 0;
252 | padding: 0;
253 | }
254 |
255 | // * Remove default vertical scrollbar in IE 8/9/10/11.
256 | textarea { overflow: auto; }
257 |
258 | // * Don't inherit the `font-weight` (applied by a rule above).
259 | // * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
260 | optgroup { font-weight: bold; }
261 |
262 | // Tables ==========================================================================
263 | // * Remove most spacing between table cells.
264 | table {
265 | border-collapse: collapse;
266 | border-spacing: 0;
267 | }
268 |
269 | td,
270 | th {
271 | padding: 0;
272 | }
273 |
274 | body{
275 | font-family:helvetica, sans-serif;
276 | }
277 |
278 |
279 | html, body{
280 | position:relative;
281 | display:block;
282 | height:100%;
283 | width:100%;
284 | padding:0;
285 | margin:0;
286 | }
287 |
288 | /* css-layout defaults */
289 | div, span, html, body{
290 | box-sizing: border-box;
291 | position: relative;
292 |
293 | display: flex;
294 | flex-direction: column;
295 | align-items: stretch;
296 | flex-shrink: 0;
297 |
298 | border: 0 solid black;
299 | margin: 0;
300 | padding: 0;
301 | }
302 |
303 | /* stretch out container */
304 | #container{
305 | flex:1;
306 | }
--------------------------------------------------------------------------------
/lib/components.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | Object.defineProperty(exports, '__esModule', {
4 | value: true
5 | });
6 |
7 | var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
8 |
9 | exports['default'] = components;
10 |
11 | var _ease = require('./ease');
12 |
13 | var noop = function noop() {};
14 |
15 | function components(React) {
16 |
17 | var Ease = React.createClass({
18 | displayName: 'Ease',
19 |
20 | propTypes: {
21 | // from: React.PropTypes.number,
22 | // to: React.PropTypes.number,
23 | duration: React.PropTypes.number,
24 | // ease: easings[easings.default],
25 | repeat: React.PropTypes.number,
26 | onProgress: React.PropTypes.func,
27 | delay: React.PropTypes.number,
28 | children: React.PropTypes.func
29 | },
30 | getDefaultProps: function getDefaultProps() {
31 | return _ease.defaults;
32 | },
33 | shouldComponentUpdate: function shouldComponentUpdate() {
34 | return true;
35 | },
36 |
37 | getInitialState: function getInitialState() {
38 | return {
39 | value: this.props.from,
40 | done: false
41 | };
42 | },
43 | componentDidMount: function componentDidMount() {
44 | var _this = this;
45 |
46 | this.ease = new _ease.Easing(_extends({}, this.props, { onProgress: function onProgress(value, done) {
47 | _this.setState({ value: value, done: done });
48 | _this.props.onProgress(value, done);
49 | } }));
50 | },
51 | componentWillUnmount: function componentWillUnmount() {
52 | this.ease.cancel();
53 | delete this.ease;
54 | },
55 | render: function render() {
56 | return this.props.children(this.state.value, this.state.done);
57 | }
58 | });
59 |
60 | var Chain = React.createClass({
61 | displayName: 'Chain',
62 |
63 | getDefaultProps: function getDefaultProps() {
64 | return {
65 | onProgress: noop,
66 | repeat: 1
67 | };
68 | },
69 | propTypes: {
70 | sequence: React.PropTypes.array,
71 | children: React.PropTypes.func,
72 | onProgress: React.PropTypes.func
73 | },
74 | getInitialState: function getInitialState() {
75 | var props = this.props.sequence[0];
76 | return {
77 | index: 0,
78 | done: false,
79 | value: props.from,
80 | from: props.from,
81 | to: typeof props.to === 'number' ? props.to : _extends({}, props.from, props.to)
82 | };
83 | },
84 |
85 | shouldComponentUpdate: function shouldComponentUpdate() {
86 | return true;
87 | },
88 | onProgress: function onProgress(value, done) {
89 | this.props.onProgress(this.state.index, value, done);
90 |
91 | if (done) {
92 | var _length = this.props.repeat * this.props.sequence.length;
93 | var allDone = this.state.index === _length - 1;
94 | var props = this.props.sequence[(this.state.index + 1) % this.props.sequence.length] || {};
95 | var mergeable = typeof value !== 'number' && !allDone;
96 | this.setState({
97 | index: allDone ? this.state.index : this.state.index + 1,
98 | done: allDone,
99 | value: value,
100 | from: mergeable ? _extends({}, value, props.from || {}) : props.from !== undefined ? props.from : value,
101 | to: mergeable ? _extends({}, value, props.to || {}) : props.to
102 | });
103 | }
104 | },
105 | render: function render() {
106 | var _this2 = this;
107 |
108 | var props = this.props.sequence[this.state.index % this.props.sequence.length];
109 | var fn = function fn(val) {
110 | return _this2.props.children(val, _this2.state.done);
111 | };
112 | return this.state.done ? fn(this.state.value, true) : React.createElement(
113 | Ease,
114 | _extends({}, props, { key: this.state.index, onProgress: this.onProgress, from: this.state.from, to: this.state.to }),
115 | fn
116 | );
117 | }
118 | });
119 |
120 | return { Ease: Ease, Chain: Chain };
121 | }
122 |
123 | module.exports = exports['default'];
--------------------------------------------------------------------------------
/lib/ease.js:
--------------------------------------------------------------------------------
1 |
2 | // pick up raf
3 | 'use strict';
4 |
5 | Object.defineProperty(exports, '__esModule', {
6 | value: true
7 | });
8 |
9 | var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
10 |
11 | var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
12 |
13 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
14 |
15 | var root = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : undefined;
16 | var raf = root.requestAnimationFrame || root.webkitRequestAnimationFrame || root.mozRequestAnimationFrame || root.msRequestAnimationFrame || function (fn) {
17 | return setTimeout(fn, 10);
18 | };
19 |
20 | exports.raf = raf;
21 | var noop = function noop() {};
22 |
23 | // penner's easing equations
24 | var easings = {
25 | 'default': 'easeOutQuad',
26 | swing: function swing(t, b, c, d) {
27 | return easings[easings['default']](t, b, c, d);
28 | },
29 | easeInQuad: function easeInQuad(t, b, c, d) {
30 | return c * (t /= d) * t + b;
31 | },
32 | easeOutQuad: function easeOutQuad(t, b, c, d) {
33 | return -c * (t /= d) * (t - 2) + b;
34 | },
35 | easeInOutQuad: function easeInOutQuad(t, b, c, d) {
36 | if ((t /= d / 2) < 1) {
37 | return c / 2 * t * t + b;
38 | }
39 | return -c / 2 * (--t * (t - 2) - 1) + b;
40 | },
41 | easeInCubic: function easeInCubic(t, b, c, d) {
42 | return c * (t /= d) * t * t + b;
43 | },
44 | easeOutCubic: function easeOutCubic(t, b, c, d) {
45 | return c * ((t = t / d - 1) * t * t + 1) + b;
46 | },
47 | easeInOutCubic: function easeInOutCubic(t, b, c, d) {
48 | if ((t /= d / 2) < 1) {
49 | return c / 2 * t * t * t + b;
50 | }
51 | return c / 2 * ((t -= 2) * t * t + 2) + b;
52 | },
53 | easeInQuart: function easeInQuart(t, b, c, d) {
54 | return c * (t /= d) * t * t * t + b;
55 | },
56 | easeOutQuart: function easeOutQuart(t, b, c, d) {
57 | return -c * ((t = t / d - 1) * t * t * t - 1) + b;
58 | },
59 | easeInOutQuart: function easeInOutQuart(t, b, c, d) {
60 | if ((t /= d / 2) < 1) {
61 | return c / 2 * t * t * t * t + b;
62 | }
63 | return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
64 | },
65 | easeInQuint: function easeInQuint(t, b, c, d) {
66 | return c * (t /= d) * t * t * t * t + b;
67 | },
68 | easeOutQuint: function easeOutQuint(t, b, c, d) {
69 | return c * ((t = t / d - 1) * t * t * t * t + 1) + b;
70 | },
71 | easeInOutQuint: function easeInOutQuint(t, b, c, d) {
72 | if ((t /= d / 2) < 1) {
73 | return c / 2 * t * t * t * t * t + b;
74 | }
75 | return c / 2 * ((t -= 2) * t * t * t * t + 2) + b;
76 | },
77 | easeInSine: function easeInSine(t, b, c, d) {
78 | return -c * Math.cos(t / d * (Math.PI / 2)) + c + b;
79 | },
80 | easeOutSine: function easeOutSine(t, b, c, d) {
81 | return c * Math.sin(t / d * (Math.PI / 2)) + b;
82 | },
83 | easeInOutSine: function easeInOutSine(t, b, c, d) {
84 | return -c / 2 * (Math.cos(Math.PI * t / d) - 1) + b;
85 | },
86 | easeInExpo: function easeInExpo(t, b, c, d) {
87 | return t === 0 ? b : c * Math.pow(2, 10 * (t / d - 1)) + b;
88 | },
89 | easeOutExpo: function easeOutExpo(t, b, c, d) {
90 | return t === d ? b + c : c * (-Math.pow(2, -10 * t / d) + 1) + b;
91 | },
92 | easeInOutExpo: function easeInOutExpo(t, b, c, d) {
93 | if (t === 0) {
94 | return b;
95 | }
96 | if (t === d) {
97 | return b + c;
98 | }
99 | if ((t /= d / 2) < 1) {
100 | return c / 2 * Math.pow(2, 10 * (t - 1)) + b;
101 | }
102 | return c / 2 * (-Math.pow(2, -10 * --t) + 2) + b;
103 | },
104 | easeInCirc: function easeInCirc(t, b, c, d) {
105 | return -c * (Math.sqrt(1 - (t /= d) * t) - 1) + b;
106 | },
107 | easeOutCirc: function easeOutCirc(t, b, c, d) {
108 | return c * Math.sqrt(1 - (t = t / d - 1) * t) + b;
109 | },
110 | easeInOutCirc: function easeInOutCirc(t, b, c, d) {
111 | if ((t /= d / 2) < 1) {
112 | return -c / 2 * (Math.sqrt(1 - t * t) - 1) + b;
113 | }
114 | return c / 2 * (Math.sqrt(1 - (t -= 2) * t) + 1) + b;
115 | },
116 | easeInElastic: function easeInElastic(t, b, c, d) {
117 | var s = 1.70158;
118 | var p = 0;
119 | var a = c;
120 | if (t === 0) {
121 | return b;
122 | }
123 | if ((t /= d) === 1) {
124 | return b + c;
125 | }
126 | if (!p) {
127 | p = d * 0.3;
128 | }
129 | if (a < Math.abs(c)) {
130 | a = c;
131 | s = p / 4;
132 | } else {
133 | s = p / (2 * Math.PI) * Math.asin(c / a);
134 | }
135 | return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
136 | },
137 | easeOutElastic: function easeOutElastic(t, b, c, d) {
138 | var s = 1.70158;
139 | var p = 0;
140 | var a = c;
141 | if (t === 0) {
142 | return b;
143 | }
144 | if ((t /= d) === 1) {
145 | return b + c;
146 | }
147 | if (!p) {
148 | p = d * 0.3;
149 | }
150 | if (a < Math.abs(c)) {
151 | a = c;
152 | s = p / 4;
153 | } else {
154 | s = p / (2 * Math.PI) * Math.asin(c / a);
155 | }
156 | return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
157 | },
158 | easeInOutElastic: function easeInOutElastic(t, b, c, d) {
159 | var s = 1.70158;
160 | var p = 0;
161 | var a = c;
162 | if (t === 0) {
163 | return b;
164 | }
165 | if ((t /= d / 2) === 2) {
166 | return b + c;
167 | }
168 | if (!p) {
169 | p = d * (0.3 * 1.5);
170 | }
171 | if (a < Math.abs(c)) {
172 | a = c;
173 | s = p / 4;
174 | } else {
175 | s = p / (2 * Math.PI) * Math.asin(c / a);
176 | }
177 | if (t < 1) {
178 | return -0.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
179 | }
180 | return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p) * 0.5 + c + b;
181 | },
182 | easeInBack: function easeInBack(t, b, c, d, s) {
183 | if (s === undefined) {
184 | s = 1.70158;
185 | }
186 | return c * (t /= d) * t * ((s + 1) * t - s) + b;
187 | },
188 | easeOutBack: function easeOutBack(t, b, c, d, s) {
189 | if (s === undefined) {
190 | s = 1.70158;
191 | }
192 | return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
193 | },
194 | easeInOutBack: function easeInOutBack(t, b, c, d, s) {
195 | if (s === undefined) {
196 | s = 1.70158;
197 | }
198 | if ((t /= d / 2) < 1) {
199 | return c / 2 * (t * t * (((s *= 1.525) + 1) * t - s)) + b;
200 | }
201 | return c / 2 * ((t -= 2) * t * (((s *= 1.525) + 1) * t + s) + 2) + b;
202 | },
203 | easeInBounce: function easeInBounce(t, b, c, d) {
204 | return c - easings.easeOutBounce(d - t, 0, c, d) + b;
205 | },
206 | easeOutBounce: function easeOutBounce(t, b, c, d) {
207 | if ((t /= d) < 1 / 2.75) {
208 | return c * (7.5625 * t * t) + b;
209 | } else if (t < 2 / 2.75) {
210 | return c * (7.5625 * (t -= 1.5 / 2.75) * t + 0.75) + b;
211 | } else if (t < 2.5 / 2.75) {
212 | return c * (7.5625 * (t -= 2.25 / 2.75) * t + 0.9375) + b;
213 | } else {
214 | return c * (7.5625 * (t -= 2.625 / 2.75) * t + 0.984375) + b;
215 | }
216 | },
217 | easeInOutBounce: function easeInOutBounce(t, b, c, d) {
218 | if (t < d / 2) {
219 | return easings.easeInBounce(t * 2, 0, c, d) * 0.5 + b;
220 | }
221 | return easings.easeOutBounce(t * 2 - d, 0, c, d) * 0.5 + c * 0.5 + b;
222 | }
223 | };
224 |
225 | exports.easings = easings;
226 | var defaults = {
227 | from: 0,
228 | to: 0,
229 | duration: 1000,
230 | ease: easings[easings['default']],
231 | onProgress: noop,
232 | delay: 0
233 | };
234 |
235 | exports.defaults = defaults;
236 | // to avoid an assign polyfill
237 | function assign(target) {
238 | for (var i = 1; i < arguments.length; i++) {
239 | var source = arguments[i];
240 | for (var key in source) {
241 | if (Object.prototype.hasOwnProperty.call(source, key)) {
242 | target[key] = source[key];
243 | }
244 | }
245 | }
246 | return target;
247 | }
248 |
249 | // animation class
250 | // - from: *number*/*object*
251 | // - to: *number*/*object*
252 | // - duration: *number* (ms)
253 | // - ease: *string*/*function* `./src.js` has a list of available easing functions, or pass in your own
254 | // - delay: *number* (ms)
255 | // - onProgress: *function* - optional callback called on every 'movement'. 'returns' the current value, and a `done` flag
256 |
257 | var Easing = (function () {
258 | function Easing(config) {
259 | var _this = this;
260 |
261 | _classCallCheck(this, Easing);
262 |
263 | assign(this, _extends({}, defaults, config));
264 | this.easing = typeof this.ease === 'function' ? this.ease : easings[this.ease || easings['default']];
265 |
266 | this.update = typeof this.from === 'object' ? this.loopProperties : this.directUpdate;
267 |
268 | this.start = Date.now() + this.delay;
269 | this.end = this.start + this.duration;
270 | this.canceled = false;
271 | this.progress = this.progress.bind(this);
272 |
273 | if (this.delay) {
274 | setTimeout(function () {
275 | return raf(_this.progress);
276 | }, this.delay);
277 | } else {
278 | raf(this.progress);
279 | }
280 | }
281 |
282 | _createClass(Easing, [{
283 | key: 'directUpdate',
284 | value: function directUpdate(from, to, easing, current, duration) {
285 | return easing(current, from, to - from, duration);
286 | }
287 | }, {
288 | key: 'loopProperties',
289 | value: function loopProperties(from, to, easing, current, duration) {
290 | var k,
291 | o = {};
292 | for (k in from) {
293 | o[k] = easing(current, from[k], to[k] - from[k], duration);
294 | }
295 | return o;
296 | }
297 | }, {
298 | key: 'progress',
299 | value: function progress() {
300 | if (this.canceled) {
301 | return;
302 | }
303 | this.time = Date.now();
304 | if (this.end <= this.time) {
305 | this.onProgress(this.to, true);
306 | } else {
307 | this.onProgress(this.update(this.from, this.to, this.easing, this.time - this.start, this.duration));
308 | raf(this.progress);
309 | }
310 | }
311 | }, {
312 | key: 'cancel',
313 | value: function cancel() {
314 | this.canceled = true;
315 | }
316 | }]);
317 |
318 | return Easing;
319 | })();
320 |
321 | exports.Easing = Easing;
322 |
323 | /*
324 | *
325 | * TERMS OF USE - EASING EQUATIONS
326 | *
327 | * Open source under the BSD License.
328 | *
329 | * Copyright © 2001 Robert Penner
330 | * All rights reserved.
331 | *
332 | * Redistribution and use in source and binary forms, with or without modification,
333 | * are permitted provided that the following conditions are met:
334 | *
335 | * Redistributions of source code must retain the above copyright notice, this list of
336 | * conditions and the following disclaimer.
337 | * Redistributions in binary form must reproduce the above copyright notice, this list
338 | * of conditions and the following disclaimer in the documentation and/or other materials
339 | * provided with the distribution.
340 | *
341 | * Neither the name of the author nor the names of contributors may be used to endorse
342 | * or promote products derived from this software without specific prior written permission.
343 | *
344 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
345 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
346 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
347 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
348 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
349 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
350 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
351 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
352 | * OF THE POSSIBILITY OF SUCH DAMAGE.
353 | *
354 | */
--------------------------------------------------------------------------------
/lib/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | Object.defineProperty(exports, '__esModule', {
4 | value: true
5 | });
6 |
7 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
8 |
9 | var _react = require('react');
10 |
11 | var _react2 = _interopRequireDefault(_react);
12 |
13 | var _components = require('./components');
14 |
15 | var _components2 = _interopRequireDefault(_components);
16 |
17 | exports['default'] = (0, _components2['default'])(_react2['default']);
18 | module.exports = exports['default'];
--------------------------------------------------------------------------------
/lib/native.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | Object.defineProperty(exports, '__esModule', {
4 | value: true
5 | });
6 |
7 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
8 |
9 | var _reactNative = require('react-native');
10 |
11 | var _reactNative2 = _interopRequireDefault(_reactNative);
12 |
13 | var _components = require('./components');
14 |
15 | var _components2 = _interopRequireDefault(_components);
16 |
17 | exports['default'] = (0, _components2['default'])(_reactNative2['default']);
18 | module.exports = exports['default'];
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-ease",
3 | "version": "1.0.7",
4 | "description": "i like to move it move it",
5 | "main": "./lib/index.js",
6 | "scripts": {
7 | "test": "mocha",
8 | "build": "babel src -d lib",
9 | "start": "HOT=1 babel-node dev.js",
10 | "dev": "babel-node dev.js"
11 | },
12 | "keywords": [
13 | "animation",
14 | "react",
15 | "easings",
16 | "chain"
17 | ],
18 | "author": "Sunil Pai",
19 | "license": "ISC",
20 | "devDependencies": {
21 | "babel": "^5.5.4",
22 | "babel-core": "^5.5.4",
23 | "babel-eslint": "^3.1.15",
24 | "babel-loader": "^5.1.4",
25 | "eslint": "^0.22.1",
26 | "eslint-plugin-react": "^2.5.0",
27 | "node-libs-browser": "^0.5.2",
28 | "react": "^0.13.3",
29 | "react-hot-loader": "^1.2.7",
30 | "webpack": "^1.9.10",
31 | "webpack-dev-server": "^1.9.0"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/components.js:
--------------------------------------------------------------------------------
1 | import {Easing, defaults} from './ease';
2 |
3 | let noop = () => {};
4 |
5 | export default function components(React){
6 |
7 | const Ease = React.createClass({
8 | propTypes: {
9 | // from: React.PropTypes.number,
10 | // to: React.PropTypes.number,
11 | duration: React.PropTypes.number,
12 | // ease: easings[easings.default],
13 | repeat: React.PropTypes.number,
14 | onProgress: React.PropTypes.func,
15 | delay: React.PropTypes.number,
16 | children: React.PropTypes.func
17 | },
18 | getDefaultProps() {
19 | return defaults;
20 | },
21 | shouldComponentUpdate() {
22 | return true;
23 | },
24 |
25 | getInitialState() {
26 | return {
27 | value: this.props.from,
28 | done: false
29 | };
30 | },
31 | componentDidMount() {
32 | this.ease = new Easing({...this.props, onProgress: (value, done) => {
33 | this.setState({value, done});
34 | this.props.onProgress(value, done);
35 | }});
36 | },
37 | componentWillUnmount() {
38 | this.ease.cancel();
39 | delete this.ease;
40 | },
41 | render() {
42 | return this.props.children(this.state.value, this.state.done);
43 | }
44 | });
45 |
46 | const Chain = React.createClass({
47 | getDefaultProps(){
48 | return {
49 | onProgress: noop,
50 | repeat: 1
51 | };
52 | },
53 | propTypes: {
54 | sequence: React.PropTypes.array,
55 | children: React.PropTypes.func,
56 | onProgress: React.PropTypes.func
57 | },
58 | getInitialState() {
59 | let props = this.props.sequence[0];
60 | return {
61 | index: 0,
62 | done: false,
63 | value: props.from,
64 | from: props.from,
65 | to: typeof props.to === 'number' ? props.to : {...props.from, ...props.to}
66 | };
67 | },
68 |
69 | shouldComponentUpdate(){
70 | return true;
71 | },
72 | onProgress(value, done){
73 | this.props.onProgress(this.state.index, value, done);
74 |
75 | if(done){
76 | let length = this.props.repeat * this.props.sequence.length;
77 | let allDone = this.state.index === (length - 1);
78 | let props = this.props.sequence[((this.state.index + 1) % this.props.sequence.length)] || {};
79 | let mergeable = ((typeof value !== 'number') && !allDone);
80 | this.setState({
81 | index: allDone ? this.state.index : this.state.index + 1,
82 | done: allDone,
83 | value: value,
84 | from: mergeable ? {...value, ...(props.from || {})} : (props.from !== undefined ? props.from : value),
85 | to: mergeable ? {...value, ...(props.to || {})} : props.to
86 | });
87 | }
88 | },
89 | render(){
90 | let props = this.props.sequence[this.state.index % this.props.sequence.length];
91 | let fn = val => this.props.children(val, this.state.done);
92 | return this.state.done ?
93 | fn(this.state.value, true) :
94 |
95 | {fn}
96 | ;
97 | }
98 | });
99 |
100 | return {Ease, Chain};
101 |
102 | }
103 |
--------------------------------------------------------------------------------
/src/ease.js:
--------------------------------------------------------------------------------
1 |
2 | // pick up raf
3 | let root = (typeof window !== 'undefined') ? window : ((typeof global !== 'undefined') ? global : this);
4 | export const raf = root.requestAnimationFrame || root.webkitRequestAnimationFrame || root.mozRequestAnimationFrame || root.msRequestAnimationFrame || (fn => setTimeout(fn, 10));
5 |
6 | let noop = () => {};
7 |
8 | // penner's easing equations
9 | export const easings = {
10 | default: 'easeOutQuad',
11 | swing(t, b, c, d) {
12 | return easings[easings.default](t, b, c, d);
13 | },
14 | easeInQuad(t, b, c, d) {
15 | return c * (t /= d) * t + b;
16 | },
17 | easeOutQuad(t, b, c, d) {
18 | return -c * (t /= d) * (t - 2) + b;
19 | },
20 | easeInOutQuad(t, b, c, d) {
21 | if ((t /= d / 2) < 1) {
22 | return c / 2 * t * t + b;
23 | }
24 | return -c / 2 * ((--t) * (t - 2) - 1) + b;
25 | },
26 | easeInCubic(t, b, c, d) {
27 | return c * (t /= d) * t * t + b;
28 | },
29 | easeOutCubic(t, b, c, d) {
30 | return c * ((t = t / d - 1) * t * t + 1) + b;
31 | },
32 | easeInOutCubic(t, b, c, d) {
33 | if ((t /= d / 2) < 1) {
34 | return c / 2 * t * t * t + b;
35 | }
36 | return c / 2 * ((t -= 2) * t * t + 2) + b;
37 | },
38 | easeInQuart(t, b, c, d) {
39 | return c * (t /= d) * t * t * t + b;
40 | },
41 | easeOutQuart(t, b, c, d) {
42 | return -c * ((t = t / d - 1) * t * t * t - 1) + b;
43 | },
44 | easeInOutQuart(t, b, c, d) {
45 | if ((t /= d / 2) < 1) {
46 | return c / 2 * t * t * t * t + b;
47 | }
48 | return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
49 | },
50 | easeInQuint(t, b, c, d) {
51 | return c * (t /= d) * t * t * t * t + b;
52 | },
53 | easeOutQuint(t, b, c, d) {
54 | return c * ((t = t / d - 1) * t * t * t * t + 1) + b;
55 | },
56 | easeInOutQuint(t, b, c, d) {
57 | if ((t /= d / 2) < 1) {
58 | return c / 2 * t * t * t * t * t + b;
59 | }
60 | return c / 2 * ((t -= 2) * t * t * t * t + 2) + b;
61 | },
62 | easeInSine(t, b, c, d) {
63 | return -c * Math.cos(t / d * (Math.PI / 2)) + c + b;
64 | },
65 | easeOutSine(t, b, c, d) {
66 | return c * Math.sin(t / d * (Math.PI / 2)) + b;
67 | },
68 | easeInOutSine(t, b, c, d) {
69 | return -c / 2 * (Math.cos(Math.PI * t / d) - 1) + b;
70 | },
71 | easeInExpo(t, b, c, d) {
72 | return (t === 0) ? b : c * Math.pow(2, 10 * (t / d - 1)) + b;
73 | },
74 | easeOutExpo(t, b, c, d) {
75 | return (t === d) ? b + c : c * (-Math.pow(2, -10 * t / d) + 1) + b;
76 | },
77 | easeInOutExpo(t, b, c, d) {
78 | if (t === 0) {
79 | return b;
80 | }
81 | if (t === d) {
82 | return b + c;
83 | }
84 | if ((t /= d / 2) < 1) {
85 | return c / 2 * Math.pow(2, 10 * (t - 1)) + b;
86 | }
87 | return c / 2 * (-Math.pow(2, -10 * --t) + 2) + b;
88 | },
89 | easeInCirc(t, b, c, d) {
90 | return -c * (Math.sqrt(1 - (t /= d) * t) - 1) + b;
91 | },
92 | easeOutCirc(t, b, c, d) {
93 | return c * Math.sqrt(1 - (t = t / d - 1) * t) + b;
94 | },
95 | easeInOutCirc(t, b, c, d) {
96 | if ((t /= d / 2) < 1) {
97 | return -c / 2 * (Math.sqrt(1 - t * t) - 1) + b;
98 | }
99 | return c / 2 * (Math.sqrt(1 - (t -= 2) * t) + 1) + b;
100 | },
101 | easeInElastic(t, b, c, d) {
102 | var s = 1.70158;
103 | var p = 0;
104 | var a = c;
105 | if (t === 0) {
106 | return b;
107 | }
108 | if ((t /= d) === 1) {
109 | return b + c;
110 | }
111 | if (!p) {
112 | p = d * .3;
113 | }
114 | if (a < Math.abs(c)) {
115 | a = c;
116 | s = p / 4;
117 | } else {
118 | s = p / (2 * Math.PI) * Math.asin(c / a);
119 | }
120 | return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
121 | },
122 | easeOutElastic(t, b, c, d) {
123 | var s = 1.70158;
124 | var p = 0;
125 | var a = c;
126 | if (t === 0) {
127 | return b;
128 | }
129 | if ((t /= d) === 1) {
130 | return b + c;
131 | }
132 | if (!p) {
133 | p = d * .3;
134 | }
135 | if (a < Math.abs(c)) {
136 | a = c;
137 | s = p / 4;
138 | } else {
139 | s = p / (2 * Math.PI) * Math.asin(c / a);
140 | }
141 | return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
142 | },
143 | easeInOutElastic(t, b, c, d) {
144 | var s = 1.70158;
145 | var p = 0;
146 | var a = c;
147 | if (t === 0) {
148 | return b;
149 | }
150 | if ((t /= d / 2) === 2) {
151 | return b + c;
152 | }
153 | if (!p) {
154 | p = d * (.3 * 1.5);
155 | }
156 | if (a < Math.abs(c)) {
157 | a = c;
158 | s = p / 4;
159 | } else {
160 | s = p / (2 * Math.PI) * Math.asin(c / a);
161 | }
162 | if (t < 1) {
163 | return -.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
164 | }
165 | return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
166 | },
167 | easeInBack(t, b, c, d, s) {
168 | if (s === undefined) {
169 | s = 1.70158;
170 | }
171 | return c * (t /= d) * t * ((s + 1) * t - s) + b;
172 | },
173 | easeOutBack(t, b, c, d, s) {
174 | if (s === undefined) {
175 | s = 1.70158;
176 | }
177 | return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
178 | },
179 | easeInOutBack(t, b, c, d, s) {
180 | if (s === undefined) {
181 | s = 1.70158;
182 | }
183 | if ((t /= d / 2) < 1) {
184 | return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
185 | }
186 | return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
187 | },
188 | easeInBounce(t, b, c, d) {
189 | return c - easings.easeOutBounce(d - t, 0, c, d) + b;
190 | },
191 | easeOutBounce(t, b, c, d) {
192 | if ((t /= d) < (1 / 2.75)) {
193 | return c * (7.5625 * t * t) + b;
194 | } else if (t < (2 / 2.75)) {
195 | return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
196 | } else if (t < (2.5 / 2.75)) {
197 | return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
198 | } else {
199 | return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
200 | }
201 | },
202 | easeInOutBounce(t, b, c, d) {
203 | if (t < d / 2) {
204 | return easings.easeInBounce(t * 2, 0, c, d) * .5 + b;
205 | }
206 | return easings.easeOutBounce(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
207 | }
208 | };
209 |
210 | export const defaults = {
211 | from: 0,
212 | to: 0,
213 | duration: 1000,
214 | ease: easings[easings.default],
215 | onProgress: noop,
216 | delay: 0
217 | };
218 |
219 | // to avoid an assign polyfill
220 | function assign(target) {
221 | for (var i = 1; i < arguments.length; i++) {
222 | var source = arguments[i];
223 | for (var key in source) {
224 | if (Object.prototype.hasOwnProperty.call(source, key)) {
225 | target[key] = source[key];
226 | }
227 | }
228 | }
229 | return target;
230 | }
231 |
232 | // animation class
233 | // - from: *number*/*object*
234 | // - to: *number*/*object*
235 | // - duration: *number* (ms)
236 | // - ease: *string*/*function* `./src.js` has a list of available easing functions, or pass in your own
237 | // - delay: *number* (ms)
238 | // - onProgress: *function* - optional callback called on every 'movement'. 'returns' the current value, and a `done` flag
239 |
240 | export class Easing{
241 | constructor(config){
242 | assign(this, {...defaults, ...config});
243 | this.easing = typeof this.ease === 'function' ?
244 | this.ease :
245 | easings[this.ease || easings.default];
246 |
247 | this.update = typeof this.from === 'object' ? this.loopProperties : this.directUpdate;
248 |
249 | this.start = Date.now() + this.delay;
250 | this.end = this.start + this.duration;
251 | this.canceled = false;
252 | this.progress = ::this.progress;
253 |
254 | if(this.delay){
255 | setTimeout(()=> raf(this.progress), this.delay);
256 | }
257 | else{
258 | raf(this.progress);
259 | }
260 | }
261 |
262 | directUpdate(from, to, easing, current, duration) {
263 | return easing(current, from, to - from, duration);
264 | }
265 |
266 | loopProperties(from, to, easing, current, duration) {
267 | var k, o = {};
268 | for (k in from) {
269 | o[k] = easing(current, from[k], to[k] - from[k], duration);
270 | }
271 | return o;
272 | }
273 |
274 | progress(){
275 | if (this.canceled) {
276 | return;
277 | }
278 | this.time = Date.now();
279 | if (this.end <= this.time) {
280 | this.onProgress(this.to, true);
281 | } else {
282 | this.onProgress(this.update(this.from, this.to, this.easing, this.time - this.start, this.duration));
283 | raf(this.progress);
284 | }
285 | }
286 |
287 | cancel(){
288 | this.canceled = true;
289 | }
290 | }
291 |
292 |
293 |
294 |
295 | /*
296 | *
297 | * TERMS OF USE - EASING EQUATIONS
298 | *
299 | * Open source under the BSD License.
300 | *
301 | * Copyright © 2001 Robert Penner
302 | * All rights reserved.
303 | *
304 | * Redistribution and use in source and binary forms, with or without modification,
305 | * are permitted provided that the following conditions are met:
306 | *
307 | * Redistributions of source code must retain the above copyright notice, this list of
308 | * conditions and the following disclaimer.
309 | * Redistributions in binary form must reproduce the above copyright notice, this list
310 | * of conditions and the following disclaimer in the documentation and/or other materials
311 | * provided with the distribution.
312 | *
313 | * Neither the name of the author nor the names of contributors may be used to endorse
314 | * or promote products derived from this software without specific prior written permission.
315 | *
316 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
317 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
318 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
319 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
320 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
321 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
322 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
323 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
324 | * OF THE POSSIBILITY OF SUCH DAMAGE.
325 | *
326 | */
327 |
328 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import components from './components';
3 |
4 | export default components(React);
5 |
6 |
--------------------------------------------------------------------------------
/src/native.js:
--------------------------------------------------------------------------------
1 | import React from 'react-native';
2 | import components from './components';
3 |
4 | export default components(React);
5 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | import webpack from 'webpack';
2 |
3 | let config = {
4 | devtool: 'source-map',
5 | target: 'web',
6 | entry: {
7 | entry: ['./example/entry.js']
8 | },
9 | output: {
10 | path: __dirname,
11 | filename: '/example/bundle.js',
12 | publicPath: '/'
13 | },
14 | module: {
15 | loaders: [{
16 | test: /\.js$/,
17 | exclude: /node_modules/,
18 | loaders: ['babel-loader']
19 | }]
20 | },
21 | resolve: {
22 | extensions: ['', '.js', '.jsx']
23 | },
24 | plugins: [new webpack.DefinePlugin({
25 | 'process.env': {
26 | 'NODE_ENV': `"${process.env.NODE_ENV || 'development'}"`
27 | }
28 | })],
29 | externals: ['react-native']
30 | };
31 |
32 | if(process.env.HOT){
33 | config = {
34 | ...config,
35 | devtool: 'eval-source-map',
36 | entry: Object.keys(config.entry).reduce((o, key) => ({...o, [key]: [
37 | 'webpack-dev-server/client?http://localhost:3000', // WebpackDevServer host and port
38 | 'webpack/hot/only-dev-server'
39 | ].concat(config.entry[key])}), {}),
40 | module: {...config.module,
41 | loaders: [{
42 | ...config.module.loaders[0],
43 | loaders: [
44 | 'react-hot'
45 | ].concat(config.module.loaders[0].loaders)
46 | }]
47 | },
48 | plugins: [
49 | new webpack.HotModuleReplacementPlugin(),
50 | new webpack.NoErrorsPlugin()
51 | ].concat(config.plugins)
52 | };
53 | }
54 |
55 | module.exports = config;
56 |
--------------------------------------------------------------------------------