feat: example of dataTableFacetedFilters virtualization
This commit is contained in:
parent
1f1e6f339f
commit
a1fcbf8ea9
|
|
@ -2,7 +2,8 @@
|
|||
import type { Column } from '@tanstack/vue-table'
|
||||
import type { Component } from 'vue'
|
||||
import { computed } from 'vue'
|
||||
import { type Task } from '../data/schema'
|
||||
import { useVirtualList } from '@vueuse/core'
|
||||
import type { Task } from '../data/schema'
|
||||
import PlusCircledIcon from '~icons/radix-icons/plus-circled'
|
||||
import CheckIcon from '~icons/radix-icons/check'
|
||||
|
||||
|
|
@ -30,8 +31,16 @@ interface DataTableFacetedFilter {
|
|||
|
||||
const props = defineProps<DataTableFacetedFilter>()
|
||||
|
||||
function repeat<T>(array: T[], times: number) {
|
||||
return Array.from({ length: times }, () => array).flat()
|
||||
}
|
||||
const facets = computed(() => props.column?.getFacetedUniqueValues())
|
||||
const selectedValues = computed(() => new Set(props.column?.getFilterValue() as string[]))
|
||||
const options = computed(() => repeat(props.options, 100))
|
||||
|
||||
const { list, containerProps, wrapperProps } = useVirtualList(options, {
|
||||
itemHeight: 32,
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
@ -73,24 +82,27 @@ const selectedValues = computed(() => new Set(props.column?.getFilterValue() as
|
|||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent class="w-[200px] p-0" align="start">
|
||||
<Command
|
||||
:filter-function="(list: DataTableFacetedFilter['options'], term) => list.filter(i => i.label.toLowerCase()?.includes(term)) "
|
||||
>
|
||||
<Command>
|
||||
<CommandInput :placeholder="title" />
|
||||
<CommandList>
|
||||
<CommandEmpty>No results found.</CommandEmpty>
|
||||
<CommandEmpty>
|
||||
No results found.
|
||||
</CommandEmpty>
|
||||
<div v-bind="containerProps" class="max-h-52">
|
||||
<div v-bind="wrapperProps">
|
||||
<CommandGroup>
|
||||
<CommandItem
|
||||
v-for="option in options"
|
||||
:key="option.value"
|
||||
:value="option"
|
||||
v-for="option in list"
|
||||
:key="option.index"
|
||||
style="height: 32px"
|
||||
:value="option.data"
|
||||
@select="() => {
|
||||
const isSelected = selectedValues.has(option.value)
|
||||
const isSelected = selectedValues.has(option.data.value)
|
||||
if (isSelected) {
|
||||
selectedValues.delete(option.value)
|
||||
selectedValues.delete(option.data.value)
|
||||
}
|
||||
else {
|
||||
selectedValues.add(option.value)
|
||||
selectedValues.add(option.data.value)
|
||||
}
|
||||
const filterValues = Array.from(selectedValues)
|
||||
column?.setFilterValue(
|
||||
|
|
@ -101,20 +113,22 @@ const selectedValues = computed(() => new Set(props.column?.getFilterValue() as
|
|||
<div
|
||||
:class="cn(
|
||||
'mr-2 flex h-4 w-4 items-center justify-center rounded-sm border border-primary',
|
||||
selectedValues.has(option.value)
|
||||
selectedValues.has(option.data.value)
|
||||
? 'bg-primary text-primary-foreground'
|
||||
: 'opacity-50 [&_svg]:invisible',
|
||||
)"
|
||||
>
|
||||
<CheckIcon :class="cn('h-4 w-4')" />
|
||||
</div>
|
||||
<component :is="option.icon" v-if="option.icon" class="mr-2 h-4 w-4 text-muted-foreground" />
|
||||
<span>{{ option.label }}</span>
|
||||
<span v-if="facets?.get(option.value)" class="ml-auto flex h-4 w-4 items-center justify-center font-mono text-xs">
|
||||
{{ facets.get(option.value) }}
|
||||
<component :is="option.data.icon" v-if="option.data.icon" class="mr-2 h-4 w-4 text-muted-foreground" />
|
||||
<span>{{ option.data.label }}</span>
|
||||
<span v-if="facets?.get(option.data.value)" class="ml-auto flex h-4 w-4 items-center justify-center font-mono text-xs">
|
||||
{{ facets.get(option.data.value) }}
|
||||
</span>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template v-if="selectedValues.size > 0">
|
||||
<CommandSeparator />
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<script setup lang="ts">
|
||||
import { type Table } from '@tanstack/vue-table'
|
||||
import type { Table } from '@tanstack/vue-table'
|
||||
import { computed } from 'vue'
|
||||
import { type Task } from '../data/schema'
|
||||
import type { Task } from '../data/schema'
|
||||
|
||||
import { priorities, statuses } from '../data/data'
|
||||
import DataTableFacetedFilter from './DataTableFacetedFilter.vue'
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user