Skip to content

Commit 2d68275

Browse files
authored
Merge pull request #5 from holux-design/feat/vue
Vue 3 support
2 parents 060bb9e + 673ac26 commit 2d68275

File tree

4 files changed

+103
-75
lines changed

4 files changed

+103
-75
lines changed

src/module.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export default defineNuxtModule<ModuleOptions>({
3131
)
3232

3333
// Do not add the extension since the `.ts` will be transpiled to `.mjs` after `npm run prepack`
34-
addPlugin(resolver.resolve('./runtime/plugin'))
34+
addPlugin(resolver.resolve('./runtime/nuxt'))
3535

3636
if (
3737
(_nuxt.options.runtimeConfig.public.vgsap as any)?.composable != false

src/runtime/nuxt.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import gsap from 'gsap'
2+
import { vGsapDirective } from './plugin'
3+
import { defineNuxtPlugin, useRuntimeConfig } from '#app'
4+
5+
export default defineNuxtPlugin((nuxtApp) => {
6+
let resizeListener
7+
8+
nuxtApp.vueApp.directive(
9+
'gsap',
10+
vGsapDirective(
11+
'nuxt',
12+
useRuntimeConfig().public.vgsap ?? {},
13+
null,
14+
resizeListener,
15+
),
16+
)
17+
})

src/runtime/plugin.ts

Lines changed: 74 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import Draggable from 'gsap/Draggable'
2-
import TextPlugin from 'gsap/TextPlugin'
32
import { gsap, ScrollTrigger, ScrollToPlugin } from 'gsap/all'
3+
import TextPlugin from 'gsap/TextPlugin'
44
import { uuidv4 } from './utils/utils'
55
import { entrancePresets } from './utils/entrance-presets'
66
import type { Preset } from './types/Preset'
7-
import { defineNuxtPlugin, useRuntimeConfig } from '#app'
7+
8+
gsap.registerPlugin(ScrollTrigger, ScrollToPlugin, Draggable, TextPlugin)
89

910
type ANIMATION_TYPES = 'from' | 'to' | 'set' | 'fromTo' | 'call'
1011

@@ -30,89 +31,88 @@ type TIMELINE_OPTIONS = {
3031

3132
const globalTimelines = {}
3233

33-
export default defineNuxtPlugin((nuxtApp) => {
34-
const configOptions = useRuntimeConfig().public.vgsap
35-
const gsapContext: gsap.Context = gsap.context(() => {})
36-
37-
gsap.registerPlugin(ScrollTrigger, ScrollToPlugin, Draggable, TextPlugin)
38-
let resizeListener
39-
40-
nuxtApp.vueApp.directive('gsap', {
41-
getSSRProps: (binding) => {
42-
binding = loadPreset(binding, configOptions)
34+
export const vGsapDirective = (
35+
appType: 'nuxt' | 'vue',
36+
configOptions,
37+
gsapContext,
38+
resizeListener,
39+
) => ({
40+
getSSRProps: (binding) => {
41+
binding = loadPreset(binding, configOptions)
42+
43+
return {
44+
'style': {
45+
opacity: binding.modifiers.fromInvisible ? '0' : '1',
46+
},
47+
'data-gsap-id': uuidv4(),
48+
}
49+
},
4350

44-
return {
45-
'style': {
46-
opacity: binding.modifiers.fromInvisible ? '0' : '1',
47-
},
48-
'data-gsap-id': uuidv4(),
49-
}
50-
},
51+
beforeMount(el, binding, vnode) {
52+
if (appType == 'vue') el.dataset.gsapId = uuidv4()
53+
if (!gsapContext) gsapContext = gsap.context(() => {})
5154

52-
beforeMount(el, binding, vnode) {
53-
binding = loadPreset(binding, configOptions)
55+
binding = loadPreset(binding, configOptions)
5456

55-
// .timeline => Prepare before children get mounted
56-
// Add data-gsap-order to children for animation steps (otherwise children get mounted first and then bottom-up)
57-
if (binding.modifiers.timeline) {
58-
if (!timelineShouldBeActive(binding, configOptions)) return
59-
assignChildrenOrderAttributesFor(vnode)
57+
// .timeline => Prepare before children get mounted
58+
// Add data-gsap-order to children for animation steps (otherwise children get mounted first and then bottom-up)
59+
if (binding.modifiers.timeline) {
60+
if (!timelineShouldBeActive(binding, configOptions)) return
61+
assignChildrenOrderAttributesFor(vnode)
6062

61-
globalTimelines[el.dataset.gsapId] = prepareTimeline(
62-
el,
63-
binding,
64-
configOptions,
65-
)
66-
el.dataset.gsapTimeline = true
63+
globalTimelines[el.dataset.gsapId] = prepareTimeline(
64+
el,
65+
binding,
66+
configOptions,
67+
)
68+
el.dataset.gsapTimeline = true
6769

68-
gsapContext.add(() => globalTimelines[el.dataset.gsapId])
69-
}
70-
},
70+
gsapContext.add(() => globalTimelines[el.dataset.gsapId])
71+
}
72+
},
7173

72-
mounted(el, binding) {
73-
let timeline
74+
mounted(el, binding) {
75+
let timeline
7476

75-
// Refresh scrollTrigger from .timeline after all has mounted
76-
if (binding.modifiers.timeline) {
77-
globalTimelines[el.dataset.gsapId]?.scrollTrigger?.refresh()
78-
ScrollTrigger?.normalizeScroll(true)
79-
}
80-
else {
81-
// All directives that are not .timeline
77+
// Refresh scrollTrigger from .timeline after all has mounted
78+
if (binding.modifiers.timeline) {
79+
globalTimelines[el.dataset.gsapId]?.scrollTrigger?.refresh()
80+
ScrollTrigger?.normalizeScroll(true)
81+
}
82+
else {
83+
// All directives that are not .timeline
8284

83-
if (binding.modifiers.magnetic) return addMagneticEffect(el, binding)
85+
if (binding.modifiers.magnetic) return addMagneticEffect(el, binding)
8486

85-
if (timelineShouldBeActive(binding, configOptions))
86-
timeline = prepareTimeline(el, binding, configOptions)
87+
if (timelineShouldBeActive(binding, configOptions))
88+
timeline = prepareTimeline(el, binding, configOptions)
8789

88-
if (binding.modifiers.add) {
89-
let order
90-
= getValueFromModifier(binding, 'order-')
91-
|| getValueFromModifier(binding, 'suggestedOrder-')
92-
if (binding.modifiers.withPrevious) order = '<'
90+
if (binding.modifiers.add) {
91+
let order
92+
= getValueFromModifier(binding, 'order-')
93+
|| getValueFromModifier(binding, 'suggestedOrder-')
94+
if (binding.modifiers.withPrevious) order = '<'
9395

94-
if (!el.closest(`[data-gsap-timeline="true"]`)?.dataset?.gsapId)
95-
return
96-
globalTimelines[
97-
el.closest(`[data-gsap-timeline="true"]`).dataset.gsapId
98-
]?.add(timeline, order)
99-
}
96+
if (!el.closest(`[data-gsap-timeline="true"]`)?.dataset?.gsapId) return
97+
globalTimelines[
98+
el.closest(`[data-gsap-timeline="true"]`).dataset.gsapId
99+
]?.add(timeline, order)
100100
}
101+
}
101102

102-
gsapContext.add(() => timeline)
103-
resizeListener = window.addEventListener('resize', () => {
104-
if (!timelineShouldBeActive(binding, configOptions) && !!timeline)
105-
timeline = resetAndKillTimeline(timeline)
106-
if (timelineShouldBeActive(binding, configOptions) && !timeline)
107-
timeline = prepareTimeline(el, binding, configOptions)
108-
})
109-
},
110-
111-
unmounted() {
112-
gsapContext.revert()
113-
removeEventListener('resize', resizeListener)
114-
},
115-
})
103+
gsapContext.add(() => timeline)
104+
resizeListener = window.addEventListener('resize', () => {
105+
if (!timelineShouldBeActive(binding, configOptions) && !!timeline)
106+
timeline = resetAndKillTimeline(timeline)
107+
if (timelineShouldBeActive(binding, configOptions) && !timeline)
108+
timeline = prepareTimeline(el, binding, configOptions)
109+
})
110+
},
111+
112+
unmounted() {
113+
gsapContext.revert()
114+
removeEventListener('resize', resizeListener)
115+
},
116116
})
117117

118118
function timelineShouldBeActive(binding, configOptions) {
@@ -269,7 +269,7 @@ function prepareTimeline(el, binding, configOptions) {
269269
if (binding.modifiers.stagger) values[1].stagger = stagger
270270
if (binding.modifiers.fromInvisible)
271271
values[1].opacity = values[1].opacity || 1
272-
timeline.fromTo(el, ...binding.value)
272+
timeline.fromTo(el, binding.value?.[0], binding.value?.[1])
273273
}
274274

275275
// .animateText. // .slow // .fast
@@ -310,7 +310,7 @@ function prepareTimeline(el, binding, configOptions) {
310310
if (binding.modifiers.draggable) {
311311
const type = Object.keys(binding.modifiers).find(modifier =>
312312
['x', 'y', 'rotation'].includes(modifier),
313-
)
313+
) as Draggable.DraggableType
314314
Draggable.create(el, {
315315
type,
316316
bounds: binding.value || el.parentElement,

src/runtime/vue.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import gsap from 'gsap'
2+
import { vGsapDirective } from './plugin'
3+
4+
export const vGsapVue = (configOptions?) => {
5+
return vGsapDirective(
6+
'vue',
7+
configOptions || {},
8+
gsap.context(() => {}),
9+
null,
10+
)
11+
}

0 commit comments

Comments
 (0)