@@ -199,7 +199,7 @@ export type CommandPaletteSlots<G extends CommandPaletteGroup<T> = CommandPalett
199199import { computed, ref, useTemplateRef, toRef } from 'vue'
200200import { ListboxRoot, ListboxFilter, ListboxContent, ListboxGroup, ListboxGroupLabel, ListboxVirtualizer, ListboxItem, ListboxItemIndicator, useForwardProps, useForwardPropsEmits } from 'reka-ui'
201201import { defu } from 'defu'
202-import { reactivePick, createReusableTemplate } from '@vueuse/core'
202+import { reactivePick, createReusableTemplate, refThrottled } from '@vueuse/core'
203203import { useFuse } from '@vueuse/integrations/useFuse'
204204import { useAppConfig } from '#imports'
205205import { useLocale } from '../composables/useLocale'
@@ -290,14 +290,18 @@ const items = computed(() => groups.value?.filter((group) => {
290290291291const { results: fuseResults } = useFuse<typeof items.value[number]>(searchTerm, items, fuse)
292292293-function getGroupWithItems(group: G, items: (T & { matches?: FuseResult<T>['matches'] })[]) {
293+const throttledFuseResults = refThrottled(fuseResults, 16, true)
294+295+function processGroupItems(group: G, items: (T & { matches?: FuseResult<T>['matches'] })[]) {
296+ let processedItems = items
297+294298 if (group?.postFilter && typeof group.postFilter === 'function') {
295- items = group.postFilter(searchTerm.value, items)
299+ processedItems = group.postFilter(searchTerm.value, processedItems)
296300 }
297301298302 return {
299303 ...group,
300- items: items.slice(0, fuse.value.resultLimit).map((item) => {
304+ items: processedItems.slice(0, fuse.value.resultLimit).map((item) => {
301305 return {
302306 ...item,
303307 labelHtml: highlight<T>(item, searchTerm.value, props.labelKey),
@@ -308,7 +312,9 @@ function getGroupWithItems(group: G, items: (T & { matches?: FuseResult<T>['matc
308312}
309313310314const filteredGroups = computed(() => {
311- const groupsById = fuseResults.value.reduce((acc, result) => {
315+ const currentGroups = groups.value
316+317+ const groupsById = throttledFuseResults.value.reduce((acc, result) => {
312318 const { item, matches } = result
313319 if (!item.group) {
314320 return acc
@@ -321,38 +327,49 @@ const filteredGroups = computed(() => {
321327 }, {} as Record<string, (T & { matches?: FuseResult<T>['matches'] })[]>)
322328323329 if (props.preserveGroupOrder) {
324- const processedGroups: Array<ReturnType<typeof getGroupWithItems>> = []
330+ const processedGroups: Array<ReturnType<typeof processGroupItems>> = []
325331326- for (const group of groups.value || []) {
332+ for (const group of currentGroups || []) {
327333 if (!group.items?.length) {
328334 continue
329335 }
330336331- const items = group.ignoreFilter
332- ? group.items
333- : groupsById[group.id]
337+ const items = group.ignoreFilter ? group.items : groupsById[group.id]
338+ if (!items?.length) {
339+ continue
340+ }
341+342+ const processedGroup = processGroupItems(group, items)
334343335- if (items?.length) {
336- processedGroups.push(getGroupWithItems(group, items))
344+ // Filter out groups that become empty after postFilter
345+ if (processedGroup.items?.length) {
346+ processedGroups.push(processedGroup)
337347 }
338348 }
339349340350 return processedGroups
341351 }
342352343353 const fuseGroups = Object.entries(groupsById).map(([id, items]) => {
344- const group = groups.value?.find(group => group.id === id)
354+ const group = currentGroups?.find(group => group.id === id)
345355 if (!group) {
346356 return
347357 }
348358349- return getGroupWithItems(group, items)
359+ const processedGroup = processGroupItems(group, items)
360+ // Filter out groups without items after postFilter
361+ return processedGroup.items?.length ? processedGroup : undefined
350362 }).filter(group => !!group)
351363352- const nonFuseGroups = groups.value
364+ const nonFuseGroups = currentGroups
353365 ?.map((group, index) => ({ ...group, index }))
354366 ?.filter(group => group.ignoreFilter && group.items?.length)
355- ?.map(group => ({ ...getGroupWithItems(group, group.items || []), index: group.index })) || []
367+ ?.map((group) => {
368+ const processedGroup = processGroupItems(group, group.items || [])
369+ return { ...processedGroup, index: group.index }
370+ })
371+ // Filter out groups without items after postFilter
372+ ?.filter(group => group.items?.length) || []
356373357374 return nonFuseGroups.reduce((acc, group) => {
358375 acc.splice(group.index, 0, group)
@@ -442,9 +459,11 @@ function onSelect(e: Event, item: T) {
442459<slot :name="((item.slot ? `${item.slot}-label` : group?.slot ? `${group.slot}-label` : `item-label`) as keyof CommandPaletteSlots<G, T>)" :item="(item as any)" :index="index" :ui="ui">
443460<span v-if="item.prefix" :class="ui.itemLabelPrefix({ class: [props.ui?.itemLabelPrefix, item.ui?.itemLabelPrefix] })">{{ item.prefix }}</span>
444461445-<span :class="ui.itemLabelBase({ class: [props.ui?.itemLabelBase, item.ui?.itemLabelBase], active: active || item.active })" v-html="item.labelHtml || get(item, props.labelKey as string)" />
462+<span v-if="item.labelHtml" :class="ui.itemLabelBase({ class: [props.ui?.itemLabelBase, item.ui?.itemLabelBase], active: active || item.active })" v-html="item.labelHtml" />
463+<span v-else :class="ui.itemLabelBase({ class: [props.ui?.itemLabelBase, item.ui?.itemLabelBase], active: active || item.active })">{{ get(item, props.labelKey as string) }}</span>
446464447-<span :class="ui.itemLabelSuffix({ class: [props.ui?.itemLabelSuffix, item.ui?.itemLabelSuffix], active: active || item.active })" v-html="item.suffixHtml || item.suffix" />
465+<span v-if="item.suffixHtml" :class="ui.itemLabelSuffix({ class: [props.ui?.itemLabelSuffix, item.ui?.itemLabelSuffix], active: active || item.active })" v-html="item.suffixHtml" />
466+<span v-else-if="item.suffix" :class="ui.itemLabelSuffix({ class: [props.ui?.itemLabelSuffix, item.ui?.itemLabelSuffix], active: active || item.active })">{{ item.suffix }}</span>
448467</slot>
449468</span>
450469