Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create stache animation guide and functionality #3864

Open
justinbmeyer opened this Issue Jan 25, 2018 · 3 comments

Comments

Projects
None yet
2 participants
@justinbmeyer
Copy link
Contributor

justinbmeyer commented Jan 25, 2018

tldr; This proposal seeks to create a guide for creating and using animation libraries in can-stache and to create the necessary functionality to enable the guide.

This was discussed on a recent live stream (32:10) and a previous live stream (19:51).

The Problem

It's not obvious how to perform animations in CanJS. CanJS 4 also lags behind in empowering animations compared to VueJS and others. Specifically, CanJS doesn't have a way to animate elements when they enter and leave the page.

NOTE: CanJS 3.0 has this ability, but we never migrated the plugin to the new can-dom-mutate.

The Solution

I would like to create a guide that shows:

  • How to perform basic animations using CSS animations when elements appear and disappear
  • How to create custom JavaScript (or css) animations

Basic animations

I'd like to more or less steal VueJS's transition helper.

If an element has a can-transition property like:

{{# each(todos) }}
  <li can-transition='todo'>

  </li>
{{/ each }}

CanJS will automatically add and remove the following classNames to the element:

  1. todo-enter: Starting state for enter. Added before element is inserted, removed one frame after element is inserted.

  2. todo-enter-active: Active state for enter. Applied during the entire entering phase. Added before element is inserted, removed when transition/animation finishes. This class can be used to define the duration, delay and easing curve for the entering transition.

  3. todo-enter-to: Ending state for enter. Added one frame after element is inserted (at the same time todo-enter is removed), removed when transition/animation finishes.

  4. todo-leave: Starting state for leave. Added immediately when a leaving transition is triggered, removed after one frame.

  5. todo-leave-active: Active state for leave. Applied during the entire leaving phase. Added immediately when leave transition is triggered, removed when the transition/animation finishes. This class can be used to define the duration, delay and easing curve for the leaving transition.

  6. todo-leave-to: Ending state for leave. Added one frame after a leaving transition is triggered (at the same time todo-leave is removed), removed when the transition/animation finishes.

A basic animation can be written with the following CSS

.todo-enter-active {
  transition: all .3s ease;
}
.todo-leave-active {
  transition: all .8s cubic-bezier(1.0, 0.5, 0.8, 1.0);
}
.todo-enter, .todo-leave-to {
  transform: translateX(10px);
  opacity: 0;
}

Local animation helper

The guide will show how to create a local animation helper function using jQuery's fadeIn and fade out:

import $ from "jquery";
import stache from "can-stache";

// stache.helper labels the function has a helper
// it also makes sure that the `this` is the `helperOptions` with
// this.element and this.event available
module.exports = stache.helper(function(duration, callback){
  if(this.event.pause) {
    this.event.pause(); // must call to prevent "disconnect" from removing the element
  }
  $(this.element).fadeIn(duration, function(){
    callback && callback() // might want to pass the event if it wants to be paused again
    this.event.resume && this.event.resume();
  })
});

Importing animation helpers in the template

Then we will show how to import the animation helper within a stache template:

<can-import from="./my-fade-in" value:to="scope.helpers.fadeIn"/>

Importing animation helpers through components

For folks who are not using steal, lets show how to import helpers for the component:

import fadeIn from "./my-fade-in";

Component.extend({
  view: `...`,
  ViewModel: { ... },
  helpers: {
    fadeIn
  }
})

Global animation helper

The guide should show how to make a global animation helper too as an aside. This is useful for JSBins that are unable to import with stache.

import $ from "jquery";
import stache from "can-stache";

// stache.helper labels the function has a helper
// it also makes sure that the `this` is the `helperOptions` with
// this.element and this.event available
module.exports = stache.addHelper(function(duration, callback){
  $(this.element).fadeIn(duration, callback)
});
  • stache.addHelper is needed so that the function gets access to the element and event without needing to ask for it. (Alternatively we could make people pass scope.helperOptions.)

Using a helper

Once a user has a helper available in stache, we will show them how to use it. There are a variety of ways:

DOM event driven

When a DOM event happens, one can call an animation like this:

<div on:click="fadeIn('slow')">Fade Me In</div>

More likely, people will want to respond to when elements are connected and disconnected from the dom. They will need to add some special events:

var domEvents = require("can-dom-events");
var connectedEvent = require("can-event-dom-connected");
var disconnectEvent = require("can-event-dom-disconnect");

domEvents.addEvent(connectedEvent);
domEvents.addEvent(disconnectEvent);
  • Note the different tenses. This is because disconnect is called before the element is actually disconnected.
{{#each(items) }}
  <li on:connected="fadeIn()" on:disconnect="fadeOut()">{{name}}</li>
{{/each}}

data-driven animations

Usually, events will happen because events are published on our observables. Folks should use :by: like:

<div on:updated:by:todo="fadeOut(100)"/>

This will work well with can-connect's created, updated and destroyed events.

Most animation functions should take a callback function to call when complete. This is so additional behaviors can happen after the animation has completed:

<div on:updated:by:todo="fadeOut(100, todo.backup)"/>

Technology changes

  • stache.helper()
  • connected / disconnected should mix into can-dom-mutate? Stache is the alternative, but can-dom-mutate is already stateful.

@justinbmeyer justinbmeyer changed the title Stache animation guide and functionality WORK IN PROGRESS: Stache animation guide and functionality Jan 25, 2018

@justinbmeyer justinbmeyer changed the title WORK IN PROGRESS: Stache animation guide and functionality Stache animation guide and functionality Jan 26, 2018

@chasenlehara chasenlehara changed the title Stache animation guide and functionality Create stache animation guide and functionality Jan 26, 2018

@frank-dspeed

This comment has been minimized.

Copy link
Contributor

frank-dspeed commented Nov 25, 2018

@justinbmeyer can we simply use callexpressions again? if we do {{fadeAnimatedLi(this, 300)}} we should get the element already as far as i remember then in our fadeIn function we can care for the disconnect function to fadeOut.

@frank-dspeed

This comment has been minimized.

Copy link
Contributor

frank-dspeed commented Nov 25, 2018

I copy the Answer from canjs/can-stache#611 =>

@justinbmeyer https://codepen.io/frank-dspeed/pen/KGemLG
example that shows what i mean it is also related to #4517

it can be also applyed here to render animated sections via callexpressions

@justinbmeyer

This comment has been minimized.

Copy link
Contributor Author

justinbmeyer commented Nov 25, 2018

Call expressions work. They can be cumbersome

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.