Skip to content

Commit 0d72cee

Browse files
committed
Add carousel prop for pagination and navigation for external control
1 parent c4f6234 commit 0d72cee

18 files changed

+125
-45
lines changed

docs/api/data.md

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,26 @@ import { ref } from 'vue';
1313
const myCarousel = ref(null);
1414

1515
// Data can be accessed under data property
16-
if (myCarousel.data.currentSlide === 10) {
16+
if (myCarousel.currentSlide === 10) {
1717
// Do your magic here
1818
}
1919
....
2020
```
2121

22-
## Available Data
22+
## Available Exposed data
2323

24-
| Data | Description |
25-
| -------------- | ---------------------------------- |
26-
| `config` | the current carousel configuration |
27-
| `currentSlide` | current slide index |
28-
| `maxSlide` | maximum slide index |
29-
| `middleSlide` | middle slide index |
30-
| `minSlide` | minimum slide index |
31-
| `slideSize` | single slide width or height |
32-
| `slidesCount` | slides total count |
24+
| Data | Description |
25+
|----------------|---------------------------------------------------------------------------------------------------|
26+
| `currentSlide` | current slide index |
27+
| `activeSlide` | current slide index even while dragging |
28+
| `isSliding` | if the slider is dragging |
29+
| `isVertical` | if the slider is vertical |
30+
| `nav` | An object of navigation methods |
31+
| `config` | the current carousel configuration |
32+
| `maxSlide` | maximum slide index |
33+
| `minSlide` | minimum slide index |
34+
| `slideSize` | single slide width or height |
35+
| `slidesCount` | slides total count |
36+
| `slides` | an array of Slides component |
37+
| `viewport` | the viewport element |
38+
| `visibleRange` | an object with {min, max} properties min being the lowest visible slide index and max the highest |

docs/config.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
| `transition` | `number` | 300 | Duration of the slide transition animation in milliseconds. |
2525
| `wrapAround` | `boolean` | false | When true, creates an infinite loop effect by connecting the last slide to the first. |
2626

27-
> **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.
27+
> **itemsToShow**: Controls the number of visible slides. Values higher than 1 and decimals are valid. Using 'auto' allows slides to determine their own width based on content.
2828
2929
> **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.
3030
@@ -88,6 +88,19 @@ Used to add display carousel addons components.
8888
</template>
8989
```
9090

91+
#### Using addons outside of the carousel
92+
93+
```vue {7,8,9}
94+
<template>
95+
<Carousel ref="carousel">
96+
<Slide v-for="slide in slides" :key="slide">
97+
<div class="carousel__item">{{ slide }}</div>
98+
</Slide>
99+
</Carousel>
100+
<Navigation :carousel="carousel" v-if="carousel && carousel.slidesCount > 1" />
101+
</template>
102+
```
103+
91104
### I18n
92105

93106
Available keys:

eslint.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export default tseslint.config(
2121
},
2222
},
2323
rules: {
24-
'no-console': 'off',
24+
'no-console': ["error", { allow: ["warn", "error"] }],
2525
'@typescript-eslint/no-unused-vars': 'error',
2626
'@typescript-eslint/no-empty-function': 'off',
2727
'@typescript-eslint/no-non-null-assertion': 'off',

rollup.config.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,9 @@ export default [
6565
{
6666
input: 'src/index.ts',
6767
output: [{ file: 'dist/carousel.d.ts', format: 'es' }],
68-
external: [/\.css$/],
68+
external: ['vue', /\.css$/],
6969
plugins: [
70+
typescript(),
7071
dts({
7172
rollupTypes: true,
7273
pathsToAliases: true,

src/components/Carousel/Carousel.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
SetupContext,
1313
shallowReactive,
1414
watch,
15-
watchEffect,
15+
watchEffect, toRefs,
1616
} from 'vue'
1717

1818
import { ARIA as ARIAComponent } from '@/components/ARIA'
@@ -212,11 +212,7 @@ export const Carousel = defineComponent({
212212

213213
// Validate itemsToShow
214214
if (!isAuto.value) {
215-
config.itemsToShow = getNumberInRange({
216-
val: Number(config.itemsToShow),
217-
max: slidesCount.value,
218-
min: 1,
219-
})
215+
config.itemsToShow = Math.max(Number(config.itemsToShow), 1);
220216
}
221217
}
222218

@@ -854,14 +850,14 @@ export const Carousel = defineComponent({
854850

855851
expose<CarouselExposed>({
856852
data,
857-
nav,
858853
next,
859854
prev,
860855
restartCarousel,
861856
slideTo,
862857
updateBreakpointsConfig,
863858
updateSlideSize,
864859
updateSlidesData,
860+
...toRefs(provided),
865861
})
866862

867863
return () => {

src/components/Carousel/Carousel.types.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,8 @@ export type CarouselData = {
2929
}
3030

3131
export type CarouselExposed = CarouselMethods & {
32-
data: Reactive<CarouselData>
33-
nav: CarouselNav
34-
}
32+
data: Reactive<CarouselData> // TODO deprecate and remove
33+
} & InjectedCarousel
3534

3635
export type CarouselMethods = CarouselNav & {
3736
restartCarousel: () => void

src/components/Carousel/carouselProps.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ export const carouselProps = {
9696
validator(value: boolean, props: { wrapAround?: boolean }) {
9797
if (value && props.wrapAround) {
9898
console.warn(
99-
`[vue3-carousel warn]: "preventExcessiveDragging" cannot be used with wrapAround. The setting will be ignored.`
99+
`[vue3-carousel]: "preventExcessiveDragging" cannot be used with wrapAround. The setting will be ignored.`
100100
)
101101
}
102102

@@ -139,7 +139,7 @@ export const carouselProps = {
139139
(!props.height || props.height === 'auto')
140140
) {
141141
console.warn(
142-
`[vue3-carousel warn]: The dir "${value}" is not supported with height "auto".`
142+
`[vue3-carousel]: The dir "${value}" is not supported with height "auto".`
143143
)
144144
}
145145
return true

src/components/Navigation/Navigation.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { computed, defineComponent, h, inject } from 'vue'
1+
import { computed, defineComponent, h, inject, PropType } from 'vue'
22

33
import { injectCarousel, NormalizedDir } from '@/shared'
44

@@ -9,11 +9,13 @@ import { NavigationProps } from './Navigation.types'
99
export const Navigation = defineComponent<NavigationProps>({
1010
name: 'CarouselNavigation',
1111
inheritAttrs: false,
12+
props: {
13+
carousel: {
14+
type: Object as PropType<NavigationProps['carousel']>,
15+
},
16+
},
1217
setup(props, { slots, attrs }) {
13-
const carousel = inject(injectCarousel)
14-
if (!carousel) {
15-
return () => '' // Don't render, let vue warn about the missing provide
16-
}
18+
let carousel = inject(injectCarousel, null)!
1719
const { next: slotNext, prev: slotPrev } = slots
1820

1921
const getPrevIcon = () => {
@@ -45,6 +47,13 @@ export const Navigation = defineComponent<NavigationProps>({
4547
)
4648

4749
return () => {
50+
if (props.carousel) {
51+
carousel = props.carousel;
52+
}
53+
if (!carousel) {
54+
console.warn('[vue3-carousel]: A carousel component must be provided for the navigation component to display')
55+
return '';
56+
}
4857
const { i18n } = carousel.config
4958
const prevButton = h(
5059
'button',
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,5 @@
1-
export type NavigationProps = Record<never, never> // No props for now
1+
import { Carousel, CarouselExposed } from '@/components/Carousel'
2+
3+
export type NavigationProps = {
4+
carousel?: InstanceType<typeof Carousel> & CarouselExposed
5+
}

src/components/Pagination/Pagination.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { computed, defineComponent, h, inject, VNode } from 'vue'
1+
import { computed, defineComponent, h, inject, PropType, VNode } from 'vue'
22

33
import { injectCarousel } from '@/shared'
44
import { getSnapAlignOffset, i18nFormatter, mapNumberToRange } from '@/utils'
@@ -14,13 +14,12 @@ export const Pagination = defineComponent<PaginationProps>({
1414
paginateByItemsToShow: {
1515
type: Boolean,
1616
},
17+
carousel: {
18+
type: Object as PropType<PaginationProps['carousel']>,
19+
}
1720
},
1821
setup(props) {
19-
const carousel = inject(injectCarousel)
20-
21-
if (!carousel) {
22-
return () => '' // Don't render, let vue warn about the missing provide
23-
}
22+
let carousel = inject(injectCarousel, null)!
2423

2524
const itemsToShow = computed(() => carousel.config.itemsToShow as number)
2625
const offset = computed(() =>
@@ -53,6 +52,13 @@ export const Pagination = defineComponent<PaginationProps>({
5352
) === slide
5453

5554
return () => {
55+
if (props.carousel) {
56+
carousel = props.carousel;
57+
}
58+
if (!carousel) {
59+
console.warn('[vue3-carousel]: A carousel component must be provided for the pagination component to display')
60+
return '';
61+
}
5662
const children: Array<VNode> = []
5763

5864
for (

0 commit comments

Comments
 (0)