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
80 lines
3.8 KiB
PHP
80 lines
3.8 KiB
PHP
{{-- A text field: M3's outlined or filled one (resources/views/components/field.blade.php).
|
|
|
|
`label`, `hint`, leading `icon`, trailing `icon-right`, `prefix` and `suffix` (text beside the
|
|
value, such as a currency or a unit), `variant`, `size` for unlabelled controls in toolbars,
|
|
and `mono` for a field that holds code. `clearable` adds a trailing button that empties the
|
|
field once it holds something; `copyable` one that copies its value and says so in a snackbar
|
|
(a share link, a token). Every other attribute reaches the `<input>`: `type`, `min`, `step`,
|
|
`readonly`, `wire:model` and the rest. Errors are read from the bag under the `wire:model` name.
|
|
|
|
The placeholder is a single space when none is given, because the label can only tell an
|
|
empty field from a filled one through `:placeholder-shown`. With a label, a real placeholder
|
|
shows only while the field has focus — until then the label stands where it would be. --}}
|
|
|
|
@props([
|
|
'label' => null,
|
|
'hint' => null,
|
|
'hintClass' => null,
|
|
'icon' => null,
|
|
'iconRight' => null,
|
|
'prefix' => null,
|
|
'suffix' => null,
|
|
'clearable' => false,
|
|
'copyable' => false,
|
|
'size' => 'md',
|
|
'variant' => null,
|
|
'mono' => false,
|
|
])
|
|
|
|
@php
|
|
$model = $attributes->whereStartsWith('wire:model')->first();
|
|
$placeholder = filled($attributes->get('placeholder')) ? $attributes->get('placeholder') : ' ';
|
|
$id = $attributes->get('id') ?? 'field-'.substr(md5($model.'|'.$label.'|'.$placeholder), 0, 12);
|
|
$messages = $model !== null && isset($errors) ? \Illuminate\Support\Arr::flatten($errors->get($model)) : [];
|
|
@endphp
|
|
|
|
<x-livewire-material::field :$id :$label :$hint :hint-class="$hintClass" :$messages :$icon :$prefix :$suffix :$size :$variant :$mono :class="$attributes->get('class')" :data-readonly="$attributes->get('readonly') ? '' : null">
|
|
<input
|
|
{{ $attributes->except(['class', 'id', 'placeholder'])->merge(['type' => 'text']) }}
|
|
id="{{ $id }}"
|
|
placeholder="{{ $placeholder }}"
|
|
@if ($messages !== []) aria-invalid="true" @endif
|
|
@if ($messages !== [] || filled($hint)) aria-describedby="{{ $id }}-support" @endif
|
|
class="field-control"
|
|
/>
|
|
|
|
@if ($clearable || $copyable || $iconRight)
|
|
<x-slot:trailing>
|
|
@if ($clearable)
|
|
<button
|
|
type="button"
|
|
x-data
|
|
x-on:click="const control = $el.closest('.field').querySelector('.field-control'); control.value = ''; control.dispatchEvent(new Event('input', { bubbles: true })); control.dispatchEvent(new Event('change', { bubbles: true })); control.focus();"
|
|
class="field-trailing field-clear field-button"
|
|
aria-label="{{ __('Clear') }}"
|
|
data-field-clear
|
|
>
|
|
<x-livewire-material::icon name="close" class="size-(--field-icon)" />
|
|
</button>
|
|
@endif
|
|
|
|
@if ($copyable)
|
|
<button
|
|
type="button"
|
|
x-data
|
|
x-on:click="navigator.clipboard.writeText($el.closest('.field').querySelector('.field-control').value).then(() => window.materialToast(@js(__('Copied to the clipboard')), { type: 'success' }))"
|
|
class="field-trailing field-button"
|
|
aria-label="{{ __('Copy') }}"
|
|
data-field-copy
|
|
>
|
|
<x-livewire-material::icon name="content_copy" class="size-(--field-icon)" />
|
|
</button>
|
|
@endif
|
|
|
|
@if ($iconRight)
|
|
<x-livewire-material::icon :name="$iconRight" class="field-trailing size-(--field-icon)" />
|
|
@endif
|
|
</x-slot:trailing>
|
|
@endif
|
|
</x-livewire-material::field>
|