@brandocms/jupiter 3.55.0 → 4.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/README.md +509 -54
  2. package/package.json +30 -18
  3. package/src/index.js +15 -10
  4. package/src/modules/Application/index.js +236 -158
  5. package/src/modules/Breakpoints/index.js +116 -36
  6. package/src/modules/Cookies/index.js +95 -64
  7. package/src/modules/CoverOverlay/index.js +21 -14
  8. package/src/modules/Dataloader/index.js +71 -24
  9. package/src/modules/Dataloader/url-sync.js +238 -0
  10. package/src/modules/Dom/index.js +24 -0
  11. package/src/modules/DoubleHeader/index.js +571 -0
  12. package/src/modules/Dropdown/index.js +108 -73
  13. package/src/modules/EqualHeightElements/index.js +8 -8
  14. package/src/modules/EqualHeightImages/index.js +15 -7
  15. package/src/modules/FixedHeader/index.js +116 -30
  16. package/src/modules/FooterReveal/index.js +5 -5
  17. package/src/modules/HeroSlider/index.js +231 -106
  18. package/src/modules/HeroVideo/index.js +72 -44
  19. package/src/modules/Lazyload/index.js +128 -80
  20. package/src/modules/Lightbox/index.js +101 -80
  21. package/src/modules/Links/index.js +77 -51
  22. package/src/modules/Looper/index.js +1737 -0
  23. package/src/modules/Marquee/index.js +106 -37
  24. package/src/modules/MobileMenu/index.js +105 -130
  25. package/src/modules/Moonwalk/index.js +479 -153
  26. package/src/modules/Parallax/index.js +280 -57
  27. package/src/modules/Popover/index.js +187 -17
  28. package/src/modules/Popup/index.js +172 -53
  29. package/src/modules/ScrollSpy/index.js +21 -0
  30. package/src/modules/StackedBoxes/index.js +8 -6
  31. package/src/modules/StickyHeader/index.js +394 -164
  32. package/src/modules/Toggler/index.js +207 -11
  33. package/src/modules/Typography/index.js +33 -20
  34. package/src/utils/motion-helpers.js +330 -0
  35. package/types/README.md +159 -0
  36. package/types/events/index.d.ts +20 -0
  37. package/types/index.d.ts +6 -0
  38. package/types/modules/Application/index.d.ts +168 -0
  39. package/types/modules/Breakpoints/index.d.ts +40 -0
  40. package/types/modules/Cookies/index.d.ts +81 -0
  41. package/types/modules/CoverOverlay/index.d.ts +6 -0
  42. package/types/modules/Dataloader/index.d.ts +38 -0
  43. package/types/modules/Dataloader/url-sync.d.ts +36 -0
  44. package/types/modules/Dom/index.d.ts +47 -0
  45. package/types/modules/DoubleHeader/index.d.ts +63 -0
  46. package/types/modules/Dropdown/index.d.ts +15 -0
  47. package/types/modules/EqualHeightElements/index.d.ts +8 -0
  48. package/types/modules/EqualHeightImages/index.d.ts +11 -0
  49. package/types/modules/FeatureTests/index.d.ts +27 -0
  50. package/types/modules/FixedHeader/index.d.ts +219 -0
  51. package/types/modules/Fontloader/index.d.ts +5 -0
  52. package/types/modules/FooterReveal/index.d.ts +5 -0
  53. package/types/modules/HeroSlider/index.d.ts +28 -0
  54. package/types/modules/HeroVideo/index.d.ts +83 -0
  55. package/types/modules/Lazyload/index.d.ts +80 -0
  56. package/types/modules/Lightbox/index.d.ts +123 -0
  57. package/types/modules/Links/index.d.ts +55 -0
  58. package/types/modules/Looper/index.d.ts +127 -0
  59. package/types/modules/Marquee/index.d.ts +23 -0
  60. package/types/modules/MobileMenu/index.d.ts +63 -0
  61. package/types/modules/Moonwalk/index.d.ts +322 -0
  62. package/types/modules/Parallax/index.d.ts +71 -0
  63. package/types/modules/Popover/index.d.ts +29 -0
  64. package/types/modules/Popup/index.d.ts +76 -0
  65. package/types/modules/ScrollSpy/index.d.ts +29 -0
  66. package/types/modules/StackedBoxes/index.d.ts +9 -0
  67. package/types/modules/StickyHeader/index.d.ts +220 -0
  68. package/types/modules/Toggler/index.d.ts +48 -0
  69. package/types/modules/Typography/index.d.ts +77 -0
  70. package/types/utils/dispatchElementEvent.d.ts +1 -0
  71. package/types/utils/imageIsLoaded.d.ts +1 -0
  72. package/types/utils/imagesAreLoaded.d.ts +1 -0
  73. package/types/utils/loadScript.d.ts +2 -0
  74. package/types/utils/prefersReducedMotion.d.ts +4 -0
  75. package/types/utils/rafCallback.d.ts +2 -0
  76. package/types/utils/zoom.d.ts +4 -0
