Skip to content

fix: add direction tracking to carousel component #1574

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

maj0rika
Copy link

@maj0rika maj0rika commented Apr 16, 2025

Closes #1551

📑 Description

Fixes an issue with carousel animations where the transition looked the same whether moving forward or backward.
This update introduces a forward state to track navigation direction — true when moving to the next slide, false for the previous one.
Now the carousel correctly animates in the appropriate direction based on user interaction.

Status

  • Not Completed
  • Completed

✅ Checks

  • My pull request adheres to the code style of this project
  • My code requires changes to the documentation
  • I have updated the documentation as required
  • I have checked the page with https://validator.unl.edu/
  • All the tests have passed
  • My pull request is based on the latest commit (not the npm version).

ℹ Additional Information

This PR fixes the issue reported in #1551 where the carousel animation was the same when moving backward as when moving forward. By tracking the direction with a forward state property (set to true for next slide and false for previous slide), we enable the carousel to use appropriate transition animations for each direction.

Commit message: fix: add direction tracking to carousel transitions

Summary by CodeRabbit

  • Improvement
    • Enhanced carousel navigation to better track slide direction, improving animation accuracy when moving between slides.
    • Updated automatic slide progression to move forwards or backwards based on user navigation direction.
    • Refined thumbnail and indicator interactions to synchronize navigation state and direction.
  • New Features
    • Added optional thumbnail display within the carousel for enhanced slide previews.
  • Documentation
    • Updated usage examples to embed thumbnails inside the carousel, reflecting unified state management.

Copy link

vercel bot commented Apr 16, 2025

@maj0rika is attempting to deploy a commit to the Themesberg Team on Vercel.

A member of the Team first needs to authorize it.

Copy link
Contributor

coderabbitai bot commented Apr 16, 2025

"""

Walkthrough

The Carousel component was enhanced to track slide navigation direction explicitly by setting _state.forward in nextSlide and prevSlide. The auto slide loop interval conditionally calls nextSlide or prevSlide based on this direction. The Indicators and Thumbnails components were refactored to use a shared reactive state context for consistent direction tracking and slide index updates. The Carousel now supports an optional thumbnail slot. Documentation and metadata were updated to reflect these changes.

Changes

File(s) Change Summary
src/lib/carousel/Carousel.svelte Added thumbnail prop; set _state.forward in nextSlide/prevSlide; auto loop interval calls nextSlide or prevSlide based on forward; render optional thumbnail slot.
src/lib/carousel/Indicators.svelte Updated indicator button handler to update shared state atomically with index, forward direction, and lastSlideChange timestamp.
src/lib/carousel/Thumbnails.svelte Removed index prop; made images optional; switched to shared reactive state from context; updated click handler to update shared state with direction and timestamp.
src/lib/types.ts Added optional thumbnail to CarouselProps; made images optional and removed index from ThumbnailsProps.
src/routes/component-data/Carousel.json Added thumbnail prop to Carousel component metadata.
src/routes/docs/components/carousel.md Updated documentation to embed Thumbnails inside Carousel component; removed external index binding and images prop from Thumbnails.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant CarouselComponent
    participant IndicatorsComponent
    participant ThumbnailsComponent
    participant StateStore

    User->>IndicatorsComponent: Click indicator button (idx)
    IndicatorsComponent->>StateStore: Update state { index: idx, forward: idx > currentIndex, lastSlideChange }
    StateStore->>CarouselComponent: State updated (index, forward)
    CarouselComponent->>CarouselComponent: Animate slide based on forward

    User->>ThumbnailsComponent: Click thumbnail (idx)
    ThumbnailsComponent->>StateStore: Update state { index: idx, forward: idx > currentIndex (with wrap), lastSlideChange }
    StateStore->>CarouselComponent: State updated (index, forward)
    CarouselComponent->>CarouselComponent: Animate slide based on forward

    Note over CarouselComponent: Auto slide loop interval
    CarouselComponent->>CarouselComponent: If forward call nextSlide else prevSlide
Loading

Assessment against linked issues

Objective Addressed Explanation
Differentiate forward and backward transitions in carousel (#1551)

Poem

🐰 A hop, a skip, the slides now know,
Which way to turn, which way to go.
Thumbnails and dots all join the dance,
With shared state giving them a chance.
Forward or back, the carousel’s bright,
A rabbit’s cheer for code done right! 🎠✨
"""

Tip

⚡️ Faster reviews with caching
  • CodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 16th. To opt out, configure Review - Disable Cache at either the organization or repository level. If you prefer to disable all data retention across your organization, simply turn off the Data Retention setting under your Organization Settings.

Enjoy the performance boost—your workflow just got faster.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9726284 and 37dfc46.

