Skip to content

Commit c8a245c

Browse files
userquinJ-Sek
andauthored
feat(VPagination, VDataTableFooter): ability to hide last page (#22788)
Co-authored-by: J-Sek <J-Sek@users.noreply.github.com>
1 parent a7ecdc3 commit c8a245c

5 files changed

Lines changed: 37 additions & 13 deletions

File tree

packages/api-generator/src/locale/en/VPagination.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
"pageAriaLabel": "Label for each page button.",
1515
"prevIcon": "The icon to use for the prev button.",
1616
"previousAriaLabel": "Label for the previous button.",
17-
"showFirstLastPage": "Show buttons for going to first and last page.",
17+
"showFirstLastPage": "Show buttons for going to first and last page. Since v4.1.0 it accepts `'only-first'`, to only the first page button.",
1818
"start": "Specify the starting page.",
1919
"totalVisible": "Specify the total visible pagination numbers."
2020
},

packages/docs/src/data/new-in.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@
133133
"headerProps": "3.5.0",
134134
"initialSortOrder": "3.11.0",
135135
"pageBy": "3.12.0",
136+
"showFirstLastPage": "4.1.0",
136137
"sortIcon": "3.12.0"
137138
},
138139
"slots": {
@@ -147,6 +148,7 @@
147148
"groupExpandIcon": "3.10.0",
148149
"initialSortOrder": "3.11.0",
149150
"pageBy": "3.12.0",
151+
"showFirstLastPage": "4.1.0",
150152
"sortIcon": "3.12.0"
151153
},
152154
"slots": {

packages/vuetify/src/components/VDataTable/VDataTableFooter.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@ import { useLocale } from '@/composables/locale'
1212

1313
// Utilities
1414
import { computed } from 'vue'
15-
import { genericComponent, omit, propsFactory, useRender } from '@/util'
15+
import { genericComponent, omit, pick, propsFactory, useRender } from '@/util'
1616

1717
// Types
1818
import type { PropType } from 'vue'
19+
import { makeVPaginationProps } from '../VPagination/VPagination'
1920

2021
export const makeVDataTableFooterProps = propsFactory({
2122
color: String,
@@ -70,6 +71,10 @@ export const makeVDataTableFooterProps = propsFactory({
7071
]),
7172
},
7273
showCurrentPage: Boolean,
74+
75+
...pick(makeVPaginationProps({
76+
showFirstLastPage: true,
77+
}), ['showFirstLastPage']),
7378
}, 'VDataTableFooter')
7479

7580
export const VDataTableFooter = genericComponent<{ prepend: never }>()({

packages/vuetify/src/components/VPagination/VPagination.tsx

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import { computed, nextTick, shallowRef, toRef } from 'vue'
2727
import { createRange, genericComponent, keyValues, propsFactory, useRender } from '@/util'
2828

2929
// Types
30-
import type { ComponentPublicInstance } from 'vue'
30+
import type { ComponentPublicInstance, PropType } from 'vue'
3131

3232
type ItemSlot = {
3333
isActive: boolean
@@ -117,7 +117,10 @@ export const makeVPaginationProps = propsFactory({
117117
type: String,
118118
default: '...',
119119
},
120-
showFirstLastPage: Boolean,
120+
showFirstLastPage: {
121+
type: [Boolean, String] as PropType<boolean | 'only-first'>,
122+
default: false,
123+
},
121124

122125
...makeBorderProps(),
123126
...makeComponentProps(),
@@ -278,7 +281,7 @@ export const VPagination = genericComponent<VPaginationSlots>()({
278281
const nextDisabled = !!props.disabled || page.value >= start.value + length.value - 1
279282

280283
return {
281-
first: props.showFirstLastPage ? {
284+
first: [true, 'only-first'].includes(props.showFirstLastPage) ? {
282285
icon: isRtl.value ? props.lastIcon : props.firstIcon,
283286
onClick: (e: Event) => setValue(e, start.value, 'first'),
284287
disabled: prevDisabled,
@@ -299,7 +302,7 @@ export const VPagination = genericComponent<VPaginationSlots>()({
299302
'aria-label': t(props.nextAriaLabel),
300303
'aria-disabled': nextDisabled,
301304
},
302-
last: props.showFirstLastPage ? {
305+
last: props.showFirstLastPage === true ? {
303306
icon: isRtl.value ? props.firstIcon : props.lastIcon,
304307
onClick: (e: Event) => setValue(e, start.value + length.value - 1, 'last'),
305308
disabled: nextDisabled,
@@ -339,7 +342,7 @@ export const VPagination = genericComponent<VPaginationSlots>()({
339342
data-test="v-pagination-root"
340343
>
341344
<ul class="v-pagination__list">
342-
{ props.showFirstLastPage && (
345+
{[true, 'only-first'].includes(props.showFirstLastPage) && (
343346
<li key="first" class="v-pagination__first" data-test="v-pagination-first">
344347
{ slots.first ? slots.first(controls.value.first!) : (
345348
<VBtn _as="VPaginationBtn" { ...controls.value.first } />
@@ -380,12 +383,8 @@ export const VPagination = genericComponent<VPaginationSlots>()({
380383
)}
381384
</li>
382385

383-
{ props.showFirstLastPage && (
384-
<li
385-
key="last"
386-
class="v-pagination__last"
387-
data-test="v-pagination-last"
388-
>
386+
{ props.showFirstLastPage === true && (
387+
<li key="last" class="v-pagination__last" data-test="v-pagination-last">
389388
{ slots.last ? slots.last(controls.value.last!) : (
390389
<VBtn _as="VPaginationBtn" { ...controls.value.last } />
391390
)}

packages/vuetify/src/components/VPagination/__tests__/VPagination.spec.browser.tsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,24 @@ describe('VPagination', () => {
2323
expect(screen.getAllByCSS('.v-pagination__item')).toHaveLength(3)
2424
})
2525

26+
it('should render without first and last page buttons', () => {
27+
render(() => (
28+
<VPagination showFirstLastPage={ false } length="3" />
29+
))
30+
31+
expect(screen.queryByCSS('[data-test="v-pagination-first"]')).not.toBeInTheDocument()
32+
expect(screen.queryByCSS('[data-test="v-pagination-last"]')).not.toBeInTheDocument()
33+
})
34+
35+
it('should render without last page button', () => {
36+
render(() => (
37+
<VPagination showFirstLastPage="only-first" showlength="3" />
38+
))
39+
40+
expect(screen.queryByCSS('[data-test="v-pagination-first"]')).toBeInTheDocument()
41+
expect(screen.queryByCSS('[data-test="v-pagination-last"]')).not.toBeInTheDocument()
42+
})
43+
2644
it('should react to mouse navigation', async () => {
2745
render(() => (
2846
<VPagination length="3" />

0 commit comments

Comments
 (0)