{{-- An M3 Expressive menu: a list of actions that opens from a trigger. The trigger's first button or link becomes the menu button (aria-haspopup, aria-expanded, aria-controls). The list is a `popover="auto"` in the top layer, placed by CSS anchor positioning at `position` (`bottom-start`, `bottom-end`, `top-start`, `top-end`) and flipping when there is no room — to the other side, the other end, or both, so a menu on a FAB in a corner of the window opens back across it; a click outside or Escape closes it. The keyboard is WAI-ARIA's menu button: Enter, Space or ArrowDown open on the first item, ArrowUp on the last; arrows, Home, End and typing a letter move between items; Tab closes; activating an item closes the menu unless the item says `keep-open`, and Escape returns focus to the trigger. The anchor name is rendered on the wrapper around the trigger slot, the only element the server can name, and resources/js/menu.js moves it onto the menu button itself: a trigger that is `position: fixed` (`` on a phone) leaves the wrapper behind as an empty box where the page put it, and the menu opened there. The id and the anchor name are new with every render. The popover carries a `wire:key`, which a Livewire morph matches it by before the id, so a render of the component around an open menu patches it in place — still open, focus and listeners kept — instead of swapping in a closed copy; menu.js then writes the menu button's ARIA attributes again. The key goes through an attribute bag: Livewire compiles a `wire:key` written in a template into the key of the loop iteration around it, which would give every child component after the menu the same key. The container is Expressive's standard menu (surface-container-low, 16px corner, elevation 2), or `vibrant` in tertiary-container — StandardMenuTokens and VibrantMenuTokens from androidx Compose Material 3 (Apache-2.0). --}} @props([ 'label' => null, 'position' => 'bottom-start', 'vibrant' => false, ]) @php $position = in_array($position, ['bottom-start', 'bottom-end', 'top-start', 'top-end'], true) ? $position : 'bottom-start'; $key = \Illuminate\Support\Str::lower(\Illuminate\Support\Str::random(10)); $anchor = "--material-menu-{$key}"; @endphp
class('relative inline-flex') }}> {{ $trigger }}
'material-menu']) }} id="material-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 min-w-28 max-w-70 overflow-visible border-0 p-1 rounded-corner-lg shadow-elevation-2 [inset:auto]', 'my-1 [position-try-fallbacks:flip-block,flip-inline,flip-block_flip-inline]', 'opacity-0 transition-[opacity,translate,display,overlay] transition-discrete duration-(--md-sys-motion-effects-fast-duration) ease-effects-fast open:opacity-100 starting:open:opacity-0', 'bg-surface-container-low text-on-surface' => ! $vibrant, 'bg-tertiary-container text-on-tertiary-container' => $vibrant, '[position-area:bottom_span-right]' => $position === 'bottom-start', '[position-area:bottom_span-left]' => $position === 'bottom-end', '[position-area:top_span-right]' => $position === 'top-start', '[position-area:top_span-left]' => $position === 'top-end', ]) > {{ $slot }}