tab: {{ $tab }}

Three files. Anna and Ben. Two downloads.
BLADE; } } function barsProbe() { Livewire::component('bars-probe', BarsProbe::class); Route::middleware('web')->get('/bars-probe', fn () => Blade::render(<<<'BLADE' @vite(config('livewire-material.showcase.vite')) @livewireStyles @livewireScripts BLADE)); return visit('/bars-probe')->waitForEvent('networkidle') ->assertScript("document.readyState === 'complete' && typeof window.Alpine !== 'undefined' && typeof window.Livewire !== 'undefined'"); } it('moves between tabs with the arrow keys, skipping disabled ones, and tells Livewire', function () { $page = barsProbe() ->click('#share-people') ->assertSeeIn('#tab', 'people') ->assertSee('Anna and Ben.') ->assertAttribute('#share-people', 'tabindex', '0') ->assertAttribute('#share-files', 'tabindex', '-1'); $page->keys('#share-people', 'ArrowRight') ->assertSeeIn('#tab', 'activity') ->assertScript("document.activeElement.id === 'share-activity'") ->assertScript("getComputedStyle(document.querySelector('#share-activity [data-tab-indicator]')).opacity === '1'"); $page->keys('#share-activity', 'Home') ->assertSeeIn('#tab', 'files') ->assertScript("document.activeElement.id === 'share-files'"); $page->keys('#share-files', 'ArrowLeft') ->assertSeeIn('#tab', 'activity'); }); it('collapses a medium app bar into its row as the page scrolls, and fades its small title in', function () { $headline = "getComputedStyle(document.querySelector('#bar [data-md-app-bar-row] [data-md-app-bar-headline]')).opacity"; $page = barsProbe() ->assertScript("! document.querySelector('#bar').hasAttribute('data-md-collapsed')") ->assertScript("{$headline} === '0'"); $page->script('window.scrollTo(0, 600)'); $page->assertScript("document.querySelector('#bar').hasAttribute('data-md-collapsed') && document.querySelector('#bar').hasAttribute('data-md-scrolled')") ->assertScript("Math.round(document.querySelector('#bar [data-md-app-bar-row]').getBoundingClientRect().top) === 0") ->assertScript("document.querySelector('#bar').getBoundingClientRect().bottom <= 65") ->assertScript("{$headline} === '1'"); $page->script('window.scrollTo(0, 0)'); $page->assertScript("! document.querySelector('#bar').hasAttribute('data-md-collapsed')"); }); it('moves focus along a toolbar with the arrow keys', function () { barsProbe() ->keys('#bold', 'ArrowRight') ->assertScript("document.activeElement.id === 'italic'") ->keys('#italic', 'End') ->assertScript("document.activeElement.id === 'underline'") ->keys('#underline', 'ArrowRight') ->assertScript("document.activeElement.id === 'bold'"); }); it('switches the theme from a toggle, a cycle and a picker', function () { $page = barsProbe() ->click('label:has(input[name="material-theme"][value="light"])') ->assertScript("document.documentElement.dataset.theme === 'light'") ->assertAttribute('#toggle', 'aria-pressed', 'false'); $page->click('#toggle') ->assertScript("document.documentElement.dataset.theme === 'dark'") ->assertAttribute('#toggle', 'aria-pressed', 'true') ->assertScript('document.querySelector(\'input[name="material-theme"][value="dark"]\').checked'); $page->click('#cycle') ->assertScript("document.documentElement.dataset.themeChoice === 'system'") ->click('#cycle') ->assertScript("document.documentElement.dataset.themeChoice === 'light'"); }); it('turns section tabs into a picker on a phone', function () { barsProbe() ->resize(400, 800) ->assertScript("getComputedStyle(document.querySelector('[data-section-nav] nav')).display === 'none'") ->click('[data-section-picker] button') ->assertScript("document.querySelector('[data-section-picker] [popover]').matches(':popover-open')") // A menu of places: the current section is the page, not a checked choice. ->assertAttribute('[data-section-picker] [role="menuitem"][href="#profile"]', 'aria-current', 'page') ->assertScript("! document.querySelector('[data-section-picker] [role=\"menuitem\"][href=\"#security\"]').hasAttribute('aria-current')"); }); class AppBarOverflowProbe extends Component { public int $stars = 0; public function star(): void { $this->stars++; } public function render(): string { return <<<'BLADE'

stars: {{ $stars }}

BLADE; } } function appBarOverflowProbe() { Livewire::component('app-bar-overflow-probe', AppBarOverflowProbe::class); Route::middleware('web')->get('/app-bar-overflow-probe', fn () => Blade::render(<<<'BLADE' @vite(config('livewire-material.showcase.vite')) @livewireStyles @livewireScripts BLADE)); return visit('/app-bar-overflow-probe')->waitForEvent('networkidle') ->assertScript("document.readyState === 'complete' && typeof window.Alpine !== 'undefined' && typeof window.Livewire !== 'undefined'"); } it('shows the app bar overflow at exactly 599 and 600px', function () { $visible = "[...document.querySelectorAll('#bar [data-md-app-bar-action]')].filter((el) => getComputedStyle(el).display !== 'none').length"; appBarOverflowProbe()->resize(599, 800) // Two icon buttons below 600px — the kept action and the overflow button. ->assertScript("{$visible} === 1") ->assertScript("getComputedStyle(document.querySelector('#bar [data-md-app-bar-overflow=\"compact\"]')).display !== 'none'") ->assertScript("getComputedStyle(document.querySelector('#bar [data-md-app-bar-overflow=\"medium\"]')).display === 'none'") ->resize(600, 800) // Four from 600px — three kept actions and the overflow button. ->assertScript("{$visible} === 3") ->assertScript("getComputedStyle(document.querySelector('#bar [data-md-app-bar-overflow=\"compact\"]')).display === 'none'") ->assertScript("getComputedStyle(document.querySelector('#bar [data-md-app-bar-overflow=\"medium\"]')).display !== 'none'") ->assertNoJavaScriptErrors(); }); it('moves the keyboard through an app bar\'s overflow menu, and closes it once the width no longer shows it', function () { $page = appBarOverflowProbe()->resize(599, 800); $page->click('#bar [data-md-app-bar-overflow="compact"] button') ->assertScript("document.querySelector('#bar [data-md-app-bar-overflow=\"compact\"] [data-md-menu-popover]').matches(':popover-open')") ->keys(':focus', 'ArrowDown') ->assertScript("document.activeElement.textContent.includes('Star')") ->keys(':focus', 'ArrowDown') ->assertScript("document.activeElement.textContent.includes('Archive')") ->keys(':focus', 'Escape') ->assertScript("! document.querySelector('#bar [data-md-app-bar-overflow=\"compact\"] [data-md-menu-popover]').matches(':popover-open')"); // Reopen it, then resize across 600px: the compact menu's trigger is no longer shown, so the // menu it opened closes rather than staying open anchored to nothing. $page->click('#bar [data-md-app-bar-overflow="compact"] button') ->assertScript("document.querySelector('#bar [data-md-app-bar-overflow=\"compact\"] [data-md-menu-popover]').matches(':popover-open')") ->resize(900, 800) ->assertScript("! document.querySelector('#bar [data-md-app-bar-overflow=\"compact\"] [data-md-menu-popover]').matches(':popover-open')") ->assertNoJavaScriptErrors(); }); it('runs a wire:click action from either the icon button or its overflow menu item', function () { $page = appBarOverflowProbe()->resize(900, 800); $page->click('#bar [data-md-app-bar-action] [aria-label="Star"]') ->assertSeeIn('#stars', '1'); $page->resize(599, 800) ->click('#bar [data-md-app-bar-overflow="compact"] button') ->click('[role="menuitem"]:has-text("Star")') ->assertSeeIn('#stars', '2'); });