Leave a toolbar's filled button its own colours

M3's colour list for a standard toolbar ends "Standard button
(Primary)" and the vibrant list ends "Standard button (On primary
container)" (N-13) — both name the *standard* button. The two rules
painted every icon button in the toolbar instead, so a button that
brings its own container got a primary label on a primary fill and its
icon disappeared: SealShare's floating navigation marks the current page
with a filled button, and that button came out a blank circle.

A button that fills its own container is now left alone — filled, tonal,
or either of them selected — and keeps the label colour that goes with
the fill. A disabled button still falls back to button.css's disabled
ink in a toolbar of either colour, as before. AppBarTest pins the
exclusion on both rules.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Andreas Reinhold / reini
2026-09-15 22:23:16 +02:00
co-authored by Claude Opus 5
parent 5014d3e576
commit 5800ab1fe1
2 changed files with 19 additions and 5 deletions
+8 -4
View File
@@ -72,7 +72,7 @@
color: var(--md-sys-color-on-primary-container);
}
[data-md-toolbar][data-md-vibrant] [data-md-icon-button]:not([aria-pressed='true'], :disabled, [aria-disabled='true']) {
[data-md-toolbar][data-md-vibrant] [data-md-icon-button]:not([data-md-variant='filled'], [data-md-variant='tonal'], [data-md-selected='true'], [aria-pressed='true'], :disabled, [aria-disabled='true']) {
color: var(--md-sys-color-on-primary-container);
}
@@ -82,9 +82,13 @@
}
/* M3's colour list for a standard toolbar ends "Standard button (Primary)", as the vibrant list
ends "Standard button (On primary container)" — the row above (N-13). A disabled button keeps
button.css's disabled colours in either. */
[data-md-toolbar]:not([data-md-vibrant]) [data-md-icon-button]:not([aria-pressed='true'], :disabled, [aria-disabled='true']) {
ends "Standard button (On primary container)" — the row above (N-13). Both rows name the
*standard* button, so a button that fills its own container is left alone: it carries the
matching label colour (`filled` on-primary, `tonal` on-tone, either selected), and painting
that label primary put a primary icon on a primary fill — the current page's button in a
navigation toolbar came out a blank circle. A disabled button keeps button.css's disabled
colours in either. */
[data-md-toolbar]:not([data-md-vibrant]) [data-md-icon-button]:not([data-md-variant='filled'], [data-md-variant='tonal'], [data-md-selected='true'], [aria-pressed='true'], :disabled, [aria-disabled='true']) {
color: var(--md-sys-color-primary);
}
+11 -1
View File
@@ -212,9 +212,19 @@ it('keeps a toolbar at the bottom clear of the navigation bar', function () {
->and($css->declarations('[data-md-toolbar][data-md-vertical][data-md-toolbar-place=\'end\'], [data-md-toolbar-group][data-md-vertical][data-md-toolbar-place=\'end\']'))
->toBe(['inset-inline-end' => 'calc(var(--md-sys-measurement-space300) + var(--material-safe-right, env(safe-area-inset-right)))'])
// A standard toolbar's standard buttons are primary (N-13).
->and($css->declarations('[data-md-toolbar]:not([data-md-vibrant]) [data-md-icon-button]:not([aria-pressed=\'true\'], :disabled, [aria-disabled=\'true\'])'))
->and($css->declarations('[data-md-toolbar]:not([data-md-vibrant]) [data-md-icon-button]:not([data-md-variant=\'filled\'], [data-md-variant=\'tonal\'], [data-md-selected=\'true\'], [aria-pressed=\'true\'], :disabled, [aria-disabled=\'true\'])'))
->toBe(['color' => 'var(--md-sys-color-primary)']);
// N-13 names the *standard* button, so a button that fills its own container keeps the label
// colour that goes with that fill: a filled button painted primary put a primary icon on a
// primary fill, and the current page's button in a navigation toolbar came out a blank circle.
foreach (['[data-md-toolbar]:not([data-md-vibrant]) [data-md-icon-button]', '[data-md-toolbar][data-md-vibrant] [data-md-icon-button]'] as $scope) {
preg_match_all('/'.preg_quote($scope, '/').':not\([^{]*\{[^}]*\bcolor:/', $css->css, $rules);
expect($rules[0])->not->toBeEmpty()
->each->toContain("[data-md-variant='filled']", "[data-md-variant='tonal']", "[data-md-selected='true']");
}
// A disabled icon button keeps button.css's disabled ink in a toolbar of either colour.
foreach (['[data-md-toolbar]:not([data-md-vibrant]) [data-md-icon-button]', '[data-md-toolbar][data-md-vibrant] [data-md-icon-button]'] as $scope) {
preg_match_all('/'.preg_quote($scope, '/').'[^{]*\{[^}]*\bcolor:/', $css->css, $rules);