@brandocms/jupiter 3.55.0 → 4.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 +318 -52
- package/package.json +26 -16
- package/src/index.js +5 -0
- package/src/modules/Application/index.js +36 -4
- package/src/modules/Breakpoints/index.js +116 -36
- package/src/modules/Cookies/index.js +67 -15
- package/src/modules/CoverOverlay/index.js +2 -2
- package/src/modules/Dom/index.js +6 -0
- package/src/modules/Dropdown/index.js +15 -6
- package/src/modules/EqualHeightElements/index.js +8 -6
- package/src/modules/EqualHeightImages/index.js +9 -6
- package/src/modules/FixedHeader/index.js +57 -1
- package/src/modules/FooterReveal/index.js +3 -3
- package/src/modules/HeroSlider/index.js +39 -30
- package/src/modules/HeroVideo/index.js +64 -24
- package/src/modules/Lazyload/index.js +27 -0
- package/src/modules/Lightbox/index.js +90 -31
- package/src/modules/Links/index.js +23 -2
- package/src/modules/MobileMenu/index.js +50 -21
- package/src/modules/Moonwalk/index.js +131 -4
- package/src/modules/Parallax/index.js +280 -57
- package/src/modules/Popover/index.js +28 -16
- package/src/modules/Popup/index.js +155 -29
- package/src/modules/ScrollSpy/index.js +21 -0
- package/src/modules/StackedBoxes/index.js +6 -4
- package/src/modules/StickyHeader/index.js +45 -24
- package/src/modules/Toggler/index.js +44 -5
- package/src/modules/Typography/index.js +33 -20
- package/types/README.md +159 -0
- package/types/events/index.d.ts +20 -0
- package/types/index.d.ts +35 -0
- package/types/modules/Application/index.d.ts +168 -0
- package/types/modules/Breakpoints/index.d.ts +38 -0
- package/types/modules/Cookies/index.d.ts +81 -0
- package/types/modules/CoverOverlay/index.d.ts +6 -0
- package/types/modules/Dataloader/index.d.ts +35 -0
- package/types/modules/Dom/index.d.ts +40 -0
- package/types/modules/Dropdown/index.d.ts +38 -0
- package/types/modules/EqualHeightElements/index.d.ts +8 -0
- package/types/modules/EqualHeightImages/index.d.ts +11 -0
- package/types/modules/FeatureTests/index.d.ts +27 -0
- package/types/modules/FixedHeader/index.d.ts +219 -0
- package/types/modules/Fontloader/index.d.ts +5 -0
- package/types/modules/FooterReveal/index.d.ts +5 -0
- package/types/modules/HeroSlider/index.d.ts +28 -0
- package/types/modules/HeroVideo/index.d.ts +83 -0
- package/types/modules/Lazyload/index.d.ts +80 -0
- package/types/modules/Lightbox/index.d.ts +128 -0
- package/types/modules/Links/index.d.ts +55 -0
- package/types/modules/Marquee/index.d.ts +23 -0
- package/types/modules/MobileMenu/index.d.ts +63 -0
- package/types/modules/Moonwalk/index.d.ts +331 -0
- package/types/modules/Parallax/index.d.ts +93 -0
- package/types/modules/Popover/index.d.ts +17 -0
- package/types/modules/Popup/index.d.ts +89 -0
- package/types/modules/ScrollSpy/index.d.ts +29 -0
- package/types/modules/StackedBoxes/index.d.ts +9 -0
- package/types/modules/StickyHeader/index.d.ts +63 -0
- package/types/modules/Toggler/index.d.ts +26 -0
- package/types/modules/Typography/index.d.ts +77 -0
- package/types/utils/dispatchElementEvent.d.ts +1 -0
- package/types/utils/imageIsLoaded.d.ts +1 -0
- package/types/utils/imagesAreLoaded.d.ts +1 -0
- package/types/utils/loadScript.d.ts +2 -0
- package/types/utils/prefersReducedMotion.d.ts +4 -0
- package/types/utils/rafCallback.d.ts +2 -0
- package/types/utils/zoom.d.ts +4 -0
|
@@ -1,9 +1,39 @@
|
|
|
1
1
|
import { Manager, Swipe } from '@egjs/hammerjs'
|
|
2
|
-
import { gsap } from 'gsap'
|
|
2
|
+
import { gsap } from 'gsap/all'
|
|
3
3
|
import _defaultsDeep from 'lodash.defaultsdeep'
|
|
4
4
|
import imageIsLoaded from '../../utils/imageIsLoaded'
|
|
5
5
|
import Dom from '../Dom'
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* @typedef {Object} LightboxElements
|
|
9
|
+
* @property {Function} [arrowRight] - Function to create right arrow element
|
|
10
|
+
* @property {Function} [arrowLeft] - Function to create left arrow element
|
|
11
|
+
* @property {Function} [close] - Function to create close button element
|
|
12
|
+
* @property {Function} [dot] - Function to create dot/indicator element
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @typedef {Object} LightboxOptions
|
|
17
|
+
* @property {boolean} [captions=false] - Enable captions
|
|
18
|
+
* @property {boolean} [numbers=false] - Enable index numbers
|
|
19
|
+
* @property {boolean} [swipe=true] - Enable swipe - this breaks native zoom
|
|
20
|
+
* @property {string|boolean} [trigger=false] - Selector for trigger element to open the lightbox
|
|
21
|
+
* @property {LightboxElements} [elements] - Custom elements configuration
|
|
22
|
+
* @property {Function} [onClick] - Click handler for lightbox
|
|
23
|
+
* @property {Function} [onPointerLeft] - Called when pointer moves left
|
|
24
|
+
* @property {Function} [onPointerRight] - Called when pointer moves right
|
|
25
|
+
* @property {Function} [onCaptionOut] - Called when caption fades out
|
|
26
|
+
* @property {Function} [onCaptionIn] - Called when caption fades in
|
|
27
|
+
* @property {Function} [onImageOut] - Called when image fades out
|
|
28
|
+
* @property {Function} [onImageIn] - Called when image fades in
|
|
29
|
+
* @property {Function} [onNumbers] - Called when numbers display updates
|
|
30
|
+
* @property {Function} [onBeforeOpen] - Called before opening lightbox
|
|
31
|
+
* @property {Function} [onOpen] - Called when lightbox opens
|
|
32
|
+
* @property {Function} [onAfterClose] - Called after lightbox closes
|
|
33
|
+
* @property {Function} [onClose] - Called when lightbox closes
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
/** @type {LightboxOptions} */
|
|
7
37
|
const DEFAULT_OPTIONS = {
|
|
8
38
|
/* enable captions */
|
|
9
39
|
captions: false,
|
|
@@ -33,7 +63,7 @@ const DEFAULT_OPTIONS = {
|
|
|
33
63
|
},
|
|
34
64
|
|
|
35
65
|
close: () => document.createTextNode('×'),
|
|
36
|
-
dot: () => document.createTextNode('▪')
|
|
66
|
+
dot: () => document.createTextNode('▪'),
|
|
37
67
|
},
|
|
38
68
|
|
|
39
69
|
onClick: (lightbox, section, e) => {
|
|
@@ -56,7 +86,10 @@ const DEFAULT_OPTIONS = {
|
|
|
56
86
|
return
|
|
57
87
|
}
|
|
58
88
|
|
|
59
|
-
lightbox.timelines.caption.to(lightbox.elements.caption, {
|
|
89
|
+
lightbox.timelines.caption.to(lightbox.elements.caption, {
|
|
90
|
+
duration: 0.4,
|
|
91
|
+
autoAlpha: 0,
|
|
92
|
+
})
|
|
60
93
|
},
|
|
61
94
|
|
|
62
95
|
onCaptionIn: (lightbox, captionHasChanged) => {
|
|
@@ -64,16 +97,26 @@ const DEFAULT_OPTIONS = {
|
|
|
64
97
|
return
|
|
65
98
|
}
|
|
66
99
|
|
|
67
|
-
lightbox.timelines.caption.to(lightbox.elements.caption, {
|
|
100
|
+
lightbox.timelines.caption.to(lightbox.elements.caption, {
|
|
101
|
+
duration: 0.4,
|
|
102
|
+
autoAlpha: 1,
|
|
103
|
+
})
|
|
68
104
|
},
|
|
69
105
|
|
|
70
|
-
onImageOut: lightbox => {
|
|
71
|
-
lightbox.timelines.image.to(lightbox.currentImage, {
|
|
106
|
+
onImageOut: (lightbox) => {
|
|
107
|
+
lightbox.timelines.image.to(lightbox.currentImage, {
|
|
108
|
+
duration: 0.5,
|
|
109
|
+
autoAlpha: 0,
|
|
110
|
+
})
|
|
72
111
|
},
|
|
73
112
|
|
|
74
|
-
onImageIn: lightbox => {
|
|
113
|
+
onImageIn: (lightbox) => {
|
|
75
114
|
const delay = lightbox.firstTransition ? 0.6 : 0.4
|
|
76
|
-
lightbox.timelines.image.to(lightbox.nextImage, {
|
|
115
|
+
lightbox.timelines.image.to(lightbox.nextImage, {
|
|
116
|
+
duration: 0.5,
|
|
117
|
+
autoAlpha: 1,
|
|
118
|
+
delay,
|
|
119
|
+
})
|
|
77
120
|
},
|
|
78
121
|
|
|
79
122
|
onNumbers: (lightbox, section) => {
|
|
@@ -82,22 +125,22 @@ const DEFAULT_OPTIONS = {
|
|
|
82
125
|
|
|
83
126
|
onBeforeOpen: () => {},
|
|
84
127
|
|
|
85
|
-
onOpen: h => {
|
|
128
|
+
onOpen: (h) => {
|
|
86
129
|
h.app.scrollLock()
|
|
87
130
|
|
|
88
131
|
gsap.to(h.elements.wrapper, {
|
|
89
132
|
duration: 0.5,
|
|
90
|
-
opacity: 1
|
|
133
|
+
opacity: 1,
|
|
91
134
|
})
|
|
92
135
|
},
|
|
93
136
|
|
|
94
137
|
onAfterClose: () => {},
|
|
95
138
|
|
|
96
|
-
onClose: h => {
|
|
139
|
+
onClose: (h) => {
|
|
97
140
|
if (h.opts.captions) {
|
|
98
141
|
gsap.to(h.elements.caption, {
|
|
99
142
|
duration: 0.45,
|
|
100
|
-
opacity: 0
|
|
143
|
+
opacity: 0,
|
|
101
144
|
})
|
|
102
145
|
}
|
|
103
146
|
|
|
@@ -107,7 +150,7 @@ const DEFAULT_OPTIONS = {
|
|
|
107
150
|
h.elements.nextArrow,
|
|
108
151
|
h.elements.prevArrow,
|
|
109
152
|
h.elements.close,
|
|
110
|
-
h.elements.dots
|
|
153
|
+
h.elements.dots,
|
|
111
154
|
],
|
|
112
155
|
{
|
|
113
156
|
duration: 0.5,
|
|
@@ -119,15 +162,23 @@ const DEFAULT_OPTIONS = {
|
|
|
119
162
|
onComplete: () => {
|
|
120
163
|
h.app.scrollRelease()
|
|
121
164
|
h.destroy()
|
|
122
|
-
}
|
|
165
|
+
},
|
|
123
166
|
})
|
|
124
|
-
}
|
|
167
|
+
},
|
|
125
168
|
}
|
|
126
169
|
)
|
|
127
|
-
}
|
|
170
|
+
},
|
|
128
171
|
}
|
|
129
172
|
|
|
173
|
+
/**
|
|
174
|
+
* Lightbox component for displaying images in a fullscreen overlay
|
|
175
|
+
*/
|
|
130
176
|
export default class Lightbox {
|
|
177
|
+
/**
|
|
178
|
+
* Create a new Lightbox instance
|
|
179
|
+
* @param {Object} app - Application instance
|
|
180
|
+
* @param {LightboxOptions} [opts={}] - Lightbox options
|
|
181
|
+
*/
|
|
131
182
|
constructor(app, opts = {}) {
|
|
132
183
|
this.app = app
|
|
133
184
|
this.opts = _defaultsDeep(opts, DEFAULT_OPTIONS)
|
|
@@ -141,15 +192,16 @@ export default class Lightbox {
|
|
|
141
192
|
this.previousCaption = null
|
|
142
193
|
this.timelines = {
|
|
143
194
|
caption: gsap.timeline({ paused: true }),
|
|
144
|
-
image: gsap.timeline({ paused: true })
|
|
195
|
+
image: gsap.timeline({ paused: true }),
|
|
145
196
|
}
|
|
146
197
|
|
|
147
|
-
this.lightboxes.forEach(lightbox => {
|
|
198
|
+
this.lightboxes.forEach((lightbox) => {
|
|
148
199
|
const href = lightbox.getAttribute('data-lightbox')
|
|
149
200
|
const srcset = lightbox.getAttribute('data-srcset')
|
|
150
201
|
const originalImage = lightbox.querySelector('img')
|
|
151
202
|
const alt = originalImage.getAttribute('alt')
|
|
152
|
-
const section =
|
|
203
|
+
const section =
|
|
204
|
+
lightbox.getAttribute('data-lightbox-section') || 'general'
|
|
153
205
|
let trigger = lightbox
|
|
154
206
|
if (this.opts.trigger) {
|
|
155
207
|
trigger = Dom.find(lightbox, this.opts.trigger) || lightbox
|
|
@@ -162,12 +214,12 @@ export default class Lightbox {
|
|
|
162
214
|
const image = {
|
|
163
215
|
href,
|
|
164
216
|
alt,
|
|
165
|
-
srcset
|
|
217
|
+
srcset,
|
|
166
218
|
}
|
|
167
219
|
|
|
168
220
|
const index = this.sections[section].push(image) - 1
|
|
169
221
|
|
|
170
|
-
trigger.addEventListener('click', e => {
|
|
222
|
+
trigger.addEventListener('click', (e) => {
|
|
171
223
|
e.preventDefault()
|
|
172
224
|
this.showBox(section, index)
|
|
173
225
|
})
|
|
@@ -207,30 +259,30 @@ export default class Lightbox {
|
|
|
207
259
|
this.elements.nextArrow.appendChild(this.opts.elements.arrowRight())
|
|
208
260
|
this.elements.nextArrow.href = '#'
|
|
209
261
|
|
|
210
|
-
this.elements.nextArrow.addEventListener('click', e => {
|
|
262
|
+
this.elements.nextArrow.addEventListener('click', (e) => {
|
|
211
263
|
e.stopPropagation()
|
|
212
264
|
e.preventDefault()
|
|
213
265
|
this.setImg(section, this.getNextIdx(section))
|
|
214
266
|
})
|
|
215
267
|
|
|
216
|
-
this.elements.prevArrow.addEventListener('click', e => {
|
|
268
|
+
this.elements.prevArrow.addEventListener('click', (e) => {
|
|
217
269
|
e.stopPropagation()
|
|
218
270
|
e.preventDefault()
|
|
219
271
|
this.setImg(section, this.getPrevIdx(section))
|
|
220
272
|
})
|
|
221
273
|
|
|
222
|
-
this.keyUpCallback = event => {
|
|
274
|
+
this.keyUpCallback = (event) => {
|
|
223
275
|
this.onKeyup(event, section)
|
|
224
276
|
}
|
|
225
277
|
|
|
226
278
|
document.removeEventListener('keyup', this.keyUpCallback)
|
|
227
279
|
document.addEventListener('keyup', this.keyUpCallback)
|
|
228
280
|
|
|
229
|
-
this.elements.wrapper.addEventListener('mousemove', event => {
|
|
281
|
+
this.elements.wrapper.addEventListener('mousemove', (event) => {
|
|
230
282
|
this.onMouseMove(event)
|
|
231
283
|
})
|
|
232
284
|
|
|
233
|
-
this.elements.wrapper.addEventListener('click', event => {
|
|
285
|
+
this.elements.wrapper.addEventListener('click', (event) => {
|
|
234
286
|
this.onClick(event, section)
|
|
235
287
|
})
|
|
236
288
|
|
|
@@ -257,7 +309,7 @@ export default class Lightbox {
|
|
|
257
309
|
activeLink = a
|
|
258
310
|
}
|
|
259
311
|
|
|
260
|
-
a.addEventListener('click', e => {
|
|
312
|
+
a.addEventListener('click', (e) => {
|
|
261
313
|
a.classList.add('active')
|
|
262
314
|
activeLink.classList.remove('active')
|
|
263
315
|
activeLink = a
|
|
@@ -296,7 +348,7 @@ export default class Lightbox {
|
|
|
296
348
|
|
|
297
349
|
this.opts.onOpen(this)
|
|
298
350
|
|
|
299
|
-
this.elements.close.addEventListener('click', e => {
|
|
351
|
+
this.elements.close.addEventListener('click', (e) => {
|
|
300
352
|
e.preventDefault()
|
|
301
353
|
e.stopPropagation()
|
|
302
354
|
|
|
@@ -334,7 +386,8 @@ export default class Lightbox {
|
|
|
334
386
|
activeDot.classList.add('active')
|
|
335
387
|
|
|
336
388
|
if (this.elements.caption) {
|
|
337
|
-
captionHasChanged =
|
|
389
|
+
captionHasChanged =
|
|
390
|
+
this.previousCaption !== this.sections[section][index].alt
|
|
338
391
|
this.previousCaption = this.sections[section][index].alt
|
|
339
392
|
this.opts.onCaptionOut(this, captionHasChanged)
|
|
340
393
|
this.timelines.caption.call(() => {
|
|
@@ -357,7 +410,10 @@ export default class Lightbox {
|
|
|
357
410
|
if (this.imgs[index + x]) {
|
|
358
411
|
this.imgs[index + x].src = this.sections[section][index + x].href
|
|
359
412
|
if (this.sections[section][index + x].srcset) {
|
|
360
|
-
this.imgs[index + x].setAttribute(
|
|
413
|
+
this.imgs[index + x].setAttribute(
|
|
414
|
+
'srcset',
|
|
415
|
+
this.sections[section][index + x].srcset
|
|
416
|
+
)
|
|
361
417
|
}
|
|
362
418
|
} else {
|
|
363
419
|
break
|
|
@@ -367,7 +423,10 @@ export default class Lightbox {
|
|
|
367
423
|
this.nextImage = this.imgs[index]
|
|
368
424
|
this.nextImage.src = this.sections[section][index].href
|
|
369
425
|
if (this.sections[section][index].srcset) {
|
|
370
|
-
this.nextImage.setAttribute(
|
|
426
|
+
this.nextImage.setAttribute(
|
|
427
|
+
'srcset',
|
|
428
|
+
this.sections[section][index].srcset
|
|
429
|
+
)
|
|
371
430
|
}
|
|
372
431
|
|
|
373
432
|
this.opts.onImageIn(this)
|
|
@@ -1,9 +1,22 @@
|
|
|
1
|
-
import { gsap } from 'gsap'
|
|
2
|
-
import { ScrollToPlugin } from 'gsap/ScrollToPlugin'
|
|
1
|
+
import { gsap, ScrollToPlugin } from 'gsap/all'
|
|
3
2
|
import _defaultsDeep from 'lodash.defaultsdeep'
|
|
4
3
|
|
|
5
4
|
gsap.registerPlugin(ScrollToPlugin)
|
|
6
5
|
|
|
6
|
+
/**
|
|
7
|
+
* @typedef {Object} LinksOptions
|
|
8
|
+
* @property {boolean} [triggerEvents=true] - Whether to trigger events when scrolling
|
|
9
|
+
* @property {number} [scrollDuration=0.8] - Duration of scroll animation
|
|
10
|
+
* @property {boolean} [scrollOffsetNav=false] - Whether to offset scroll for nav header
|
|
11
|
+
* @property {number} [mobileMenuDelay=800] - Delay for mobile menu before scrolling
|
|
12
|
+
* @property {boolean} [openExternalInWindow=true] - Whether to open external links in new window
|
|
13
|
+
* @property {string} [linkQuery] - Query selector for regular links
|
|
14
|
+
* @property {string} [anchorQuery] - Query selector for anchor links
|
|
15
|
+
* @property {Function} [onAnchor] - Called when an anchor link is clicked
|
|
16
|
+
* @property {Function} [onTransition] - Called when transitioning between pages
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/** @type {LinksOptions} */
|
|
7
20
|
const DEFAULT_OPTIONS = {
|
|
8
21
|
triggerEvents: true,
|
|
9
22
|
scrollDuration: 0.8,
|
|
@@ -82,7 +95,15 @@ const DEFAULT_OPTIONS = {
|
|
|
82
95
|
},
|
|
83
96
|
}
|
|
84
97
|
|
|
98
|
+
/**
|
|
99
|
+
* Links handler for navigation and transitions
|
|
100
|
+
*/
|
|
85
101
|
export default class Links {
|
|
102
|
+
/**
|
|
103
|
+
* Create a new Links instance
|
|
104
|
+
* @param {Object} app - Application instance
|
|
105
|
+
* @param {LinksOptions} [opts={}] - Links options
|
|
106
|
+
*/
|
|
86
107
|
constructor(app, opts = {}) {
|
|
87
108
|
this.app = app
|
|
88
109
|
this.opts = _defaultsDeep(opts, DEFAULT_OPTIONS)
|
|
@@ -1,7 +1,20 @@
|
|
|
1
|
-
import { gsap } from 'gsap'
|
|
1
|
+
import { gsap } from 'gsap/all'
|
|
2
2
|
import _defaultsDeep from 'lodash.defaultsdeep'
|
|
3
3
|
import * as Events from '../../events'
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* @typedef {Object} MobileMenuOptions
|
|
7
|
+
* @property {string} [logoColor='#000'] - Color for logo when menu is open
|
|
8
|
+
* @property {string} [logoPathSelector='svg path'] - Selector for logo SVG paths
|
|
9
|
+
* @property {string} [contentSelector='section'] - Selector for menu content
|
|
10
|
+
* @property {string} [liSelector='li'] - Selector for menu items
|
|
11
|
+
* @property {string} [hamburgerColor='#000'] - Color for hamburger icon
|
|
12
|
+
* @property {Function|null} [onResize=null] - Called when window is resized
|
|
13
|
+
* @property {Function} [openTween] - Animation for opening menu
|
|
14
|
+
* @property {Function} [closeTween] - Animation for closing menu
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/** @type {MobileMenuOptions} */
|
|
5
18
|
const DEFAULT_OPTIONS = {
|
|
6
19
|
logoColor: '#000',
|
|
7
20
|
logoPathSelector: 'svg path',
|
|
@@ -10,7 +23,7 @@ const DEFAULT_OPTIONS = {
|
|
|
10
23
|
hamburgerColor: '#000',
|
|
11
24
|
|
|
12
25
|
onResize: null,
|
|
13
|
-
openTween: m => {
|
|
26
|
+
openTween: (m) => {
|
|
14
27
|
const timeline = gsap.timeline()
|
|
15
28
|
|
|
16
29
|
m.hamburger.classList.toggle('is-active')
|
|
@@ -23,12 +36,12 @@ const DEFAULT_OPTIONS = {
|
|
|
23
36
|
duration: 0.35,
|
|
24
37
|
x: '0%',
|
|
25
38
|
opacity: 0,
|
|
26
|
-
height: window.innerHeight
|
|
39
|
+
height: window.innerHeight,
|
|
27
40
|
},
|
|
28
41
|
{
|
|
29
42
|
duration: 0.35,
|
|
30
43
|
opacity: 1,
|
|
31
|
-
ease: 'sine.in'
|
|
44
|
+
ease: 'sine.in',
|
|
32
45
|
}
|
|
33
46
|
)
|
|
34
47
|
.to(
|
|
@@ -36,7 +49,7 @@ const DEFAULT_OPTIONS = {
|
|
|
36
49
|
{
|
|
37
50
|
duration: 0.35,
|
|
38
51
|
opacity: 0,
|
|
39
|
-
ease: 'power3.out'
|
|
52
|
+
ease: 'power3.out',
|
|
40
53
|
},
|
|
41
54
|
'-=0.35'
|
|
42
55
|
)
|
|
@@ -45,7 +58,7 @@ const DEFAULT_OPTIONS = {
|
|
|
45
58
|
{
|
|
46
59
|
duration: 0.55,
|
|
47
60
|
backgroundColor: 'transparent',
|
|
48
|
-
ease: 'power3.out'
|
|
61
|
+
ease: 'power3.out',
|
|
49
62
|
},
|
|
50
63
|
'-=0.35'
|
|
51
64
|
)
|
|
@@ -61,13 +74,13 @@ const DEFAULT_OPTIONS = {
|
|
|
61
74
|
{
|
|
62
75
|
duration: 1,
|
|
63
76
|
opacity: 0,
|
|
64
|
-
x: 20
|
|
77
|
+
x: 20,
|
|
65
78
|
},
|
|
66
79
|
{
|
|
67
80
|
duration: 1,
|
|
68
81
|
x: 0,
|
|
69
82
|
opacity: 1,
|
|
70
|
-
ease: 'power3.out'
|
|
83
|
+
ease: 'power3.out',
|
|
71
84
|
},
|
|
72
85
|
0.05
|
|
73
86
|
)
|
|
@@ -77,14 +90,14 @@ const DEFAULT_OPTIONS = {
|
|
|
77
90
|
duration: 0.55,
|
|
78
91
|
opacity: 1,
|
|
79
92
|
xPercent: 0,
|
|
80
|
-
ease: 'power3.inOut'
|
|
93
|
+
ease: 'power3.inOut',
|
|
81
94
|
},
|
|
82
95
|
'-=1.2'
|
|
83
96
|
)
|
|
84
97
|
.call(m._emitMobileMenuOpenEvent)
|
|
85
98
|
},
|
|
86
99
|
|
|
87
|
-
closeTween: m => {
|
|
100
|
+
closeTween: (m) => {
|
|
88
101
|
document.body.classList.toggle('open-menu')
|
|
89
102
|
const timeline = gsap.timeline()
|
|
90
103
|
|
|
@@ -97,13 +110,13 @@ const DEFAULT_OPTIONS = {
|
|
|
97
110
|
{
|
|
98
111
|
duration: 0.2,
|
|
99
112
|
opacity: 1,
|
|
100
|
-
xPercent: 0
|
|
113
|
+
xPercent: 0,
|
|
101
114
|
},
|
|
102
115
|
{
|
|
103
116
|
duration: 0.2,
|
|
104
117
|
opacity: 0,
|
|
105
118
|
xPercent: 5,
|
|
106
|
-
ease: 'power3.out'
|
|
119
|
+
ease: 'power3.out',
|
|
107
120
|
}
|
|
108
121
|
)
|
|
109
122
|
.set(m.logoPath, { clearProps: 'fill' })
|
|
@@ -113,7 +126,7 @@ const DEFAULT_OPTIONS = {
|
|
|
113
126
|
duration: 0.5,
|
|
114
127
|
opacity: 0,
|
|
115
128
|
x: 20,
|
|
116
|
-
ease: 'power3.out'
|
|
129
|
+
ease: 'power3.out',
|
|
117
130
|
},
|
|
118
131
|
0.04
|
|
119
132
|
)
|
|
@@ -123,7 +136,7 @@ const DEFAULT_OPTIONS = {
|
|
|
123
136
|
{
|
|
124
137
|
duration: 0.25,
|
|
125
138
|
x: '100%',
|
|
126
|
-
ease: 'sine.in'
|
|
139
|
+
ease: 'sine.in',
|
|
127
140
|
},
|
|
128
141
|
'-=0.3'
|
|
129
142
|
)
|
|
@@ -138,12 +151,20 @@ const DEFAULT_OPTIONS = {
|
|
|
138
151
|
.to(m.logo, {
|
|
139
152
|
duration: 0.35,
|
|
140
153
|
opacity: 1,
|
|
141
|
-
ease: 'power3.in'
|
|
154
|
+
ease: 'power3.in',
|
|
142
155
|
})
|
|
143
|
-
}
|
|
156
|
+
},
|
|
144
157
|
}
|
|
145
158
|
|
|
159
|
+
/**
|
|
160
|
+
* MobileMenu component for mobile navigation menu
|
|
161
|
+
*/
|
|
146
162
|
export default class MobileMenu {
|
|
163
|
+
/**
|
|
164
|
+
* Create a new MobileMenu instance
|
|
165
|
+
* @param {Object} app - Application instance
|
|
166
|
+
* @param {MobileMenuOptions} [opts={}] - MobileMenu options
|
|
167
|
+
*/
|
|
147
168
|
constructor(app, opts = {}) {
|
|
148
169
|
this.app = app
|
|
149
170
|
this.opts = _defaultsDeep(opts, DEFAULT_OPTIONS)
|
|
@@ -152,9 +173,13 @@ export default class MobileMenu {
|
|
|
152
173
|
this.header = document.querySelector('header')
|
|
153
174
|
this.bg = this.header.querySelector('.mobile-bg')
|
|
154
175
|
this.logo = this.header.querySelector('figure.brand')
|
|
155
|
-
this.logoPath = this.logo
|
|
176
|
+
this.logoPath = this.logo
|
|
177
|
+
? this.logo.querySelectorAll(this.opts.logoPathSelector)
|
|
178
|
+
: null
|
|
156
179
|
this.menuButton = this.header.querySelector('figure.menu-button')
|
|
157
|
-
this.hamburger = this.menuButton
|
|
180
|
+
this.hamburger = this.menuButton
|
|
181
|
+
? this.menuButton.querySelector('.hamburger')
|
|
182
|
+
: null
|
|
158
183
|
this.hamburgerInner = this.menuButton
|
|
159
184
|
? this.menuButton.querySelector('.hamburger-inner')
|
|
160
185
|
: null
|
|
@@ -163,7 +188,7 @@ export default class MobileMenu {
|
|
|
163
188
|
this.nav = this.header.querySelector('nav')
|
|
164
189
|
|
|
165
190
|
if (this.hamburger) {
|
|
166
|
-
this.hamburger.addEventListener('click', e => {
|
|
191
|
+
this.hamburger.addEventListener('click', (e) => {
|
|
167
192
|
e.preventDefault()
|
|
168
193
|
e.stopPropagation()
|
|
169
194
|
this.toggleMenu()
|
|
@@ -198,12 +223,16 @@ export default class MobileMenu {
|
|
|
198
223
|
}
|
|
199
224
|
|
|
200
225
|
_emitMobileMenuOpenEvent() {
|
|
201
|
-
const mobileMenuOpenEvent = new window.CustomEvent(
|
|
226
|
+
const mobileMenuOpenEvent = new window.CustomEvent(
|
|
227
|
+
Events.APPLICATION_MOBILE_MENU_OPEN
|
|
228
|
+
)
|
|
202
229
|
window.dispatchEvent(mobileMenuOpenEvent)
|
|
203
230
|
}
|
|
204
231
|
|
|
205
232
|
_emitMobileMenuClosedEvent() {
|
|
206
|
-
const mobileMenuClosedEvent = new window.CustomEvent(
|
|
233
|
+
const mobileMenuClosedEvent = new window.CustomEvent(
|
|
234
|
+
Events.APPLICATION_MOBILE_MENU_CLOSED
|
|
235
|
+
)
|
|
207
236
|
window.dispatchEvent(mobileMenuClosedEvent)
|
|
208
237
|
}
|
|
209
238
|
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Vendor imports
|
|
3
3
|
*/
|
|
4
|
-
import { gsap } from 'gsap'
|
|
5
|
-
import { CSSPlugin } from 'gsap/CSSPlugin'
|
|
4
|
+
import { gsap, CSSPlugin } from 'gsap/all'
|
|
6
5
|
import _defaultsDeep from 'lodash.defaultsdeep'
|
|
7
6
|
|
|
8
7
|
/**
|
|
@@ -16,6 +15,50 @@ import Dom from '../Dom'
|
|
|
16
15
|
|
|
17
16
|
gsap.registerPlugin(CSSPlugin)
|
|
18
17
|
|
|
18
|
+
/**
|
|
19
|
+
* @typedef {Object} MoonwalkTransition
|
|
20
|
+
* @property {Object} from - Starting properties for the transition
|
|
21
|
+
* @property {Object} to - Ending properties for the transition
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @typedef {Object} MoonwalkWalk
|
|
26
|
+
* @property {number} [startDelay=0] - Delay before the animation starts
|
|
27
|
+
* @property {number} [interval=0.15] - Time between animations in a sequence
|
|
28
|
+
* @property {number} [duration=0.65] - Duration of the animation
|
|
29
|
+
* @property {boolean|Object} [alphaTween=false] - Whether to add a separate opacity tween
|
|
30
|
+
* @property {MoonwalkTransition} transition - The transition configuration
|
|
31
|
+
* @property {string} [sectionTargets] - CSS selector for targeting elements in named sections
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @typedef {Object} MoonwalkRun
|
|
36
|
+
* @property {number} [threshold=0] - IntersectionObserver threshold
|
|
37
|
+
* @property {Function} callback - Function called when element enters viewport
|
|
38
|
+
* @property {Function} [onExit] - Function called when element exits viewport
|
|
39
|
+
* @property {boolean} [repeated=false] - Whether the run should repeat
|
|
40
|
+
* @property {string} [rootMargin] - IntersectionObserver rootMargin
|
|
41
|
+
* @property {Function} [initialize] - Function called during initialization
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @typedef {Object} MoonwalkOptions
|
|
46
|
+
* @property {string|Function} [on=Events.APPLICATION_REVEALED] - Event to trigger animations
|
|
47
|
+
* @property {number} [initialDelay=0.1] - Delay before starting animations
|
|
48
|
+
* @property {boolean} [clearLazyload=false] - Clear data-ll-srcset attributes
|
|
49
|
+
* @property {boolean} [clearNestedSections=true] - Remove nested data-moonwalk-section attributes
|
|
50
|
+
* @property {boolean} [clearNestedWalks=true] - Remove nested data-moonwalk attributes
|
|
51
|
+
* @property {boolean} [clearMoonwalkOnAnchors=true] - Disable animations when page loaded via anchor
|
|
52
|
+
* @property {boolean} [warnRunWithSection=true] - Warn when run and section on same element
|
|
53
|
+
* @property {string} [rootMargin='-10% 0%'] - Default IntersectionObserver rootMargin
|
|
54
|
+
* @property {number} [threshold=0] - Default IntersectionObserver threshold
|
|
55
|
+
* @property {boolean} [uniqueIds=false] - Generate unique IDs for moonwalk elements
|
|
56
|
+
* @property {boolean} [addIndexes=false] - Add index attributes to elements
|
|
57
|
+
* @property {Object.<string, MoonwalkRun>} [runs={}] - Run configurations
|
|
58
|
+
* @property {Object.<string, MoonwalkWalk>} walks - Walk configurations
|
|
59
|
+
*/
|
|
60
|
+
|
|
61
|
+
/** @type {MoonwalkOptions} */
|
|
19
62
|
const DEFAULT_OPTIONS = {
|
|
20
63
|
/**
|
|
21
64
|
* If your app needs to do some initialization before the
|
|
@@ -102,7 +145,15 @@ const DEFAULT_OPTIONS = {
|
|
|
102
145
|
},
|
|
103
146
|
}
|
|
104
147
|
|
|
148
|
+
/**
|
|
149
|
+
* Moonwalk animation system for scroll-based reveal animations
|
|
150
|
+
*/
|
|
105
151
|
export default class Moonwalk {
|
|
152
|
+
/**
|
|
153
|
+
* @param {Object} app - The application instance
|
|
154
|
+
* @param {MoonwalkOptions} [opts={}] - Configuration options
|
|
155
|
+
* @param {HTMLElement} [container=document.body] - Container element
|
|
156
|
+
*/
|
|
106
157
|
constructor(app, opts = {}, container = document.body) {
|
|
107
158
|
this.app = app
|
|
108
159
|
this.opts = _defaultsDeep(opts, DEFAULT_OPTIONS)
|
|
@@ -648,15 +699,56 @@ export default class Moonwalk {
|
|
|
648
699
|
* @param {*} rootMargin
|
|
649
700
|
*/
|
|
650
701
|
runObserver(run, rootMargin) {
|
|
702
|
+
// Store the previous positions of observed elements to compare for exit direction
|
|
703
|
+
const elementPositions = new WeakMap()
|
|
704
|
+
|
|
651
705
|
return new IntersectionObserver(
|
|
652
706
|
(entries, self) => {
|
|
653
707
|
for (let i = 0; i < entries.length; i += 1) {
|
|
654
708
|
const entry = entries[i]
|
|
709
|
+
|
|
710
|
+
// Store the element's current position in the viewport
|
|
711
|
+
const boundingRect = entry.boundingClientRect
|
|
712
|
+
const viewportHeight = window.innerHeight
|
|
713
|
+
const viewportWidth = window.innerWidth
|
|
714
|
+
|
|
655
715
|
if (entry.isIntersecting && run.callback) {
|
|
716
|
+
// Calculate entry direction
|
|
717
|
+
let meta = { direction: null }
|
|
718
|
+
|
|
719
|
+
// Use the app's scroll direction for reliable detection
|
|
720
|
+
// If scrollDirection is null, the element was likely revealed on initial load
|
|
721
|
+
if (this.app.state && this.app.state.scrollDirection) {
|
|
722
|
+
// Map scroll direction to viewport entry direction
|
|
723
|
+
switch (this.app.state.scrollDirection) {
|
|
724
|
+
case 'down':
|
|
725
|
+
meta.direction = 'bottom' // When scrolling down, elements enter from bottom
|
|
726
|
+
break
|
|
727
|
+
case 'up':
|
|
728
|
+
meta.direction = 'top' // When scrolling up, elements enter from top
|
|
729
|
+
break
|
|
730
|
+
case 'right':
|
|
731
|
+
meta.direction = 'left' // When scrolling right, elements enter from left
|
|
732
|
+
break
|
|
733
|
+
case 'left':
|
|
734
|
+
meta.direction = 'right' // When scrolling left, elements enter from right
|
|
735
|
+
break
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
// If no scroll direction is available, direction remains null
|
|
739
|
+
|
|
740
|
+
// Store the element's position when it enters the viewport
|
|
741
|
+
elementPositions.set(entry.target, {
|
|
742
|
+
top: boundingRect.top,
|
|
743
|
+
bottom: boundingRect.bottom,
|
|
744
|
+
left: boundingRect.left,
|
|
745
|
+
right: boundingRect.right
|
|
746
|
+
})
|
|
747
|
+
|
|
656
748
|
const runRepeated = entry.target.hasAttribute(
|
|
657
749
|
'data-moonwalk-run-triggered'
|
|
658
750
|
)
|
|
659
|
-
run.callback(entry.target, runRepeated)
|
|
751
|
+
run.callback(entry.target, runRepeated, meta)
|
|
660
752
|
entry.target.setAttribute('data-moonwalk-run-triggered', '')
|
|
661
753
|
if (!run.onExit && !run.repeated) {
|
|
662
754
|
self.unobserve(entry.target)
|
|
@@ -670,7 +762,42 @@ export default class Moonwalk {
|
|
|
670
762
|
'data-moonwalk-run-exit-triggered'
|
|
671
763
|
)
|
|
672
764
|
entry.target.setAttribute('data-moonwalk-run-exit-triggered', '')
|
|
673
|
-
|
|
765
|
+
|
|
766
|
+
// Calculate exit direction
|
|
767
|
+
let meta = { direction: null }
|
|
768
|
+
|
|
769
|
+
// Use the app's scroll direction for reliable detection
|
|
770
|
+
// For exit direction, it's the opposite of the entry direction for the same scroll
|
|
771
|
+
if (this.app.state && this.app.state.scrollDirection) {
|
|
772
|
+
// Map scroll direction to viewport exit direction
|
|
773
|
+
switch (this.app.state.scrollDirection) {
|
|
774
|
+
case 'down':
|
|
775
|
+
meta.direction = 'top' // When scrolling down, elements exit from top
|
|
776
|
+
break
|
|
777
|
+
case 'up':
|
|
778
|
+
meta.direction = 'bottom' // When scrolling up, elements exit from bottom
|
|
779
|
+
break
|
|
780
|
+
case 'right':
|
|
781
|
+
meta.direction = 'right' // When scrolling right, elements exit from right
|
|
782
|
+
break
|
|
783
|
+
case 'left':
|
|
784
|
+
meta.direction = 'left' // When scrolling left, elements exit from left
|
|
785
|
+
break
|
|
786
|
+
}
|
|
787
|
+
} else {
|
|
788
|
+
// If no scroll direction is available, use the simplest position-based check
|
|
789
|
+
if (boundingRect.bottom <= 0) {
|
|
790
|
+
meta.direction = 'top'
|
|
791
|
+
} else if (boundingRect.top >= viewportHeight) {
|
|
792
|
+
meta.direction = 'bottom'
|
|
793
|
+
} else if (boundingRect.right <= 0) {
|
|
794
|
+
meta.direction = 'left'
|
|
795
|
+
} else if (boundingRect.left >= viewportWidth) {
|
|
796
|
+
meta.direction = 'right'
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
run.onExit(entry.target, runExited, meta)
|
|
674
801
|
if (!run.repeated) {
|
|
675
802
|
self.unobserve(entry.target)
|
|
676
803
|
}
|