aurelia

Accidental NPM Packaging (and JSPM!)

Last week I created a package - an NPM. I didn’t intend to. I just wanted to use the Microsoft Signal-R javascript client, and I was surprised to see it wasn’t listed in the Node package repository.

How hard can it be to create a package anyway?

There are two great motivators for developers. Laziness and annoyance.

  • Laziness: “I bet I can automate this, so I can spend more time doing interesting things”.
  • Annoyance:“Why isn’t there an NPM package for this? what is this, the dark ages?!”.

I found myself annoyed when I decided to use Microsoft’s SignalR Javascript client. There was no JSPM or NPM package.

The package manager I was using is JSPM - a wonderful bundle of joy that can use either NPMs or git repos as a package source. Lets make packages!

Pre Conditions

You need:

  • npm (node package manager)
  • jspm (javascript package manager)
  • a git client
  • github & npm accounts

Make a JSPM github package


c:\\github> mkdir mypackage
c:\\github> cd mypackage
c:\\github\\mypackage> git init

Add a .gitignore file, and setup your github remote repo as your origin.

Now you need a package.json file. This file defines what your package is, what it depends on, who maintains it, and where it lives. It can define a lot of other things too, as defined by the package.json spec. We can create one with npm.


c:\\github\\mypackage> npm init

name: (mypackage)
version: (1.0.0)
description:
entry point: (index.js)
test command:
git repository:
keywords:
author:
license: (ISC)
About to write to C:\github\mypackage\package.json:

{
  "name": "mypackage",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}


Is this ok? (yes)

Edit your package.json to suit your project. Run it through a json validator. Once you’re happy with it, commit and push it to github:


c:\\github\\mypackage> git commit -a
c:\\github\\mypackage> git push origin master

Now you can test it. Add trying adding it to another project, directly from your github repo:


c:\\github\\mypackage> jspm install github:[youraccount]/[your repo]

Ok, hopefully that went well.

Create NPM package & add to NPM repo


c:\\github\\mypackage> npm publish

Update NPM package

/eof

Animating Aurelia

Have you heard of Aurelia? It’s Rob Eisenberg’s new framework. If you travelled forward in time two years and wrote a framework based on cutting edge tech, Aurelia would be the result. Aurelia is built on technology so new that the standards haven’t been ratified yet. I’m talking ES6, ES7, transpiling, a proper module loader, lambda expressions (arrow functions), computed properties, and more.

Aurelia

Now let’s use this massively powerful framework to animate a few boxes.

{% raw %}

2015-04-28 Article Updated

This article had some incorrect code listed, and was not making proper use of the Aurelia-Animator. I have corrected the text and updated the code samples. Thanks to commenter “firens” for giving me a heads up.

{% endraw %}

Applying CSS Animations in Aurelia

What we are going to do is this:

Have new databound elements fade in as they are added to the DOM, using CSS transitions. Then, we will update a counter and animate it.

To achieve our goal, we start by installing Aurelia’s animation library. Open a command prompt and add it to your project as follows:


$ jspm install aurelia-animator-css

If you haven’t seen jspm before, check it out. It isn’t limited to jspm packages. Jspm can also install and manage npm packages, as well as pulling modules down from github repositories.

CSS Animations

If you’re unfamiliar with CSS animations - don’t worry. They are straight forward. You define the key points in the animation - the starting state (0%) and the end state (100%). Apply CSS styles for those key points. The browser will extrapolate the rest. Here are the definitions for our “fade-in” and “flash” animations:


@keyframes fade-in {
  0%   { opacity: 0; }
  100% { opacity: 1; }
}
/* for compatibility with older browsers */
@-webkit-keyframes fade-in{
  0%   { opacity: 0; }
  100% { opacity: 1; }
}

@-webkit-keyframes flash {
  0%, 50%, 100% {
    opacity: 1;
  }

  25%, 75% {
    opacity: 0;
  }
}

