UNPKG

@coreui/vue-pro

Version:

UI Components Library for Vue.js

356 lines (336 loc) 8.69 kB
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 '&laquo;' */ firstButton: { type: String, default: '&laquo;', }, /** * The content of 'lastButton' button * * @default '&raquo;' */ lastButton: { type: String, default: '&raquo;', }, /** * Maximum items number * * @default 5 */ limit: { type: Number, default: 5, }, /** * The content of 'nextButton' button * * @default '&rsaquo;' */ nextButton: { type: String, default: '&rsaquo;', }, /** * Number of pages */ pages: { type: Number, default: 1000, }, /** * The content of 'previousButton' button * * @default '&lsaquo;' */ previousButton: { type: String, default: '&lsaquo;', }, /** * 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 }