Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Ability to work with numeric css units (Fixes #2)
  • Loading branch information
codepunkt committed Jan 26, 2017
commit f55ef3395ce46108e79b5c8bc1c66ef29e4d46ea
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