Skip to content

Commit 1026259

Browse files
simonhampclaude
andauthored
fix(nav): close the site menu when search opens (#526)
The menu is a popover, so the browser draws it above the DocSearch modal. Opening search from the menu left the menu sitting on top of the search box on desktop and mobile. Clicking Search now closes the menu in the same click handler. For Cmd+K and /, DocSearch's onOpen callback fires a docsearch:open event that the menu listens for. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 912b672 commit 1026259

3 files changed

Lines changed: 64 additions & 1 deletion

File tree

‎resources/js/app.js‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,9 @@ const docsearchOptions = {
189189
docsearch({
190190
...docsearchOptions,
191191
container: '#docsearch-desktop',
192+
// The site menu is a popover, so it renders above the search modal. Tell it
193+
// to close when a keyboard shortcut opens search while the menu is open.
194+
onOpen: () => window.dispatchEvent(new CustomEvent('docsearch:open')),
192195
})
193196

194197
// Mirror the desktop DocSearch button into the mobile container so that

‎resources/views/components/navbar/mobile-menu.blade.php‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
})
4343
}
4444
"
45+
x-on:docsearch:open.window="showMobileMenu = false"
4546
class="relative z-40"
4647
>
4748
<button
@@ -419,7 +420,10 @@ class="-mr-0.5 transition-all duration-200 ease-in-out will-change-transform lg:
419420
>
420421
<div
421422
id="docsearch-desktop"
422-
x-on:click="if (window.innerWidth < 640) window.scrollTo({ top: 0, behavior: 'instant' })"
423+
x-on:click="
424+
showMobileMenu = false
425+
if (window.innerWidth < 640) window.scrollTo({ top: 0, behavior: 'instant' })
426+
"
423427
aria-label="Search documentation"
424428
></div>
425429
</div>
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
3+
namespace Tests\Feature;
4+
5+
use DOMDocument;
6+
use DOMElement;
7+
use DOMXPath;
8+
use Illuminate\Foundation\Testing\RefreshDatabase;
9+
use Tests\TestCase;
10+
11+
/**
12+
* The menu is a popover, so the browser draws it above everything else,
13+
* including the DocSearch modal. It has to close whenever search opens,
14+
* otherwise it sits on top of the search box.
15+
*/
16+
class NavigationMobileMenuSearchTest extends TestCase
17+
{
18+
use RefreshDatabase;
19+
20+
public function test_menu_closes_when_its_search_button_is_clicked(): void
21+
{
22+
$searchButtonContainer = $this->elementOnHomePage('//*[@id="docsearch-desktop"]');
23+
24+
$this->assertStringContainsString(
25+
'showMobileMenu = false',
26+
$searchButtonContainer->getAttribute('x-on:click'),
27+
);
28+
}
29+
30+
public function test_menu_closes_when_a_keyboard_shortcut_opens_search(): void
31+
{
32+
$menu = $this->elementOnHomePage('//*[@id="mobile-menu-popover"]/..');
33+
34+
$this->assertSame('showMobileMenu = false', $menu->getAttribute('x-on:docsearch:open.window'));
35+
36+
$this->assertMatchesRegularExpression(
37+
"/onOpen: .*new CustomEvent\('docsearch:open'\)/",
38+
file_get_contents(resource_path('js/app.js')),
39+
'DocSearch should announce that it opened with the event the menu listens for.',
40+
);
41+
}
42+
43+
private function elementOnHomePage(string $xpath): DOMElement
44+
{
45+
$dom = new DOMDocument;
46+
libxml_use_internal_errors(true);
47+
$dom->loadHTML('<?xml encoding="utf-8" ?>'.$this->get('/')->assertOk()->getContent());
48+
libxml_clear_errors();
49+
50+
$element = (new DOMXPath($dom))->query($xpath)->item(0);
51+
52+
$this->assertInstanceOf(DOMElement::class, $element, "Nothing on the home page matches {$xpath}.");
53+
54+
return $element;
55+
}
56+
}

0 commit comments

Comments
 (0)