Skip to content

Commit

Permalink
[@labs/motion] Renames the flip() directive to animate() (#2166)
Browse files Browse the repository at this point in the history
Naming tweaks:
* `animate`: renamed `AnimateOptions` type to `Options`.
* `animate`: renamed `animationOptions` option to `keyframeOptions`
* `AnimateController`:  renamed `animateOptions` to `defaultOptions`
  • Loading branch information
Steve Orvell committed Sep 18, 2021
1 parent 08f6032 commit 94dff0a
Show file tree
Hide file tree
Showing 25 changed files with 674 additions and 547 deletions.
5 changes: 5 additions & 0 deletions .changeset/chilled-dodos-invent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@lit-labs/motion': patch
---

Renamed `animate` option `animateOptions` to `keyframeOptions` and `AnimateController` `animateOptions` to `defaultOptions`
5 changes: 5 additions & 0 deletions .changeset/mighty-wombats-add.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@lit-labs/motion': patch
---

Renamed `flip()` to `animate()`
4 changes: 2 additions & 2 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,9 @@ packages/ts-transformers/tests/
packages/labs/motion/development/
packages/labs/motion/node_modules/
packages/labs/motion/index.*
packages/labs/motion/flip.*
packages/labs/motion/animate.*
packages/labs/motion/position.*
packages/labs/motion/flip-controller.*
packages/labs/motion/animate-controller.*
packages/labs/react/development/
packages/labs/react/test/
packages/labs/react/node_modules/
Expand Down
4 changes: 2 additions & 2 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,9 @@ packages/ts-transformers/tests/
packages/labs/motion/development/
packages/labs/motion/node_modules/
packages/labs/motion/index.*
packages/labs/motion/flip.*
packages/labs/motion/animate.*
packages/labs/motion/position.*
packages/labs/motion/flip-controller.*
packages/labs/motion/animate-controller.*
packages/labs/react/development/
packages/labs/react/test/
packages/labs/react/node_modules/
Expand Down
4 changes: 2 additions & 2 deletions packages/labs/motion/.gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/development/
/node_modules/
/index.*
/flip.*
/animate.*
/position.*
/flip-controller.*
/animate-controller.*
68 changes: 34 additions & 34 deletions packages/labs/motion/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,44 +10,44 @@ From inside your project folder, run:
$ npm install @lit-labs/motion
```

## Flip directive
## Animate directive

The `flip` directive can be used to animate DOM elements from one lit render
to the next. If the `flip` element between renders, it will perform a "tweening"
The `animate` directive can be used to animate DOM elements from one lit render
to the next. If the `animate` element between renders, it will perform a "tweening"
animation between the two states based on the options given. In addition,
elements can animate when they initially render to DOM and when they are
removed.

The directive supports a number of options:

| Option | Usage |
| ---------------- | -------------------------------------------------------------------------------------------------------------- |
| animationOptions | configure animation via standard KeyframeAnimationOptions |
| properties | list of properties to animate, defaults to ['left', 'top','width', 'height', 'opacity', 'color', 'background'] |
| disabled | disables animation |
| guard | function producing values that must change for the flip to run |
| in | keyframes to use when animating in |
| out | keyframes to use when animating out |
| skipInitial | skip animating in the first time |
| id | used to link to other flips via `inId` |
| inId | id of the flip to render from when animating in |
| onStart | run when the flip starts |
| onComplete | run when the flip completes |
| onFrames | run when the frames are produces, use to modify frames |
| Option | Usage |
| --------------- | -------------------------------------------------------------------------------------------------------------- |
| keyframeOptions | configure animation via standard KeyframeAnimationOptions |
| properties | list of properties to animate, defaults to ['left', 'top','width', 'height', 'opacity', 'color', 'background'] |
| disabled | disables animation |
| guard | function producing values that must change for the `animate` to run |
| in | keyframes to use when animating in |
| out | keyframes to use when animating out |
| skipInitial | skip animating in the first time |
| id | used to link to other `animate`'s via `inId` |
| inId | id of the `animate` to render from when animating in |
| onStart | run when the `animate` starts |
| onComplete | run when the `animate` completes |
| onFrames | run when the frames are produces, use to modify frames |

### How it works

The directive name is based on an animation technique of the same
name derived from First, Last, Invert, Play. This describes how the directive
works. It measures the styling of the flip element before a layout change
works. It measures the styling of the `animate` element before a layout change
(first) and after a layout change (last). Then it inverts the last layout
such that it matches the first layout. Finally it plays an animation which
removes the inverted layout such that the element animates to the "last" layout.
See the [flip article by Paul Lewis](https://aerotwist.com/blog/flip-your-animations/)
for more information about the technique.

The directive uses a reactive controller to coordinate measuring the DOM of the
flip element. The first layout is measured when the hosting element updates,
`animate` element. The first layout is measured when the hosting element updates,
and the last layout is measured when the hosting element renders and completes
its update.

Expand All @@ -56,7 +56,7 @@ its update.
Here's an example:

```ts
import {flip} from '@lit-labs/motion';
import {animate} from '@lit-labs/motion';
// ...

class MyElement extends LitElement {
Expand All @@ -79,7 +79,7 @@ class MyElement extends LitElement {
render() {
return html`
<button @click=${this._toggle}>Move</button>
<div class="box ${this.shifted ? 'shifted' : ''}" ${flip()}></div>
<div class="box ${this.shifted ? 'shifted' : ''}" ${animate()}></div>
`;
}

Expand All @@ -89,26 +89,26 @@ class MyElement extends LitElement {
}
```

## Flip controller
## AnimateController

The flip controller allows you to coordinate and control flip directives within
The animate controller allows you to coordinate and control `animate` directives within
a given element.

The controller constructor takes an options object with the following properties:

| Property | Usage |
| ----------- | ---------------------------------------------------------------- |
| flipOptions | default options for all element flip directives |
| startPaused | all element flip animations start paused |
| disabled | disables all element flip animations |
| onComplete | run when all element flip animations complete for a given update |
| Property | Usage |
| -------------- | ----------------------------------------------------------- |
| defaultOptions | default options for all element `animate` directives |
| startPaused | all element animations start paused |
| disabled | disables all element animations |
| onComplete | run when all element animations complete for a given update |

The flip controller also provides API for controlling flip animations,
The animate controller also provides API for controlling `animate` animations,
including `play()`, `pause()`, `cancel()`, `finish()`, and `togglePlay()`.
These methods affect all the flip animations for a given element. Finally,
flip controller has properties which reflect the state of the flip animations
in the host element: `isPlaying` returns true if any flips are
currently playing; `isAnimating` returns true if any flips currently have
These methods affect all the `animate` animations for a given element. Finally,
animate controller has properties which reflect the state of the `animate` animations
in the host element: `isPlaying` returns true if any `animate`'s are
currently playing; `isAnimating` returns true if any `animate`s currently have
animations (which may be paused).

## Contributing
Expand Down
30 changes: 15 additions & 15 deletions packages/labs/motion/demo/animation.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ <h2>Animation</h2>
<script type="module">
import {LitElement, html, css} from 'lit';
import {classMap} from 'lit/directives/class-map.js';
import {flip, flyBelow} from '../development/flip.js';
import {FlipController} from '../development/flip-controller.js';
import {animate, flyBelow} from '../development/animate.js';
import {AnimateController} from '../development/animate-controller.js';

class MyElement extends LitElement {
static properties = {
Expand All @@ -39,9 +39,9 @@ <h2>Animation</h2>
constructor() {
super();
this.layout = 0;
this.flipController = new FlipController(this, {
flipOptions: {
animationOptions: {
this.controller = new AnimateController(this, {
defaultOptions: {
keyframeOptions: {
duration: 1200,
},
},
Expand Down Expand Up @@ -188,24 +188,24 @@ <h2>Animation</h2>

return html`
<section class="animation-list ${classMap(classes)}">
<div class="box" ${flip()}>Item 1</div>
<div class="box" ${flip()}>Item 2</div>
<div class="box" ${flip()}>Item 3</div>
<div class="box" ${flip()}>Item 4</div>
<div class="box" ${animate()}>Item 1</div>
<div class="box" ${animate()}>Item 2</div>
<div class="box" ${animate()}>Item 3</div>
<div class="box" ${animate()}>Item 4</div>
</section>
<section>
<div
class="hibox box ${classMap(classes)}"
${flip({id: 'hi-outer'})}
${animate({id: 'hi-outer'})}
>
<div ${flip()}>Hi</div>
<div ${animate()}>Hi</div>
</div>
</section>
<section class="in-out">
${this.layout !== 0
? html`<div
class="box ${classMap(classes)}"
${flip({
${animate({
in: flyBelow,
out: flyBelow,
stabilizeOut: true,
Expand All @@ -219,7 +219,7 @@ <h2>Animation</h2>
}

changeLayout() {
if (!this.flipController.isAnimating) {
if (!this.controller.isAnimating) {
this.layout = ++this.layout % 4;
}
}
Expand All @@ -233,8 +233,8 @@ <h2>Animation</h2>
}

async clickHandler() {
if (this.flipController.isAnimating) {
this.flipController.togglePlay();
if (this.controller.isAnimating) {
this.controller.togglePlay();
} else {
this.changeLayout();
}
Expand Down
114 changes: 114 additions & 0 deletions packages/labs/motion/demo/around.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
<!DOCTYPE html>
<!--
@license
Copyright 2021 Google LLC
SPDX-License-Identifier: BSD-3-Clause
-->
<html>
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes"
/>
<style>
body {
font-family: 'Open Sans', sans-serif;
margin: 0;
height: 100vh;
width: 100vw;
display: flex;
justify-content: center;
align-items: center;
}
</style>
<title>Simple Animation</title>
</head>
<body>
<my-element></my-element>
<script type="module">
import {LitElement, html, css} from 'lit';
import {classMap} from 'lit/directives/class-map.js';
import {
animate,
flyBelow,
defaultCssProperties,
} from '../development/animate.js';

class MyElement extends LitElement {
static properties = {layout: {type: Number}};
static styles = css`
.container {
height: 70vh;
width: 50vw;
display: flex;
justify-content: space-between;
background: #e1e2e1;
border-radius: 5em;
padding: 5em;
}
.container.layout0 {
align-items: flex-start;
}
.container.layout1 {
flex-direction: column;
align-items: flex-end;
}
.container.layout2 {
flex-direction: row-reverse;
align-items: flex-end;
}
.container.layout3 {
flex-direction: column-reverse;
align-items: flex-start;
}
.container > * {
background: #002171;
color: white;
text-align: center;
border-radius: 50%;
width: 5em;
height: 5em;
}
`;

constructor() {
super();
this.layout = 0;
}

render() {
const options = {
keyframeOptions: {duration: 1500},
};
return html`
<section class="container layout${this.layout}">
<div ${animate(options)}></div>
<div ${animate(options)}></div>
<div ${animate(options)}></div>
<div ${animate(options)}></div>
<div
${animate({...options, onComplete: () => this.changeLayout()})}
></div>
</section>
`;
}

firstUpdated() {
this.changeLayout();
}

changeLayout() {
this.layout = (this.layout + 1) % 4;
}
}

customElements.define('my-element', MyElement);
</script>
</body>
</html>

0 comments on commit 94dff0a

Please sign in to comment.