Cover six actions/communication behaviours the browser suite missed
Plan step 36's handoff listed six behaviours no browser test exercised yet: - FieldsTest: <x-select>'s open list uses the customizable picker (appearance: base-select) where the browser supports it, drawn as M3's 48px-row menu. - CommunicationTest: a two-line snackbar's action stays on the title's row from 600px, only wrapping under it below that (toast.css's [data-md-toast-wrap]). - ActionsTest: a disabled menu item reached by the keyboard withholds its state layer (interaction.css's [aria-disabled="true"] rule). - DataTest: a paginator's page step shows md-focus-ring's outline on keyboard focus, alongside its already-tested 48px target. - CommunicationTest: a transient rich tooltip stays open 1.5s after focus leaves rather than closing at once (rich-tooltip.js's LEAVE_GRACE_MS). - ActionsTest: an xs or sm group segment takes a press at its 48px edge, past its drawn size, now that the target comes from the shared md-touch-target class rather than a rule of its own. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
4bf1ca13a3
commit
a29a147f1a
@@ -171,6 +171,20 @@ it('opens a menu from the keyboard, on the last item with ArrowUp', function ()
|
||||
->assertScript(focused("textContent.trim().startsWith('Delete')"));
|
||||
});
|
||||
|
||||
it('shows no state layer on a disabled menu item even when keyboard focus reaches it', function () {
|
||||
$trigger = '#menus button:has-text("Sort")';
|
||||
$reset = '#menus [role="menuitem"]:has-text("Reset")';
|
||||
|
||||
$page = showcase('menus')->click($trigger);
|
||||
|
||||
// M3 keeps a disabled item reachable so a person can find out it is there, but
|
||||
// .md-state-layer withholds the layer itself from [aria-disabled="true"] (interaction.css).
|
||||
$page->keys(':focus', 'End')
|
||||
->assertScript(focused("textContent.trim().startsWith('Reset')"))
|
||||
->assertAttribute($reset, 'aria-disabled', 'true')
|
||||
->assertScript("getComputedStyle(document.activeElement, '::before').display === 'none'");
|
||||
});
|
||||
|
||||
it('opens a menu the moment the page can be used', function () {
|
||||
// The guard against a light-dismiss press reopening the menu once measured from the page's
|
||||
// time origin, and swallowed every click in the first quarter second.
|
||||
@@ -501,6 +515,68 @@ it('takes a press on a small connected segment at its 48px edge, past what it dr
|
||||
JS);
|
||||
});
|
||||
|
||||
class GroupSizeProbe extends Component
|
||||
{
|
||||
public function render(): string
|
||||
{
|
||||
return <<<'BLADE'
|
||||
<div class="grid gap-6 p-4">
|
||||
<x-group name="xs-group" size="xs" :options="[['id' => 'a', 'name' => 'A'], ['id' => 'b', 'name' => 'B']]" />
|
||||
<x-group name="sm-group" size="sm" :options="[['id' => 'a', 'name' => 'A'], ['id' => 'b', 'name' => 'B']]" />
|
||||
</div>
|
||||
BLADE;
|
||||
}
|
||||
}
|
||||
|
||||
function groupSizeProbe()
|
||||
{
|
||||
Livewire::component('group-size-probe', GroupSizeProbe::class);
|
||||
|
||||
Route::middleware('web')->get('/group-size-probe', fn () => Blade::render(<<<'BLADE'
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<x-theme-script />
|
||||
@vite(config('livewire-material.showcase.vite'))
|
||||
@livewireStyles
|
||||
</head>
|
||||
<body class="bg-surface">
|
||||
<livewire:group-size-probe />
|
||||
@livewireScripts
|
||||
</body>
|
||||
</html>
|
||||
BLADE));
|
||||
|
||||
return visit('/group-size-probe')->waitForEvent('networkidle')
|
||||
->assertScript("document.readyState === 'complete' && typeof window.Alpine !== 'undefined'");
|
||||
}
|
||||
|
||||
it('takes a press at an xs or sm group segment\'s 48px edge, past what it draws, from the shared classes', function () {
|
||||
// M3: "XS and S connected button groups have a 48dp target area and a 48dp minimum width" —
|
||||
// group.blade.php reaches it with md-touch-target, not a rule of its own.
|
||||
groupSizeProbe()
|
||||
->assertScript(<<<'JS'
|
||||
(() => {
|
||||
const segment = document.querySelector('input[name="xs-group"][value="a"]').parentElement
|
||||
const box = segment.getBoundingClientRect()
|
||||
const x = box.left + box.width / 2
|
||||
return box.height < 48
|
||||
&& document.elementFromPoint(x, box.top - 3) === segment
|
||||
&& document.elementFromPoint(x, box.bottom + 3) === segment
|
||||
})()
|
||||
JS)
|
||||
->assertScript(<<<'JS'
|
||||
(() => {
|
||||
const segment = document.querySelector('input[name="sm-group"][value="a"]').parentElement
|
||||
const box = segment.getBoundingClientRect()
|
||||
const x = box.left + box.width / 2
|
||||
return box.height < 48
|
||||
&& document.elementFromPoint(x, box.top - 3) === segment
|
||||
&& document.elementFromPoint(x, box.bottom + 3) === segment
|
||||
})()
|
||||
JS);
|
||||
});
|
||||
|
||||
it('keeps one choice in a single, required selection group', function () {
|
||||
$group = '#buttons [data-md-selection="single"]';
|
||||
$view = "document.querySelector('{$group}').parentElement.querySelector('code').textContent";
|
||||
|
||||
Reference in New Issue
Block a user