Skip to content

Commit 1f64f3c

Browse files
authored
feat(VDataTable): loading prop to accept object with side (#22872)
resolves #9655
1 parent 7923f7b commit 1f64f3c

6 files changed

Lines changed: 62 additions & 6 deletions

File tree

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
"item.data-table-select": "Slot to replace the default `v-checkbox-btn` used when selecting rows.",
4040
"item.data-table-expand": "Slot to replace the default `v-icon` used when expanding rows.",
4141
"item.<name>": "Slot to customize a specific column.",
42+
"loader": "Slot to replace the default `v-progress-linear` shown when `loading` is set.",
4243
"loading": "Defines content for when `loading` is true and no items are provided.",
4344
"tbody": "Slot to replace the default table `<tbody>`.",
4445
"thead": "Slot to replace the default table `<thead>`.",

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { makeDataTableExpandProps, provideExpanded } from './composables/expand'
1313
import { createGroupBy, makeDataTableGroupProps, provideGroupBy, useGroupedItems, useOpenAllGroups } from './composables/group'
1414
import { createHeaders, makeDataTableHeaderProps } from './composables/headers'
1515
import { makeDataTableItemsProps, useDataTableItems } from './composables/items'
16+
import { useLoadingConfig } from './composables/loading'
1617
import { useOptions } from './composables/options'
1718
import {
1819
createPagination,
@@ -25,6 +26,7 @@ import { makeDataTableSelectProps, provideSelection } from './composables/select
2526
import { createSort, makeDataTableSortProps, provideSort, useSortedItems } from './composables/sort'
2627
import { provideDefaults } from '@/composables/defaults'
2728
import { makeFilterProps, useFilter } from '@/composables/filter'
29+
import { LoaderSlot } from '@/composables/loader'
2830

2931
// Utilities
3032
import { computed, toRef, toRefs, toValue } from 'vue'
@@ -220,6 +222,8 @@ export const VDataTable = genericComponent<new <T extends readonly any[], V>(
220222

221223
const { isExpanded, toggleExpand } = provideExpanded(props)
222224

225+
const loadingConfig = useLoadingConfig(() => props.loading, () => props.color)
226+
223227
useOptions({
224228
page,
225229
itemsPerPage,
@@ -313,6 +317,20 @@ export const VDataTable = genericComponent<new <T extends readonly any[], V>(
313317
/>
314318
)}
315319
{ slots['body.append']?.(slotProps.value) }
320+
{ loadingConfig.active.value && ['end', 'both'].includes(loadingConfig.side.value) && (
321+
<tr class="v-data-table-progress v-data-table-progress--bottom">
322+
<th colspan={ columns.value.length }>
323+
<LoaderSlot
324+
name="v-data-table-progress"
325+
absolute
326+
active
327+
color={ loadingConfig.color.value }
328+
indeterminate
329+
v-slots={{ default: slots.loader }}
330+
/>
331+
</th>
332+
</tr>
333+
)}
316334
</tbody>
317335
)}
318336
{ slots.tbody?.(slotProps.value) }

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { VSelect } from '@/components/VSelect'
77

88
// Composables
99
import { useHeaders } from './composables/headers'
10+
import { useLoadingConfig } from './composables/loading'
1011
import { useSelection } from './composables/select'
1112
import { useSort } from './composables/sort'
1213
import { useBackgroundColor } from '@/composables/color'
@@ -139,6 +140,8 @@ export const VDataTableHeaders = genericComponent<VDataTableHeadersSlots>()({
139140

140141
const { displayClasses, mobile } = useDisplay(props)
141142

143+
const loadingConfig = useLoadingConfig(() => props.loading, () => props.color)
144+
142145
const slotProps = computed(() => ({
143146
headers: headers.value,
144147
columns: columns.value,
@@ -366,16 +369,14 @@ export const VDataTableHeaders = genericComponent<VDataTableHeadersSlots>()({
366369
</tr>
367370
))}
368371

369-
{ props.loading && (
372+
{ loadingConfig.active.value && ['start', 'both'].includes(loadingConfig.side.value) && (
370373
<tr class="v-data-table-progress">
371374
<th colspan={ columns.value.length }>
372375
<LoaderSlot
373376
name="v-data-table-progress"
374377
absolute
375378
active
376-
color={ typeof props.loading === 'boolean' || props.loading === 'true'
377-
? props.color
378-
: props.loading }
379+
color={ loadingConfig.color.value }
379380
indeterminate
380381
v-slots={{ default: slots.loader }}
381382
/>

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import { genericComponent, getPrefixedEventHandlers, pick, propsFactory, useRend
1919
// Types
2020
import type { Component, PropType, TransitionProps } from 'vue'
2121
import type { Group, GroupSummary } from './composables/group'
22-
import type { CellProps, DataTableItem, GroupHeaderSlot, GroupSummarySlot, ItemSlot, RowProps } from './types'
22+
import type { CellProps, DataTableItem, DataTableLoading, GroupHeaderSlot, GroupSummarySlot, ItemSlot, RowProps } from './types'
2323
import type { VDataTableGroupHeaderRowSlots } from './VDataTableGroupHeaderRow'
2424
import type { VDataTableRowSlots } from './VDataTableRow'
2525
import type { GenericProps } from '@/util'
@@ -36,7 +36,7 @@ export type VDataTableRowsSlots<T> = VDataTableGroupHeaderRowSlots & VDataTableR
3636

3737
export const makeVDataTableRowsProps = propsFactory({
3838
color: String,
39-
loading: [Boolean, String],
39+
loading: [Boolean, String, Object] as PropType<DataTableLoading>,
4040
loadingText: {
4141
type: String,
4242
default: '$vuetify.dataIterator.loadingText',
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Utilities
2+
import { computed } from 'vue'
3+
4+
// Types
5+
import type { DataTableLoading, DataTableLoadingSide } from '../types'
6+
7+
export function useLoadingConfig (
8+
loading: () => DataTableLoading | undefined,
9+
fallbackColor: () => string | undefined,
10+
) {
11+
const active = computed(() => {
12+
const v = loading()
13+
return v != null && v !== false && v !== 'false'
14+
})
15+
16+
const side = computed<DataTableLoadingSide>(() => {
17+
const v = loading()
18+
if (typeof v === 'object' && v !== null && v.side) return v.side
19+
return 'start'
20+
})
21+
22+
const color = computed(() => {
23+
const v = loading()
24+
if (typeof v === 'object' && v !== null && v.color) return v.color
25+
if (typeof v === 'string' && v !== 'true') return v
26+
return fallbackColor()
27+
})
28+
29+
return { active, side, color }
30+
}

packages/vuetify/src/components/VDataTable/types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ import type { SelectItemKey } from '@/util'
77

88
export type DataTableCompareFunction<T = any> = (a: T, b: T) => number | null
99

10+
export type DataTableLoadingSide = 'start' | 'end' | 'both'
11+
export type DataTableLoading =
12+
| boolean
13+
| string
14+
| { side?: DataTableLoadingSide, color?: string }
15+
1016
export type DataTableHeader<T = Record<string, any>> = {
1117
key?: 'data-table-group' | 'data-table-select' | 'data-table-expand' | (string & {})
1218
value?: SelectItemKey<T>

0 commit comments

Comments
 (0)