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>
95 lines
4.0 KiB
CSS
95 lines
4.0 KiB
CSS
/*
|
|
* Data tables: `<x-table>` (resources/views/components/table.blade.php), whose callers write plain
|
|
* `<thead>`, `<tr>`, `<th>` and `<td>` inside it.
|
|
*
|
|
* So the styling is descendant selectors on the one attribute the component sets, `data-md-table`,
|
|
* with every cell and row selector inside `:where()`: a caller's alignment or wrapping on a cell
|
|
* always wins, whatever layer it comes from. Header cells in title-small on-surface-variant over an
|
|
* outline-variant rule, body cells in body-medium between outline-variant rules — the role itself,
|
|
* never a fraction of it, since M3 reserves opacity for state layers and disabled. A selected row
|
|
* (`data-md-selected`, or `aria-selected="true"` where the table is a grid, the only place ARIA
|
|
* allows it on a row) is secondary-container. A row that opens something is `data-md-list-row`
|
|
* and answers a pointer as a list row does (components/list-item.css, shared with `<x-card>` and
|
|
* `<x-list-item>`); a selected one names its fill `--md-list-row-fill`, so that state layer is laid
|
|
* over the secondary-container rather than in place of it.
|
|
*
|
|
* A row is 52px: 16px above and below a body-medium line, 12px beside each cell. Density is never
|
|
* applied by itself — "don't apply density by default; offer an explicit density opt-in instead,
|
|
* keeping opt-out targets at >= 48x48 CSS px" (docs/reference/m3/foundations-supplement.md
|
|
* § Accessibility) — so `dense` (`data-md-dense`) is the caller's decision, and it is the caller's
|
|
* to justify: a dense row is 36px (8px above and below). `data-md-size="xs"`, for a table inside a
|
|
* panel inside a panel, is body-small with label-medium headers, 8px around each cell (32px rows),
|
|
* and 4px above and below when dense (24px).
|
|
*/
|
|
|
|
@layer material.reset, material.tokens, material.base, material.layout, material.components, material.text, material.visibility;
|
|
|
|
@import './list-item.css';
|
|
|
|
@layer material.components {
|
|
/* `position: relative` makes the table the containing block for anything absolute inside it —
|
|
a visually hidden header label, a tooltip. Without it they escape the scroll box and widen a
|
|
phone's layout viewport. */
|
|
[data-md-table] {
|
|
--cell-x: 12px;
|
|
--cell-y: var(--md-sys-measurement-space200);
|
|
|
|
position: relative;
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
color: var(--md-sys-color-on-surface);
|
|
font: var(--md-sys-typescale-body-md);
|
|
letter-spacing: var(--md-sys-typescale-body-md-tracking);
|
|
}
|
|
|
|
[data-md-table][data-md-size='xs'] {
|
|
--cell-x: var(--md-sys-measurement-space100);
|
|
--cell-y: var(--md-sys-measurement-space100);
|
|
|
|
font: var(--md-sys-typescale-body-sm);
|
|
letter-spacing: var(--md-sys-typescale-body-sm-tracking);
|
|
}
|
|
|
|
[data-md-table][data-md-dense] {
|
|
--cell-y: var(--md-sys-measurement-space100);
|
|
}
|
|
|
|
[data-md-table][data-md-size='xs'][data-md-dense] {
|
|
--cell-y: var(--md-sys-measurement-space50);
|
|
}
|
|
|
|
[data-md-table] :where(th, td) {
|
|
padding: var(--cell-y) var(--cell-x);
|
|
text-align: start;
|
|
vertical-align: middle;
|
|
}
|
|
|
|
[data-md-table] :where(thead th) {
|
|
color: var(--md-sys-color-on-surface-variant);
|
|
font: var(--md-sys-typescale-title-sm);
|
|
letter-spacing: var(--md-sys-typescale-title-sm-tracking);
|
|
white-space: nowrap;
|
|
border-bottom: 1px solid var(--md-sys-color-outline-variant);
|
|
}
|
|
|
|
[data-md-table][data-md-size='xs'] :where(thead th) {
|
|
font: var(--md-sys-typescale-label-md);
|
|
letter-spacing: var(--md-sys-typescale-label-md-tracking);
|
|
}
|
|
|
|
[data-md-table] :where(tbody tr) {
|
|
border-bottom: 1px solid var(--md-sys-color-outline-variant);
|
|
}
|
|
|
|
[data-md-table] :where(tbody tr:last-child) {
|
|
border-bottom: 0;
|
|
}
|
|
|
|
[data-md-table] :where(tbody tr:is([aria-selected='true'], [data-md-selected])) {
|
|
--md-list-row-fill: var(--md-sys-color-secondary-container);
|
|
|
|
background-color: var(--md-list-row-fill);
|
|
color: var(--md-sys-color-on-secondary-container);
|
|
}
|
|
}
|