Skip to content

Commit 455e492

Browse files
committed
fix: sort autocomplete list alphabetically with prefix matches first
- Add sortKey prop to useFilteredList for alphabetical sorting - Prefix matches are prioritized and sorted alphabetically - Non-prefix matches follow, also sorted alphabetically - Apply sortKey to slash command autocomplete in prompt-input
1 parent bded900 commit 455e492

File tree

2 files changed

+21
-2
lines changed

2 files changed

+21
-2
lines changed

packages/app/src/components/prompt-input.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
460460
key: (x) => x?.id,
461461
filterKeys: ["trigger", "title", "description"],
462462
onSelect: handleSlashSelect,
463+
sortKey: "trigger",
463464
})
464465

465466
const createPill = (part: FileAttachmentPart | AgentPart) => {

packages/ui/src/hooks/use-filtered-list.tsx

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export interface FilteredListProps<T> {
1313
sortBy?: (a: T, b: T) => number
1414
sortGroupsBy?: (a: { category: string; items: T[] }, b: { category: string; items: T[] }) => number
1515
onSelect?: (value: T | undefined, index: number) => void
16+
sortKey?: keyof T
1617
}
1718

1819
export function useFilteredList<T>(props: FilteredListProps<T>) {
@@ -33,10 +34,27 @@ export function useFilteredList<T>(props: FilteredListProps<T>) {
3334
all,
3435
(x) => {
3536
if (!needle) return x
37+
let filtered: T[]
3638
if (!props.filterKeys && Array.isArray(x) && x.every((e) => typeof e === "string")) {
37-
return fuzzysort.go(needle, x).map((x) => x.target) as T[]
39+
filtered = fuzzysort.go(needle, x).map((x) => x.target) as T[]
40+
} else {
41+
filtered = fuzzysort.go(needle, x, { keys: props.filterKeys! }).map((x) => x.obj)
3842
}
39-
return fuzzysort.go(needle, x, { keys: props.filterKeys! }).map((x) => x.obj)
43+
// Sort with prefix matches first, then alphabetically within each group
44+
if (props.sortKey) {
45+
const key = props.sortKey
46+
const lowerNeedle = needle.toLowerCase()
47+
filtered.sort((a, b) => {
48+
const aVal = String(a[key]).toLowerCase()
49+
const bVal = String(b[key]).toLowerCase()
50+
const aPrefix = aVal.startsWith(lowerNeedle)
51+
const bPrefix = bVal.startsWith(lowerNeedle)
52+
if (aPrefix && !bPrefix) return -1
53+
if (!aPrefix && bPrefix) return 1
54+
return aVal.localeCompare(bVal)
55+
})
56+
}
57+
return filtered
4058
},
4159
groupBy((x) => (props.groupBy ? props.groupBy(x) : "")),
4260
entries(),

0 commit comments

Comments
 (0)