@@ -1,5 +1,4 @@
1
- import { gsap } from 'gsap'
2
- import { ScrollToPlugin } from 'gsap/ScrollToPlugin'
1
+ import { animate, stagger } from 'motion'
3
2
  import _defaultsDeep from 'lodash.defaultsdeep'
4
3
  import rafCallback from '../../utils/rafCallback'
5
4
  import prefersReducedMotion from '../../utils/prefersReducedMotion'
@@ -9,37 +8,57 @@ import Breakpoints from '../Breakpoints'
9
8
  import FeatureTests from '../FeatureTests'
10
9
  import Fontloader from '../Fontloader'
11
10
  import Dom from '../Dom'
11
+ import { set, clearProps } from '../../utils/motion-helpers'
12
+
13
+ window.onpageshow = event => {
14
+ // Fix for hash anchor navigation issues
15
+ // When navigating to a page with #anchor, ensure overlay is removed and content is visible
16
+ const hasHash = window.location.hash
17
+ const needsFix = event.persisted || hasHash
18
+
19
+ if (needsFix) {
20
+ // Use setTimeout to ensure this runs after any initialization
21
+ const fixVisibility = () => {
22
+ const f = document.querySelector('#fader')
23
+ if (f) {
24
+ // Force remove the fader (autoAlpha: 0 = opacity: 0 + visibility: hidden)
25
+ set(f, { opacity: 0, display: 'none' })
26
+ f.style.visibility = 'hidden'
27
+ }
12
28
 
13
- gsap.registerPlugin(ScrollToPlugin)
14
- gsap.defaults({
15
- ease: 'sine.out',
16
- })
29
+ const dataFaders = document.querySelectorAll('[data-fader]')
30
+ if (dataFaders.length) {
31
+ // autoAlpha: 0 = opacity: 0 + visibility: hidden
32
+ set(dataFaders, { opacity: 0 })
33
+ dataFaders.forEach(el => (el.style.visibility = 'hidden'))
34
+ }
17
35
 
18
- window.onpageshow = (event) => {
19
- if (event.persisted) {
20
- const f = document.querySelector('#fader')
21
- if (f) {
22
- gsap.to(f, { duration: 0.35, autoAlpha: 0 })
23
- }
36
+ // Clear all opacity/transform issues
37
+ clearProps(document.body, ['opacity'])
38
+ document.body.classList.remove('unloaded')
24
39
 
25
- const dataFaders = document.querySelectorAll('[data-fader]')
26
- if (dataFaders.length) {
27
- gsap.to(dataFaders, { duration: 0.35, autoAlpha: 0 })
28
- }
40
+ // Ensure navigation is visible
41
+ const $nav = Dom.find('header[data-nav]')
42
+ if ($nav) clearProps($nav, ['opacity', 'transform'])
29
43
 
30
- gsap.set(document.body, { clearProps: 'opacity' })
44
+ // Ensure main is visible
45
+ const $main = Dom.find('main')
46
+ if ($main) clearProps($main, ['opacity', 'transform'])
31
47
 
32
- // check that navigation is visible
33
- const $nav = Dom.find('header[data-nav]')
34
- gsap.set($nav, { clearProps: 'opacity' })
35
-
36
- // check that main is visible
37
- const $main = Dom.find('main')
38
- gsap.set($main, { clearProps: 'opacity' })
48
+ // Ensure footer is visible
49
+ const $footer = Dom.find('footer')
50
+ if ($footer) clearProps($footer, ['opacity', 'transform'])
51
+ }
39
52
 
40
- // check that footer is visible
41
- const $footer = Dom.find('footer')
42
- gsap.set($footer, { clearProps: 'opacity' })
53
+ // Execute immediately for bfcache
54
+ if (event.persisted) {
55
+ fixVisibility()
56
+ } else if (hasHash) {
57
+ // For hash navigation, delay slightly to ensure it runs after initialization attempts
58
+ setTimeout(fixVisibility, 100)
59
+ // Also run again after a longer delay as a failsafe
60
+ setTimeout(fixVisibility, 500)
61
+ }
43
62
  }
44
63
  }
45
64
 
@@ -58,28 +77,42 @@ const DEFAULT_OPTIONS = {
58
77
  'iframe', // , 'video'?
59
78
  ],
60
79
 
80
+ breakpointConfig: {
81
+ breakpoints: [
82
+ 'iphone',
83
+ 'mobile',
84
+ 'ipad_portrait',
85
+ 'ipad_landscape',
86
+ 'desktop_md',
87
+ 'desktop_lg',
88
+ 'desktop_xl',
89
+ ],
90
+ },
91
+
61
92
  bindScroll: true,
62
93
  bindResize: true,
63
94
 
64
95
  // Big Sur + Safari 14 is now trying to display webp, but fails intermittently
65
- disableWebpSafari: true,
96
+ disableWebpSafari: false,
66
97
 
67
98
  faderOpts: {
68
99
  fadeIn: (callback = () => {}) => {
69
100
  const fader = document.querySelector('#fader')
70
- gsap.to(fader, {
71
- opacity: 0,
72
- ease: 'power1.inOut',
73
- delay: 0,
74
- duration: 0.65,
75
- onComplete: () => {
76
- if (window.bfTO) {
77
- clearTimeout(window.bfTO)
78
- }
79
- gsap.set(fader, { display: 'none' })
80
- document.body.classList.remove('unloaded')
81
- callback()
82
- },
101
+ if (!fader) {
102
+ if (window.bfTO) {
103
+ clearTimeout(window.bfTO)
104
+ }
105
+ document.body.classList.remove('unloaded')
106
+ callback()
107
+ return
108
+ }
109
+
110
+ animate(fader, { opacity: 0 }, { duration: 0.65 }).finished.then(() => {
111
+ if (window.bfTO) {
112
+ clearTimeout(window.bfTO)
113
+ }
114
+ document.body.classList.remove('unloaded')
115
+ callback()
83
116
  })
84
117
  },
85
118
  },
@@ -107,16 +140,26 @@ export default class Application {
107
140
  this.position = {
108
141
  top: 0,
109
142
  left: 0,
143
+ lastTop: 0,
144
+ lastLeft: 0,
110
145
  }
111
146
 
112
147
  this.state = {
113
148
  revealed: false,
114
149
  forcedScroll: false,
150
+ scrollDirection: null,
115
151
  }
116
152
 
153
+ // Special handling for breakpointConfig to avoid array merging
154
+ const breakpointConfig = opts.breakpointConfig
155
+ delete opts.breakpointConfig
156
+
117
157
  this.opts = _defaultsDeep(opts, DEFAULT_OPTIONS)
118
- this.focusableSelectors = this.opts.focusableSelectors
119
158
 
159
+ // Restore breakpointConfig, using provided config or default
160
+ this.opts.breakpointConfig = breakpointConfig || DEFAULT_OPTIONS.breakpointConfig
161
+
162
+ this.focusableSelectors = this.opts.focusableSelectors
120
163
  this.featureTests = new FeatureTests(this, this.opts.featureTests)
121
164
 
122
165
  if (typeof this.opts.breakpointConfig === 'object') {
@@ -142,35 +185,20 @@ export default class Application {
142
185
 
143
186
  this.PREFERS_REDUCED_MOTION = prefersReducedMotion()
144
187
  if (this.PREFERS_REDUCED_MOTION && this.opts.respectReducedMotion) {
145
- gsap.globalTimeline.timeScale(200)
188
+ // Motion respects prefers-reduced-motion automatically
146
189
  document.documentElement.classList.add('prefers-reduced-motion')
147
190
  }
148
- window.addEventListener(
149
- Events.BREAKPOINT_CHANGE,
150
- this.onBreakpointChanged.bind(this)
151
- )
191
+ window.addEventListener(Events.BREAKPOINT_CHANGE, this.onBreakpointChanged.bind(this))
152
192
 
153
- this.beforeInitializedEvent = new window.CustomEvent(
154
- Events.APPLICATION_PRELUDIUM,
155
- this
156
- )
157
- this.initializedEvent = new window.CustomEvent(
158
- Events.APPLICATION_INITIALIZED,
159
- this
160
- )
193
+ this.beforeInitializedEvent = new window.CustomEvent(Events.APPLICATION_PRELUDIUM, this)
194
+ this.initializedEvent = new window.CustomEvent(Events.APPLICATION_INITIALIZED, this)
161
195
  this.readyEvent = new window.CustomEvent(Events.APPLICATION_READY, this)
162
- this.revealedEvent = new window.CustomEvent(
163
- Events.APPLICATION_REVEALED,
164
- this
165
- )
196
+ this.revealedEvent = new window.CustomEvent(Events.APPLICATION_REVEALED, this)
166
197
 
167
198
  /**
168
199
  * Grab common events and defer
169
200
  */
170
- document.addEventListener(
171
- 'visibilitychange',
172
- this.onVisibilityChange.bind(this)
173
- )
201
+ document.addEventListener('visibilitychange', this.onVisibilityChange.bind(this))
174
202
  window.addEventListener('orientationchange', this.onResize.bind(this), {
175
203
  capture: false,
176
204
  passive: true,
@@ -224,13 +252,10 @@ export default class Application {
224
252
  break
225
253
 
226
254
  case 'safari':
227
- this._zoomSVG = document.createElementNS(
228
- 'http://www.w3.org/2000/svg',
229
- 'svg'
230
- )
255
+ this._zoomSVG = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
231
256
  this._zoomSVG.setAttribute('xmlns', 'http://www.w3.org/2000/svg')
232
257
  this._zoomSVG.setAttribute('version', '1.1')
233
- gsap.set(this._zoomSVG, { display: 'none' })
258
+ set(this._zoomSVG, { display: 'none' })
234
259
  document.body.appendChild(this._zoomSVG)
235
260
  this._initialZoom = this._zoomSVG.currentScale
236
261
  break
@@ -271,17 +296,13 @@ export default class Application {
271
296
  default:
272
297
  if ([1, -1].indexOf(dprDelta) === -1) {
273
298
  if (dimsChanged) {
274
- this.size.zoom =
275
- 1 + (zoom.calculate(this.browser) - this._initialZoom)
299
+ this.size.zoom = 1 + (zoom.calculate(this.browser) - this._initialZoom)
276
300
  if (this.size.zoom === 0) {
277
301
  this.size.zoom = 1
278
302
  }
279
303
  }
280
304
  } else {
281
- this._initialZoom = Math.min(
282
- Math.max(this._initialZoom - dprDelta, 1),
283
- 2
284
- )
305
+ this._initialZoom = Math.min(Math.max(this._initialZoom - dprDelta, 1), 2)
285
306
  }
286
307
  }
287
308
 
@@ -312,7 +333,7 @@ export default class Application {
312
333
  if (!Object.prototype.hasOwnProperty.call(this.callbacks, type)) {
313
334
  return
314
335
  }
315
- this.callbacks[type].forEach((cb) => cb(this))
336
+ this.callbacks[type].forEach(cb => cb(this))
316
337
  }
317
338
 
318
339
  /**
@@ -347,9 +368,9 @@ export default class Application {
347
368
  this._scrollPaddedElements = [document.body, ...extraPaddedElements]
348
369
  window.dispatchEvent(ev)
349
370
  this.SCROLL_LOCKED = true
350
- gsap.set(document.body, { overflow: 'hidden' })
351
- gsap.set(this._scrollPaddedElements, {
352
- paddingRight: currentScrollbarWidth,
371
+ set(document.body, { overflow: 'hidden' })
372
+ set(this._scrollPaddedElements, {
373
+ paddingRight: `${currentScrollbarWidth}px`,
353
374
  })
354
375
  document.addEventListener('touchmove', this.scrollVoid, false)
355
376
  }
@@ -361,8 +382,8 @@ export default class Application {
361
382
  const ev = new window.CustomEvent(Events.APPLICATION_SCROLL_RELEASED, this)
362
383
  window.dispatchEvent(ev)
363
384
  this.SCROLL_LOCKED = false
364
- gsap.set(document.body, { overflow: defaultOverflow })
365
- gsap.set(this._scrollPaddedElements, { clearProps: 'paddingRight' })
385
+ set(document.body, { overflow: defaultOverflow })
386
+ clearProps(this._scrollPaddedElements, ['paddingRight'])
366
387
  document.removeEventListener('touchmove', this.scrollVoid, false)
367
388
  }
368
389
 
@@ -373,36 +394,74 @@ export default class Application {
373
394
  * @param {*} time
374
395
  * @param {*} emitEvents
375
396
  */
376
- scrollTo(target, time = 0.8, emitEvents = true, ease = 'sine.inOut') {
377
- let scrollToData
378
- const forcedScrollEventStart = new window.CustomEvent(
379
- Events.APPLICATION_FORCED_SCROLL_START
380
- )
397
+ scrollTo(target, time = 0.8, emitEvents = true, ease = 'easeInOut') {
398
+ const forcedScrollEventStart = new window.CustomEvent(Events.APPLICATION_FORCED_SCROLL_START)
381
399
  this.state.forcedScroll = true
382
400
  if (emitEvents) {
383
401
  window.dispatchEvent(forcedScrollEventStart)
384
402
  }
385
403
 
386
- if (typeof target === 'object') {
387
- scrollToData = target
388
- } else {
389
- scrollToData = { y: target, autoKill: false }
404
+ // Calculate target position
405
+ let targetY = 0
406
+ if (typeof target === 'number') {
407
+ // Handle number
408
+ targetY = target
409
+ } else if (typeof target === 'string') {
410
+ // Handle selector string
411
+ const el = document.querySelector(target)
412
+ if (el) {
413
+ targetY = el.getBoundingClientRect().top + window.pageYOffset
414
+ }
415
+ } else if (target instanceof Element) {
416
+ // Handle DOM element
417
+ targetY = target.getBoundingClientRect().top + window.pageYOffset
418
+ } else if (typeof target === 'object') {
419
+ // Handle object format: {y: "#someID", offsetY: 50} or {y: element, offsetY: 50}
420
+ const yValue = target.y
421
+ if (yValue instanceof Element) {
422
+ targetY = yValue.getBoundingClientRect().top + window.pageYOffset
423
+ } else if (typeof yValue === 'string') {
424
+ const el = document.querySelector(yValue)
425
+ if (el) {
426
+ targetY = el.getBoundingClientRect().top + window.pageYOffset
427
+ }
428
+ } else if (typeof yValue === 'number') {
429
+ targetY = yValue
430
+ }
431
+ // Add offset if provided
432
+ if (target.offsetY) {
433
+ targetY += target.offsetY
434
+ }
390
435
  }
391
436
 
392
- gsap.to(window, {
393
- duration: time,
394
- scrollTo: scrollToData,
395
- onComplete: () => {
396
- const forcedScrollEventEnd = new window.CustomEvent(
397
- Events.APPLICATION_FORCED_SCROLL_END
398
- )
437
+ // Animate scroll using requestAnimationFrame
438
+ const startY = window.pageYOffset
439
+ const distance = targetY - startY
440
+ const duration = time * 1000 // convert to milliseconds
441
+ const startTime = performance.now()
442
+
443
+ const easeInOut = t => (t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t)
444
+
445
+ const animateScroll = currentTime => {
446
+ const elapsed = currentTime - startTime
447
+ const progress = Math.min(elapsed / duration, 1)
448
+ const eased = easeInOut(progress)
449
+ const currentY = startY + distance * eased
450
+
451
+ window.scrollTo(0, currentY)
452
+
453
+ if (progress < 1) {
454
+ requestAnimationFrame(animateScroll)
455
+ } else {
456
+ const forcedScrollEventEnd = new window.CustomEvent(Events.APPLICATION_FORCED_SCROLL_END)
399
457
  if (emitEvents) {
400
458
  window.dispatchEvent(forcedScrollEventEnd)
401
459
  requestAnimationFrame(() => (this.state.forcedScroll = false))
402
460
  }
403
- },
404
- ease,
405
- })
461
+ }
462
+ }
463
+
464
+ requestAnimationFrame(animateScroll)
406
465
  }
407
466
 
408
467
  hardScrollToTop() {
@@ -458,7 +517,6 @@ export default class Application {
458
517
  hacks() {
459
518
  if (this.opts.disableWebpSafari) {
460
519
  if (this.browser === 'safari') {
461
- console.debug('==> disable webp')
462
520
  const webps = Dom.all('source[type="image/webp"]')
463
521
  for (let i = 0; i < webps.length; i += 1) {
464
522
  webps[i].remove()
@@ -547,22 +605,10 @@ export default class Application {
547
605
  this.size.initialOuterWidth = window.outerWidth
548
606
  this.size.scrollHeight = document.body.scrollHeight
549
607
 
550
- root.style.setProperty(
551
- '--vp-initial-inner-h',
552
- `${this.size.initialInnerHeight}px`
553
- )
554
- root.style.setProperty(
555
- '--vp-initial-outer-h',
556
- `${this.size.initialOuterHeight}px`
557
- )
558
- root.style.setProperty(
559
- '--vp-initial-inner-w',
560
- `${this.size.initialInnerWidth}px`
561
- )
562
- root.style.setProperty(
563
- '--vp-initial-outer-w',
564
- `${this.size.initialOuterWidth}px`
565
- )
608
+ root.style.setProperty('--vp-initial-inner-h', `${this.size.initialInnerHeight}px`)
609
+ root.style.setProperty('--vp-initial-outer-h', `${this.size.initialOuterHeight}px`)
610
+ root.style.setProperty('--vp-initial-inner-w', `${this.size.initialInnerWidth}px`)
611
+ root.style.setProperty('--vp-initial-outer-w', `${this.size.initialOuterWidth}px`)
566
612
  root.style.setProperty('--ec-zoom', `${this.size.zoom}`)
567
613
  root.style.setProperty('--scroll-h', `${this.size.scrollHeight}px`)
568
614
 
@@ -594,9 +640,7 @@ export default class Application {
594
640
  */
595
641
  setvh100() {
596
642
  const root = document.querySelector(':root')
597
- const height = this.featureTests.results.ios
598
- ? screen.height
599
- : window.innerHeight
643
+ const height = this.featureTests.results.ios ? screen.height : window.innerHeight
600
644
  root.style.setProperty('--vp-100vh', `${height}px`)
601
645
  root.style.setProperty('--vp-1vh', `${height * 0.01}px`)
602
646
  }
@@ -662,10 +706,33 @@ export default class Application {
662
706
  return
663
707
  }
664
708
 
709
+ // Store previous position
710
+ this.position.lastTop = this.position.top
711
+ this.position.lastLeft = this.position.left
712
+
713
+ // Get current position
665
714
  this.position.top = window.pageYOffset
666
715
  this.position.left = window.pageXOffset
667
716
 
668
- const evt = new CustomEvent(Events.APPLICATION_SCROLL, e)
717
+ // Determine scroll direction
718
+ if (this.position.top > this.position.lastTop) {
719
+ this.state.scrollDirection = 'down'
720
+ } else if (this.position.top < this.position.lastTop) {
721
+ this.state.scrollDirection = 'up'
722
+ } else if (this.position.left > this.position.lastLeft) {
723
+ this.state.scrollDirection = 'right'
724
+ } else if (this.position.left < this.position.lastLeft) {
725
+ this.state.scrollDirection = 'left'
726
+ }
727
+
728
+ // Create an enhanced event object with additional data
729
+ const detail = {
730
+ scrollDirection: this.state.scrollDirection,
731
+ position: this.position,
732
+ originalEvent: e,
733
+ }
734
+
735
+ const evt = new CustomEvent(Events.APPLICATION_SCROLL, { detail })
669
736
  window.dispatchEvent(evt)
670
737
  }
671
738
 
@@ -712,18 +779,14 @@ export default class Application {
712
779
  this.debugOverlay.addEventListener('click', this.toggleDebug.bind(this))
713
780
 
714
781
  const userAgent = this.debugOverlay.querySelector('.user-agent')
715
- gsap.set(userAgent, { display: 'none' })
782
+ set(userAgent, { display: 'none' })
716
783
  userAgent.innerHTML = `<b>&rarr; ${this.userAgent}</b> >> <span>KOPIER</span>`
717
784
 
718
785
  const span = userAgent.querySelector('span')
719
786
  const windowWidth =
720
- window.innerWidth ||
721
- document.documentElement.clientWidth ||
722
- document.body.clientWidth
787
+ window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth
723
788
  const windowHeight =
724
- window.innerHeight ||
725
- document.documentElement.clientHeight ||
726
- document.body.clientHeight
789
+ window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight
727
790
 
728
791
  span.addEventListener('click', () => {
729
792
  const copyText = userAgent.querySelector('b')
@@ -748,7 +811,6 @@ ${JSON.stringify(this.featureTests.results, undefined, 2)}
748
811
  }
749
812
 
750
813
  toggleDebug() {
751
- const tl = gsap.timeline()
752
814
  const breakpoint = this.debugOverlay.querySelector('.breakpoint')
753
815
  const userAgent = this.debugOverlay.querySelector('.user-agent')
754
816
 
@@ -761,28 +823,35 @@ ${JSON.stringify(this.featureTests.results, undefined, 2)}
761
823
  switch (this.debugType) {
762
824
  case 0:
763
825
  // hide all except branding
764
- tl.to([breakpoint, userAgent], { duration: 0.3, autoAlpha: 0 })
765
- .to([breakpoint, userAgent], { duration: 0.7, width: 0 })
766
- .call(() => {
767
- gsap.set([breakpoint, userAgent], { display: 'none' })
826
+ // First fade out (autoAlpha: 0 = opacity: 0 + visibility: hidden)
827
+ animate([breakpoint, userAgent], { opacity: 0 }, { duration: 0.3 }).finished.then(() => {
828
+ ;[breakpoint, userAgent].forEach(el => (el.style.visibility = 'hidden'))
829
+ // Then collapse width
830
+ animate([breakpoint, userAgent], { width: 0 }, { duration: 0.7 }).finished.then(() => {
831
+ set([breakpoint, userAgent], { display: 'none' })
768
832
  })
833
+ })
769
834
  break
770
835
 
771
836
  case 1:
772
- //
773
- gsap.set(breakpoint, { width: 'auto', display: 'block' })
774
- tl.from(breakpoint, { duration: 0.7, width: 0 }).to(breakpoint, {
775
- duration: 0.3,
776
- autoAlpha: 1,
837
+ // Show breakpoint
838
+ set(breakpoint, { width: 'auto', display: 'block' })
839
+ breakpoint.style.visibility = 'visible'
840
+ // Animate from width: 0 to auto
841
+ animate(breakpoint, { width: [0, 'auto'] }, { duration: 0.7 }).finished.then(() => {
842
+ // Then fade in (autoAlpha: 1 = opacity: 1 + visibility: visible)
843
+ animate(breakpoint, { opacity: 1 }, { duration: 0.3 })
777
844
  })
778
845
  break
779
846
 
780
847
  case 2:
781
- //
782
- gsap.set(userAgent, { width: 'auto', display: 'block' })
783
- tl.from(userAgent, { duration: 0.7, width: 0 }).to(userAgent, {
784
- duration: 0.3,
785
- autoAlpha: 1,
848
+ // Show userAgent
849
+ set(userAgent, { width: 'auto', display: 'block' })
850
+ userAgent.style.visibility = 'visible'
851
+ // Animate from width: 0 to auto
852
+ animate(userAgent, { width: [0, 'auto'] }, { duration: 0.7 }).finished.then(() => {
853
+ // Then fade in (autoAlpha: 1 = opacity: 1 + visibility: visible)
854
+ animate(userAgent, { opacity: 1 }, { duration: 0.3 })
786
855
  })
787
856
  break
788
857
 
@@ -795,7 +864,7 @@ ${JSON.stringify(this.featureTests.results, undefined, 2)}
795
864
  * CTRL-G to show grid overlay
796
865
  */
797
866
  setupGridoverlay() {
798
- const gridKeyPressed = (e) => {
867
+ const gridKeyPressed = e => {
799
868
  if (e.keyCode === 71 && e.ctrlKey) {
800
869
  const guides = Dom.find('.dbg-grid')
801
870
  const cols = Dom.all(guides, 'b')
@@ -805,25 +874,34 @@ ${JSON.stringify(this.featureTests.results, undefined, 2)}
805
874
  }
806
875
 
807
876
  if (Dom.hasClass(guides, 'visible')) {
808
- gsap.set(cols, { width: 'auto' })
809
- gsap.to(cols, {
810
- duration: 0.35,
811
- width: 0,
812
- stagger: 0.02,
813
- ease: 'sine.inOut',
814
- onComplete: () => {
815
- guides.classList.toggle('visible')
877
+ set(cols, { width: 'auto' })
878
+ animate(
879
+ cols,
880
+ {
881
+ width: 0,
816
882
  },
883
+ {
884
+ duration: 0.35,
885
+ delay: stagger(0.02),
886
+ ease: 'easeInOut',
887
+ }
888
+ ).finished.then(() => {
889
+ guides.classList.toggle('visible')
817
890
  })
818
891
  } else {
819
- gsap.set(cols, { width: 0 })
892
+ set(cols, { width: 0 })
820
893
  guides.classList.toggle('visible')
821
- gsap.to(cols, {
822
- duration: 0.35,
823
- width: '100%',
824
- stagger: 0.02,
825
- ease: 'sine.inOut',
826
- })
894
+ animate(
895
+ cols,
896
+ {
897
+ width: '100%',
898
+ },
899
+ {
900
+ duration: 0.35,
901
+ delay: stagger(0.02),
902
+ ease: 'easeInOut',
903
+ }
904
+ )
827
905
  }
828
906
  }
829
907
  }