diff --git a/UPGRADE.md b/UPGRADE.md index bb533e54..d9c7e321 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -87,6 +87,10 @@ 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. +- **A searchable ``' list is as wide as its field.** It was anchored to a wrapper + around the field, which fills its container, so from `medium`, where the field stops at 40rem, + the list ran on past the field's end across the whole container. The field itself is the anchor + now, and the wrapper `
` is gone; the list keeps hanging under the field's supporting text. ## From 2.0.0 to 2.1.0 diff --git a/resources/views/components/choices.blade.php b/resources/views/components/choices.blade.php index caa0085e..739b6734 100644 --- a/resources/views/components/choices.blade.php +++ b/resources/views/components/choices.blade.php @@ -11,7 +11,8 @@ and End go to the ends of the open list (with it closed they are the field's own and move the caret), Enter chooses, Escape puts the field back — WAI-ARIA's combobox keyboard, since M3 has no combobox. One value only. The list is a popover in the top - layer, placed by CSS anchor positioning, so a card's clipping never cuts it off. `icon`, + layer, placed by CSS anchor positioning on the field itself, so a card's clipping never cuts + it off and it is as wide as the field, 40rem bound and all. `icon`, `variant` and `placeholder` are the field's, and `full` takes the 40rem bound off the field as it does off every field. Chips have no such bound, so they take `full` and change nothing. @@ -135,42 +136,40 @@ }" @if ($model === null) x-modelable="value" @endif > -
- - + + - - - - -
+ + + +
    get('/wide-choices-probe', fn () => Blade::render(<<<'BLADE' + + + + + @vite(config('livewire-material.showcase.vite')) + @livewireStyles + + +
    + + +
    +
    + @livewireScripts + + + BLADE)); + + // [the field's width, the list's width, the list's start against the field's]. + $placed = fn (string $id): string => "(() => { + const field = document.querySelector('[data-md-field]:has(#{$id})').getBoundingClientRect(); + const list = document.getElementById('{$id}-list').getBoundingClientRect(); + + return [Math.round(field.width), Math.round(list.width), Math.round(list.left - field.left)]; + })()"; + + $page = visit('/wide-choices-probe')->resize(1280, 800)->waitForEvent('networkidle') + ->assertScript("document.readyState === 'complete' && typeof window.Alpine !== 'undefined'"); + + $page->click('#bounded-zone')->assertScript("document.getElementById('bounded-zone-list').matches(':popover-open')"); + + expect($page->script($placed('bounded-zone')))->toBe([640, 640, 0]); + + $page->keys('#bounded-zone', 'Escape')->assertScript("! document.getElementById('bounded-zone-list').matches(':popover-open')"); + $page->click('#full-zone')->assertScript("document.getElementById('full-zone-list').matches(':popover-open')"); + + expect($page->script($placed('full-zone')))->toBe([1168, 1168, 0]); +}); + it('opens the search view with the results Livewire renders for the query', function () { $view = "document.querySelector('#find-view')";