Skip to content

Commit b0b209e

Browse files
fix(Table): only forward necessary props (#5527)
1 parent 70317e5 commit b0b209e

File tree

6 files changed

+295
-375
lines changed

6 files changed

+295
-375
lines changed

docs/app/components/content/examples/table/TablePaginationExample.vue

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,13 +147,24 @@ const pagination = ref({
147147
pageIndex: 0,
148148
pageSize: 5
149149
})
150+
151+
const globalFilter = ref('')
150152
</script>
151153

152154
<template>
153155
<div class="w-full space-y-4 pb-4">
156+
<div class="flex px-4 py-3.5 border-b border-accented">
157+
<UInput
158+
v-model="globalFilter"
159+
class="max-w-sm"
160+
placeholder="Filter..."
161+
/>
162+
</div>
163+
154164
<UTable
155165
ref="table"
156166
v-model:pagination="pagination"
167+
v-model:global-filter="globalFilter"
157168
:data="data"
158169
:columns="columns"
159170
:pagination-options="{
@@ -162,9 +173,9 @@ const pagination = ref({
162173
class="flex-1"
163174
/>
164175

165-
<div class="flex justify-center border-t border-default pt-4">
176+
<div class="flex justify-end border-t border-default pt-4 px-4">
166177
<UPagination
167-
:default-page="(table?.tableApi?.getState().pagination.pageIndex || 0) + 1"
178+
:page="(table?.tableApi?.getState().pagination.pageIndex || 0) + 1"
168179
:items-per-page="table?.tableApi?.getState().pagination.pageSize"
169180
:total="table?.tableApi?.getFilteredRowModel().rows.length"
170181
@update:page="(p) => table?.tableApi?.setPageIndex(p - 1)"

playgrounds/nuxt/app/pages/components/table.vue

Lines changed: 77 additions & 172 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import { h, resolveComponent } from 'vue'
33
import { upperFirst } from 'scule'
44
import type { TableColumn, TableRow } from '@nuxt/ui'
5+
import type { Column } from '@tanstack/vue-table'
56
import { getPaginationRowModel } from '@tanstack/vue-table'
67
import { useClipboard, refDebounced } from '@vueuse/core'
78
@@ -17,6 +18,8 @@ type Payment = {
1718
id: string
1819
date: string
1920
status: 'paid' | 'failed' | 'refunded'
21+
firstName: string
22+
lastName: string
2023
email: string
2124
amount: number
2225
}
@@ -25,137 +28,28 @@ const table = useTemplateRef('table')
2528
2629
const virtualize = ref(false)
2730
28-
const data = ref<Payment[]>([{
29-
id: '4600',
30-
date: '2024-03-11T15:30:00',
31-
status: 'paid',
32-
33-
amount: 594
34-
}, {
35-
id: '4599',
36-
date: '2024-03-11T10:10:00',
37-
status: 'failed',
38-
39-
amount: 276
40-
}, {
41-
id: '4598',
42-
date: '2024-03-11T08:50:00',
43-
status: 'refunded',
44-
45-
amount: 315
46-
}, {
47-
id: '4597',
48-
date: '2024-03-10T19:45:00',
49-
status: 'paid',
50-
51-
amount: 529
52-
}, {
53-
id: '4596',
54-
date: '2024-03-10T15:55:00',
55-
status: 'paid',
56-
57-
amount: 639
58-
}, {
59-
id: '4595',
60-
date: '2024-03-10T13:40:00',
61-
status: 'refunded',
62-
63-
amount: 428
64-
}, {
65-
id: '4594',
66-
date: '2024-03-10T09:15:00',
67-
status: 'paid',
68-
69-
amount: 683
70-
}, {
71-
id: '4593',
72-
date: '2024-03-09T20:25:00',
73-
status: 'failed',
74-
75-
amount: 947
76-
}, {
77-
id: '4592',
78-
date: '2024-03-09T18:45:00',
79-
status: 'paid',
80-
81-
amount: 851
82-
}, {
83-
id: '4591',
84-
date: '2024-03-09T16:05:00',
85-
status: 'paid',
86-
87-
amount: 762
88-
}, {
89-
id: '4590',
90-
date: '2024-03-09T14:20:00',
91-
status: 'paid',
92-
93-
amount: 573
94-
}, {
95-
id: '4589',
96-
date: '2024-03-09T11:35:00',
97-
status: 'failed',
98-
99-
amount: 389
100-
}, {
101-
id: '4588',
102-
date: '2024-03-08T22:50:00',
103-
status: 'refunded',
104-
105-
amount: 701
106-
}, {
107-
id: '4587',
108-
date: '2024-03-08T20:15:00',
109-
status: 'paid',
110-
111-
amount: 856
112-
}, {
113-
id: '4586',
114-
date: '2024-03-08T17:40:00',
115-
status: 'paid',
116-
117-
amount: 492
118-
}, {
119-
id: '4585',
120-
date: '2024-03-08T14:55:00',
121-
status: 'failed',
122-
123-
amount: 637
124-
}, {
125-
id: '4584',
126-
date: '2024-03-08T12:30:00',
127-
status: 'paid',
128-
129-
amount: 784
130-
}, {
131-
id: '4583',
132-
date: '2024-03-08T09:45:00',
133-
status: 'refunded',
134-
135-
amount: 345
136-
}, {
137-
id: '4582',
138-
date: '2024-03-07T23:10:00',
139-
status: 'paid',
140-
141-
amount: 918
142-
}, {
143-
id: '4581',
144-
date: '2024-03-07T20:25:00',
145-
status: 'paid',
146-
147-
amount: 567
148-
}])
149-
150-
const largeData = useState<Payment[]>('largeData', () => Array.from({ length: 1000 }, (_, i) => ({
151-
id: `4580-${i}`,
152-
date: new Date().toISOString(),
153-
status: 'paid',
154-
email: `email-${i}@example.com`,
155-
amount: Math.random() * 1000
156-
})))
157-
158-
const currentID = ref(4601)
31+
const statuses: Payment['status'][] = ['paid', 'failed', 'refunded']
32+
const domains = ['gmail.com', 'outlook.com', 'yahoo.com', 'company.com', 'mail.com']
33+
const firstNames = ['john', 'jane', 'alex', 'sarah', 'mike', 'emma', 'david', 'lisa', 'chris', 'anna']
34+
const lastNames = ['smith', 'johnson', 'williams', 'brown', 'jones', 'garcia', 'miller', 'davis', 'rodriguez', 'martinez']
35+
36+
function makeData(id: number | string, index?: number): Payment {
37+
const i = index ?? Number(id)
38+
const firstName = firstNames[i % firstNames.length]!
39+
const lastName = lastNames[i % lastNames.length]!
40+
41+
return {
42+
id: id.toString(),
43+
date: index !== undefined ? new Date(Date.now() - index * 3600000 * 2).toISOString() : new Date().toISOString(),
44+
firstName,
45+
lastName,
46+
status: statuses[i % statuses.length]!,
47+
email: `${firstName}.${lastName}${i > 100 ? Math.floor(i / 10) : ''}@${domains[i % domains.length]}`,
48+
amount: Math.floor(Math.random() * 900) + 100
49+
}
50+
}
51+
52+
const data = useState<Payment[]>('data', () => Array.from({ length: 1000 }, (_, i) => makeData(45800 - i, i)))
15953
16054
function getRowItems(row: TableRow<Payment>) {
16155
return [{
@@ -199,11 +93,13 @@ const columns: TableColumn<Payment>[] = [{
19993
'aria-label': 'Select row'
20094
}),
20195
enableSorting: false,
202-
enableHiding: false
96+
enableHiding: false,
97+
size: 32
20398
}, {
20499
accessorKey: 'id',
205-
header: '#',
206-
cell: ({ row }) => `#${row.getValue('id')}`
100+
header: ({ column }) => getPinnedHeader(column, '#', 'left'),
101+
cell: ({ row }) => `#${row.getValue('id')}`,
102+
size: 84
207103
}, {
208104
accessorKey: 'date',
209105
header: 'Date',
@@ -224,7 +120,7 @@ const columns: TableColumn<Payment>[] = [{
224120
}
225121
}, {
226122
accessorKey: 'status',
227-
header: 'Status',
123+
header: ({ column }) => getPinnedHeader(column, 'Status', 'left'),
228124
cell: ({ row }) => {
229125
const color = ({
230126
paid: 'success' as const,
@@ -233,7 +129,18 @@ const columns: TableColumn<Payment>[] = [{
233129
})[row.getValue('status') as string]
234130
235131
return h(UBadge, { class: 'capitalize', variant: 'subtle', color }, () => row.getValue('status'))
236-
}
132+
},
133+
size: 102
134+
}, {
135+
accessorKey: 'firstName',
136+
header: ({ column }) => getPinnedHeader(column, 'First Name', 'left'),
137+
cell: ({ row }) => h('div', { class: 'capitalize' }, row.getValue('firstName')),
138+
size: 128
139+
}, {
140+
accessorKey: 'lastName',
141+
header: ({ column }) => getPinnedHeader(column, 'Last Name', 'left'),
142+
cell: ({ row }) => h('div', { class: 'capitalize' }, row.getValue('lastName')),
143+
size: 128
237144
}, {
238145
accessorKey: 'email',
239146
header: ({ column }) => {
@@ -251,7 +158,7 @@ const columns: TableColumn<Payment>[] = [{
251158
cell: ({ row }) => h('div', { class: 'lowercase' }, row.getValue('email'))
252159
}, {
253160
accessorKey: 'amount',
254-
header: () => h('div', { class: 'text-right' }, 'Amount'),
161+
header: ({ column }) => h('div', { class: 'text-right' }, getPinnedHeader(column, 'Amount', 'right')),
255162
footer: ({ column }) => {
256163
const total = column.getFacetedRowModel().rows.reduce((acc: number, row: TableRow<Payment>) => acc + Number.parseFloat(row.getValue('amount')), 0)
257164
@@ -271,7 +178,8 @@ const columns: TableColumn<Payment>[] = [{
271178
}).format(amount)
272179
273180
return h('div', { class: 'text-right font-medium' }, formatted)
274-
}
181+
},
182+
size: 117
275183
}, {
276184
id: 'actions',
277185
enableHiding: false,
@@ -289,33 +197,43 @@ const columns: TableColumn<Payment>[] = [{
289197
'class': 'ms-auto',
290198
'aria-label': 'Actions dropdown'
291199
})))
292-
}
200+
},
201+
size: 64
293202
}]
294203
204+
function getPinnedHeader(column: Column<Payment>, label: string, position: 'left' | 'right') {
205+
const isPinned = column.getIsPinned()
206+
207+
return h(UButton, {
208+
color: 'neutral',
209+
variant: 'ghost',
210+
label,
211+
icon: isPinned ? 'i-lucide-pin-off' : 'i-lucide-pin',
212+
class: '-mx-2.5',
213+
onClick() {
214+
column.pin(isPinned === position ? false : position)
215+
}
216+
})
217+
}
218+
295219
const loading = ref(true)
296220
const columnPinning = ref({
297-
left: ['id'],
221+
left: ['select'],
298222
right: ['actions']
299223
})
300224
301225
const pagination = ref({
302226
pageIndex: 0,
303-
pageSize: 10
227+
pageSize: 50
304228
})
305229
306230
function addElement() {
307-
(virtualize.value ? largeData.value : data.value).unshift({
308-
id: currentID.value.toString(),
309-
date: new Date().toISOString(),
310-
status: 'paid',
311-
312-
amount: Math.random() * 1000
313-
})
314-
currentID.value++
231+
const maxId = Math.max(...data.value.map(item => Number(item.id)))
232+
data.value.unshift(makeData(maxId + 1))
315233
}
316234
317235
function randomize() {
318-
(virtualize.value ? largeData : data).value = (virtualize.value ? largeData : data).value.sort(() => Math.random() - 0.5)
236+
data.value.sort(() => Math.random() - 0.5)
319237
}
320238
321239
const rowSelection = ref<Record<string, boolean>>({})
@@ -405,21 +323,17 @@ onMounted(() => {
405323
<UTable
406324
ref="table"
407325
:key="String(virtualize)"
326+
:data="data"
408327
:columns="columns"
409328
:column-pinning="columnPinning"
410329
:row-selection="rowSelection"
411330
:loading="loading"
412331
:virtualize="virtualize"
413-
v-bind="virtualize ? {
414-
data: largeData
415-
} : {
332+
v-bind="virtualize ? {} : {
416333
data,
417334
pagination,
418335
paginationOptions: {
419336
getPaginationRowModel: getPaginationRowModel()
420-
},
421-
ui: {
422-
tr: 'divide-x divide-default'
423337
}
424338
}"
425339
sticky
@@ -453,22 +367,13 @@ onMounted(() => {
453367
</div>
454368

455369
<div class="flex items-center gap-1.5">
456-
<UButton
457-
color="neutral"
458-
variant="outline"
459-
:disabled="!table?.tableApi?.getCanPreviousPage()"
460-
@click="table?.tableApi?.previousPage()"
461-
>
462-
Prev
463-
</UButton>
464-
<UButton
465-
color="neutral"
466-
variant="outline"
467-
:disabled="!table?.tableApi?.getCanNextPage()"
468-
@click="table?.tableApi?.nextPage()"
469-
>
470-
Next
471-
</UButton>
370+
<UPagination
371+
:disabled="!!virtualize"
372+
:page="(table?.tableApi?.getState().pagination.pageIndex ?? 0) + 1"
373+
:items-per-page="table?.tableApi?.getState().pagination.pageSize ?? 10"
374+
:total="table?.tableApi?.getFilteredRowModel().rows.length || 0"
375+
@update:page="(p: number) => table?.tableApi?.setPageIndex(p - 1)"
376+
/>
472377
</div>
473378
</div>
474379
</div>

0 commit comments

Comments
 (0)