Lift a bottom-placed toolbar above the navigation bar
`place="bottom"` ignored --material-bottom-bar, so a floating toolbar overlapped the shell's navigation bar and a docked one landed squarely on it. Both now clear it — max(), not a sum, since that height already swallows the bottom safe area — and the docs say what M3 says: never show a docked toolbar and a navigation bar together. Plan: docs/plans/material-3-alignment.md, step 14 (navigation N-02). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
This commit is contained in:
co-authored by
Claude Opus 5
parent
4a4982b1ef
commit
700869ded4
@@ -789,6 +789,8 @@ M3 Expressive toolbar, `role="toolbar"` (arrow keys move between controls). `var
|
|||||||
</x-toolbar>
|
</x-toolbar>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
A docked toolbar and a navigation bar occupy the same screen region and must never be on screen together: show the bar on a primary page and the toolbar on a secondary or contextual one. A `place="bottom"` toolbar clears `--material-bottom-bar` if a bar is there anyway, so nothing is buried.
|
||||||
|
|
||||||
### `<x-tabs>`, `<x-tab>`
|
### `<x-tabs>`, `<x-tab>`
|
||||||
|
|
||||||
M3 tabs with a server-rendered tablist (arrow keys, Home/End, disabled tabs skipped, the indicator moves in a view transition). `tabs`: `['name', 'label', 'icon', 'badge', 'disabled']`; panels are `<x-tab name>` in the slot. Bind with `wire:model` (entangled), or `selected` / `x-model` without Livewire. `variant` `primary` (default) or `secondary`; `stacked` (icon over label), `scrollable`. Give two identical tab sets on one page distinct `id`s.
|
M3 tabs with a server-rendered tablist (arrow keys, Home/End, disabled tabs skipped, the indicator moves in a view transition). `tabs`: `['name', 'label', 'icon', 'badge', 'disabled']`; panels are `<x-tab name>` in the slot. Bind with `wire:model` (entangled), or `selected` / `x-model` without Livewire. `variant` `primary` (default) or `secondary`; `stacked` (icon over label), `scrollable`. Give two identical tab sets on one page distinct `id`s.
|
||||||
|
|||||||
@@ -71,10 +71,17 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Placed over the page: centred above the bottom edge, or centred against the end edge. */
|
/* Placed over the page: centred above the bottom edge, or centred against the end edge.
|
||||||
|
*
|
||||||
|
* A toolbar at the bottom shares the screen region with a navigation bar, so it clears the one
|
||||||
|
* <x-app-shell> publishes as --material-bottom-bar, exactly as the FAB and the snackbar do —
|
||||||
|
* `max()`, not a sum, because that height already swallows the bottom safe area; without a bar
|
||||||
|
* the safe area alone applies. A *docked* toolbar and a navigation bar must never be on screen
|
||||||
|
* together at all (docs/reference/m3/components-navigation-selection-inputs.md § Toolbars); the
|
||||||
|
* offset is the backstop, not a licence. */
|
||||||
[data-toolbar-place="bottom"] {
|
[data-toolbar-place="bottom"] {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: calc(1rem + var(--material-safe-bottom, env(safe-area-inset-bottom)));
|
bottom: calc(max(var(--material-bottom-bar, 0px), var(--material-safe-bottom, env(safe-area-inset-bottom))) + 1rem);
|
||||||
left: 50%;
|
left: 50%;
|
||||||
z-index: 30;
|
z-index: 30;
|
||||||
translate: -50% 0;
|
translate: -50% 0;
|
||||||
@@ -90,7 +97,7 @@
|
|||||||
|
|
||||||
[data-toolbar][data-variant="docked"][data-toolbar-place="bottom"] {
|
[data-toolbar][data-variant="docked"][data-toolbar-place="bottom"] {
|
||||||
inset-inline: 0;
|
inset-inline: 0;
|
||||||
bottom: 0;
|
bottom: var(--material-bottom-bar, 0px);
|
||||||
left: 0;
|
left: 0;
|
||||||
translate: none;
|
translate: none;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,11 @@
|
|||||||
toolbar sits where it is written. A `fab` slot sets an `<x-fab>` beside a floating toolbar.
|
toolbar sits where it is written. A `fab` slot sets an `<x-fab>` beside a floating toolbar.
|
||||||
`label` names it for screen readers.
|
`label` names it for screen readers.
|
||||||
|
|
||||||
|
A docked toolbar and a navigation bar occupy the same region of the screen and M3 says never to
|
||||||
|
show both at once: the bar belongs on a primary page, the toolbar on a secondary or contextual
|
||||||
|
one. Either way a toolbar placed at `bottom` clears `--material-bottom-bar`, so it is never
|
||||||
|
buried under `<x-app-shell>`'s bar.
|
||||||
|
|
||||||
Put `<x-button icon="…" tooltip="…" />` controls in the slot (`:selected` for toggles). It is a
|
Put `<x-button icon="…" tooltip="…" />` controls in the slot (`:selected` for toggles). It is a
|
||||||
`role="toolbar"`: the arrow keys move between its controls (resources/js/toolbar.js,
|
`role="toolbar"`: the arrow keys move between its controls (resources/js/toolbar.js,
|
||||||
resources/css/components/toolbar.css). --}}
|
resources/css/components/toolbar.css). --}}
|
||||||
|
|||||||
@@ -69,6 +69,15 @@ it('draws floating and docked toolbars', function () {
|
|||||||
->not->toContain('data-toolbar-group');
|
->not->toContain('data-toolbar-group');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('keeps a toolbar at the bottom clear of the navigation bar', function () {
|
||||||
|
$css = file_get_contents(__DIR__.'/../../../resources/css/components/toolbar.css');
|
||||||
|
|
||||||
|
expect($css)
|
||||||
|
// Never a sum: --material-bottom-bar already swallows the bottom safe area (N-02).
|
||||||
|
->toContain('bottom: calc(max(var(--material-bottom-bar, 0px), var(--material-safe-bottom, env(safe-area-inset-bottom))) + 1rem);')
|
||||||
|
->toContain('bottom: var(--material-bottom-bar, 0px);');
|
||||||
|
});
|
||||||
|
|
||||||
it('offers M3\'s three contrast levels, marking the one in force', function () {
|
it('offers M3\'s three contrast levels, marking the one in force', function () {
|
||||||
expect((string) $this->blade('<x-theme-toggle mode="contrast" />'))
|
expect((string) $this->blade('<x-theme-toggle mode="contrast" />'))
|
||||||
->toContain('data-theme-toggle="contrast"')
|
->toContain('data-theme-toggle="contrast"')
|
||||||
|
|||||||
Reference in New Issue
Block a user