Skip to content

Commit b990011

Browse files
committed
feat: implement virtualized scrolling for search icons
1 parent 25527e7 commit b990011

1 file changed

Lines changed: 35 additions & 10 deletions

File tree

src/components/search-icons.tsx

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,59 @@
11
'use client'
22

3-
import { useState } from 'react'
3+
import { useRef, useState } from 'react'
4+
import { useVirtualizer } from '@tanstack/react-virtual'
45

56
import { Input } from '@/components/ui/input'
6-
import { ScrollArea } from '@/components/ui/scroll-area'
77
import { AddIconButton } from '@/components/add-icon-button'
88
import { icons } from '@/assets/icons'
99

1010
function SearchIcons() {
11+
const parentRef = useRef<HTMLDivElement>(null)
1112
const [searchValue, setSearchValue] = useState('')
1213

14+
const handleSearch = (event: React.ChangeEvent<HTMLInputElement>) => {
15+
setSearchValue(event.target.value.toLowerCase())
16+
}
17+
1318
const filteredIcons = Object.entries(icons).filter((icon) =>
1419
icon[1].title.toLowerCase().includes(searchValue),
1520
)
1621

17-
const handleSearch = (event: React.ChangeEvent<HTMLInputElement>) => {
18-
setSearchValue(event.target.value.toLowerCase())
19-
}
22+
const rowVirtualizer = useVirtualizer({
23+
count: filteredIcons.length,
24+
getScrollElement: () => parentRef.current,
25+
estimateSize: () => 66,
26+
gap: 16,
27+
})
2028

2129
return (
2230
<>
2331
<h2 className="text-xl font-bold">Search</h2>
2432
<Input placeholder="Search Icons" onChange={handleSearch} />
25-
<ScrollArea className="max-h-[calc(100dvh-512px)] min-h-96">
26-
<div className="flex flex-col gap-4 px-4">
27-
{filteredIcons.map((icon, index) => (
28-
<AddIconButton key={`icon-${index}`} icon={icon[1]} />
33+
<div
34+
className="max-h-[calc(100dvh-512px)] min-h-96 overflow-auto"
35+
ref={parentRef}
36+
>
37+
<div
38+
className="relative w-full"
39+
style={{
40+
height: `${rowVirtualizer.getTotalSize()}px`,
41+
}}
42+
>
43+
{rowVirtualizer.getVirtualItems().map((virtualRow) => (
44+
<div
45+
key={virtualRow.key}
46+
className="absolute left-0 top-0 w-full"
47+
style={{
48+
height: `${virtualRow.size}px`,
49+
transform: `translateY(${virtualRow.start}px)`,
50+
}}
51+
>
52+
<AddIconButton icon={filteredIcons[virtualRow.index][1]} />
53+
</div>
2954
))}
3055
</div>
31-
</ScrollArea>
56+
</div>
3257
</>
3358
)
3459
}

0 commit comments

Comments
 (0)