/** * createPagination - the HEADLESS core behind : the page/ellipsis * sequence (via the pure `paginationRange`) plus navigation (first/prev/next/last * with clamping) and prop-getters you spread onto your own markup. Pure getters, * no runes - so it is directly unit-testable and framework-free. * * ```svelte * * * ``` */ import { paginationRange, type PaginationItem } from './paginate' export type PaginationConfig = { /** 1-based current page. */ page: () => number pageCount: () => number onChange?: (page: number) => void siblingCount?: () => number boundaryCount?: () => number disabled?: () => boolean } export function createPagination(config: PaginationConfig) { const page = () => config.page() const pageCount = () => config.pageCount() const disabled = () => config.disabled?.() ?? false function go(p: number) { if (disabled()) return const next = Math.min(Math.max(p, 1), pageCount()) if (next !== page()) config.onChange?.(next) } const first = () => go(1) const prev = () => go(page() - 1) const next = () => go(page() + 1) const last = () => go(pageCount()) const canPrev = () => !disabled() && page() > 1 const canNext = () => !disabled() && page() < pageCount() return { /** The page/ellipsis sequence to render, recomputed from the live inputs. */ get items(): PaginationItem[] { return paginationRange({ page: page(), pageCount: pageCount(), siblingCount: config.siblingCount?.() ?? 1, boundaryCount: config.boundaryCount?.() ?? 1, }) }, go, first, prev, next, last, canPrev, canNext, isActive: (p: number) => p === page(), /** Spread onto the `