DEV Community

Cover image for NGXA Library
klodian shaba
klodian shaba

Posted on

NGXA Library

Ngxa 🚀

So excited to announce another one open source contribution of me. With purpose of helping me and anyone else on using Angular Animations.
Animations are one of the essential UI trends of any modern website/application, they create the effect of real “live” communication between users and the system.
So to build animations easy and reusing single style code I created Ngxa.

Ngxa library helps to build animations easy in angular apps based on Angular Animations
Easy builder, Dynamically, Reusable
Utility functions based on Animate.css styles with the power of ngxa library
Reusing single style code functions with different configurations

Quick Links

Demo ~ Documentation ~ Npm Package

Getting Started

Installation

npm i ngxa --save
Enter fullscreen mode Exit fullscreen mode

Usage

import { roll } from 'ngxa';

@Component({
  animations: [
    roll({direction:'In'}), // rollIn
    roll({direction:'Out'}) // rollOut
  ]
})
Enter fullscreen mode Exit fullscreen mode

Example Of Building Trigger

Building animation trigger by using buildTrigger function from ngxa

import {animate, animation, AnimationTriggerMetadata, keyframes, style} from "@angular/animations";
import {AnimationConfig} from "ngxa/common";
import {buildTrigger} from "ngxa/base";

const FadeKeyFrames: AnimationKeyframesSequenceMetadata = keyframes([
  style({opacity: 0, offset: 0}),
  style({opacity: 1, offset: 1}),
]);

const FadeAnimation: AnimationReferenceMetadata = animation( animate('{{timings}}', FadeKeyFrames));

export const fade = (animationConfig?: Partial<AnimationConfig>): AnimationTriggerMetadata => {
  return buildTrigger({
    triggerName: (animationConfig && animationConfig.triggerName) || 'fade',
    transitions: {
      animationReferenceMetadata: FadeAnimation,
      animationConfig,
      animationOptions: {params: {timings: '500ms'}}
    },
    states: []
  });
};
Enter fullscreen mode Exit fullscreen mode

Now the trigger can be reused anywhere we want just by importing it and Including into animations property in component decorator.
The trigger function accept an optional configuration parameter to overwrite default AnimationConfig.

import {fade} from "./path";

@Component({
  selector: 'app-header',
  templateUrl: './header.component.html',
  styleUrls: ['./header.component.scss'],
  animations: [
    // use fadeAnimation and overwrite optional configs
    fade({timings:'0.3s', stateChangeExpressions: [':enter', '0 => 1'], triggerName: 'fadeAnimation'} ) 
  ]
})
Enter fullscreen mode Exit fullscreen mode

Using Animation in component's Template

<span [@fadeAnimation]="state">Fade Me</span>
Enter fullscreen mode Exit fullscreen mode

Or with dynamic params

<span [@fadeAnimation]="{value:state,params:{timings:'0.3s'}}">Fade Me</span>
Enter fullscreen mode Exit fullscreen mode

Common Configuration Interfaces

export interface AnimationConfig{
  triggerName: string;
  stateChangeExpressions: string | string[];
  delay: string;
  timings: string | number;
  nestedAnimations: NestedAnimationsType;
}

export interface TransitionConfig{
  animationReferenceMetadata: AnimationReferenceMetadata;
  animationConfig?: Partial<AnimationConfig>;
  animationOptions?: AnimationOptions | null;
}

export interface BuildTriggerConfig{
  triggerName: string;
  transitions: TransitionConfig | TransitionConfig[];
  states?: AnimationStateMetadata | AnimationStateMetadata[],
}
Enter fullscreen mode Exit fullscreen mode

If needed to add specific configaration properties based on each style, we should create a new interface and extend AnimationConfig to include all necessary properties

import {AnimationConfig} from "./ngxa/common";

interface RotateInConfig extends AnimationConfig{
  degrees: number;
  direction: RotateInAnimationDirection;
}
Enter fullscreen mode Exit fullscreen mode

Utility functions Based On Animate.css Styles

Each style offers two functions, building trigger and building transition

Triggers

Can be reused for single style with different configurations

import {
bounce, flash, pulse, rubberBand, shake, headShake, swing, tada, wobble, jello, heartBeat,
backIn, backOut, bounceIn, bounceOut, fadeIn, fadeOut, flip, flipIn, flipOut,
lightspeedIn, lightspeedOut, rotateIn, rotateOut, hinge, jackInTheBox, roll, zoomIn, zoomOut, slideIn, slideOut
} from "./ngxa";
Enter fullscreen mode Exit fullscreen mode

Let's take on consideration reusing zoomIn function on multiple directions such as: zoomInUp, zoomInDown, zoomInLeft, zoomInRight

import {zoomIn} from "./ngxa";
@Component({
  selector: 'app-header',
  templateUrl: './header.component.html',
  styleUrls: ['./header.component.scss'],
  animations:[
    zoomIn(),
    zoomIn({direction: 'Up', stateChangeExpressions: ':enter, 0 => 1', translate: '200px'}), 
    zoomIn({direction: 'Down', stateChangeExpressions: [':enter','out => in'], translate: '500px'}),
    zoomIn({direction: 'Left', translate: '300px', nestedAnimations:'parallel'}),
    zoomIn({direction: 'Right', timings:'1s', triggerName:'customZoomInRight'}),
  ]
})
Enter fullscreen mode Exit fullscreen mode
<div [@zoomIn]>
  <span>ZoomIn Me</span>
