@brandocms/jupiter 3.54.4 → 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 +37 -5
- 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,7 +1,26 @@
|
|
|
1
|
-
import { gsap } from 'gsap'
|
|
1
|
+
import { gsap } from 'gsap/all'
|
|
2
2
|
import _defaultsDeep from 'lodash.defaultsdeep'
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* @typedef {Object} PopupOptions
|
|
6
|
+
* @property {string} [selector] - CSS selector to find popup elements
|
|
7
|
+
* @property {Function} [responsive] - Function that determines if popup should be shown on current breakpoint
|
|
8
|
+
* @property {Function} [onOpen] - Called when popup opens
|
|
9
|
+
* @property {Function} [onClose] - Called when popup closes
|
|
10
|
+
* @property {Function} [tweenIn] - Animation function for opening popup
|
|
11
|
+
* @property {Function} [tweenOut] - Animation function for closing popup
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/** @type {PopupOptions} */
|
|
4
15
|
const DEFAULT_OPTIONS = {
|
|
16
|
+
/**
|
|
17
|
+
* selector
|
|
18
|
+
*
|
|
19
|
+
* CSS selector to find popup elements
|
|
20
|
+
* Default: '[data-popup]'
|
|
21
|
+
*/
|
|
22
|
+
selector: '[data-popup]',
|
|
23
|
+
|
|
5
24
|
/**
|
|
6
25
|
* responsive
|
|
7
26
|
*
|
|
@@ -30,104 +49,211 @@ const DEFAULT_OPTIONS = {
|
|
|
30
49
|
x: -5,
|
|
31
50
|
xPercent: -50,
|
|
32
51
|
opacity: 0,
|
|
33
|
-
display: 'block'
|
|
52
|
+
display: 'block',
|
|
34
53
|
},
|
|
35
54
|
{
|
|
36
55
|
duration: 0.3,
|
|
37
56
|
yPercent: -50,
|
|
38
57
|
xPercent: -50,
|
|
39
58
|
x: 0,
|
|
40
|
-
opacity: 1
|
|
59
|
+
opacity: 1,
|
|
41
60
|
}
|
|
42
61
|
)
|
|
43
|
-
}
|
|
62
|
+
},
|
|
44
63
|
})
|
|
45
64
|
},
|
|
46
65
|
|
|
47
|
-
tweenOut: popup => {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
66
|
+
tweenOut: (popup) => {
|
|
67
|
+
console.log('default tweenOut')
|
|
68
|
+
const popupElement = popup.currentPopup
|
|
69
|
+
if (popupElement) {
|
|
70
|
+
gsap.to(popupElement, {
|
|
71
|
+
duration: 0.3,
|
|
72
|
+
opacity: 0,
|
|
73
|
+
display: 'none',
|
|
74
|
+
})
|
|
75
|
+
}
|
|
54
76
|
gsap.to(popup.backdrop, {
|
|
55
77
|
duration: 0.3,
|
|
56
78
|
opacity: 0,
|
|
57
79
|
onComplete: () => {
|
|
58
|
-
|
|
59
|
-
|
|
80
|
+
// Remove the backdrop completely instead of just hiding it
|
|
81
|
+
popup.backdrop.remove()
|
|
82
|
+
},
|
|
60
83
|
})
|
|
61
|
-
}
|
|
84
|
+
},
|
|
62
85
|
}
|
|
63
86
|
|
|
87
|
+
/**
|
|
88
|
+
* Popup component for modal dialogs and popups
|
|
89
|
+
*/
|
|
64
90
|
export default class Popup {
|
|
65
|
-
|
|
91
|
+
/**
|
|
92
|
+
* Create a new Popup instance
|
|
93
|
+
* @param {Object} app - Application instance
|
|
94
|
+
* @param {string} [selector] - CSS selector to find popup elements
|
|
95
|
+
* @param {PopupOptions} [opts={}] - Popup options
|
|
96
|
+
*/
|
|
97
|
+
constructor(app, selector = '[data-popup]', opts = {}) {
|
|
66
98
|
this.app = app
|
|
67
99
|
this.opts = _defaultsDeep(opts, DEFAULT_OPTIONS)
|
|
68
|
-
this.
|
|
100
|
+
this.opts.selector = selector
|
|
101
|
+
this.backdrop = null
|
|
102
|
+
this.currentPopup = null
|
|
103
|
+
this.popupKey = null
|
|
69
104
|
this.bindTriggers()
|
|
70
105
|
}
|
|
71
106
|
|
|
107
|
+
/**
|
|
108
|
+
* Bind click handlers to popup triggers and close buttons
|
|
109
|
+
*/
|
|
72
110
|
bindTriggers() {
|
|
73
|
-
|
|
74
|
-
const
|
|
111
|
+
// Find all triggers that match this popup's selector
|
|
112
|
+
const allTriggers = document.querySelectorAll('[data-popup-trigger]')
|
|
113
|
+
const matchingTriggers = Array.from(allTriggers).filter(trigger => {
|
|
114
|
+
const target = trigger.getAttribute('data-popup-trigger')
|
|
115
|
+
if (typeof target === 'string') {
|
|
116
|
+
const element = document.querySelector(target)
|
|
117
|
+
return element && element.matches(this.opts.selector)
|
|
118
|
+
}
|
|
119
|
+
return false
|
|
120
|
+
})
|
|
75
121
|
|
|
76
|
-
|
|
122
|
+
// Get all popups that match this instance's selector
|
|
123
|
+
const popups = document.querySelectorAll(this.opts.selector)
|
|
124
|
+
|
|
125
|
+
// Find all close buttons inside matching popups
|
|
126
|
+
const closers = []
|
|
127
|
+
popups.forEach(popup => {
|
|
128
|
+
const popupClosers = popup.querySelectorAll('[data-popup-close]')
|
|
129
|
+
closers.push(...popupClosers)
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
// Bind click handlers to matching triggers
|
|
133
|
+
matchingTriggers.forEach((trigger) => {
|
|
77
134
|
const triggerTarget = trigger.getAttribute('data-popup-trigger')
|
|
78
|
-
|
|
135
|
+
// Get the popup key if present
|
|
136
|
+
const popupKey = trigger.getAttribute('data-popup-key') || this.getKeyFromTarget(triggerTarget)
|
|
137
|
+
|
|
138
|
+
trigger.addEventListener('click', (event) => {
|
|
79
139
|
if (this.opts.responsive(this.app)) {
|
|
80
140
|
event.stopImmediatePropagation()
|
|
81
141
|
event.preventDefault()
|
|
82
|
-
this.open(trigger, triggerTarget)
|
|
142
|
+
this.open(trigger, triggerTarget, popupKey)
|
|
83
143
|
}
|
|
84
144
|
})
|
|
85
145
|
})
|
|
86
146
|
|
|
87
|
-
|
|
88
|
-
|
|
147
|
+
// Bind click handlers to close buttons
|
|
148
|
+
closers.forEach((closer) => {
|
|
149
|
+
// Get the popup key from the closest parent popup element
|
|
150
|
+
const popupElement = closer.closest(this.opts.selector)
|
|
151
|
+
const popupKey = popupElement ? popupElement.getAttribute('data-popup-key') : null
|
|
152
|
+
|
|
153
|
+
closer.addEventListener('click', (event) => {
|
|
89
154
|
event.stopImmediatePropagation()
|
|
90
155
|
event.preventDefault()
|
|
91
|
-
|
|
92
|
-
|
|
156
|
+
|
|
157
|
+
// Only close if keys match or no key is set
|
|
158
|
+
if (!this.popupKey || !popupKey || this.popupKey === popupKey) {
|
|
159
|
+
this.opts.onClose(this)
|
|
160
|
+
this.close()
|
|
161
|
+
}
|
|
93
162
|
})
|
|
94
163
|
})
|
|
95
164
|
}
|
|
96
165
|
|
|
97
|
-
|
|
166
|
+
/**
|
|
167
|
+
* Extract key from target selector or element
|
|
168
|
+
* @param {HTMLElement|string} target - Target element or selector
|
|
169
|
+
* @returns {string|null} - The popup key or null
|
|
170
|
+
*/
|
|
171
|
+
getKeyFromTarget(target) {
|
|
172
|
+
if (typeof target === 'string') {
|
|
173
|
+
const element = document.querySelector(target)
|
|
174
|
+
return element ? element.getAttribute('data-popup-key') : null
|
|
175
|
+
} else if (target instanceof HTMLElement) {
|
|
176
|
+
return target.getAttribute('data-popup-key')
|
|
177
|
+
}
|
|
178
|
+
return null
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Create backdrop element for popup
|
|
183
|
+
* @param {string|null} key - Optional popup key to associate with backdrop
|
|
184
|
+
* @returns {HTMLElement} The created backdrop element
|
|
185
|
+
*/
|
|
186
|
+
createBackdrop(key) {
|
|
98
187
|
const backdrop = document.createElement('div')
|
|
99
188
|
backdrop.setAttribute('data-popup-backdrop', '')
|
|
189
|
+
if (key) {
|
|
190
|
+
backdrop.setAttribute('data-popup-key', key)
|
|
191
|
+
}
|
|
100
192
|
gsap.set(backdrop, { opacity: 0, display: 'none', zIndex: 4999 })
|
|
101
193
|
|
|
102
|
-
backdrop.addEventListener('click', e => {
|
|
194
|
+
backdrop.addEventListener('click', (e) => {
|
|
103
195
|
e.stopPropagation()
|
|
104
196
|
this.close()
|
|
105
197
|
})
|
|
106
198
|
|
|
107
199
|
document.body.append(backdrop)
|
|
108
|
-
|
|
200
|
+
return backdrop
|
|
109
201
|
}
|
|
110
202
|
|
|
111
|
-
|
|
203
|
+
/**
|
|
204
|
+
* Open a popup
|
|
205
|
+
* @param {HTMLElement} trigger - Element that triggered the popup
|
|
206
|
+
* @param {HTMLElement|string} target - Popup element or selector
|
|
207
|
+
* @param {string|null} key - Optional popup key
|
|
208
|
+
*/
|
|
209
|
+
open(trigger, target, key = null) {
|
|
112
210
|
this.keyUpListener = this.onKeyup.bind(this)
|
|
113
211
|
document.addEventListener('keyup', this.keyUpListener)
|
|
212
|
+
|
|
213
|
+
// Store the popup key
|
|
214
|
+
this.popupKey = key || this.getKeyFromTarget(target)
|
|
215
|
+
|
|
216
|
+
// Create a new backdrop for this popup
|
|
217
|
+
this.backdrop = this.createBackdrop(this.popupKey)
|
|
218
|
+
|
|
114
219
|
if (typeof target === 'string') {
|
|
115
220
|
target = document.querySelector(target)
|
|
116
221
|
}
|
|
117
222
|
|
|
118
223
|
if (!target) {
|
|
119
224
|
console.error(`JUPITER/POPUP >>> Element ${target} not found`)
|
|
225
|
+
return
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Store the current popup element for reference
|
|
229
|
+
this.currentPopup = target
|
|
230
|
+
|
|
231
|
+
// If key isn't already set on the popup element, set it now
|
|
232
|
+
if (this.popupKey && !target.hasAttribute('data-popup-key')) {
|
|
233
|
+
target.setAttribute('data-popup-key', this.popupKey)
|
|
120
234
|
}
|
|
235
|
+
|
|
121
236
|
this.opts.onOpen(trigger, target, this)
|
|
122
237
|
this.opts.tweenIn(trigger, target, this)
|
|
123
238
|
}
|
|
124
239
|
|
|
240
|
+
/**
|
|
241
|
+
* Close the popup
|
|
242
|
+
*/
|
|
125
243
|
close() {
|
|
126
244
|
document.removeEventListener('keyup', this.keyUpListener)
|
|
127
245
|
this.opts.onClose(this)
|
|
128
246
|
this.opts.tweenOut(this)
|
|
247
|
+
|
|
248
|
+
// Reset popup state
|
|
249
|
+
this.popupKey = null
|
|
250
|
+
this.currentPopup = null
|
|
129
251
|
}
|
|
130
252
|
|
|
253
|
+
/**
|
|
254
|
+
* Handle keyup event for Escape key to close popup
|
|
255
|
+
* @param {KeyboardEvent} e - Keyboard event
|
|
256
|
+
*/
|
|
131
257
|
onKeyup(e) {
|
|
132
258
|
const key = e.keyCode || e.which
|
|
133
259
|
|
|
@@ -1,17 +1,34 @@
|
|
|
1
1
|
import _defaultsDeep from 'lodash.defaultsdeep'
|
|
2
2
|
import Dom from '../Dom'
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* @typedef {Object} ScrollSpyOptions
|
|
6
|
+
* @property {Function} [onIntersect] - Called when a target intersects with the viewport
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/** @type {ScrollSpyOptions} */
|
|
4
10
|
const DEFAULT_OPTIONS = {
|
|
5
11
|
onIntersect: (target, trigger) => {}
|
|
6
12
|
}
|
|
7
13
|
|
|
14
|
+
/**
|
|
15
|
+
* ScrollSpy component for highlighting active sections during scrolling
|
|
16
|
+
*/
|
|
8
17
|
export default class ScrollSpy {
|
|
18
|
+
/**
|
|
19
|
+
* Create a new ScrollSpy instance
|
|
20
|
+
* @param {Object} app - Application instance
|
|
21
|
+
* @param {ScrollSpyOptions} [opts={}] - ScrollSpy options
|
|
22
|
+
*/
|
|
9
23
|
constructor(app, opts = {}) {
|
|
10
24
|
this.app = app
|
|
11
25
|
this.opts = _defaultsDeep(opts, DEFAULT_OPTIONS)
|
|
12
26
|
this.initialize()
|
|
13
27
|
}
|
|
14
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Initialize ScrollSpy
|
|
31
|
+
*/
|
|
15
32
|
initialize() {
|
|
16
33
|
this.triggers = Dom.all('[data-scrollspy-trigger]')
|
|
17
34
|
const config = {
|
|
@@ -29,6 +46,10 @@ export default class ScrollSpy {
|
|
|
29
46
|
this.triggers.forEach(section => observer.observe(section))
|
|
30
47
|
}
|
|
31
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Handle intersection with viewport
|
|
51
|
+
* @param {IntersectionObserverEntry} entry - Intersection observer entry
|
|
52
|
+
*/
|
|
32
53
|
intersectionHandler(entry) {
|
|
33
54
|
const id = entry.target.dataset.scrollspyTrigger
|
|
34
55
|
const currentlyActive = document.querySelector('[data-scrollspy-active]')
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { gsap } from 'gsap'
|
|
1
|
+
import { gsap } from 'gsap/all'
|
|
2
2
|
import _defaultsDeep from 'lodash.defaultsdeep'
|
|
3
3
|
|
|
4
4
|
const DEFAULT_OPTIONS = {}
|
|
@@ -13,14 +13,14 @@ export default class StackedBoxes {
|
|
|
13
13
|
initialize() {
|
|
14
14
|
const boxes = document.querySelectorAll('[data-boxes-stacked]')
|
|
15
15
|
|
|
16
|
-
const observer = new IntersectionObserver(entries => {
|
|
16
|
+
const observer = new IntersectionObserver((entries) => {
|
|
17
17
|
const [{ isIntersecting, target }] = entries
|
|
18
18
|
if (isIntersecting) {
|
|
19
19
|
this.adjustBox(target)
|
|
20
20
|
}
|
|
21
21
|
})
|
|
22
22
|
|
|
23
|
-
Array.from(boxes).forEach(box => {
|
|
23
|
+
Array.from(boxes).forEach((box) => {
|
|
24
24
|
observer.observe(box)
|
|
25
25
|
})
|
|
26
26
|
}
|
|
@@ -53,7 +53,9 @@ export default class StackedBoxes {
|
|
|
53
53
|
break
|
|
54
54
|
|
|
55
55
|
default:
|
|
56
|
-
console.error(
|
|
56
|
+
console.error(
|
|
57
|
+
'==> JUPITER/STACKEDBOXES: `data-boxes-stacked-pull` has wrong value'
|
|
58
|
+
)
|
|
57
59
|
}
|
|
58
60
|
this.pull(pull, pullPx)
|
|
59
61
|
}
|
|
@@ -23,36 +23,36 @@
|
|
|
23
23
|
*
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
|
-
import { gsap } from 'gsap'
|
|
26
|
+
import { gsap } from 'gsap/all'
|
|
27
27
|
import _defaultsDeep from 'lodash.defaultsdeep'
|
|
28
28
|
import * as Events from '../../events'
|
|
29
29
|
|
|
30
30
|
const DEFAULT_EVENTS = {
|
|
31
|
-
onMainVisible: h => {
|
|
31
|
+
onMainVisible: (h) => {
|
|
32
32
|
gsap.to(h.el, {
|
|
33
33
|
duration: 3,
|
|
34
34
|
opacity: 1,
|
|
35
|
-
delay: 0.5
|
|
35
|
+
delay: 0.5,
|
|
36
36
|
})
|
|
37
37
|
},
|
|
38
38
|
|
|
39
|
-
onMainInvisible: h => {
|
|
39
|
+
onMainInvisible: (h) => {
|
|
40
40
|
gsap.to(h.el, {
|
|
41
41
|
duration: 1,
|
|
42
|
-
opacity: 0
|
|
42
|
+
opacity: 0,
|
|
43
43
|
})
|
|
44
44
|
},
|
|
45
45
|
|
|
46
|
-
onPin: h => {
|
|
46
|
+
onPin: (h) => {
|
|
47
47
|
gsap.to(h.auxEl, {
|
|
48
48
|
duration: 0.35,
|
|
49
49
|
yPercent: '0',
|
|
50
50
|
ease: 'sine.out',
|
|
51
|
-
autoRound: true
|
|
51
|
+
autoRound: true,
|
|
52
52
|
})
|
|
53
53
|
},
|
|
54
54
|
|
|
55
|
-
onUnpin: h => {
|
|
55
|
+
onUnpin: (h) => {
|
|
56
56
|
h._hiding = true
|
|
57
57
|
gsap.to(h.auxEl, {
|
|
58
58
|
duration: 0.25,
|
|
@@ -61,10 +61,10 @@ const DEFAULT_EVENTS = {
|
|
|
61
61
|
autoRound: true,
|
|
62
62
|
onComplete: () => {
|
|
63
63
|
h._hiding = false
|
|
64
|
-
}
|
|
64
|
+
},
|
|
65
65
|
})
|
|
66
66
|
},
|
|
67
|
-
onSmall: () => {}
|
|
67
|
+
onSmall: () => {},
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
const DEFAULT_OPTIONS = {
|
|
@@ -75,12 +75,12 @@ const DEFAULT_OPTIONS = {
|
|
|
75
75
|
unPinOnResize: false,
|
|
76
76
|
|
|
77
77
|
default: {
|
|
78
|
-
onClone: h => h.el.cloneNode(true),
|
|
78
|
+
onClone: (h) => h.el.cloneNode(true),
|
|
79
79
|
canvas: window,
|
|
80
|
-
beforeEnter: h => {
|
|
80
|
+
beforeEnter: (h) => {
|
|
81
81
|
gsap.set(h.el, { opacity: 0 })
|
|
82
82
|
},
|
|
83
|
-
enter: h => {
|
|
83
|
+
enter: (h) => {
|
|
84
84
|
const timeline = gsap.timeline()
|
|
85
85
|
timeline
|
|
86
86
|
.set(h.auxEl, { yPercent: -100 })
|
|
@@ -89,7 +89,7 @@ const DEFAULT_OPTIONS = {
|
|
|
89
89
|
yPercent: 0,
|
|
90
90
|
delay: h.opts.enterDelay,
|
|
91
91
|
ease: 'power3.out',
|
|
92
|
-
autoRound: true
|
|
92
|
+
autoRound: true,
|
|
93
93
|
})
|
|
94
94
|
.staggerTo(h.lis, 0.8, { opacity: 1, ease: 'sine.in' }, 0.1, '-=1')
|
|
95
95
|
},
|
|
@@ -98,8 +98,8 @@ const DEFAULT_OPTIONS = {
|
|
|
98
98
|
offset: 0, // how far from the top before we trigger hide
|
|
99
99
|
offsetSmall: 50, // how far from the top before we trigger the shrinked padding,
|
|
100
100
|
offsetBg: 200, // how far down before changing backgroundcolor
|
|
101
|
-
...DEFAULT_EVENTS
|
|
102
|
-
}
|
|
101
|
+
...DEFAULT_EVENTS,
|
|
102
|
+
},
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
export default class StickyHeader {
|
|
@@ -174,14 +174,18 @@ export default class StickyHeader {
|
|
|
174
174
|
this._bindMobileMenuListeners()
|
|
175
175
|
|
|
176
176
|
if (this.opts.unPinOnResize) {
|
|
177
|
-
window.addEventListener(
|
|
177
|
+
window.addEventListener(
|
|
178
|
+
Events.APPLICATION_RESIZE,
|
|
179
|
+
this.setResizeTimer.bind(this),
|
|
180
|
+
false
|
|
181
|
+
)
|
|
178
182
|
}
|
|
179
183
|
|
|
180
184
|
this.opts.beforeEnter(this)
|
|
181
185
|
}
|
|
182
186
|
|
|
183
187
|
setupObserver() {
|
|
184
|
-
this.observer = new IntersectionObserver(entries => {
|
|
188
|
+
this.observer = new IntersectionObserver((entries) => {
|
|
185
189
|
const [{ isIntersecting }] = entries
|
|
186
190
|
|
|
187
191
|
if (isIntersecting) {
|
|
@@ -200,7 +204,11 @@ export default class StickyHeader {
|
|
|
200
204
|
}
|
|
201
205
|
})
|
|
202
206
|
|
|
203
|
-
window.addEventListener(
|
|
207
|
+
window.addEventListener(
|
|
208
|
+
Events.APPLICATION_SCROLL,
|
|
209
|
+
this.update.bind(this),
|
|
210
|
+
false
|
|
211
|
+
)
|
|
204
212
|
|
|
205
213
|
if (this.mainOpts.pinOnForcedScroll) {
|
|
206
214
|
window.addEventListener(Events.APPLICATION_FORCED_SCROLL_START, () => {
|
|
@@ -292,7 +300,10 @@ export default class StickyHeader {
|
|
|
292
300
|
}
|
|
293
301
|
|
|
294
302
|
checkBot(force) {
|
|
295
|
-
if (
|
|
303
|
+
if (
|
|
304
|
+
this.currentScrollY + this.getViewportHeight() >=
|
|
305
|
+
this.getScrollerHeight()
|
|
306
|
+
) {
|
|
296
307
|
if (force) {
|
|
297
308
|
this.bottom()
|
|
298
309
|
} else if (!this._bottom) {
|
|
@@ -420,7 +431,8 @@ export default class StickyHeader {
|
|
|
420
431
|
isOutOfBounds() {
|
|
421
432
|
const pastTop = this.currentScrollY < 0
|
|
422
433
|
const pastBottom =
|
|
423
|
-
this.currentScrollY + this.getScrollerPhysicalHeight() >
|
|
434
|
+
this.currentScrollY + this.getScrollerPhysicalHeight() >
|
|
435
|
+
this.getScrollerHeight()
|
|
424
436
|
|
|
425
437
|
return pastTop || pastBottom
|
|
426
438
|
}
|
|
@@ -453,7 +465,9 @@ export default class StickyHeader {
|
|
|
453
465
|
|
|
454
466
|
getViewportHeight() {
|
|
455
467
|
return (
|
|
456
|
-
window.innerHeight ||
|
|
468
|
+
window.innerHeight ||
|
|
469
|
+
document.documentElement.clientHeight ||
|
|
470
|
+
document.body.clientHeight
|
|
457
471
|
)
|
|
458
472
|
}
|
|
459
473
|
|
|
@@ -472,11 +486,18 @@ export default class StickyHeader {
|
|
|
472
486
|
if (this.opts.canvas.scrollTop !== undefined) {
|
|
473
487
|
return this.opts.canvas.scrollTop
|
|
474
488
|
}
|
|
475
|
-
return (
|
|
489
|
+
return (
|
|
490
|
+
document.documentElement ||
|
|
491
|
+
document.body.parentNode ||
|
|
492
|
+
document.body
|
|
493
|
+
).scrollTop
|
|
476
494
|
}
|
|
477
495
|
|
|
478
496
|
toleranceExceeded() {
|
|
479
|
-
return
|
|
497
|
+
return (
|
|
498
|
+
Math.abs(this.currentScrollY - this.lastKnownScrollY) >=
|
|
499
|
+
this.opts.tolerance
|
|
500
|
+
)
|
|
480
501
|
}
|
|
481
502
|
|
|
482
503
|
_getOptionsForSection(section, opts) {
|
|
@@ -1,17 +1,37 @@
|
|
|
1
|
-
import { gsap } from 'gsap'
|
|
1
|
+
import { gsap } from 'gsap/all'
|
|
2
2
|
import Dom from '../Dom'
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Toggler component for show/hide functionality
|
|
6
|
+
* Uses [data-toggle-trigger] for the toggle button and [data-toggle-content] for toggleable content
|
|
7
|
+
*/
|
|
4
8
|
export default class Toggler {
|
|
9
|
+
/**
|
|
10
|
+
* Create a new Toggler instance
|
|
11
|
+
* @param {Object} app - Application instance
|
|
12
|
+
* @param {HTMLElement} el - Container element with [data-toggle] attribute
|
|
13
|
+
*/
|
|
5
14
|
constructor(app, el) {
|
|
6
15
|
this.open = false
|
|
7
16
|
this.app = app
|
|
8
17
|
this.el = el
|
|
9
18
|
this.trigger = Dom.find(this.el, '[data-toggle-trigger]')
|
|
19
|
+
this.triggerTarget = this.trigger.dataset.toggleTrigger
|
|
20
|
+
if (this.triggerTarget) {
|
|
21
|
+
this.content = Dom.all(
|
|
22
|
+
this.el,
|
|
23
|
+
`[data-toggle-content="${this.triggerTarget}"]`
|
|
24
|
+
)
|
|
25
|
+
} else {
|
|
26
|
+
this.content = Dom.all(this.el, '[data-toggle-content]')
|
|
27
|
+
}
|
|
10
28
|
this.triggerIcon = Dom.find(this.trigger, 'span.icon')
|
|
11
|
-
this.content = Dom.find(this.el, '[data-toggle-content]')
|
|
12
29
|
this.trigger.addEventListener('click', this.onClick.bind(this))
|
|
13
30
|
}
|
|
14
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Handle click on trigger element
|
|
34
|
+
*/
|
|
15
35
|
onClick() {
|
|
16
36
|
this.toggleState()
|
|
17
37
|
|
|
@@ -21,7 +41,17 @@ export default class Toggler {
|
|
|
21
41
|
}
|
|
22
42
|
gsap.set(this.content, { height: 'auto', display: 'block' })
|
|
23
43
|
this.el.classList.toggle('open')
|
|
24
|
-
gsap.from(this.content, {
|
|
44
|
+
gsap.from(this.content, {
|
|
45
|
+
height: 0,
|
|
46
|
+
ease: 'power1.inOut',
|
|
47
|
+
stagger: 0.1,
|
|
48
|
+
onComplete: () => {
|
|
49
|
+
this.content.forEach((el) => el.removeAttribute('data-toggle-hidden'))
|
|
50
|
+
this.content.forEach((el) =>
|
|
51
|
+
el.setAttribute('data-toggle-visible', '')
|
|
52
|
+
)
|
|
53
|
+
},
|
|
54
|
+
})
|
|
25
55
|
} else {
|
|
26
56
|
if (this.triggerIcon) {
|
|
27
57
|
this.triggerIcon.classList.toggle('active')
|
|
@@ -30,13 +60,22 @@ export default class Toggler {
|
|
|
30
60
|
duration: 0.25,
|
|
31
61
|
onComplete: () => {
|
|
32
62
|
this.el.classList.toggle('open')
|
|
33
|
-
|
|
63
|
+
this.content.forEach((el) =>
|
|
64
|
+
el.removeAttribute('data-toggle-visible')
|
|
65
|
+
)
|
|
66
|
+
this.content.forEach((el) =>
|
|
67
|
+
el.setAttribute('data-toggle-hidden', '')
|
|
68
|
+
)
|
|
69
|
+
},
|
|
34
70
|
})
|
|
35
71
|
|
|
36
|
-
gsap.to(this.content, { height: 0, ease: 'power3.out' })
|
|
72
|
+
gsap.to(this.content, { height: 0, ease: 'power3.out', stagger: 0.1 })
|
|
37
73
|
}
|
|
38
74
|
}
|
|
39
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Toggle open/closed state
|
|
78
|
+
*/
|
|
40
79
|
toggleState() {
|
|
41
80
|
if (this.open) {
|
|
42
81
|
this.open = false
|