@brandocms/jupiter 4.0.0-beta.1 → 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 (50) hide show
  1. package/README.md +191 -2
  2. package/package.json +20 -18
  3. package/src/index.js +10 -10
  4. package/src/modules/Application/index.js +203 -157
  5. package/src/modules/Cookies/index.js +34 -55
  6. package/src/modules/CoverOverlay/index.js +20 -13
  7. package/src/modules/Dataloader/index.js +71 -24
  8. package/src/modules/Dataloader/url-sync.js +238 -0
  9. package/src/modules/Dom/index.js +18 -0
  10. package/src/modules/DoubleHeader/index.js +571 -0
  11. package/src/modules/Dropdown/index.js +101 -75
  12. package/src/modules/EqualHeightElements/index.js +5 -7
  13. package/src/modules/EqualHeightImages/index.js +7 -2
  14. package/src/modules/FixedHeader/index.js +60 -30
  15. package/src/modules/FooterReveal/index.js +3 -3
  16. package/src/modules/HeroSlider/index.js +207 -91
  17. package/src/modules/HeroVideo/index.js +15 -27
  18. package/src/modules/Lazyload/index.js +101 -80
  19. package/src/modules/Lightbox/index.js +17 -55
  20. package/src/modules/Links/index.js +54 -49
  21. package/src/modules/Looper/index.js +1737 -0
  22. package/src/modules/Marquee/index.js +106 -37
  23. package/src/modules/MobileMenu/index.js +70 -124
  24. package/src/modules/Moonwalk/index.js +349 -150
  25. package/src/modules/Popover/index.js +186 -28
  26. package/src/modules/Popup/index.js +27 -34
  27. package/src/modules/StackedBoxes/index.js +3 -3
  28. package/src/modules/StickyHeader/index.js +364 -155
  29. package/src/modules/Toggler/index.js +184 -27
  30. package/src/utils/motion-helpers.js +330 -0
  31. package/types/index.d.ts +1 -30
  32. package/types/modules/Application/index.d.ts +6 -6
  33. package/types/modules/Breakpoints/index.d.ts +2 -0
  34. package/types/modules/Dataloader/index.d.ts +5 -2
  35. package/types/modules/Dataloader/url-sync.d.ts +36 -0
  36. package/types/modules/Dom/index.d.ts +7 -0
  37. package/types/modules/DoubleHeader/index.d.ts +63 -0
  38. package/types/modules/Dropdown/index.d.ts +7 -30
  39. package/types/modules/EqualHeightImages/index.d.ts +1 -1
  40. package/types/modules/FixedHeader/index.d.ts +1 -1
  41. package/types/modules/Lazyload/index.d.ts +9 -9
  42. package/types/modules/Lightbox/index.d.ts +0 -5
  43. package/types/modules/Looper/index.d.ts +127 -0
  44. package/types/modules/Moonwalk/index.d.ts +6 -15
  45. package/types/modules/Parallax/index.d.ts +10 -32
  46. package/types/modules/Popover/index.d.ts +12 -0
  47. package/types/modules/Popup/index.d.ts +6 -19
  48. package/types/modules/ScrollSpy/index.d.ts +1 -1
  49. package/types/modules/StickyHeader/index.d.ts +171 -14
  50. package/types/modules/Toggler/index.d.ts +24 -2
@@ -1,4 +1,4 @@
1
- import { gsap, ScrollToPlugin } from 'gsap/all'
1
+ import { animate, stagger } from 'motion'
2
2
  import _defaultsDeep from 'lodash.defaultsdeep'
3
3
  import rafCallback from '../../utils/rafCallback'
4
4
  import prefersReducedMotion from '../../utils/prefersReducedMotion'
@@ -8,37 +8,57 @@ import Breakpoints from '../Breakpoints'
8
8
  import FeatureTests from '../FeatureTests'
9
9
  import Fontloader from '../Fontloader'
10
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
+ }
11
28
 
12
- gsap.registerPlugin(ScrollToPlugin)
13
- gsap.defaults({
14
- ease: 'sine.out',
15
- })
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
+ }
16
35
 