📒 Files selected for processing (2)
  • src/lib/carousel/Indicators.svelte (1 hunks)
  • src/lib/carousel/Thumbnails.svelte (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/lib/carousel/Indicators.svelte
  • src/lib/carousel/Thumbnails.svelte

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@maj0rika maj0rika force-pushed the fix--add-direction-tracking-to-carousel-transitions branch from 07972c3 to 7942bd1 Compare April 16, 2025 06:07
@maj0rika maj0rika changed the title feat: add direction tracking to carousel component fix: add direction tracking to carousel component Apr 16, 2025
@shinokada
Copy link
Collaborator

It doesn't work. The direction of slide when clicking an indicator behind still move forwards.

@maj0rika
Copy link
Author

maj0rika commented May 8, 2025

@shinokada

Hi!
I’ve updated the carousel so that the auto-rotation now follows the last drag direction.
Instead of always moving forward, it now checks the forward state and rotates accordingly.
Would appreciate it if you could take a look and let me know your thoughts!

@shinokada
Copy link
Collaborator

It seems Control buttons works, but Indicators and Thumbnails don't work.

Copy link
Contributor

@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.

Actionable comments posted: 1

🧹 Nitpick comments (3)
src/lib/carousel/Thumbnails.svelte (3)

15-20: Redundant $effect re-assigns images and can be safely removed

The reactive statement only runs once (when images is initially undefined), after which images is frozen and no longer tracks $state.images.
Because the #each block already falls back to $state.images (images || $state.images), the extra assignment adds complexity without benefit and creates the risk of the two sources diverging.

-$effect(() => {
-  if (!images) {
-    images = $state.images;
-  }
-});

Removing it keeps a single source of truth and avoids accidental stale data.


34-39: Avoid mutating _state inside the store update callback

Writable.update expects you to return the new value; mutating the draft object before spreading can lead to subtle bugs if other references to the same object exist.

-state.update((_state) => {
-  _state.forward = isForward;
-  _state.index = idx;
-  _state.lastSlideChange = new Date();
-  return { ..._state };
-});
+state.update((_state) => ({
+  ..._state,
+  forward: isForward,
+  index: idx,
+  lastSlideChange: new Date()
+}));

This keeps state updates immutable and predictable.


46-55: Add a keyed #each for stable DOM and smoother transitions

Without a key Svelte re-uses elements by index, which can cause focus/animation glitches when the images array changes order or length.

{#each images || $state.images as image, idx (image.id ?? idx)}
  <!-- … -->
{/each}

Using a stable key (e.g., image.id or the index as a fallback) improves DOM diffing and prevents accidental re-mounts.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 54fcdc9 and 9726284.

📒 Files selected for processing (6)
  • src/lib/carousel/Carousel.svelte (5 hunks)
  • src/lib/carousel/Indicators.svelte (1 hunks)
  • src/lib/carousel/Thumbnails.svelte (2 hunks)
  • src/lib/types.ts (2 hunks)
  • src/routes/component-data/Carousel.json (1 hunks)
  • src/routes/docs/components/carousel.md (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/lib/carousel/Carousel.svelte
🔇 Additional comments (7)
src/routes/component-data/Carousel.json (1)

9-9: New optional thumbnail prop added for Carousel component.

This addition of the thumbnail property to the Carousel component's props list supports the new ability to render thumbnails as a child component with shared state.

src/lib/carousel/Indicators.svelte (1)

18-27: Direction tracking implemented for indicator clicks.

The indicator click handler now updates the state with direction information by determining if the clicked indicator represents moving forward or backward relative to the current index. This properly fixes the issue where direction wasn't being tracked when navigating via indicators.

The implementation correctly:

  1. Determines direction with isForward = idx > $state.index
  2. Updates the shared state with the forward flag and current timestamp
  3. Uses an immutable update pattern with { ..._state }
src/lib/types.ts (2)

393-393: New type definition for thumbnail slot added to CarouselProps.

The thumbnail property has been correctly added to the CarouselProps interface as an optional Snippet without parameters, supporting the new design where thumbnails are rendered as a child component through a slot.


428-428: The images property in ThumbnailsProps is now optional.

Making the images property optional allows the Thumbnails component to retrieve images from the shared state context when not explicitly provided, supporting the new context-based state sharing model.

Note that the index property has been removed (not shown in diff) which is consistent with the component now using the shared state for tracking the current index.

src/routes/docs/components/carousel.md (3)

124-124: Documentation updated to reflect new state-sharing architecture.

The explanation now clearly indicates that Thumbnails should be used as a child of Carousel and shares the same state store, which aligns with the implementation changes.


138-140: Example code updated to use the new thumbnail slot.

The example properly demonstrates how to use the new thumbnail snippet slot to render thumbnails inside the Carousel component, reflecting the architectural change to use context-based state sharing.


238-244: Advanced customization example updated for thumbnail integration.

The example now correctly shows how to customize thumbnails using the new slot-based approach, including how to customize individual thumbnail styling based on selection state.

@maj0rika
Copy link
Author

maj0rika commented May 8, 2025

@shinokada

Hi!
To address the feedback, I made two key updates:

  1. Indicators now update the shared store, so the direction is correctly set before transitioning.
  2. Thumbnails have been refactored into a child component of Carousel to share the same context. This resolves the issue where direction wasn't applied correctly due to a separate store.

Initially, I tried determining the direction based on the index alone.
However, when index was updated from the Thumbnails component, the slide transition had already started — which made the timing off and caused incorrect animations.
Refactoring Thumbnails to live inside Carousel ensured they share the same state and that direction tracking works consistently.

As a side benefit, this also resolved an existing issue where index changes via thumbnails weren’t properly synchronized with the indicators. Now, all components reflect the same active slide state.

Let me know if anything still needs tweaking — happy to follow up!

@shinokada
Copy link
Collaborator

v1.0.6 fixed #1551
Thank you for your contribution.

@shinokada shinokada closed this May 8, 2025
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.

Carousel has strange transition
2 participants