import { makeComponentProps } from '@/composables/component' import { makeTagProps } from '@/composables/tag' import { genericComponent, propsFactory, useRender } from '@/utils' import { ExtractPropTypes, PropType, ref, computed, onMounted } from 'vue' import UntitledColorTypes from '@/types/untitledColorTypes' import { UButton } from '@/components' import { UPaginationNumber } from '@/components' import { useEventListener } from '@vueuse/core' import { throttle } from '@/utils/throttle' export const makeUPaginationProps = propsFactory( { modelValue: { type: String, default: '0', required: false, }, type: { type: String, default: 'default', required: false, }, shape: { type: String, default: 'square', required: false, }, align: { type: [String, undefined] as PropType, required: false, }, pagesCount: { type: String, default: '0', required: false, }, ...makeComponentProps(), ...makeTagProps(), }, 'UPagination' ) export type UPaginationProps = ExtractPropTypes export const UPagination = genericComponent()({ name: 'UPagination', props: makeUPaginationProps(), emits: { change: (value: number) => true, 'update:modelValue': (value: string) => true, }, setup(props, { emit }) { const isMinimalPagination = ref(false) const containerWidth = ref(0) const paginationContainer = ref(null) const containerWidthBreakPoint = 640 const count = parseInt(props.pagesCount, 10) const numbers = Array.from(Array(count), (_, index) => index + 1) const updateActivePage = (pageNumber: number) => { emit('change', pageNumber) emit('update:modelValue', pageNumber.toString()) } const activePageIndex = computed(() => { return parseInt(props.modelValue, 10) }) const getDisplayedPages = computed(() => { if (count <= 6) { return numbers } const centralPage = count / 2 let displayedLeftPages: number[] = [] let displayedRightPages: number[] = [] if (activePageIndex.value >= centralPage) { displayedLeftPages = numbers.slice(0, 3) displayedRightPages = [ numbers[activePageIndex.value - 2], numbers[activePageIndex.value - 1], numbers[activePageIndex.value], ] } else if (activePageIndex.value < centralPage) { displayedLeftPages = [ numbers[activePageIndex.value - 2], numbers[activePageIndex.value - 1], numbers[activePageIndex.value], ] displayedRightPages = numbers.slice(-3) } if (activePageIndex.value === 1) { displayedLeftPages = numbers.slice(0, 3) } if (activePageIndex.value === count) { displayedRightPages = numbers.slice(-3) } return [...displayedLeftPages, '...', ...displayedRightPages] }) const goToPreviousPage = () => { if (activePageIndex.value) { updateActivePage(activePageIndex.value - 1) } } const goToNextPage = () => { const pageCount = parseInt(props.pagesCount, 10) if (activePageIndex.value < pageCount) { updateActivePage(activePageIndex.value + 1) } } const updateContainerWidth = () => { console.log('Called!') if (!paginationContainer.value) { return false } const computedStyle = getComputedStyle(paginationContainer.value) const margin = parseFloat(computedStyle.marginLeft) + parseFloat(computedStyle.marginRight) containerWidth.value = paginationContainer.value.clientWidth + margin isMinimalPagination.value = containerWidth.value <= containerWidthBreakPoint } onMounted(() => { updateContainerWidth() }) useEventListener(window, 'resize', throttle(updateContainerWidth, 100)) const alignClasses = computed(() => ({ ['left-0']: props.align === 'left', ['right-0']: props.align === 'right', ['transform left-1/2 transform -translate-x-1/2']: props.align === 'center' || props.align === undefined || isMinimalPagination.value, })) const prependButtonClasses = computed(() => ({ ['absolute']: props.align === 'left' || props.align === 'right', ['left-0']: props.align === 'right', ['right-72']: props.align === 'left', })) const buttonType = computed(() => { return props.type === 'default' && !isMinimalPagination.value ? UntitledColorTypes.linkGray : UntitledColorTypes.secondaryGray }) const appendButtonClasses = computed(() => ({ ['absolute']: props.align === 'left' || props.align === 'right', ['left-99']: props.align === 'right', ['right-0']: props.align === 'left', })) useRender(() => { return (
{!isMinimalPagination.value ? 'Previous' : null}
{(props.align === undefined || props.align === 'center') && !isMinimalPagination.value ? (
{getDisplayedPages.value.map((page, index) => ( updateActivePage(page as number)} class={page === '...' ? 'pointer-events-none' : ''} > {page} ))}
) : null} {props.align === 'left' || props.align === 'right' || isMinimalPagination.value ? (
{'Page ' + (activePageIndex.value + 1) + ' of ' + props.pagesCount}
) : null}
{!isMinimalPagination.value ? 'Next' : null}
) }) return { count, updateActivePage, goToNextPage, goToPreviousPage, } }, }) export type UPagination = InstanceType