17
- window.onpageshow = (event) => {
18
- if (event.persisted) {
19
- const f = document.querySelector('#fader')
20
- if (f) {
21
- gsap.to(f, { duration: 0.35, autoAlpha: 0 })
22
- }
36
+ // Clear all opacity/transform issues
37
+ clearProps(document.body, ['opacity'])
38
+ document.body.classList.remove('unloaded')
23
39
 
24
- const dataFaders = document.querySelectorAll('[data-fader]')
25
- if (dataFaders.length) {
26
- gsap.to(dataFaders, { duration: 0.35, autoAlpha: 0 })
27
- }
40
+ // Ensure navigation is visible
41
+ const $nav = Dom.find('header[data-nav]')
42
+ if ($nav) clearProps($nav, ['opacity', 'transform'])
28
43
 
29
- gsap.set(document.body, { clearProps: 'opacity' })
44
+ // Ensure main is visible
45
+ const $main = Dom.find('main')
46
+ if ($main) clearProps($main, ['opacity', 'transform'])
30
47
 
31
- // check that navigation is visible
32
- const $nav = Dom.find('header[data-nav]')
33
- gsap.set($nav, { clearProps: 'opacity' })
34
-
35
- // check that main is visible
36
- const $main = Dom.find('main')
37
- gsap.set($main, { clearProps: 'opacity' })
48
+ // Ensure footer is visible
49
+ const $footer = Dom.find('footer')
50
+ if ($footer) clearProps($footer, ['opacity', 'transform'])
51
+ }
38
52
 
39
- // check that footer is visible
40
- const $footer = Dom.find('footer')
41
- 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
+ }
42
62
  }
43
63
  }
44
64
 
@@ -57,11 +77,23 @@ const DEFAULT_OPTIONS = {
57
77
  'iframe', // , 'video'?
58
78
  ],
59
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
+
60
92
  bindScroll: true,
61
93
  bindResize: true,
62
94
 
63
95
  // Big Sur + Safari 14 is now trying to display webp, but fails intermittently
64
- disableWebpSafari: true,
96
+ disableWebpSafari: false,
65
97
 
66
98
  faderOpts: {
67
99
  fadeIn: (callback = () => {}) => {
@@ -74,19 +106,13 @@ const DEFAULT_OPTIONS = {
74
106
  callback()
75
107
  return
76
108
  }
77
- gsap.to(fader, {
78
- opacity: 0,
79
- ease: 'power1.inOut',
80
- delay: 0,
81
- duration: 0.65,
82
- onComplete: () => {
83
- if (window.bfTO) {
84
- clearTimeout(window.bfTO)
85
- }
86
- gsap.set(fader, { display: 'none' })
87
- document.body.classList.remove('unloaded')
88
- callback()
89
- },
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()
90
116
  })
91
117
  },
92
118
  },
@@ -124,7 +150,15 @@ export default class Application {
124
150
  scrollDirection: null,
125
151
  }
126
152
 
153
+ // Special handling for breakpointConfig to avoid array merging
154
+ const breakpointConfig = opts.breakpointConfig
155
+ delete opts.breakpointConfig
156
+
127
157
  this.opts = _defaultsDeep(opts, DEFAULT_OPTIONS)
158
+
159
+ // Restore breakpointConfig, using provided config or default
160
+ this.opts.breakpointConfig = breakpointConfig || DEFAULT_OPTIONS.breakpointConfig
161
+
128
162
  this.focusableSelectors = this.opts.focusableSelectors
129
163
  this.featureTests = new FeatureTests(this, this.opts.featureTests)
130
164
 
