Skip to content

Commit

Permalink
Merge pull request #446 from Tofandel/feat/paginated-pagination
Browse files Browse the repository at this point in the history
feat: add paginated navigation for carousel pagination
  • Loading branch information
ismail9k authored Dec 16, 2024
2 parents 31107b7 + 3315633 commit 334e0b4
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 17 deletions.
7 changes: 4 additions & 3 deletions docs/addons.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import { Pagination as CarouselPagination } from 'vue3-carousel'

### Config

| Prop | Default | Description |
| ---------------- | ------- | ---------------------------- |
| `disableOnClick` | false | Disables navigation on click |
| Prop | Default | Description |
|-------------------------| ------- |-------------------------------------------------------------------------------------------------------------------------------------|
| `disableOnClick` | false | Disables navigation on click |
| `paginateByItemsToShow` | false | Enables grouping of slides into pages (calculated based on the current itemsToShow) where each page gets a single navigation button |
2 changes: 1 addition & 1 deletion playground/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ const handelButtonClick = () => {
</div>
</CarouselSlide>
<template #addons>
<CarouselPagination />
<CarouselPagination paginated />
<CarouselNavigation />
</template>
</VueCarousel>
Expand Down
53 changes: 40 additions & 13 deletions src/components/Pagination/Pagination.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { inject, h, VNode, defineComponent } from 'vue'
import { inject, h, VNode, defineComponent, computed } from 'vue'

import { injectCarousel } from '@/shared'
import { mapNumberToRange, i18nFormatter } from '@/utils'
import { mapNumberToRange, i18nFormatter, calculateOffset } from '@/utils'

import { PaginationProps } from './Pagination.types'

Expand All @@ -11,7 +11,7 @@ export const Pagination = defineComponent<PaginationProps>({
disableOnClick: {
type: Boolean,
},
paginated: {
paginateByItemsToShow: {
type: Boolean
},
},
Expand All @@ -22,19 +22,46 @@ export const Pagination = defineComponent<PaginationProps>({
return () => '' // Don't render, let vue warn about the missing provide
}

const offset = computed(() => calculateOffset(carousel.config.snapAlign, carousel.config.itemsToShow))
const isPaginated = computed(() => props.paginateByItemsToShow && carousel.config.itemsToShow > 1)
const currentPage = computed(() =>
Math.ceil((carousel.currentSlide - offset.value) / carousel.config.itemsToShow)
)
const pageCount = computed(() =>
Math.ceil(carousel.slidesCount / carousel.config.itemsToShow)
)

const isActive = (slide: number): boolean =>
mapNumberToRange({
val: carousel.currentSlide,
max: carousel.maxSlide,
min: 0,
}) === slide
mapNumberToRange(
isPaginated.value
? {
val: currentPage.value,
max: pageCount.value - 1,
min: 0,
}
: {
val: carousel.currentSlide,
max: carousel.maxSlide,
min: carousel.minSlide,
}
) === slide

return () => {
const children: Array<VNode> = []
for (let slide = carousel.minSlide; slide <= carousel.maxSlide; slide++) {
const buttonLabel = i18nFormatter(carousel.config.i18n.ariaNavigateToSlide, {
slideNumber: slide + 1,
})

for (
let slide = isPaginated.value ? 0 : carousel.minSlide;
slide <= (isPaginated.value ? pageCount.value - 1 : carousel.maxSlide);
slide++
) {
const buttonLabel = i18nFormatter(
carousel.config.i18n[
isPaginated.value ? 'ariaNavigateToPage' : 'ariaNavigateToSlide'
],
{
slideNumber: slide + 1,
}
)
const active = isActive(slide)
const button = h('button', {
type: 'button',
Expand All @@ -47,7 +74,7 @@ export const Pagination = defineComponent<PaginationProps>({
'aria-controls': carousel.slides[slide]?.exposed?.id,
title: buttonLabel,
disabled: props.disableOnClick,
onClick: () => carousel.nav.slideTo(slide),
onClick: () => carousel.nav.slideTo(isPaginated.value ? slide * carousel.config.itemsToShow + offset.value : slide),
})
const item = h('li', { class: 'carousel__pagination-item', key: slide }, button)
children.push(item)
Expand Down
1 change: 1 addition & 0 deletions src/components/Pagination/Pagination.types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export interface PaginationProps {
disableOnClick?: boolean
paginateByItemsToShow?: boolean
}
1 change: 1 addition & 0 deletions src/shared/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export const I18N_DEFAULT_CONFIG = {
ariaNextSlide: 'Navigate to next slide',
ariaPreviousSlide: 'Navigate to previous slide',
ariaNavigateToSlide: 'Navigate to slide {slideNumber}',
ariaNavigateToPage: 'Navigate to page {slideNumber}',
ariaGallery: 'Gallery',
itemXofY: 'Item {currentSlide} of {slidesCount}',
iconArrowUp: 'Arrow pointing upwards',
Expand Down

0 comments on commit 334e0b4

Please sign in to comment.