@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,8 +1,18 @@
1
- import { gsap } from 'gsap/all'
1
+ import { animate } from 'motion'
2
2
  import Dom from '../Dom'
3
3
  import _defaultsDeep from 'lodash.defaultsdeep'
4
+ import * as Events from '../../events'
4
5
 
5
- const DEFAULT_OPTIONS = {}
6
+ const DEFAULT_OPTIONS = {
7
+ clickToggle: false,
8
+ allowMultiple: false,
9
+ followTrigger: false,
10
+ followSpeed: 0.3,
11
+ onShow: null,
12
+ }
13
+
14
+ // Static array to track active popovers
15
+ const activePopovers = []
6
16
 
7
17
  export default class Popover {
8
18
  constructor(app, trigger, opts = {}) {
@@ -13,10 +23,17 @@ export default class Popover {
13
23
  this.position = this.trigger.getAttribute('data-popover-position') || 'top'
14
24
  this.className = 'popover'
15
25
  this.orderedPositions = ['top', 'right', 'bottom', 'left']
26
+ this.currentPosition = this.position
16
27
 
17
28
  const popoverTemplate = document.querySelector(
18
29
  `[data-popover-template=${trigger.dataset.popoverTarget}]`
19
30
  )
31
+
32
+ if (!popoverTemplate) {
33
+ console.warn(`Popover template not found for trigger: ${trigger.dataset.popoverTarget}`)
34
+ return
35
+ }
36
+
20
37
  this.popover = document.createElement('div')
21
38
  this.popover.innerHTML = popoverTemplate.innerHTML
22
39
 
@@ -24,22 +41,31 @@ export default class Popover {
24
41
  position: 'fixed',
25
42
  })
26
43
 
44
+ // Add base popover class
27
45
  this.popover.classList.add(this.className)
28
46
 
47
+ // Add any classes from the template element
48
+ if (popoverTemplate.classList && popoverTemplate.classList.length > 0) {
49
+ popoverTemplate.classList.forEach(className => {
50
+ if (className !== 'popover-template') {
51
+ this.popover.classList.add(className)
52
+ }
53
+ })
54
+ }
55
+
56
+ // Bind handlers
57
+ this.boundHandleDocumentClick = this.handleDocumentClick.bind(this)
58
+ this.boundHandleScroll = this.handleScroll.bind(this)
59
+
29
60
  if (!app.featureTests.results.touch) {
30
- this.trigger.addEventListener(
31
- 'mouseenter',
32
- this.handleMouseEnter.bind(this)
33
- )
34
- this.trigger.addEventListener(
35
- 'mouseleave',
36
- this.handleMouseLeave.bind(this)
37
- )
61
+ if (this.opts.clickToggle) {
62
+ this.trigger.addEventListener('click', this.handleClick.bind(this))
63
+ } else {
64
+ this.trigger.addEventListener('mouseenter', this.handleMouseEnter.bind(this))
65
+ this.trigger.addEventListener('mouseleave', this.handleMouseLeave.bind(this))
66
+ }
38
67
  } else {
39
- this.trigger.addEventListener(
40
- 'touchstart',
41
- this.handleTouchStart.bind(this)
42
- )
68
+ this.trigger.addEventListener('touchstart', this.handleTouchStart.bind(this))
43
69
  }
44
70
  }
45
71
 
@@ -55,19 +81,61 @@ export default class Popover {
55
81
  this.toggle()
56
82
  }
57
83
 
84
+ handleClick(e) {
85
+ e.stopPropagation()
86
+ this.toggle()
87
+ }
88
+
58
89
  get isVisible() {
59
90
  return document.body.contains(this.popover)
60
91
  }
61
92
 
62
93
  show() {
94
+ // Close other popovers if not allowing multiple
95
+ if (!this.opts.allowMultiple) {
96
+ this.closeAllExcept(this)
97
+ }
98
+
63
99
  document.body.appendChild(this.popover)
64
100
 
65
- const { top: triggerTop, left: triggerLeft } =
66
- this.trigger.getBoundingClientRect()
67
- const { offsetHeight: triggerHeight, offsetWidth: triggerWidth } =
68
- this.trigger
69
- const { offsetHeight: popoverHeight, offsetWidth: popoverWidth } =
70
- this.popover
101
+ // Add to active popovers list
102
+ if (!activePopovers.includes(this)) {
103
+ activePopovers.push(this)
104
+ }
105
+
106
+ // Calculate initial position
107
+ this.updatePosition(false)
108
+
109
+ // Setup document click handler for click outside closing
110
+ if (this.opts.clickToggle) {
111
+ this.addDocumentClickHandler()
112
+ }
113
+
114
+ // Setup scroll handler if followTrigger is enabled
115
+ if (this.opts.followTrigger) {
116
+ // Use requestAnimationFrame to ensure the popover is fully rendered
117
+ requestAnimationFrame(() => {
118
+ this.addScrollListener()
119
+ })
120
+ }
121
+
122
+ // Call onShow callback if provided
123
+ if (typeof this.opts.onShow === 'function') {
124
+ requestAnimationFrame(() => {
125
+ this.opts.onShow(this)
126
+ })
127
+ }
128
+ }
129
+
130
+ // Update popover position based on trigger position
131
+ updatePosition(shouldAnimate = true) {
132
+ const {
133
+ top: triggerTop,
134
+ left: triggerLeft,
135
+ width: triggerWidth,
136
+ height: triggerHeight,
137
+ } = this.trigger.getBoundingClientRect()
138
+ const { offsetHeight: popoverHeight, offsetWidth: popoverWidth } = this.popover
71
139
 
72
140
  const positionIndex = this.orderedPositions.indexOf(this.position)
73
141
 
@@ -94,31 +162,77 @@ export default class Popover {
94
162
  },
95
163
  }
96
164
 
165
+ // Try to find a position that keeps the popover in viewport
97
166
  const position = this.orderedPositions
98
167
  .slice(positionIndex)
99
168
  .concat(this.orderedPositions.slice(0, positionIndex))
100
- .map((pos) => positions[pos])
101
- .find((pos) => {
102
- this.popover.style.top = `${pos.top}px`
103
- this.popover.style.left = `${pos.left}px`
104
- return Dom.inViewport(this.popover)
169
+ .map(pos => positions[pos])
170
+ .find(pos => {
171
+ // Temporarily set position to check viewport
172
+ if (!shouldAnimate) {
173
+ this.popover.style.top = `${pos.top}px`
174
+ this.popover.style.left = `${pos.left}px`
175
+ }
176
+ return Dom.inViewportStrict(this.popover)
105
177
  })
106
178
 
107
- this.orderedPositions.forEach((pos) => {
179
+ // Remove previous position classes
180
+ this.orderedPositions.forEach(pos => {
108
181
  this.popover.classList.remove(`${this.className}--${pos}`)
109
182
  })
110
183
 
184
+ // Set position and apply appropriate class
111
185
  if (position) {
186
+ if (shouldAnimate && this.isVisible) {
187
+ animate(this.popover, {
188
+ top: Math.max(0, position.top),
189
+ left: Math.max(0, position.left)
190
+ }, {
191
+ duration: this.opts.followSpeed,
192
+ ease: 'easeOut'
193
+ })
194
+ } else if (!shouldAnimate) {
195
+ this.popover.style.top = `${Math.max(0, position.top)}px`
196
+ this.popover.style.left = `${Math.max(0, position.left)}px`
197
+ }
112
198
  this.popover.classList.add(`${this.className}--${position.name}`)
199
+ this.currentPosition = position.name
113
200
  } else {
114
- this.popover.style.top = positions.bottom.top
115
- this.popover.style.left = positions.bottom.left
201
+ // Fallback to bottom if no position works
202
+ if (shouldAnimate && this.isVisible) {
203
+ animate(this.popover, {
204
+ top: Math.max(0, positions.bottom.top),
205
+ left: Math.max(0, positions.bottom.left)
206
+ }, {
207
+ duration: this.opts.followSpeed,
208
+ ease: 'easeOut'
209
+ })
210
+ } else if (!shouldAnimate) {
211
+ this.popover.style.top = `${Math.max(0, positions.bottom.top)}px`
212
+ this.popover.style.left = `${Math.max(0, positions.bottom.left)}px`
213
+ }
116
214
  this.popover.classList.add(`${this.className}--bottom`)
215
+ this.currentPosition = 'bottom'
117
216
  }
118
217
  }
119
218
 
120
219
  hide() {
121
220
  this.popover.remove()
221
+
222
+ // Remove from active popovers
223
+ const index = activePopovers.indexOf(this)
224
+ if (index !== -1) {
225
+ activePopovers.splice(index, 1)
226
+ }
227
+
228
+ // Remove handlers
229
+ if (this.opts.clickToggle) {
230
+ this.removeDocumentClickHandler()
231
+ }
232
+
233
+ if (this.opts.followTrigger) {
234
+ this.removeScrollListener()
235
+ }
122
236
  }
123
237
 
124
238
  toggle() {
@@ -128,4 +242,48 @@ export default class Popover {
128
242
  this.show()
129
243
  }
130
244
  }
245
+
246
+ // Add document click handler to close popover when clicking outside
247
+ addDocumentClickHandler() {
248
+ document.addEventListener('click', this.boundHandleDocumentClick)
249
+ }
250
+
251
+ // Remove document click handler
252
+ removeDocumentClickHandler() {
253
+ document.removeEventListener('click', this.boundHandleDocumentClick)
254
+ }
255
+
256
+ // Handle clicks on document to close popover when clicking outside
257
+ handleDocumentClick(e) {
258
+ // If click is outside the popover and the trigger, close it
259
+ if (this.isVisible && !this.popover.contains(e.target) && !this.trigger.contains(e.target)) {
260
+ this.hide()
261
+ }
262
+ }
263
+
264
+ // Close all popovers except the specified one
265
+ closeAllExcept(exceptPopover) {
266
+ activePopovers.forEach(popover => {
267
+ if (popover !== exceptPopover) {
268
+ popover.hide()
269
+ }
270
+ })
271
+ }
272
+
273
+ // Handle scroll events to update popover position
274
+ handleScroll() {
275
+ if (this.isVisible) {
276
+ this.updatePosition(true)
277
+ }
278
+ }
279
+
280
+ // Add scroll event listener using APPLICATION:SCROLL event
281
+ addScrollListener() {
282
+ window.addEventListener(Events.APPLICATION_SCROLL, this.boundHandleScroll)
283
+ }
284
+
285
+ // Remove scroll event listener
286
+ removeScrollListener() {
287
+ window.removeEventListener(Events.APPLICATION_SCROLL, this.boundHandleScroll)
288
+ }
131
289
  }
@@ -1,4 +1,5 @@
1
- import { gsap } from 'gsap/all'
1
+ import { animate } from 'motion'
2
+ import { set } from '../../utils/motion-helpers'
2
3
  import _defaultsDeep from 'lodash.defaultsdeep'
3
4
 
4
5
  /**
@@ -36,51 +37,41 @@ const DEFAULT_OPTIONS = {
36
37
  onClose: () => {},
37
38
 
38
39
  tweenIn: (trigger, target, popup) => {
39
- gsap.set(popup.backdrop, { display: 'block' })
40
- gsap.to(popup.backdrop, {
41
- duration: 0.3,
42
- opacity: 1,
43
- onComplete: () => {
44
- gsap.fromTo(
40
+ popup.backdrop.style.display = 'block'
41
+ animate(popup.backdrop, { opacity: 1 }, { duration: 0.3 })
42
+ .finished
43
+ .then(() => {
44
+ target.style.display = 'block'
45
+ animate(
45
46
  target,
46
47
  {
47
- duration: 0.3,
48
- yPercent: -50,
49
- x: -5,
50
- xPercent: -50,
51
- opacity: 0,
52
- display: 'block',
48
+ transform: [
49
+ 'translate(calc(-50% - 5px), -50%)',
50
+ 'translate(-50%, -50%)'
51
+ ],
52
+ opacity: [0, 1]
53
53
  },
54
- {
55
- duration: 0.3,
56
- yPercent: -50,
57
- xPercent: -50,
58
- x: 0,
59
- opacity: 1,
60
- }
54
+ { duration: 0.3, ease: [0.4, 0, 0.2, 1] }
61
55
  )
62
- },
63
- })
56
+ })
64
57
  },
65
58
 
66
59
  tweenOut: (popup) => {
67
60
  console.log('default tweenOut')
68
61
  const popupElement = popup.currentPopup
69
62
  if (popupElement) {
70
- gsap.to(popupElement, {
71
- duration: 0.3,
72
- opacity: 0,
73
- display: 'none',
74
- })
63
+ animate(popupElement, { opacity: 0 }, { duration: 0.3 })
64
+ .finished
65
+ .then(() => {
66
+ popupElement.style.display = 'none'
67
+ })
75
68
  }
76
- gsap.to(popup.backdrop, {
77
- duration: 0.3,
78
- opacity: 0,
79
- onComplete: () => {
69
+ animate(popup.backdrop, { opacity: 0 }, { duration: 0.3 })
70
+ .finished
71
+ .then(() => {
80
72
  // Remove the backdrop completely instead of just hiding it
81
73
  popup.backdrop.remove()
82
- },
83
- })
74
+ })
84
75
  },
85
76
  }
86
77
 
@@ -189,7 +180,9 @@ export default class Popup {
189
180
  if (key) {
190
181
  backdrop.setAttribute('data-popup-key', key)
191
182
  }
192
- gsap.set(backdrop, { opacity: 0, display: 'none', zIndex: 4999 })
183
+ backdrop.style.display = 'none'
184
+ backdrop.style.zIndex = '4999'
185
+ set(backdrop, { opacity: 0 })
193
186
 
194
187
  backdrop.addEventListener('click', (e) => {
195
188
  e.stopPropagation()
@@ -1,4 +1,4 @@
1
- import { gsap } from 'gsap/all'
1
+ import { set } from '../../utils/motion-helpers'
2
2
  import _defaultsDeep from 'lodash.defaultsdeep'
3
3
 
4
4
  const DEFAULT_OPTIONS = {}
@@ -62,10 +62,10 @@ export default class StackedBoxes {
62
62
  }
63
63
 
64
64
  pull(box, amnt) {
65
- gsap.set(box, { y: amnt * -1, marginBottom: amnt * -1 })
65
+ set(box, { y: amnt * -1, marginBottom: amnt * -1 })
66
66
  }
67
67
 
68
68
  size(target, src) {
69
- gsap.set(target, { height: src.clientHeight })
69
+ set(target, { height: src.clientHeight })
70
70
  }
71
71
  }