tests / lint (push) Successful in 1m3s
tests / feature (8.4) (push) Failing after 1m5s
tests / feature (8.5) (push) Failing after 1m4s
tests / browser (chrome, chromium) (push) Failing after 1m5s
tests / browser (firefox, firefox) (push) Failing after 1m1s
tests / browser (safari, webkit) (push) Failing after 1m1s
<x-toast> hosts the snackbar queue for the Toasts concern and window.materialToast(), one at a time, paused on hover and focus, with an optional action; it listens from the moment its script loads, so a toast dispatched before Alpine starts is shown rather than lost. <x-badge> is M3's dot and count, plus a tonal or outlined status label; <x-rich-tooltip> is transient or persistent; <x-alert>, <x-stat> and <x-empty-state> are built from M3's parts. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V9NnLxnPp8vaaurb3Z1MFy
68 lines
3.4 KiB
PHP
68 lines
3.4 KiB
PHP
{{-- A badge: M3's count or dot on an icon, or a short status label.
|
|
|
|
M3's two badges (BadgeTokens, androidx Compose Material 3, Apache-2.0):
|
|
- `<x-badge />` — the small badge, a 6px dot: something new, no number.
|
|
- `<x-badge value="3" />` — the large badge, 16px tall, label-small: a count. `max` caps what is
|
|
shown ("99+").
|
|
Both are `error` by default, as M3 draws them. `floating` pins one to the top-end corner of a
|
|
`relative` parent — an icon or an icon button:
|
|
|
|
<span class="relative inline-flex"><x-icon name="notifications" /><x-badge value="4" floating /></span>
|
|
|
|
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
|
|
`tone`): `error` (the default), `primary`, `secondary`, `tertiary`, `success`, `warning`, `info`.
|
|
|
|
A count or dot says nothing to a screen reader on its own: give the icon's control a label
|
|
that includes it ("Notifications, 4 new"), or pass `label` here. --}}
|
|
|
|
@props([
|
|
'value' => null,
|
|
'max' => null,
|
|
'color' => null,
|
|
'tone' => null,
|
|
'tonal' => false,
|
|
'outline' => false,
|
|
'floating' => false,
|
|
'label' => null,
|
|
])
|
|
|
|
@php
|
|
$color = in_array($color ?? $tone, ['primary', 'secondary', 'tertiary', 'error', 'success', 'warning', 'info'], true) ? ($color ?? $tone) : 'error';
|
|
$text = $value ?? ($slot->isNotEmpty() ? trim((string) $slot) : null);
|
|
$dot = blank($text);
|
|
$status = ($tonal || $outline) && ! $dot;
|
|
|
|
if (! $dot && $max !== null && is_numeric($text) && (int) $text > (int) $max) {
|
|
$text = $max.'+';
|
|
}
|
|
|
|
$filled = [
|
|
'primary' => 'bg-primary text-on-primary', 'secondary' => 'bg-secondary text-on-secondary', 'tertiary' => 'bg-tertiary text-on-tertiary',
|
|
'error' => 'bg-error text-on-error', 'success' => 'bg-success text-on-success', 'warning' => 'bg-warning text-on-warning', 'info' => 'bg-info text-on-info',
|
|
];
|
|
$container = [
|
|
'primary' => 'bg-primary-container text-on-primary-container', 'secondary' => 'bg-secondary-container text-on-secondary-container', 'tertiary' => 'bg-tertiary-container text-on-tertiary-container',
|
|
'error' => 'bg-error-container text-on-error-container', 'success' => 'bg-success-container text-on-success-container', 'warning' => 'bg-warning-container text-on-warning-container', 'info' => 'bg-info-container text-on-info-container',
|
|
];
|
|
|
|
$attributes = $attributes
|
|
->class([
|
|
'inline-flex shrink-0 items-center justify-center whitespace-nowrap',
|
|
'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,
|
|
$filled[$color] => ! $status,
|
|
$container[$color] => $tonal && ! $dot,
|
|
'border border-outline-variant text-on-surface-variant' => $outline && ! $tonal && ! $dot,
|
|
'absolute top-0.5 end-0.5' => $floating && $dot,
|
|
'absolute -top-1 start-[calc(100%-0.75rem)]' => $floating && ! $dot,
|
|
])
|
|
->merge(array_filter([
|
|
'aria-label' => $label,
|
|
'aria-hidden' => $label === null && ! $status ? 'true' : null,
|
|
]));
|
|
@endphp
|
|
|
|
<span {{ $attributes }}>@unless ($dot){{ $text }}@endunless</span>
|