{{-- An M3 Expressive floating action button: the screen's primary action. With only an `icon` it is a FAB — `size` `sm` 56px (the default; M3's deprecated small FAB is gone, so this is the baseline FAB), `md` 80px, `lg` 96px. With a `label` it is an extended FAB at the same three heights. `color` is `primary` (the default), `secondary` or `tertiary`, drawn in its container, or in the colour itself with `variant="filled"`. It does not place itself: put it where the layout wants it, e.g. `
`. For a create action that is a FAB on a phone and a header button above, use ``. The glyph is filled, not outlined: M3 says so twice, in the FAB's anatomy and again in its guidelines ("icon should be filled (not outlined) and unambiguous"). There is no `disabled`: M3 says never to disable a FAB — "if its action is unavailable, remove the FAB entirely instead" — so hide it (`@if`), or leave it out of the render, rather than greying it out. A form-submit FAB that must not be pressed twice takes the caller's own `wire:loading.attr="disabled"`. `data-md-fab` marks the root, so a place a FAB sits in can draw it its own way: a navigation rail flattens a nested FAB to elevation 0. `collapse-on-scroll` is M3's extended FAB that "can collapse to a FAB on scroll-down and re-expand to extended on scroll-up": while the window scrolls down it shrinks to the FAB of its size, and it extends again when the page scrolls back up or reaches the top. The label closes and fades while the width follows it on the spatial spring; under reduced motion the two swap outright. The label stays in the page, clipped rather than removed, so the collapsed FAB keeps its accessible name. It needs an `icon` — a FAB with no glyph is no FAB — and does nothing on a plain FAB. Sizes, corners and elevation from FabBaseline/Medium/LargeTokens and ExtendedFab*Tokens (androidx Compose Material 3, Apache-2.0), drawn by resources/css/components/fab.css. --}} @props([ 'icon' => null, 'label' => null, 'size' => 'sm', 'color' => 'primary', 'variant' => 'container', 'link' => null, 'external' => false, 'tooltip' => null, 'type' => 'button', 'collapseOnScroll' => false, ]) @php $size = in_array($size, ['sm', 'md', 'lg'], true) ? $size : 'sm'; $color = in_array($color, ['primary', 'secondary', 'tertiary'], true) ? $color : 'primary'; $variant = $variant === 'filled' ? 'filled' : 'container'; $extended = filled($label) || $slot->isNotEmpty(); $collapsing = $collapseOnScroll && $extended && filled($icon); $isLink = filled($link); $iconSize = ['sm' => 24, 'md' => 28, 'lg' => 32][$size]; $anchor = $tooltip !== null ? '--material-fab-'.\Illuminate\Support\Str::lower(\Illuminate\Support\Str::random(10)) : null; $tag = $isLink ? 'a' : 'button'; $attributes = $attributes->merge(array_filter([ // The hook a place uses to draw a nested FAB its own way: a rail flattens it to 0dp. 'data-md-fab' => true, 'data-md-size' => $size, 'data-md-color' => $color, 'data-md-variant' => $variant, 'data-md-extended' => $extended ? true : null, 'data-md-collapse-on-scroll' => $collapsing ? true : null, 'href' => $isLink ? $link : null, 'target' => $isLink && $external ? '_blank' : null, 'rel' => $isLink && $external ? 'noopener' : null, 'wire:navigate' => $isLink && ! $external && ! $attributes->has('wire:navigate') ? true : null, 'type' => $isLink ? null : $type, 'x-data' => $collapsing ? 'materialFab' : null, 'x-bind:data-md-collapsed' => $collapsing ? "collapsed ? '' : null" : null, 'aria-label' => ! $extended && ! $attributes->has('aria-label') ? $tooltip : null, 'style' => $anchor ? "anchor-name: {$anchor}" : null, ], fn ($value): bool => $value !== null))->class(['md-state-layer', 'md-focus-ring']); @endphp <{{ $tag }} {{ $attributes }}> @if ($icon) @endif @if ($collapsing) {{ $label ?? $slot }} @elseif ($extended) {{ $label ?? $slot }} @endif @if ($tooltip !== null) @endif