@@ -10,19 +10,29 @@ import styles from "./styles.module.css";
10
10
11
11
function DocsCategoryDropdown ( { dropdownCategory } ) {
12
12
const [ isOpen , setIsOpen ] = useState ( false ) ;
13
+ const [ isVisible , setIsVisible ] = useState ( false ) ;
13
14
const [ dropdownStyles , setDropdownStyles ] = useState ( {
14
15
top : "0px" ,
15
16
left : "0px" ,
16
17
} ) ;
17
18
const dropdownMenuRef = useRef ( null ) ;
18
19
const triggerRef = useRef ( null ) ; // Reference for the individual menu item trigger
20
+ const hideTimeoutRef = useRef ( null ) ;
19
21
20
22
const handleMouseEnter = ( ) => {
23
+ if ( hideTimeoutRef . current ) {
24
+ clearTimeout ( hideTimeoutRef . current ) ;
25
+ hideTimeoutRef . current = null ;
26
+ }
21
27
setIsOpen ( true ) ;
28
+ setTimeout ( ( ) => setIsVisible ( true ) , 10 ) ;
22
29
} ;
23
30
24
31
const handleMouseLeave = ( ) => {
25
- setIsOpen ( false ) ;
32
+ setIsVisible ( false ) ;
33
+ hideTimeoutRef . current = setTimeout ( ( ) => {
34
+ setIsOpen ( false ) ;
35
+ } , 150 ) ;
26
36
} ;
27
37
28
38
// Use useEffect to update the dropdown position when isOpen changes
@@ -42,17 +52,17 @@ function DocsCategoryDropdown({ dropdownCategory }) {
42
52
} else {
43
53
// Align to center
44
54
left =
45
- triggerRect . left + triggerRect . width / 2 - dropdownRect . width / 2 ;
55
+ triggerRect . left + triggerRect . width / 2 - dropdownRect . width / 2 ;
46
56
}
47
57
48
58
// Ensure the dropdown doesn't go off-screen
49
59
left = Math . max (
50
- 10 ,
51
- Math . min ( left , viewportWidth - dropdownRect . width - 10 ) ,
60
+ 10 ,
61
+ Math . min ( left , viewportWidth - dropdownRect . width - 10 ) ,
52
62
) ;
53
63
54
64
setDropdownStyles ( {
55
- top : `${ triggerRect . bottom } px` , // Align the dropdown below the menu item
65
+ top : `${ triggerRect . bottom } px` , // Back to original positioning
56
66
left : `${ left } px` , // Align the dropdown with the menu item
57
67
} ) ;
58
68
}
@@ -67,132 +77,130 @@ function DocsCategoryDropdown({ dropdownCategory }) {
67
77
68
78
// Guard against undefined sidebar
69
79
const isSelected =
70
- sidebar && sidebar . name && dropdownCategory
71
- ? sidebar . name === dropdownCategory . customProps . sidebar
72
- : false ;
80
+ sidebar && sidebar . name && dropdownCategory
81
+ ? sidebar . name === dropdownCategory . customProps . sidebar
82
+ : false ;
73
83
74
84
return (
75
- < div
76
- className = { styles . docsNavDropdownContainer }
77
- onMouseEnter = { handleMouseEnter }
78
- onMouseLeave = { handleMouseLeave }
79
- >
85
+ < div
86
+ className = { styles . docsNavDropdownContainer }
87
+ onMouseEnter = { handleMouseEnter }
88
+ onMouseLeave = { handleMouseLeave }
89
+ >
80
90
< span
81
- className = { styles . docsNavDropdownToolbarLink }
82
- ref = { triggerRef } // Attach the ref to the individual link that triggers the dropdown
91
+ className = { styles . docsNavDropdownToolbarLink }
92
+ ref = { triggerRef } // Attach the ref to the individual link that triggers the dropdown
83
93
>
84
94
< Link
85
- className = { `${ styles . docsNavDropdownToolbarTopLevelLink } ${ isSelected ? styles . docsNavSelected : ""
95
+ className = { `${ styles . docsNavDropdownToolbarTopLevelLink } ${ isSelected ? styles . docsNavSelected : ""
86
96
} `}
87
- href = { dropdownCategory . customProps . href }
97
+ href = { dropdownCategory . customProps . href }
88
98
>
89
99
< Translate
90
- id = { `sidebar.dropdownCategories.category.${ dropdownCategory . label } ` }
91
- description = { `Translation for ${ dropdownCategory . label } ` }
100
+ id = { `sidebar.dropdownCategories.category.${ dropdownCategory . label } ` }
101
+ description = { `Translation for ${ dropdownCategory . label } ` }
92
102
>
93
103
{ dropdownCategory . label }
94
104
</ Translate >
95
105
</ Link > { " " }
96
106
< DropdownCaret />
97
107
</ span >
98
- { isOpen && (
99
- < DropdownContent
100
- dropdownCategory = { dropdownCategory }
101
- handleMouseLeave = { handleMouseLeave }
102
- dropdownStyles = { dropdownStyles } // Pass the dynamic styles to position the dropdown
103
- dropdownMenuRef = { dropdownMenuRef } // Pass the ref to the dropdown content
104
- />
105
- ) }
106
- </ div >
108
+ { isOpen && (
109
+ < DropdownContent
110
+ dropdownCategory = { dropdownCategory }
111
+ handleMouseLeave = { handleMouseLeave }
112
+ dropdownStyles = { dropdownStyles } // Pass the dynamic styles to position the dropdown
113
+ dropdownMenuRef = { dropdownMenuRef } // Pass the ref to the dropdown content
114
+ isVisible = { isVisible }
115
+ />
116
+ ) }
117
+ </ div >
107
118
) ;
108
119
}
109
120
110
121
export const DocsCategoryDropdownLinkOnly = ( { title, link } ) => {
111
122
return (
112
- < div className = { styles . docsNavDropdownContainer } >
113
- < Link href = { link } className = { styles . docsNavDropdownToolbarTopLevelLink } >
114
- < span > { title } </ span >
115
- </ Link >
116
- </ div >
123
+ < div className = { styles . docsNavDropdownContainer } >
124
+ < Link href = { link } className = { styles . docsNavDropdownToolbarTopLevelLink } >
125
+ < span > { title } </ span >
126
+ </ Link >
127
+ </ div >
117
128
) ;
118
129
} ;
119
130
120
131
const DropdownContent = ( {
121
- dropdownCategory,
122
- handleMouseLeave,
123
- dropdownStyles,
124
- dropdownMenuRef,
125
- } ) => {
132
+ dropdownCategory,
133
+ handleMouseLeave,
134
+ dropdownStyles,
135
+ dropdownMenuRef,
136
+ isVisible,
137
+ } ) => {
126
138
const [ hovered , setHovered ] = useState ( null ) ;
127
139
128
140
return (
129
- < div
130
- ref = { dropdownMenuRef }
131
- className = { styles . docsNavDropdownMenu }
132
- style = { { position : "fixed" , ...dropdownStyles } }
133
- >
134
141
< div
135
- key = { 99 }
136
- className = { `${ styles . docsNavMenuItem } ${ hovered === 99 ? styles . docsNavHovered : "" } ` }
137
- onMouseEnter = { ( ) => setHovered ( 99 ) }
138
- onMouseLeave = { ( ) => setHovered ( null ) }
142
+ ref = { dropdownMenuRef }
143
+ className = { `${ styles . docsNavDropdownMenu } ${ isVisible ? styles . visible : '' } ` }
144
+ style = { { position : "fixed" , ...dropdownStyles } }
139
145
>
140
146
< Link
141
- to = { dropdownCategory . customProps . href }
142
- className = { styles . docsNavMenuHeader }
143
- onClick = { handleMouseLeave }
144
- >
145
- < Translate
146
- id = { `sidebar.dropdownCategories.category.${ dropdownCategory . label } ` }
147
- description = { `Translation for ${ dropdownCategory . label } ` }
148
- >
149
- { dropdownCategory . label }
150
- </ Translate >
151
- </ Link >
152
- < div className = { styles . docsNavMenuDescription } >
153
- < Translate
154
- id = { `sidebar.dropdownCategories.category.description.${ dropdownCategory . label } ` }
155
- description = { `Translation for ${ dropdownCategory . label } description` }
156
- >
157
- { dropdownCategory . description }
158
- </ Translate >
159
- </ div >
160
- </ div >
161
- < hr className = { styles . docsNavMenuDivider } />
162
- < div className = { styles . docsNavMenuItems } >
163
- { dropdownCategory . items . map ( ( item , index ) => (
164
- < div
165
- key = { index }
166
- className = { `${ styles . docsNavMenuItem } ${ hovered === index ? styles . docsNavHovered : "" } ` }
167
- onMouseEnter = { ( ) => setHovered ( index ) }
147
+ key = { 99 }
148
+ to = { dropdownCategory . customProps . href }
149
+ className = { `${ styles . docsNavMenuItem } ${ hovered === 99 ? styles . docsNavHovered : "" } ` }
150
+ onMouseEnter = { ( ) => setHovered ( 99 ) }
168
151
onMouseLeave = { ( ) => setHovered ( null ) }
169
- >
170
- < Link
171
- to = { item . href }
172
- className = { styles . docsNavItemTitle }
173
- onClick = { handleMouseLeave }
152
+ onClick = { handleMouseLeave }
153
+ style = { { textDecoration : 'none' , display : 'block' } }
154
+ >
155
+ < div className = { styles . docsNavMenuHeader } >
156
+ < Translate
157
+ id = { `sidebar.dropdownCategories.category.${ dropdownCategory . label } ` }
158
+ description = { `Translation for ${ dropdownCategory . label } ` }
174
159
>
175
- < Translate
176
- id = { `sidebar.dropdownCategories.category.${ dropdownCategory . label } .${ item . label } ` }
177
- description = { `Translation for ${ dropdownCategory . label } .${ item . label } ` }
178
- >
179
- { item . label }
180
- </ Translate >
181
-
182
- </ Link >
183
- < div className = { styles . docsNavItemDescription } >
184
- < Translate
185
- id = { `sidebar.dropdownCategories.category.${ dropdownCategory . label } .${ item . label } .description` }
186
- description = { `Translation for ${ dropdownCategory . label } .${ item . label } description` }
187
- >
188
- { item . description }
189
- </ Translate >
190
-
191
- </ div >
160
+ { dropdownCategory . label }
161
+ </ Translate >
162
+ </ div >
163
+ < div className = { styles . docsNavMenuDescription } >
164
+ < Translate
165
+ id = { `sidebar.dropdownCategories.category.description.${ dropdownCategory . label } ` }
166
+ description = { `Translation for ${ dropdownCategory . label } description` }
167
+ >
168
+ { dropdownCategory . description }
169
+ </ Translate >
192
170
</ div >
193
- ) ) }
171
+ </ Link >
172
+ < hr className = { styles . docsNavMenuDivider } />
173
+ < div className = { styles . docsNavMenuItems } >
174
+ { dropdownCategory . items . map ( ( item , index ) => (
175
+ < Link
176
+ key = { index }
177
+ to = { item . href }
178
+ className = { `${ styles . docsNavMenuItem } ${ hovered === index ? styles . docsNavHovered : "" } ` }
179
+ onMouseEnter = { ( ) => setHovered ( index ) }
180
+ onMouseLeave = { ( ) => setHovered ( null ) }
181
+ onClick = { handleMouseLeave }
182
+ style = { { textDecoration : 'none' , display : 'block' } }
183
+ >
184
+ < div className = { styles . docsNavItemTitle } >
185
+ < Translate
186
+ id = { `sidebar.dropdownCategories.category.${ dropdownCategory . label } .${ item . label } ` }
187
+ description = { `Translation for ${ dropdownCategory . label } .${ item . label } ` }
188
+ >
189
+ { item . label }
190
+ </ Translate >
191
+ </ div >
192
+ < div className = { styles . docsNavItemDescription } >
193
+ < Translate
194
+ id = { `sidebar.dropdownCategories.category.${ dropdownCategory . label } .${ item . label } .description` }
195
+ description = { `Translation for ${ dropdownCategory . label } .${ item . label } description` }
196
+ >
197
+ { item . description }
198
+ </ Translate >
199
+ </ div >
200
+ </ Link >
201
+ ) ) }
202
+ </ div >
194
203
</ div >
195
- </ div >
196
204
) ;
197
205
} ;
198
206
@@ -211,24 +219,24 @@ const DropdownCaret = () => {
211
219
} ;
212
220
213
221
return (
214
- < span style = { { marginLeft : "8px" } } >
222
+ < span style = { { marginLeft : "8px" } } >
215
223
< svg
216
- xmlns = "http://www.w3.org/2000/svg"
217
- width = "6"
218
- height = "10"
219
- viewBox = "0 0 6 10"
220
- style = { rotatedIconStyle }
224
+ xmlns = "http://www.w3.org/2000/svg"
225
+ width = "6"
226
+ height = "10"
227
+ viewBox = "0 0 6 10"
228
+ style = { rotatedIconStyle }
221
229
>
222
230
< path
223
- stroke = "currentColor"
224
- strokeLinecap = "round"
225
- strokeLinejoin = "round"
226
- strokeWidth = "1.5"
227
- d = "M1 9L5 5 1 1"
231
+ stroke = "currentColor"
232
+ strokeLinecap = "round"
233
+ strokeLinejoin = "round"
234
+ strokeWidth = "1.5"
235
+ d = "M1 9L5 5 1 1"
228
236
/>
229
237
</ svg >
230
238
</ span >
231
239
) ;
232
240
} ;
233
241
234
- export default DocsCategoryDropdown ;
242
+ export default DocsCategoryDropdown ;
0 commit comments