1
1
"use client" ;
2
2
3
+ import { Input } from "@/components/ui/input" ;
3
4
import { useDashboardRouter } from "@/lib/DashboardRouter" ;
4
5
import { cn } from "@/lib/utils" ;
5
6
import {
@@ -24,6 +25,7 @@ import {
24
25
} from "@chakra-ui/react" ;
25
26
import type { AbiEvent , AbiFunction } from "abitype" ;
26
27
import { camelToTitle } from "contract-ui/components/solidity-inputs/helpers" ;
28
+ import { SearchIcon } from "lucide-react" ;
27
29
import { usePathname , useSearchParams } from "next/navigation" ;
28
30
import { type Dispatch , type SetStateAction , useMemo , useState } from "react" ;
29
31
import type { ThirdwebContract } from "thirdweb" ;
@@ -33,6 +35,7 @@ import * as ERC1155Ext from "thirdweb/extensions/erc1155";
33
35
import { useReadContract } from "thirdweb/react" ;
34
36
import { toFunctionSelector } from "thirdweb/utils" ;
35
37
import { Badge , Button , Card , Heading , Text } from "tw-components" ;
38
+ import { useDebounce } from "use-debounce" ;
36
39
import { useContractFunctionSelectors } from "../../contract-ui/hooks/useContractFunctionSelectors" ;
37
40
import {
38
41
COMMANDS ,
@@ -331,43 +334,53 @@ export const ContractFunctionsPanel: React.FC<ContractFunctionsPanelProps> = ({
331
334
? 1
332
335
: 0 ;
333
336
334
- const functionSection = ( e : ExtensionFunctions ) => (
335
- < Flex key = { e . extension } flexDir = "column" mb = { 6 } >
336
- { e . extension ? (
337
- < >
338
- < Flex alignItems = "center" alignContent = "center" gap = { 2 } >
339
- < Image
340
- src = "/assets/dashboard/extension-check.svg"
341
- alt = "Extension detected"
342
- objectFit = "contain"
343
- mb = "2px"
344
- />
345
- < Heading as = "label" size = "label.md" >
346
- { e . extension }
347
- </ Heading >
348
- </ Flex >
349
- < Divider my = { 2 } />
350
- </ >
351
- ) : (
352
- < >
353
- < Flex alignItems = "center" alignContent = "center" gap = { 2 } >
354
- < Heading as = "label" size = "label.md" >
355
- Other Functions
356
- </ Heading >
357
- </ Flex >
358
- < Divider my = { 2 } />
359
- </ >
360
- ) }
361
- { e . functions . map ( ( fn ) => (
362
- < FunctionsOrEventsListItem
363
- key = { `${ fn . name } _${ fn . type } _${ fn . inputs . length } ` }
364
- fn = { fn }
365
- selectedFunction = { selectedFunction }
366
- setSelectedFunction = { setSelectedFunction }
367
- />
368
- ) ) }
369
- </ Flex >
370
- ) ;
337
+ const [ _keywordSearch , setKeywordSearch ] = useState < string > ( "" ) ;
338
+ const [ keywordSearch ] = useDebounce ( _keywordSearch , 150 ) ;
339
+
340
+ const functionSection = ( e : ExtensionFunctions ) => {
341
+ const filteredFunctions = keywordSearch
342
+ ? e . functions . filter ( ( o ) =>
343
+ o . name . toLowerCase ( ) . includes ( keywordSearch . toLowerCase ( ) ) ,
344
+ )
345
+ : e . functions ;
346
+ return (
347
+ < Flex key = { e . extension } flexDir = "column" mb = { 6 } >
348
+ { e . extension ? (
349
+ < >
350
+ < Flex alignItems = "center" alignContent = "center" gap = { 2 } >
351
+ < Image
352
+ src = "/assets/dashboard/extension-check.svg"
353
+ alt = "Extension detected"
354
+ objectFit = "contain"
355
+ mb = "2px"
356
+ />
357
+ < Heading as = "label" size = "label.md" >
358
+ { e . extension }
359
+ </ Heading >
360
+ </ Flex >
361
+ < Divider my = { 2 } />
362
+ </ >
363
+ ) : (
364
+ < >
365
+ < Flex alignItems = "center" alignContent = "center" gap = { 2 } >
366
+ < Heading as = "label" size = "label.md" >
367
+ Other Functions
368
+ </ Heading >
369
+ </ Flex >
370
+ < Divider my = { 2 } />
371
+ </ >
372
+ ) }
373
+ { filteredFunctions . map ( ( fn ) => (
374
+ < FunctionsOrEventsListItem
375
+ key = { `${ fn . name } _${ fn . type } _${ fn . inputs . length } ` }
376
+ fn = { fn }
377
+ selectedFunction = { selectedFunction }
378
+ setSelectedFunction = { setSelectedFunction }
379
+ />
380
+ ) ) }
381
+ </ Flex >
382
+ ) ;
383
+ } ;
371
384
372
385
return (
373
386
< SimpleGrid height = "100%" columns = { 12 } gap = { 5 } >
@@ -406,6 +419,19 @@ export const ContractFunctionsPanel: React.FC<ContractFunctionsPanelProps> = ({
406
419
</ Tab >
407
420
) }
408
421
</ TabList >
422
+
423
+ < div className = "sticky top-0 z-[1]" >
424
+ < div className = "relative w-full" >
425
+ < SearchIcon className = "-translate-y-1/2 absolute top-[50%] left-3 size-4 text-muted-foreground" />
426
+ < Input
427
+ value = { _keywordSearch }
428
+ placeholder = "Search"
429
+ className = "h-auto rounded-none border-x-0 py-3 pl-9 focus-visible:ring-0 focus-visible:ring-offset-0"
430
+ onChange = { ( e ) => setKeywordSearch ( e . target . value ) }
431
+ />
432
+ </ div >
433
+ </ div >
434
+
409
435
< TabPanels h = "auto" overflow = "auto" >
410
436
{ writeFunctions . length > 0 && (
411
437
< TabPanel >
0 commit comments