| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { | ||
| value: true | ||
| }); | ||
| // this splits css numbers from units. | ||
| // according to the css spec, a number can either be an integer or it can be | ||
| // zero or more digits followed by a dot followed by one or more digits. | ||
| // assuming the unit can be any sequence of lowercase letters (including none) | ||
| var numberUnitSplit = /^([+-]?(?:\d+|\d*\.\d+))([a-z]*|%)$/; | ||
| // returns an object that lists the unit, start and end values of the | ||
| // animatable properties based on the given arguments. | ||
| // to be animatable, a property has to be present on both `startProps` and | ||
| // `endProps` with the same unit. | ||
| var getAnimatableProps = exports.getAnimatableProps = function getAnimatableProps(startProps, endProps) { | ||
| var result = {}; | ||
| // @todo check if props are listed in animatable properties! | ||
| // @see https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_animated_properties | ||
| // @see https://github.com/gilmoreorless/css-animated-properties | ||
| for (var key in startProps) { | ||
| if (key in endProps) { | ||
| var startMatches = startProps[key].toString().match(numberUnitSplit); | ||
| var endMatches = endProps[key].toString().match(numberUnitSplit); | ||
| if (startMatches && endMatches && startMatches[2] === endMatches[2]) { | ||
| result[key] = { | ||
| unit: startMatches[2], | ||
| start: +startMatches[1], | ||
| end: +endMatches[1] | ||
| }; | ||
| } | ||
| } | ||
| } | ||
| return result; | ||
| }; |
| 'use strict'; | ||
| Object.defineProperty(exports, "__esModule", { | ||
| value: true | ||
| }); | ||
| var defaultFormatter = function defaultFormatter(key, value) { | ||
| return key + ':' + value + ';'; | ||
| }; | ||
| var reduceProperties = exports.reduceProperties = function reduceProperties(props) { | ||
| var formatter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : defaultFormatter; | ||
| return Object.keys(props).reduce(function (acc, prop) { | ||
| return '' + acc + formatter(prop, props[prop]); | ||
| }, ''); | ||
| }; | ||
| var toString = exports.toString = function toString(keyframes) { | ||
| var formatter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : defaultFormatter; | ||
| return Object.keys(keyframes).reduce(function (outer, perc) { | ||
| var value = reduceProperties(keyframes[perc], formatter); | ||
| return '' + outer + perc + '{' + value + '}'; | ||
| }, ''); | ||
| }; | ||
| exports.default = toString; |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { | ||
| value: true | ||
| }); | ||
| var mapValues = exports.mapValues = function mapValues(object, iteratee) { | ||
| var result = {}; | ||
| for (var key in object) { | ||
| result[key] = iteratee(object[key], key, object); | ||
| } | ||
| return result; | ||
| }; |
+3
-1
@@ -19,3 +19,5 @@ 'use strict'; | ||
| var format = function format(keyframes) { | ||
| var formatter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : format.PX_FORMATTER; | ||
| var formatter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function (key, value) { | ||
| return key + ':' + value + ';'; | ||
| }; | ||
@@ -22,0 +24,0 @@ return Object.keys(keyframes).reduce(function (outer, perc) { |
+71
-32
@@ -6,12 +6,12 @@ 'use strict'; | ||
| }); | ||
| exports.format = exports.getKeyframes = undefined; | ||
| exports.toString = exports.spring = undefined; | ||
| var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); | ||
| var _format = require('./format'); | ||
| var _toString = require('./to-string'); | ||
| Object.defineProperty(exports, 'format', { | ||
| Object.defineProperty(exports, 'toString', { | ||
| enumerable: true, | ||
| get: function get() { | ||
| return _interopRequireDefault(_format).default; | ||
| return _interopRequireDefault(_toString).default; | ||
| } | ||
@@ -24,4 +24,6 @@ }); | ||
| var _cache = require('./cache'); | ||
| var _util = require('./util'); | ||
| var _props = require('./props'); | ||
| function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
@@ -38,12 +40,18 @@ | ||
| var defaults = { | ||
| stiffness: 170, | ||
| damping: 26, | ||
| // default spring options. | ||
| // damping and precision reflect the values of the `wobbly` preset, | ||
| // precision defaults to 3 which should be a good tradeoff between | ||
| // animation detail and resulting filesize. | ||
| var defaultOptions = { | ||
| stiffness: 180, | ||
| damping: 12, | ||
| precision: 3 | ||
| }; | ||
| var getKeyframes = exports.getKeyframes = function getKeyframes(startProps, targetProps) { | ||
| var spring = exports.spring = function spring(startProps, endProps) { | ||
| var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; | ||
| var _Object$assign = Object.assign({}, defaults, options, presets[options.preset] || {}), | ||
| // define stiffness, damping and precision based on default options | ||
| // and options given in arguments. | ||
| var _Object$assign = Object.assign({}, defaultOptions, options, presets[options.preset] || {}), | ||
| stiffness = _Object$assign.stiffness, | ||
@@ -53,29 +61,60 @@ damping = _Object$assign.damping, | ||
| var cache = (0, _cache.initCache)(startProps, targetProps); | ||
| var steps = { '0%': Object.keys(cache).reduce(function (accu, key) { | ||
| return Object.assign(accu, _defineProperty({}, key, cache[key].start)); | ||
| }, {}) }; | ||
| var animatableProps = (0, _props.getAnimatableProps)(startProps, endProps); | ||
| var startValues = (0, _util.mapValues)(animatableProps, function (_ref) { | ||
| var start = _ref.start; | ||
| return start; | ||
| }); | ||
| var endValues = (0, _util.mapValues)(animatableProps, function (_ref2) { | ||
| var end = _ref2.end; | ||
| return end; | ||
| }); | ||
| var _loop = function _loop(i) { | ||
| var props = {}; | ||
| Object.keys(cache).forEach(function (key) { | ||
| var prop = cache[key]; | ||
| var _stepper = (0, _stepper4.default)(0.01, prop.cache.value, prop.cache.velocity, parseFloat(prop.target), stiffness, damping), | ||
| _stepper2 = _slicedToArray(_stepper, 2), | ||
| value = _stepper2[0], | ||
| velocity = _stepper2[1]; | ||
| prop.cache = { value: value, velocity: velocity }; | ||
| props[key] = +(i === 100 ? prop.target : prop.cache.value).toFixed(precision); | ||
| var addUnits = function addUnits(object) { | ||
| return (0, _util.mapValues)(object, function (v, k) { | ||
| return '' + v + animatableProps[k].unit; | ||
| }); | ||
| steps[i + '%'] = props; | ||
| }; | ||
| for (var i = 1; i < 101; i += 1) { | ||
| _loop(i); | ||
| } | ||
| return steps; | ||
| var keyframes = { | ||
| '0%': addUnits(startValues), | ||
| '100%': addUnits(endValues) | ||
| }; | ||
| Object.keys(startValues).forEach(function (key) { | ||
| var velocity = 0; | ||
| var value = startValues[key]; | ||
| var end = endValues[key]; | ||
| for (var i = 1; i < 100; i += 1) { | ||
| var _stepper = (0, _stepper4.default)(0.01, value, velocity, end, stiffness, damping); | ||
| var _stepper2 = _slicedToArray(_stepper, 2); | ||
| value = _stepper2[0]; | ||
| velocity = _stepper2[1]; | ||
| var percent = i + '%'; | ||
| keyframes[percent] = Object.assign(keyframes[percent] || {}, _defineProperty({}, key, '' + +value.toFixed(precision) + animatableProps[key].unit)); | ||
| } | ||
| }); | ||
| return keyframes; | ||
| }; | ||
| exports.default = getKeyframes; | ||
| // console.log(spring({ | ||
| // left: '10px', | ||
| // right: '20em', | ||
| // foo: 'bar', | ||
| // opacity: 0, | ||
| // rotate: '5deg' | ||
| // }, { | ||
| // left: '20px', | ||
| // right: '30em', | ||
| // baz: true, | ||
| // opacity: 1, | ||
| // rotate: '10deg' | ||
| // }, { | ||
| // preset: 'noWobble' | ||
| // })) | ||
| exports.default = spring; |
+1
-1
| { | ||
| "name": "css-spring", | ||
| "version": "2.1.1", | ||
| "version": "3.0.0", | ||
| "description": "Generate physics based css-keyframe animations", | ||
@@ -5,0 +5,0 @@ "main": "build/index.js", |
+67
-32
@@ -8,3 +8,3 @@ # css-spring 🚀 | ||
| Generate physics based css-keyframe animations. | ||
| Generate physics based css-keyframe animations for the css-in-js solution of your choice or plain css. | ||
@@ -15,14 +15,11 @@ <table> | ||
| <pre lang="javascript"> | ||
| import spring, { format } from 'css-spring' | ||
| import spring, { toString } from 'css-spring' | ||
| const keyframes = spring( | ||
| { left: 0 }, | ||
| { left: 250 }, | ||
| { left: '0px', opacity: 0 }, | ||
| { left: '250px', opacity: 1 }, | ||
| { preset: 'wobbly', precision: 5 } | ||
| ) | ||
| const moveLeft = format( | ||
| keyframes, | ||
| format.PX_FORMATTER | ||
| ) | ||
| const keyframeString = toString(keyframes) | ||
| </pre> | ||
@@ -44,3 +41,3 @@ </td> | ||
| - [spring(start, target, options)](#springstart-target-options) | ||
| - [format(keyframes, formatter)](#formatkeyframes-formatter) | ||
| - [toString(keyframes, formatter)](#tostringkeyframes-formatter) | ||
| - [Contributing](#contributing) | ||
@@ -52,3 +49,3 @@ | ||
| This is where **css-spring** enters the stage. Enter the desired starting properties and target properties of your animation, optionally adjust the spring settings and **css-spring** generates a keyframe objects or formatted keyframe animation css for your spring-based animation of choice. | ||
| This is where **css-spring** enters the stage. Enter the desired starting properties and target properties of your animation, optionally adjust the spring settings and **css-spring** generates a keyframe object or keyframe animation css for your spring-based animation of choice. | ||
@@ -66,7 +63,7 @@ The library is small and easy to work with. Nevertheless, it is in the early stages of development. There is a lot of improvements to be made - read the [Contributing](#contributing) section if you want to know how you can help. | ||
| ```javascript | ||
| import spring, { format } from 'css-spring' | ||
| import spring, { toString } from 'css-spring' | ||
| import styled, { keyframes } from 'styled-components' | ||
| const springLeft = format(spring( | ||
| { left: 50 }, { left: 250 }, { preset: 'gentle' } | ||
| const springLeft = toString(spring( | ||
| { left: '50px' }, { left: '250px' }, { preset: 'gentle' } | ||
| )) | ||
@@ -81,3 +78,3 @@ | ||
| When used with the `keyframes` method of [glamor](https://github.com/threepointone/glamor), no special formatting is needed for pixel values: | ||
| When used with the `keyframes` method of [glamor](https://github.com/threepointone/glamor), the keyframe object can be used as-is and there is no need to convert it to a string: | ||
@@ -89,3 +86,3 @@ ```jsx | ||
| const springLeft = css.keyframes('springLeft', spring( | ||
| { left: 50 }, { left: 250 }, { preset: 'gentle' } | ||
| { left: '50px' }, { left: '250px' }, { preset: 'gentle' } | ||
| )); | ||
@@ -103,8 +100,25 @@ | ||
| This method creates spring-based keyframes. Called with start and target properties, it returns an object with the interpolated animation values. | ||
| This method creates spring-based keyframes. Called with `startProp` and `targetProp` arguments | ||
| reflecting the starting and ending properties of the animation, it returns an object with the | ||
| interpolated animation values. | ||
| The following properties in both the `startProp` and `endProp` objects are ignored when | ||
| calculating the animation: | ||
| - properties that do not exist in both arguments | ||
| - properties that have non-numeric values | ||
| - properties with units that differ between both arguments | ||
| #### Arguments | ||
| - `start` (_Object_): The start properties for the animation. The keys should be css properties, the values should be able to be parsed to a number by `parseFloat`. Keys that can not be parsed or do not exist in the target properties are ignored. | ||
| - `target` (_Object_): The target properties for the animation. The keys should be css properties, the values should be able to be parsed to a number by `parseFloat`. Keys that can not be parsed or do not exist in the start properties are ignored. | ||
| - `startProps` (_Object_): The start properties for the animation.<br> | ||
| ```javascript | ||
| // `startProps` example | ||
| { 'margin-left': '0px', opacity: 0 } | ||
| ``` | ||
| - `endProps` (_Object_): The end properties for the animation.<br> | ||
| ```javascript | ||
| // `endProps` example | ||
| { 'margin-left': '250px', opacity: 1 } | ||
| ``` | ||
| - `options` (_Object_, optional): Animation options with these properties: | ||
@@ -126,14 +140,14 @@ - `precision` (_Number_, optional, defaults to `3`) Specifies the number of decimals in the rounding of interpolated values. | ||
| { | ||
| "0%": { "left": 0 }, | ||
| "1%": { "left": 3 }, | ||
| "2%": { "left": 8.544 }, | ||
| "0%": { "margin-left": "0px" }, | ||
| "1%": { "margin-left": "3px" }, | ||
| "2%": { "margin-left": "8.544px" }, | ||
| // 3% … 98% | ||
| "99%": { "left": 249.981 } | ||
| "100%": { "left": 250 } | ||
| "99%": { "margin-left": "249.981px" } | ||
| "100%": { "margin-left": "250px" } | ||
| } | ||
| ``` | ||
| ### `format(keyframes, formatter)` | ||
| ### `toString(keyframes, formatter)` | ||
| This method takes the return value of `spring` and formats it to valid css (with corresponding units). As of now, the interpolated key-frame values are unitless because units are stripped at creation. Simple formatters that add `px`, `em` or `rem` units to every property value are available as `format.PX_FORMATTER`, `format.EM_FORMATTER` and `format.REM_FORMATTER`. | ||
| This method takes the return value of `spring` and converts it to a css string. | ||
@@ -143,18 +157,40 @@ #### Arguments | ||
| - `keyframes` (_Object_): The interpolated animation values object given by `spring`. | ||
| - `formatter` (_Function_, optional, defaults to `format.PX_FORMATTER`): The formatter function that is invoked for every property/value combination. | ||
| - `formatter` (_Function_, optional): The formatter function that is invoked for every property/value combination. | ||
| ```javascript | ||
| // default formatter | ||
| (property, value) => `${property}:${value};` | ||
| ``` | ||
| #### Returns | ||
| A formatted css keyframes string. | ||
| A css keyframe string. | ||
| #### Example | ||
| A keyframes object based on `startValues = { opacity: 0, left: '10px' }` and `targetValues = { opacity: 1, left: '20px' }` will have all units (in this case, `px`) removed from the interpolated values. In order to get css with the correct unit for the interpolated `left` values, but no unit for the interpolated `opacity` values, write your own formatter such as this: | ||
| A keyframes object based on `startValues = { rotate: '0deg', left: '10px' }` and `targetValues = { rotate: '180deg', left: '20px' }` will be converted to this css string: | ||
| ```css | ||
| 0%{rotate:0deg;left:10px} | ||
| /* ... */ | ||
| 100%{rotate:180deg;left:20px;} | ||
| ``` | ||
| In order to have this formatted to a valid css transform, you could use a custom formatter like this one: | ||
| ```javascript | ||
| const keyframeCss = format(mySpring, (key, value) => { | ||
| return `${key}:${value}${key === 'left' ? 'px' : ''};` | ||
| }); | ||
| const keyframeCss = toString(keyframes, (property, value) => | ||
| property === 'rotate' | ||
| ? `transform:${property}(${value});` | ||
| : `${property}:${value};` | ||
| ) | ||
| ``` | ||
| This would net you the following css: | ||
| ```css | ||
| 0%{transform:rotate(0deg);left:10px} | ||
| /* ... */ | ||
| 100%{transform:rotate(180deg);left:20px;} | ||
| ``` | ||
| ## Contributing | ||
@@ -165,5 +201,4 @@ | ||
| - allowing the interpolation of array values like margins, paddings or translates ([#1](/../../issues/1)) | ||
| - automatically detecting css-units and re-applying them to the interpolated values of the keyframe animation ([#2](/../../issues/2)) | ||
| - color interpolation ([#3](/../../issues/3)) | ||
| Feel free to contribute with your own issues and ideas, your thoughts on the ones listed above, example documentation for usage with other css-in-js frameworks or pull requests for features/improvements you'd like to see. |
427059
0.88%18
20%232
71.85%194
22.01%