@brandocms/jupiter 3.55.0 → 4.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/README.md +318 -52
  2. package/package.json +26 -16
  3. package/src/index.js +5 -0
  4. package/src/modules/Application/index.js +36 -4
  5. package/src/modules/Breakpoints/index.js +116 -36
  6. package/src/modules/Cookies/index.js +67 -15
  7. package/src/modules/CoverOverlay/index.js +2 -2
  8. package/src/modules/Dom/index.js +6 -0
  9. package/src/modules/Dropdown/index.js +15 -6
  10. package/src/modules/EqualHeightElements/index.js +8 -6
  11. package/src/modules/EqualHeightImages/index.js +9 -6
  12. package/src/modules/FixedHeader/index.js +57 -1
  13. package/src/modules/FooterReveal/index.js +3 -3
  14. package/src/modules/HeroSlider/index.js +39 -30
  15. package/src/modules/HeroVideo/index.js +64 -24
  16. package/src/modules/Lazyload/index.js +27 -0
  17. package/src/modules/Lightbox/index.js +90 -31
  18. package/src/modules/Links/index.js +23 -2
  19. package/src/modules/MobileMenu/index.js +50 -21
  20. package/src/modules/Moonwalk/index.js +131 -4
  21. package/src/modules/Parallax/index.js +280 -57
  22. package/src/modules/Popover/index.js +28 -16
  23. package/src/modules/Popup/index.js +155 -29
  24. package/src/modules/ScrollSpy/index.js +21 -0
  25. package/src/modules/StackedBoxes/index.js +6 -4
  26. package/src/modules/StickyHeader/index.js +45 -24
  27. package/src/modules/Toggler/index.js +44 -5
  28. package/src/modules/Typography/index.js +33 -20
  29. package/types/README.md +159 -0
  30. package/types/events/index.d.ts +20 -0
  31. package/types/index.d.ts +35 -0
  32. package/types/modules/Application/index.d.ts +168 -0
  33. package/types/modules/Breakpoints/index.d.ts +38 -0
  34. package/types/modules/Cookies/index.d.ts +81 -0
  35. package/types/modules/CoverOverlay/index.d.ts +6 -0
  36. package/types/modules/Dataloader/index.d.ts +35 -0
  37. package/types/modules/Dom/index.d.ts +40 -0
  38. package/types/modules/Dropdown/index.d.ts +38 -0
  39. package/types/modules/EqualHeightElements/index.d.ts +8 -0
  40. package/types/modules/EqualHeightImages/index.d.ts +11 -0
  41. package/types/modules/FeatureTests/index.d.ts +27 -0
  42. package/types/modules/FixedHeader/index.d.ts +219 -0
  43. package/types/modules/Fontloader/index.d.ts +5 -0
  44. package/types/modules/FooterReveal/index.d.ts +5 -0
  45. package/types/modules/HeroSlider/index.d.ts +28 -0
  46. package/types/modules/HeroVideo/index.d.ts +83 -0
  47. package/types/modules/Lazyload/index.d.ts +80 -0
  48. package/types/modules/Lightbox/index.d.ts +128 -0
  49. package/types/modules/Links/index.d.ts +55 -0
  50. package/types/modules/Marquee/index.d.ts +23 -0
  51. package/types/modules/MobileMenu/index.d.ts +63 -0
  52. package/types/modules/Moonwalk/index.d.ts +331 -0
  53. package/types/modules/Parallax/index.d.ts +93 -0
  54. package/types/modules/Popover/index.d.ts +17 -0
  55. package/types/modules/Popup/index.d.ts +89 -0
  56. package/types/modules/ScrollSpy/index.d.ts +29 -0
  57. package/types/modules/StackedBoxes/index.d.ts +9 -0
  58. package/types/modules/StickyHeader/index.d.ts +63 -0
  59. package/types/modules/Toggler/index.d.ts +26 -0
  60. package/types/modules/Typography/index.d.ts +77 -0
  61. package/types/utils/dispatchElementEvent.d.ts +1 -0
  62. package/types/utils/imageIsLoaded.d.ts +1 -0
  63. package/types/utils/imagesAreLoaded.d.ts +1 -0
  64. package/types/utils/loadScript.d.ts +2 -0
  65. package/types/utils/prefersReducedMotion.d.ts +4 -0
  66. package/types/utils/rafCallback.d.ts +2 -0
  67. package/types/utils/zoom.d.ts +4 -0
