npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@dreamonkey/quasar-app-extension-animate

v2.3.0

Published

Extend Quasar animation system

Downloads

37

Readme

Quasar animation system extension

This App Extension(AE) simplifies the use of animations activated when elements show up on the screen. It's meant to work with Intersection Directive.

All elements marked by a [data-animate] attribute will be hidden upon component mount and shown, with the animation you provide, once they come into view for a percentage you decide. You can also manage the animation delay, duration and easing via CSS classes or SCSS variables and functions.

Install

Add the App Extension into your Quasar project

quasar ext add @dreamonkey/animate

This AE contains many variables, functions and utility classes you can use to make your style definitions more readable and coherent. It provides the most used durations and commonly used easing functions. Utility classes are automatically registered by the AE, but you need to import the variables and functions in your Quasar SCSS variables file to make them available in the style tag of all your components:

// src/css/quasar.variables.scss
@import "~@dreamonkey/quasar-app-extension-animate/dist/animations";

If using Options or Class API, register the mixin on all components using this AE features

import {
  AnimateMixin,
  animateIn,
  whenPastEnd,
} from "@dreamonkey/quasar-app-extension-animate";

export default {
  name: "AboutPage",
  mixins: [AnimateMixin],
  methods: {
    animateIn,
    whenPastEnd,
  },
};

If using Composition API, call the composable in all components using this AE features (aka every component which contains at least a data-animate attribute)

import {
  useAnimate,
  animateIn,
  whenPastEnd,
} from "@dreamonkey/quasar-app-extension-animate";
import { defineComponent } from "vue";

export default defineComponent({
  name: "AboutPage",
  setup() {
    useAnimate();

    return { whenPastEnd, animateIn };
  },
});

Uninstall

Remove the AE from your Quasar project:

quasar ext remove @dreamonkey/animate

Remove the SCSS variables file import from src/css/quasar.variables.scss.

Remove all AnimateMixin and useAnimate references.

How to use it

Add data-animate attribute on every element to which you want to attach an appear animation. The mixin/composable will set the opacity of all marked elements to zero during the component mount phase, making them invisible until they are triggered.

<img data-animate class="my-dog" src="img/doggo.jpg" />

Use the v-intersection directive and combine the functions provided by this AE to express the animation you want to obtain. As example, here's how you can animate an image with the following properties:

  • activate the animation when it fully came into view (whenPastEnd)
  • apply a decelerating easing, typical of entering animations (animateIn)
  • use the fadeInDown class to define the animation you want to apply
  • make the animation last 800ms
<img
  v-intersection.once="
    whenPastEnd(animateIn('fadeInDown', { duration: '800ms' }))
  "
  data-animate
  class="my-dog"
  src="img/doggo.jpg"
/>

Concatenated animations

You can manage multiple parallel, staggered or concatenated animations adding a bit of scripting. In this example a vertical separator is animated to grow in height while a title is animated in too, then all paragraphs of the content div are animated with a staggered fading in effect.

Our template will be:

<template>
  <div
    v-intersection.once="whenPastPercentage(0.1, animateSection)"
    class="container"
  >
    <span class="separator" />
    <div class="body">
      <h5 data-animate class="title">MY TITLE</h5>
      <div class="content">
        <p data-animate>p1</p>
        <p data-animate>p2</p>
        <p data-animate>p3</p>
        <p data-animate>p4</p>
        <p data-animate>p5</p>
      </div>
    </div>
  </div>
</template>
.separator {
  border-left: solid 4px black;
  // separator animation is based on `scaleY` so we initially set it to 0
  transform: scaleY(0);
  transform-origin: top;
}

.scale-normal {
  transform: scale(1);
  transition-property: transform;
}

Define the method which starts the animations on the component

import { animateIn } from "@dreamonkey/quasar-app-extension-animate";

export default {
  // ...
  methods: {
    animateSection(el) {
      const separator = el.querySelector(".separator");
      const title = el.querySelector(".title");
      const elements = el.querySelector(".content").children;
      let i = 0;
      animateIn("fadeInLeft", {
        duration: `${TITLE_AND_SEPARATOR_ANIMATION_DURATION}ms`,
      })(title);
      animateIn("scale-normal", {
        duration: `${TITLE_AND_SEPARATOR_ANIMATION_DURATION}ms`,
      })(separator);
      elements.forEach((element) => {
        animateIn("fadeInLeft", {
          duration: `${PARAGRAPHS_ANIMATION_DURATION}ms`,
          delay: DELAY_BEFORE_START + DELAY_BETWEEN_PARAGRAPHS_ANIMATION * i,
        })(element);
        i++;
      });
    },
  },
};

API

animate(animationClass, options)

Automatically sets a timeout to create a delay if needed and adds the provided class, the animated class (needed to execute animations). Based on the options, it will also apply easing and duration classes. In case the element was hidden thanks to data-animate attribute, the opacity is reset to its original CSS value before the the animation starts.

Returns an intersectionHandler function usable with whenPastXxx helpers.

animateIn(animationClass, options)

Same as animate but adds a decelerate easing by default.

animateOut(animationClass, options)

Same as animate but adds an accelerate easing by default.

whenPast(percentageOrAlias, intersectionHandler)

percentageOrAlias can be both a percentage (0.0 < x < 1.0) or a percentage alias (start => 0.0, quarter => 0.25, half => 0.5, end => 1.0).

Returns a function in the format accepted by v-intersection Quasar directive, accepting an element reference and returning an intersection observer configuration object.

whenPastPercentage(percentage, intersectionHandler)

Same as whenPast but only accepts a numeric percentage.

whenPastStart(intersectionHandler) | whenPastQuarter(intersectionHandler) | whenPastHalf(intersectionHandler) | whenPastEnd(intersectionHandler)

Same as whenPast but with pre-applied percentage.

Common mistakes

SVG images doesn't works with directives

Currently if you try to use this directive on svg tags you'll get an error like ReferenceError: _directive_intersection is not defined. Here is the issue link.

A work around is wrapping the svg into a div and apply this directive on it:

<div
  v-intersection.once="
    whenPastEnd(animateIn('fadeInDown', { duration: '800ms' }))
  "
  data-animate
>
  <svg
    xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    version="1.1"
    width="24"
    height="24"
    viewBox="0 0 24 24"
  >
    <path
      d="M2,3H5.5L12,15L18.5,3H22L12,21L2,3M6.5,3H9.5L12,7.58L14.5,3H17.5L12,13.08L6.5,3Z"
    />
  </svg>
</div>

Notice that this is the case for svg inlined by third party tools too, eg. svg-inline-loader.

Animation are triggered based on the percentage of the element which is contained in the screen, NOT ON THE ELEMENT HEIGHT :

  • On small screens elements might not resize correctly and part of them could overflow. Having a piece of it always out of the screen would prevent the trigger to fire.
  • The same concept applies if the element is too big and overflows its container.
  • Borders and paddings are part of the element box model and could prevent the trigger to fire.

As example, consider a screen with height 900px containing an element with height of 1000px, both with the same width. If you want to animate the element with whenPastEnd(...) the element will never show up because the trigger condition cannot be met.

In this context, the End part represent the moment where the element is fully contained into the view, not the end of the element height.

Donate

If you appreciate the work that went into this App Extension, please consider donating.