@brandocms/jupiter 5.0.0-beta.11 → 5.0.0-beta.12
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/Looper/index.js +44 -4
package/package.json
CHANGED
|
@@ -18,6 +18,7 @@ import Dom from '../Dom'
|
|
|
18
18
|
|
|
19
19
|
const DEFAULT_OPTIONS = {
|
|
20
20
|
center: false,
|
|
21
|
+
peek: false, // Centers viewport on the gap between two items (half | full | full | half)
|
|
21
22
|
snap: false, // Set to true to enable snap-to-item behavior
|
|
22
23
|
crawl: true, // Continuous auto-scrolling
|
|
23
24
|
loop: true, // Infinite looping (false for linear scrolling)
|
|
@@ -257,7 +258,15 @@ function horizontalLoop(app, items, config) {
|
|
|
257
258
|
|
|
258
259
|
// Calculate max scroll for non-looping based on endAlignment
|
|
259
260
|
if (!shouldLoop && originalItemCount > 0) {
|
|
260
|
-
if (config.
|
|
261
|
+
if (config.peek) {
|
|
262
|
+
// Peek mode: max scroll where gap after last item is at viewport center
|
|
263
|
+
const lastItemIndex = originalItemCount - 1
|
|
264
|
+
const lastItemRightEdge = offsetLefts[lastItemIndex] + widths[lastItemIndex] - startX
|
|
265
|
+
const viewportCenter = containerWidth / 2
|
|
266
|
+
const idealMaxScroll = lastItemRightEdge + gap / 2 - viewportCenter
|
|
267
|
+
const absoluteMax = lastItemRightEdge - containerWidth
|
|
268
|
+
maxScrollPosition = Math.max(0, Math.min(idealMaxScroll, absoluteMax))
|
|
269
|
+
} else if (config.centerSlide) {
|
|
261
270
|
// Center mode: max scroll is where last item's center is at viewport center
|
|
262
271
|
// But clamped so we don't show empty space
|
|
263
272
|
const lastItemIndex = originalItemCount - 1
|
|
@@ -294,7 +303,13 @@ function horizontalLoop(app, items, config) {
|
|
|
294
303
|
const curX = (xPercents[i] / 100) * widths[i]
|
|
295
304
|
let snapPos
|
|
296
305
|
|
|
297
|
-
if (config.
|
|
306
|
+
if (config.peek) {
|
|
307
|
+
// Peek mode: viewport center at the gap AFTER this item
|
|
308
|
+
// This shows: half(i) | gap | full(i+1) | gap | full(i+2) | gap | half(i+3)
|
|
309
|
+
const itemRightEdge = item.offsetLeft + curX + widths[i] - startX
|
|
310
|
+
const viewportCenter = containerWidth / 2
|
|
311
|
+
snapPos = itemRightEdge + gap / 2 - viewportCenter
|
|
312
|
+
} else if (config.centerSlide) {
|
|
298
313
|
// Center mode: item's center at viewport's center
|
|
299
314
|
const itemCenter = item.offsetLeft + curX + widths[i] / 2 - startX
|
|
300
315
|
const viewportCenter = containerWidth / 2
|
|
@@ -314,7 +329,12 @@ function horizontalLoop(app, items, config) {
|
|
|
314
329
|
const curX = (xPercents[i] / 100) * widths[i]
|
|
315
330
|
let snapPos
|
|
316
331
|
|
|
317
|
-
if (config.
|
|
332
|
+
if (config.peek) {
|
|
333
|
+
// Peek mode: viewport center at the gap AFTER this item
|
|
334
|
+
const itemRightEdge = item.offsetLeft + curX + widths[i] - startX
|
|
335
|
+
const viewportCenter = containerWidth / 2
|
|
336
|
+
snapPos = itemRightEdge + gap / 2 - viewportCenter
|
|
337
|
+
} else if (config.centerSlide) {
|
|
318
338
|
// Center mode: item's center at viewport's center
|
|
319
339
|
const itemCenter = item.offsetLeft + curX + widths[i] / 2 - startX
|
|
320
340
|
const viewportCenter = containerWidth / 2
|
|
@@ -555,6 +575,19 @@ function horizontalLoop(app, items, config) {
|
|
|
555
575
|
populateWidths()
|
|
556
576
|
populateSnapTimes()
|
|
557
577
|
|
|
578
|
+
// Warn if [data-looper] has overflow-x: clip — this clips wrapped items
|
|
579
|
+
// whose individual translateX positions fall outside the container's bounds,
|
|
580
|
+
// even when they are visually positioned within the viewport.
|
|
581
|
+
// Apply overflow-x: clip on a parent element instead.
|
|
582
|
+
const itemsContainer = items[0].parentElement
|
|
583
|
+
const containerOverflow = getComputedStyle(itemsContainer).overflowX
|
|
584
|
+
if (containerOverflow === 'clip') {
|
|
585
|
+
console.warn(
|
|
586
|
+
`[Looper] ⚠️ [data-looper] has overflow-x: clip which will hide looped items. Apply overflow-x: clip on a parent wrapper element instead.`,
|
|
587
|
+
itemsContainer
|
|
588
|
+
)
|
|
589
|
+
}
|
|
590
|
+
|
|
558
591
|
// Set initial container position
|
|
559
592
|
const containerElement = items[0].parentElement
|
|
560
593
|
containerElement.style.willChange = 'transform'
|
|
@@ -1614,6 +1647,12 @@ export default class Looper {
|
|
|
1614
1647
|
const centerValue = looperEl?.getAttribute('data-looper-center')
|
|
1615
1648
|
const shouldCenterSlide = centerValue === 'false' ? false : hasCenterAttr
|
|
1616
1649
|
|
|
1650
|
+
// Peek: data-looper-peek or data-looper-peek="false"
|
|
1651
|
+
// Centers viewport on the gap between two items (half | full | full | half)
|
|
1652
|
+
const hasPeekAttr = looperEl?.hasAttribute('data-looper-peek')
|
|
1653
|
+
const peekValue = looperEl?.getAttribute('data-looper-peek')
|
|
1654
|
+
const shouldPeek = peekValue === 'false' ? false : hasPeekAttr || this.opts.peek
|
|
1655
|
+
|
|
1617
1656
|
// Create stub for Moonwalk compatibility
|
|
1618
1657
|
const stubLoop = {
|
|
1619
1658
|
play: () => {},
|
|
@@ -1633,7 +1672,8 @@ export default class Looper {
|
|
|
1633
1672
|
repeat: -1,
|
|
1634
1673
|
draggable: this.opts.draggable,
|
|
1635
1674
|
center: this.opts.center,
|
|
1636
|
-
centerSlide: shouldCenterSlide,
|
|
1675
|
+
centerSlide: shouldCenterSlide || shouldPeek,
|
|
1676
|
+
peek: shouldPeek,
|
|
1637
1677
|
snap: shouldSnap,
|
|
1638
1678
|
speed,
|
|
1639
1679
|
reversed: isReverse,
|