Files
livewire-material/resources/views/components/split-button.blade.php
T
Andreas ReinholdandClaude Opus 5 d560e7449c Put the split button on its own geometry
It borrowed the connected group's corner variables, so its inner corners were
wrong at four of five sizes and shrank under the finger where SplitButton*Tokens
grows them; its chevron took the icon-button table's size at every step, sat dead
centre, and turned over on the expressive spring. groups.css now carries
--split-inner, --split-icon and --split-nudge per size, and the rotation uses
M3's standard scheme. Plan step 18, actions.md ACT-06, ACT-07, ACT-29, ACT-30.

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

76 lines
3.1 KiB
PHP

{{-- An M3 Expressive split button: an action, and a menu of its alternatives.
<x-split-button label="Download all" icon="download" wire:click="downloadZip" menu-label="Download options">
<x-menu-item label="Download as ZIP" wire:click="downloadZip" />
<x-menu-item label="Download files one by one" wire:click="downloadEach" />
</x-split-button>
Attributes (wire:click, spinner…) go to the leading button; the slot is the menu. `variant` is
`filled` (the default), `tonal`, `outlined` or `elevated` a text split button does not exist
in M3 with `color` and `size` as on `<x-button>`. The halves sit 2px apart; the trailing
one rounds fully and turns its chevron over while the menu is open. `menu-label` names the
trailing button and the menu for screen readers.
Padding from SplitButton*Tokens (androidx Compose Material 3, Apache-2.0): the leading button
keeps less room on its inner side at the two smallest sizes, and the trailing button is 48px
wide there. resources/css/components/groups.css carries the rest of the spec, which is all
geometry: the inner corners (4/4/4/8/12px, growing under the finger, not shrinking as a
connected group's do), the trailing icon's own size (22/22/26/38/50px, which the icon-button
table has no entry for), the 1/1/2/3/6px nudge that sits the chevron towards the leading half,
and the standard motion scheme M3 asks for while it turns over. --}}
@props([
'label' => null,
'icon' => null,
'variant' => 'filled',
'color' => 'primary',
'size' => 'sm',
'disabled' => false,
'spinner' => null,
'menuLabel' => null,
'position' => 'bottom-end',
])
@php
$variant = in_array($variant, ['filled', 'tonal', 'outlined', 'elevated'], true) ? $variant : 'filled';
$size = in_array($size, ['xs', 'sm', 'md', 'lg', 'xl'], true) ? $size : 'sm';
$menuLabel ??= __('More options');
$leadingPadding = ['xs' => 'pe-2.5', 'sm' => 'pe-3', 'md' => '', 'lg' => '', 'xl' => ''][$size];
$trailingWidth = ['xs' => 'w-12', 'sm' => 'w-12', 'md' => '', 'lg' => '', 'xl' => ''][$size];
@endphp
<div data-button-group="split" data-size="{{ $size }}" {{ $attributes->only('class')->class('inline-flex items-center gap-0.5') }}>
<x-livewire-material::button
{{ $attributes->except('class') }}
:label="$label"
:icon="$icon"
:variant="$variant"
:color="$color"
:size="$size"
:disabled="$disabled"
:spinner="$spinner"
corners=""
data-split="leading"
:class="$leadingPadding"
/>
<x-livewire-material::menu :position="$position" :label="$menuLabel">
<x-slot:trigger>
<x-livewire-material::button
icon="keyboard_arrow_down"
:aria-label="$menuLabel"
:variant="$variant"
:color="$color"
:size="$size"
:disabled="$disabled"
corners=""
data-split="trailing"
:class="$trailingWidth"
/>
</x-slot:trigger>
{{ $slot }}
</x-livewire-material::menu>
</div>