Skip to content

Commit 54affe1

Browse files
committed
fix(VDataTable): improvements for sorting in mobile mode
- use initial sort when selecting new chip(s) - keep chips when toggling (rely on clearable to remove chip) fixes #22288 closes #22426
1 parent 985c39d commit 54affe1

2 files changed

Lines changed: 25 additions & 12 deletions

File tree

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

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ import { LoaderSlot, makeLoaderProps, useLoader } from '@/composables/loader'
1717
import { useLocale } from '@/composables/locale'
1818

1919
// Utilities
20-
import { computed, mergeProps } from 'vue'
21-
import { convertToUnit, genericComponent, propsFactory, useRender } from '@/util'
20+
import { computed, mergeProps, nextTick } from 'vue'
21+
import { convertToUnit, genericComponent, propsFactory, useRender, wrapInArray } from '@/util'
2222

2323
// Types
2424
import type { CSSProperties, PropType, UnwrapRef } from 'vue'
@@ -256,10 +256,21 @@ export const VDataTableHeaders = genericComponent<VDataTableHeadersSlots>()({
256256
}
257257

258258
const VDataTableMobileHeaderCell = () => {
259-
const displayItems = computed<ItemProps['items']>(() => {
259+
const sortableColumns = computed<ItemProps['items']>(() => {
260260
return columns.value.filter(column => column?.sortable && !props.disableSort)
261261
})
262262
const showSelectColumn = columns.value.find(column => column.key === 'data-table-select')
263+
const sortingChips = computed<InternalDataTableHeader | InternalDataTableHeader[] | null>({
264+
get: () => sortableColumns.value.filter(({ key }) => sortBy.value.some(v => v.key === key)),
265+
set: val => {
266+
const sortedColumns = wrapInArray(val)
267+
const activeSortKeys = sortBy.value.map(v => v.key)
268+
const newColumnsToSort = sortedColumns.filter(({ key }) => !activeSortKeys.includes(key!))
269+
newColumnsToSort.forEach(column => toggleSort(column))
270+
// sortBy is proxied model, needs nextTick after toggleSort
271+
nextTick(() => sortBy.value = sortBy.value.filter(({ key }) => sortedColumns.some(c => c.key === key)))
272+
},
273+
})
263274

264275
return (
265276
<VDataTableColumn
@@ -272,15 +283,17 @@ export const VDataTableHeaders = genericComponent<VDataTableHeadersSlots>()({
272283
>
273284
<div class="v-data-table-header__content">
274285
<VSelect
286+
v-model={ sortingChips.value }
275287
chips
276288
color={ props.color }
277289
class="v-data-table__td-sort-select"
278290
clearable
279291
density="default"
280-
items={ displayItems.value }
292+
items={ sortableColumns.value }
281293
label={ t('$vuetify.dataTable.sortBy') }
282294
multiple={ props.multiSort }
283295
variant="underlined"
296+
returnObject
284297
onClick:clear={ () => sortBy.value = [] }
285298
>
286299
{{
@@ -293,21 +306,21 @@ export const VDataTableHeaders = genericComponent<VDataTableHeadersSlots>()({
293306
onUpdate:modelValue={ () => selectAll(!allSelected.value) }
294307
/>
295308
) : undefined,
296-
chip: props => (
309+
chip: ({ internalItem }) => (
297310
<VChip
298-
onClick={ props.item.raw?.sortable ? () => toggleSort(props.item.raw) : undefined }
311+
onClick={ internalItem.raw.sortable ? () => toggleSort(internalItem.raw, undefined, true) : undefined }
299312
onMousedown={ (e: MouseEvent) => {
300313
e.preventDefault()
301314
e.stopPropagation()
302315
}}
303316
>
304-
{ props.item.title }
317+
{ internalItem.title }
305318
<VIcon
306319
class={[
307320
'v-data-table__td-sort-icon',
308-
isSorted(props.item.raw) && 'v-data-table__td-sort-icon-active',
321+
isSorted(internalItem.raw) && 'v-data-table__td-sort-icon-active',
309322
]}
310-
icon={ getSortIcon(props.item.raw) }
323+
icon={ getSortIcon(internalItem.raw) }
311324
size="small"
312325
/>
313326
</VChip>

packages/vuetify/src/components/VDataTable/composables/sort.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export const makeDataTableSortProps = propsFactory({
3131

3232
const VDataTableSortSymbol: InjectionKey<{
3333
sortBy: Ref<readonly SortItem[]>
34-
toggleSort: (column: InternalDataTableHeader, event?: KeyboardEvent | PointerEvent) => void
34+
toggleSort: (column: InternalDataTableHeader, event?: KeyboardEvent | PointerEvent, mandatory?: boolean) => void
3535
isSorted: (column: InternalDataTableHeader) => boolean
3636
}> = Symbol.for('vuetify:data-table-sort')
3737

@@ -90,7 +90,7 @@ export function provideSort (options: {
9090
}) {
9191
const { initialSortOrder, sortBy, mustSort, multiSort, page } = options
9292

93-
const toggleSort = (column: InternalDataTableHeader, event?: KeyboardEvent | PointerEvent) => {
93+
const toggleSort = (column: InternalDataTableHeader, event?: KeyboardEvent | PointerEvent, mandatory = false) => {
9494
if (column.key == null) return
9595

9696
let newSortBy = sortBy.value.map(x => ({ ...x })) ?? []
@@ -110,7 +110,7 @@ export function provideSort (options: {
110110
newSortBy = [{ key: column.key, order: initialOrder }]
111111
}
112112
} else if (item.order === secondaryOrder) {
113-
if (mustSort.value && newSortBy.length === 1) {
113+
if (mandatory || (mustSort.value && newSortBy.length === 1)) {
114114
item.order = initialSortOrder.value
115115
} else {
116116
newSortBy = newSortBy.filter(x => x.key !== column.key)

0 commit comments

Comments
 (0)