{{-- An M3 Expressive FAB menu: a FAB that opens into a short list of related actions.
Two to six items. The FAB (`icon`, `add` by default, in `color`'s container) turns into a round close button in the colour itself while the list is open above it, end-aligned; the list is a `popover="auto"` menu with the menu keyboard of ``. `label` names the FAB and the menu for screen readers, and defaults to "Toggle menu" — the icons inside the button are aria-hidden, so without it the trigger has no name at all. Give the items the same `color`. Like ``'s, the list is keyed for Livewire, so it stays open through a render of the component around it. It does not place itself. M3's margin from the edge of the window is 16dp, and 24dp from the `large` class up: `fixed end-4 bottom-4 large:end-6 large:bottom-6`. A window too short for the list scrolls it; the items rise into place as it opens and sink back as it closes. FabMenuBaselineTokens (androidx Compose Material 3, Apache-2.0): 56px items, 4px apart, 8px above the close button. The FAB's corner and colours morph on the two default springs at once (`state-transition-default`, resources/css/components/actions.css). --}} @props([ 'icon' => 'add', 'label' => null, 'color' => 'primary', 'position' => 'top-end', ]) @php // The trigger's only content is two icons, which are aria-hidden, so without a name it is an // unnamed button. M3 asks the FAB's label to say what menu it opens; "Toggle menu" is its own // fallback wording for the close button. $label = filled($label) ? $label : __('Toggle menu'); $color = in_array($color, ['primary', 'secondary', 'tertiary'], true) ? $color : 'primary'; $key = \Illuminate\Support\Str::lower(\Illuminate\Support\Str::random(10)); $anchor = "--material-fab-menu-{$key}"; $colours = [ 'primary' => 'bg-primary-container text-on-primary-container aria-expanded:bg-primary aria-expanded:text-on-primary', 'secondary' => 'bg-secondary-container text-on-secondary-container aria-expanded:bg-secondary aria-expanded:text-on-secondary', 'tertiary' => 'bg-tertiary-container text-on-tertiary-container aria-expanded:bg-tertiary aria-expanded:text-on-tertiary', ][$color]; @endphp
class('relative inline-flex') }}>
'material-fab-menu']) }} id="material-fab-menu-{{ $key }}" popover="auto" role="menu" data-fab-menu aria-label="{{ $label }}" tabindex="-1" style="position-anchor: {{ $anchor }}" x-on:keydown="navigate($event)" x-on:click="activate($event)" @class([ 'm-0 flex-col gap-1 border-0 bg-transparent p-2 open:flex [inset:auto]', // A landscape phone has no room for six 56px items: the list scrolls, the FAB below it // does not. The 8px padding is the gap M3 leaves above the FAB and the room the items' // elevation needs inside the scroll box; the negative margins put it back where it was. 'max-h-[calc(100dvh-8rem)] overflow-y-auto', 'transition-[display,overlay] transition-discrete duration-(--md-sys-motion-spatial-fast-duration)', '-mx-2 -mt-2 items-end [position-area:top_span-left]' => $position === 'top-end', '-mx-2 -mt-2 items-start [position-area:top_span-right]' => $position === 'top-start', '-mx-2 -mb-2 items-end [position-area:bottom_span-left]' => $position === 'bottom-end', '-mx-2 -mb-2 items-start [position-area:bottom_span-right]' => $position === 'bottom-start', ]) > {{ $slot }}