From 7aa6dc7d33af2f5f8be8341da2316a9d576a9323 Mon Sep 17 00:00:00 2001 From: Andreas Reinhold / reini Date: Thu, 17 Sep 2026 07:04:12 +0200 Subject: [PATCH] Take full on the searchable choice and the pickers, as on every field `full` takes the 40rem bound off `[data-md-field]` from `medium`, and ``, ``, ``, `` and `` pass it to the field they draw. ``, `` and `` draw the same field but did not declare the prop, and their roots only forward `class` and `style`, so `full` reached no element and the field stopped at 40rem: ReStride's time zone choice stood narrower than the rows filling its card. The three now declare `full` and pass it to their field (the date picker's own field, not the dialog's entry fields). ``' chips are not a field and have no bound, so they take `full` and render nothing for it, and a call site can switch `searchable` on and off without it. The docblocks and the skill list every component that takes it. The browser test that bounds a field at 600px now measures a bounded and a `full` searchable choice, date picker and time picker too; it fails without the change in Chrome, Firefox and Safari. A feature test renders `full` on every field-shaped component and none on the chips. Co-Authored-By: Claude Opus 5 (1M context) --- UPGRADE.md | 6 +++++ .../livewire-material-development/SKILL.md | 8 +++---- resources/views/components/choices.blade.php | 6 +++-- .../views/components/datepicker.blade.php | 9 +++++--- .../views/components/timepicker.blade.php | 9 ++++---- tests/Browser/FieldsTest.php | 14 +++++++++++- tests/Feature/Components/FieldTest.php | 22 +++++++++++++++++++ 7 files changed, 60 insertions(+), 14 deletions(-) diff --git a/UPGRADE.md b/UPGRADE.md index d5219084..bb533e54 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -81,6 +81,12 @@ `medium` it is the disabled filled button, as before. A `spinner` that disables the button while its action runs leaves the FAB on screen. An application's own `hide-below` or condition around a disabled fab button can go. +- **``, `` and `` take `full`**, as ``, + ``, `` and `` do, to take the 40rem bound off a field from + `medium`; the prop did nothing there, so the field stopped at 40rem beside rows that filled their + card. ``' chips have no bound and take `full` without a change, so a call site can + switch `searchable` on and off. A width rule an application wrote around one of them for this + can go. ## From 2.0.0 to 2.1.0 diff --git a/resources/boost/skills/livewire-material-development/SKILL.md b/resources/boost/skills/livewire-material-development/SKILL.md index e858674b..445e7e9c 100644 --- a/resources/boost/skills/livewire-material-development/SKILL.md +++ b/resources/boost/skills/livewire-material-development/SKILL.md @@ -669,7 +669,7 @@ M3 text fields. `variant`: `outlined` or `filled`; without it, `config('livewire - ``: `icon`, `icon-right`, `prefix`, `suffix`, `clearable`, `copyable` (copies the value, confirms with a snackbar), `counter`, `size` (`sm` 40px, `xs` 32px — for unlabelled toolbar controls; give them `aria-label`), `mono`. - ``: a reveal button; `icon`, `size`. - ``: grows from `rows` (3) to `max-rows`, then scrolls; `:autogrow="false"` for a fixed, hand-resizable one; `counter`. -- Width: M3 asks that a text field never span the full width of a large screen, so from `medium` (600px) every field stops at **40rem**; below that it fills its pane. A width rule of your own on its `class` (`max-inline-size: 24rem`) narrows or widens it, because your unlayered CSS outranks the package's, and `full` (on ``, ``, ``) takes the bound off for a field that really is the width of its pane — a search row, an editor. ``'s bar carries M3's own bound, 720px. +- Width: M3 asks that a text field never span the full width of a large screen, so from `medium` (600px) every field stops at **40rem**; below that it fills its pane. A width rule of your own on its `class` (`max-inline-size: 24rem`) narrows or widens it, because your unlayered CSS outranks the package's, and `full` (on ``, ``, ``, ``, ``, ``, ``, `` and ``) takes the bound off for a field that really is the width of its pane — a search row, an editor. ``'s bar carries M3's own bound, 720px. - `counter` (on `` and ``) puts M3's character counter at the end of the supporting-text row, beside the hint or the error: `n/max`, counted on every keystroke against the field's own `maxlength`, and in the error colour once the value is past it. It needs `maxlength` — without one there is nothing to count against and nothing is drawn. It is said as "Character count, 5/20" from a polite region a second after typing stops. - ``: native ` false, 'weekStart' => null, 'format' => null, + 'full' => false, ]) @php @@ -168,6 +170,7 @@ :$icon :$size :$variant + :$full :data-md-invalid="$invalid ? '' : null" :data-md-readonly="$attributes->get('readonly') ? '' : null" x-bind:data-md-invalid="(fieldError !== '' || {{ $invalid ? 'true' : 'false' }}) ? '' : null" diff --git a/resources/views/components/timepicker.blade.php b/resources/views/components/timepicker.blade.php index 69beda35..e955247b 100644 --- a/resources/views/components/timepicker.blade.php +++ b/resources/views/components/timepicker.blade.php @@ -23,9 +23,9 @@ multiple of the step; a drag and the arrows move by the step). `min` and `max` (`H:i`, inclusive; a `min` later than `max` spans midnight) grey out and skip what lies outside them and turn typed values outside them into errors — validate on the server as well. `clearable` adds a button that - empties the field; `name` posts the value from a hidden input. `label`, `hint`, `icon`, `variant` - and `size` are the field's; `class` and `style` land on the root, other attributes (`required`, - `disabled`, `placeholder`) reach the field's input. + empties the field; `name` posts the value from a hidden input. `label`, `hint`, `icon`, `variant`, + `size` and `full` (the 40rem bound taken off) are the field's; `class` and `style` land on the + root, other attributes (`required`, `disabled`, `placeholder`) reach the field's input. From androidx Compose Material 3 at commit 27cf9a7d5788aa0f5f2d8b6699ce279560daf326 (Apache-2.0): TimePickerTokens and TimeInputTokens — a surface-container-high dialog with an extra-large @@ -56,6 +56,7 @@ 'value' => null, 'name' => null, 'clearable' => false, + 'full' => false, ]) @php @@ -143,7 +144,7 @@ x-data="materialTimepicker(@if ($model !== null) @entangle($attributes->wire('model')) @else @js($current) @endif, @js($config))" @if ($model === null) x-modelable="value" @endif > - + + + + + + + @@ -459,10 +465,16 @@ it('bounds a field to 40rem from 600px, unless the caller\'s width rule or full ->assertScript("({$width('narrow')}) === 200") ->assertScript("({$width('full')}) === 1400"); - fieldWidthProbe(600) + $page = fieldWidthProbe(600) ->assertScript("({$width('bounded')}) === 640") ->assertScript("({$width('narrow')}) === 200") ->assertScript("({$width('full')}) === 1400"); + + // The fields the searchable choice and the pickers draw take `full` as the others do. + foreach (['choices', 'date', 'time'] as $field) { + expect($page->script($width("{$field}-bounded")))->toBe(640) + ->and($page->script($width("{$field}-full")))->toBe(1400); + } }); it('draws the field at M3\'s geometry and the file picker\'s button as a tonal pill', function () { diff --git a/tests/Feature/Components/FieldTest.php b/tests/Feature/Components/FieldTest.php index 744da674..88fee067 100644 --- a/tests/Feature/Components/FieldTest.php +++ b/tests/Feature/Components/FieldTest.php @@ -201,6 +201,28 @@ it('bounds a field\'s width from medium unless it is told to fill its pane', fun expect((string) $this->blade(''))->toContain('data-md-full') ->and((string) $this->blade(''))->toContain('data-md-full') ->and((string) $this->blade(''))->not->toContain('data-md-full'); + + // Every field-shaped component takes it: the searchable choice and the pickers draw a field too. + $zones = "[['id' => 'Europe/Zurich', 'name' => 'Zurich']]"; + + foreach ([ + '', + '', + '', + "", + '', + '', + '', + ] as $blade) { + expect(substr_count((string) $this->blade($blade), 'data-md-full'))->toBe(1, $blade); + } + + expect((string) $this->blade(""))->not->toContain('data-md-full') + ->and((string) $this->blade(''))->not->toContain('data-md-full') + ->and((string) $this->blade(''))->not->toContain('data-md-full') + // Chips are no field and have no bound to take off: `full` is taken, and reaches no element. + ->and((string) $this->blade(""))->not->toMatch('/\\bfull\\b|data-md-full/') + ->and((string) $this->blade(""))->not->toMatch('/\\bfull\\b|data-md-full/'); }); it('lays out a form with its actions under an optional divider', function () {