Skip to content

Commit

Permalink
Merge pull request #6 from codepunkt/next
Browse files Browse the repository at this point in the history
Ability to work with numeric css units (Fixes #2)
  • Loading branch information
codepunkt authored Jan 26, 2017
2 parents a112ae7 + f55ef33 commit 175853b
Show file tree
Hide file tree
Showing 14 changed files with 611 additions and 592 deletions.
97 changes: 66 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,21 @@
[![Code Coverage](https://img.shields.io/coveralls/codepunkt/css-spring.svg?style=flat&label=Code%20Coverage)](https://coveralls.io/github/codepunkt/css-spring?branch=master)
[![MIT License](https://img.shields.io/npm/l/css-spring.svg?style=flat&label=License)](http://opensource.org/licenses/MIT)

Generate physics based css-keyframe animations.
Generate physics based css-keyframe animations for the css-in-js solution of your choice or plain css.

<table>
<tr>
<td>
<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>
</td>
<td>
Expand All @@ -39,14 +36,14 @@ const moveLeft = format(
- [glamor](#glamor)
- [API](#api)
- [spring(start, target, options)](#springstart-target-options)
- [format(keyframes, formatter)](#formatkeyframes-formatter)
- [toString(keyframes, formatter)](#tostringkeyframes-formatter)
- [Contributing](#contributing)

## Introduction

This library was inspired heavily by [react-motion](https://github.com/chenglou/react-motion), which allows you to create spring-based animations by repeatedly updating an elements inline styles. When animating lots of elements at the same time, this can be a burden on performance. Also, based on my own experience, integrating with some css-in-js libraries is hard.

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 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.

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.

Expand All @@ -59,11 +56,11 @@ This section lists some examples of popular css-in-js libraries such as `styled-
When used with the [styled-components](https://github.com/styled-components/styled-components) `keyframes` helper, generated keyframe animations can be applied to a styled component like this:

```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' }
))

const StyledDiv = styled.div`
Expand All @@ -73,14 +70,14 @@ const StyledDiv = styled.div`

### glamor

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:

```jsx
import { css } from 'glamor';
import spring from 'css-spring';

const springLeft = css.keyframes('springLeft', spring(
{ left: 50 }, { left: 250 }, { preset: 'gentle' }
{ left: '50px' }, { left: '250px' }, { preset: 'gentle' }
));

const MyComponent = () => (
Expand All @@ -93,12 +90,29 @@ const MyComponent = () => (
## API
### `spring(start, target, options)`

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:
- `precision` (_Number_, optional, defaults to `3`) Specifies the number of decimals in the rounding of interpolated values.
- `preset` (_String_, optional): Presets for `stiffness` and `damping`, overriding any stiffness and damping values given. Available presets:
Expand All @@ -115,44 +129,65 @@ An object with `0%` to `100%` keys and the interpolated physics-based values for

```javascript
{
"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.

#### 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) =>
`${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

There's a lot of ideas floating in my head that could make working with **css-spring** easier. Some of these are:
- 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.
Loading

0 comments on commit 175853b

Please sign in to comment.