{{-- M3 Expressive's loading indicator: a shape that morphs through seven Expressive shapes while it turns, for a wait that has no known length. In the text colour — primary unless the caller colours it — and 48px unless sized. `contained` puts it on a primary-container circle, for a spinner over content. It is a `progressbar` named `label` ("Loading" by default); pass `:label="false"` where something else already says what is happening, as a button's own spinner does. Pure SVG with SMIL, so it animates in every engine without script. Under `prefers-reduced-motion` the shape rests. The geometry is androidx Compose Material 3's LoadingIndicator and Morph, ported in bin/loading-indicator.mjs (Apache-2.0): LoadingIndicatorTokens' 38px indicator in a 48px container, a morph every 650ms on a spring, a quarter turn per morph and a full turn every 4666ms. --}} @props([ 'contained' => false, 'label' => null, ]) @php $sized = preg_match('/(^|\s)(size|w|h)-/', (string) $attributes->get('class')) === 1; $coloured = preg_match('/(^|\s)text-(?!(xs|sm|base|lg|xl|[2-9]xl|left|center|right|start|end)(\s|$))/', (string) $attributes->get('class')) === 1; $decorative = $label === false; $label = $decorative ? null : ($label ?? __('Loading')); $attributes = $attributes ->class([ 'inline-flex shrink-0 items-center justify-center', 'size-12' => ! $sized, 'rounded-corner-full bg-primary-container text-on-primary-container' => $contained, 'text-primary' => ! $contained && ! $coloured, ]) ->merge(array_filter([ 'role' => $decorative ? null : 'progressbar', 'aria-label' => $label, 'aria-hidden' => $decorative ? 'true' : null, ])); @endphp {{ \NoNameWeb\LivewireMaterial\Support\SvgFile::loadingIndicator(true, new \Illuminate\View\ComponentAttributeBag(['class' => 'size-full motion-reduce:hidden', 'aria-hidden' => 'true', 'focusable' => 'false'])) }} {{ \NoNameWeb\LivewireMaterial\Support\SvgFile::loadingIndicator(false, new \Illuminate\View\ComponentAttributeBag(['class' => 'hidden size-full motion-reduce:block', 'aria-hidden' => 'true', 'focusable' => 'false'])) }}