nanime 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.md +94 -0
  2. package/dist/module.d.mts +14 -0
  3. package/dist/module.json +12 -0
  4. package/dist/module.mjs +56 -0
  5. package/dist/runtime/app/components/transition/Scale.d.vue.ts +13 -0
  6. package/dist/runtime/app/components/transition/Scale.vue +8 -0
  7. package/dist/runtime/app/components/transition/Scale.vue.d.ts +13 -0
  8. package/dist/runtime/app/components/transition/Slide.d.vue.ts +13 -0
  9. package/dist/runtime/app/components/transition/Slide.vue +145 -0
  10. package/dist/runtime/app/components/transition/Slide.vue.d.ts +13 -0
  11. package/dist/runtime/app/components/transition/types.d.ts +44 -0
  12. package/dist/runtime/app/components/transition/types.js +6 -0
  13. package/dist/runtime/app/composables/useAnimatable.d.ts +4 -0
  14. package/dist/runtime/app/composables/useAnimatable.js +21 -0
  15. package/dist/runtime/app/composables/useAnimate.d.ts +5 -0
  16. package/dist/runtime/app/composables/useAnimate.js +22 -0
  17. package/dist/runtime/app/composables/useLayout.d.ts +9 -0
  18. package/dist/runtime/app/composables/useLayout.js +34 -0
  19. package/dist/runtime/app/composables/useSplitText.d.ts +50 -0
  20. package/dist/runtime/app/composables/useSplitText.js +48 -0
  21. package/dist/runtime/app/composables/useWaapiAnimate.d.ts +5 -0
  22. package/dist/runtime/app/composables/useWaapiAnimate.js +19 -0
  23. package/dist/runtime/app/utils/easings.d.ts +1 -0
  24. package/dist/runtime/app/utils/easings.js +1 -0
  25. package/dist/runtime/app/utils/extract-props.d.ts +6 -0
  26. package/dist/runtime/app/utils/extract-props.js +13 -0
  27. package/dist/runtime/app/utils/index.d.ts +1 -0
  28. package/dist/runtime/app/utils/index.js +1 -0
  29. package/dist/runtime/app/utils/normalize-targets.d.ts +14 -0
  30. package/dist/runtime/app/utils/normalize-targets.js +44 -0
  31. package/dist/runtime/app/utils/transitions/normalizers/index.d.ts +3 -0
  32. package/dist/runtime/app/utils/transitions/normalizers/index.js +3 -0
  33. package/dist/runtime/app/utils/transitions/normalizers/normalize-axis.d.ts +2 -0
  34. package/dist/runtime/app/utils/transitions/normalizers/normalize-axis.js +12 -0
  35. package/dist/runtime/app/utils/transitions/normalizers/normalize-duration.d.ts +2 -0
  36. package/dist/runtime/app/utils/transitions/normalizers/normalize-duration.js +12 -0
  37. package/dist/runtime/app/utils/transitions/normalizers/normalize-offsets.d.ts +2 -0
  38. package/dist/runtime/app/utils/transitions/normalizers/normalize-offsets.js +23 -0
  39. package/dist/runtime/app/utils/transitions/types.d.ts +31 -0
  40. package/dist/runtime/app/utils/transitions/types.js +0 -0
  41. package/dist/runtime/server/tsconfig.json +3 -0
  42. package/dist/types.d.mts +3 -0
  43. package/package.json +64 -0
