Skip to content

fix: clamp the current slide to the slide range#3701

Open
Arukuen wants to merge 1 commit into
developfrom
fix/3695-carousel-slide-exceed
Open

fix: clamp the current slide to the slide range#3701
Arukuen wants to merge 1 commit into
developfrom
fix/3695-carousel-slide-exceed

Conversation

@Arukuen
Copy link
Copy Markdown
Contributor

@Arukuen Arukuen commented May 14, 2026

fixes #3695

Summary by CodeRabbit

  • Bug Fixes
    • Improved carousel infinite scroll functionality to properly maintain slide position during navigation.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 14, 2026

📝 Walkthrough

Walkthrough

The carousel's onScroll method corrects how it normalizes the computed slide index when infinite scroll is enabled. It now uses modular arithmetic to properly clamp the index to the original slide range, fixing edge cases where the previous single-subtraction approach left indices out of bounds.

Changes

Infinite Scroll Slide Index Normalization

Layer / File(s) Summary
Slide index modulo clamping in onScroll
src/block/carousel/frontend-carousel.js
The infinite scroll handler now normalizes the computed slide index using modulo arithmetic to ensure all values stay within the valid range, replacing the prior adjustment that only handled overflow by a single length subtraction.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Possibly related PRs

  • gambitph/Stackable#3619: Both PRs update the carousel's infinite-scroll sliding logic in frontend-carousel.js—this PR normalizes the computed slide index in onScroll, while PR #3619 guards clone-offset calculations used during scroll/drag/wheel interactions.

Poem

🐰 A carousel spins 'round and 'round,
With clones that dance without a sound.
Modulo magic tames the slide,
Keeps indices in proper stride.
No more out-of-bounds despair,
Infinite scrolling, smooth and fair!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR addresses the first of two proposed fixes (clamping slide index in onScroll) but omits the second defensive fix (clamping in goToSlide and guarding undefined elements). Implement the second proposed fix by clamping the target index in goToSlide and adding guards before accessing slide element properties.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change—clamping the current slide to valid range—which directly addresses the infinite carousel bug.
Out of Scope Changes check ✅ Passed All changes are directly related to the linked issue #3695 and implement the proposed fix for the infinite carousel bug.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/3695-carousel-slide-exceed

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown

🤖 Pull request artifacts

file commit
pr3701-stackable-3701-merge.zip 4d77320

github-actions Bot added a commit that referenced this pull request May 14, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/block/carousel/frontend-carousel.js (1)

680-683: 💤 Low value

Modulo arithmetic prevents the crash but has an edge case with the duplicate lastClone.

The modulo successfully clamps all clone indices back into [1, slideEls.length], which prevents the TypeError mentioned in issue #3695. However, there's a subtle semantic issue:

When slidesToShow equals slideEls.length, the init code creates a duplicate clone of the last slide (lastClone in addition to the regular clone). For example, with 3 slides:

  • Combined array indices 1-3: original slides 1-3
  • Indices 4-6: clones of slides 1-3
  • Index 7: duplicate lastClone of slide 3

The modulo ((7-1) % 3) + 1 = 1 maps this to slide 1, when semantically it represents slide 3. This could cause the wrong dot to be highlighted or other minor UI inconsistencies if the user scrolls to a position where the lastClone is nearest.

That said, the fix achieves its primary objective of preventing crashes. The old logic (subtracting length once) would still leave index 7 out of range (7 - 3 = 4), so this is a clear improvement. The semantic edge case is unlikely to cause serious issues in practice, since the carousel's swap logic typically keeps users away from the lastClone position during normal scrolling.

Alternative approach for perfect semantic correctness

If the lastClone edge case becomes problematic, consider tracking which source slide each clone represents:

 if ( this.infiniteScroll ) {
-  // Clamp clone indexes back to the original slide range.
-  slide = ( ( slide - 1 ) % this.slideEls.length ) + 1
+  // Map clones back to their source slide
+  if ( slide > this.slideEls.length ) {
+    const cloneIndex = slide - this.slideEls.length - 1
+    // clones[0..slidesToShow-1] map to slides 1..slidesToShow
+    // clones[slidesToShow] (lastClone) maps to slideEls.length
+    slide = cloneIndex < this.slidesToShow ? cloneIndex + 1 : this.slideEls.length
+  }
 }

However, the current modulo approach is simpler and adequate for preventing the crash.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/block/carousel/frontend-carousel.js` around lines 680 - 683, The modulo
fix prevents out-of-range indices but mishandles the special duplicate lastClone
when slidesToShow === this.slideEls.length; update the logic in the block where
this.infiniteScroll is handled (the code that currently does slide = ((slide -
1) % this.slideEls.length) + 1) to special-case the duplicate lastClone: detect
when the index corresponds to the extra lastClone (e.g., by checking
slidesToShow === this.slideEls.length and that the computed/initial slide index
is the extra clone position or by inspecting the DOM node/class/clone metadata
for "lastClone") and map that case to this.slideEls.length instead of applying
the modulo; otherwise keep the modulo mapping.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/block/carousel/frontend-carousel.js`:
- Around line 680-683: The modulo fix prevents out-of-range indices but
mishandles the special duplicate lastClone when slidesToShow ===
this.slideEls.length; update the logic in the block where this.infiniteScroll is
handled (the code that currently does slide = ((slide - 1) %
this.slideEls.length) + 1) to special-case the duplicate lastClone: detect when
the index corresponds to the extra lastClone (e.g., by checking slidesToShow ===
this.slideEls.length and that the computed/initial slide index is the extra
clone position or by inspecting the DOM node/class/clone metadata for
"lastClone") and map that case to this.slideEls.length instead of applying the
modulo; otherwise keep the modulo mapping.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9be04a20-ff5c-4d09-9c2e-59750f71f62e

📥 Commits

Reviewing files that changed from the base of the PR and between 2438d9e and 4d77320.

📒 Files selected for processing (1)
  • src/block/carousel/frontend-carousel.js

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Infinite carousel throws TypeError when slidesToShow equals total number of slides

1 participant