From e6f4357a2a28aeb64953f7ae3eadaa8b96f120c6 Mon Sep 17 00:00:00 2001 From: Andreas Reinhold / reini Date: Sun, 13 Sep 2026 21:08:55 +0200 Subject: [PATCH] Add a solid status label to the badge A status label came tonal (the colour's container) or outlined; a label that has to stand out in the colour itself fell back to the filled count, which is 16px and hidden from screen readers. solid draws the label shape in the colour's filled pair and is spoken like the others. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01RHoXZSHc8gGpZjFmA5fPc2 --- .../skills/livewire-material-development/SKILL.md | 2 +- resources/views/components/badge.blade.php | 10 ++++++---- .../showcase/sections/communication.blade.php | 1 + tests/Feature/Components/BadgeTest.php | 14 ++++++++++++++ 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/resources/boost/skills/livewire-material-development/SKILL.md b/resources/boost/skills/livewire-material-development/SKILL.md index 3c35741e..a90f6c44 100644 --- a/resources/boost/skills/livewire-material-development/SKILL.md +++ b/resources/boost/skills/livewire-material-development/SKILL.md @@ -353,7 +353,7 @@ A value the server changes animates after a morph (the SVG is `wire:ignore`; onl ### `` - `` — M3's small badge, a dot. `` — M3's large badge, a count. Both `error` by default. `floating` pins it to the top-end corner of a `relative` parent: ``. A dot or count is `aria-hidden` unless it has a `label`; name the control instead ("Messages, 4 unread"). -- ``, ``, `` — a status label (not an M3 badge) in the colour's container or a neutral edge. `color` (alias `tone`): `error` default, `primary`, `secondary`, `tertiary`, `success`, `warning`, `info`, `neutral`, `plain`; an unknown colour is `error`. +- ``, ``, ``, `` — a status label (not an M3 badge) in the colour's container, in the colour itself (`solid`, for a label that has to stand out), or a neutral edge. `color` (alias `tone`): `error` default, `primary`, `secondary`, `tertiary`, `success`, `warning`, `info`, `neutral`, `plain`; an unknown colour is `error`. - `color="neutral"` — neutral ink on every variant: a dot or count in on-surface-variant with surface text, `tonal` in surface-container-high with on-surface-variant text, `outline` in the outline-variant edge with on-surface-variant text. - `color="plain"` — no background, text or border colour in any variant (shape, size and type stay), so the classes you pass paint it: ``. Pass both a background and a text class; an `outline` badge's edge takes the text colour unless you pass a `border-*` colour. - The value is `value` or the slot; the slot renders as HTML: ` Pro`. `value` is escaped. A slot that holds only whitespace or comments is still a dot. diff --git a/resources/views/components/badge.blade.php b/resources/views/components/badge.blade.php index 00dec897..181642b2 100644 --- a/resources/views/components/badge.blade.php +++ b/resources/views/components/badge.blade.php @@ -10,7 +10,8 @@ The status label is not an M3 badge but every app needs one: `tonal` draws the value in the - colour's container ("Expired" in error-container), `outline` in a neutral edge. `color` (alias + colour's container ("Expired" in error-container), `solid` in the colour itself (a label that + has to stand out, "Built in" in primary), `outline` in a neutral edge. `color` (alias `tone`): `error` (the default), `primary`, `secondary`, `tertiary`, `success`, `warning`, `info`, and two without a hue of their own: - `neutral` — neutral ink on every variant: on-surface-variant with surface text as a dot or @@ -31,6 +32,7 @@ 'color' => null, 'tone' => null, 'tonal' => false, + 'solid' => false, 'outline' => false, 'floating' => false, 'label' => null, @@ -42,7 +44,7 @@ $markup = $value === null && $slot->hasActualContent(); $text = $value ?? ($markup ? trim((string) $slot) : null); $dot = blank($text); - $status = ($tonal || $outline) && ! $dot; + $status = ($tonal || $solid || $outline) && ! $dot; if (! $dot && $max !== null && is_numeric($text) && (int) $text > (int) $max) { $text = $max.'+'; @@ -61,7 +63,7 @@ ]; $paint = match (true) { $color === 'plain' => '', - ! $status => $filled[$color], + ! $status, $solid => $filled[$color], $tonal => $container[$color], default => 'border-outline-variant text-on-surface-variant', }; @@ -72,7 +74,7 @@ 'size-1.5 rounded-corner-full' => $dot, 'h-4 min-w-4 rounded-corner-full px-1 type-label-sm tabular-nums' => ! $dot && ! $status, 'h-6 gap-1 rounded-corner-sm px-2 type-label-md' => $status, - 'border' => $outline && ! $tonal && ! $dot, + 'border' => $outline && ! $tonal && ! $solid && ! $dot, $paint => $paint !== '', 'absolute top-0.5 end-0.5' => $floating && $dot, 'absolute -top-1 start-[calc(100%-0.75rem)]' => $floating && ! $dot, diff --git a/resources/views/showcase/sections/communication.blade.php b/resources/views/showcase/sections/communication.blade.php index 5cc7c320..fd2a9cc6 100644 --- a/resources/views/showcase/sections/communication.blade.php +++ b/resources/views/showcase/sections/communication.blade.php @@ -7,6 +7,7 @@ + diff --git a/tests/Feature/Components/BadgeTest.php b/tests/Feature/Components/BadgeTest.php index 4c8cd824..056603e4 100644 --- a/tests/Feature/Components/BadgeTest.php +++ b/tests/Feature/Components/BadgeTest.php @@ -76,3 +76,17 @@ it('keeps its default colours, and falls back to error on a colour it does not k ->toContain('class="inline-flex shrink-0 items-center justify-center whitespace-nowrap h-6 gap-1 rounded-corner-sm px-2 type-label-md border border-outline-variant text-on-surface-variant"') ->and((string) $this->blade(''))->toContain('bg-error text-on-error'); }); + +it('draws a solid status label in the colour itself, spoken like any label', function () { + $html = (string) $this->blade(''); + + expect($html) + ->toContain('bg-primary text-on-primary') + ->toContain('h-6 gap-1 rounded-corner-sm px-2 type-label-md') + ->not->toContain('aria-hidden') + ->toContain('>Built in<') + ->and((string) $this->blade('')) + ->toContain('bg-on-surface-variant text-surface') + ->and((string) $this->blade('')) + ->toContain('size-1.5'); +});