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
98 lines
4.5 KiB
PHP
98 lines
4.5 KiB
PHP
{{-- A choice of a few options as an M3 Expressive connected button group — the successor of the
|
|
segmented button.
|
|
|
|
<x-group label="Theme" wire:model.live="theme" :options="[
|
|
['id' => 'light', 'name' => 'Light', 'icon' => 'light_mode'],
|
|
['id' => 'dark', 'name' => 'Dark', 'icon' => 'dark_mode'],
|
|
]" />
|
|
|
|
Native radios under the segments (checkboxes with `multiple`), so `wire:model` and `x-model`
|
|
bind as on any input, the arrow keys move the choice, and a screen reader announces a group.
|
|
The chosen segment rounds fully and takes the selected colour; `variant` is `tonal` (the
|
|
default), `filled` or `outlined`, as for toggle buttons. The segments share the row unless
|
|
`inline`. An option with `'disabled' => true` greys its own segment.
|
|
|
|
ReStride's props, kept: `label`, `hint`, `name` (needed with `x-model`, which names no
|
|
property), `options`, `option-value`, `option-label`; plus `option-icon`, `size`, `variant`,
|
|
`multiple`, `inline`. A validation message for the bound property replaces the hint. --}}
|
|
|
|
@props([
|
|
'label' => null,
|
|
'hint' => null,
|
|
'name' => null,
|
|
'options' => [],
|
|
'optionValue' => 'id',
|
|
'optionLabel' => 'name',
|
|
'optionIcon' => 'icon',
|
|
'size' => 'sm',
|
|
'variant' => 'tonal',
|
|
'multiple' => false,
|
|
'inline' => false,
|
|
])
|
|
|
|
@php
|
|
$model = $attributes->whereStartsWith('wire:model')->first();
|
|
$name ??= $model;
|
|
$messages = $model !== null && isset($errors) ? \Illuminate\Support\Arr::flatten($errors->get($model)) : [];
|
|
$size = in_array($size, ['xs', 'sm', 'md', 'lg', 'xl'], true) ? $size : 'sm';
|
|
|
|
$segment = [
|
|
'xs' => 'h-8 gap-2 px-3 type-label-lg',
|
|
'sm' => 'h-10 gap-2 px-4 type-label-lg',
|
|
'md' => 'h-14 gap-2 px-6 type-title-md',
|
|
'lg' => 'h-24 gap-3 px-12 type-headline-sm',
|
|
'xl' => 'h-34 gap-4 px-16 type-headline-lg',
|
|
][$size];
|
|
|
|
$iconSize = ['xs' => 'size-5', 'sm' => 'size-5', 'md' => 'size-6', 'lg' => 'size-8', 'xl' => 'size-10'][$size];
|
|
|
|
$colours = match ($variant) {
|
|
'filled' => 'bg-surface-container text-on-surface-variant has-checked:bg-primary has-checked:text-on-primary',
|
|
'outlined' => 'border border-outline-variant text-on-surface-variant has-checked:border-transparent has-checked:bg-inverse-surface has-checked:text-inverse-on-surface',
|
|
default => 'bg-secondary-container text-on-secondary-container has-checked:bg-secondary has-checked:text-on-secondary',
|
|
};
|
|
@endphp
|
|
|
|
<fieldset {{ $attributes->only(['class', 'wire:key'])->class('min-w-0') }}>
|
|
@if (filled($label))
|
|
<legend class="mb-2 type-label-lg text-on-surface-variant">{{ $label }}</legend>
|
|
@endif
|
|
|
|
<div data-button-group="connected" data-size="{{ $size }}" @class(['flex gap-0.5', 'w-full' => ! $inline, 'w-fit' => $inline])>
|
|
@foreach ($options as $option)
|
|
<label @class([
|
|
'state-layer relative flex cursor-pointer select-none items-center justify-center whitespace-nowrap',
|
|
'transition-[border-radius,background-color,color] duration-(--md-sys-motion-spatial-fast-duration) ease-spatial-fast',
|
|
'min-w-0 flex-1' => ! $inline,
|
|
$segment,
|
|
$colours,
|
|
'has-focus-visible:outline-3 has-focus-visible:outline-offset-2 has-focus-visible:outline-secondary',
|
|
'has-disabled:cursor-not-allowed has-disabled:bg-on-surface/10 has-disabled:text-on-surface/38',
|
|
])>
|
|
<input
|
|
{{ $attributes->whereStartsWith(['wire:model', 'x-model']) }}
|
|
type="{{ $multiple ? 'checkbox' : 'radio' }}"
|
|
name="{{ $multiple ? $name.'[]' : $name }}"
|
|
value="{{ data_get($option, $optionValue) }}"
|
|
@disabled(data_get($option, 'disabled'))
|
|
class="peer sr-only"
|
|
/>
|
|
|
|
@if (filled(data_get($option, $optionIcon)))
|
|
<x-livewire-material::icon :name="data_get($option, $optionIcon)" :class="$iconSize" />
|
|
@endif
|
|
|
|
<span class="truncate">{{ data_get($option, $optionLabel) }}</span>
|
|
</label>
|
|
@endforeach
|
|
</div>
|
|
|
|
@if ($messages !== [])
|
|
@foreach ($messages as $message)
|
|
<p class="mt-1 type-body-sm text-error">{{ $message }}</p>
|
|
@endforeach
|
|
@elseif (filled($hint))
|
|
<p class="mt-1 type-body-sm text-on-surface-variant">{{ $hint }}</p>
|
|
@endif
|
|
</fieldset>
|