Files
livewire-material/resources/views/components/fab-menu.blade.php
T
Andreas Reinhold / reiniandClaude Opus 5 1e580c573e Resolve the package's own components through its namespace
Package views now write <x-livewire-material::button>, so a configured
prefix (which Blade spells <x-m::button>) and an application component
of the same name can no longer break or shadow them. The showcase
rewrites its examples to the configured prefix. Adds the README, and
waits for the adaptive rail to hear a resize before the navigation
tests press its menu button.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9NnLxnPp8vaaurb3Z1MFy
2026-09-13 09:05:24 +02:00

78 lines
3.5 KiB
PHP

{{-- An M3 Expressive FAB menu: a FAB that opens into a short list of related actions.
<div class="fixed end-4 bottom-4">
<x-fab-menu label="New">
<x-fab-menu-item label="Upload files" icon="upload_file" wire:click="uploadFiles" />
<x-fab-menu-item label="Upload a folder" icon="drive_folder_upload" wire:click="uploadFolder" />
</x-fab-menu>
</div>
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 `<x-menu>`. `label` names the FAB
for screen readers. Give the items the same `color`.
FabMenuBaselineTokens (androidx Compose Material 3, Apache-2.0): 56px items, 4px apart, 8px
above the close button. --}}
@props([
'icon' => 'add',
'label' => null,
'color' => 'primary',
'position' => 'top-end',
])
@php
$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
<div x-data="materialMenu" {{ $attributes->class('relative inline-flex') }}>
<span x-ref="trigger" class="inline-flex" style="anchor-name: {{ $anchor }}"
x-on:click="toggle('first')"
x-on:keydown.down.prevent="open('first')"
x-on:keydown.up.prevent="open('last')"
>
<button
type="button"
@if ($label) aria-label="{{ $label }}" @endif
@class([
'group/fab state-layer focus-ring inline-flex size-14 shrink-0 cursor-pointer items-center justify-center rounded-corner-lg shadow-elevation-3 hover:shadow-elevation-4',
'transition-[border-radius,background-color,color,box-shadow] duration-(--md-sys-motion-spatial-default-duration) ease-spatial-default aria-expanded:rounded-corner-full',
$colours,
])
>
<x-livewire-material::icon :name="$icon" class="size-6 group-aria-expanded/fab:hidden" />
<x-livewire-material::icon name="close" class="hidden size-5 group-aria-expanded/fab:block" />
</button>
</span>
<div
x-ref="menu"
id="material-fab-menu-{{ $key }}"
popover="auto"
role="menu"
@if ($label) aria-label="{{ $label }}" @endif
tabindex="-1"
style="position-anchor: {{ $anchor }}"
x-on:keydown="navigate($event)"
x-on:click="activate($event)"
@class([
'm-0 flex-col gap-1 overflow-visible border-0 bg-transparent p-0 open:flex [inset:auto]',
'mb-2 items-end [position-area:top_span-left]' => $position === 'top-end',
'mb-2 items-start [position-area:top_span-right]' => $position === 'top-start',
'mt-2 items-end [position-area:bottom_span-left]' => $position === 'bottom-end',
'mt-2 items-start [position-area:bottom_span-right]' => $position === 'bottom-start',
])
>
{{ $slot }}
</div>
</div>