Fill a selected row written by hand in secondary-container again
1.x drew `data-selected` on any `data-list-row` that was not a card in secondary-container with on-secondary-container ink, whatever element the row was. 2.0.0 kept that only for `<x-list-item selected>` and a table row's `aria-selected="true"`, so an application's own `<li>`, `<div>` or `<tr>` with `data-md-list-row` and `data-md-selected` - the contract list-rows.js still describes - lost its selected state without a word. list-item.css now fills such a row, cards and list items excluded, and names the fill `--md-list-row-fill`, so hover, focus and press tint it as they tint a selected list item rather than replacing it (1.x's selected fill hid them). In `<x-table>`, `data-md-selected` selects a plain row too, beside `aria-selected="true"`, which ARIA allows on a row only in a grid. A browser test compares a hand-made selected `<li>` and a plain selected `<tr>` with the role pair in the light and dark themes, checks that a selected card keeps its own fill and that hover tints the row's fill; it fails without the change. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
613ac20013
commit
b7e16476cd
@@ -966,6 +966,79 @@ it('keeps a selected segmented row\'s fill under the hover and focus tint', func
|
||||
->and($selectedFocusBackground)->not->toBe($selectedHoverBackground);
|
||||
});
|
||||
|
||||
/**
|
||||
* An element's background and ink, "background / color", once the transitions a change started on
|
||||
* it have run: a row moves its background on the effects springs.
|
||||
*/
|
||||
function settledPaint(string $element): string
|
||||
{
|
||||
return "(async () => { const element = {$element}; await Promise.allSettled(element.getAnimations().map((animation) => animation.finished)); const style = getComputedStyle(element); return style.backgroundColor + ' / ' + style.color })()";
|
||||
}
|
||||
|
||||
it('fills a selected row written by hand in secondary-container in both themes, but not a card', function () {
|
||||
Route::middleware('web')->get('/hand-made-selected-row-probe', fn () => Blade::render(<<<'BLADE'
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<x-theme-script />
|
||||
@vite(config('livewire-material.showcase.vite'))
|
||||
@livewireStyles
|
||||
</head>
|
||||
<body style="background-color: var(--md-sys-color-surface);">
|
||||
<div style="padding: var(--md-sys-measurement-space200); max-width: 400px;">
|
||||
<p id="swatch" style="background-color: var(--md-sys-color-secondary-container); color: var(--md-sys-color-on-secondary-container);">The role pair</p>
|
||||
<ul>
|
||||
<li id="selected-row" data-md-list-row data-md-selected><a href="#selected" data-md-list-open>Selected</a></li>
|
||||
<li id="plain-row" data-md-list-row><a href="#plain" data-md-list-open>Plain</a></li>
|
||||
</ul>
|
||||
<x-table>
|
||||
<tbody>
|
||||
<tr id="selected-table-row" data-md-selected><td>Selected, opening nothing</td></tr>
|
||||
</tbody>
|
||||
</x-table>
|
||||
<x-card id="selected-card" data-md-list-row data-md-selected>
|
||||
<a href="#card" data-md-list-open>A card</a>
|
||||
</x-card>
|
||||
</div>
|
||||
@livewireScripts
|
||||
</body>
|
||||
</html>
|
||||
BLADE));
|
||||
|
||||
$page = visit('/hand-made-selected-row-probe')->waitForEvent('networkidle')
|
||||
->assertScript("document.readyState === 'complete' && typeof window.Alpine !== 'undefined'");
|
||||
|
||||
$swatch = settledPaint("document.getElementById('swatch')");
|
||||
$row = settledPaint("document.getElementById('selected-row')");
|
||||
$tableRow = settledPaint("document.getElementById('selected-table-row')");
|
||||
$light = $page->script($swatch);
|
||||
|
||||
// The role pair itself, on an `<li>` and on a plain `<tr>` in a table; a card keeps its own
|
||||
// container, and a row that is not selected has no fill.
|
||||
expect($page->script($row))->toBe($light)
|
||||
->and($page->script($tableRow))->toBe($light)
|
||||
->and($page->script("getComputedStyle(document.getElementById('plain-row')).backgroundColor"))->toBe('rgba(0, 0, 0, 0)')
|
||||
->and($page->script("getComputedStyle(document.getElementById('selected-card')).backgroundColor"))->not->toBe(explode(' / ', $light)[0]);
|
||||
|
||||
$page->script("document.documentElement.setAttribute('data-theme', 'dark')");
|
||||
$dark = $page->script($swatch);
|
||||
|
||||
expect($dark)->not->toBe($light)
|
||||
->and($page->script($row))->toBe($dark)
|
||||
->and($page->script($tableRow))->toBe($dark);
|
||||
|
||||
// The hover tint is laid over the fill, so it is neither the fill nor a plain row's hover.
|
||||
$page->hover('#selected-row');
|
||||
$selectedHover = explode(' / ', $page->script($row))[0];
|
||||
|
||||
$page->hover('#plain-row');
|
||||
$plainHover = explode(' / ', $page->script(settledPaint("document.getElementById('plain-row')")))[0];
|
||||
|
||||
expect($selectedHover)->not->toBe(explode(' / ', $dark)[0])
|
||||
->and($selectedHover)->not->toBe($plainHover)
|
||||
->and($page->script($row))->toBe($dark);
|
||||
});
|
||||
|
||||
/**
|
||||
* Collapses to watch move: one on its own with a paragraph under it, one bound to Alpine, and a
|
||||
* `name` group of two with the first open. Each body is tall enough for a height caught part-way
|
||||
|
||||
@@ -25,7 +25,7 @@ it('draws 52px rows, 36px dense ones, from its stylesheet in the components laye
|
||||
expect($css)->toContain('@layer material.components')
|
||||
->toMatch('/\\[data-md-table\\] \\{\\s*--cell-x: 12px;\\s*--cell-y: var\\(--md-sys-measurement-space200\\);/')
|
||||
->toMatch('/\\[data-md-table\\]\\[data-md-dense\\] \\{\\s*--cell-y: var\\(--md-sys-measurement-space100\\);/')
|
||||
->toContain('[data-md-table] :where(tbody tr[aria-selected=\'true\'])')
|
||||
->toContain('[data-md-table] :where(tbody tr:is([aria-selected=\'true\'], [data-md-selected]))')
|
||||
->and((string) file_get_contents(__DIR__.'/../../../resources/css/all.css'))->toContain("@import './components/table.css';");
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user