@@ -151,35 +185,20 @@ export default class Application {
151
185
 
152
186
  this.PREFERS_REDUCED_MOTION = prefersReducedMotion()
153
187
  if (this.PREFERS_REDUCED_MOTION && this.opts.respectReducedMotion) {
154
- gsap.globalTimeline.timeScale(200)
188
+ // Motion respects prefers-reduced-motion automatically
155
189
  document.documentElement.classList.add('prefers-reduced-motion')
156
190
  }
157
- window.addEventListener(
158
- Events.BREAKPOINT_CHANGE,
159
- this.onBreakpointChanged.bind(this)
160
- )
191
+ window.addEventListener(Events.BREAKPOINT_CHANGE, this.onBreakpointChanged.bind(this))
161
192
 
162
- this.beforeInitializedEvent = new window.CustomEvent(
163
- Events.APPLICATION_PRELUDIUM,
164
- this
165
- )
166
- this.initializedEvent = new window.CustomEvent(
167
- Events.APPLICATION_INITIALIZED,
168
- this
169
- )
193
+ this.beforeInitializedEvent = new window.CustomEvent(Events.APPLICATION_PRELUDIUM, this)
194
+ this.initializedEvent = new window.CustomEvent(Events.APPLICATION_INITIALIZED, this)
170
195
  this.readyEvent = new window.CustomEvent(Events.APPLICATION_READY, this)
171
- this.revealedEvent = new window.CustomEvent(
172
- Events.APPLICATION_REVEALED,
173
- this
174
- )
196
+ this.revealedEvent = new window.CustomEvent(Events.APPLICATION_REVEALED, this)
175
197
 
176
198
  /**
177
199
  * Grab common events and defer
178
200
  */
179
- document.addEventListener(
180
- 'visibilitychange',
181
- this.onVisibilityChange.bind(this)
182
- )
201
+ document.addEventListener('visibilitychange', this.onVisibilityChange.bind(this))
183
202
  window.addEventListener('orientationchange', this.onResize.bind(this), {
184
203
  capture: false,
185
204
  passive: true,
@@ -233,13 +252,10 @@ export default class Application {
233
252
  break
234
253
 
235
254
  case 'safari':
236
- this._zoomSVG = document.createElementNS(
237
- 'http://www.w3.org/2000/svg',
238
- 'svg'
239
- )
255
+ this._zoomSVG = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
240
256
  this._zoomSVG.setAttribute('xmlns', 'http://www.w3.org/2000/svg')
241
257
  this._zoomSVG.setAttribute('version', '1.1')
242
- gsap.set(this._zoomSVG, { display: 'none' })
258
+ set(this._zoomSVG, { display: 'none' })
243
259
  document.body.appendChild(this._zoomSVG)
244
260
  this._initialZoom = this._zoomSVG.currentScale
245
261
  break
@@ -280,17 +296,13 @@ export default class Application {
280
296
  default:
281
297
  if ([1, -1].indexOf(dprDelta) === -1) {
282
298
  if (dimsChanged) {
283
- this.size.zoom =
284
- 1 + (zoom.calculate(this.browser) - this._initialZoom)
299
+ this.size.zoom = 1 + (zoom.calculate(this.browser) - this._initialZoom)
285
300
  if (this.size.zoom === 0) {
286
301
  this.size.zoom = 1
287
302
  }
288
303
  }
289
304
  } else {
290
- this._initialZoom = Math.min(
291
- Math.max(this._initialZoom - dprDelta, 1),
292
- 2
293
- )
305
+ this._initialZoom = Math.min(Math.max(this._initialZoom - dprDelta, 1), 2)
294
306
  }
295
307
  }
296
308
 
@@ -321,7 +333,7 @@ export default class Application {
321
333
  if (!Object.prototype.hasOwnProperty.call(this.callbacks, type)) {
322
334
  return
323
335
  }
324
- this.callbacks[type].forEach((cb) => cb(this))
336
+ this.callbacks[type].forEach(cb => cb(this))
325
337
  }
326
338
 
327
339
  /**
@@ -356,9 +368,9 @@ export default class Application {
356
368
  this._scrollPaddedElements = [document.body, ...extraPaddedElements]
357
369
  window.dispatchEvent(ev)
358
370
  this.SCROLL_LOCKED = true
359
- gsap.set(document.body, { overflow: 'hidden' })
360
- gsap.set(this._scrollPaddedElements, {
361
- paddingRight: currentScrollbarWidth,
371
+ set(document.body, { overflow: 'hidden' })
372
+ set(this._scrollPaddedElements, {
373
+ paddingRight: `${currentScrollbarWidth}px`,
362
374
  })
363
375
  document.addEventListener('touchmove', this.scrollVoid, false)
364
376
  }
@@ -370,8 +382,8 @@ export default class Application {
370
382
  const ev = new window.CustomEvent(Events.APPLICATION_SCROLL_RELEASED, this)
371
383
  window.dispatchEvent(ev)
372
384
  this.SCROLL_LOCKED = false
373
- gsap.set(document.body, { overflow: defaultOverflow })
374
- gsap.set(this._scrollPaddedElements, { clearProps: 'paddingRight' })
385
+ set(document.body, { overflow: defaultOverflow })
386
+ clearProps(this._scrollPaddedElements, ['paddingRight'])
375
387
  document.removeEventListener('touchmove', this.scrollVoid, false)
376
388
  }
377
389
 
@@ -382,36 +394,74 @@ export default class Application {
382
394
  * @param {*} time
383
395
  * @param {*} emitEvents
384
396
  */
385
- scrollTo(target, time = 0.8, emitEvents = true, ease = 'sine.inOut') {
386
- let scrollToData
387
- const forcedScrollEventStart = new window.CustomEvent(
388
- Events.APPLICATION_FORCED_SCROLL_START
389
- )
397
+ scrollTo(target, time = 0.8, emitEvents = true, ease = 'easeInOut') {
398
+ const forcedScrollEventStart = new window.CustomEvent(Events.APPLICATION_FORCED_SCROLL_START)
390
399
  this.state.forcedScroll = true
391
400
  if (emitEvents) {
392
401
  window.dispatchEvent(forcedScrollEventStart)
393
402
  }
394
403
 
395
- if (typeof target === 'object') {
396
- scrollToData = target
397
- } else {
398
- 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
+ }
399
435
  }
400
436
 
401
- gsap.to(window, {
402
- duration: time,
403
- scrollTo: scrollToData,
404
- onComplete: () => {
405
- const forcedScrollEventEnd = new window.CustomEvent(
406
- Events.APPLICATION_FORCED_SCROLL_END
407
- )
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)
408
457
  if (emitEvents) {
409
458
  window.dispatchEvent(forcedScrollEventEnd)
410
459
  requestAnimationFrame(() => (this.state.forcedScroll = false))
411
460
  }
412
- },
413
- ease,
414
- })
461
+ }
462
+ }
463
+
464
+ requestAnimationFrame(animateScroll)
415
465
  }
416
466
 
417
467
  hardScrollToTop() {
@@ -467,7 +517,6 @@ export default class Application {
467
517
  hacks() {
468
518
  if (this.opts.disableWebpSafari) {
469
519
  if (this.browser === 'safari') {
470
- console.debug('==> disable webp')
471
520
  const webps = Dom.all('source[type="image/webp"]')
472
521
  for (let i = 0; i < webps.length; i += 1) {
473
522
  webps[i].remove()
@@ -556,22 +605,10 @@ export default class Application {
556
605
  this.size.initialOuterWidth = window.outerWidth
557
606
  this.size.scrollHeight = document.body.scrollHeight
558
607
 
559
- root.style.setProperty(
560
- '--vp-initial-inner-h',
561
- `${this.size.initialInnerHeight}px`
562
- )
563
- root.style.setProperty(
564
- '--vp-initial-outer-h',
565
- `${this.size.initialOuterHeight}px`
566
- )
567
- root.style.setProperty(
568
- '--vp-initial-inner-w',
569
- `${this.size.initialInnerWidth}px`
570
- )
571
- root.style.setProperty(
572
- '--vp-initial-outer-w',
573
- `${this.size.initialOuterWidth}px`
574
- )
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`)
575
612
  root.style.setProperty('--ec-zoom', `${this.size.zoom}`)
576
613
  root.style.setProperty('--scroll-h', `${this.size.scrollHeight}px`)
577
614
 
@@ -603,9 +640,7 @@ export default class Application {
603
640
  */
604
641
  setvh100() {
605
642
  const root = document.querySelector(':root')
606
- const height = this.featureTests.results.ios
607
- ? screen.height
608
- : window.innerHeight
643
+ const height = this.featureTests.results.ios ? screen.height : window.innerHeight
609
644
  root.style.setProperty('--vp-100vh', `${height}px`)
610
645
  root.style.setProperty('--vp-1vh', `${height * 0.01}px`)
611
646
  }
@@ -694,9 +729,9 @@ export default class Application {
694
729
  const detail = {
695
730
  scrollDirection: this.state.scrollDirection,
696
731
  position: this.position,
697
- originalEvent: e
732
+ originalEvent: e,
698
733
  }
699
-
734
+
700
735
  const evt = new CustomEvent(Events.APPLICATION_SCROLL, { detail })
701
736
  window.dispatchEvent(evt)
702
737
  }
@@ -744,18 +779,14 @@ export default class Application {
744
779
  this.debugOverlay.addEventListener('click', this.toggleDebug.bind(this))
745
780
 
746
781
  const userAgent = this.debugOverlay.querySelector('.user-agent')
747
- gsap.set(userAgent, { display: 'none' })
782
+ set(userAgent, { display: 'none' })
748
783
  userAgent.innerHTML = `<b>&rarr; ${this.userAgent}</b> >> <span>KOPIER</span>`
749
784
 
750
785
  const span = userAgent.querySelector('span')
751
786
  const windowWidth =
752
- window.innerWidth ||
753
- document.documentElement.clientWidth ||
754
- document.body.clientWidth
787
+ window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth
755
788
  const windowHeight =
756
- window.innerHeight ||
757
- document.documentElement.clientHeight ||
758
- document.body.clientHeight
789
+ window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight
759
790
 
760
791
  span.addEventListener('click', () => {
761
792
  const copyText = userAgent.querySelector('b')
@@ -780,7 +811,6 @@ ${JSON.stringify(this.featureTests.results, undefined, 2)}
780
811
  }
781
812
 
782
813
  toggleDebug() {
783
- const tl = gsap.timeline()
784
814
  const breakpoint = this.debugOverlay.querySelector('.breakpoint')
785
815
  const userAgent = this.debugOverlay.querySelector('.user-agent')
786
816
 
@@ -793,28 +823,35 @@ ${JSON.stringify(this.featureTests.results, undefined, 2)}
793
823
  switch (this.debugType) {
794
824
  case 0:
795
825
  // hide all except branding
796
- tl.to([breakpoint, userAgent], { duration: 0.3, autoAlpha: 0 })
797
- .to([breakpoint, userAgent], { duration: 0.7, width: 0 })
798
- .call(() => {
799
- 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' })
800
832
  })
833
+ })
801
834
  break
802
835
 
803
836
  case 1:
804
- //
805
- gsap.set(breakpoint, { width: 'auto', display: 'block' })
806
- tl.from(breakpoint, { duration: 0.7, width: 0 }).to(breakpoint, {
807
- duration: 0.3,
808
- 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 })
809
844
  })
810
845
  break
811
846
 
812
847
  case 2:
813
- //
814
- gsap.set(userAgent, { width: 'auto', display: 'block' })
815
- tl.from(userAgent, { duration: 0.7, width: 0 }).to(userAgent, {
816
- duration: 0.3,
817
- 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 })
818
855
  })
819
856
  break
820
857
 
@@ -827,7 +864,7 @@ ${JSON.stringify(this.featureTests.results, undefined, 2)}
827
864
  * CTRL-G to show grid overlay
828
865
  */
829
866
  setupGridoverlay() {
830
- const gridKeyPressed = (e) => {
867
+ const gridKeyPressed = e => {
831
868
  if (e.keyCode === 71 && e.ctrlKey) {
832
869
  const guides = Dom.find('.dbg-grid')
833
870
  const cols = Dom.all(guides, 'b')
@@ -837,25 +874,34 @@ ${JSON.stringify(this.featureTests.results, undefined, 2)}
837
874
  }
838
875
 
839
876
  if (Dom.hasClass(guides, 'visible')) {
840
- gsap.set(cols, { width: 'auto' })
841
- gsap.to(cols, {
842
- duration: 0.35,
843
- width: 0,
844
- stagger: 0.02,
845
- ease: 'sine.inOut',
846
- onComplete: () => {
847
- guides.classList.toggle('visible')
877
+ set(cols, { width: 'auto' })
878
+ animate(
879
+ cols,
880
+ {
881
+ width: 0,
848
882
  },
883
+ {
884
+ duration: 0.35,
885
+ delay: stagger(0.02),
886
+ ease: 'easeInOut',
887
+ }
888
+ ).finished.then(() => {
889
+ guides.classList.toggle('visible')
849
890
  })
850
891
  } else {
851
- gsap.set(cols, { width: 0 })
892
+ set(cols, { width: 0 })
852
893
  guides.classList.toggle('visible')
853
- gsap.to(cols, {
854
- duration: 0.35,
855
- width: '100%',
856
- stagger: 0.02,
857
- ease: 'sine.inOut',
858
- })
894
+ animate(
895
+ cols,
896
+ {
897
+ width: '100%',
898
+ },
899
+ {
900
+ duration: 0.35,
901
+ delay: stagger(0.02),
902
+ ease: 'easeInOut',
903
+ }
904
+ )
859
905
  }
860
906
  }
861
907
  }
@@ -1,6 +1,7 @@
1
- import { gsap } from 'gsap/all'
1
+ import { animate } from 'motion'
2
2
  import _defaultsDeep from 'lodash.defaultsdeep'
3
3
  import * as Events from '../../events'
4
+ import { set } from '../../utils/motion-helpers'
4
5
 
5
6
  /**
6
7
  * @typedef {Object} CookiesOptions
@@ -18,27 +19,33 @@ const DEFAULT_OPTIONS = {
18
19
  const oneYearFromNow = new Date()
19
20
  oneYearFromNow.setFullYear(oneYearFromNow.getFullYear() + 1)
20
21
 
21
- const timeline = gsap.timeline()
22
22
  c.setCookie('COOKIES_CONSENT_STATUS', 1, oneYearFromNow, '/')
23
23
  c.opts.setCookies(c)
24
24
 
25
- timeline
26
- .to(c.cc, { duration: 0.35, y: '120%', ease: 'power3.in' }, '0')
27
- .to(c.inner, { duration: 0.3, opacity: 0, ease: 'power3.in' }, '0')
28
- .set(c.cc, { display: 'none' })
25
+ const timeline = [
26
+ [c.cc, { y: '120%' }, { duration: 0.35, ease: 'easeIn', at: 0 }],
27
+ [c.inner, { opacity: 0 }, { duration: 0.3, ease: 'easeIn', at: 0 }]
28
+ ]
29
+
30
+ animate(timeline).finished.then(() => {
31
+ c.cc.style.display = 'none'
32
+ })
29
33
  },
30
34
 
31
35
  onRefuse: (c) => {
32
36
  const oneYearFromNow = new Date()
33
37
  oneYearFromNow.setFullYear(oneYearFromNow.getFullYear() + 1)
34
38
 
35
- const timeline = gsap.timeline()
36
39
  c.setCookie('COOKIES_CONSENT_STATUS', 0, oneYearFromNow, '/')
37
40
 
38
- timeline
39
- .to(c.cc, { duration: 0.35, y: '120%', ease: 'power3.in' }, '0')
40
- .to(c.inner, { duration: 0.3, opacity: 0, ease: 'power3.in' }, '0')
41
- .set(c.cc, { display: 'none' })
41
+ const timeline = [
42
+ [c.cc, { y: '120%' }, { duration: 0.35, ease: 'easeIn', at: 0 }],
43
+ [c.inner, { opacity: 0 }, { duration: 0.3, ease: 'easeIn', at: 0 }]
44
+ ]
45
+
46
+ animate(timeline).finished.then(() => {
47
+ c.cc.style.display = 'none'
48
+ })
42
49
  },
43
50
 
44
51
  alreadyConsented: (c) => {
@@ -61,50 +68,22 @@ const DEFAULT_OPTIONS = {
61
68
  return
62
69
  }
63
70
 
64
- const timeline = gsap.timeline()
65
-
66
- timeline
67
- .fromTo(
68
- c.cc,
69
- {
70
- duration: 0.5,
71
- y: '120%',
72
- display: 'block',
73
- },
74
- {
75
- duration: 0.5,
76
- y: '0%',
77
- delay: '0.5',
78
- ease: 'power3.out',
79
- },
80
- '0.5'
81
- )
82
- .fromTo(
83
- c.text,
84
- {
85
- duration: 0.7,
86
- opacity: 0,
87
- },
88
- {
89
- duration: 0.7,
90
- opacity: 1,
91
- ease: 'power3.out',
92
- },
93
- '-=0.35'
94
- )
95
- .fromTo(
96
- c.btns,
97
- {
98
- duration: 0.7,
99
- opacity: 0,
100
- },
101
- {
102
- duration: 0.7,
103
- opacity: 1,
104
- ease: 'power3.out',
105
- },
106
- '-=0.35'
107
- )
71
+ // Set display block and reset state immediately
72
+ c.cc.style.display = 'block'
73
+ set(c.cc, { opacity: 1 })
74
+ set(c.inner, { opacity: 1 })
75
+
76
+ // Calculate timeline positions:
77
+ // - c.cc: starts at 1s, duration 0.5s, ends at 1.5s
78
+ // - c.text: starts at 1.15s (0.15s after cc starts), duration 0.7s, ends at 1.85s
79
+ // - c.btns: starts at 1.5s (when cc finishes), duration 0.7s
80
+ const timeline = [
81
+ [c.cc, { y: ['120%', '0%'] }, { duration: 0.5, ease: 'easeOut', at: 1 }],
82
+ [c.text, { opacity: [0, 1] }, { duration: 0.7, ease: 'easeOut', at: 1.15 }],
83
+ [c.btns, { opacity: [0, 1] }, { duration: 0.7, ease: 'easeOut', at: 1.5 }]
84
+ ]
85
+
86
+ animate(timeline)
108
87
  },
109
88
  }
110
89