Skip to content

Commit c0bdb9c

Browse files
feat(VDataTable): add mobile header slot (#21429)
Co-authored-by: J-Sek <J-Sek@users.noreply.github.com> resolves #19730
1 parent cce5485 commit c0bdb9c

3 files changed

Lines changed: 69 additions & 45 deletions

File tree

packages/vuetify/src/components/VDataTable/VDataTable.sass

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,13 @@
135135
display: flex
136136
align-items: center
137137

138+
> .v-data-table-header__select-all
139+
margin-inline: $data-table-header-select-all-margin-inline
140+
flex-grow: 0
141+
142+
&:only-child
143+
margin-inline-start: auto
144+
138145
.v-data-table-header__sort-icon
139146
margin-inline: $data-table-header-sort-icon-margin-inline
140147

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

Lines changed: 61 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ export type VDataTableHeadersSlots = {
5656
loader: LoaderSlotProps
5757
'header.data-table-select': VDataTableHeaderCellColumnSlotProps
5858
'header.data-table-expand': VDataTableHeaderCellColumnSlotProps
59+
'mobile.header': HeadersSlotProps
5960
} & { [key: `header.${string}`]: VDataTableHeaderCellColumnSlotProps }
6061

6162
export const makeVDataTableHeadersProps = propsFactory({
@@ -273,6 +274,60 @@ export const VDataTableHeaders = genericComponent<VDataTableHeadersSlots>()({
273274
},
274275
})
275276

277+
function renderSortSelect () {
278+
return (
279+
<VSelect
280+
v-model={ sortingChips.value }
281+
chips
282+
color={ props.color }
283+
class="v-data-table__td-sort-select"
284+
clearable
285+
density="default"
286+
items={ sortableColumns.value }
287+
label={ t('$vuetify.dataTable.sortBy') }
288+
multiple={ props.multiSort }
289+
variant="underlined"
290+
returnObject
291+
onClick:clear={ () => sortBy.value = [] }
292+
>
293+
{{
294+
chip: ({ internalItem }) => (
295+
<VChip
296+
onClick={ internalItem.raw.sortable ? () => toggleSort(internalItem.raw, undefined, true) : undefined }
297+
onMousedown={ (e: MouseEvent) => {
298+
e.preventDefault()
299+
e.stopPropagation()
300+
}}
301+
>
302+
{ internalItem.title }
303+
<VIcon
304+
class={[
305+
'v-data-table__td-sort-icon',
306+
isSorted(internalItem.raw) && 'v-data-table__td-sort-icon-active',
307+
]}
308+
icon={ getSortIcon(internalItem.raw) }
309+
size="small"
310+
/>
311+
</VChip>
312+
),
313+
}}
314+
</VSelect>
315+
)
316+
}
317+
318+
function renderSelectAll () {
319+
return (
320+
<VCheckboxBtn
321+
class="v-data-table-header__select-all"
322+
color={ props.color }
323+
density="compact"
324+
modelValue={ allSelected.value }
325+
indeterminate={ someSelected.value && !allSelected.value }
326+
onUpdate:modelValue={ () => selectAll(!allSelected.value) }
327+
/>
328+
)
329+
}
330+
276331
return (
277332
<VDataTableColumn
278333
tag="th"
@@ -283,51 +338,12 @@ export const VDataTableHeaders = genericComponent<VDataTableHeadersSlots>()({
283338
{ ...props.headerProps }
284339
>
285340
<div class="v-data-table-header__content">
286-
<VSelect
287-
v-model={ sortingChips.value }
288-
chips
289-
color={ props.color }
290-
class="v-data-table__td-sort-select"
291-
clearable
292-
density="default"
293-
items={ sortableColumns.value }
294-
label={ t('$vuetify.dataTable.sortBy') }
295-
multiple={ props.multiSort }
296-
variant="underlined"
297-
returnObject
298-
onClick:clear={ () => sortBy.value = [] }
299-
>
300-
{{
301-
append: showSelectColumn ? () => (
302-
<VCheckboxBtn
303-
color={ props.color }
304-
density="compact"
305-
modelValue={ allSelected.value }
306-
indeterminate={ someSelected.value && !allSelected.value }
307-
onUpdate:modelValue={ () => selectAll(!allSelected.value) }
308-
/>
309-
) : undefined,
310-
chip: ({ internalItem }) => (
311-
<VChip
312-
onClick={ internalItem.raw.sortable ? () => toggleSort(internalItem.raw, undefined, true) : undefined }
313-
onMousedown={ (e: MouseEvent) => {
314-
e.preventDefault()
315-
e.stopPropagation()
316-
}}
317-
>
318-
{ internalItem.title }
319-
<VIcon
320-
class={[
321-
'v-data-table__td-sort-icon',
322-
isSorted(internalItem.raw) && 'v-data-table__td-sort-icon-active',
323-
]}
324-
icon={ getSortIcon(internalItem.raw) }
325-
size="small"
326-
/>
327-
</VChip>
328-
),
329-
}}
330-
</VSelect>
341+
{ slots['mobile.header']?.(slotProps.value) ?? (
342+
<>
343+
{ sortableColumns.value.length > 0 && renderSortSelect() }
344+
{ showSelectColumn && renderSelectAll() }
345+
</>
346+
)}
331347
</div>
332348
</VDataTableColumn>
333349
)

packages/vuetify/src/components/VDataTable/_variables.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ $data-table-header-sort-badge-color: rgba(var(--v-border-color), var(--v-border-
66
$data-table-header-sort-icon-default-opacity: .0 !default;
77
$data-table-header-sort-icon-hover-opacity: .5 !default;
88
$data-table-header-sort-icon-margin-inline: 0px !default;
9+
$data-table-header-select-all-margin-inline: 16px -4px !default;
910

1011
$data-table-loading-opacity: var(--v-disabled-opacity) !default;
1112

0 commit comments

Comments
 (0)