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
75 lines
3.2 KiB
PHP
75 lines
3.2 KiB
PHP
{{-- One destination in an `<x-navigation-rail>`, drawn in whichever shape the rail has.
|
||
|
||
<x-navigation-rail-item label="Inbox" icon="inbox" link="{{ route('inbox') }}" :active="request()->routeIs('inbox')" badge="12" />
|
||
|
||
Expanded, it is a 56px full-width pill: the icon, the label-large label beside it and a count
|
||
at its end. Collapsed, the icon sits in a 56×32 indicator over a label-medium label (two lines
|
||
at most), with the count on the icon. The current destination (`active`) is
|
||
`aria-current="page"` with the filled icon on secondary-container, its label in secondary when
|
||
collapsed.
|
||
|
||
`link` renders an anchor with `wire:navigate` (unless `external` or `no-wire-navigate`);
|
||
without one it is a button. `badge`: `true` for M3's small dot on the icon, a number or a few
|
||
characters for the large badge (999+ at most). Screen readers hear a count after the label
|
||
(", 12"); `badge-label` replaces it with words ("12 unread") and gives a dot something to say.
|
||
|
||
Values from NavigationRailVerticalItemTokens.kt, NavigationRailHorizontalItemTokens.kt,
|
||
NavigationRailBaselineItemTokens.kt and NavigationRailColorTokens.kt (androidx Compose
|
||
Material 3, Apache-2.0); see `<x-navigation-rail>`. Compose's expanded item hugs its label; the
|
||
package draws the full-width pill, which leaves room for the count at the end. --}}
|
||
|
||
@props([
|
||
'label' => null,
|
||
'icon' => null,
|
||
'link' => null,
|
||
'external' => false,
|
||
'noWireNavigate' => false,
|
||
'active' => false,
|
||
'badge' => null,
|
||
'badgeLabel' => null,
|
||
])
|
||
|
||
@php
|
||
$isLink = filled($link);
|
||
$tag = $isLink ? 'a' : 'button';
|
||
$dot = $badge === true;
|
||
$count = ! $dot && $badge !== null && $badge !== false && $badge !== '';
|
||
$spoken = $badgeLabel ?? ($count ? $badge : null);
|
||
|
||
$attributes = $attributes->merge(array_filter([
|
||
'href' => $isLink ? $link : null,
|
||
'target' => $isLink && $external ? '_blank' : null,
|
||
'rel' => $isLink && $external ? 'noopener' : null,
|
||
'wire:navigate' => $isLink && ! $external && ! $noWireNavigate && ! $attributes->has('wire:navigate') ? true : null,
|
||
'type' => $isLink ? null : 'button',
|
||
'aria-current' => $active ? 'page' : null,
|
||
'data-active' => $active ? true : null,
|
||
], fn ($value): bool => $value !== null));
|
||
@endphp
|
||
|
||
<{{ $tag }} data-navigation-rail-item {{ $attributes }}>
|
||
<span data-navigation-indicator>
|
||
<span class="relative inline-flex">
|
||
@if ($icon)
|
||
<x-livewire-material::icon :name="$icon" :filled="$active" class="size-6" />
|
||
@endif
|
||
|
||
@if ($dot)
|
||
<x-livewire-material::badge floating />
|
||
@elseif ($count)
|
||
<span class="hidden rail-collapsed:contents"><x-livewire-material::badge :value="$badge" max="999" floating /></span>
|
||
@endif
|
||
</span>
|
||
</span>
|
||
|
||
<span data-navigation-label>{{ $label ?? $slot }}</span>
|
||
|
||
@if ($count)
|
||
<span class="flex shrink-0 rail-collapsed:hidden"><x-livewire-material::badge :value="$badge" max="999" /></span>
|
||
@endif
|
||
|
||
@if ($spoken !== null)
|
||
<span class="sr-only">, {{ $spoken }}</span>
|
||
@endif
|
||
</{{ $tag }}>
|