diff --git a/resources/css/components/dialog.css b/resources/css/components/dialog.css index ff85919e..74f2d82c 100644 --- a/resources/css/components/dialog.css +++ b/resources/css/components/dialog.css @@ -56,3 +56,21 @@ opacity: 1; } } + +/* + * The scrolling body is a keyboard stop of its own when nothing inside it can take focus: Chrome + * makes a scroll container focusable so the keyboard can scroll it, and `showModal()` hands it the + * dialog's first focus. It then showed the browser's own ring. It takes M3's focus indicator + * instead — 3px in secondary (tokens/state.css) — drawn inside its edge, because the dialog's + * rounded, overflow-hidden box would clip a ring drawn 2px outside. + */ +@layer components { + [data-dialog-body] { + outline: none; + } + + [data-dialog-body]:focus-visible { + outline: 3px solid var(--md-sys-color-secondary); + outline-offset: -3px; + } +} diff --git a/resources/views/components/modal.blade.php b/resources/views/components/modal.blade.php index ec150aad..bb28feeb 100644 --- a/resources/views/components/modal.blade.php +++ b/resources/views/components/modal.blade.php @@ -139,7 +139,7 @@ @endif @if ($body) -
$header, 'max-medium:pt-4' => $header && $barAboveBody, diff --git a/tests/Feature/Components/OverlayTest.php b/tests/Feature/Components/OverlayTest.php index 9c048aa8..3f78f736 100644 --- a/tests/Feature/Components/OverlayTest.php +++ b/tests/Feature/Components/OverlayTest.php @@ -63,7 +63,7 @@ it('pins a dialog\'s headline and actions and scrolls only the body between them ->toContain('overflow-hidden rounded-corner-xl bg-surface-container-high shadow-elevation-3') ->not->toContain('overflow-y-auto rounded-corner-xl') ->toMatch('//') - ->toMatch('/
\s*
Body<\/div>\s*<\/div>/') + ->toMatch('/
\s*
Body<\/div>\s*<\/div>/') ->toMatch('//'); });