@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brandocms/jupiter",
3
- "version": "5.0.0-beta.2",
3
+ "version": "5.0.0-beta.4",
4
4
  "description": "Frontend helpers.",
5
5
  "author": "Univers/Twined",
6
6
  "license": "UNLICENSED",
@@ -50,7 +50,7 @@ const DEFAULT_EVENTS = {
50
50
 
51
51
  onPin: (h) => {
52
52
  animate(h.auxEl, {
53
- yPercent: '0'
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
- yPercent: '-100'
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, { yPercent: -100 })
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
- yPercent: 0
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
- yPercent: '0'
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
- yPercent: '-100'
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, { yPercent: -100 })
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
- yPercent: 0
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
- // Cleanup and shuffle z-indexes
310
- set(this._nextSlide, { zIndex: this.opts.zIndex.next, opacity: 1 })
311
- set(this._currentSlide, {
312
- zIndex: this.opts.zIndex.visible,
313
- width: '100%',
314
- opacity: 1,
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
- set(this._previousSlide, {
317
- zIndex: this.opts.zIndex.regular,
326
+
327
+ animate(this._currentSlide, {
318
328
  width: '100%',
319
- opacity: 0, // Hide previous slide
320
- })
321
- // Reset previous slide image scale for next time
322
- set(previousSlideImg, { scale: 1.0 })
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
- while (totalWidth < minRequiredWidth && count < maxReplications) {
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
- // Forward drag (low boundedPos): wrap to END
395
- // Backward drag (high boundedPos): don't wrap, clones fill in from right
396
- newOffset = boundedPos < originalItemsWidth / 2 ? wrapOffset : 0
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
- const cyclePos = currentPos % originalItemsWidth
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
- yPercent: '0'
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
- yPercent: '-100'
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, { yPercent: -100 })
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
- yPercent: 0
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') {