Draw the app bar without Tailwind
Plan step 36 (navigation group, first stream): <x-app-bar>'s class
lists move into resources/css/components/app-bar.css, keyed on
data-md-app-bar (with data-md-variant/-sticky/-subtitled/-scrolled/
-collapsed) and its parts data-md-app-bar-row/-leading/-headline/
-title/-subtitle/-search/-trailing/-action/-overflow/-expanded. The
overflow menu (two icon buttons below 600px, four from it, N-09's
312px search cap and N-11's three-column centred row) already matched
the audit; only its hooks, units and layer needed to change. Every
length is px, spacing through the measurement tokens where one
matches (M3's own "4dp leading/trailing space" and "16dp" headline
inset had no exact token, so those stay literal). Imports button.css,
menu.css and menu-item.css for the overflow menu the view renders.
Hooks renamed: every unprefixed data-app-bar-* attribute and
data-scrolled/data-collapsed to data-md-*, updated in
tests/Feature/Components/{AppBarTest,PaneTest}.php and
tests/Browser/{BarsTest,NavigationTest}.php. app-bar.js needed no
change: it reads the bar through $root, not by hook name.
tests/Feature/Components/NavigationStylesheetsTest.php is the
navigation twin of ContainmentStylesheetsTest.php, on the same
tests/Support/ViewClasses.php rule; its dataset starts at 'app-bar'
and a 'tabs' entry (once that commit lands) will read both
tabs.blade.php and tab.blade.php, since they share one stylesheet.
Added the owed browser tests (docs/plans/material-3-browser-tests.md):
the overflow at 599/600px, keyboard in its menu, a menu closing once
its width no longer shows it, and a wire:click action from both the
icon button and the menu item form.
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
b7f120af98
commit
b7641a35c2
@@ -6,7 +6,7 @@ it('draws a content region with a body and no app bar when it has no title', fun
|
||||
expect(layoutRoot($html))->toMatchArray(['<' => 'div', 'data-md-pane' => 'data-md-pane'])
|
||||
->not->toHaveKeys(['data-md-width', 'data-md-hide-below', 'data-md-hide-from'])
|
||||
->and($html)->toMatch('/<div data-md-pane-body>The page<\/div>/')
|
||||
->not->toContain('data-app-bar')
|
||||
->not->toContain('data-md-app-bar')
|
||||
->not->toContain('data-md-pane-navigation');
|
||||
});
|
||||
|
||||
@@ -19,18 +19,18 @@ it('gives the pane its own app bar, a direct child spanning it, with the title,
|
||||
BLADE);
|
||||
|
||||
expect($html)
|
||||
->toMatch('/^\s*<div data-md-pane[^>]*>\s*<header\b[^>]*data-app-bar[^>]*data-md-pane-bar/s')
|
||||
->toContain('<h2 data-app-bar-title>Settings</h2>')
|
||||
->toContain('<p data-app-bar-subtitle>Your account</p>')
|
||||
->toMatch('/<div data-app-bar-trailing><span>ACTIONS<\/span><\/div>/')
|
||||
->toContain('data-sticky')
|
||||
->toMatch('/^\s*<div data-md-pane[^>]*>\s*<header\b[^>]*data-md-app-bar[^>]*data-md-pane-bar/s')
|
||||
->toContain('<h2 data-md-app-bar-title>Settings</h2>')
|
||||
->toContain('<p data-md-app-bar-subtitle>Your account</p>')
|
||||
->toMatch('/<div data-md-app-bar-trailing><span>ACTIONS<\/span><\/div>/')
|
||||
->toContain('data-md-sticky')
|
||||
->toMatch('/<\/header>\s*<div data-md-pane-body>\s*BODY\s*<\/div>/s')
|
||||
->and((string) $this->blade('<x-pane title="Settings" :sticky="false" />'))->not->toContain('data-sticky');
|
||||
->and((string) $this->blade('<x-pane title="Settings" :sticky="false" />'))->not->toContain('data-md-sticky');
|
||||
});
|
||||
|
||||
it('draws a bar for actions alone, and names the heading h1 by default', function () {
|
||||
expect((string) $this->blade('<x-pane><x-slot:actions><span>ACTIONS</span></x-slot:actions></x-pane>'))->toContain('data-md-pane-bar')
|
||||
->and((string) $this->blade('<x-pane title="Inbox" />'))->toContain('<h1 data-app-bar-title>Inbox</h1>');
|
||||
->and((string) $this->blade('<x-pane title="Inbox" />'))->toContain('<h1 data-md-app-bar-title>Inbox</h1>');
|
||||
});
|
||||
|
||||
it('puts the section navigation under the bar and above the body', function () {
|
||||
@@ -43,7 +43,7 @@ it('puts the section navigation under the bar and above the body', function () {
|
||||
|
||||
expect($html)->toMatch('/<\/header>\s*<div data-md-pane-navigation><nav>SECTIONS<\/nav><\/div>\s*<div data-md-pane-body>\s*BODY/s')
|
||||
// It is the pane's section navigation, not the bar's leading button.
|
||||
->not->toContain('data-app-bar-leading');
|
||||
->not->toContain('data-md-app-bar-leading');
|
||||
});
|
||||
|
||||
it('leads the bar with a back link, a back action for a list-detail, or the leading slot', function () {
|
||||
@@ -51,12 +51,12 @@ it('leads the bar with a back link, a back action for a list-detail, or the lead
|
||||
$action = (string) $this->blade('<x-pane title="Message" back />');
|
||||
$leading = (string) $this->blade('<x-pane title="Inbox" back><x-slot:leading><button>MENU</button></x-slot:leading></x-pane>');
|
||||
|
||||
expect($link)->toMatch('/data-app-bar-leading><span data-md-pane-back\s*>/')
|
||||
expect($link)->toMatch('/data-md-app-bar-leading><span data-md-pane-back\s*>/')
|
||||
->toMatch('/<a[^>]*href="\/shares"[^>]*aria-label="Back"/s')
|
||||
->not->toContain('data-md-list-detail-back')
|
||||
->and($action)->toMatch('/<span data-md-pane-back\s+data-md-list-detail-back\s*>/')
|
||||
->toMatch('/<button[^>]*aria-label="Back"[^>]*x-on:click="back\(\)"/s')
|
||||
->and($leading)->toContain('<div data-app-bar-leading><button>MENU</button></div>')
|
||||
->and($leading)->toContain('<div data-md-app-bar-leading><button>MENU</button></div>')
|
||||
->not->toContain('data-md-pane-back');
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user