@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,6 +1,7 @@
1
- import gsap from 'gsap/gsap-core'
1
+ import { animate } from 'motion'
2
2
  import _defaultsDeep from 'lodash.defaultsdeep'
3
3
  import Dom from '../Dom'
4
+ import { set, clearProps } from '../../utils/motion-helpers'
4
5
 
5
6
  const DEFAULT_OPTIONS = {
6
7
  speed: 100,
@@ -11,7 +12,7 @@ const DEFAULT_OPTIONS = {
11
12
  spacer: '<span>&nbsp;&mdash;&nbsp;</span>',
12
13
 
13
14
  onReveal: marqueeEl => {
14
- gsap.to(marqueeEl, { opacity: 1, ease: 'none' })
15
+ animate(marqueeEl, { opacity: 1 }, { ease: 'linear' })
15
16
  }
16
17
  }
17
18
 
@@ -31,7 +32,7 @@ export default class Marquee {
31
32
  }
32
33
 
33
34
  initialize() {
34
- gsap.set(this.elements.$marquee, { opacity: 0 })
35
+ set(this.elements.$marquee, { opacity: 0 })
35
36
  window.addEventListener('APPLICATION:RESIZE', this.updateMarquee.bind(this))
36
37
  window.addEventListener('APPLICATION:REVEALED', this.revealMarquee.bind(this))
37
38
  this.updateMarquee()
@@ -57,15 +58,19 @@ export default class Marquee {
57
58
 
58
59
  this.killTweens()
59
60
  this.clearHolders()
60
- this.setHeight()
61
61
  this.fillText()
62
+ this.setHeight()
62
63
 
63
64
  const holderWidth = this.elements.$holder.offsetWidth
64
65
  const $allHolders = Dom.all(this.elements.$el, '[data-marquee-holder]')
65
66
  const marqueeWidth = holderWidth * $allHolders.length
66
- this.duration = (holderWidth + marqueeWidth) / this.opts.speed
67
+ // Cap duration at 40s to prevent precision issues at slow speeds
68
+ this.duration = Math.min(
69
+ (holderWidth + marqueeWidth) / this.opts.speed,
70
+ 40
71
+ )
67
72
 
68
- gsap.set(this.elements.$marquee, { width: marqueeWidth })
73
+ set(this.elements.$marquee, { width: marqueeWidth })
69
74
  this.initializeTween()
70
75
 
71
76
  if (Dom.inViewport(this.elements.$el)) {
@@ -75,29 +80,43 @@ export default class Marquee {
75
80
 
76
81
  clearHolders() {
77
82
  const $allHolders = Dom.all(this.elements.$el, '[data-marquee-holder]')
78
- Array.from($allHolders).forEach(h => gsap.set(h, { clearProps: 'all' }))
83
+ Array.from($allHolders).forEach(h => clearProps(h, 'all'))
79
84
  }
80
85
 
81
86
  killTweens() {
82
87
  if (this.timeline) {
83
- this.timeline.kill()
88
+ this.timeline.stop()
84
89
  this.timeline = null
85
90
  }
91
+ if (this.speedAnimation) {
92
+ this.speedAnimation.stop()
93
+ this.speedAnimation = null
94
+ }
86
95
  }
87
96
 
88
97
  initializeTween() {
89
98
  const $allHolders = Dom.all(this.elements.$el, '[data-marquee-holder]')
90
99
 
91
100
  Array.from($allHolders).forEach((h, idx) => {
92
- gsap.set(h, { position: 'absolute', left: h.offsetWidth * idx })
101
+ set(h, {
102
+ position: 'absolute',
103
+ left: h.offsetWidth * idx,
104
+ transform: 'translateZ(0)',
105
+ willChange: 'transform'
106
+ })
93
107
  })
94
108
 
95
- this.timeline = gsap.timeline({ paused: true })
96
- this.timeline
97
- .to($allHolders, { xPercent: -100, ease: 'none', duration: this.duration }, 'standard')
98
- .repeat(-1)
109
+ this.timeline = animate(
110
+ $allHolders,
111
+ { transform: ['translateX(0) translateZ(0)', 'translateX(-100%) translateZ(0)'] },
112
+ { duration: this.duration, ease: 'linear', repeat: Infinity }
113
+ )
114
+ this.timeline.pause()
99
115
 
100
- this.timeline.totalProgress(this.opts.startProgress)
116
+ // Set initial progress if specified
117
+ if (this.opts.startProgress > 0) {
118
+ this.timeline.currentTime = this.opts.startProgress * this.duration
119
+ }
101
120
 
102
121
  window.timeline = this.timeline
103
122
  window.marquee = this
@@ -105,45 +124,85 @@ export default class Marquee {
105
124
 
106
125
  play(rampUp = false) {
107
126
  this.playing = true
108
- gsap.killTweensOf(this.timeline)
127
+ if (this.speedAnimation) {
128
+ this.speedAnimation.stop()
129
+ }
109
130
 
110
131
  if (rampUp) {
111
132
  this.timeline.play()
112
- gsap.to(this.timeline, {
113
- timeScale: 1,
114
- ease: 'sine.in',
115
- duration: 0.8
116
- })
133
+ const state = { speed: this.timeline.speed || 0 }
134
+ this.speedAnimation = animate(
135
+ state,
136
+ { speed: 1 },
137
+ {
138
+ duration: 0.8,
139
+ ease: 'easeIn',
140
+ onUpdate: () => {
141
+ this.timeline.speed = state.speed
142
+ }
143
+ }
144
+ )
117
145
  } else {
118
- this.timeline.timeScale(1)
146
+ this.timeline.speed = 1
119
147
  this.timeline.play()
120
148
  }
121
149
  }
122
150
 
123
151
  pause() {
124
152
  this.playing = false
125
- gsap.to(this.timeline, {
126
- timeScale: 0.01,
127
- onComplete: () => {
153
+ const state = { speed: this.timeline.speed || 1 }
154
+ this.speedAnimation = animate(
155
+ state,
156
+ { speed: 0.01 },
157
+ {
158
+ duration: 0.8,
159
+ onUpdate: () => {
160
+ this.timeline.speed = state.speed
161
+ }
162
+ }
163
+ )
164
+ this.speedAnimation.finished.then(() => {
165
+ // Only pause if we're still in paused state (haven't called play() in the meantime)
166
+ if (!this.playing) {
128
167
  this.timeline.pause()
129
- },
130
- duration: 0.8
168
+ }
131
169
  })
132
170
  }
133
171
 
134
172
  slowDown() {
135
- gsap.to(this.timeline, {
136
- timeScale: 0.5,
137
- duration: 0.8
138
- })
173
+ if (this.speedAnimation) {
174
+ this.speedAnimation.stop()
175
+ }
176
+ const state = { speed: this.timeline.speed || 1 }
177
+ this.speedAnimation = animate(
178
+ state,
179
+ { speed: 0.5 },
180
+ {
181
+ duration: 0.3,
182
+ ease: [0.4, 0, 0.2, 1], // ease-out
183
+ onUpdate: () => {
184
+ this.timeline.speed = state.speed
185
+ }
186
+ }
187
+ )
139
188
  }
140
189
 
141
190
  speedUp() {
142
- gsap.to(this.timeline, {
143
- timeScale: 1,
144
- duration: 0.8,
145
- ease: 'sine.in'
146
- })
191
+ if (this.speedAnimation) {
192
+ this.speedAnimation.stop()
193
+ }
194
+ const state = { speed: this.timeline.speed || 0.5 }
195
+ this.speedAnimation = animate(
196
+ state,
197
+ { speed: 1 },
198
+ {
199
+ duration: 0.3,
200
+ ease: [0.4, 0, 0.2, 1], // ease-out
201
+ onUpdate: () => {
202
+ this.timeline.speed = state.speed
203
+ }
204
+ }
205
+ )
147
206
  }
148
207
 
149
208
  setupObserver() {
@@ -169,12 +228,19 @@ export default class Marquee {
169
228
  }
170
229
 
171
230
  fillText() {
231
+ // Clear any previously set heights to get accurate measurement
232
+ clearProps(this.elements.$el, 'height')
233
+ clearProps(this.elements.$marquee, 'height')
234
+
172
235
  this.elements.$marquee.innerHTML = ''
173
236
  this.elements.$marquee.appendChild(this.elements.$holder)
174
237
 
175
238
  this.elements.$holder.innerHTML = ''
176
239
  this.elements.$holder.appendChild(this.elements.$item)
177
240
 
241
+ // Measure height of item only (marquee padding will be added by CSS)
242
+ this.measuredHeight = this.elements.$item.offsetHeight
243
+
178
244
  const textWidth = this.elements.$item.offsetWidth
179
245
  if (textWidth) {
180
246
  if (this.opts.spacer) {
@@ -199,7 +265,10 @@ export default class Marquee {
199
265
  }
200
266
 
201
267
  setHeight() {
202
- const height = this.elements.$item.offsetHeight + this.opts.extraHeight
203
- gsap.set(this.elements.$el, { height })
268
+ // Use the height measured in fillText() (before cloning) plus any extra height
269
+ const height = this.measuredHeight + this.opts.extraHeight
270
+ // Set height on both container and marquee to preserve it when holders become absolute
271
+ set(this.elements.$el, { height })
272
+ set(this.elements.$marquee, { height })
204
273
  }
205
274
  }
@@ -1,7 +1,21 @@
1
- import { gsap } from 'gsap'
1
+ import { animate, stagger } from 'motion'
2
2
  import _defaultsDeep from 'lodash.defaultsdeep'
3
3
  import * as Events from '../../events'
4
+ import { set, clearProps } from '../../utils/motion-helpers'
4
5
 
6
+ /**
7
+ * @typedef {Object} MobileMenuOptions
8
+ * @property {string} [logoColor='#000'] - Color for logo when menu is open
9
+ * @property {string} [logoPathSelector='svg path'] - Selector for logo SVG paths
10
+ * @property {string} [contentSelector='section'] - Selector for menu content
11
+ * @property {string} [liSelector='li'] - Selector for menu items
12
+ * @property {string} [hamburgerColor='#000'] - Color for hamburger icon
13
+ * @property {Function|null} [onResize=null] - Called when window is resized
14
+ * @property {Function} [openTween] - Animation for opening menu
15
+ * @property {Function} [closeTween] - Animation for closing menu
16
+ */
17
+
18
+ /** @type {MobileMenuOptions} */
5
19
  const DEFAULT_OPTIONS = {
6
20
  logoColor: '#000',
7
21
  logoPathSelector: 'svg path',
@@ -10,140 +24,93 @@ const DEFAULT_OPTIONS = {
10
24
  hamburgerColor: '#000',
11
25
 
12
26
  onResize: null,
13
- openTween: m => {
14
- const timeline = gsap.timeline()
15
-
27
+ openTween: async (m) => {
16
28
  m.hamburger.classList.toggle('is-active')
17
29
  document.body.classList.toggle('open-menu')
18
30
 
19
- timeline
20
- .fromTo(
21
- m.bg,
22
- {
23
- duration: 0.35,
24
- x: '0%',
25
- opacity: 0,
26
- height: window.innerHeight
27
- },
28
- {
29
- duration: 0.35,
30
- opacity: 1,
31
- ease: 'sine.in'
32
- }
33
- )
34
- .to(
35
- m.logo,
36
- {
37
- duration: 0.35,
38
- opacity: 0,
39
- ease: 'power3.out'
40
- },
41
- '-=0.35'
42
- )
43
- .to(
44
- m.header,
45
- {
46
- duration: 0.55,
47
- backgroundColor: 'transparent',
48
- ease: 'power3.out'
49
- },
50
- '-=0.35'
51
- )
52
- .call(() => {
53
- m.nav.style.gridTemplateRows = 'auto 1fr'
54
- })
55
- .set(m.nav, { height: window.innerHeight })
56
- .set(m.content, { display: 'block' })
57
- .set(m.logoPath, { fill: m.opts.logoColor })
58
- .set(m.logo, { xPercent: 3 })
59
- .staggerFromTo(
60
- m.lis,
61
- {
62
- duration: 1,
63
- opacity: 0,
64
- x: 20
65
- },
66
- {
67
- duration: 1,
68
- x: 0,
69
- opacity: 1,
70
- ease: 'power3.out'
71
- },
72
- 0.05
73
- )
74
- .to(
75
- m.logo,
76
- {
77
- duration: 0.55,
78
- opacity: 1,
79
- xPercent: 0,
80
- ease: 'power3.inOut'
81
- },
82
- '-=1.2'
83
- )
84
- .call(m._emitMobileMenuOpenEvent)
31
+ // Set initial state for bg
32
+ set(m.bg, { x: '0%', opacity: 0, height: window.innerHeight })
33
+
34
+ // Parallel animations at start (0-0.35s)
35
+ const timeline = [
36
+ [m.bg, { opacity: 1 }, { duration: 0.35, ease: 'easeIn', at: 0 }],
37
+ [m.logo, { opacity: 0 }, { duration: 0.35, ease: 'easeOut', at: 0 }],
38
+ [m.header, { backgroundColor: 'transparent' }, { duration: 0.55, ease: 'easeOut', at: 0 }]
39
+ ]
40
+
41
+ await animate(timeline).finished
42
+
43
+ // Immediate settings
44
+ m.nav.style.gridTemplateRows = 'auto 1fr'
45
+ set(m.nav, { height: window.innerHeight })
46
+ Array.from(m.content).forEach(el => set(el, { display: 'block' }))
47
+ Array.from(m.logoPath).forEach(path => path.setAttribute('fill', m.opts.logoColor))
48
+ set(m.logo, { x: '3%' })
49
+
50
+ // Staggered li animations and logo animation in parallel
51
+ const lisAnimation = animate(
52
+ m.lis,
53
+ { opacity: [0, 1], x: [20, 0] },
54
+ { duration: 1, ease: 'easeOut', delay: stagger(0.05) }
55
+ )
56
+
57
+ const logoAnimation = animate(
58
+ m.logo,
59
+ { opacity: 1, x: ['3%', '0%'] },
60
+ { duration: 0.55, ease: 'easeInOut', at: 0.15 }
61
+ )
62
+
63
+ await Promise.all([lisAnimation.finished, logoAnimation.finished])
64
+
65
+ m._emitMobileMenuOpenEvent()
85
66
  },
86
67
 
87
- closeTween: m => {
68
+ closeTween: async (m) => {
88
69
  document.body.classList.toggle('open-menu')
89
- const timeline = gsap.timeline()
70
+ m.hamburger.classList.toggle('is-active')
90
71
 
91
- timeline
92
- .call(() => {
93
- m.hamburger.classList.toggle('is-active')
94
- })
95
- .fromTo(
96
- m.logo,
97
- {
98
- duration: 0.2,
99
- opacity: 1,
100
- xPercent: 0
101
- },
102
- {
103
- duration: 0.2,
104
- opacity: 0,
105
- xPercent: 5,
106
- ease: 'power3.out'
107
- }
108
- )
109
- .set(m.logoPath, { clearProps: 'fill' })
110
- .staggerTo(
111
- m.lis,
112
- {
113
- duration: 0.5,
114
- opacity: 0,
115
- x: 20,
116
- ease: 'power3.out'
117
- },
118
- 0.04
119
- )
120
- .set(m.nav, { clearProps: 'height' })
121
- .to(
122
- m.bg,
123
- {
124
- duration: 0.25,
125
- x: '100%',
126
- ease: 'sine.in'
127
- },
128
- '-=0.3'
129
- )
130
- .call(() => {
131
- m._emitMobileMenuClosedEvent()
132
- })
133
- .set(m.content, { display: 'none' })
134
- .call(() => {
135
- m.nav.style.gridTemplateRows = 'auto'
136
- })
137
- .set(m.lis, { clearProps: 'opacity' })
138
- .to(m.logo, {
139
- duration: 0.35,
140
- opacity: 1,
141
- ease: 'power3.in'
142
- })
143
- }
72
+ // Fade out logo
73
+ await animate(m.logo, { opacity: 0, x: '5%' }, { duration: 0.2, ease: 'easeOut' }).finished
74
+
75
+ // Clear logo fill
76
+ Array.from(m.logoPath).forEach(path => path.removeAttribute('fill'))
77
+
78
+ // Stagger out lis and slide bg in parallel
79
+ const lisAnimation = animate(
80
+ m.lis,
81
+ { opacity: 0, x: 20 },
82
+ { duration: 0.5, ease: 'easeOut', delay: stagger(0.04) }
83
+ )
84
+
85
+ // bg animation starts 0.3s before lis finish
86
+ // lis duration is 0.5s + last stagger delay, so starts around 0.2s
87
+ setTimeout(() => {
88
+ animate(m.bg, { x: '100%' }, { duration: 0.25, ease: 'easeIn' })
89
+ }, 200)
90
+
91
+ await lisAnimation.finished
92
+
93
+ // Cleanup
94
+ clearProps(m.nav, 'height')
95
+ m._emitMobileMenuClosedEvent()
96
+ Array.from(m.content).forEach(el => set(el, { display: 'none' }))
97
+ m.nav.style.gridTemplateRows = 'auto'
98
+ Array.from(m.lis).forEach(li => clearProps(li, 'opacity'))
99
+
100
+ // Fade logo back in
101
+ await animate(m.logo, { opacity: 1 }, { duration: 0.35, ease: 'easeIn' }).finished
102
+ },
144
103
  }
145
104
 
105
+ /**
106
+ * MobileMenu component for mobile navigation menu
107
+ */
146
108
  export default class MobileMenu {
109
+ /**
110
+ * Create a new MobileMenu instance
111
+ * @param {Object} app - Application instance
112
+ * @param {MobileMenuOptions} [opts={}] - MobileMenu options
113
+ */
147
114
  constructor(app, opts = {}) {
148
115
  this.app = app
149
116
  this.opts = _defaultsDeep(opts, DEFAULT_OPTIONS)
@@ -152,9 +119,13 @@ export default class MobileMenu {
152
119
  this.header = document.querySelector('header')
153
120
  this.bg = this.header.querySelector('.mobile-bg')
154
121
  this.logo = this.header.querySelector('figure.brand')
155
- this.logoPath = this.logo ? this.logo.querySelectorAll(this.opts.logoPathSelector) : null
122
+ this.logoPath = this.logo
123
+ ? this.logo.querySelectorAll(this.opts.logoPathSelector)
124
+ : null
156
125
  this.menuButton = this.header.querySelector('figure.menu-button')
157
- this.hamburger = this.menuButton ? this.menuButton.querySelector('.hamburger') : null
126
+ this.hamburger = this.menuButton
127
+ ? this.menuButton.querySelector('.hamburger')
128
+ : null
158
129
  this.hamburgerInner = this.menuButton
159
130
  ? this.menuButton.querySelector('.hamburger-inner')
160
131
  : null
@@ -163,7 +134,7 @@ export default class MobileMenu {
163
134
  this.nav = this.header.querySelector('nav')
164
135
 
165
136
  if (this.hamburger) {
166
- this.hamburger.addEventListener('click', e => {
137
+ this.hamburger.addEventListener('click', (e) => {
167
138
  e.preventDefault()
168
139
  e.stopPropagation()
169
140
  this.toggleMenu()
@@ -198,12 +169,16 @@ export default class MobileMenu {
198
169
  }
199
170
 
200
171
  _emitMobileMenuOpenEvent() {
201
- const mobileMenuOpenEvent = new window.CustomEvent(Events.APPLICATION_MOBILE_MENU_OPEN)
172
+ const mobileMenuOpenEvent = new window.CustomEvent(
173
+ Events.APPLICATION_MOBILE_MENU_OPEN
174
+ )
202
175
  window.dispatchEvent(mobileMenuOpenEvent)
203
176
  }
204
177
 
205
178
  _emitMobileMenuClosedEvent() {
206
- const mobileMenuClosedEvent = new window.CustomEvent(Events.APPLICATION_MOBILE_MENU_CLOSED)
179
+ const mobileMenuClosedEvent = new window.CustomEvent(
180
+ Events.APPLICATION_MOBILE_MENU_CLOSED
181
+ )
207
182
  window.dispatchEvent(mobileMenuClosedEvent)
208
183
  }
209
184
  }