@brandocms/jupiter 4.0.0-beta.1 → 5.0.0-beta.1
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.
- package/README.md +191 -2
- package/package.json +20 -18
- package/src/index.js +10 -10
- package/src/modules/Application/index.js +203 -157
- package/src/modules/Cookies/index.js +34 -55
- package/src/modules/CoverOverlay/index.js +20 -13
- package/src/modules/Dataloader/index.js +71 -24
- package/src/modules/Dataloader/url-sync.js +238 -0
- package/src/modules/Dom/index.js +18 -0
- package/src/modules/DoubleHeader/index.js +571 -0
- package/src/modules/Dropdown/index.js +101 -75
- package/src/modules/EqualHeightElements/index.js +5 -7
- package/src/modules/EqualHeightImages/index.js +7 -2
- package/src/modules/FixedHeader/index.js +60 -30
- package/src/modules/FooterReveal/index.js +3 -3
- package/src/modules/HeroSlider/index.js +207 -91
- package/src/modules/HeroVideo/index.js +15 -27
- package/src/modules/Lazyload/index.js +101 -80
- package/src/modules/Lightbox/index.js +17 -55
- package/src/modules/Links/index.js +54 -49
- package/src/modules/Looper/index.js +1737 -0
- package/src/modules/Marquee/index.js +106 -37
- package/src/modules/MobileMenu/index.js +70 -124
- package/src/modules/Moonwalk/index.js +349 -150
- package/src/modules/Popover/index.js +186 -28
- package/src/modules/Popup/index.js +27 -34
- package/src/modules/StackedBoxes/index.js +3 -3
- package/src/modules/StickyHeader/index.js +364 -155
- package/src/modules/Toggler/index.js +184 -27
- package/src/utils/motion-helpers.js +330 -0
- package/types/index.d.ts +1 -30
- package/types/modules/Application/index.d.ts +6 -6
- package/types/modules/Breakpoints/index.d.ts +2 -0
- package/types/modules/Dataloader/index.d.ts +5 -2
- package/types/modules/Dataloader/url-sync.d.ts +36 -0
- package/types/modules/Dom/index.d.ts +7 -0
- package/types/modules/DoubleHeader/index.d.ts +63 -0
- package/types/modules/Dropdown/index.d.ts +7 -30
- package/types/modules/EqualHeightImages/index.d.ts +1 -1
- package/types/modules/FixedHeader/index.d.ts +1 -1
- package/types/modules/Lazyload/index.d.ts +9 -9
- package/types/modules/Lightbox/index.d.ts +0 -5
- package/types/modules/Looper/index.d.ts +127 -0
- package/types/modules/Moonwalk/index.d.ts +6 -15
- package/types/modules/Parallax/index.d.ts +10 -32
- package/types/modules/Popover/index.d.ts +12 -0
- package/types/modules/Popup/index.d.ts +6 -19
- package/types/modules/ScrollSpy/index.d.ts +1 -1
- package/types/modules/StickyHeader/index.d.ts +171 -14
- package/types/modules/Toggler/index.d.ts +24 -2
|
@@ -1,27 +1,50 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { animate } from 'motion'
|
|
2
2
|
import Dom from '../Dom'
|
|
3
|
+
import { set } from '../../utils/motion-helpers'
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Toggler component for show/hide functionality
|
|
6
7
|
* Uses [data-toggle-trigger] for the toggle button and [data-toggle-content] for toggleable content
|
|
8
|
+
* Can be grouped using [data-toggle-group] to create accordion-like behavior
|
|
9
|
+
*
|
|
10
|
+
* IMPORTANT: For smooth animations, avoid padding/margins on [data-toggle-content].
|
|
11
|
+
* Instead, wrap content in a child element with padding/margins:
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* // ❌ DON'T: Padding/margins directly on toggle content
|
|
15
|
+
* <div data-toggle-content style="padding: 20px; margin-top: 10px">
|
|
16
|
+
* Content here
|
|
17
|
+
* </div>
|
|
18
|
+
*
|
|
19
|
+
* // ✅ DO: Wrap content in child element
|
|
20
|
+
* <div data-toggle-content>
|
|
21
|
+
* <div style="padding: 20px; margin-top: 10px">
|
|
22
|
+
* Content here
|
|
23
|
+
* </div>
|
|
24
|
+
* </div>
|
|
7
25
|
*/
|
|
8
26
|
export default class Toggler {
|
|
9
27
|
/**
|
|
10
28
|
* Create a new Toggler instance
|
|
11
29
|
* @param {Object} app - Application instance
|
|
12
30
|
* @param {HTMLElement} el - Container element with [data-toggle] attribute
|
|
31
|
+
* @param {Object} options - Configuration options
|
|
32
|
+
* @param {Function} options.onOpen - Callback when toggle opens
|
|
33
|
+
* @param {Function} options.onClose - Callback when toggle closes
|
|
13
34
|
*/
|
|
14
|
-
constructor(app, el) {
|
|
35
|
+
constructor(app, el, options = {}) {
|
|
15
36
|
this.open = false
|
|
16
37
|
this.app = app
|
|
17
38
|
this.el = el
|
|
39
|
+
this.onOpen = options.onOpen
|
|
40
|
+
this.onClose = options.onClose
|
|
41
|
+
this.onBeforeOpen = options.onBeforeOpen
|
|
42
|
+
this.onBeforeClose = options.onBeforeClose
|
|
18
43
|
this.trigger = Dom.find(this.el, '[data-toggle-trigger]')
|
|
19
44
|
this.triggerTarget = this.trigger.dataset.toggleTrigger
|
|
45
|
+
this.group = this.el.dataset.toggleGroup
|
|
20
46
|
if (this.triggerTarget) {
|
|
21
|
-
this.content = Dom.all(
|
|
22
|
-
this.el,
|
|
23
|
-
`[data-toggle-content="${this.triggerTarget}"]`
|
|
24
|
-
)
|
|
47
|
+
this.content = Dom.all(this.el, `[data-toggle-content="${this.triggerTarget}"]`)
|
|
25
48
|
} else {
|
|
26
49
|
this.content = Dom.all(this.el, '[data-toggle-content]')
|
|
27
50
|
}
|
|
@@ -29,48 +52,182 @@ export default class Toggler {
|
|
|
29
52
|
this.trigger.addEventListener('click', this.onClick.bind(this))
|
|
30
53
|
}
|
|
31
54
|
|
|
55
|
+
/**
|
|
56
|
+
* Get the index of this toggle within its group (1-based)
|
|
57
|
+
* @returns {number} The 1-based index of this toggle in its group
|
|
58
|
+
*/
|
|
59
|
+
getGroupIndex() {
|
|
60
|
+
if (!this.group || !this.app.togglers) return 1
|
|
61
|
+
|
|
62
|
+
const groupTogglers = this.app.togglers.filter(t => t.group === this.group)
|
|
63
|
+
return groupTogglers.indexOf(this) + 1
|
|
64
|
+
}
|
|
65
|
+
|
|
32
66
|
/**
|
|
33
67
|
* Handle click on trigger element
|
|
34
68
|
*/
|
|
35
69
|
onClick() {
|
|
70
|
+
// If this toggler belongs to a group and is currently closed,
|
|
71
|
+
// close all others in the same group
|
|
72
|
+
if (this.group && !this.open) {
|
|
73
|
+
this.closeOthersInGroup()
|
|
74
|
+
}
|
|
75
|
+
|
|
36
76
|
this.toggleState()
|
|
37
77
|
|
|
38
78
|
if (this.open) {
|
|
39
79
|
if (this.triggerIcon) {
|
|
40
80
|
this.triggerIcon.classList.toggle('active')
|
|
41
81
|
}
|
|
42
|
-
|
|
82
|
+
this.trigger.setAttribute('data-toggle-trigger-active', '')
|
|
83
|
+
|
|
84
|
+
// Set initial state before making visible
|
|
85
|
+
this.content.forEach(el => {
|
|
86
|
+
el.style.height = '0'
|
|
87
|
+
el.style.display = 'block'
|
|
88
|
+
// Force layout reflow to ensure 0 height is applied
|
|
89
|
+
el.offsetHeight
|
|
90
|
+
})
|
|
91
|
+
|
|
43
92
|
this.el.classList.toggle('open')
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
93
|
+
if (this.onBeforeOpen) {
|
|
94
|
+
this.onBeforeOpen(this, this.getGroupIndex())
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Animate each content element with stagger
|
|
98
|
+
const animations = []
|
|
99
|
+
this.content.forEach((el, index) => {
|
|
100
|
+
// Measure the actual height now
|
|
101
|
+
const targetHeight = el.scrollHeight
|
|
102
|
+
|
|
103
|
+
animations.push(
|
|
104
|
+
animate(el, { height: [0, targetHeight + 'px'] }, {
|
|
105
|
+
ease: 'easeInOut',
|
|
106
|
+
delay: index * 0.1
|
|
107
|
+
})
|
|
108
|
+
)
|
|
54
109
|
})
|
|
110
|
+
|
|
111
|
+
// Wait for the last animation to complete
|
|
112
|
+
const lastAnimation = animations[animations.length - 1]
|
|
113
|
+
if (lastAnimation) {
|
|
114
|
+
lastAnimation.finished.then(() => {
|
|
115
|
+
// Set height to auto for responsiveness
|
|
116
|
+
this.content.forEach(el => {
|
|
117
|
+
el.style.height = 'auto'
|
|
118
|
+
el.removeAttribute('data-toggle-hidden')
|
|
119
|
+
el.setAttribute('data-toggle-visible', '')
|
|
120
|
+
})
|
|
121
|
+
if (this.onOpen) {
|
|
122
|
+
this.onOpen(this, this.getGroupIndex())
|
|
123
|
+
}
|
|
124
|
+
})
|
|
125
|
+
}
|
|
55
126
|
} else {
|
|
56
127
|
if (this.triggerIcon) {
|
|
57
128
|
this.triggerIcon.classList.toggle('active')
|
|
58
129
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
130
|
+
this.trigger.removeAttribute('data-toggle-trigger-active')
|
|
131
|
+
if (this.onBeforeClose) {
|
|
132
|
+
this.onBeforeClose(this, this.getGroupIndex())
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Animate each content element with stagger
|
|
136
|
+
const animations = []
|
|
137
|
+
this.content.forEach((el, index) => {
|
|
138
|
+
// Get current height and set explicitly before animating
|
|
139
|
+
const currentHeight = el.scrollHeight
|
|
140
|
+
el.style.height = currentHeight + 'px'
|
|
141
|
+
// Force layout reflow to ensure pixel height is applied
|
|
142
|
+
el.offsetHeight
|
|
143
|
+
|
|
144
|
+
animations.push(
|
|
145
|
+
animate(el, { height: 0 }, {
|
|
146
|
+
duration: 0.25,
|
|
147
|
+
ease: 'easeOut',
|
|
148
|
+
delay: index * 0.1
|
|
149
|
+
})
|
|
150
|
+
)
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
// Wait for the last animation to complete
|
|
154
|
+
const lastAnimation = animations[animations.length - 1]
|
|
155
|
+
if (lastAnimation) {
|
|
156
|
+
lastAnimation.finished.then(() => {
|
|
62
157
|
this.el.classList.toggle('open')
|
|
63
|
-
this.content.forEach(
|
|
158
|
+
this.content.forEach(el => {
|
|
159
|
+
el.style.display = 'none'
|
|
160
|
+
el.style.removeProperty('height')
|
|
64
161
|
el.removeAttribute('data-toggle-visible')
|
|
65
|
-
)
|
|
66
|
-
this.content.forEach((el) =>
|
|
67
162
|
el.setAttribute('data-toggle-hidden', '')
|
|
163
|
+
})
|
|
164
|
+
if (this.onClose) {
|
|
165
|
+
this.onClose(this, this.getGroupIndex())
|
|
166
|
+
}
|
|
167
|
+
})
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Close all other togglers in the same group
|
|
174
|
+
*/
|
|
175
|
+
closeOthersInGroup() {
|
|
176
|
+
if (!this.group || !this.app.togglers) return
|
|
177
|
+
|
|
178
|
+
this.app.togglers.forEach(toggler => {
|
|
179
|
+
// Skip if it's this toggler or not in the same group
|
|
180
|
+
if (toggler === this || toggler.group !== this.group) return
|
|
181
|
+
|
|
182
|
+
// Only close if it's open
|
|
183
|
+
if (toggler.open) {
|
|
184
|
+
// Close the toggler
|
|
185
|
+
toggler.open = false
|
|
186
|
+
|
|
187
|
+
// Update UI
|
|
188
|
+
if (toggler.triggerIcon) {
|
|
189
|
+
toggler.triggerIcon.classList.remove('active')
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
toggler.trigger.removeAttribute('data-toggle-trigger-active')
|
|
193
|
+
toggler.el.classList.remove('open')
|
|
194
|
+
|
|
195
|
+
// Animate content closing with stagger
|
|
196
|
+
const animations = []
|
|
197
|
+
toggler.content.forEach((el, index) => {
|
|
198
|
+
// Get current height and set explicitly before animating
|
|
199
|
+
const currentHeight = el.scrollHeight
|
|
200
|
+
el.style.height = currentHeight + 'px'
|
|
201
|
+
// Force layout reflow to ensure pixel height is applied
|
|
202
|
+
el.offsetHeight
|
|
203
|
+
|
|
204
|
+
animations.push(
|
|
205
|
+
animate(el, { height: 0 }, {
|
|
206
|
+
duration: 0.25,
|
|
207
|
+
ease: 'easeOut',
|
|
208
|
+
delay: index * 0.1
|
|
209
|
+
})
|
|
68
210
|
)
|
|
69
|
-
}
|
|
70
|
-
})
|
|
211
|
+
})
|
|
71
212
|
|
|
72
|
-
|
|
73
|
-
|
|
213
|
+
// Wait for the last animation to complete
|
|
214
|
+
const lastAnimation = animations[animations.length - 1]
|
|
215
|
+
if (lastAnimation) {
|
|
216
|
+
lastAnimation.finished.then(() => {
|
|
217
|
+
toggler.content.forEach(el => {
|
|
218
|
+
el.style.display = 'none'
|
|
219
|
+
el.style.removeProperty('height')
|
|
220
|
+
el.removeAttribute('data-toggle-visible')
|
|
221
|
+
el.setAttribute('data-toggle-hidden', '')
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
if (toggler.onClose) {
|
|
225
|
+
toggler.onClose(toggler, toggler.getGroupIndex())
|
|
226
|
+
}
|
|
227
|
+
})
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
})
|
|
74
231
|
}
|
|
75
232
|
|
|
76
233
|
/**
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
import { animate, delay } from 'motion'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Set properties immediately (like gsap.set)
|
|
5
|
+
* Uses direct DOM manipulation for synchronous style application
|
|
6
|
+
*
|
|
7
|
+
* @param {Element|string|NodeList|Array} target - Element(s) or selector
|
|
8
|
+
* @param {Object} values - Properties to set
|
|
9
|
+
*/
|
|
10
|
+
export function set(target, values) {
|
|
11
|
+
// Get elements as array
|
|
12
|
+
let elements
|
|
13
|
+
if (typeof target === 'string') {
|
|
14
|
+
elements = Array.from(document.querySelectorAll(target))
|
|
15
|
+
} else if (target instanceof NodeList) {
|
|
16
|
+
elements = Array.from(target)
|
|
17
|
+
} else if (Array.isArray(target)) {
|
|
18
|
+
elements = target
|
|
19
|
+
} else {
|
|
20
|
+
elements = [target]
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
elements.forEach((element) => {
|
|
24
|
+
if (!element) return
|
|
25
|
+
|
|
26
|
+
// Build transform string from transform properties
|
|
27
|
+
const transformProps = []
|
|
28
|
+
const styleProps = {}
|
|
29
|
+
|
|
30
|
+
Object.entries(values).forEach(([key, value]) => {
|
|
31
|
+
// Handle transform properties
|
|
32
|
+
if (key === 'x') {
|
|
33
|
+
transformProps.push(`translateX(${typeof value === 'number' ? value + 'px' : value})`)
|
|
34
|
+
} else if (key === 'y') {
|
|
35
|
+
transformProps.push(`translateY(${typeof value === 'number' ? value + 'px' : value})`)
|
|
36
|
+
} else if (key === 'scale') {
|
|
37
|
+
transformProps.push(`scale(${value})`)
|
|
38
|
+
} else if (key === 'scaleX') {
|
|
39
|
+
transformProps.push(`scaleX(${value})`)
|
|
40
|
+
} else if (key === 'scaleY') {
|
|
41
|
+
transformProps.push(`scaleY(${value})`)
|
|
42
|
+
} else if (key === 'rotate') {
|
|
43
|
+
transformProps.push(`rotate(${typeof value === 'number' ? value + 'deg' : value})`)
|
|
44
|
+
} else if (key === 'rotateX') {
|
|
45
|
+
transformProps.push(`rotateX(${typeof value === 'number' ? value + 'deg' : value})`)
|
|
46
|
+
} else if (key === 'rotateY') {
|
|
47
|
+
transformProps.push(`rotateY(${typeof value === 'number' ? value + 'deg' : value})`)
|
|
48
|
+
} else if (key === 'rotateZ') {
|
|
49
|
+
transformProps.push(`rotateZ(${typeof value === 'number' ? value + 'deg' : value})`)
|
|
50
|
+
} else {
|
|
51
|
+
// Regular CSS property
|
|
52
|
+
styleProps[key] = value
|
|
53
|
+
}
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
// Apply transform
|
|
57
|
+
if (transformProps.length > 0) {
|
|
58
|
+
element.style.transform = transformProps.join(' ')
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Apply other styles
|
|
62
|
+
Object.entries(styleProps).forEach(([key, value]) => {
|
|
63
|
+
element.style[key] = value
|
|
64
|
+
})
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Animate autoAlpha (opacity + visibility)
|
|
70
|
+
* Mimics GSAP's autoAlpha property
|
|
71
|
+
*
|
|
72
|
+
* @param {Element|string} target - Element or selector
|
|
73
|
+
* @param {number} value - Target alpha value (0 or 1)
|
|
74
|
+
* @param {Object} options - Animation options
|
|
75
|
+
* @returns {Object} Animation object
|
|
76
|
+
*/
|
|
77
|
+
export function animateAutoAlpha(target, value, options = {}) {
|
|
78
|
+
const element = typeof target === 'string'
|
|
79
|
+
? document.querySelector(target)
|
|
80
|
+
: target
|
|
81
|
+
|
|
82
|
+
if (value === 0) {
|
|
83
|
+
// Fade out, then hide
|
|
84
|
+
return animate(element, { opacity: 0 }, {
|
|
85
|
+
...options,
|
|
86
|
+
onComplete: () => {
|
|
87
|
+
element.style.visibility = 'hidden'
|
|
88
|
+
options.onComplete?.()
|
|
89
|
+
}
|
|
90
|
+
})
|
|
91
|
+
} else {
|
|
92
|
+
// Show, then fade in
|
|
93
|
+
element.style.visibility = 'visible'
|
|
94
|
+
return animate(element, { opacity: value }, options)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Clear inline styles
|
|
100
|
+
* Mimics GSAP's clearProps
|
|
101
|
+
*
|
|
102
|
+
* @param {Element|string|NodeList|Array} target - Element(s) or selector
|
|
103
|
+
* @param {string|Array} props - Properties to clear or 'all'
|
|
104
|
+
*/
|
|
105
|
+
export function clearProps(target, props = 'all') {
|
|
106
|
+
// Get elements as array
|
|
107
|
+
let elements
|
|
108
|
+
if (typeof target === 'string') {
|
|
109
|
+
elements = Array.from(document.querySelectorAll(target))
|
|
110
|
+
} else if (target instanceof NodeList) {
|
|
111
|
+
elements = Array.from(target)
|
|
112
|
+
} else if (Array.isArray(target)) {
|
|
113
|
+
elements = target
|
|
114
|
+
} else {
|
|
115
|
+
elements = [target]
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
elements.forEach(element => {
|
|
119
|
+
if (!element) return
|
|
120
|
+
|
|
121
|
+
if (props === 'all') {
|
|
122
|
+
element.removeAttribute('style')
|
|
123
|
+
} else {
|
|
124
|
+
const properties = Array.isArray(props) ? props : [props]
|
|
125
|
+
properties.forEach(prop => {
|
|
126
|
+
element.style.removeProperty(prop)
|
|
127
|
+
})
|
|
128
|
+
}
|
|
129
|
+
})
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Delayed call helper
|
|
134
|
+
* Mimics gsap.delayedCall
|
|
135
|
+
* Uses Motion's delay function (locked to animation frame loop for better sync)
|
|
136
|
+
*
|
|
137
|
+
* @param {number} duration - Delay in seconds
|
|
138
|
+
* @param {Function} callback - Callback function
|
|
139
|
+
* @returns {Promise} Promise that resolves after delay
|
|
140
|
+
*/
|
|
141
|
+
export function delayedCall(duration, callback) {
|
|
142
|
+
return new Promise(resolve => {
|
|
143
|
+
delay(() => {
|
|
144
|
+
callback()
|
|
145
|
+
resolve()
|
|
146
|
+
}, duration)
|
|
147
|
+
})
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Paused Timeline helper
|
|
152
|
+
* Mimics GSAP's paused timeline pattern for building sequences
|
|
153
|
+
* Used by modules like Lightbox that build animations before playing them
|
|
154
|
+
*/
|
|
155
|
+
export class PausedTimeline {
|
|
156
|
+
constructor() {
|
|
157
|
+
this.sequence = []
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Add animation to timeline
|
|
162
|
+
* @param {Element|string} target - Element or selector
|
|
163
|
+
* @param {Object} values - Properties to animate
|
|
164
|
+
* @param {Object} options - Animation options
|
|
165
|
+
* @returns {PausedTimeline} this for chaining
|
|
166
|
+
*/
|
|
167
|
+
to(target, values, options = {}) {
|
|
168
|
+
this.sequence.push(['animate', target, values, options])
|
|
169
|
+
return this
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Add callback to timeline
|
|
174
|
+
* @param {Function} callback - Function to call
|
|
175
|
+
* @returns {PausedTimeline} this for chaining
|
|
176
|
+
*/
|
|
177
|
+
call(callback) {
|
|
178
|
+
this.sequence.push(['call', callback])
|
|
179
|
+
return this
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Clear timeline sequence
|
|
184
|
+
* @returns {PausedTimeline} this for chaining
|
|
185
|
+
*/
|
|
186
|
+
clear() {
|
|
187
|
+
this.sequence = []
|
|
188
|
+
return this
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Play timeline sequence
|
|
193
|
+
* Executes all animations and callbacks in order
|
|
194
|
+
* @returns {Promise} Promise that resolves when sequence completes
|
|
195
|
+
*/
|
|
196
|
+
async play() {
|
|
197
|
+
const sequence = [...this.sequence] // Copy so we can clear while playing
|
|
198
|
+
this.sequence = [] // Clear for next time
|
|
199
|
+
|
|
200
|
+
for (const item of sequence) {
|
|
201
|
+
if (item[0] === 'animate') {
|
|
202
|
+
const [, target, values, options] = item
|
|
203
|
+
// Handle autoAlpha
|
|
204
|
+
if (values.autoAlpha !== undefined) {
|
|
205
|
+
const autoAlphaOptions = { ...options }
|
|
206
|
+
delete autoAlphaOptions.autoAlpha
|
|
207
|
+
await animateAutoAlpha(target, values.autoAlpha, autoAlphaOptions).finished
|
|
208
|
+
} else {
|
|
209
|
+
await animate(target, values, options).finished
|
|
210
|
+
}
|
|
211
|
+
} else if (item[0] === 'call') {
|
|
212
|
+
item[1]() // Execute callback
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Convert GSAP easing strings to Motion.js compatible easings
|
|
220
|
+
* Handles common GSAP easing types and returns valid Motion.js easing
|
|
221
|
+
*
|
|
222
|
+
* @param {string|Array} easing - GSAP easing string or bezier array
|
|
223
|
+
* @returns {string|Array} Motion.js compatible easing
|
|
224
|
+
*
|
|
225
|
+
* Valid Motion.js easings:
|
|
226
|
+
* - "linear"
|
|
227
|
+
* - "easeIn"
|
|
228
|
+
* - "easeInOut"
|
|
229
|
+
* - "easeOut"
|
|
230
|
+
* - "circIn"
|
|
231
|
+
* - "circInOut"
|
|
232
|
+
* - "circOut"
|
|
233
|
+
* - "backIn"
|
|
234
|
+
* - "backInOut"
|
|
235
|
+
* - "backOut"
|
|
236
|
+
* - "anticipate"
|
|
237
|
+
* - Bezier arrays: [x1, y1, x2, y2]
|
|
238
|
+
*/
|
|
239
|
+
export function convertEasing(easing) {
|
|
240
|
+
// If already an array (bezier), return as-is
|
|
241
|
+
if (Array.isArray(easing)) {
|
|
242
|
+
return easing
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// If not a string, return default
|
|
246
|
+
if (typeof easing !== 'string') {
|
|
247
|
+
return 'easeOut'
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// Already a valid Motion.js easing
|
|
251
|
+
const validMotionEasings = [
|
|
252
|
+
'linear',
|
|
253
|
+
'easeIn',
|
|
254
|
+
'easeInOut',
|
|
255
|
+
'easeOut',
|
|
256
|
+
'circIn',
|
|
257
|
+
'circInOut',
|
|
258
|
+
'circOut',
|
|
259
|
+
'backIn',
|
|
260
|
+
'backInOut',
|
|
261
|
+
'backOut',
|
|
262
|
+
'anticipate',
|
|
263
|
+
]
|
|
264
|
+
|
|
265
|
+
if (validMotionEasings.includes(easing)) {
|
|
266
|
+
return easing
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Convert GSAP easings to Motion.js equivalents
|
|
270
|
+
const easingMap = {
|
|
271
|
+
// Power easings (most common)
|
|
272
|
+
'power1.in': 'easeIn',
|
|
273
|
+
'power1.out': 'easeOut',
|
|
274
|
+
'power1.inOut': 'easeInOut',
|
|
275
|
+
'power2.in': 'easeIn',
|
|
276
|
+
'power2.out': 'easeOut',
|
|
277
|
+
'power2.inOut': 'easeInOut',
|
|
278
|
+
'power3.in': 'easeIn',
|
|
279
|
+
'power3.out': 'easeOut',
|
|
280
|
+
'power3.inOut': 'easeInOut',
|
|
281
|
+
'power4.in': 'easeIn',
|
|
282
|
+
'power4.out': 'easeOut',
|
|
283
|
+
'power4.inOut': 'easeInOut',
|
|
284
|
+
|
|
285
|
+
// Sine easings
|
|
286
|
+
'sine.in': 'easeIn',
|
|
287
|
+
'sine.out': 'easeOut',
|
|
288
|
+
'sine.inOut': 'easeInOut',
|
|
289
|
+
|
|
290
|
+
// Expo easings
|
|
291
|
+
'expo.in': 'easeIn',
|
|
292
|
+
'expo.out': 'easeOut',
|
|
293
|
+
'expo.inOut': 'easeInOut',
|
|
294
|
+
|
|
295
|
+
// Circ easings (Motion.js has these!)
|
|
296
|
+
'circ.in': 'circIn',
|
|
297
|
+
'circ.out': 'circOut',
|
|
298
|
+
'circ.inOut': 'circInOut',
|
|
299
|
+
|
|
300
|
+
// Back easings (Motion.js has these!)
|
|
301
|
+
'back.in': 'backIn',
|
|
302
|
+
'back.out': 'backOut',
|
|
303
|
+
'back.inOut': 'backInOut',
|
|
304
|
+
|
|
305
|
+
// Elastic and bounce - no direct equivalent, use anticipate or backOut
|
|
306
|
+
'elastic.in': 'backIn',
|
|
307
|
+
'elastic.out': 'backOut',
|
|
308
|
+
'elastic.inOut': 'backInOut',
|
|
309
|
+
'bounce.in': 'backIn',
|
|
310
|
+
'bounce.out': 'anticipate',
|
|
311
|
+
'bounce.inOut': 'backInOut',
|
|
312
|
+
|
|
313
|
+
// Common aliases
|
|
314
|
+
none: 'linear',
|
|
315
|
+
'linear': 'linear',
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// Try to find a mapping
|
|
319
|
+
const converted = easingMap[easing.toLowerCase()]
|
|
320
|
+
|
|
321
|
+
if (converted) {
|
|
322
|
+
return converted
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// If no mapping found, log warning and return default
|
|
326
|
+
console.warn(
|
|
327
|
+
`[Motion Helpers] Unknown easing type "${easing}", using "easeOut" as fallback`
|
|
328
|
+
)
|
|
329
|
+
return 'easeOut'
|
|
330
|
+
}
|
package/types/index.d.ts
CHANGED
|
@@ -1,35 +1,6 @@
|
|
|
1
|
-
import Application from './modules/Application';
|
|
2
|
-
import Breakpoints from './modules/Breakpoints';
|
|
3
|
-
import Cookies from './modules/Cookies';
|
|
4
|
-
import CoverOverlay from './modules/CoverOverlay';
|
|
5
|
-
import Dataloader from './modules/Dataloader';
|
|
6
|
-
import Dom from './modules/Dom';
|
|
7
|
-
import Dropdown from './modules/Dropdown';
|
|
8
|
-
import EqualHeightElements from './modules/EqualHeightElements';
|
|
9
|
-
import EqualHeightImages from './modules/EqualHeightImages';
|
|
10
|
-
import * as Events from './events';
|
|
11
|
-
import FixedHeader from './modules/FixedHeader';
|
|
12
|
-
import FooterReveal from './modules/FooterReveal';
|
|
13
|
-
import Parallax from './modules/Parallax';
|
|
14
|
-
import HeroSlider from './modules/HeroSlider';
|
|
15
|
-
import HeroVideo from './modules/HeroVideo';
|
|
16
|
-
import Lazyload from './modules/Lazyload';
|
|
17
|
-
import Lightbox from './modules/Lightbox';
|
|
18
|
-
import Links from './modules/Links';
|
|
19
|
-
import Marquee from './modules/Marquee';
|
|
20
|
-
import MobileMenu from './modules/MobileMenu';
|
|
21
|
-
import Moonwalk from './modules/Moonwalk';
|
|
22
|
-
import Popover from './modules/Popover';
|
|
23
|
-
import Popup from './modules/Popup';
|
|
24
|
-
import ScrollSpy from './modules/ScrollSpy';
|
|
25
|
-
import StackedBoxes from './modules/StackedBoxes';
|
|
26
|
-
import StickyHeader from './modules/StickyHeader';
|
|
27
|
-
import Toggler from './modules/Toggler';
|
|
28
|
-
import Typography from './modules/Typography';
|
|
29
1
|
import imageIsLoaded from './utils/imageIsLoaded';
|
|
30
2
|
import imagesAreLoaded from './utils/imagesAreLoaded';
|
|
31
3
|
import loadScript from './utils/loadScript';
|
|
32
4
|
import prefersReducedMotion from './utils/prefersReducedMotion';
|
|
33
5
|
import rafCallback from './utils/rafCallback';
|
|
34
|
-
|
|
35
|
-
export { Application, Breakpoints, Cookies, CoverOverlay, Dataloader, Dom, Draggable, Dropdown, EqualHeightElements, EqualHeightImages, Events, FixedHeader, FooterReveal, Parallax, HeroSlider, HeroVideo, Lazyload, Lightbox, Links, Marquee, MobileMenu, Moonwalk, Popover, Popup, ScrollSpy, StackedBoxes, StickyHeader, Toggler, Typography, imageIsLoaded, imagesAreLoaded, loadScript, prefersReducedMotion, rafCallback, _defaultsDeep, gsap, CSSPlugin, ScrollToPlugin, ScrollTrigger, Hammer };
|
|
6
|
+
export { Application, Breakpoints, Cookies, CoverOverlay, Dataloader, Dom, DoubleHeader, Draggable, Dropdown, EqualHeightElements, EqualHeightImages, Events, FixedHeader, FooterReveal, Parallax, HeroSlider, HeroVideo, Lazyload, Lightbox, Links, Looper, Marquee, MobileMenu, Moonwalk, Popover, Popup, ScrollSpy, StackedBoxes, StickyHeader, Toggler, Typography, imageIsLoaded, imagesAreLoaded, loadScript, prefersReducedMotion, rafCallback, _defaultsDeep, gsap, CSSPlugin, ScrollToPlugin, ScrollTrigger, SplitText, InertiaPlugin };
|
|
@@ -18,16 +18,19 @@ export default class Application {
|
|
|
18
18
|
position: {
|
|
19
19
|
top: number;
|
|
20
20
|
left: number;
|
|
21
|
+
lastTop: number;
|
|
22
|
+
lastLeft: number;
|
|
21
23
|
};
|
|
22
24
|
state: {
|
|
23
25
|
revealed: boolean;
|
|
24
26
|
forcedScroll: boolean;
|
|
27
|
+
scrollDirection: any;
|
|
25
28
|
};
|
|
26
29
|
opts: any;
|
|
27
30
|
focusableSelectors: any;
|
|
28
|
-
featureTests:
|
|
29
|
-
breakpoints:
|
|
30
|
-
fontLoader:
|
|
31
|
+
featureTests: any;
|
|
32
|
+
breakpoints: any;
|
|
33
|
+
fontLoader: any;
|
|
31
34
|
fader: any;
|
|
32
35
|
callbacks: {};
|
|
33
36
|
SCROLL_LOCKED: boolean;
|
|
@@ -163,6 +166,3 @@ export default class Application {
|
|
|
163
166
|
*/
|
|
164
167
|
getFocusableSelectors(): any;
|
|
165
168
|
}
|
|
166
|
-
import FeatureTests from '../FeatureTests';
|
|
167
|
-
import Breakpoints from '../Breakpoints';
|
|
168
|
-
import Fontloader from '../Fontloader';
|
|
@@ -4,16 +4,18 @@ export default class Dataloader {
|
|
|
4
4
|
status: string;
|
|
5
5
|
app: any;
|
|
6
6
|
$el: any;
|
|
7
|
+
id: any;
|
|
7
8
|
$canvasEl: any;
|
|
8
9
|
opts: any;
|
|
9
10
|
debounce(func: any, delay?: number): (...args: any[]) => void;
|
|
10
11
|
updateBaseURL(url: any): void;
|
|
11
12
|
baseURL: any;
|
|
13
|
+
setInitialParams(): void;
|
|
12
14
|
initialize(): void;
|
|
13
|
-
$paramEls: any
|
|
15
|
+
$paramEls: any;
|
|
16
|
+
urlSync: DataloaderUrlSync;
|
|
14
17
|
$moreBtn: any;
|
|
15
18
|
$filterInput: any;
|
|
16
|
-
id: any;
|
|
17
19
|
onFilterInput(e: any): void;
|
|
18
20
|
onMore(e: any): void;
|
|
19
21
|
onParam(e: any): void;
|
|
@@ -33,3 +35,4 @@ export default class Dataloader {
|
|
|
33
35
|
*/
|
|
34
36
|
updateButton(): void;
|
|
35
37
|
}
|
|
38
|
+
import DataloaderUrlSync from './url-sync';
|