@@ -2,6 +2,7 @@ import React, { useState, useRef, useEffect } from 'react';
22
33/**
44 * NetworkSelector component for selecting between different SVM networks
5+ * Now using ASCII dropdown style matching ProfileDropdown
56 *
67 * @param {Object } props - Component props
78 * @param {Object } props.networks - Object containing network configurations
@@ -11,210 +12,62 @@ import React, { useState, useRef, useEffect } from 'react';
1112 */
1213export const NetworkSelector = ( { networks, selectedNetwork, onSelectNetwork } ) => {
1314 const [ isOpen , setIsOpen ] = useState ( false ) ;
14- const [ dropdownPosition , setDropdownPosition ] = useState ( { top : 0 , left : 0 } ) ;
15- const [ focusedIndex , setFocusedIndex ] = useState ( - 1 ) ;
1615 const dropdownRef = useRef ( null ) ;
17- const buttonRef = useRef ( null ) ;
18- const optionRefs = useRef ( [ ] ) ;
1916 const network = networks [ selectedNetwork ] ;
2017
2118 const networkKeys = Object . keys ( networks ) ;
2219
23- // Custom SVG icon component based on provided SVG file
24- const DropdownIcon = ( { className } ) => (
25- < svg
26- className = { className }
27- width = "24"
28- height = "24"
29- viewBox = "0 0 900 762"
30- fill = "currentColor"
31- xmlns = "http://www.w3.org/2000/svg"
32- aria-hidden = "true"
33- >
34- < g transform = "translate(0.000000,762.000000) scale(0.100000,-0.100000)" >
35- < path d = "M4185 6864 c-207 -16 -356 -44 -640 -119 -59 -16 -187 -60 -230 -80 -16 -7 -55 -23 -85 -35 -67 -26 -277 -132 -331 -166 -21 -13 -41 -24 -45 -24 -3 0 -23 -13 -44 -30 -21 -16 -40 -30 -44 -30 -3 0 -25 -14 -48 -30 -24 -17 -54 -38 -68 -47 -135 -90 -407 -342 -536 -495 -98 -117 -264 -346 -264 -365 0 -3 -6 -14 -14 -22 -59 -69 -232 -440 -290 -625 -36 -114 -53 -176 -71 -256 -9 -41 -21 -95 -27 -120 -28 -127 -48 -353 -48 -564 0 -296 20 -466 87 -731 14 -55 29 -116 33 -135 12 -50 58 -180 75 -212 8 -14 15 -33 15 -42 0 -8 9 -32 19 -53 11 -21 31 -65 46 -98 14 -33 32 -71 39 -85 68 -130 155 -275 198 -331 15 -20 28 -40 28 -43 0 -9 90 -125 179 -231 134 -158 325 -338 491 -461 65 -49 210 -147 230 -157 8 -4 38 -21 65 -37 162 -97 425 -213 615 -270 144 -43 166 -49 393 -95 250 -50 756 -51 1002 0 39 8 106 21 150 30 76 15 155 35 220 57 17 5 64 20 106 33 42 13 85 28 95 33 11 6 60 27 109 47 183 76 300 138 486 261 295 194 540 425 760 719 77 102 139 192 139 201 0 2 12 23 27 47 52 80 138 246 180 347 68 162 93 229 93 247 0 11 4 23 9 28 12 13 57 184 95 365 52 249 64 676 27 955 -12 83 -25 168 -30 190 -5 22 -19 81 -31 130 -35 151 -115 400 -149 463 -6 9 -24 49 -41 87 -35 79 -32 72 -90 180 -224 413 -554 779 -945 1048 -93 64 -120 81 -145 93 -8 4 -33 19 -55 33 -98 61 -364 184 -490 226 -39 13 -81 28 -95 33 -78 32 -354 94 -520 117 -110 16 -521 28 -635 19z m500 -225 c39 -5 102 -14 140 -19 445 -60 913 -257 1285 -540 119 -91 147 -115 295 -265 301 -303 490 -600 650 -1025 19 -51 72 -230 79 -265 3 -16 14 -71 25 -122 59 -269 76 -637 41 -860 -6 -37 -18 -111 -26 -163 -8 -52 -21 -120 -28 -150 -8 -30 -18 -73 -24 -95 -20 -82 -92 -296 -121 -359 -180 -396 -348 -642 -626 -919 -104 -103 -348 -307 -368 -307 -2 0 -35 -20 -73 -45 -37 -25 -74 -45 -82 -45 -8 0 -26 -6 -40 -14 -120 -65 -422 -65 -727 -1 -337 70 -409 79 -670 79 -192 0 -268 -3 -330 -16 -44 -9 -123 -24 -175 -33 -52 -9 -126 -23 -165 -31 -177 -35 -260 -44 -410 -44 -254 0 -318 22 -575 197 -73 50 -260 216 -365 325 -99 102 -260 299 -312 383 -123 196 -206 356 -275 535 -54 137 -108 307 -108 337 0 12 -5 34 -11 50 -12 32 -41 204 -60 353 -16 128 -16 411 0 540 18 145 52 343 62 362 5 9 9 26 9 38 0 36 92 323 131 409 119 261 256 494 385 653 33 40 70 86 83 103 52 63 272 275 367 351 159 128 336 239 519 328 55 27 108 53 118 58 9 4 43 18 75 29 31 11 71 27 87 34 30 14 186 61 280 85 96 24 207 43 405 70 84 11 456 11 535 -1z" />
36- < path d = "M4837 4045 c-233 -234 -431 -425 -439 -425 -8 0 -196 182 -419 405 -222 223 -411 405 -420 405 -16 0 -159 -141 -159 -157 0 -14 978 -987 995 -991 19 -4 1034 1006 1035 1028 0 18 -139 160 -157 160 -6 0 -202 -191 -436 -425z" />
37- </ g >
38- </ svg >
39- ) ;
40-
41- // Calculate dropdown position
42- const calculateDropdownPosition = ( ) => {
43- if ( buttonRef . current ) {
44- const buttonRect = buttonRef . current . getBoundingClientRect ( ) ;
45- const dropdownWidth = 200 ; // Approximate dropdown width
46- const dropdownHeight = 300 ; // Max dropdown height
47-
48- let top = buttonRect . bottom + 4 ;
49- let left = buttonRect . right - dropdownWidth ;
50-
51- // Adjust if dropdown would go off screen
52- if ( left < 8 ) {
53- left = buttonRect . left ;
54- }
55-
56- if ( top + dropdownHeight > window . innerHeight - 8 ) {
57- top = buttonRect . top - dropdownHeight - 4 ;
58- }
59-
60- setDropdownPosition ( { top, left } ) ;
61- }
62- } ;
63-
6420 // Close dropdown when clicking outside
6521 useEffect ( ( ) => {
66- const handleClickOutside = ( event ) => {
22+ function handleClickOutside ( event ) {
6723 if ( dropdownRef . current && ! dropdownRef . current . contains ( event . target ) ) {
6824 setIsOpen ( false ) ;
69- setFocusedIndex ( - 1 ) ;
7025 }
71- } ;
26+ }
7227
7328 document . addEventListener ( 'mousedown' , handleClickOutside ) ;
7429 return ( ) => {
7530 document . removeEventListener ( 'mousedown' , handleClickOutside ) ;
7631 } ;
7732 } , [ ] ) ;
78-
79- // Focus management for accessibility
80- useEffect ( ( ) => {
81- if ( isOpen && focusedIndex >= 0 && optionRefs . current [ focusedIndex ] ) {
82- optionRefs . current [ focusedIndex ] . focus ( ) ;
83- }
84- } , [ isOpen , focusedIndex ] ) ;
85-
86- // Update position when opening dropdown
87- useEffect ( ( ) => {
88- if ( isOpen ) {
89- calculateDropdownPosition ( ) ;
90- window . addEventListener ( 'resize' , calculateDropdownPosition ) ;
91- window . addEventListener ( 'scroll' , calculateDropdownPosition ) ;
92-
93- return ( ) => {
94- window . removeEventListener ( 'resize' , calculateDropdownPosition ) ;
95- window . removeEventListener ( 'scroll' , calculateDropdownPosition ) ;
96- } ;
97- }
98- } , [ isOpen ] ) ;
99-
100- // Keyboard navigation
101- const handleKeyDown = ( event ) => {
102- switch ( event . key ) {
103- case 'ArrowDown' :
104- event . preventDefault ( ) ;
105- if ( ! isOpen ) {
106- setIsOpen ( true ) ;
107- calculateDropdownPosition ( ) ;
108- setFocusedIndex ( 0 ) ;
109- } else if ( networkKeys . length > 0 ) {
110- setFocusedIndex ( prev =>
111- prev < networkKeys . length - 1 ? prev + 1 : 0
112- ) ;
113- }
114- break ;
115- case 'ArrowUp' :
116- event . preventDefault ( ) ;
117- if ( isOpen && networkKeys . length > 0 ) {
118- setFocusedIndex ( prev =>
119- prev > 0 ? prev - 1 : networkKeys . length - 1
120- ) ;
121- }
122- break ;
123- case 'Enter' :
124- case ' ' :
125- event . preventDefault ( ) ;
126- if ( ! isOpen ) {
127- setIsOpen ( true ) ;
128- calculateDropdownPosition ( ) ;
129- setFocusedIndex ( 0 ) ;
130- } else if ( focusedIndex >= 0 && networkKeys [ focusedIndex ] ) {
131- handleNetworkSelect ( networkKeys [ focusedIndex ] ) ;
132- }
133- break ;
134- case 'Escape' :
135- event . preventDefault ( ) ;
136- setIsOpen ( false ) ;
137- setFocusedIndex ( - 1 ) ;
138- buttonRef . current ?. focus ( ) ;
139- break ;
140- default :
141- break ;
142- }
143- } ;
14433
14534 const handleNetworkSelect = ( networkKey ) => {
14635 onSelectNetwork ( networkKey ) ;
14736 setIsOpen ( false ) ;
148- setFocusedIndex ( - 1 ) ;
149- buttonRef . current ?. focus ( ) ; // Return focus to trigger button
150- } ;
151-
152- const handleToggleDropdown = ( ) => {
153- if ( ! isOpen ) {
154- calculateDropdownPosition ( ) ;
155- setFocusedIndex ( 0 ) ;
156- } else {
157- setFocusedIndex ( - 1 ) ;
158- }
159- setIsOpen ( ! isOpen ) ;
16037 } ;
16138
16239 return (
163- < div className = "network-selector " ref = { dropdownRef } >
40+ < div className = "ascii-dropdown-container " ref = { dropdownRef } >
16441 < button
165- ref = { buttonRef }
166- className = "network-selector-button"
167- onClick = { handleToggleDropdown }
168- onKeyDown = { handleKeyDown }
42+ className = "ascii-header-control ascii-dropdown-trigger"
43+ onClick = { ( ) => setIsOpen ( ! isOpen ) }
16944 aria-expanded = { isOpen }
170- aria-haspopup = "listbox "
171- aria-label = { `Current network: ${ network . name } . Press Enter or Space to open network options ` }
45+ aria-haspopup = "true "
46+ aria-label = { `Current network: ${ network . name } ` }
17247 >
17348 < div
17449 className = "network-indicator"
17550 style = { { backgroundColor : network . color } }
17651 />
177- < span className = "network-selector-text" > { network . name } </ span >
178- < DropdownIcon
179- className = { `network-dropdown-icon ${ isOpen ? 'open' : '' } ` }
180- />
52+ { network . name } ▼
18153 </ button >
18254
18355 { isOpen && (
184- < >
185- < div className = "dropdown-backdrop" onClick = { ( ) => setIsOpen ( false ) } />
186- < div
187- className = "network-selector-dropdown"
188- role = "listbox"
189- style = { {
190- position : 'fixed' ,
191- top : `${ dropdownPosition . top } px` ,
192- left : `${ dropdownPosition . left } px` ,
193- zIndex : 99999
194- } }
195- >
196- { Object . entries ( networks ) . map ( ( [ key , network ] , index ) => (
56+ < div className = "ascii-dropdown-menu" >
57+ { Object . entries ( networks ) . map ( ( [ key , networkOption ] ) => (
58+ < button
59+ key = { key }
60+ className = { `ascii-dropdown-item ${ key === selectedNetwork ? 'active' : '' } ` }
61+ onClick = { ( ) => handleNetworkSelect ( key ) }
62+ >
19763 < div
198- key = { key }
199- ref = { el => optionRefs . current [ index ] = el }
200- className = { `network-option ${ key === selectedNetwork ? 'active' : '' } ${
201- focusedIndex === index ? 'focused' : ''
202- } `}
203- onClick = { ( ) => handleNetworkSelect ( key ) }
204- onKeyDown = { handleKeyDown }
205- role = "option"
206- aria-selected = { key === selectedNetwork }
207- tabIndex = { - 1 }
208- >
209- < div
210- className = "network-indicator"
211- style = { { backgroundColor : network . color } }
212- />
213- < span className = "network-option-name" > { network . name } </ span >
214- </ div >
215- ) ) }
216- </ div >
217- </ >
64+ className = "network-indicator"
65+ style = { { backgroundColor : networkOption . color } }
66+ />
67+ { networkOption . name }
68+ </ button >
69+ ) ) }
70+ </ div >
21871 ) }
21972 </ div >
22073 ) ;
0 commit comments