diff --git a/packages/bootstrap-vue-next/src/components/BPagination/BPagination.vue b/packages/bootstrap-vue-next/src/components/BPagination/BPagination.vue index 38f321373..bc65ab132 100644 --- a/packages/bootstrap-vue-next/src/components/BPagination/BPagination.vue +++ b/packages/bootstrap-vue-next/src/components/BPagination/BPagination.vue @@ -7,7 +7,13 @@ :aria-label="props.ariaLabel || undefined" @keydown="handleKeyNav" > -
  • +
  • ({ const pageClick = (event: Readonly, pageNumber: number) => { if (pageNumber === computedModelValue.value) return - const clickEvent = new BvEvent('page-click', { cancelable: true, target: event.target, @@ -315,6 +320,13 @@ const pageClick = (event: Readonly, pageNumber: number) => { modelValue.value = pageNumber + nextTick(() => { + if (pageNumber === 1) { + focusFirst() + } else if (pageNumber === pagination.value.numberOfPages) { + focusLast() + } + }) // nextTick(() => { // if (isVisible(target) && un_element.contains(target)) { // attemptFocus(target) @@ -332,18 +344,24 @@ const isDisabled = (el: HTMLButtonElement) => { return !isElement || el.disabled || hasAttr || hasClass } -const getButtons = () => - pageElements.value - ?.map((page) => page.children[0] as HTMLButtonElement) - .filter((btn) => { - if (btn.getAttribute('display') === 'none') { +const getButtons = (): HTMLButtonElement[] => + [...(pageElements.value ?? [])] + ?.sort( + (a, b) => + parseInt(a.getAttribute('displayIndex') || '0') - + parseInt(b.getAttribute('displayIndex') || '0') + ) + ?.map((page) => page.children[0]) + ?.filter((el) => { + if (el.getAttribute('display') === 'none' || el.tagName.toUpperCase() !== 'BUTTON') { return false } - const bcr = btn.getBoundingClientRect() + const bcr = el.getBoundingClientRect() - return !!(bcr && bcr.height > 0 && bcr.width > 0) - }) ?? [] + return true || !!(bcr && bcr.height > 0 && bcr.width > 0) + }) + ?.map((el) => el as HTMLButtonElement) const focusFirst = () => { nextTick(() => { @@ -376,7 +394,6 @@ const focusNext = () => { nextTick(() => { const buttons = getButtons() const index = buttons.indexOf(getActiveElement() as HTMLButtonElement) - if (index < buttons.length - 1 && !isDisabled(buttons[index + 1])) { buttons[index + 1]?.focus() } @@ -385,7 +402,6 @@ const focusNext = () => { const handleKeyNav = (event: KeyboardEvent) => { const {code, shiftKey} = event - if (code === CODE_LEFT || code === CODE_UP) { stopEvent(event) if (shiftKey) { diff --git a/packages/bootstrap-vue-next/src/components/BPagination/pagination.spec.ts b/packages/bootstrap-vue-next/src/components/BPagination/pagination.spec.ts index 5a618711a..591f5a395 100644 --- a/packages/bootstrap-vue-next/src/components/BPagination/pagination.spec.ts +++ b/packages/bootstrap-vue-next/src/components/BPagination/pagination.spec.ts @@ -466,6 +466,25 @@ describe('pagination', () => { expect(await TestScenariosAgainstInvariants(wrapper)).toBe(0) }) + it('can navigate to different pages using the left and right arrow keys', async () => { + const wrapper = mount(BPagination, { + props: {totalRows: 7, perPage: 1, modelValue: 1}, + attachTo: document.body, + }) + await wrapper.find('li.active > button').element?.focus() + expect(document.activeElement?.textContent).toBe('1') + await wrapper.find('ul').trigger('keydown', {code: 'ArrowRight'}) + expect(document.activeElement?.textContent).toBe('2') + await wrapper.find('ul').trigger('keydown', {code: 'ArrowRight'}) + expect(document.activeElement?.textContent).toBe('3') + await wrapper.find('ul').trigger('keydown', {code: 'ArrowRight'}) + expect(document.activeElement?.textContent).toBe('4') + await wrapper.find('button[aria-posinset="4"]').trigger('click') + await wrapper.find('ul').trigger('keydown', {code: 'ArrowRight'}) + expect(document.activeElement?.textContent).toBe('5') + await wrapper.find('ul').trigger('keydown', {code: 'ArrowLeft'}) + expect(document.activeElement?.textContent).toBe('4') + }) }) // eslint-disable-next-line @typescript-eslint/no-explicit-any