Skip to content

Commit 61b880a

Browse files
authored
Merge pull request #494 from ismail9k/mouse-scroll-support
Mouse scroll support
2 parents f57515c + 7dd304e commit 61b880a

File tree

15 files changed

+575
-113
lines changed

15 files changed

+575
-113
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Modern lightweight Vue 3 carousel component
1919
- 📱 **Responsive** - Breakpoints support
2020
- 🔄 **Infinite Scroll** - Wrap around sliding
2121
- 🖱️ **Mouse/Touch** - Dragging support
22+
- 🖲️ **Mouse Wheel** - Scroll navigation support
2223
-**Auto Play** - Automatic sliding
2324
- 🎯 **Slide Classes** - Active & visible states
2425
- 🌐 **RTL** - Right-to-left support

docs/config.md

Lines changed: 74 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
| `breakpoints` | `object` | null | Responsive breakpoint configurations. Each breakpoint can override any carousel prop. |
1010
| `clamp` | `boolean` | false | If true will clamp itemsToShow to the number of available slides |
1111
| `dir` | 'ltr', 'rtl', 'ttb', 'btt' | 'ltr' | Carousel sliding direction. Supports horizontal (ltr/rtl) and vertical (ttb/btt) orientations. |
12-
| `dragThreshold` | `number` | 0.3 | Define a threshold for the drag distance required to trigger a slide transition. |
1312
| `enabled` | `boolean` | true | Controls whether the carousel is interactive. When false, all interactions are disabled. |
1413
| `gap` | `number` | 0 | Space (in pixels) between carousel slides. |
1514
| `height` | `number` \| `string` | 'auto' | Sets the carousel track height. Required for vertical orientation. |
@@ -18,12 +17,13 @@
1817
| `itemsToScroll` | `number` | 1 | Number of slides to move when navigating. Useful for creating slide groups. |
1918
| `itemsToShow` | `number` \| 'auto' | 1 | Number of slides visible simultaneously. Use 'auto' for variable width slides. |
2019
| `modelValue` | `number` | 0 | Controls the active slide index. Can be used with v-model for two-way binding. |
21-
| `mouseDrag` | `boolean` | true | Enables/disables mouse drag navigation. |
20+
| `mouseDrag` | `boolean` \| `DragConfig` | true | Enables/disables mouse drag navigation. See [Drag Options](#drag-options) for configuration details. |
21+
| `mouseWheel` | `boolean` \| `WheelConfig` | false | Enables/disables mouse wheel scrolling for carousel navigation. See [Wheel Options](#wheel-options) for configuration details. |
2222
| `pauseAutoplayOnHover` | `boolean` | false | When true, autoplay pauses while the mouse cursor is over the carousel. |
2323
| `preventExcessiveDragging` | `boolean` | false | Limits dragging behavior at carousel boundaries for better UX. <Badge text="0.13.0" /> |
2424
| `slideEffect` | 'slide', 'fade' | 'slide' | Determines the transition effect between slides. |
2525
| `snapAlign` | 'start', 'end', 'center-odd', 'center-even' | 'center' | Determines how slides are aligned within the viewport. |
26-
| `touchDrag` | `boolean` | true | Enables/disables touch navigation on touch-enabled devices. |
26+
| `touchDrag` | `boolean` \| `DragConfig` | true | Enables/disables touch navigation on touch-enabled devices. See [Drag Options](#drag-options) for configuration details. |
2727
| `transition` | `number` | 300 | Duration of the slide transition animation in milliseconds. |
2828
| `wrapAround` | `boolean` | false | When true, creates an infinite loop effect by connecting the last slide to the first. |
2929

@@ -33,6 +33,64 @@
3333
3434
> **Drag Prevention**: The `preventExcessiveDragging` option is automatically disabled when `wrapAround` is enabled, as boundary restrictions aren't needed in infinite loop mode.
3535
36+
## Drag Options
37+
38+
Both `mouseDrag` and `touchDrag` properties accept either a boolean value or a `DragConfig` object with the following properties:
39+
40+
| Property | Type | Default | Description |
41+
|-------------|----------|---------|--------------------------------------------------------------------------------------------|
42+
| `threshold` | `number` | 0.3 | Controls the drag distance required to trigger a slide transition, as a fraction of slide width. Higher values require more dragging to trigger a slide change. |
43+
44+
### Example
45+
46+
```vue
47+
<template>
48+
<Carousel
49+
:mouseDrag="{ threshold: 0.5 }"
50+
:touchDrag="{ threshold: 0.7 }"
51+
>
52+
<!-- Slides -->
53+
</Carousel>
54+
</template>
55+
```
56+
57+
## Wheel Options
58+
59+
The `mouseWheel` property accepts either a boolean value or a `WheelConfig` object with the following properties:
60+
61+
| Property | Type | Default | Description |
62+
|---------------|----------|---------|--------------------------------------------------------------------------------------------|
63+
| `threshold` | `number` | 10 | Controls the wheel movement threshold required to trigger a slide transition. Higher values require more scrolling to trigger a slide change. |
64+
65+
66+
### Example
67+
68+
```vue
69+
<template>
70+
<Carousel
71+
:mouseWheel="{ threshold: 20 }"
72+
>
73+
<!-- Slides -->
74+
</Carousel>
75+
</template>
76+
```
77+
78+
## I18n
79+
80+
Available keys:
81+
82+
| Key | Defaults | Description |
83+
| --------------------- | -------------------------------------- | -------------------------------------------------------------------------- |
84+
| `ariaGallery` | "Gallery" | Used as the aria-label for the main carousel element, indicating purpose. |
85+
| `ariaNavigateToSlide` | "Navigate to slide {slideNumber}" | Sets title and aria-label for pagination buttons to select a slide. |
86+
| `ariaNextSlide` | "Navigate to next slide" | Sets title and aria-label for the "Next" navigation button. |
87+
| `ariaPreviousSlide` | "Navigate to previous slide" | Sets title and aria-label for the "Previous" navigation button. |
88+
| `iconArrowDown` | "Arrow pointing downwards" | Sets title and aria-label for the downward-pointing arrow SVG icon. |
89+
| `iconArrowLeft` | "Arrow pointing to the left" | Sets title and aria-label for the left-pointing arrow SVG icon. |
90+
| `iconArrowRight` | "Arrow pointing to the right" | Sets title and aria-label for the right-pointing arrow SVG icon. |
91+
| `iconArrowUp` | "Arrow pointing upwards" | Sets title and aria-label for the upward-pointing arrow SVG icon. |
92+
| `itemXofY` | "Item {currentSlide} of {slidesCount}" | Provides screen readers with the current slide's position in the sequence. |
93+
3694
## Slots
3795

3896
### Slides/Default
@@ -119,3 +177,16 @@ Available keys:
119177
| `iconArrowRight` | "Arrow pointing to the right" | Sets title and aria-label for the right-pointing arrow SVG icon. |
120178
| `iconArrowUp` | "Arrow pointing upwards" | Sets title and aria-label for the upward-pointing arrow SVG icon. |
121179
| `itemXofY` | "Item {currentSlide} of {slidesCount}" | Provides screen readers with the current slide's position in the sequence. |
180+
181+
### Example
182+
183+
```vue
184+
<template>
185+
<Carousel
186+
:mouseDrag="{ threshold: 0.5 }"
187+
:touchDrag="{ threshold: 0.7 }"
188+
>
189+
<!-- Slides -->
190+
</Carousel>
191+
</template>
192+
```

docs/examples-fallback.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ Illustrates the carousel with autoplay functionality enabled.
3030

3131
<ExampleAutoplay />
3232

33+
## Mouse Scroll
34+
35+
Demonstrates the carousel with mouse wheel scrolling navigation enabled.
36+
37+
<ExampleMouseScroll />
38+
3339
## Active Classes
3440

3541
An example highlighting active items with custom classes.
@@ -64,6 +70,7 @@ import ExampleCustomNavigation from './examples/ExampleCustomNavigation.vue';
6470
import ExampleGallery from './examples/ExampleGallery.vue';
6571
import ExampleVertical from './examples/ExampleVertical.vue';
6672
import ExampleDisable from './examples/ExampleDisable.vue';
73+
import ExampleMouseScroll from './examples/ExampleMouseScroll.vue';
6774
</script>
6875

6976
<style>

docs/examples.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ Illustrates the carousel with autoplay functionality enabled.
3232

3333
<live-codes v-bind="LiveCodeExamples.autoplay" />
3434

35+
## Mouse Scroll
36+
37+
Demonstrates the carousel with mouse wheel scrolling navigation enabled.
38+
39+
<live-codes v-bind="LiveCodeExamples.mouseScroll" />
40+
3541
## Active Classes
3642

3743
An example highlighting active items with custom classes.

docs/examples/ExampleMouseScroll.vue

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
<script setup>
2+
import { Carousel, Slide, Pagination, Navigation } from 'vue3-carousel'
3+
import { ref } from 'vue'
4+
5+
const images = Array.from({ length: 10 }, (_, index) => ({
6+
id: index + 1,
7+
url: `https://picsum.photos/800/600?random=${index + 1}`,
8+
}))
9+
10+
const threshold = ref(30)
11+
12+
const config = {
13+
height: 200,
14+
itemsToShow: 2,
15+
gap: 5,
16+
mouseScroll: true,
17+
mouseScrollThreshold: threshold.value,
18+
wrapAround: true,
19+
}
20+
21+
function updateThreshold(event) {
22+
threshold.value = Number(event.target.value)
23+
config.mouseScrollThreshold = threshold.value
24+
}
25+
</script>
26+
27+
<template>
28+
<div class="example-container">
29+
<h3>Mouse Scroll Navigation</h3>
30+
<p>Scroll your mouse wheel over the carousel to navigate through slides</p>
31+
32+
<div class="threshold-control">
33+
<label for="threshold">Mouse Scroll Threshold: {{ threshold }}</label>
34+
<input
35+
id="threshold"
36+
type="range"
37+
min="10"
38+
max="100"
39+
step="10"
40+
v-model="threshold"
41+
@input="updateThreshold"
42+
/>
43+
<small>Higher values require more scrolling (less sensitive)</small>
44+
</div>
45+
46+
<Carousel v-bind="config">
47+
<Slide v-for="image in images" :key="image.id">
48+
<div class="carousel__item">
49+
<img :src="image.url" alt="image" />
50+
</div>
51+
</Slide>
52+
53+
<template #addons>
54+
<Navigation />
55+
<Pagination />
56+
</template>
57+
</Carousel>
58+
</div>
59+
</template>
60+
61+
<style scoped>
62+
.example-container {
63+
text-align: center;
64+
}
65+
66+
.threshold-control {
67+
margin: 20px 0;
68+
display: flex;
69+
flex-direction: column;
70+
align-items: center;
71+
gap: 8px;
72+
}
73+
74+
input[type='range'] {
75+
width: 200px;
76+
}
77+
78+
small {
79+
color: #888;
80+
font-size: 0.8em;
81+
}
82+
83+
img {
84+
width: 100%;
85+
height: 100%;
86+
object-fit: cover;
87+
border-radius: 8px;
88+
}
89+
</style>

docs/examples/LiveCodeExamples.ts

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,109 @@ img {
549549
.thumbnail:hover {
550550
opacity: 1;
551551
}
552+
`.trimStart(),
553+
},
554+
mouseScroll: {
555+
code: `
556+
<script setup>
557+
import 'vue3-carousel/carousel.css';
558+
import { Carousel, Slide, Pagination, Navigation } from 'vue3-carousel';
559+
import { ref } from 'vue';
560+
561+
const images = Array.from({ length: 10 }, (_, index) => ({
562+
id: index + 1,
563+
url: \`https://picsum.photos/800/600?random=\${index + 1}\`,
564+
}));
565+
566+
const threshold = ref(30);
567+
568+
const config = {
569+
height: 200,
570+
itemsToShow: 2,
571+
gap: 5,
572+
mouseScroll: true,
573+
mouseScrollThreshold: threshold.value,
574+
wrapAround: true,
575+
};
576+
577+
function updateThreshold(event) {
578+
threshold.value = Number(event.target.value);
579+
config.mouseScrollThreshold = threshold.value;
580+
}
581+
</script>
582+
583+
<template>
584+
<div class="example-container">
585+
<h3>Mouse Scroll Navigation</h3>
586+
<p>Scroll your mouse wheel over the carousel to navigate through slides</p>
587+
588+
<div class="threshold-control">
589+
<label for="threshold">Mouse Scroll Threshold: {{ threshold }}</label>
590+
<input
591+
id="threshold"
592+
type="range"
593+
min="10"
594+
max="100"
595+
step="10"
596+
v-model="threshold"
597+
@input="updateThreshold"
598+
/>
599+
<small>Higher values require more scrolling (less sensitive)</small>
600+
</div>
601+
602+
<Carousel v-bind="config">
603+
<Slide v-for="image in images" :key="image.id">
604+
<img :src="image.url" alt="image" />
605+
</Slide>
606+
607+
<template #addons>
608+
<Navigation />
609+
<Pagination />
610+
</template>
611+
</Carousel>
612+
</div>
613+
</template>
614+
`.trimStart(),
615+
styles: `
616+
:root {
617+
background-color: #242424;
618+
}
619+
620+
.example-container {
621+
color: white;
622+
text-align: center;
623+
}
624+
625+
.threshold-control {
626+
margin: 20px 0;
627+
display: flex;
628+
flex-direction: column;
629+
align-items: center;
630+
gap: 8px;
631+
}
632+
633+
input[type="range"] {
634+
width: 200px;
635+
}
636+
637+
small {
638+
color: #888;
639+
font-size: 0.8em;
640+
}
641+
642+
.carousel {
643+
--vc-pgn-background-color: rgba(255, 255, 255, 0.7);
644+
--vc-pgn-active-color: rgba(255, 255, 255, 1);
645+
--vc-nav-background: rgba(255, 255, 255, 0.7);
646+
--vc-nav-border-radius: 100%;
647+
}
648+
649+
img {
650+
border-radius: 8px;
651+
width: 100%;
652+
height: 100%;
653+
object-fit: cover;
654+
}
552655
`.trimStart(),
553656
},
554657
}

playground/App.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ const defaultConfig = {
4141
autoplay: null,
4242
wrapAround: true,
4343
height: '200',
44+
mouseWheel: true,
4445
dir: 'left-to-right',
4546
breakpointMode: 'carousel',
4647
gap: 10,
@@ -210,6 +211,7 @@ const events = [
210211
'slide-end',
211212
'loop',
212213
'drag',
214+
'wheel',
213215
'slide-registered',
214216
'slide-unregistered',
215217
]

0 commit comments

Comments
 (0)