</div>
<div [@zoomInUp]>
  <span>ZoomInUp Me</span>
</div>
<div [@zoomInDown]>
  <span>ZoomInDown Me</span>
</div>
<div [@zoomInLeft]>
  <span>ZoomInLeft Me</span>
</div>
<div [@customZoomInRight]>
  <span>ZoomInRight Me</span>
</div>
Enter fullscreen mode Exit fullscreen mode

Using it with dynamic params and state

<div [@zoomInDown]="{value:state,params:{timings:'1s', delay:'0ms', translate:'2000px'}}">
  <span>ZoomInDown Me</span>
</div>
<button mat-raised-button (click)="onAnimateIt()">Animate It</button>
Enter fullscreen mode Exit fullscreen mode

onAnimateIt event handler

state: string = 'out';

onAnimateIt(): void{
    this.state = 'out';
    setTimeout(()=> {
      this.state = 'in';
    },1)
}
Enter fullscreen mode Exit fullscreen mode

Transitions

can be included into other triggers with different configurations

import {
bounceTransition, flashTransition, pulseTransition, rubberBandTransition, shakeTransition, headShakeTransition,
swingTransition, tadaTransition, wobbleTransition, jelloTransition, heartBeatTransition,
backInTransition, backOutTransition, bounceInTransition, bounceOutTransition,
fadeInTransition, fadeOutTransition, flipInTransition, flipOutTransition, flipTransition,
lightspeedInTransition, lightspeedOutTransition, rotateInTransition, rotateOutTransition,
hingeTransition, jackInTheBoxTransition, rollTransition, zoomInTransition, zoomOutTransition,
slideInTransition, slideOutTransition,
} from "./ngxa";
Enter fullscreen mode Exit fullscreen mode

Creating a trigger with multiple styles by using transition functions

export function attentionsAndBounceInStyles(config?: Partial<AnimationConfig>): AnimationTriggerMetadata {
  return buildTrigger(
    {
      triggerName: (config && config.triggerName) || 'animations',
      transitions: [
        swingTransition({stateChangeExpressions: '* => swing'}),
        bounceTransition({stateChangeExpressions: '* => bounce'}),
        flashTransition({stateChangeExpressions: '* => flash'}),
        headShakeTransition({stateChangeExpressions: '* => headShake'}),
        heartBeatTransition({stateChangeExpressions: '* => heartBeat'}),
        jelloTransition({stateChangeExpressions: '* => jello'}),
        pulseTransition({stateChangeExpressions: '* => pulse'}),
        rubberBandTransition({stateChangeExpressions: '* => rubberBand'}),
        shakeTransition({stateChangeExpressions: '* => shake'}),
        tadaTransition({stateChangeExpressions: '* => tada'}),
        wobbleTransition({stateChangeExpressions: '* => wobble'}),

        // bounce in transition on different directions
        bounceInTransition({stateChangeExpressions: '* => bounceIn'}),
        bounceInTransition({stateChangeExpressions: '* => bounceInUp', direction: 'Up'}),
        bounceInTransition({stateChangeExpressions: '* => bounceInDown', direction: 'Down'}),
        bounceInTransition({stateChangeExpressions: '* => bounceInLeft', direction: 'Left'}),
        bounceInTransition({stateChangeExpressions: '* => bounceInRight', direction: 'Right'}),
      ]
    }
  )
}
Enter fullscreen mode Exit fullscreen mode

Stagger Nested Animations

To fire animations into a list can be used staggerNestedAnimations function as a parent animation

import {swing, zoomIn, staggerNestedAnimations} from "./ngxa";

@Component({
  selector: 'app-description',
  templateUrl: './description.component.html',
  styleUrls: ['./description.component.scss'],
  animations: [
    zoomIn({stateChangeExpressions:':enter, 0 => 1', timings:'1s', direction: 'Down'}),
    swing({stateChangeExpressions:':enter, 0 => 1'}),
    staggerNestedAnimations({timings:'300ms', stateChangeExpressions:':enter, 0 => 1'})
  ]
})

export class DescriptionComponent{
  status: boolean = true;
  onAnimateIt() {
    this.status = false;
    setTimeout(() => {
      this.status = true;
    }, 1);
  }
}
Enter fullscreen mode Exit fullscreen mode
<div [@staggerNestedAnimations]="status">
  <div [@zoomInDown]="status">
    <span>Angular Animations Wrapper</span>
  </div>
  <div [@zoomInDown]="status">
    <div [@swing]="{value:status, params:{timings:'1500ms'}}">
      <span>Easy Builder, Dynamically, Reusable And Different Direction On Single Base Code</span>
    </div>
    <span>This wrapper helps you to implement animations easy in your angular application</span>
  </div>
  <button [@zoomInDown]="status" (click)="onAnimateIt()" >
    Animate It
  </button>
</div>
Enter fullscreen mode Exit fullscreen mode

That's all for now 👋🏼

Please file issues and pull requests against that Repo, let's improve it and add more futures together.

I hope this package will be helpful for your current and future projects to implement Animations.

If it looks helpful for you, please like and share to help others get knowing about it.

Thanks for reading, let me know your opinion, it's worth a lot!

Top comments (2)

Collapse
 
oliverdjbrown profile image
Oliver Brown

this looks amazing, has a lot of potential

Collapse
 
klodianshaba profile image
klodian shaba

many thanks Oliver, happy to hear that.