Draw the section navigation without Tailwind
Plan step 36 (navigation group, third batch): <x-section-nav>'s class lists move into resources/css/components/section-nav.css, keyed on data-md-section-nav (data-md-section-nav-picker, its own trigger and label) and <x-tabs>'s own hooks, reused whole rather than copied (N-16's fix keeps the real scrollable tab bar it landed): the bar's outline-variant divider, active indicator and aria-current colouring are tabs.css's rules, not this file's. The picker's trigger takes the shared md-focus-ring class and the fixed md-type-body-lg/md-ink/ md-text-start text classes for its own body-large type, since it is prose on a plain button rather than a component's own type; icons take a size prop instead of a size class. Hooks renamed: data-section-nav to data-md-section-nav, data-section-picker to data-md-section-nav-picker, updated in TabsTest.php (which carries section-nav's render tests) and tests/Browser/BarsTest.php. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
ed93222d22
commit
f1cd6e4eb4
@@ -138,12 +138,12 @@ it('switches the theme from a toggle, a cycle and a picker', function () {
|
||||
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')")
|
||||
->assertScript("getComputedStyle(document.querySelector('[data-md-section-nav] nav')).display === 'none'")
|
||||
->click('[data-md-section-nav-picker] button')
|
||||
->assertScript("document.querySelector('[data-md-section-nav-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')");
|
||||
->assertAttribute('[data-md-section-nav-picker] [role="menuitem"][href="#profile"]', 'aria-current', 'page')
|
||||
->assertScript("! document.querySelector('[data-md-section-nav-picker] [role=\"menuitem\"][href=\"#security\"]').hasAttribute('aria-current')");
|
||||
});
|
||||
|
||||
class AppBarOverflowProbe extends Component
|
||||
|
||||
@@ -20,6 +20,8 @@ use NoNameWeb\LivewireMaterial\Tests\Support\ViewClasses;
|
||||
* published that variable through a Tailwind utility, which no layered rule could outrank; now
|
||||
* scaffold.css sets it in `material.layout`, which this file's `material.components` always beats,
|
||||
* so the whole stylesheet fits one `@layer material.components` block like every other entry here.
|
||||
* `section-nav` renders `<x-tabs>`'s hooks rather than `<x-tabs>` itself (it reuses its stylesheet
|
||||
* whole, tabs.css, N-16), so `navigationViews()` need not special-case it the way it does 'tabs'.
|
||||
*/
|
||||
dataset('navigation components', [
|
||||
'app-bar',
|
||||
@@ -30,6 +32,7 @@ dataset('navigation components', [
|
||||
'navigation-rail',
|
||||
'navigation-rail-item',
|
||||
'navigation-rail-section',
|
||||
'section-nav',
|
||||
]);
|
||||
|
||||
/**
|
||||
|
||||
@@ -110,16 +110,23 @@ it('draws section navigation as secondary tabs and a picker', function () {
|
||||
|
||||
expect($html)
|
||||
->toContain('aria-label="Settings"')
|
||||
->toContain('data-section-picker')
|
||||
->toContain('data-md-section-nav-picker')
|
||||
->toContain('data-md-variant="secondary"')
|
||||
->toContain('max-medium:hidden')
|
||||
->toMatch('/href="\/settings\/security"\s+data-md-tab\s+aria-current="page"\s+wire:navigate/')
|
||||
->not->toMatch('/href="\/settings\/profile"\s+data-md-tab\s+aria-current/')
|
||||
// The picker is a menu of places: the current one is the page, not a checked choice,
|
||||
// and a section's badge shows there as well as on its tab.
|
||||
->not->toContain('role="menuitemcheckbox"')
|
||||
->toMatch('/role="menuitem"[^>]*aria-current="page"[^>]*href="\/settings\/security"/')
|
||||
->toMatch('/data-section-picker.*Security.*>\s*1\s*<.*<nav/s');
|
||||
->toMatch('/data-md-section-nav-picker.*Security.*>\s*1\s*<.*<nav/s');
|
||||
|
||||
// The picker shows only below medium, the tab bar only from it (N-16's compact fallback).
|
||||
$css = ComponentStylesheet::read('section-nav');
|
||||
|
||||
expect($css->declarations('[data-md-section-nav-picker]', ['@media (width >= 600px)']))
|
||||
->toBe(['display' => 'none'])
|
||||
->and($css->declarations('[data-md-section-nav] > nav', ['@media (width < 600px)']))
|
||||
->toBe(['display' => 'none']);
|
||||
});
|
||||
|
||||
it('marks the section whose url is the request\'s, and scrolls many sections', function () {
|
||||
@@ -131,7 +138,7 @@ it('marks the section whose url is the request\'s, and scrolls many sections', f
|
||||
// Five or more sections are M3's scrollable tabs, not a grid of wrapped rows (N-16).
|
||||
->toMatch('/<ul data-md-tabs-bar data-md-variant="secondary"\s+data-md-scrollable\s*>/')
|
||||
->not->toContain('grid-cols-')
|
||||
->toMatch('/data-md-tab\s+aria-current="page"\s*>\s*<span data-md-tab-content>\s*<span class="truncate">S3/')
|
||||
->toMatch('/data-md-tab\s+aria-current="page"\s*>\s*<span data-md-tab-content>\s*<span class="md-truncate">S3/')
|
||||
->not->toContain('wire:navigate')
|
||||
// Four still share the row.
|
||||
->and((string) $this->blade('<x-section-nav :items="$items" no-wire-navigate />', ['items' => array_slice($items, 0, 4)]))
|
||||
|
||||
Reference in New Issue
Block a user