/* Credit goes to http://daneden.github.io/animate.css/ */
@keyframes flash {
  0%, 50%, 100% {
    opacity: 1;
  }

  25%, 75% {
    opacity: 0;
  }
}

To use our new animations we need to create a CSS class to apply to our new DOM elements, and we need to define a class to animate our counter.


.fade-in-box {
  -webkit-animation: 0.5s fade-in;
  animation: 0.5s fade-in;

  border: 1px solid black;
  background: yellow;
}

.au-attention {
  -webkit-animation: 0.5s flash;
  animation:  0.5s flash;
}

Aurelia .js class

This is our view model.


import {inject} from 'aurelia-framework';
import {CssAnimator} from 'aurelia-animator-css';

// Use this decorator to inject the animator
@inject(CssAnimator)
export class ListExample{

  heading = 'List Example';

  listItems = [
    { listItem: 'pencils', qty: 2 },
    { listItem: 'glue', qty: 1 },
  ];

  // The inject decorator needs an appropriate constructor
  // to inject the animator.
  constructor(animator) {
    this.animator = animator;
  }

  addListItem() {
     this.listItems.push({listItem: 'packing tape',  qty: 1 });

     // then removeClass method returns a promise. We can use "then"
     // to chain it to addClass. This allows us to 'toggle' the class on the
     // element - and fire the animation
     this.animator.removeClass(this.elGridCount, 'au-attention')
        .then(this.animator.addClass(this.elGridCount, 'au-attention'));
  }

}

The code above creates a list of items and a button - which we bind our view to. Notice the nice ES6 syntax?

Aurelia .html view

This is our view.


<template>
  <section>
    <h2>${heading}</h2>

    <div><button click.trigger="addListItem()">Add List Item</button></div>

    <div role="grid">
      <div repeat.for="row of listItems" style="display: flex;">
        <div style="flex: 1 auto;" class="fade-in-box" >${row.listItem}</div>
        <div style="flex: 1 100px;" class="fade-in-box" >${row.qty}</div>
      </div>
    </div>

    Count: <div ref="elGridCount">${listItems.length}</div>

  </section>
</template>

In the view, we’ve defined a list, and used “repeat.for” to bind it to our view model list items. The button is bound to addListItem().

We’ve also added a count of our list items. Note the “ref” attribute on the counter. This attribute is used in the model to reference the element in the view.

Click!

When the user clicks the button, the following events occur:

Events related to new item addition

  1. The view model method addListItem() adds a new item to the list.
  2. Aurelia observes the new item being added, and triggers a DOM insert to add it to the grid.
  3. The browser begins the fade in animation for the new element

Events related to the counter

  1. The view model method addListItem() calls the aurelia animator with the removeClass method, and passes in addClass via a promise..
  2. The Aurelia-Animator removes the “au-attention” class (if it exists), then follows the next function in the promise chain (addClass).
  3. The Aurelia-animator adds the “au-attention” class to the “elGridCount” element in the view.
  4. The browser renders the “flash” animation referenced in the “au-attention” css class.

Pretty cool, huh? Some subtle, unobtrusive animations can really make a page seem slick. Just don’t go overboard, or you’ll take us back to the hellish days of animated gif wall papers.

You may be thinking “all the animator has done is add a css class to an element - the browser handled the animation part. What is the point of the animator?”.

Good question. The animator:

  • gives us events (such as animation start/end)
  • allows us to chain multiple animations together using promises
  • can also set/change the speed of animations
  • can stagger animations - one after the other

The animator uses Aurelia’s animator service - which provides an animation interface. The interface allows the animator service to have alternative implementations swapped in. For example, an implementation of the famo.us animation library) could be integrated. Exciting times ahead!

Aurelia-animator Supported Events

The DOM events supported by Aurelia’s animator are:

  • enter - Element enters view
  • leave - Element leaves view
  • removeClass - Class removed from DOM
  • addClass - Class added to DOM

The “move” event is defined, but not currently supported. It will return a failed result if you try.

/eof