Commit ad7300b
authored
Fixes: #3701
This PR fixes an issue where an open `Menu` is not closed when opening a
new `Menu`. This is also fixed for `Listbox` and `Combobox` that used
the same techniques.
This happened because we recently shipped an improvement where the
`Menu` opens on `pointerdown` instead of on `click`. This means that the
`useOutsideClick` hook was not correct anymore because it relies on
`click`.
We could try and figure out that we should already close on
`pointerdown` but this might not be expected for other components.
Instead we want to simplify things a bit and ideally not even worry
about what event caused a specific state change.
Instead of trying to fight timing issues when certain events happen,
this PR takes a slightly different approach.
We already had the concept of a "top-layer" similar to the browser's
`#top-layer` (when using native `dialog`). This essentially lets us know
which component sits on top of the hierarchy.
This top-layer is important because when you have the following
structure:
```
<Dialog>
<Menu />
</Dialog>
```
Assuming that both the `Dialog` and `Menu` are open, clicking outside or
pressing escape should _only_ close the `Menu`. Once the `Menu` is
closed, we should close the `Dialog`.
In this case, we can enable/disable the `useOutsideClick` hook based on
whether the current component is the top-layer or not.
Some components like the `Menu`, `Listbox` and `Combobox` should
immediately close when they are not the top-layer anymore. A `Dialog`
can stay open, because you can have interactable elements like the
example above in the `Dialog`.
Luckily, these components that should immediately close already use
their own state machine. This allows us to listen to the `OpenMenu` (or
`OpenListbox`, `OpenCombobox`) event, and if that happens, we can push
the current component on the shared stack machine.
This now means that it doesn't matter _how_ the `Menu` is opened, but
the moment a user event (click, enter, ...) opens the `Menu`, we now
that we are on top of the stack.
All other components could listen to push events on the stack. Once
those happen, we can close the current component immediately. This has
the nice side effect that we don't have to use a `useEffect` to check
for state changes. We can just act immediately when an event happens.
The `useOutsideClick` hooks is still used and useful in situations where
you literally just clicked somewhere else. But in case you are opening
another `Menu` or another `Listbox`, we can immediately close the one
that was open before.
## Test plan
Before:
https://github.com/user-attachments/assets/f2efd94b-9aa2-404c-ad54-c8747b4d46ac
After:
https://github.com/user-attachments/assets/25c78fc4-c1da-4e51-89b6-4270f2804ab0
1 parent afc04bc commit ad7300b
File tree
19 files changed
+272
-102
lines changed- packages/@headlessui-react
- src
- components
- combobox
- dialog
- listbox
- popover
- hooks
- playgrounds/react/pages
- popover
19 files changed
+272
-102
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
18 | 18 | | |
19 | 19 | | |
20 | 20 | | |
| 21 | + | |
21 | 22 | | |
22 | 23 | | |
23 | 24 | | |
| |||
Lines changed: 6 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
| 2 | + | |
2 | 3 | | |
3 | 4 | | |
4 | 5 | | |
| |||
13 | 14 | | |
14 | 15 | | |
15 | 16 | | |
| 17 | + | |
16 | 18 | | |
17 | 19 | | |
18 | | - | |
19 | | - | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
20 | 24 | | |
Lines changed: 32 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
| 2 | + | |
2 | 3 | | |
3 | 4 | | |
4 | 5 | | |
| |||
32 | 33 | | |
33 | 34 | | |
34 | 35 | | |
| 36 | + | |
| 37 | + | |
35 | 38 | | |
36 | 39 | | |
37 | 40 | | |
| |||
405 | 408 | | |
406 | 409 | | |
407 | 410 | | |
| 411 | + | |
408 | 412 | | |
409 | 413 | | |
410 | 414 | | |
| 415 | + | |
411 | 416 | | |
412 | 417 | | |
413 | 418 | | |
414 | 419 | | |
415 | 420 | | |
416 | 421 | | |
417 | 422 | | |
418 | | - | |
| 423 | + | |
419 | 424 | | |
| 425 | + | |
420 | 426 | | |
421 | 427 | | |
422 | 428 | | |
| |||
435 | 441 | | |
436 | 442 | | |
437 | 443 | | |
| 444 | + | |
| 445 | + | |
| 446 | + | |
| 447 | + | |
| 448 | + | |
| 449 | + | |
| 450 | + | |
| 451 | + | |
| 452 | + | |
| 453 | + | |
| 454 | + | |
| 455 | + | |
| 456 | + | |
| 457 | + | |
| 458 | + | |
| 459 | + | |
| 460 | + | |
| 461 | + | |
| 462 | + | |
| 463 | + | |
| 464 | + | |
| 465 | + | |
| 466 | + | |
| 467 | + | |
| 468 | + | |
438 | 469 | | |
439 | 470 | | |
440 | 471 | | |
| |||
Lines changed: 12 additions & 4 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
57 | 57 | | |
58 | 58 | | |
59 | 59 | | |
| 60 | + | |
60 | 61 | | |
61 | 62 | | |
62 | 63 | | |
| |||
288 | 289 | | |
289 | 290 | | |
290 | 291 | | |
| 292 | + | |
| 293 | + | |
291 | 294 | | |
292 | 295 | | |
293 | 296 | | |
| |||
315 | 318 | | |
316 | 319 | | |
317 | 320 | | |
318 | | - | |
| 321 | + | |
319 | 322 | | |
320 | 323 | | |
321 | 324 | | |
| |||
401 | 404 | | |
402 | 405 | | |
403 | 406 | | |
| 407 | + | |
| 408 | + | |
| 409 | + | |
| 410 | + | |
| 411 | + | |
| 412 | + | |
404 | 413 | | |
405 | | - | |
406 | | - | |
| 414 | + | |
407 | 415 | | |
408 | 416 | | |
409 | 417 | | |
| |||
1082 | 1090 | | |
1083 | 1091 | | |
1084 | 1092 | | |
1085 | | - | |
| 1093 | + | |
1086 | 1094 | | |
1087 | 1095 | | |
1088 | 1096 | | |
| |||
Lines changed: 25 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| 8 | + | |
8 | 9 | | |
9 | 10 | | |
10 | 11 | | |
| |||
22 | 23 | | |
23 | 24 | | |
24 | 25 | | |
| 26 | + | |
25 | 27 | | |
26 | 28 | | |
27 | 29 | | |
| |||
36 | 38 | | |
37 | 39 | | |
38 | 40 | | |
| 41 | + | |
| 42 | + | |
39 | 43 | | |
40 | 44 | | |
41 | 45 | | |
| |||
212 | 216 | | |
213 | 217 | | |
214 | 218 | | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
215 | 238 | | |
216 | | - | |
| 239 | + | |
217 | 240 | | |
218 | 241 | | |
219 | 242 | | |
220 | 243 | | |
221 | 244 | | |
222 | | - | |
| 245 | + | |
223 | 246 | | |
224 | 247 | | |
225 | 248 | | |
| |||
Lines changed: 11 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
| 2 | + | |
2 | 3 | | |
3 | 4 | | |
4 | 5 | | |
| |||
12 | 13 | | |
13 | 14 | | |
14 | 15 | | |
15 | | - | |
16 | | - | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
17 | 26 | | |
Lines changed: 26 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
| 2 | + | |
2 | 3 | | |
3 | 4 | | |
4 | 5 | | |
| |||
30 | 31 | | |
31 | 32 | | |
32 | 33 | | |
| 34 | + | |
| 35 | + | |
33 | 36 | | |
34 | 37 | | |
35 | 38 | | |
| |||
394 | 397 | | |
395 | 398 | | |
396 | 399 | | |
397 | | - | |
| 400 | + | |
398 | 401 | | |
| 402 | + | |
399 | 403 | | |
400 | 404 | | |
401 | 405 | | |
| |||
422 | 426 | | |
423 | 427 | | |
424 | 428 | | |
| 429 | + | |
| 430 | + | |
| 431 | + | |
| 432 | + | |
| 433 | + | |
| 434 | + | |
| 435 | + | |
| 436 | + | |
| 437 | + | |
| 438 | + | |
| 439 | + | |
| 440 | + | |
| 441 | + | |
| 442 | + | |
| 443 | + | |
| 444 | + | |
| 445 | + | |
| 446 | + | |
| 447 | + | |
| 448 | + | |
| 449 | + | |
425 | 450 | | |
426 | 451 | | |
427 | 452 | | |
| |||
Lines changed: 13 additions & 4 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
55 | 55 | | |
56 | 56 | | |
57 | 57 | | |
| 58 | + | |
58 | 59 | | |
59 | 60 | | |
60 | 61 | | |
| |||
162 | 163 | | |
163 | 164 | | |
164 | 165 | | |
| 166 | + | |
| 167 | + | |
165 | 168 | | |
166 | 169 | | |
167 | 170 | | |
| |||
188 | 191 | | |
189 | 192 | | |
190 | 193 | | |
191 | | - | |
| 194 | + | |
192 | 195 | | |
193 | 196 | | |
194 | 197 | | |
| |||
241 | 244 | | |
242 | 245 | | |
243 | 246 | | |
244 | | - | |
245 | | - | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
246 | 253 | | |
247 | 254 | | |
248 | 255 | | |
249 | 256 | | |
250 | | - | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
251 | 260 | | |
252 | 261 | | |
253 | 262 | | |
| |||
Lines changed: 5 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
| 2 | + | |
2 | 3 | | |
3 | 4 | | |
4 | 5 | | |
| |||
12 | 13 | | |
13 | 14 | | |
14 | 15 | | |
15 | | - | |
16 | | - | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
17 | 20 | | |
0 commit comments