tests / browser (firefox, firefox) (push) Successful in 1m54s
tests / browser (safari, webkit) (push) Successful in 2m17s
tests / lint (push) Successful in 59s
tests / feature (8.4) (push) Successful in 1m7s
tests / feature (8.5) (push) Successful in 1m0s
tests / browser (chrome, chromium) (push) Successful in 1m49s
<x-button> (label buttons, icon buttons and toggles in five sizes, with filled, tonal, outlined, elevated and text variants in any colour role), <x-tooltip>, <x-menu> with items, groups and separators, <x-button-group>, <x-group> as a connected button group, <x-split-button>, <x-fab>, <x-fab-menu> and <x-loading>. Sizes, colours and shapes come from androidx Compose Material 3's tokens; the loading indicator ports its Morph into SVG + SMIL. Menus follow WAI-ARIA's menu button pattern on popovers placed by CSS anchor positioning. Browser tests run in Chromium, Firefox and WebKit. The showcase fetches the icon names on demand: inlined, they tripped Pest's test server into HTTP 431s under Firefox. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V9NnLxnPp8vaaurb3Z1MFy
48 lines
1.9 KiB
PHP
48 lines
1.9 KiB
PHP
{{-- One action in an `<x-fab-menu>`: a 56px pill with an icon and a label, rising into place as
|
|
the menu opens. `link` makes it an anchor (with `wire:navigate` unless `external`); `color`
|
|
should match the menu's. --}}
|
|
|
|
@props([
|
|
'label' => null,
|
|
'icon' => null,
|
|
'color' => 'primary',
|
|
'link' => null,
|
|
'external' => false,
|
|
])
|
|
|
|
@php
|
|
$isLink = filled($link);
|
|
$tag = $isLink ? 'a' : 'button';
|
|
|
|
$colours = [
|
|
'primary' => 'bg-primary-container text-on-primary-container',
|
|
'secondary' => 'bg-secondary-container text-on-secondary-container',
|
|
'tertiary' => 'bg-tertiary-container text-on-tertiary-container',
|
|
][in_array($color, ['primary', 'secondary', 'tertiary'], true) ? $color : 'primary'];
|
|
|
|
$attributes = $attributes
|
|
->class([
|
|
'state-layer inline-flex h-14 shrink-0 cursor-pointer items-center gap-2 rounded-corner-full px-6 whitespace-nowrap type-title-md shadow-elevation-3 outline-none',
|
|
'focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-secondary',
|
|
'transition-[translate,opacity] duration-(--md-sys-motion-spatial-fast-duration) ease-spatial-fast starting:translate-y-2 starting:opacity-0',
|
|
$colours,
|
|
])
|
|
->merge(array_filter([
|
|
'role' => 'menuitem',
|
|
'tabindex' => '-1',
|
|
'type' => $isLink ? null : 'button',
|
|
'href' => $isLink ? $link : null,
|
|
'target' => $isLink && $external ? '_blank' : null,
|
|
'rel' => $isLink && $external ? 'noopener' : null,
|
|
'wire:navigate' => $isLink && ! $external && ! $attributes->has('wire:navigate') ? true : null,
|
|
], fn ($value): bool => $value !== null));
|
|
@endphp
|
|
|
|
<{{ $tag }} {{ $attributes }}>
|
|
@if ($icon)
|
|
<x-icon :name="$icon" class="size-6" />
|
|
@endif
|
|
|
|
<span>{{ $label ?? $slot }}</span>
|
|
</{{ $tag }}>
|