@brandocms/jupiter 5.0.0-beta.2 → 5.0.0-beta.4
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.
- package/package.json +1 -1
- package/src/modules/DoubleHeader/index.js +4 -4
- package/src/modules/FixedHeader/index.js +4 -4
- package/src/modules/HeroSlider/index.js +22 -12
- package/src/modules/Looper/index.js +21 -11
- package/src/modules/StickyHeader/index.js +4 -4
- package/src/utils/motion-helpers.js +2 -0
package/package.json
CHANGED
|
@@ -50,7 +50,7 @@ const DEFAULT_EVENTS = {
|
|
|
50
50
|
|
|
51
51
|
onPin: (h) => {
|
|
52
52
|
animate(h.auxEl, {
|
|
53
|
-
|
|
53
|
+
y: '0%'
|
|
54
54
|
}, {
|
|
55
55
|
duration: 0.35,
|
|
56
56
|
ease: 'easeOut'
|
|
@@ -60,7 +60,7 @@ const DEFAULT_EVENTS = {
|
|
|
60
60
|
onUnpin: (h) => {
|
|
61
61
|
h._hiding = true
|
|
62
62
|
animate(h.auxEl, {
|
|
63
|
-
|
|
63
|
+
y: '-100%'
|
|
64
64
|
}, {
|
|
65
65
|
duration: 0.25,
|
|
66
66
|
ease: 'easeIn'
|
|
@@ -86,12 +86,12 @@ const DEFAULT_OPTIONS = {
|
|
|
86
86
|
},
|
|
87
87
|
enter: (h) => {
|
|
88
88
|
// Set initial states
|
|
89
|
-
set(h.auxEl, {
|
|
89
|
+
set(h.auxEl, { y: '-100%' })
|
|
90
90
|
set(h.lis, { opacity: 0 })
|
|
91
91
|
|
|
92
92
|
// Auxiliary header slides down
|
|
93
93
|
animate(h.auxEl, {
|
|
94
|
-
|
|
94
|
+
y: '0%'
|
|
95
95
|
}, {
|
|
96
96
|
duration: 1,
|
|
97
97
|
delay: h.opts.enterDelay,
|
|
@@ -79,7 +79,7 @@ import { set } from '../../utils/motion-helpers'
|
|
|
79
79
|
const DEFAULT_EVENTS = {
|
|
80
80
|
onPin: (h) => {
|
|
81
81
|
animate(h.el, {
|
|
82
|
-
|
|
82
|
+
y: '0%'
|
|
83
83
|
}, {
|
|
84
84
|
duration: 0.35,
|
|
85
85
|
ease: 'easeOut'
|
|
@@ -89,7 +89,7 @@ const DEFAULT_EVENTS = {
|
|
|
89
89
|
onUnpin: (h) => {
|
|
90
90
|
h._hiding = true
|
|
91
91
|
animate(h.el, {
|
|
92
|
-
|
|
92
|
+
y: '-100%'
|
|
93
93
|
}, {
|
|
94
94
|
duration: 0.25,
|
|
95
95
|
ease: 'easeIn'
|
|
@@ -156,14 +156,14 @@ const DEFAULT_OPTIONS = {
|
|
|
156
156
|
canvas: window,
|
|
157
157
|
intersects: null,
|
|
158
158
|
beforeEnter: (h) => {
|
|
159
|
-
set(h.el, {
|
|
159
|
+
set(h.el, { y: '-100%' })
|
|
160
160
|
set(h.lis, { opacity: 0 })
|
|
161
161
|
},
|
|
162
162
|
|
|
163
163
|
enter: (h) => {
|
|
164
164
|
// Header slides down
|
|
165
165
|
animate(h.el, {
|
|
166
|
-
|
|
166
|
+
y: '0%'
|
|
167
167
|
}, {
|
|
168
168
|
duration: 1,
|
|
169
169
|
delay: h.opts.enterDelay,
|
|
@@ -306,20 +306,30 @@ export default class HeroSlider {
|
|
|
306
306
|
this._currentAnimation = animate(sequence)
|
|
307
307
|
|
|
308
308
|
this._currentAnimation.finished.then(() => {
|
|
309
|
-
//
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
309
|
+
// Reset ALL slides using instant animations to ensure Motion.js state is clean
|
|
310
|
+
Array.from(this.slides).forEach((slide) => {
|
|
311
|
+
if (slide === this._currentSlide) return
|
|
312
|
+
const img = slide.querySelector('.hero-slide-img')
|
|
313
|
+
if (img) {
|
|
314
|
+
// Use animate with duration 0 to reset Motion.js internal state
|
|
315
|
+
animate(img, { scale: 1 }, { duration: 0 })
|
|
316
|
+
}
|
|
317
|
+
const isNext = slide === this._nextSlide
|
|
318
|
+
// Reset slide using animate with duration 0
|
|
319
|
+
animate(slide, {
|
|
320
|
+
width: '100%',
|
|
321
|
+
opacity: isNext ? 1 : 0,
|
|
322
|
+
}, { duration: 0 })
|
|
323
|
+
slide.style.overflow = ''
|
|
324
|
+
slide.style.zIndex = isNext ? this.opts.zIndex.next : this.opts.zIndex.regular
|
|
315
325
|
})
|
|
316
|
-
|
|
317
|
-
|
|
326
|
+
|
|
327
|
+
animate(this._currentSlide, {
|
|
318
328
|
width: '100%',
|
|
319
|
-
opacity:
|
|
320
|
-
})
|
|
321
|
-
|
|
322
|
-
|
|
329
|
+
opacity: 1,
|
|
330
|
+
}, { duration: 0 })
|
|
331
|
+
this._currentSlide.style.zIndex = this.opts.zIndex.visible
|
|
332
|
+
|
|
323
333
|
this.next()
|
|
324
334
|
})
|
|
325
335
|
}
|
|
@@ -103,6 +103,10 @@ function horizontalLoop(app, items, config) {
|
|
|
103
103
|
let positionUnsubscribe = null // Track position listener for cleanup
|
|
104
104
|
let renderUnsubscribe = null // Track frame.render loop for cleanup
|
|
105
105
|
|
|
106
|
+
// Scroll direction tracking for wrap logic
|
|
107
|
+
let scrollDirection = 0 // -1 = backward, 0 = neutral, 1 = forward
|
|
108
|
+
let lastPositionForDirection = 0
|
|
109
|
+
|
|
106
110
|
// Display elements for index/count
|
|
107
111
|
let indexElements = []
|
|
108
112
|
let countElements = []
|
|
@@ -163,18 +167,15 @@ function horizontalLoop(app, items, config) {
|
|
|
163
167
|
// This prevents items from visibly moving to the back before they're off-screen
|
|
164
168
|
const minRequiredWidth = containerWidth * 2.5 + maxItemWidth
|
|
165
169
|
|
|
166
|
-
// Only replicate if needed
|
|
167
|
-
if (totalWidth >= minRequiredWidth) {
|
|
168
|
-
return
|
|
169
|
-
}
|
|
170
|
-
|
|
171
170
|
// Store original count to prevent exponential growth
|
|
172
171
|
const originalItemCount = items.length
|
|
173
172
|
const maxReplications = 10
|
|
174
173
|
let count = 0
|
|
175
174
|
let previousTotalWidth = totalWidth
|
|
176
175
|
|
|
177
|
-
|
|
176
|
+
// Always create at least one set of clones - the wrapping logic depends on clones existing
|
|
177
|
+
// Then continue until we have enough width for seamless looping
|
|
178
|
+
while ((count === 0 || totalWidth < minRequiredWidth) && count < maxReplications) {
|
|
178
179
|
// Clone ONLY original items
|
|
179
180
|
for (let i = 0; i < originalItemCount; i++) {
|
|
180
181
|
const clone = items[i].cloneNode(true)
|
|
@@ -390,10 +391,11 @@ function horizontalLoop(app, items, config) {
|
|
|
390
391
|
// In reset zone but item doesn't need reset → keep current offset
|
|
391
392
|
newOffset = itemWrapOffsets[i]
|
|
392
393
|
} else if (itemLeft < -(widths[i] + containerWidth * 0.5)) {
|
|
393
|
-
// Item exited LEFT edge
|
|
394
|
-
//
|
|
395
|
-
//
|
|
396
|
-
|
|
394
|
+
// Item exited LEFT edge - only wrap during forward scroll
|
|
395
|
+
// During reverse scroll (scrollDirection < 0), items off-screen left
|
|
396
|
+
// will naturally scroll back into view - don't wrap them
|
|
397
|
+
const isForwardScroll = scrollDirection >= 0
|
|
398
|
+
newOffset = (isForwardScroll && boundedPos < originalItemsWidth / 2) ? wrapOffset : 0
|
|
397
399
|
} else if (itemLeft > containerWidth + containerWidth * 0.5) {
|
|
398
400
|
// Item exited RIGHT edge
|
|
399
401
|
// This shouldn't happen much, but handle it
|
|
@@ -532,6 +534,13 @@ function horizontalLoop(app, items, config) {
|
|
|
532
534
|
// Set up boundedPos motionValue to automatically sync with position
|
|
533
535
|
// This calculates the bounded position (0 to originalItemsWidth)
|
|
534
536
|
const positionUnsubscribe = position.on('change', latest => {
|
|
537
|
+
// Track scroll direction for wrap logic
|
|
538
|
+
const delta = latest - lastPositionForDirection
|
|
539
|
+
if (Math.abs(delta) > 1) {
|
|
540
|
+
scrollDirection = delta > 0 ? 1 : -1
|
|
541
|
+
}
|
|
542
|
+
lastPositionForDirection = latest
|
|
543
|
+
|
|
535
544
|
const bounded = ((latest % originalItemsWidth) + originalItemsWidth) % originalItemsWidth
|
|
536
545
|
boundedPos.set(bounded)
|
|
537
546
|
})
|
|
@@ -1165,7 +1174,8 @@ function horizontalLoop(app, items, config) {
|
|
|
1165
1174
|
const currentPos = position.get()
|
|
1166
1175
|
|
|
1167
1176
|
// Calculate position within current cycle (using originalItemsWidth)
|
|
1168
|
-
|
|
1177
|
+
// Use proper modulo for negative positions (dragging right/backward)
|
|
1178
|
+
const cyclePos = ((currentPos % originalItemsWidth) + originalItemsWidth) % originalItemsWidth
|
|
1169
1179
|
const remainingDist = originalItemsWidth - cyclePos
|
|
1170
1180
|
const remainingDuration = remainingDist / pixelsPerSecond
|
|
1171
1181
|
|
|
@@ -81,7 +81,7 @@ import { set } from '../../utils/motion-helpers'
|
|
|
81
81
|
const DEFAULT_EVENTS = {
|
|
82
82
|
onPin: (h) => {
|
|
83
83
|
animate(h.el, {
|
|
84
|
-
|
|
84
|
+
y: '0%'
|
|
85
85
|
}, {
|
|
86
86
|
duration: 0.35,
|
|
87
87
|
ease: 'easeOut'
|
|
@@ -91,7 +91,7 @@ const DEFAULT_EVENTS = {
|
|
|
91
91
|
onUnpin: (h) => {
|
|
92
92
|
h._hiding = true
|
|
93
93
|
animate(h.el, {
|
|
94
|
-
|
|
94
|
+
y: '-100%'
|
|
95
95
|
}, {
|
|
96
96
|
duration: 0.25,
|
|
97
97
|
ease: 'easeIn'
|
|
@@ -158,14 +158,14 @@ const DEFAULT_OPTIONS = {
|
|
|
158
158
|
canvas: window,
|
|
159
159
|
intersects: null,
|
|
160
160
|
beforeEnter: (h) => {
|
|
161
|
-
set(h.el, {
|
|
161
|
+
set(h.el, { y: '-100%' })
|
|
162
162
|
set(h.lis, { opacity: 0 })
|
|
163
163
|
},
|
|
164
164
|
|
|
165
165
|
enter: (h) => {
|
|
166
166
|
// Header slides down
|
|
167
167
|
animate(h.el, {
|
|
168
|
-
|
|
168
|
+
y: '0%'
|
|
169
169
|
}, {
|
|
170
170
|
duration: 1,
|
|
171
171
|
delay: h.opts.enterDelay,
|
|
@@ -33,6 +33,8 @@ export function set(target, values) {
|
|
|
33
33
|
transformProps.push(`translateX(${typeof value === 'number' ? value + 'px' : value})`)
|
|
34
34
|
} else if (key === 'y') {
|
|
35
35
|
transformProps.push(`translateY(${typeof value === 'number' ? value + 'px' : value})`)
|
|
36
|
+
} else if (key === 'yPercent') {
|
|
37
|
+
transformProps.push(`translateY(${value}%)`)
|
|
36
38
|
} else if (key === 'scale') {
|
|
37
39
|
transformProps.push(`scale(${value})`)
|
|
38
40
|
} else if (key === 'scaleX') {
|