diff --git a/docs/api/data.md b/docs/api/data.md
index 35b2f2a8..d4c46f7a 100644
--- a/docs/api/data.md
+++ b/docs/api/data.md
@@ -21,13 +21,12 @@ if (myCarousel.data.currentSlide === 10) {
## Available Data
-| Data | Description |
-| ---------------- | -------------------------------------------------------------------------- |
-| `config` | the current carousel configuration |
-| `slidesCount` | slides total count |
-| ~~`slideWidth`~~ | ~~single slide width~~ |
-| `slideSize` | single slide width or height |
-| `currentSlide` | current slide index |
-| `maxSlide` | maximum slide index |
-| `minSlide` | minimum slide index |
-| `middleSlide` | middle slide index |
+| Data | Description |
+| -------------- | ---------------------------------- |
+| `config` | the current carousel configuration |
+| `currentSlide` | current slide index |
+| `maxSlide` | maximum slide index |
+| `middleSlide` | middle slide index |
+| `minSlide` | minimum slide index |
+| `slideSize` | single slide width or height |
+| `slidesCount` | slides total count |
diff --git a/docs/api/events.md b/docs/api/events.md
index bfe1a2ca..61ffc2bc 100644
--- a/docs/api/events.md
+++ b/docs/api/events.md
@@ -30,18 +30,23 @@ const handleSlideStart = (data) => {
Triggered before the carousel is initialized. Use this to perform any setup tasks required before the carousel is ready.
+### @drag
+
+Triggered while the carousel is being dragged, providing live positional data. Emits the following:
+
+- `x`: The horizontal drag position.
+- `y`: The vertical drag position.
+
### @init
Triggered once the carousel is mounted and fully initialized. This is ideal for executing post-initialization logic.
-### slide-start
+### @loop
-Triggered at the beginning of the sliding function. Emits the following data:
+Triggered when the carousel loops over (wraps around), only in wrap-around mode. Emits the following data:
-- `slidingToIndex`: The index of the slide the carousel is moving to.
-- `currentSlideIndex`: The current slide index before the transition starts.
-- `prevSlideIndex`: The index of the slide before the current one.
-- `slidesCount`: The total number of slides in the carousel.
+- `currentSlideIndex`: The current slide index before the loop occurs.
+- `slidingToIndex`: The index of the slide the carousel loops to.
### @slide-end
@@ -51,33 +56,28 @@ Triggered after the sliding animation completes and the current slide is updated
- `prevSlideIndex`: The index of the slide before the transition.
- `slidesCount`: The total number of slides in the carousel.
-### @loop
-
-Triggered when the carousel loops over (wraps around), only in wrap-around mode. Emits the following data:
-
-- `slidingToIndex`: The index of the slide the carousel loops to.
-- `currentSlideIndex`: The current slide index before the loop occurs.
-
-### @drag
-
-Triggered while the carousel is being dragged, providing live positional data. Emits the following:
-
-- `x`: The horizontal drag position.
-- `y`: The vertical drag position.
-
### @slide-registered
Triggered when a new slide is registered with the carousel. Emits the following data:
-- `slide`: The Vue component instance of the registered slide
- `index`: The index position where the slide was registered
+- `slide`: The Vue component instance of the registered slide
+
+### @slide-start
+
+Triggered at the beginning of the sliding function. Emits the following data:
+
+- `currentSlideIndex`: The current slide index before the transition starts.
+- `prevSlideIndex`: The index of the slide before the current one.
+- `slidingToIndex`: The index of the slide the carousel is moving to.
+- `slidesCount`: The total number of slides in the carousel.
### @slide-unregistered
Triggered when a slide is unregistered (removed) from the carousel. Emits the following data:
-- `slide`: The Vue component instance of the unregistered slide
- `index`: The index position from which the slide was removed
+- `slide`: The Vue component instance of the unregistered slide
## Notes
diff --git a/docs/api/methods.md b/docs/api/methods.md
index 1d76967d..ee50306f 100644
--- a/docs/api/methods.md
+++ b/docs/api/methods.md
@@ -17,10 +17,6 @@ myCarousel.next()
myCarousel.updateSlideSize()
```
-## slideTo(index: number)
-
-Slide to specific slide index
-
## next()
Slide to the next slide
@@ -29,37 +25,32 @@ Slide to the next slide
Slide to the previous slide
-## ~~updateSlideWidth()~~
+## restartCarousel()
-~~Update `slideWidth` value based on `itemsToShow` and the current carousel width~~
+Restart the carousel settings and data, internally it calls:
-## updateSlideSize()
+- `resetAutoplay`
+- `updateBreakpointsConfig`
+- `updateSlidesData`
+- `updateSlideSize`
-Update `slideSize` value based on `itemsToShow`, `dir` and the current carousel width/height
+## slideTo(index: number, skipTransition = false)
+
+Slide to specific slide index
## updateBreakpointsConfig()
Update the current carousel config based on `breakpoints` settings and screen width
+## updateSlideSize()
+
+Update `slideSize` value based on `itemsToShow`, `dir` and the current carousel width/height
+
## updateSlidesData()
Update all the slide related date includes:
- `currentSlideIndex`
-- `middleSlide`
- `maxSlide`
+- `middleSlide`
- `minSlide`
-
-## ~~initDefaultConfig()~~
-
-~~Init carousel default configurations~~
-
-## restartCarousel()
-
-Restart the carousel settings and data, internally it calls:
-
-- ~~`initDefaultConfig`~~
-- `resetAutoplay`
-- `updateBreakpointsConfig`
-- `updateSlidesData`
-- `updateSlideSize`
diff --git a/docs/components/navigation.md b/docs/components/navigation.md
index 3db9a55a..3bfd0f3c 100644
--- a/docs/components/navigation.md
+++ b/docs/components/navigation.md
@@ -61,12 +61,12 @@ You can customize the navigation buttons using slots:
| Variable | Default Value | Description |
| ------------------------ | ------------------------- | ------------------------------- |
-| `--vc-nav-width` | `30px` | Navigation button width |
-| `--vc-nav-height` | `30px` | Navigation button height |
+| `--vc-nav-background` | `transparent` | Navigation button background |
| `--vc-nav-border-radius` | `0` | Navigation button border radius |
| `--vc-nav-color` | `var(--vc-clr-primary)` | Navigation button color |
| `--vc-nav-color-hover` | `var(--vc-clr-secondary)` | Navigation button hover color |
-| `--vc-nav-background` | `transparent` | Navigation button background |
+| `--vc-nav-height` | `30px` | Navigation button height |
+| `--vc-nav-width` | `30px` | Navigation button width |
## Accessibility
diff --git a/docs/components/pagination.md b/docs/components/pagination.md
index 03262e47..d31e6053 100644
--- a/docs/components/pagination.md
+++ b/docs/components/pagination.md
@@ -35,13 +35,12 @@ import { Pagination as CarouselPagination } from 'vue3-carousel'
| Variable | Default Value | Description |
| --------------------------- | ------------------------- | ---------------------------------- |
-| `--vc-pgn-width` | `16px` | Pagination button width |
+| `--vc-pgn-active-color` | `var(--vc-clr-primary)` | Active pagination button color |
+| `--vc-pgn-background-color` | `var(--vc-clr-secondary)` | Pagination button background color |
+| `--vc-pgn-border-radius` | `0` | Pagination button border radius |
| `--vc-pgn-height` | `4px` | Pagination button height |
| `--vc-pgn-margin` | `6px 5px` | Pagination button margin |
-| `--vc-pgn-border-radius` | `0` | Pagination button border radius |
-| `--vc-pgn-background-color` | `var(--vc-clr-secondary)` | Pagination button background color |
-| `--vc-pgn-active-color` | `var(--vc-clr-primary)` | Active pagination button color |
-
+| `--vc-pgn-width` | `16px` | Pagination button width |
## Accessibility
diff --git a/docs/components/slide.md b/docs/components/slide.md
index 3803a981..e4a5cec6 100644
--- a/docs/components/slide.md
+++ b/docs/components/slide.md
@@ -31,8 +31,8 @@ The default slot exposes these reactive properties for custom slide content:
| currentIndex | Number | Current index position of the slide |
| isActive | Boolean | True when this slide is the current active slide |
| isClone | Boolean | True if this is a clone slide (used for infinite scroll) |
-| isPrev | Boolean | True if this slide is immediately before the active slide |
| isNext | Boolean | True if this slide is immediately after the active slide |
+| isPrev | Boolean | True if this slide is immediately before the active slide |
| isSliding | Boolean | True during slide transition animations |
| isVisible | Boolean | True when the slide is within the visible viewport |
@@ -80,12 +80,12 @@ The component provides these CSS classes for styling:
| CSS Class | Description |
| --------------------------- | ------------------------- |
| `.carousel__slide` | Base slide styles |
-| `.carousel__slide--clone` | Cloned slide styles |
-| `.carousel__slide--visible` | Visible slide styles |
| `.carousel__slide--active` | Active slide styles |
-| `.carousel__slide--prev` | Previous slide styles |
+| `.carousel__slide--clone` | Cloned slide styles |
| `.carousel__slide--next` | Next slide styles |
+| `.carousel__slide--prev` | Previous slide styles |
| `.carousel__slide--sliding` | Styles during transitions |
+| `.carousel__slide--visible` | Visible slide styles |
## Best Practices
diff --git a/docs/config.md b/docs/config.md
index 1a859ce9..a0b15987 100644
--- a/docs/config.md
+++ b/docs/config.md
@@ -2,29 +2,33 @@
## Available Props
-| Prop | Default | Description |
-| -------------------------- | -------------------------------- |-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| `enabled` | true | Controlled weather the carousel is enabled or disabled. |
-| `itemsToShow` | 1 | Count of items to showed per view (can be a fraction). Must be between 1 and the total number of slides. If set to a value less than 1, it defaults to 1. If set to a value greater than the total number of slides, it defaults to the total number of slides. |
-| `itemsToScroll` | 1 | Number of slides to be scrolled |
-| `wrapAround` | false | Enable infinite scrolling mode. |
-| `snapAlign` | 'center' | Controls the carousel position alignment, can be 'start', 'end', 'center-[odd\|even]' |
-| `transition` | 300 | Sliding transition time in ms. |
-| `autoplay` | 0 | Auto play time in ms. |
-| `breakpointMode` | 'viewport' | Determines how the carousel breakpoints are calculated. acceptable values: 'viewport', 'carousel' |
-| `breakpoints` | null | An object to pass all the breakpoints settings. |
-| `modelValue` | 0 | Index number of the initial slide. |
-| `mouseDrag` | true | Toggle mouse dragging |
-| `touchDrag` | true | Toggle pointer touch dragging |
-| `pauseAutoplayOnHover` | false | Toggle if auto play should pause on mouse hover |
-| `dir` | 'ltr' | Controls the carousel direction. Available values: 'ltr', 'rtl', 'ttb', 'btt' or use verbose 'left-to-right', 'right-to-left', 'top-to-bottom', 'bottom-to-top' |
-| `i18n` | [`{ ariaNextSlide: ...}`](#i18n) | Used to translate and/or change aria labels and additional texts used in the carousel. |
-| `gap` | 0 | Used to add gap between the slides. |
-| `height` | 'auto' | Carousel track height. |
-| `ignoreAnimations` | false | List of animation names to ignore for size calculations. Can be a boolean, string, or array of strings. |
-| `preventExcessiveDragging` | false | Prevents unwanted dragging behavior when the carousel reaches its first or last slide. |
-
-
+| Prop | Type | Default | Description |
+| -------------------------- | ------------------------------------------- | -------------------------------- | ------------------------------------------------------------------------------------------------------ |
+| `autoplay` | `number` | 0 | Time interval (in milliseconds) between auto-advancing slides. Set to 0 to disable autoplay. |
+| `breakpointMode` | 'viewport', 'carousel' | 'viewport' | Defines whether breakpoints are calculated based on viewport width or carousel container width. |
+| `breakpoints` | `object` | null | Responsive breakpoint configurations. Each breakpoint can override any carousel prop. |
+| `dir` | 'ltr', 'rtl', 'ttb', 'btt' | 'ltr' | Carousel sliding direction. Supports horizontal (ltr/rtl) and vertical (ttb/btt) orientations. |
+| `enabled` | `boolean` | true | Controls whether the carousel is interactive. When false, all interactions are disabled. |
+| `gap` | `number` | 0 | Space (in pixels) between carousel slides. |
+| `height` | `number` \| `string` | 'auto' | Sets the carousel track height. Required for vertical orientation. |
+| `i18n` | `object` | [`{ ariaNextSlide: ...}`](#i18n) | Internationalization options for accessibility labels and text content. |
+| `ignoreAnimations` | `boolean` \| `string` \| `array` | false | Specifies which CSS animations should be excluded from slide size calculations. |
+| `itemsToScroll` | `number` | 1 | Number of slides to move when navigating. Useful for creating slide groups. |
+| `itemsToShow` | `number` \| 'auto' | 1 | Number of slides visible simultaneously. Use 'auto' for variable width slides. |
+| `modelValue` | `number` | 0 | Controls the active slide index. Can be used with v-model for two-way binding. |
+| `mouseDrag` | `boolean` | true | Enables/disables mouse drag navigation. |
+| `pauseAutoplayOnHover` | `boolean` | false | When true, autoplay pauses while the mouse cursor is over the carousel. |
+| `preventExcessiveDragging` | `boolean` | false | Limits dragging behavior at carousel boundaries for better UX. |
+| `snapAlign` | 'start', 'end', 'center-odd', 'center-even' | 'center' | Determines how slides are aligned within the viewport. |
+| `touchDrag` | `boolean` | true | Enables/disables touch navigation on touch-enabled devices. |
+| `transition` | `number` | 300 | Duration of the slide transition animation in milliseconds. |
+| `wrapAround` | `boolean` | false | When true, creates an infinite loop effect by connecting the last slide to the first. |
+
+> **itemsToShow**: Controls the number of visible slides. Values between 1 and the total slide count are valid. Values outside this range are automatically clamped. Using 'auto' allows slides to determine their own width based on content.
+
+> **Direction Settings**: For vertical orientations ('ttb'/'top-to-bottom', 'btt'/'bottom-to-top'), the carousel requires a fixed height setting. Direction can be specified using either short ('ltr', 'rtl', 'ttb', 'btt') or verbose ('left-to-right', 'right-to-left', 'top-to-bottom', 'bottom-to-top') formats.
+
+> **Drag Prevention**: The `preventExcessiveDragging` option is automatically disabled when `wrapAround` is enabled, as boundary restrictions aren't needed in infinite loop mode.
## Slots
@@ -62,12 +66,11 @@ Used to add display carousel addons components.
### Slots Attributes
-| Prop | Description |
-| ---------------- | ------------------------------------------------------------------------------------------- |
-| ~~`slideWidth`~~ | ~~the width of a single slide element.~~ |
-| `slideSize` | the width/height of a single slide element. |
-| `currentSlide` | index number of the current slide. |
-| `slidesCount` | the count of all slides |
+| Prop | Description |
+| -------------- | ------------------------------------------- |
+| `currentSlide` | index number of the current slide. |
+| `slideSize` | the width/height of a single slide element. |
+| `slidesCount` | the count of all slides |
#### Example
@@ -91,12 +94,12 @@ Available keys:
| Key | Defaults | Description |
| --------------------- | -------------------------------------- | -------------------------------------------------------------------------- |
+| `ariaGallery` | "Gallery" | Used as the aria-label for the main carousel element, indicating purpose. |
+| `ariaNavigateToSlide` | "Navigate to slide {slideNumber}" | Sets title and aria-label for pagination buttons to select a slide. |
| `ariaNextSlide` | "Navigate to next slide" | Sets title and aria-label for the “Next” navigation button. |
| `ariaPreviousSlide` | "Navigate to previous slide" | Sets title and aria-label for the “Previous” navigation button. |
-| `ariaNavigateToSlide` | "Navigate to slide {slideNumber}" | Sets title and aria-label for pagination buttons to select a slide. |
-| `ariaGallery` | "Gallery" | Used as the aria-label for the main carousel element, indicating purpose. |
-| `itemXofY` | "Item {currentSlide} of {slidesCount}" | Provides screen readers with the current slide’s position in the sequence. |
-| `iconArrowUp` | "Arrow pointing upwards" | Sets title and aria-label for the upward-pointing arrow SVG icon. |
| `iconArrowDown` | "Arrow pointing downwards" | Sets title and aria-label for the downward-pointing arrow SVG icon. |
-| `iconArrowRight` | "Arrow pointing to the right" | Sets title and aria-label for the right-pointing arrow SVG icon. |
| `iconArrowLeft` | "Arrow pointing to the left" | Sets title and aria-label for the left-pointing arrow SVG icon. |
+| `iconArrowRight` | "Arrow pointing to the right" | Sets title and aria-label for the right-pointing arrow SVG icon. |
+| `iconArrowUp` | "Arrow pointing upwards" | Sets title and aria-label for the upward-pointing arrow SVG icon. |
+| `itemXofY` | "Item {currentSlide} of {slidesCount}" | Provides screen readers with the current slide’s position in the sequence. |
diff --git a/src/components/ARIA/ARIA.ts b/src/components/ARIA/ARIA.ts
index 0809bede..3164109b 100644
--- a/src/components/ARIA/ARIA.ts
+++ b/src/components/ARIA/ARIA.ts
@@ -1,4 +1,4 @@
-import { defineComponent, inject, h } from 'vue'
+import { defineComponent, h, inject } from 'vue'
import { injectCarousel } from '@/shared'
import { i18nFormatter } from '@/utils'
diff --git a/src/components/Carousel/Carousel.css b/src/components/Carousel/Carousel.css
index a1100a09..099cd04e 100644
--- a/src/components/Carousel/Carousel.css
+++ b/src/components/Carousel/Carousel.css
@@ -4,11 +4,11 @@
}
.carousel {
+ height: var(--vc-carousel-height);
+ overscroll-behavior: none;
position: relative;
touch-action: pan-y;
- overscroll-behavior: none;
z-index: 1;
- height: var(--vc-carousel-height);
}
.carousel.is-dragging {
@@ -17,78 +17,68 @@
.carousel__track {
display: flex;
+ gap: var(--vc-slide-gap);
+ height: 100%;
list-style: none;
- padding: 0 !important;
margin: 0 !important;
- width: 100%;
- height: 100%;
+ padding: 0 !important;
position: relative;
transition: transform ease-out;
transition-duration: var(--vc-transition-duration);
- gap: var(--vc-slide-gap);
+ width: 100%;
}
.carousel__viewport {
+ height: 100%;
overflow: hidden;
width: 100%;
- height: 100%;
}
.carousel__sr-only {
- position: absolute;
- width: 1px;
+ border: 0;
+ clip: rect(0, 0, 0, 0);
height: 1px;
- padding: 0;
margin: -1px;
overflow: hidden;
- clip: rect(0, 0, 0, 0);
- border: 0;
+ padding: 0;
+ position: absolute;
+ width: 1px;
}
-.carousel.is-ttb {
- .carousel__track {
- flex-direction: column;
- }
+.carousel.is-ttb .carousel__track {
+ flex-direction: column;
}
-.carousel.is-btt {
- .carousel__track {
- flex-direction: column-reverse;
- }
+.carousel.is-btt .carousel__track {
+ flex-direction: column-reverse;
}
-.carousel.is-vertical {
- .carousel__slide--clone:first-child {
- margin-block-start: var(--vc-cloned-offset);
- }
+.carousel.is-vertical .carousel__slide--clone:first-child {
+ margin-block-start: var(--vc-cloned-offset);
}
-.carousel:not(.is-vertical) {
- .carousel__slide--clone:first-child {
- margin-inline-start: var(--vc-cloned-offset);
- }
+.carousel:not(.is-vertical) .carousel__slide--clone:first-child {
+ margin-inline-start: var(--vc-cloned-offset);
}
-.carousel.is-effect-fade {
- .carousel__track {
- transition: none;
- display: grid;
- grid-template-columns: 100%;
- grid-template-rows: 100%;
- }
+.carousel.is-effect-fade .carousel__track {
+ display: grid;
+ grid-template-columns: 100%;
+ grid-template-rows: 100%;
+ transition: none;
+}
- .carousel__slide {
- opacity: 0;
- width: 100% !important;
- height: 100% !important;
- transition: opacity ease-in-out;
- transition-duration: var(--vc-transition-duration);
- grid-area: 1 / 1; /* Make all slides occupy the same grid cell */
- pointer-events: none; /* Prevent inactive slides from being clickable */
- }
+.carousel.is-effect-fade .carousel__slide {
+ grid-area: 1 / 1;
+ height: 100% !important;
+ opacity: 0;
+ pointer-events: none;
+ transition: opacity ease-in-out;
+ transition-duration: var(--vc-transition-duration);
+ width: 100% !important;
+}
- .carousel__slide--active {
- opacity: 1;
- pointer-events: auto; /* Re-enable pointer events for active slide */
- }
+.carousel.is-effect-fade .carousel__slide--active {
+ opacity: 1;
+ pointer-events: auto;
}
diff --git a/src/components/Carousel/Carousel.spec.ts b/src/components/Carousel/Carousel.spec.ts
index 9ac54ba8..9e0e8880 100644
--- a/src/components/Carousel/Carousel.spec.ts
+++ b/src/components/Carousel/Carousel.spec.ts
@@ -1,5 +1,5 @@
import { mount } from '@vue/test-utils'
-import { expect, it, describe, beforeEach } from 'vitest'
+import { beforeEach, describe, expect, it } from 'vitest'
import { Carousel } from './Carousel'
diff --git a/src/components/Carousel/Carousel.ts b/src/components/Carousel/Carousel.ts
index 4a77e114..af91a7e9 100644
--- a/src/components/Carousel/Carousel.ts
+++ b/src/components/Carousel/Carousel.ts
@@ -1,42 +1,42 @@
import {
+ ComputedRef,
+ computed,
defineComponent,
- onMounted,
+ h,
onBeforeUnmount,
- ref,
- reactive,
+ onMounted,
provide,
- computed,
- h,
- watch,
- SetupContext,
+ reactive,
Ref,
- ComputedRef,
- watchEffect,
+ ref,
+ SetupContext,
shallowReactive,
+ watch,
+ watchEffect,
} from 'vue'
import { ARIA as ARIAComponent } from '@/components/ARIA'
import {
CarouselConfig,
+ createSlideRegistry,
DEFAULT_CONFIG,
DIR_MAP,
+ injectCarousel,
NonNormalizedDir,
NormalizedDir,
- injectCarousel,
- createSlideRegistry,
} from '@/shared'
import {
- except,
- throttle,
- getNumberInRange,
- mapNumberToRange,
+ calculateAverage,
createCloneSlides,
+ except,
getDraggedSlidesCount,
- getSnapAlignOffset,
+ getNumberInRange,
getScaleMultipliers,
+ getSnapAlignOffset,
+ mapNumberToRange,
ScaleMultipliers,
+ throttle,
toCssValue,
- calculateAverage,
} from '@/utils'
import {
@@ -52,15 +52,15 @@ export const Carousel = defineComponent({
name: 'VueCarousel',
props: carouselProps,
emits: [
- 'init',
+ 'before-init',
'drag',
- 'slide-start',
+ 'init',
'loop',
- 'update:modelValue',
'slide-end',
- 'before-init',
'slide-registered',
+ 'slide-start',
'slide-unregistered',
+ 'update:modelValue',
],
setup(props: CarouselConfig, { slots, emit, expose }: SetupContext) {
const slideRegistry = createSlideRegistry(emit)
@@ -823,45 +823,45 @@ export const Carousel = defineComponent({
const nav: CarouselNav = { slideTo, next, prev }
const provided: InjectedCarousel = reactive({
+ activeSlide: activeSlideIndex,
config,
- slidesCount,
- viewport,
- slides,
currentSlide: currentSlideIndex,
- activeSlide: activeSlideIndex,
+ isSliding,
+ isVertical,
maxSlide: maxSlideIndex,
minSlide: minSlideIndex,
- visibleRange,
- slideSize,
- isVertical,
- normalizedDir,
nav,
- isSliding,
+ normalizedDir,
slideRegistry,
+ slideSize,
+ slides,
+ slidesCount,
+ viewport,
+ visibleRange,
})
provide(injectCarousel, provided)
const data = reactive({
config,
- slidesCount,
- slideSize,
currentSlide: currentSlideIndex,
maxSlide: maxSlideIndex,
- minSlide: minSlideIndex,
middleSlide: middleSlideIndex,
+ minSlide: minSlideIndex,
+ slideSize,
+ slidesCount,
})
expose({
- updateBreakpointsConfig,
- updateSlidesData,
- updateSlideSize,
- restartCarousel,
- slideTo,
+ data,
+ nav,
next,
prev,
- nav,
- data,
+ restartCarousel,
+ slideTo,
+ updateBreakpointsConfig,
+ updateSlideSize,
+ updateSlidesData,
})
return () => {
diff --git a/src/components/Carousel/Carousel.types.ts b/src/components/Carousel/Carousel.types.ts
index 4ce77cea..05a39099 100644
--- a/src/components/Carousel/Carousel.types.ts
+++ b/src/components/Carousel/Carousel.types.ts
@@ -6,50 +6,60 @@ import {
ShallowReactive,
} from 'vue'
-import { SlideRegistry, CarouselConfig, NormalizedDir } from '@/shared'
+import { CarouselConfig, NormalizedDir, SlideRegistry } from '@/shared'
-export interface CarouselNav {
- slideTo: (index: number) => void
- next: (skipTransition?: boolean) => void
- prev: (skipTransition?: boolean) => void
+export type ElRect = {
+ height: number
+ width: number
}
-export type InjectedCarousel = Reactive<{
- config: CarouselConfig
- viewport: Ref
- slides: ShallowReactive>
- slidesCount: ComputedRef
- activeSlide: Ref
- currentSlide: Ref
- maxSlide: ComputedRef
- minSlide: ComputedRef
- visibleRange: ComputedRef<{ min: number; max: number }>
- slideSize: Ref
- isVertical: ComputedRef
- normalizedDir: ComputedRef
- nav: CarouselNav
- isSliding: Ref
- slideRegistry: SlideRegistry
-}>
+export type Range = {
+ min: number
+ max: number
+}
-export interface CarouselData {
+export type CarouselData = {
config: CarouselConfig
- slidesCount: Ref
- slideSize: Ref
currentSlide: Ref
maxSlide: Ref
- minSlide: Ref
middleSlide: Ref
+ minSlide: Ref
+ slideSize: Ref
+ slidesCount: Ref
}
-export interface CarouselMethods extends CarouselNav {
+export type CarouselExposed = CarouselMethods & {
+ data: Reactive
+ nav: CarouselNav
+}
+
+export type CarouselMethods = CarouselNav & {
+ restartCarousel: () => void
updateBreakpointsConfig: () => void
- updateSlidesData: () => void
updateSlideSize: () => void
- restartCarousel: () => void
+ updateSlidesData: () => void
}
-export interface CarouselExposed extends CarouselMethods {
- nav: CarouselNav
- data: Reactive
+
+export type CarouselNav = {
+ next: (skipTransition?: boolean) => void
+ prev: (skipTransition?: boolean) => void
+ slideTo: (index: number) => void
}
-export type ElRect = { width: number; height: number }
+
+export type InjectedCarousel = Reactive<{
+ activeSlide: Ref
+ config: CarouselConfig
+ currentSlide: Ref
+ isSliding: Ref
+ isVertical: ComputedRef
+ maxSlide: ComputedRef
+ minSlide: ComputedRef
+ nav: CarouselNav
+ normalizedDir: ComputedRef
+ slideRegistry: SlideRegistry
+ slideSize: Ref
+ slides: ShallowReactive>
+ slidesCount: ComputedRef
+ viewport: Ref
+ visibleRange: ComputedRef
+}>
diff --git a/src/components/Carousel/carouselProps.ts b/src/components/Carousel/carouselProps.ts
index f752bbdc..9456741f 100644
--- a/src/components/Carousel/carouselProps.ts
+++ b/src/components/Carousel/carouselProps.ts
@@ -11,33 +11,35 @@ import {
import type {
BreakpointMode,
- Dir,
- SnapAlign,
CarouselConfig,
- SlideEffect,
+ Dir,
NonNormalizedDir,
NormalizedDir,
+ SlideEffect,
+ SnapAlign,
} from '@/shared'
export const carouselProps = {
- // enable/disable the carousel component
- enabled: {
- default: DEFAULT_CONFIG.enabled,
- type: Boolean,
+ // time to auto advance slides in ms
+ autoplay: {
+ default: DEFAULT_CONFIG.autoplay,
+ type: Number,
},
- // count of items to showed per view
- itemsToShow: {
- default: DEFAULT_CONFIG.itemsToShow,
- type: [Number, String],
+ // an object to store breakpoints
+ breakpoints: {
+ default: DEFAULT_CONFIG.breakpoints,
+ type: Object as PropType,
},
- // count of items to be scrolled
- itemsToScroll: {
- default: DEFAULT_CONFIG.itemsToScroll,
- type: Number,
+ // controls the breakpoint mode relative to the carousel container or the viewport
+ breakpointMode: {
+ default: DEFAULT_CONFIG.breakpointMode,
+ validator(value: BreakpointMode) {
+ return BREAKPOINT_MODE_OPTIONS.includes(value)
+ },
},
- // control infinite scrolling mode
- wrapAround: {
- default: DEFAULT_CONFIG.wrapAround,
+ // enable/disable the carousel component
+ enabled: {
+ default: DEFAULT_CONFIG.enabled,
type: Boolean,
},
// control the gap between slides
@@ -50,39 +52,24 @@ export const carouselProps = {
default: DEFAULT_CONFIG.height,
type: [Number, String],
},
- // control snap position alignment
- snapAlign: {
- default: DEFAULT_CONFIG.snapAlign,
- validator(value: SnapAlign) {
- return SNAP_ALIGN_OPTIONS.includes(value)
- },
+ ignoreAnimations: {
+ default: false,
+ type: [Array, Boolean, String] as PropType,
},
- // sliding transition time in ms
- transition: {
- default: DEFAULT_CONFIG.transition,
+ // count of items to be scrolled
+ itemsToScroll: {
+ default: DEFAULT_CONFIG.itemsToScroll,
type: Number,
},
- // controls the breakpoint mode relative to the carousel container or the viewport
- breakpointMode: {
- default: DEFAULT_CONFIG.breakpointMode,
- validator(value: BreakpointMode) {
- return BREAKPOINT_MODE_OPTIONS.includes(value)
- },
- },
- // an object to store breakpoints
- breakpoints: {
- default: DEFAULT_CONFIG.breakpoints,
- type: Object as PropType,
- },
- // time to auto advance slides in ms
- autoplay: {
- default: DEFAULT_CONFIG.autoplay,
- type: Number,
+ // count of items to showed per view
+ itemsToShow: {
+ default: DEFAULT_CONFIG.itemsToShow,
+ type: [Number, String],
},
- // pause autoplay when mouse hover over the carousel
- pauseAutoplayOnHover: {
- default: DEFAULT_CONFIG.pauseAutoplayOnHover,
- type: Boolean,
+ // aria-labels and additional text labels
+ i18n: {
+ default: DEFAULT_CONFIG.i18n,
+ type: Object as PropType,
},
// slide number number of initial slide
modelValue: {
@@ -99,7 +86,43 @@ export const carouselProps = {
default: DEFAULT_CONFIG.touchDrag,
type: Boolean,
},
+ pauseAutoplayOnHover: {
+ default: DEFAULT_CONFIG.pauseAutoplayOnHover,
+ type: Boolean,
+ },
+ preventExcessiveDragging: {
+ default: false,
+ type: Boolean,
+ validator(value: boolean, props: { wrapAround?: boolean }) {
+ if (value && props.wrapAround) {
+ console.warn(
+ `[vue3-carousel warn]: "preventExcessiveDragging" cannot be used with wrapAround. The setting will be ignored.`
+ )
+ }
+
+ return true
+ },
+ },
// control snap position alignment
+ snapAlign: {
+ default: DEFAULT_CONFIG.snapAlign,
+ validator(value: SnapAlign) {
+ return SNAP_ALIGN_OPTIONS.includes(value)
+ },
+ },
+ slideEffect: {
+ type: String as PropType,
+ default: DEFAULT_CONFIG.slideEffect,
+ validator(value: SlideEffect) {
+ return SLIDE_EFFECTS.includes(value)
+ },
+ },
+ // sliding transition time in ms
+ transition: {
+ default: DEFAULT_CONFIG.transition,
+ type: Number,
+ },
+ // control the gap between slides
dir: {
type: String as PropType,
default: DEFAULT_CONFIG.dir,
@@ -122,33 +145,9 @@ export const carouselProps = {
return true
},
},
- // aria-labels and additional text labels
- i18n: {
- default: DEFAULT_CONFIG.i18n,
- type: Object as PropType,
- },
- ignoreAnimations: {
- default: false,
- type: [Array, Boolean, String] as PropType,
- },
- slideEffect: {
- type: String as PropType,
- default: DEFAULT_CONFIG.slideEffect,
- validator(value: SlideEffect) {
- return SLIDE_EFFECTS.includes(value)
- },
- },
- preventExcessiveDragging: {
- default: false,
+ // control infinite scrolling mode
+ wrapAround: {
+ default: DEFAULT_CONFIG.wrapAround,
type: Boolean,
- validator(value: boolean, props: { wrapAround?: boolean }) {
- if (value && props.wrapAround) {
- console.warn(
- `[vue3-carousel warn]: "preventExcessiveDragging" cannot be used with wrapAround. The setting will be ignored.`
- )
- }
-
- return true
- },
},
}
diff --git a/src/components/Icon/Icon.css b/src/components/Icon/Icon.css
index 9f17dd99..5ff14f48 100644
--- a/src/components/Icon/Icon.css
+++ b/src/components/Icon/Icon.css
@@ -3,7 +3,7 @@
}
.carousel__icon {
- width: var(--vc-icn-width);
- height: var(--vc-icn-width);
fill: currentColor;
+ height: var(--vc-icn-width);
+ width: var(--vc-icn-width);
}
diff --git a/src/components/Icon/Icon.spec.ts b/src/components/Icon/Icon.spec.ts
index 53a94b3a..f328925e 100644
--- a/src/components/Icon/Icon.spec.ts
+++ b/src/components/Icon/Icon.spec.ts
@@ -1,5 +1,5 @@
import { mount } from '@vue/test-utils'
-import { expect, it, describe, afterEach, vi } from 'vitest'
+import { afterEach, describe, expect, it, vi } from 'vitest'
import { Icon } from './Icon'
import { IconName, IconProps } from './Icon.types'
@@ -11,13 +11,6 @@ describe('Icon.ts', () => {
consoleMock.mockReset()
})
- it('It should error if no iconName', () => {
- const wrapper = mount(Icon, { props: {} as IconProps })
- expect(wrapper.html()).toBe('')
- expect(consoleMock).toHaveBeenCalledOnce()
- expect(consoleMock.mock.calls[0][0]).toBe('[Vue warn]: Missing required prop: "name"')
- })
-
it('It should error if iconName is invalid', () => {
const wrapper = mount(Icon, { props: { name: 'foo' as IconProps['name'] } })
expect(wrapper.html()).toBe('')
@@ -27,14 +20,23 @@ describe('Icon.ts', () => {
)
})
+ it('It should error if no iconName', () => {
+ const wrapper = mount(Icon, { props: {} as IconProps })
+ expect(wrapper.html()).toBe('')
+ expect(consoleMock).toHaveBeenCalledOnce()
+ expect(consoleMock.mock.calls[0][0]).toBe('[Vue warn]: Missing required prop: "name"')
+ })
+
it('It should render standalone', async () => {
- await Promise.all(Object.values(IconName).map(async (name) => {
- const wrapper = mount(Icon, { props: { name: name } })
- expect(consoleMock).not.toHaveBeenCalled()
- expect(wrapper.html()).toMatchSnapshot()
+ await Promise.all(
+ Object.values(IconName).map(async (name) => {
+ const wrapper = mount(Icon, { props: { name: name } })
+ expect(consoleMock).not.toHaveBeenCalled()
+ expect(wrapper.html()).toMatchSnapshot()
- await wrapper.setProps({ title: 'Test title' })
- expect(wrapper.find('svg title').text()).toBe('Test title')
- }))
+ await wrapper.setProps({ title: 'Test title' })
+ expect(wrapper.find('svg title').text()).toBe('Test title')
+ })
+ )
})
})
diff --git a/src/components/Icon/Icon.ts b/src/components/Icon/Icon.ts
index 6d800c5e..6ea50efa 100644
--- a/src/components/Icon/Icon.ts
+++ b/src/components/Icon/Icon.ts
@@ -4,22 +4,22 @@ import { DEFAULT_CONFIG, injectCarousel } from '@/shared'
import { IconName, IconNameValue, IconProps } from './Icon.types'
-function isIconName(candidate: string): candidate is IconName {
- return candidate in IconName
-}
-
const iconI18n = (name: Name) =>
`icon${name.charAt(0).toUpperCase() + name.slice(1)}` as `icon${Capitalize}`
-const validateIconName = (value: IconNameValue) => {
- return value && isIconName(value)
-}
-
export const icons = {
- arrowUp: 'M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z',
arrowDown: 'M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z',
- arrowRight: 'M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z',
arrowLeft: 'M15.41 16.59L10.83 12l4.58-4.59L14 6l-6 6 6 6 1.41-1.41z',
+ arrowRight: 'M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z',
+ arrowUp: 'M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z',
+}
+
+function isIconName(candidate: string): candidate is IconName {
+ return candidate in IconName
+}
+
+const validateIconName = (value: IconNameValue) => {
+ return value && isIconName(value)
}
export const Icon = defineComponent({
@@ -45,8 +45,7 @@ export const Icon = defineComponent({
const path = icons[iconName]
const pathEl = h('path', { d: path })
- const iconTitle: string =
- carousel?.config.i18n[iconI18n(iconName)] || props.title!
+ const iconTitle: string = carousel?.config.i18n[iconI18n(iconName)] || props.title!
const titleEl = h('title', iconTitle)
diff --git a/src/components/Icon/Icon.types.ts b/src/components/Icon/Icon.types.ts
index 9245c13d..5cd98826 100644
--- a/src/components/Icon/Icon.types.ts
+++ b/src/components/Icon/Icon.types.ts
@@ -1,13 +1,13 @@
export enum IconName {
- arrowUp = 'arrowUp',
arrowDown = 'arrowDown',
- arrowRight = 'arrowRight',
arrowLeft = 'arrowLeft',
+ arrowRight = 'arrowRight',
+ arrowUp = 'arrowUp',
}
export type IconNameValue = `${IconName}`
-export interface IconProps {
- title?: string
+export type IconProps = {
name: IconNameValue
+ title?: string
}
diff --git a/src/components/Icon/__snapshots__/Icon.spec.ts.snap b/src/components/Icon/__snapshots__/Icon.spec.ts.snap
index 0d259894..f39abf83 100644
--- a/src/components/Icon/__snapshots__/Icon.spec.ts.snap
+++ b/src/components/Icon/__snapshots__/Icon.spec.ts.snap
@@ -1,16 +1,16 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`Icon.ts > It should render standalone 1`] = `
-"