GitHub

@@ -199,7 +199,7 @@ export type CommandPaletteSlots<G extends CommandPaletteGroup<T> = CommandPalett

199199

import { computed, ref, useTemplateRef, toRef } from 'vue'

200200

import { ListboxRoot, ListboxFilter, ListboxContent, ListboxGroup, ListboxGroupLabel, ListboxVirtualizer, ListboxItem, ListboxItemIndicator, useForwardProps, useForwardPropsEmits } from 'reka-ui'

201201

import { defu } from 'defu'

202-

import { reactivePick, createReusableTemplate } from '@vueuse/core'

202+

import { reactivePick, createReusableTemplate, refThrottled } from '@vueuse/core'

203203

import { useFuse } from '@vueuse/integrations/useFuse'

204204

import { useAppConfig } from '#imports'

205205

import { useLocale } from '../composables/useLocale'

@@ -290,14 +290,18 @@ const items = computed(() => groups.value?.filter((group) => {

290290291291

const { 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

}

309313310314

const 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

Read the original on github.com ↗