@@ -12,15 +12,15 @@ import {
1212} from "@/components/ui/form" ;
1313import { Input } from "@/components/ui/input" ;
1414import {
15- Select ,
16- SelectContent ,
17- SelectItem ,
18- SelectTrigger ,
19- SelectValue ,
20- } from "@/components/ui/select" ;
15+ Popover ,
16+ PopoverContent ,
17+ PopoverTrigger ,
18+ } from "@/components/ui/popover" ;
2119import { Textarea } from "@/components/ui/textarea" ;
2220import { useThirdwebClient } from "@/constants/thirdweb.client" ;
21+ import { cn } from "@/lib/utils" ;
2322import { useQueryClient } from "@tanstack/react-query" ;
23+ import { useState } from "react" ;
2424import type { UseFormReturn } from "react-hook-form" ;
2525
2626import { MultiNetworkSelector } from "@/components/blocks/NetworkSelectors" ;
@@ -48,6 +48,74 @@ interface FilterDetailsStepProps {
4848 supportedChainIds : Array < number > ;
4949}
5050
51+ interface SignatureDropdownProps {
52+ signatures : Array < { name : string ; signature : string ; abi ?: string } > ;
53+ value : string ;
54+ onChange : ( val : string ) => void ;
55+ setAbi : ( abi : string ) => void ;
56+ buttonLabel : string ;
57+ secondaryTextFormatter : ( sig : { name : string ; signature : string } ) => string ;
58+ disabled ?: boolean ;
59+ }
60+
61+ function SignatureDropdown ( {
62+ signatures,
63+ value,
64+ onChange,
65+ setAbi,
66+ buttonLabel,
67+ secondaryTextFormatter,
68+ disabled,
69+ } : SignatureDropdownProps ) {
70+ const [ open , setOpen ] = useState ( false ) ;
71+ return (
72+ < Popover modal open = { open } onOpenChange = { setOpen } >
73+ < PopoverTrigger asChild >
74+ < button
75+ type = "button"
76+ className = { cn (
77+ "h-10 w-full rounded-md border bg-background px-3 py-2 text-left text-sm focus:outline-none focus:ring-2 focus:ring-ring disabled:opacity-50" ,
78+ ! value && "text-muted-foreground" ,
79+ ) }
80+ disabled = { disabled }
81+ >
82+ { value
83+ ? signatures . find ( ( sig ) => sig . signature === value ) ?. name || ""
84+ : buttonLabel }
85+ </ button >
86+ </ PopoverTrigger >
87+ < PopoverContent
88+ className = "max-h-60 w-[--radix-popover-trigger-width] overflow-y-auto p-0"
89+ align = "start"
90+ >
91+ < ul className = "divide-y divide-border" >
92+ { signatures . map ( ( sig ) => (
93+ < li key = { sig . signature } >
94+ < button
95+ type = "button"
96+ className = { cn (
97+ "w-full px-4 py-2 text-left text-sm hover:bg-accent focus:bg-accent" ,
98+ value === sig . signature && "bg-accent" ,
99+ ) }
100+ onClick = { ( ) => {
101+ onChange ( sig . signature ) ;
102+ setAbi ( sig . abi || "" ) ;
103+ setOpen ( false ) ;
104+ } }
105+ >
106+ < div className = "font-medium" > { sig . name } </ div >
107+ < div className = "text-muted-foreground text-xs" >
108+ { secondaryTextFormatter ( sig ) }
109+ </ div >
110+ </ button >
111+ </ li >
112+ ) ) }
113+ </ ul >
114+ </ PopoverContent >
115+ </ Popover >
116+ ) ;
117+ }
118+
51119export function FilterDetailsStep ( {
52120 form,
53121 eventSignatures,
@@ -305,97 +373,29 @@ export function FilterDetailsStep({
305373 { watchFilterType === "event" &&
306374 Object . keys ( fetchedAbis ) . length > 0 &&
307375 eventSignatures . length > 0 ? (
308- < Select
309- value = { field . value }
310- onValueChange = { ( value ) => {
311- field . onChange ( value ) ;
312- // Find the selected event
313- const selectedEvent = eventSignatures . find (
314- ( sig ) => sig . signature === value ,
315- ) ;
316- // Set the ABI for the event
317- form . setValue ( "sigHashAbi" , selectedEvent ?. abi || "" ) ;
318- } }
319- >
320- < SelectTrigger >
321- < SelectValue placeholder = "Select an event signature" >
322- { field . value
323- ? eventSignatures . find (
324- ( sig ) => sig . signature === field . value ,
325- ) ?. name || ""
326- : null }
327- </ SelectValue >
328- </ SelectTrigger >
329- < SelectContent className = "max-h-60 overflow-y-auto" >
330- { eventSignatures . map ( ( event ) => {
331- // Truncate the hash for display purposes
332- const truncatedHash = truncateMiddle (
333- event . signature ,
334- 6 ,
335- 4 ,
336- ) ;
337-
338- return (
339- < SelectItem
340- key = { event . signature }
341- value = { event . signature }
342- title = { event . name }
343- >
344- < div className = "flex flex-col" >
345- < span className = "font-medium" > { event . name } </ span >
346- < span className = "text-muted-foreground text-xs" >
347- Signature: { truncatedHash }
348- </ span >
349- </ div >
350- </ SelectItem >
351- ) ;
352- } ) }
353- </ SelectContent >
354- </ Select >
376+ < SignatureDropdown
377+ signatures = { eventSignatures }
378+ value = { field . value || "" }
379+ onChange = { field . onChange }
380+ setAbi = { ( abi ) => form . setValue ( "sigHashAbi" , abi ) }
381+ buttonLabel = "Select an event signature"
382+ secondaryTextFormatter = { ( sig ) =>
383+ `Signature: ${ truncateMiddle ( sig . signature , 6 , 4 ) } `
384+ }
385+ />
355386 ) : watchFilterType === "transaction" &&
356387 Object . keys ( fetchedTxAbis ) . length > 0 &&
357388 functionSignatures . length > 0 ? (
358- < Select
359- value = { field . value }
360- onValueChange = { ( value ) => {
361- field . onChange ( value ) ;
362- // Find the selected function
363- const selectedFunction = functionSignatures . find (
364- ( sig ) => sig . signature === value ,
365- ) ;
366- // Set the ABI for the function
367- form . setValue ( "sigHashAbi" , selectedFunction ?. abi || "" ) ;
368- } }
369- >
370- < SelectTrigger className = "max-w-full" >
371- < SelectValue placeholder = "Select a function signature" >
372- { field . value
373- ? functionSignatures . find (
374- ( sig ) => sig . signature === field . value ,
375- ) ?. name || ""
376- : null }
377- </ SelectValue >
378- </ SelectTrigger >
379- < SelectContent className = "max-h-60 max-w-[600px] overflow-y-auto" >
380- { functionSignatures . map ( ( func ) => (
381- < SelectItem
382- key = { func . signature }
383- value = { func . signature }
384- title = { func . signature }
385- className = "w-full overflow-x-auto"
386- >
387- < div className = "flex w-full flex-col" >
388- < span className = "overflow-x-auto whitespace-nowrap pb-1 font-medium" >
389- { func . name }
390- </ span >
391- < span className = "overflow-x-auto text-muted-foreground text-xs" >
392- Selector: { func . signature }
393- </ span >
394- </ div >
395- </ SelectItem >
396- ) ) }
397- </ SelectContent >
398- </ Select >
389+ < SignatureDropdown
390+ signatures = { functionSignatures }
391+ value = { field . value || "" }
392+ onChange = { field . onChange }
393+ setAbi = { ( abi ) => form . setValue ( "sigHashAbi" , abi ) }
394+ buttonLabel = "Select a function signature"
395+ secondaryTextFormatter = { ( sig ) =>
396+ `Selector: ${ sig . signature } `
397+ }
398+ />
399399 ) : (
400400 < Input
401401 placeholder = {
0 commit comments