import { computed, type ComputedRef, type Ref, ref } from "vue"; /** * Options for configuring pagination */ export interface UsePaginationOptions { /** Number of items per page (default: 24) */ itemsPerPage?: number; } /** * Return type for the usePagination composable */ export interface UsePaginationReturn { /** Current page number (1-indexed) */ currentPage: Ref; /** Number of items per page */ itemsPerPage: Ref; /** Paginated subset of items for the current page */ paginatedItems: ComputedRef; /** Total number of items */ totalItems: ComputedRef; /** Whether pagination should be shown (total items > items per page) */ showPagination: ComputedRef; /** Handler for page change events */ onPageChange: (page: number) => void; /** Reset to first page */ resetPage: () => void; } /** * Composable for client-side pagination of items * * @example * ```typescript * const items = ref([...]); * const { paginatedItems, currentPage, showPagination, onPageChange } = usePagination(items); * * // In template: * * * ``` * * @param items - Reactive array of items to paginate * @param options - Pagination configuration options * @returns Pagination state and controls */ export function usePagination( items: Ref | ComputedRef, options: UsePaginationOptions = {}, ): UsePaginationReturn { const { itemsPerPage: initialItemsPerPage = 24 } = options; const currentPage = ref(1); const itemsPerPage = ref(initialItemsPerPage); const totalItems = computed(() => items.value.length); const paginatedItems = computed(() => { const offset = (currentPage.value - 1) * itemsPerPage.value; const start = Math.max(0, offset); const end = Math.min(items.value.length, offset + itemsPerPage.value); return items.value.slice(start, end); }); const showPagination = computed(() => totalItems.value > itemsPerPage.value); function onPageChange(page: number) { currentPage.value = page; } function resetPage() { currentPage.value = 1; } return { currentPage, itemsPerPage, paginatedItems, totalItems, showPagination, onPageChange, resetPage, }; }