Skip to content

Commit

Permalink
feat: simplify usage with Composition API (#8)
Browse files Browse the repository at this point in the history
Co-authored-by: Alessandro Vandelli <[email protected]>
  • Loading branch information
IlCallo and vandelpavel committed Mar 3, 2022
1 parent b270e2f commit 24c555b
Show file tree
Hide file tree
Showing 7 changed files with 204 additions and 74 deletions.
39 changes: 35 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export default {
};
```

If using Composition API, call the composable on all components using this AE features and provide it a ref to the component template root
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)

```ts
import { useAnimate } from "@dreamonkey/quasar-app-extension-animate";
Expand All @@ -41,9 +41,9 @@ import { defineComponent, ref, Ref } from "@vue/composition-api";
export default defineComponent({
name: "AboutPage",
setup() {
const hostRef = ref() as Ref<HTMLElement>;
const { whenPastEnd, animateIn } = useAnimate();

return { hostRef, ...useAnimate(hostRef) };
return { whenPastEnd, animateIn };
},
});
```
Expand Down Expand Up @@ -191,7 +191,38 @@ Same as `whenPast` but with pre-applied percentage.

## Common mistakes

Animation are triggered based on the percentage of the element which is contained in the screen, **NOT ON THE ELEMENT HEIGHT** :
### 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](https://github.com/vuejs/core/issues/5289).

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

```html
<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](https://github.com/webpack-contrib/svg-inline-loader#svg-inline-loader-for-webpack).

### 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.
Expand Down
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"typings": "dist/types/exports.d.ts",
"scripts": {
"build": "rm -rf dist && tsc --declaration --declarationDir dist/types && copyfiles -f src/css/animations.scss dist",
"install-build-clean": "yarn install && yarn build && rm -rf node_modules",
"test": "echo \"No test specified\" && exit 0",
"deploy": "yarn build && yarn publish --tag latest"
},
Expand All @@ -28,9 +29,10 @@
"yarn": ">= 1.17.3"
},
"devDependencies": {
"@babel/types": "^7.17.0",
"copyfiles": "^2.4.1",
"typescript": "^4.4.3",
"vue": "^3.1.0"
"typescript": "^4.6.2",
"vue": "^3.2.31"
},
"publishConfig": {
"access": "public"
Expand Down
10 changes: 7 additions & 3 deletions src/composables/animate.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import { onMounted, Ref } from "vue";
import { getCurrentInstance, onMounted } from "vue";
import {
animationFns,
hideAnimatableElements,
insersectionFns,
} from "../internals";

export function useAnimate(hostRef: Ref<HTMLElement>) {
onMounted(() => hideAnimatableElements(hostRef.value));
export function useAnimate() {
const vm = getCurrentInstance()?.proxy!;

onMounted(() => {
hideAnimatableElements(vm);
});

return {
...animationFns,
Expand Down
3 changes: 2 additions & 1 deletion src/css/animations.scss
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ $duration: (
}

@each $duration-name, $duration-value in $duration {
.duration-#{$duration-name} {
//We must increase the specificity otherwise the properties would be overwritten by ".animated" class
.duration-#{$duration-name}.duration-#{$duration-name} {
animation-duration: $duration-value;
// The next line is set to allow the management of transition durations
// This could cause bugs and in case will be removed, WATCH OUT
Expand Down
13 changes: 12 additions & 1 deletion src/internals.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { ComponentPublicInstance } from "vue";
import { ShapeFlags } from "@vue/shared";

export interface AnimateOptions {
delay?: number;
easing?: string;
Expand Down Expand Up @@ -88,7 +91,15 @@ function whenPast(
return whenPastPercentage(percentage, intersectionHandler);
}

export function hideAnimatableElements(element: HTMLElement) {
// Taken from https://github.com/vuejs/test-utils/blob/1b35e75868025ab1925c15208c55580e52b27326/src/vueWrapper.ts#L67
function getComponentRoot(vm: ComponentPublicInstance): HTMLElement {
// if the subtree is an array of children, we have multiple root nodes
const hasMultipleRoots = vm.$.subTree.shapeFlag === ShapeFlags.ARRAY_CHILDREN;
return hasMultipleRoots ? vm.$el : vm.$el.parentElement;
}

export function hideAnimatableElements(vm: ComponentPublicInstance) {
const element = getComponentRoot(vm);
element.querySelectorAll<HTMLElement>("[data-animate]").forEach((el) => {
el.style.opacity = "0";
});
Expand Down
7 changes: 4 additions & 3 deletions src/mixins/animate.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { ComponentPublicInstance } from "vue";
import {
hideAnimatableElements,
animationFns,
hideAnimatableElements,
insersectionFns,
} from "../internals";

export default {
mounted(this: { $el: HTMLElement }) {
hideAnimatableElements(this.$el);
mounted(this: ComponentPublicInstance) {
hideAnimatableElements(this);
},
methods: {
...animationFns,
Expand Down
Loading

0 comments on commit 24c555b

Please sign in to comment.