package/README.md ADDED
@@ -0,0 +1,94 @@
1
+ # nanime
2
+
3
+ [![npm version][npm-version-src]][npm-version-href]
4
+ [![npm downloads][npm-downloads-src]][npm-downloads-href]
5
+ [![License][license-src]][license-href]
6
+ [![Nuxt][nuxt-src]][nuxt-href]
7
+
8
+ This module provides a set of SSR safe composables and components to make it easier
9
+ to use [AnimeJS](https://animejs.com/) in your Nuxt application.
10
+
11
+ - [✨  Release Notes](/CHANGELOG.md)
12
+ <!-- - [🏀 Online playground](https://stackblitz.com/github/your-org/my-module?file=playground%2Fapp.vue) -->
13
+ <!-- - [📖 &nbsp;Documentation](https://example.com) -->
14
+
15
+ ## Features
16
+
17
+ - Help to integrate animejs into your project without the need for much boilerplate codes
18
+ - SSR Safe components like `useAnimate`, `useWaapiAnimate`, ..etc
19
+ - Provides a set of transition components created with the `waapi` utility
20
+ - Doesn't include predefined animation settings other than `animejs` defaults
21
+ - Zero-config setup needed
22
+
23
+ ## Quick Setup
24
+
25
+ ### Installation with `nuxt module` command
26
+
27
+ Install the module to your Nuxt application with one command:
28
+
29
+ ```bash
30
+ npx nuxt module add nanime
31
+ ```
32
+
33
+ ### Manual install
34
+
35
+ ```bash
36
+ npm install nanime
37
+ ```
38
+
39
+ Then add the module to the `modules` section of your `nuxt.config.ts`:
40
+
41
+ ```ts
42
+ export default defineNuxtConfig({
43
+ modules: ['nanime'],
44
+ nanime: { ... },
45
+ })
46
+ ```
47
+
48
+ That's it! You can now use the module in your application
49
+
50
+
51
+ ## Contribution
52
+
53
+ <details>
54
+ <summary>Local development</summary>
55
+
56
+ ```bash
57
+ # Install dependencies
58
+ npm install
59
+
60
+ # Generate type stubs
61
+ npm run dev:prepare
62
+
63
+ # Develop with the playground
64
+ npm run dev
65
+
66
+ # Build the playground
67
+ npm run dev:build
68
+
69
+ # Run ESLint
70
+ npm run lint
71
+
72
+ # Run Vitest
73
+ npm run test
74
+ npm run test:watch
75
+
76
+ # Release new version
77
+ npm run release
78
+ ```
79
+
80
+ </details>
81
+
82
+
83
+ <!-- Badges -->
84
+ [npm-version-src]: https://img.shields.io/npm/v/my-module/latest.svg?style=flat&colorA=020420&colorB=00DC82
85
+ [npm-version-href]: https://npmjs.com/package/my-module
86
+
87
+ [npm-downloads-src]: https://img.shields.io/npm/dm/my-module.svg?style=flat&colorA=020420&colorB=00DC82
88
+ [npm-downloads-href]: https://npm.chart.dev/my-module
89
+
90
+ [license-src]: https://img.shields.io/npm/l/my-module.svg?style=flat&colorA=020420&colorB=00DC82
91
+ [license-href]: https://npmjs.com/package/my-module
92
+
93
+ [nuxt-src]: https://img.shields.io/badge/Nuxt-020420?logo=nuxt
94
+ [nuxt-href]: https://nuxt.com
@@ -0,0 +1,14 @@
1
+ import * as _nuxt_schema from '@nuxt/schema';
2
+
3
+ interface ModuleOptions {
4
+ /** Add composables for animejs */
5
+ composables: boolean;
6
+ /** Add custom transition components */
7
+ components: boolean;
8
+ /** Prefix for components */
9
+ prefix: string;
10
+ }
11
+ declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
12
+
13
+ export { _default as default };
14
+ export type { ModuleOptions };
@@ -0,0 +1,12 @@
1
+ {
2
+ "name": "nanime",
3
+ "configKey": "nanime",
4
+ "compatibility": {
5
+ "nuxt": ">=3.13.5 <5.0.0"
6
+ },
7
+ "version": "0.0.3",
8
+ "builder": {
9
+ "@nuxt/module-builder": "1.0.2",
10
+ "unbuild": "3.6.1"
11
+ }
12
+ }
@@ -0,0 +1,56 @@
1
+ import { defineNuxtModule, createResolver, addVitePlugin, addComponentsDir, addImportsDir } from '@nuxt/kit';
2
+
3
+ const __name = "nanime";
4
+ const __configKey = "nanime";
5
+ const module$1 = defineNuxtModule({
6
+ meta: {
7
+ name: __name,
8
+ configKey: __configKey,
9
+ compatibility: {
10
+ nuxt: ">=3.13.5 <5.0.0"
11
+ }
12
+ },
13
+ defaults: {
14
+ composables: true,
15
+ components: true,
16
+ prefix: "A"
17
+ },
18
+ setup(_options, _nuxt) {
19
+ const resolver = createResolver(import.meta.url);
20
+ addVitePlugin(() => ({
21
+ name: "__optimize-deps",
22
+ config(config) {
23
+ config.optimizeDeps ||= {};
24
+ config.optimizeDeps.include ||= [];
25
+ config.optimizeDeps.include.push(
26
+ "animejs",
27
+ "animejs/animatable",
28
+ "@vueuse/core",
29
+ "animejs/animation",
30
+ "animejs/utils",
31
+ "lodash-es",
32
+ "animejs/waapi",
33
+ "tailwind-merge",
34
+ "animejs/layout",
35
+ "animejs/text"
36
+ );
37
+ }
38
+ }));
39
+ if (_options.components) {
40
+ addComponentsDir({
41
+ prefix: _options.prefix,
42
+ path: resolver.resolve("./runtime/app/components"),
43
+ global: true
44
+ });
45
+ }
46
+ if (_options.composables) {
47
+ addImportsDir(resolver.resolve("./runtime/app/composables"));
48
+ }
49
+ _nuxt.options.alias[`#${__configKey}`] = resolver.resolve("./runtime/app/composables");
50
+ _nuxt.options.alias[`#${__configKey}/components`] = resolver.resolve("./runtime/app/components");
51
+ _nuxt.options.alias[`#${__configKey}/utils`] = resolver.resolve("./runtime/app/utils/index");
52
+ _nuxt.options.alias[`#${__configKey}/easings`] = resolver.resolve("./runtime/app/utils/easings");
53
+ }
54
+ });
55
+
56
+ export { module$1 as default };
@@ -0,0 +1,13 @@
1
+ declare var __VLS_7: {};
2
+ type __VLS_Slots = {} & {
3
+ default?: (props: typeof __VLS_7) => any;
4
+ };
5
+ declare const __VLS_base: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
6
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
7
+ declare const _default: typeof __VLS_export;
8
+ export default _default;
9
+ type __VLS_WithSlots<T, S> = T & {
10
+ new (): {
11
+ $slots: S;
12
+ };
13
+ };
@@ -0,0 +1,8 @@
1
+ <script setup lang="ts">
2
+ </script>
3
+
4
+ <template>
5
+ <Transition>
6
+ <slot />
7
+ </Transition>
8
+ </template>
@@ -0,0 +1,13 @@
1
+ declare var __VLS_7: {};
2
+ type __VLS_Slots = {} & {
3
+ default?: (props: typeof __VLS_7) => any;
4
+ };
5
+ declare const __VLS_base: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
6
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
7
+ declare const _default: typeof __VLS_export;
8
+ export default _default;
9
+ type __VLS_WithSlots<T, S> = T & {
10
+ new (): {
11
+ $slots: S;
12
+ };
13
+ };
@@ -0,0 +1,13 @@
1
+ declare var __VLS_14: {};
2
+ type __VLS_Slots = {} & {
3
+ default?: (props: typeof __VLS_14) => any;
4
+ };
5
+ declare const __VLS_base: import("vue").DefineSetupFnComponent<Record<string, any>, {}, {}, Record<string, any> & {}, import("vue").PublicProps>;
6
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
7
+ declare const _default: typeof __VLS_export;
8
+ export default _default;
9
+ type __VLS_WithSlots<T, S> = T & {
10
+ new (): {
11
+ $slots: S;
12
+ };
13
+ };
@@ -0,0 +1,145 @@
1
+ <script setup>
2
+ import { TransitionGroup, Transition } from "vue";
3
+ import { isStandardEase, isWaapiEase } from "./types";
4
+ import { animate, utils, waapi } from "animejs";
5
+ import { nextTick, unref, useAnimeLayout, useTemplateRef, computed } from "#imports";
6
+ import { normalizeAxis, normalizeDuration, normalizeOffset } from "../../utils/transitions/normalizers";
7
+ const props = defineProps({
8
+ duration: { type: [Number, Array, Object], required: false, default: () => ({
9
+ enter: 300,
10
+ leave: 300
11
+ }) },
12
+ delay: { type: [Number, Array, Object], required: false },
13
+ noOpacity: { type: Boolean, required: false, default: false },
14
+ tag: { type: null, required: false, default: "div" },
15
+ group: { type: Boolean, required: false, skipCheck: true },
16
+ useWaapi: { type: Boolean, required: false, default: true },
17
+ ease: { type: null, required: false, default: "out" },
18
+ layoutOptions: { type: null, required: false },
19
+ animateOptions: { type: null, required: false },
20
+ mode: { type: null, required: false, default: "out-in" },
21
+ axis: { type: String, required: false },
22
+ offset: { type: null, required: false, default: "-20%" }
23
+ });
24
+ const delays = computed(() => normalizeDuration(props.delay));
25
+ const durations = computed(() => normalizeDuration(props.duration));
26
+ const offsets = computed(() => normalizeOffset(props.offset));
27
+ const axis = computed(() => normalizeAxis(props.axis));
28
+ const isGrouped = computed(() => props.group ?? false);
29
+ const groupWrapper = useTemplateRef("group-wrapper");
30
+ const groupWrapperRef = computed(() => isGrouped.value ? unref(groupWrapper) : null);
31
+ const layoutOptions = computed(() => {
32
+ const ease = isStandardEase(props) ? props.ease : void 0;
33
+ const easeString = typeof ease === "string" ? ease : void 0;
34
+ const layoutOptions2 = "layoutOptions" in props && props.layoutOptions;
35
+ return {
36
+ ...layoutOptions2,
37
+ enterFrom: {
38
+ delay: delays.value.enter,
39
+ duration: durations.value.enter,
40
+ ...axis.value.enter === "y" && { transform: `translateY(${offsets.value.enter}) scale(0.95)` },
41
+ ...axis.value.enter === "x" && { transform: `translateX(${offsets.value.enter}) scale(0.95)` },
42
+ ...!props.noOpacity && { opacity: 0 },
43
+ ...easeString && { ease: easeString }
44
+ },
45
+ leaveTo: {
46
+ delay: delays.value.leave,
47
+ duration: durations.value.leave,
48
+ ...axis.value.leave === "y" && { transform: `translateY(${offsets.value.leave}) scale(0.95)` },
49
+ ...axis.value.leave === "x" && { transform: `translateX(${offsets.value.leave}) scale(0.95)` },
50
+ ...!props.noOpacity && { opacity: 0 },
51
+ ...easeString && { ease: easeString }
52
+ }
53
+ };
54
+ });
55
+ const layoutAnimation = useAnimeLayout(groupWrapperRef, layoutOptions);
56
+ const onChangeComplete = (callback = () => {
57
+ }) => {
58
+ layoutAnimation.animate(props.animateOptions, () => {
59
+ callback();
60
+ nextTick(() => {
61
+ layoutAnimation.revert();
62
+ });
63
+ });
64
+ };
65
+ function onEnter(el, done) {
66
+ const sharedEnterOptions = {
67
+ delay: delays.value.enter,
68
+ duration: durations.value.enter
69
+ };
70
+ if (props.useWaapi && !props.group) {
71
+ const ease = isWaapiEase(props) ? props.ease : void 0;
72
+ waapi.animate(el, {
73
+ ...sharedEnterOptions,
74
+ ...axis.value.enter === "y" && { y: { from: offsets.value.enter } },
75
+ ...axis.value.enter === "x" && { x: { from: offsets.value.enter } },
76
+ ...!props.noOpacity && { opacity: { from: 0 } },
77
+ ...ease && { ease },
78
+ onComplete: done
79
+ });
80
+ } else if (!props.group) {
81
+ const ease = isStandardEase(props) ? props.ease : void 0;
82
+ utils.set(el, {
83
+ ...axis.value.enter === "y" && { y: offsets.value.enter },
84
+ ...axis.value.enter === "x" && { x: offsets.value.enter },
85
+ ...!props.noOpacity && { opacity: 0 }
86
+ });
87
+ animate(el, {
88
+ ...sharedEnterOptions,
89
+ ...axis.value.enter === "y" && { y: { to: 0 } },
90
+ ...axis.value.enter === "x" && { x: { to: 0 } },
91
+ ...!props.noOpacity && { opacity: { to: 1 } },
92
+ ...ease && { ease },
93
+ onComplete: done
94
+ });
95
+ } else {
96
+ done();
97
+ }
98
+ }
99
+ function onLeave(el, done) {
100
+ const sharedLeaveOptions = {
101
+ delay: delays.value.leave,
102
+ duration: durations.value.leave,
103
+ ...axis.value.leave === "y" && { y: { to: offsets.value.leave } },
104
+ ...axis.value.leave === "x" && { x: { to: offsets.value.leave } },
105
+ ...!props.noOpacity && { opacity: { to: 0 } }
106
+ };
107
+ if (props.useWaapi && !props.group) {
108
+ const ease = isWaapiEase(props) ? props.ease : void 0;
109
+ waapi.animate(el, {
110
+ ...sharedLeaveOptions,
111
+ ...ease && { ease },
112
+ onComplete: done
113
+ });
114
+ } else if (!props.group) {
115
+ const ease = isStandardEase(props) ? props.ease : void 0;
116
+ animate(el, {
117
+ ...sharedLeaveOptions,
118
+ ...ease && { ease },
119
+ onComplete: done
120
+ });
121
+ } else {
122
+ el.style.display = "none";
123
+ onChangeComplete(() => {
124
+ el.style.display = "";
125
+ done();
126
+ });
127
+ }
128
+ }
129
+ </script>
130
+
131
+ <template>
132
+ <component
133
+ :is="isGrouped ? TransitionGroup : Transition"
134
+ :ref="isGrouped ? 'group-wrapper' : void 0"
135
+ :mode="!isGrouped ? props.mode : void 0"
136
+ :tag="isGrouped ? props.tag : void 0"
137
+ @before-enter="isGrouped && layoutAnimation.record()"
138
+ @enter="onEnter"
139
+ @after-enter="() => onChangeComplete()"
140
+ @before-leave="isGrouped && layoutAnimation.record()"
141
+ @leave="onLeave"
142
+ >
143
+ <slot />
144
+ </component>
145
+ </template>
@@ -0,0 +1,13 @@
1
+ declare var __VLS_14: {};
2
+ type __VLS_Slots = {} & {
3
+ default?: (props: typeof __VLS_14) => any;
4
+ };
5
+ declare const __VLS_base: import("vue").DefineSetupFnComponent<Record<string, any>, {}, {}, Record<string, any> & {}, import("vue").PublicProps>;
6
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
7
+ declare const _default: typeof __VLS_export;
8
+ export default _default;
9
+ type __VLS_WithSlots<T, S> = T & {
10
+ new (): {
11
+ $slots: S;
12
+ };
13
+ };
@@ -0,0 +1,44 @@
1
+ import type { AutoLayoutParams, EasingParam, LayoutAnimationParams, WAAPIEasingParam } from 'animejs';
2
+ import type { VueInstance } from '@vueuse/core';
3
+ import type { BaseTransitionProps } from 'vue';
4
+ import type { TransitionDurationInput } from '../../utils/transitions/types.js';
5
+ type Prettify<T> = {
6
+ [K in keyof T]: T[K];
7
+ } & {};
8
+ export type SharedTransitionProps = {
9
+ duration?: TransitionDurationInput;
10
+ delay?: TransitionDurationInput;
11
+ noOpacity?: boolean;
12
+ tag?: keyof HTMLElementTagNameMap | HTMLElement | VueInstance;
13
+ } & ({
14
+ /**
15
+ * Constraint 1 & 2:
16
+ * When group is true, useWaapi MUST be false.
17
+ * Layout/Animate options are available.
18
+ */
19
+ group: true;
20
+ useWaapi?: false;
21
+ ease?: EasingParam;
22
+ layoutOptions?: Prettify<Omit<AutoLayoutParams, 'leaveTo' | 'enterFrom'>>;
23
+ animateOptions?: LayoutAnimationParams;
24
+ mode?: never;
25
+ } | {
26
+ /**
27
+ * When group is false/undefined:
28
+ * useWaapi can be a boolean variable.
29
+ * Layout/Animate options are strictly disabled.
30
+ */
31
+ group?: false | undefined;
32
+ useWaapi?: boolean;
33
+ ease?: WAAPIEasingParam | EasingParam;
34
+ mode?: BaseTransitionProps['mode'];
35
+ layoutOptions?: never;
36
+ animateOptions?: never;
37
+ });
38
+ export declare const isWaapiEase: (properties: SharedTransitionProps) => properties is SharedTransitionProps & {
39
+ ease?: WAAPIEasingParam;
40
+ };
41
+ export declare const isStandardEase: (properties: SharedTransitionProps) => properties is SharedTransitionProps & {
42
+ ease?: EasingParam;
43
+ };
44
+ export {};
@@ -0,0 +1,6 @@
1
+ export const isWaapiEase = (properties) => {
2
+ return properties.useWaapi === true && !properties.group;
3
+ };
4
+ export const isStandardEase = (properties) => {
5
+ return properties.useWaapi === false || properties.group === true;
6
+ };
@@ -0,0 +1,4 @@
1
+ import { type MaybeRefOrGetter } from '#imports';
2
+ import { normalizeAnimeTarget } from '../utils/normalize-targets.js';
3
+ import type { AnimatableObject, AnimatableParams } from 'animejs';
4
+ export declare function useAnimatable(target: Parameters<typeof normalizeAnimeTarget>[0], options?: MaybeRefOrGetter<AnimatableParams>): AnimatableObject;
@@ -0,0 +1,21 @@
1
+ import { createAnimatable } from "animejs/animatable";
2
+ import { tryOnScopeDispose, useMounted } from "@vueuse/core";
3
+ import { shallowReactive, toValue, watchEffect } from "#imports";
4
+ import { normalizeAnimeTarget } from "../utils/normalize-targets.js";
5
+ export function useAnimatable(target, options) {
6
+ const mounted = useMounted();
7
+ const animatable = shallowReactive(createAnimatable({}, {}));
8
+ let oldTarget;
9
+ watchEffect(() => {
10
+ if (!mounted.value) return;
11
+ const targets = normalizeAnimeTarget(target);
12
+ if (oldTarget === targets) return;
13
+ oldTarget = targets;
14
+ const newAnimatable = createAnimatable(targets, toValue(options) || {});
15
+ Object.assign(animatable, newAnimatable);
16
+ });
17
+ tryOnScopeDispose(() => {
18
+ animatable.revert();
19
+ });
20
+ return animatable;
21
+ }
@@ -0,0 +1,5 @@
1
+ import { type MaybeRefOrGetter } from '#imports';
2
+ import { normalizeAnimeTarget } from '../utils/normalize-targets.js';
3
+ import type { AnimationParams } from 'animejs';
4
+ import { type JSAnimation } from 'animejs/animation';
5
+ export declare function useAnimate(target: Parameters<typeof normalizeAnimeTarget>[0], options?: MaybeRefOrGetter<AnimationParams>): JSAnimation;
@@ -0,0 +1,22 @@
1
+ import { toReactive, tryOnScopeDispose, useMounted } from "@vueuse/core";
2
+ import { shallowRef, toValue, watchEffect } from "#imports";
3
+ import { normalizeAnimeTarget } from "../utils/normalize-targets.js";
4
+ import { animate } from "animejs/animation";
5
+ export function useAnimate(target, options) {
6
+ const mounted = useMounted();
7
+ const animation = shallowRef(animate({}, {}));
8
+ let oldTarget;
9
+ watchEffect(() => {
10
+ if (!mounted.value) return;
11
+ const targets = normalizeAnimeTarget(target);
12
+ if (oldTarget === targets) return;
13
+ if (animation.value) animation.value.revert();
14
+ oldTarget = targets;
15
+ const newAnimation = animate(targets, toValue(options) || {});
16
+ animation.value = newAnimation;
17
+ });
18
+ tryOnScopeDispose(() => {
19
+ animation.value?.revert();
20
+ });
21
+ return toReactive(animation);
22
+ }
@@ -0,0 +1,9 @@
1
+ import { type MaybeRef, type MaybeRefOrGetter } from '#imports';
2
+ import { type AutoLayoutParams, type LayoutAnimationParams } from 'animejs/layout';
3
+ import { normalizeLayoutTarget } from '../utils/normalize-targets.js';
4
+ export declare function useAnimeLayout(target: MaybeRef<Parameters<typeof normalizeLayoutTarget>[0]>, options?: MaybeRefOrGetter<AutoLayoutParams>): {
5
+ properties: import("vue").ComputedRef<import("../utils/extract-props.js").NonFunctionProperties<import("animejs").AutoLayout> | undefined>;
6
+ record: () => import("animejs").AutoLayout | undefined;
7
+ revert: () => import("animejs").AutoLayout | undefined;
8
+ animate: (options?: LayoutAnimationParams, cb?: () => void) => void | import("animejs").Timeline;
9
+ };
@@ -0,0 +1,34 @@
1
+ import { computed, shallowRef, toValue, watchEffect } from "#imports";
2
+ import { createLayout } from "animejs/layout";
3
+ import { normalizeLayoutTarget } from "../utils/normalize-targets.js";
4
+ import { extractNonFunctionProperties } from "../utils/extract-props.js";
5
+ import { tryOnScopeDispose, useMounted } from "@vueuse/core";
6
+ export function useAnimeLayout(target, options) {
7
+ const mounted = useMounted();
8
+ const layout = shallowRef(null);
9
+ watchEffect(() => {
10
+ if (!mounted.value) return;
11
+ const wrapper = normalizeLayoutTarget(toValue(target));
12
+ if (!wrapper) return;
13
+ const newLayout = createLayout(wrapper, toValue(options) || {});
14
+ layout.value = newLayout;
15
+ });
16
+ tryOnScopeDispose(() => {
17
+ layout.value?.revert();
18
+ layout.value = null;
19
+ });
20
+ return {
21
+ properties: computed(() => layout.value ? extractNonFunctionProperties(layout.value) : void 0),
22
+ record: () => layout.value?.record(),
23
+ revert: () => layout.value?.revert(),
24
+ animate: (options2, cb) => {
25
+ const animation = layout.value?.animate(options2 || {});
26
+ if (!animation && cb) return cb();
27
+ if (!animation) return;
28
+ animation.play();
29
+ animation.then(() => cb?.());
30
+ if (animation.completed) return cb?.();
31
+ return animation;
32
+ }
33
+ };
34
+ }
@@ -0,0 +1,50 @@
1
+ import { type MaybeRef, type MaybeRefOrGetter } from '#imports';
2
+ import { splitText, type TextSplitter } from 'animejs/text';
3
+ import { normalizeSplitTextTarget } from '../utils/normalize-targets.js';
4
+ export declare function useSplitText(target: MaybeRef<Parameters<typeof normalizeSplitTextTarget>[0]>, parameters?: MaybeRefOrGetter<Parameters<typeof splitText>[1]>): {
5
+ lines: import("vue").ShallowRef<HTMLElement[], HTMLElement[]>;
6
+ words: import("vue").ShallowRef<HTMLElement[], HTMLElement[]>;
7
+ chars: import("vue").ShallowRef<HTMLElement[], HTMLElement[]>;
8
+ properties: import("vue").ComputedRef<import("../utils/extract-props.js").NonFunctionProperties<{
9
+ debug: boolean;
10
+ includeSpaces: boolean;
11
+ accessible: boolean;
12
+ linesOnly: boolean;
13
+ lineTemplate: string | false | import("animejs").SplitFunctionValue;
14
+ wordTemplate: string | false | import("animejs").SplitFunctionValue;
15
+ charTemplate: string | false | import("animejs").SplitFunctionValue;
16
+ $target: HTMLElement;
17
+ html: string;
18
+ lines: any[];
19
+ words: any[];
20
+ chars: any[];
21
+ effects: any[];
22
+ effectsCleanups: any[];
23
+ cache: string;
24
+ ready: boolean;
25
+ width: number;
26
+ resizeTimeout: {
27
+ close: () => NodeJS.Timeout;
28
+ hasRef: () => boolean;
29
+ ref: () => NodeJS.Timeout;
30
+ refresh: () => NodeJS.Timeout;
31
+ unref: () => NodeJS.Timeout;
32
+ _onTimeout: (...args: any[]) => void;
33
+ [Symbol.toPrimitive]: () => number;
34
+ [Symbol.dispose]: () => void;
35
+ };
36
+ resizeObserver: {
37
+ disconnect: () => void;
38
+ observe: (target: Element, options?: ResizeObserverOptions) => void;
39
+ unobserve: (target: Element) => void;
40
+ };
41
+ addEffect: (effect: (...args: any[]) => import("animejs").Tickable | (() => void)) => void | TextSplitter;
42
+ revert: () => TextSplitter;
43
+ splitNode: (node: Node) => void;
44
+ split: (clearCache?: boolean) => TextSplitter;
45
+ refresh: () => void;
46
+ }> | undefined>;
47
+ revert: () => TextSplitter | undefined;
48
+ split: () => TextSplitter | undefined;
49
+ refresh: () => void | undefined;
50
+ };
@@ -0,0 +1,48 @@
1
+ import { computed, nextTick, ref, shallowRef, toValue, watchEffect } from "#imports";
2
+ import { splitText } from "animejs/text";
3
+ import { normalizeSplitTextTarget } from "../utils/normalize-targets.js";
4
+ import { extractNonFunctionProperties } from "../utils/extract-props.js";
5
+ import { tryOnScopeDispose, useMounted } from "@vueuse/core";
6
+ export function useSplitText(target, parameters) {
7
+ const mounted = useMounted();
8
+ const splitter = ref(null);
9
+ const lines = shallowRef([]);
10
+ const words = shallowRef([]);
11
+ const chars = shallowRef([]);
12
+ const syncArrays = () => {
13
+ if (!splitter.value) return;
14
+ lines.value = [...splitter.value.lines];
15
+ words.value = [...splitter.value.words];
16
+ chars.value = [...splitter.value.chars];
17
+ };
18
+ watchEffect(() => {
19
+ if (!mounted.value) return;
20
+ const element = normalizeSplitTextTarget(toValue(target));
21
+ if (!element) return;
22
+ if (splitter.value) splitter.value.revert();
23
+ const newSplitter = splitText(element, toValue(parameters));
24
+ splitter.value = newSplitter;
25
+ newSplitter.addEffect(() => {
26
+ syncArrays();
27
+ return () => {
28
+ };
29
+ });
30
+ nextTick(syncArrays);
31
+ });
32
+ tryOnScopeDispose(() => {
33
+ splitter.value?.revert();
34
+ splitter.value = null;
35
+ lines.value = [];
36
+ words.value = [];
37
+ chars.value = [];
38
+ });
39
+ return {
40
+ lines,
41
+ words,
42
+ chars,
43
+ properties: computed(() => splitter.value ? extractNonFunctionProperties(splitter.value) : void 0),
44
+ revert: () => splitter.value?.revert(),
45
+ split: () => splitter.value?.split(),
46
+ refresh: () => splitter.value?.refresh()
47
+ };
48
+ }
@@ -0,0 +1,5 @@
1
+ import { type MaybeRefOrGetter } from '#imports';
2
+ import type { WAAPIAnimationParams } from 'animejs';
3
+ import { normalizeWaapiAnimeTarget } from '../utils/normalize-targets.js';
4
+ import { type WAAPIAnimation } from 'animejs/waapi';
5
+ export declare function useWaapiAnimate(target: Parameters<typeof normalizeWaapiAnimeTarget>[0], options?: MaybeRefOrGetter<WAAPIAnimationParams>): WAAPIAnimation;
@@ -0,0 +1,19 @@
1
+ import { toReactive, tryOnScopeDispose, useMounted } from "@vueuse/core";
2
+ import { shallowRef, toValue, watchEffect } from "#imports";
3
+ import { normalizeWaapiAnimeTarget } from "../utils/normalize-targets.js";
4
+ import { waapi } from "animejs/waapi";
5
+ export function useWaapiAnimate(target, options) {
6
+ const mounted = useMounted();
7
+ const animation = shallowRef(waapi.animate([], {}));
8
+ watchEffect(() => {
9
+ const targets = normalizeWaapiAnimeTarget(target);
10
+ if (!mounted.value || !targets) return;
11
+ if (animation.value) animation.value.revert();
12
+ const newAnimation = waapi.animate(targets, toValue(options) || {});
13
+ animation.value = newAnimation;
14
+ });
15
+ tryOnScopeDispose(() => {
16
+ animation.value?.revert();
17
+ });
18
+ return toReactive(animation);
19
+ }
@@ -0,0 +1 @@
1
+ export * from 'animejs/easings';
@@ -0,0 +1 @@
1
+ export * from "animejs/easings";
@@ -0,0 +1,6 @@
1
+ type NonFunctionKeys<T> = {
2
+ [K in keyof T]: T[K] extends Function ? never : K;
3
+ }[keyof T];
4
+ export type NonFunctionProperties<T> = Pick<T, NonFunctionKeys<T>>;
5
+ export declare function extractNonFunctionProperties<T extends object>(obj: T): NonFunctionProperties<T>;
6
+ export {};
@@ -0,0 +1,13 @@
1
+ export function extractNonFunctionProperties(obj) {
2
+ if (!obj || typeof obj !== "object") return {};
3
+ const result = {};
4
+ for (const key in obj) {
5
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
6
+ const value = obj[key];
7
+ if (typeof value !== "function") {
8
+ result[key] = value;
9
+ }
10
+ }
11
+ }
12
+ return result;
13
+ }
@@ -0,0 +1 @@
1
+ export * from 'animejs/utils';
@@ -0,0 +1 @@
1
+ export * from "animejs/utils";
@@ -0,0 +1,14 @@
1
+ import { type MaybeRef } from '#imports';
2
+ import type { MaybeElementRef, VueInstance } from '@vueuse/core';
3
+ import type { TargetsParam, DOMTargetsParam, DOMTargetSelector } from 'animejs';
4
+ type WaapiElementTargets = VueInstance | HTMLElement | HTMLElement[] | SVGElement | SVGElement[] | NodeList | string | null;
5
+ type WaapiTargets = MaybeRef<WaapiElementTargets> | MaybeRef<WaapiElementTargets>[];
6
+ export declare function normalizeWaapiAnimeTarget(target: WaapiTargets): DOMTargetsParam | null;
7
+ type AnimeTargets = TargetsParam | MaybeElementRef | MaybeElementRef[];
8
+ export declare function normalizeAnimeTarget(target: AnimeTargets): TargetsParam;
9
+ type AnimeLayoutTargets = DOMTargetSelector | MaybeElementRef<HTMLElement | VueInstance> | null | undefined;
10
+ export declare function normalizeLayoutTarget(target: AnimeLayoutTargets): DOMTargetSelector | null;
11
+ type SplitTargets = HTMLElement | string;
12
+ type SplitTextTargets = SplitTargets | MaybeElementRef<HTMLElement> | null | undefined | MaybeElementRef<VueInstance>;
13
+ export declare function normalizeSplitTextTarget(target: SplitTextTargets): SplitTargets | null;
14
+ export {};
@@ -0,0 +1,44 @@
1
+ import { isReactive, toValue } from "#imports";
2
+ function isVueInstance(value) {
3
+ return value !== null && typeof value === "object" && "$el" in value;
4
+ }
5
+ export function normalizeWaapiAnimeTarget(target) {
6
+ const resolved = toValue(target);
7
+ if (!resolved) return null;
8
+ if (isVueInstance(resolved)) {
9
+ return resolved.$el;
10
+ }
11
+ if (Array.isArray(resolved)) {
12
+ const targets = resolved.map((t) => normalizeWaapiAnimeTarget(t)).filter((t) => t !== null).flat();
13
+ return targets.length ? targets : null;
14
+ }
15
+ return resolved;
16
+ }
17
+ export function normalizeAnimeTarget(target) {
18
+ const resolved = isReactive(target) ? target : toValue(target);
19
+ if (!resolved) return [];
20
+ if (isVueInstance(resolved)) {
21
+ return resolved.$el;
22
+ }
23
+ if (Array.isArray(resolved)) {
24
+ const targets = resolved.map((t) => normalizeAnimeTarget(t)).filter((t) => t !== null && (Array.isArray(t) ? t.length > 0 : true)).flat();
25
+ return targets;
26
+ }
27
+ return resolved;
28
+ }
29
+ export function normalizeLayoutTarget(target) {
30
+ const resolved = toValue(target);
31
+ if (!resolved) return null;
32
+ if (isVueInstance(resolved)) {
33
+ return resolved.$el;
34
+ }
35
+ return resolved;
36
+ }
37
+ export function normalizeSplitTextTarget(target) {
38
+ const resolved = toValue(target);
39
+ if (!resolved) return null;
40
+ if (isVueInstance(resolved)) {
41
+ return resolved.$el;
42
+ }
43
+ return resolved;
44
+ }
@@ -0,0 +1,3 @@
1
+ export { normalizeAxis } from './normalize-axis.js';
2
+ export { normalizeDuration } from './normalize-duration.js';
3
+ export { normalizeOffset } from './normalize-offsets.js';
@@ -0,0 +1,3 @@
1
+ export { normalizeAxis } from "./normalize-axis.js";
2
+ export { normalizeDuration } from "./normalize-duration.js";
3
+ export { normalizeOffset } from "./normalize-offsets.js";
@@ -0,0 +1,2 @@
1
+ import type { AxisInput, AxisOutput } from '../types.js';
2
+ export declare function normalizeAxis(axis?: AxisInput): AxisOutput;
@@ -0,0 +1,12 @@
1
+ export function normalizeAxis(axis) {
2
+ if (axis === void 0) {
3
+ return { enter: "y", leave: "y" };
4
+ }
5
+ if (typeof axis === "string") {
6
+ return { enter: axis, leave: axis };
7
+ }
8
+ if (Array.isArray(axis)) {
9
+ return { enter: axis[0], leave: axis[1] };
10
+ }
11
+ return axis;
12
+ }
@@ -0,0 +1,2 @@
1
+ import type { TransitionDurationInput, DurationOutput } from '../types.js';
2
+ export declare function normalizeDuration(duration?: TransitionDurationInput): DurationOutput;
@@ -0,0 +1,12 @@
1
+ export function normalizeDuration(duration) {
2
+ if (duration === void 0) {
3
+ return { enter: 300, leave: 300 };
4
+ }
5
+ if (typeof duration === "number") {
6
+ return { enter: duration, leave: duration };
7
+ }
8
+ if (Array.isArray(duration)) {
9
+ return { enter: duration[0], leave: duration[1] };
10
+ }
11
+ return duration;
12
+ }
@@ -0,0 +1,2 @@
1
+ import type { OffsetOutput, TransitionOffsetInput } from '../types.js';
2
+ export declare function normalizeOffset(offset?: TransitionOffsetInput): OffsetOutput;
@@ -0,0 +1,23 @@
1
+ function validateOffsetValue(value) {
2
+ if (typeof value !== "string") return;
3
+ if (value.endsWith("px") || value.endsWith("%")) return;
4
+ if (/^-?\d+$/.test(value)) return;
5
+ throw new Error(`Invalid offset value: "${value}". Offset strings must end with "px" or "%", or be a plain number.`);
6
+ }
7
+ export function normalizeOffset(offset) {
8
+ if (offset === void 0) {
9
+ return { enter: 0, leave: 0 };
10
+ }
11
+ if (typeof offset === "number" || typeof offset === "string") {
12
+ validateOffsetValue(offset);
13
+ return { enter: offset, leave: offset };
14
+ }
15
+ if (Array.isArray(offset)) {
16
+ validateOffsetValue(offset[0]);
17
+ validateOffsetValue(offset[1]);
18
+ return { enter: offset[0], leave: offset[1] };
19
+ }
20
+ validateOffsetValue(offset.enter);
21
+ validateOffsetValue(offset.leave);
22
+ return offset;
23
+ }
@@ -0,0 +1,31 @@
1
+ /** Duration types */
2
+ export type DurationOutput = {
3
+ enter: number;
4
+ leave: number;
5
+ };
6
+ export type TransitionDurationInput = number | [number, number] | {
7
+ enter: number;
8
+ leave: number;
9
+ };
10
+ /** Axis types */
11
+ type Axis = 'x' | 'y';
12
+ export type AxisInput = Axis | [Axis, Axis] | {
13
+ enter: Axis;
14
+ leave: Axis;
15
+ };
16
+ export type AxisOutput = {
17
+ enter: Axis;
18
+ leave: Axis;
19
+ };
20
+ /** Offset types */
21
+ type PropertyValue = 'px' | '%';
22
+ type OffsetInput = `${number}` | `-${number}` | `${number}${PropertyValue}` | `-${number}${PropertyValue}`;
23
+ export type OffsetOutput = {
24
+ enter: OffsetInput | number;
25
+ leave: OffsetInput | number;
26
+ };
27
+ export type TransitionOffsetInput = OffsetInput | number | [OffsetInput | number, OffsetInput | number] | {
28
+ enter: OffsetInput | number;
29
+ leave: OffsetInput | number;
30
+ };
31
+ export {};
File without changes
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": "../../../.nuxt/tsconfig.server.json",
3
+ }
@@ -0,0 +1,3 @@
1
+ export { default } from './module.mjs'
2
+
3
+ export { type ModuleOptions } from './module.mjs'
package/package.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "nanime",
3
+ "version": "0.0.3",
4
+ "description": "Nuxt module for animejs integration and transitions",
5
+ "repository": "https://github.com/astraldev/nanime",
6
+ "license": "MIT",
7
+ "type": "module",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/types.d.mts",
11
+ "import": "./dist/module.mjs"
12
+ }
13
+ },
14
+ "main": "./dist/module.mjs",
15
+ "typesVersions": {
16
+ "*": {
17
+ ".": [
18
+ "./dist/types.d.mts"
19
+ ]
20
+ }
21
+ },
22
+ "files": [
23
+ "dist"
24
+ ],
25
+ "scripts": {
26
+ "postinstall": "lefthook install",
27
+ "prepack": "nuxt-module-build build",
28
+ "dev": "npm run dev:prepare && nuxt dev playground",
29
+ "dev:build": "nuxt build playground",
30
+ "dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxt prepare playground",
31
+ "release": "npm run lint && npm run test && npm run prepack && changelogen --release && npm publish && git push --follow-tags",
32
+ "lint": "eslint .",
33
+ "test": "vitest run",
34
+ "test:watch": "vitest watch",
35
+ "test:types": "vue-tsc --noEmit && cd playground && vue-tsc --noEmit",
36
+ "clean": "rm -rf playground/.nuxt docs/.nuxt playground/.output docs/.output .nuxt"
37
+ },
38
+ "dependencies": {
39
+ "@vueuse/core": "^14.1.0",
40
+ "animejs": "^4.3.5",
41
+ "defu": "^6.1.4",
42
+ "vue": "^3.5.27"
43
+ },
44
+ "devDependencies": {
45
+ "@nuxt/devtools": "^3.1.1",
46
+ "@nuxt/eslint-config": "^1.13.0",
47
+ "@nuxt/kit": "^4.3.0",
48
+ "@nuxt/module-builder": "^1.0.2",
49
+ "@nuxt/schema": "^4.3.0",
50
+ "@nuxt/test-utils": "^3.23.0",
51
+ "@types/node": "latest",
52
+ "@vue/test-utils": "^2.4.6",
53
+ "@vueuse/nuxt": "14.1.0",
54
+ "changelogen": "^0.6.2",
55
+ "eslint": "^9.39.2",
56
+ "happy-dom": "^20.4.0",
57
+ "lefthook": "^2.0.16",
58
+ "nuxt": "^4.3.0",
59
+ "typescript": "~5.9.3",
60
+ "vitest": "^4.0.18",
61
+ "vue-tsc": "^3.2.4"
62
+ },
63
+ "packageManager": "pnpm@10.15.0+sha512.486ebc259d3e999a4e8691ce03b5cac4a71cbeca39372a9b762cb500cfdf0873e2cb16abe3d951b1ee2cf012503f027b98b6584e4df22524e0c7450d9ec7aa7b"
64
+ }