@coreui/vue-pro
Version:
UI Components Library for Vue.js
356 lines (336 loc) • 8.69 kB
text/typescript
import { computed, defineComponent, h, ref, watch } from 'vue'
import { CPagination, CPaginationItem } from './../pagination'
const CSmartPagination = defineComponent({
name: 'CSmartPagination',
props: {
/**
* Horizontall align
*
* @default 'start'
*/
align: {
type: String,
default: 'start',
validator: (value: string) => {
return ['start', 'center', 'end'].includes(value)
},
},
/**
* Current page number
*
* @default 1
*/
activePage: {
type: Number,
default: 1,
},
/**
* Show/hide arrows
*
* @default true
*/
arrows: {
type: Boolean,
default: true,
},
/**
* Show/hide dots
*
* @default true
*/
dots: {
type: Boolean,
default: true,
},
/**
* Show double arrows buttons
*
* @default true
*/
doubleArrows: {
type: Boolean,
default: true,
},
/**
* The content of 'firstButton' button
*
* @default '«'
*/
firstButton: {
type: String,
default: '«',
},
/**
* The content of 'lastButton' button
*
* @default '»'
*/
lastButton: {
type: String,
default: '»',
},
/**
* Maximum items number
*
* @default 5
*/
limit: {
type: Number,
default: 5,
},
/**
* The content of 'nextButton' button
*
* @default '›'
*/
nextButton: {
type: String,
default: '›',
},
/**
* Number of pages
*/
pages: {
type: Number,
default: 1000,
},
/**
* The content of 'previousButton' button
*
* @default '‹'
*/
previousButton: {
type: String,
default: '‹',
},
/**
* Size of pagination, valid values: 'sm', 'lg'
*/
size: {
type: String,
default: undefined,
required: false,
validator: (value: string) => {
return ['sm', 'lg'].includes(value)
},
},
},
emits: [
/**
* On active page change callback.
*/
'activePageChange',
],
setup(props, { emit }) {
const activePage = ref(props.activePage)
const limit = ref(props.limit)
const pages = ref(props.pages)
watch(
() => props.activePage,
() => {
activePage.value = props.activePage
},
)
watch(
() => props.limit,
() => {
limit.value = props.limit
},
)
watch(
() => props.pages,
() => {
pages.value = props.pages
},
)
const showDots = computed(() => {
return props.dots && limit.value > 4 && limit.value < pages.value
})
const maxPrevItems = computed(() => {
return Math.floor((limit.value - 1) / 2)
})
const maxNextItems = computed(() => {
return Math.ceil((limit.value - 1) / 2)
})
const beforeDots = computed(() => {
return showDots.value && activePage.value > maxPrevItems.value + 1
})
const afterDots = computed(() => {
return showDots.value && activePage.value < pages.value - maxNextItems.value
})
const computedLimit = computed(() => {
return limit.value - (afterDots.value ? 1 : 0) - (beforeDots.value ? 1 : 0)
})
const range = computed(() => {
return activePage.value + maxNextItems.value
})
const lastItem = computed(() => {
return range.value >= pages.value ? pages.value : range.value - (afterDots.value ? 1 : 0)
})
const itemsAmount = computed(() => {
return pages.value < computedLimit.value ? pages.value : computedLimit.value
})
const items = computed(() => {
if (activePage.value - maxPrevItems.value <= 1) {
return Array.from(
{
length: itemsAmount.value,
},
(_v, i) => i + 1,
)
} else {
return Array.from(
{
length: itemsAmount.value,
},
(_v, i) => {
return lastItem.value - i
},
).reverse()
}
})
const setPage = (number: number): void => {
if (number !== activePage.value) {
activePage.value = number
emit('activePageChange', number)
}
}
return () =>
h(
CPagination,
{
align: props.align,
'aria-label': 'pagination',
size: props.size,
},
{
default: () => [
props.doubleArrows &&
h(
CPaginationItem,
{
onClick: () => {
activePage.value !== 1 && setPage(1)
},
'aria-label': 'Go to first page',
...(activePage.value === 1 && {
'aria-disabled': true,
disabled: true,
}),
},
{
default: () =>
typeof props.firstButton === 'string'
? h('span', {
innerHTML: props.firstButton,
})
: props.firstButton,
},
),
props.arrows &&
h(
CPaginationItem,
{
onClick: () => {
activePage.value !== 1 && setPage(activePage.value - 1)
},
'aria-label': 'Go to previous page',
...(activePage.value === 1 && {
'aria-disabled': true,
disabled: true,
}),
},
{
default: () =>
typeof props.previousButton === 'string'
? h('span', {
innerHTML: props.previousButton,
})
: props.previousButton,
},
),
beforeDots.value &&
h(
CPaginationItem,
{
role: 'separator',
disabled: true,
},
{
default: () => '...',
},
),
items.value.map((i: number) => {
return h(
CPaginationItem,
{
onClick: () => setPage(i),
'aria-label': activePage.value === i ? `Current page ${i}` : `Go to page ${i}`,
active: activePage.value === i,
},
{
default: () => i,
},
)
}),
afterDots.value &&
h(
CPaginationItem,
{
role: 'separator',
disabled: true,
},
{
default: () => '...',
},
),
props.arrows &&
h(
CPaginationItem,
{
onClick: () => {
activePage.value !== pages.value && setPage(activePage.value + 1)
},
'aria-label': 'Go to next page',
...(activePage.value === pages.value && {
'aria-disabled': true,
disabled: true,
}),
},
{
default: () =>
typeof props.nextButton === 'string'
? h('span', {
innerHTML: props.nextButton,
})
: props.nextButton,
},
),
props.doubleArrows &&
h(
CPaginationItem,
{
onClick: () => {
activePage.value !== pages.value && setPage(pages.value)
},
'aria-label': 'Go to last page',
...(activePage.value === pages.value && {
'aria-disabled': true,
disabled: true,
}),
},
{
default: () =>
typeof props.lastButton === 'string'
? h('span', {
innerHTML: props.lastButton,
})
: props.lastButton,
},
),
],
},
)
},
})
export { CSmartPagination }