@@ -1,6 +1,14 @@
1
1
  import _defaultsDeep from 'lodash.defaultsdeep'
2
2
  import * as Events from '../../events'
3
3
 
4
+ /**
5
+ * @typedef {Object} BreakpointsOptions
6
+ * @property {boolean} [runListenerOnInit=false] - Whether to run listener on initialization
7
+ * @property {string[]} [breakpoints=['xs', 'sm', 'md', 'lg']] - Breakpoint names
8
+ * @property {Object.<string, Function>} [listeners={}] - Listener functions for breakpoints
9
+ */
10
+
11
+ /** @type {BreakpointsOptions} */
4
12
  const DEFAULT_OPTIONS = {
5
13
  runListenerOnInit: false,
6
14
  breakpoints: ['xs', 'sm', 'md', 'lg'],
@@ -13,14 +21,24 @@ const DEFAULT_OPTIONS = {
13
21
  // // NOT XS ANYMORE
14
22
  // }
15
23
  // }
16
- }
24
+ },
17
25
  }
18
26
 
27
+ /**
28
+ * Breakpoints module for responsive design
29
+ */
19
30
  export default class Breakpoints {
31
+ /**
32
+ * Create a new Breakpoints instance
33
+ * @param {Object} app - Application instance
34
+ * @param {BreakpointsOptions} [opts={}] - Breakpoints options
35
+ */
20
36
  constructor(app, opts = {}) {
21
37
  this.app = app
22
38
  this.mediaQueries = {}
23
39
  this.opts = _defaultsDeep(opts, DEFAULT_OPTIONS)
40
+ this.currentBreakpoint = null
41
+ this.initialized = false
24
42
  window.addEventListener(Events.APPLICATION_PRELUDIUM, () => {
25
43
  this.initialize(false)
26
44
  })
@@ -30,63 +48,125 @@ export default class Breakpoints {
30
48
  }
31
49
 
32
50
  initialize(reveal = false) {
33
- this.opts.breakpoints.forEach(size => {
34
- this.mediaQueries[size] = this._getVal(`--breakpoint-${size}`)
35
- })
51
+ if (!reveal) {
52
+ this.opts.breakpoints.forEach((size) => {
53
+ this.mediaQueries[size] = this._getVal(`--breakpoint-${size}`)
54
+ })
36
55
 
37
- const keys = Object.keys(this.mediaQueries)
38
- keys.forEach(key => {
39
- let query = ''
40
- const next = keys[(keys.indexOf(key) + 1) % keys.length]
41
- if (key === this.opts.breakpoints[0] && this.mediaQueries[key] === '0') {
42
- query = `(min-width: 0px) and (max-width: ${parseInt(this.mediaQueries[next]) - 1}px)`
43
- } else if (next === this.opts.breakpoints[0]) {
44
- // max size
45
- query = `(min-width: ${this.mediaQueries[key]})`
46
- } else {
47
- query = `(min-width: ${this.mediaQueries[key]}) and (max-width: ${
48
- parseInt(this.mediaQueries[next]) - 1
49
- }px)`
50
- }
56
+ const keys = Object.keys(this.mediaQueries)
57
+ keys.forEach((key) => {
58
+ let query = ''
59
+ const next = keys[(keys.indexOf(key) + 1) % keys.length]
60
+ if (
61
+ key === this.opts.breakpoints[0] &&
62
+ this.mediaQueries[key] === '0'
63
+ ) {
64
+ query = `(min-width: 0px) and (max-width: ${parseInt(this.mediaQueries[next]) - 1}px)`
65
+ } else if (next === this.opts.breakpoints[0]) {
66
+ // max size
67
+ query = `(min-width: ${this.mediaQueries[key]})`
68
+ } else {
69
+ query = `(min-width: ${this.mediaQueries[key]}) and (max-width: ${
70
+ parseInt(this.mediaQueries[next]) - 1
71
+ }px)`
72
+ }
51
73
 
52
- this.mediaQueries[key] = window.matchMedia(query)
53
- this.mediaQueries[key].addListener(this.defaultListener.bind(this))
74
+ this.mediaQueries[key] = window.matchMedia(query)
54
75
 
55
- if (Object.prototype.hasOwnProperty.call(this.opts.listeners, key)) {
56
- this.mediaQueries[key].addListener(this.opts.listeners[key])
57
- }
58
- })
76
+ // Replace the direct listener with a combined one that handles both core and custom behavior
77
+ const combinedListener = (e) => {
78
+ if (e.matches) {
79
+ // Get the current breakpoint
80
+ const oldBreakpoint = this.currentBreakpoint
81
+ this.setCurrentBreakpoint()
59
82
 
60
- if (reveal && this.opts.runListenerOnInit) {
61
- const { key, mq } = this.getCurrentBreakpoint()
62
- if (Object.prototype.hasOwnProperty.call(this.opts.listeners, key)) {
63
- this.opts.listeners[key](mq)
64
- }
83
+ // Only dispatch event if breakpoint actually changed
84
+ if (oldBreakpoint !== this.currentBreakpoint) {
85
+ const evt = new CustomEvent(Events.BREAKPOINT_CHANGE, {
86
+ detail: {
87
+ leaveBreakpoint: oldBreakpoint,
88
+ enterBreakpoint: this.currentBreakpoint,
89
+ },
90
+ })
91
+ window.dispatchEvent(evt)
92
+ }
93
+ }
94
+
95
+ // Run any custom listener if one exists for this breakpoint
96
+ if (Object.prototype.hasOwnProperty.call(this.opts.listeners, key)) {
97
+ this.opts.listeners[key](e)
98
+ }
99
+ }
100
+
101
+ this.mediaQueries[key].addListener(combinedListener)
102
+ })
65
103
  }
66
104
 
105
+ // Set the current breakpoint first
67
106
  this.setCurrentBreakpoint()
107
+
108
+ // Only fire events and run listeners for initialization if needed
109
+ if (reveal && this.opts.runListenerOnInit && !this.initialized) {
110
+ this.initialized = true
111
+ const result = this.getCurrentBreakpoint()
112
+
113
+ if (result && result.key && result.mq) {
114
+ // Create a fake event object that mimics MediaQueryListEvent
115
+ const fakeEvent = {
116
+ matches: result.mq.matches,
117
+ media: result.mq.media,
118
+ target: result.mq,
119
+ }
120
+
121
+ // Fire the BREAKPOINT_CHANGE event only once during initialization
122
+ const evt = new CustomEvent(Events.BREAKPOINT_CHANGE)
123
+ window.dispatchEvent(evt)
124
+
125
+ // Run any custom listener if one exists for this breakpoint
126
+ if (
127
+ Object.prototype.hasOwnProperty.call(this.opts.listeners, result.key)
128
+ ) {
129
+ this.opts.listeners[result.key](fakeEvent)
130
+ }
131
+ }
132
+ }
68
133
  }
69
134
 
70
135
  getCurrentBreakpoint() {
71
- const key = Object.keys(this.mediaQueries).find(q => this.mediaQueries[q].matches)
136
+ // First check if mediaQueries is populated
137
+ if (!Object.keys(this.mediaQueries).length) {
138
+ return null
139
+ }
72
140
 
73
- return { key, mq: this.mediaQueries[key] }
141
+ const key = Object.keys(this.mediaQueries).find((q) => {
142
+ return this.mediaQueries[q] && this.mediaQueries[q].matches
143
+ })
144
+
145
+ // Only return if we found a matching breakpoint
146
+ if (key && this.mediaQueries[key]) {
147
+ return { key, mq: this.mediaQueries[key] }
148
+ }
149
+
150
+ return null
74
151
  }
75
152
 
76
153
  defaultListener(e) {
77
154
  if (e.matches) {
78
155
  this.setCurrentBreakpoint()
79
156
  }
80
- const evt = new CustomEvent(Events.BREAKPOINT_CHANGE)
81
- window.dispatchEvent(evt)
82
157
  }
83
158
 
84
159
  setCurrentBreakpoint() {
85
- const { key } = this.getCurrentBreakpoint()
86
- this.app.breakpoint = key
160
+ const result = this.getCurrentBreakpoint()
161
+ if (result && result.key) {
162
+ this.currentBreakpoint = result.key
163
+ this.app.breakpoint = result.key
164
+ }
87
165
  }
88
166
 
89
167
  _getVal(key) {
90
- return getComputedStyle(document.documentElement).getPropertyValue(key).trim()
168
+ return getComputedStyle(document.documentElement)
169
+ .getPropertyValue(key)
170
+ .trim()
91
171
  }
92
172
  }
@@ -1,9 +1,20 @@
1
- import { gsap } from 'gsap'
1
+ import { gsap } from 'gsap/all'
2
2
  import _defaultsDeep from 'lodash.defaultsdeep'
3
3
  import * as Events from '../../events'
4
4
 
5
+ /**
6
+ * @typedef {Object} CookiesOptions
7
+ * @property {Function} [onAccept] - Called when cookies are accepted
8
+ * @property {Function} [onRefuse] - Called when cookies are refused
9
+ * @property {Function} [alreadyConsented] - Called if user has already consented to cookies
10
+ * @property {Function} [alreadyRefused] - Called if user has already refused cookies
11
+ * @property {Function} [setCookies] - Custom function to set cookies
12
+ * @property {Function} [showCC] - Custom function to display cookie consent dialog
13
+ */
14
+
15
+ /** @type {CookiesOptions} */
5
16
  const DEFAULT_OPTIONS = {
6
- onAccept: c => {
17
+ onAccept: (c) => {
7
18
  const oneYearFromNow = new Date()
8
19
  oneYearFromNow.setFullYear(oneYearFromNow.getFullYear() + 1)
9
20
 
@@ -17,7 +28,7 @@ const DEFAULT_OPTIONS = {
17
28
  .set(c.cc, { display: 'none' })
18
29
  },
19
30
 
20
- onRefuse: c => {
31
+ onRefuse: (c) => {
21
32
  const oneYearFromNow = new Date()
22
33
  oneYearFromNow.setFullYear(oneYearFromNow.getFullYear() + 1)
23
34
 
@@ -30,17 +41,17 @@ const DEFAULT_OPTIONS = {
30
41
  .set(c.cc, { display: 'none' })
31
42
  },
32
43
 
33
- alreadyConsented: c => {
44
+ alreadyConsented: (c) => {
34
45
  // user has already consented to cookies. Can be used to update/load gtm etc.
35
46
  },
36
47
 
37
- alreadyRefused: c => {
48
+ alreadyRefused: (c) => {
38
49
  // user has already refused cookies.
39
50
  },
40
51
 
41
- setCookies: c => {},
52
+ setCookies: (c) => {},
42
53
 
43
- showCC: c => {
54
+ showCC: (c) => {
44
55
  if (c.hasCookie('COOKIES_CONSENT_STATUS')) {
45
56
  if (c.getCookie('COOKIES_CONSENT_STATUS') === '1') {
46
57
  c.opts.alreadyConsented(c)
@@ -58,13 +69,13 @@ const DEFAULT_OPTIONS = {
58
69
  {
59
70
  duration: 0.5,
60
71
  y: '120%',
61
- display: 'block'
72
+ display: 'block',
62
73
  },
63
74
  {
64
75
  duration: 0.5,
65
76
  y: '0%',
66
77
  delay: '0.5',
67
- ease: 'power3.out'
78
+ ease: 'power3.out',
68
79
  },
69
80
  '0.5'
70
81
  )
@@ -72,12 +83,12 @@ const DEFAULT_OPTIONS = {
72
83
  c.text,
73
84
  {
74
85
  duration: 0.7,
75
- opacity: 0
86
+ opacity: 0,
76
87
  },
77
88
  {
78
89
  duration: 0.7,
79
90
  opacity: 1,
80
- ease: 'power3.out'
91
+ ease: 'power3.out',
81
92
  },
82
93
  '-=0.35'
83
94
  )
@@ -85,19 +96,27 @@ const DEFAULT_OPTIONS = {
85
96
  c.btns,
86
97
  {
87
98
  duration: 0.7,
88
- opacity: 0
99
+ opacity: 0,
89
100
  },
90
101
  {
91
102
  duration: 0.7,
92
103
  opacity: 1,
93
- ease: 'power3.out'
104
+ ease: 'power3.out',
94
105
  },
95
106
  '-=0.35'
96
107
  )
97
- }
108
+ },
98
109
  }
99
110
 
111
+ /**
112
+ * Cookies module for handling cookie consent
113
+ */
100
114
  export default class Cookies {
115
+ /**
116
+ * Create a new Cookies instance
117
+ * @param {Object} app - Application instance
118
+ * @param {CookiesOptions} [opts={}] - Cookies options
119
+ */
101
120
  constructor(app, opts = {}) {
102
121
  this.app = app
103
122
  this.opts = _defaultsDeep(opts, DEFAULT_OPTIONS)
@@ -127,6 +146,11 @@ export default class Cookies {
127
146
  }
128
147
  }
129
148
 
149
+ /**
150
+ * Get a cookie value by key
151
+ * @param {string} sKey - Cookie key
152
+ * @returns {string|null} Cookie value or null if not found
153
+ */
130
154
  getCookie(sKey) {
131
155
  if (!sKey) {
132
156
  return null
@@ -146,6 +170,16 @@ export default class Cookies {
146
170
  )
147
171
  }
148
172
 
173
+ /**
174
+ * Set a cookie
175
+ * @param {string} sKey - Cookie key
176
+ * @param {string|number} sValue - Cookie value
177
+ * @param {Date|string|number} vEnd - Expiration date, string date, or max age in seconds
178
+ * @param {string} [sPath] - Cookie path
179
+ * @param {string} [sDomain] - Cookie domain
180
+ * @param {boolean} [bSecure] - Secure flag
181
+ * @returns {boolean} Whether cookie was set successfully
182
+ */
149
183
  setCookie(sKey, sValue, vEnd, sPath, sDomain, bSecure) {
150
184
  if (!sKey || /^(?:expires|max-age|path|domain|secure)$/i.test(sKey)) {
151
185
  return false
@@ -155,7 +189,9 @@ export default class Cookies {
155
189
  switch (vEnd.constructor) {
156
190
  case Number:
157
191
  sExpires =
158
- vEnd === Infinity ? '; expires=Fri, 31 Dec 9999 23:59:59 GMT' : `; max-age=${vEnd}`
192
+ vEnd === Infinity
193
+ ? '; expires=Fri, 31 Dec 9999 23:59:59 GMT'
194
+ : `; max-age=${vEnd}`
159
195
  break
160
196
  case String:
161
197
  sExpires = `; expires=${vEnd}`
@@ -173,6 +209,13 @@ export default class Cookies {
173
209
  return true
174
210
  }
175
211
 
212
+ /**
213
+ * Remove a cookie
214
+ * @param {string} sKey - Cookie key
215
+ * @param {string} [sPath] - Cookie path
216
+ * @param {string} [sDomain] - Cookie domain
217
+ * @returns {boolean} Whether cookie was removed successfully
218
+ */
176
219
  removeCookie(sKey, sPath, sDomain) {
177
220
  if (!this.hasCookie(sKey)) {
178
221
  return false
@@ -183,6 +226,11 @@ export default class Cookies {
183
226
  return true
184
227
  }
185
228
 
229
+ /**
230
+ * Check if a cookie exists
231
+ * @param {string} sKey - Cookie key
232
+ * @returns {boolean} Whether cookie exists
233
+ */
186
234
  hasCookie(sKey) {
187
235
  if (!sKey || /^(?:expires|max-age|path|domain|secure)$/i.test(sKey)) {
188
236
  return false
@@ -192,6 +240,10 @@ export default class Cookies {
192
240
  ).test(document.cookie)
193
241
  }
194
242
 
243
+ /**
244
+ * Get all cookie keys
245
+ * @returns {string[]} Array of cookie keys
246
+ */
195
247
  keys() {
196
248
  const aKeys = document.cookie
197
249
  .replace(/((?:^|\s*;)[^=]+)(?=;|$)|^\s*|\s*(?:=[^;]*)?(?:\1|$)/g, '')
@@ -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,7 +13,7 @@ export default class CoverOverlay {
13
13
  initialize() {
14
14
  const coveredModules = document.querySelectorAll('[data-cover-overlay]')
15
15
 
16
- Array.from(coveredModules).forEach(v => {
16
+ Array.from(coveredModules).forEach((v) => {
17
17
  let player
18
18
  const overlay = v.querySelector('.picture-wrapper')
19
19
  const btn = v.querySelector('[data-cover-overlay-button]')
@@ -1,4 +1,10 @@
1
+ /**
2
+ * DOM utility class for simplifying DOM operations
3
+ */
1
4
  class DOM {
5
+ /**
6
+ * Create a new DOM utility instance
7
+ */
2
8
  constructor() {
3
9
  this.body = document.body
4
10
  this.html = document.documentElement
@@ -1,4 +1,4 @@
1
- import { gsap } from 'gsap'
1
+ import { gsap } from 'gsap/all'
2
2
  import _defaultsDeep from 'lodash.defaultsdeep'
3
3
  import Dom from '../Dom'
4
4
 
@@ -27,6 +27,8 @@ const DEFAULT_OPTIONS = {
27
27
  menu: '[data-dropdown-menu]',
28
28
  menuItems: '[data-dropdown-menu] > li',
29
29
  },
30
+ overlapTweens: true,
31
+ menuOpenDuration: 0.1,
30
32
  tweens: {
31
33
  items: {
32
34
  duration: 0.2,
@@ -80,7 +82,7 @@ export default class Dropdown {
80
82
  this.elements.menu,
81
83
  {
82
84
  className: `${this.elements.menu.className} zero-height`,
83
- duration: 0.1,
85
+ duration: 0.05,
84
86
  },
85
87
  'open'
86
88
  )
@@ -88,7 +90,7 @@ export default class Dropdown {
88
90
  this.elements.menu,
89
91
  {
90
92
  height: 'auto',
91
- duration: 0.1,
93
+ duration: 0.05,
92
94
  },
93
95
  'open'
94
96
  )
@@ -126,13 +128,16 @@ export default class Dropdown {
126
128
  this.elements.menu.style.left = `${currentLeft - (menuRect.right - viewportWidth)}px`
127
129
  }
128
130
  })
129
- .to(this.elements.menu, { opacity: 1 })
131
+ .to(this.elements.menu, {
132
+ opacity: 1,
133
+ duration: this.opts.menuOpenDuration,
134
+ })
130
135
 
131
136
  if (this.elements.menuItems.length) {
132
137
  this.timeline.from(
133
138
  this.elements.menuItems,
134
139
  this.opts.tweens.items,
135
- 'open+=.1'
140
+ `open+=${this.opts.menuOpenDuration}`
136
141
  )
137
142
  }
138
143
 
@@ -160,7 +165,11 @@ export default class Dropdown {
160
165
  async openMenu() {
161
166
  if (!this.opts.multipleActive) {
162
167
  if (this.app.currentMenu) {
163
- this.app.currentMenu.closeMenu()
168
+ if (this.opts.overlapTweens) {
169
+ this.app.currentMenu.closeMenu()
170
+ } else {
171
+ await this.app.currentMenu.closeMenu()
172
+ }
164
173
  }
165
174
  this.app.currentMenu = this
166
175
  }
@@ -1,4 +1,4 @@
1
- import { gsap } from 'gsap'
1
+ import { gsap } from 'gsap/all'
2
2
  import Dom from '../Dom'
3
3
  import _defaultsDeep from 'lodash.defaultsdeep'
4
4
  import * as Events from '../../events'
@@ -13,21 +13,23 @@ export default class EqualHeightElements {
13
13
  this.selector = selector
14
14
  this.initialize()
15
15
  window.addEventListener(Events.APPLICATION_RESIZE, () => {
16
- gsap.set('[data-eq-height-elements-adjusted]', { clearProps: 'minHeight' })
16
+ gsap.set('[data-eq-height-elements-adjusted]', {
17
+ clearProps: 'minHeight',
18
+ })
17
19
  this.initialize()
18
20
  })
19
21
  }
20
22
 
21
23
  initialize() {
22
24
  const canvases = Dom.all(this.container, '[data-eq-height-elements]')
23
- Array.from(canvases).forEach(canvas => {
25
+ Array.from(canvases).forEach((canvas) => {
24
26
  let lastTop = null
25
27
  const actionables = []
26
28
  let elements = []
27
29
  let height = 0
28
30
  const eqElements = Dom.all(canvas, this.selector)
29
31
 
30
- eqElements.forEach(el => {
32
+ eqElements.forEach((el) => {
31
33
  const rect = el.getBoundingClientRect()
32
34
 
33
35
  if (lastTop === null) {
@@ -58,10 +60,10 @@ export default class EqualHeightElements {
58
60
  }
59
61
 
60
62
  if (actionables.length) {
61
- actionables.forEach(a => {
63
+ actionables.forEach((a) => {
62
64
  gsap.set(a.elements, {
63
65
  minHeight: a.height,
64
- attr: { 'data-eq-height-elements-adjusted': true }
66
+ attr: { 'data-eq-height-elements-adjusted': true },
65
67
  })
66
68
  })
67
69
  }
@@ -1,11 +1,11 @@
1
- import { gsap } from 'gsap'
1
+ import { gsap } from 'gsap/all'
2
2
  import Dom from '../Dom'
3
3
  import * as Events from '../../events'
4
4
  import imagesAreLoaded from '../../utils/imagesAreLoaded'
5
5
  import _defaultsDeep from 'lodash.defaultsdeep'
6
6
 
7
7
  const DEFAULT_OPTIONS = {
8
- listenForResize: true
8
+ listenForResize: true,
9
9
  }
10
10
 
11
11
  export default class EqualHeightImages {
@@ -23,7 +23,7 @@ export default class EqualHeightImages {
23
23
  }
24
24
 
25
25
  run() {
26
- Array.from(this.canvases).forEach(canvas => {
26
+ Array.from(this.canvases).forEach((canvas) => {
27
27
  let lastTop = null
28
28
  const actionables = []
29
29
  let elements = []
@@ -31,7 +31,7 @@ export default class EqualHeightImages {
31
31
  const imgs = Dom.all(canvas, 'img')
32
32
 
33
33
  imagesAreLoaded(imgs, false).then(() => {
34
- imgs.forEach(el => {
34
+ imgs.forEach((el) => {
35
35
  const rect = el.getBoundingClientRect()
36
36
  const size = this.getImgSizeInfo(el)
37
37
 
@@ -62,7 +62,7 @@ export default class EqualHeightImages {
62
62
  }
63
63
 
64
64
  if (actionables.length) {
65
- actionables.forEach(a => {
65
+ actionables.forEach((a) => {
66
66
  gsap.set(a.elements, { minHeight: a.height })
67
67
  })
68
68
  }
@@ -94,7 +94,10 @@ export default class EqualHeightImages {
94
94
  }
95
95
 
96
96
  getImgSizeInfo(img) {
97
- const pos = window.getComputedStyle(img).getPropertyValue('object-position').split(' ')
97
+ const pos = window
98
+ .getComputedStyle(img)
99
+ .getPropertyValue('object-position')
100
+ .split(' ')
98
101
 
99
102
  return this.getRenderedSize(
100
103
  true,
@@ -23,11 +23,58 @@
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
  import Dom from '../Dom'
30
30
 
31
+ /**
32
+ * @typedef {Object} FixedHeaderEvents
33
+ * @property {Function} [onPin] - Called when header is pinned
34
+ * @property {Function} [onUnpin] - Called when header is unpinned
35
+ * @property {Function} [onAltBg] - Called when alternate background is applied
36
+ * @property {Function} [onNotAltBg] - Called when regular background is applied
37
+ * @property {Function} [onSmall] - Called when header becomes small
38
+ * @property {Function} [onNotSmall] - Called when header becomes normal size
39
+ * @property {Function} [onTop] - Called when page is at the top
40
+ * @property {Function} [onNotTop] - Called when page is not at the top
41
+ * @property {Function} [onBottom] - Called when page is at the bottom
42
+ * @property {Function} [onNotBottom] - Called when page is not at the bottom
43
+ * @property {Function} [onMobileMenuOpen] - Called when mobile menu opens
44
+ * @property {Function} [onMobileMenuClose] - Called when mobile menu closes
45
+ * @property {Function} [onIntersect] - Called when header intersects with an element
46
+ * @property {Function} [onOutline] - Called when user tabs (outline mode)
47
+ */
48
+
49
+ /**
50
+ * @typedef {Object} FixedHeaderSectionOptions
51
+ * @property {boolean} [unPinOnResize=true] - Whether to unpin header on window resize
52
+ * @property {Window|HTMLElement} [canvas=window] - Scrolling element
53
+ * @property {string|null} [intersects=null] - Selector for elements to check intersection with
54
+ * @property {Function} [beforeEnter] - Called before header enters
55
+ * @property {Function} [enter] - Called when header enters
56
+ * @property {number} [enterDelay=0] - Delay before enter animation
57
+ * @property {number} [tolerance=3] - Scroll tolerance before triggering hide/show
58
+ * @property {number|string|Function} [offset=0] - Offset from top before triggering hide
59
+ * @property {number|string|Function} [offsetSmall=50] - Offset from top before shrinking header
60
+ * @property {number|string|Function} [offsetBg=200] - Offset from top before changing background color
61
+ * @property {string|null} [regBgColor=null] - Regular background color
62
+ * @property {string|null} [altBgColor=null] - Alternate background color
63
+ */
64
+
65
+ /**
66
+ * @typedef {Object} FixedHeaderOptions
67
+ * @property {string|HTMLElement} [el='header[data-nav]'] - Header element or selector
68
+ * @property {string} [on=Events.APPLICATION_REVEALED] - Event to initialize on
69
+ * @property {boolean} [unpinOnForcedScrollStart=true] - Whether to unpin on forced scroll start
70
+ * @property {boolean} [pinOnForcedScrollEnd=true] - Whether to pin on forced scroll end
71
+ * @property {boolean} [ignoreForcedScroll=false] - Whether to ignore forced scroll events
72
+ * @property {boolean} [rafScroll=true] - Whether to use requestAnimationFrame for scrolling
73
+ * @property {FixedHeaderSectionOptions} [default] - Default options for all sections
74
+ * @property {Object.<string, FixedHeaderSectionOptions>} [sections] - Section-specific options
75
+ */
76
+
77
+ /** @type {FixedHeaderEvents} */
31
78
  const DEFAULT_EVENTS = {
32
79
  onPin: (h) => {
33
80
  gsap.to(h.el, {
@@ -93,6 +140,7 @@ const DEFAULT_EVENTS = {
93
140
  },
94
141
  }
95
142
 
143
+ /** @type {FixedHeaderOptions} */
96
144
  const DEFAULT_OPTIONS = {
97
145
  el: 'header[data-nav]',
98
146
  on: Events.APPLICATION_REVEALED,
@@ -134,7 +182,15 @@ const DEFAULT_OPTIONS = {
134
182
  },
135
183
  }
136
184
 
185
+ /**
186
+ * FixedHeader component for sticky navigation headers with scroll behaviors
187
+ */
137
188
  export default class FixedHeader {
189
+ /**
190
+ * Create a new FixedHeader instance
191
+ * @param {Object} app - Application instance
192
+ * @param {FixedHeaderOptions} [opts={}] - FixedHeader options
193
+ */
138
194
  constructor(app, opts = {}) {
139
195
  this.app = app
140
196
  this.mainOpts = _defaultsDeep(opts, DEFAULT_OPTIONS)
@@ -1,9 +1,9 @@
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 = {
5
5
  shadow: false,
6
- shadowColor: 'rgba(255, 255, 255, 1)'
6
+ shadowColor: 'rgba(255, 255, 255, 1)',
7
7
  }
8
8
 
9
9
  export default class FooterReveal {
@@ -17,7 +17,7 @@ export default class FooterReveal {
17
17
  gsap.set(footer, {
18
18
  'z-index': -100,
19
19
  position: 'fixed',
20
- bottom: 0
20
+ bottom: 0,
21
21
  })
22
22
  const footerHeight = footer.offsetHeight
23
23
  // add height as margin