From ac47a006d1c51ecde7bb67835ab655ac84c7e853 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 25 Jul 2026 04:20:01 +0000 Subject: [PATCH 1/2] Initial plan From 46e3f1e4fcb5921febf7320aea35806765d833e4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 25 Jul 2026 04:23:37 +0000 Subject: [PATCH 2/2] fix: prevent duplicate pagination page numbers near window transitions --- src/components/pagination/index.ts | 18 +++++++++++---- src/components/pagination/pagination.test.ts | 23 ++++++++++++++++++++ 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/src/components/pagination/index.ts b/src/components/pagination/index.ts index 81222a8..0b71a86 100644 --- a/src/components/pagination/index.ts +++ b/src/components/pagination/index.ts @@ -115,13 +115,23 @@ export class JellyPagination extends HTMLElement { const cur = this.page; const out: (number | '…')[] = []; const win = 1; + const pages = new Set([1, total]); - for (let p = 1; p <= total; p++) { - if (p === 1 || p === total || (p >= cur - win && p <= cur + win)) { - out.push(p); - } else if (out[out.length - 1] !== '…') { + for (let p = cur - win; p <= cur + win; p++) { + if (p >= 1 && p <= total) { + pages.add(p); + } + } + + let previous: number | null = null; + + for (const p of [...pages].sort((a, b) => a - b)) { + if (previous !== null && p - previous > 1) { out.push('…'); } + + out.push(p); + previous = p; } return out; diff --git a/src/components/pagination/pagination.test.ts b/src/components/pagination/pagination.test.ts index 63231a7..c456c03 100644 --- a/src/components/pagination/pagination.test.ts +++ b/src/components/pagination/pagination.test.ts @@ -34,3 +34,26 @@ test('clicking a page button navigates and fires change', async () => { host.remove(); }); + +test('moving from page 1 to 6 does not duplicate page numbers', async () => { + const host = mount(''); + const el = host.querySelector('jelly-pagination') as JellyPagination; + await raf(); + + for (let i = 0; i < 5; i++) { + const next = [...el.shadowRoot!.querySelectorAll('jelly-button')].find((button) => button.getAttribute('label') === 'Next page'); + + next?.dispatchEvent(new MouseEvent('click', { bubbles: true })); + await raf(); + } + + expect(el.page).toBe(6); + + const labels = [...el.shadowRoot!.querySelectorAll('jelly-button')].map((button) => button.textContent?.trim() ?? ''); + const pages = labels.filter((label) => /^\d+$/.test(label)); + + expect(pages.filter((label) => label === '5')).toHaveLength(1); + expect(new Set(pages).size).toBe(pages.length); + + host.remove(); +});