Draw the dragged layer on a card that is not a row
Plan step 36 review of f04e31b3. The card rendered md-state-layer only
on a row, so a card the application marks data-md-dragged without being
a row, as the showcase's "A card being dragged" is, lost the 16% dragged
layer its old inset shadow drew and its header still promises. Every
card now renders the class, since the attribute arrives from script
after render, and card.css keeps the layer off a card that is neither a
row nor dragged. The divider under the header is matched as its child.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
This commit is contained in:
co-authored by
Claude Opus 5
parent
7d3abdd506
commit
c298b19e75
@@ -6,10 +6,13 @@
|
|||||||
* which never morphs (M3 specifies shape morph for buttons, FABs and list items, never cards —
|
* which never morphs (M3 specifies shape morph for buttons, FABs and list items, never cards —
|
||||||
* docs/audits/m3-alignment/containment.md, C-23).
|
* docs/audits/m3-alignment/containment.md, C-23).
|
||||||
*
|
*
|
||||||
* A row (`data-md-list-row`, `resources/js/list-rows.js`) renders the shared `md-state-layer` and
|
* Every card renders the shared `md-state-layer` class, and a row (`data-md-list-row`,
|
||||||
* `md-focus-ring` classes (foundation/interaction.css) for its tint and its ring; this file adds
|
* `resources/js/list-rows.js`) `md-focus-ring` too (foundation/interaction.css), for its tint and
|
||||||
* only what a card needs beyond them:
|
* its ring; this file adds only what a card needs beyond them:
|
||||||
*
|
*
|
||||||
|
* - *no layer* on a card that is neither a row nor dragged: a card that does not open anything
|
||||||
|
* answers no pointer, but any card can be carried, and the application sets `data-md-dragged`
|
||||||
|
* from script long after the view rendered;
|
||||||
* - per-state *elevation*, which the shared class has no opinion on: elevated 1dp rest → 2dp
|
* - per-state *elevation*, which the shared class has no opinion on: elevated 1dp rest → 2dp
|
||||||
* hover → 1dp focus/pressed; filled and outlined 0dp rest → 1dp hover → 0dp focus/pressed
|
* hover → 1dp focus/pressed; filled and outlined 0dp rest → 1dp hover → 0dp focus/pressed
|
||||||
* (the cross-check table's Hover/Focus/Pressed rows). Pressed and focus fall back to the rest
|
* (the cross-check table's Hover/Focus/Pressed rows). Pressed and focus fall back to the rest
|
||||||
@@ -57,6 +60,10 @@
|
|||||||
background-color: var(--md-sys-color-surface);
|
background-color: var(--md-sys-color-surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[data-md-card]:not([data-md-list-row], [data-md-dragged])::before {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
[data-md-card][data-md-list-row] {
|
[data-md-card][data-md-list-row] {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition-property: box-shadow;
|
transition-property: box-shadow;
|
||||||
@@ -157,7 +164,7 @@
|
|||||||
margin-inline-end: calc(-1 * var(--md-sys-measurement-space100));
|
margin-inline-end: calc(-1 * var(--md-sys-measurement-space100));
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-md-card-header] [data-md-divider] {
|
[data-md-card-header] > [data-md-divider] {
|
||||||
margin-top: var(--md-sys-measurement-space200);
|
margin-top: var(--md-sys-measurement-space200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,20 +22,21 @@
|
|||||||
reaches the opener. Put `tabindex="-1"` on that opener so the card is the one stop, and leave
|
reaches the opener. Put `tabindex="-1"` on that opener so the card is the one stop, and leave
|
||||||
the card's other actions as they are — they follow it in the tab order.
|
the card's other actions as they are — they follow it in the tab order.
|
||||||
|
|
||||||
A row (`data-md-list-row`, `actionable` or not) renders the shared `md-state-layer` and
|
Every card renders the shared `md-state-layer` class and a row (`data-md-list-row`,
|
||||||
`md-focus-ring` classes (foundation/interaction.css), which draw the tint and the ring for a
|
`actionable` or not) `md-focus-ring` too (foundation/interaction.css), which draw the tint and
|
||||||
card focused directly; resources/css/components/card.css refines their opacity when the
|
the ring for a card focused directly; resources/css/components/card.css keeps the layer off a
|
||||||
pointer or the keyboard is on one of the card's *own* buttons instead (which should light only
|
card that is neither a row nor dragged, refines its opacity when the pointer or the keyboard is
|
||||||
itself), and adds the `:has([data-md-list-open]:focus-visible)` ring for the non-actionable
|
on one of the card's *own* buttons instead (which should light only itself), and adds the
|
||||||
row, whose focus never lands on the card itself. Elevation is separate from the tint — M3
|
`:has([data-md-list-open]:focus-visible)` ring for the non-actionable row, whose focus never
|
||||||
gives each variant its own per-state box-shadow (elevated 1dp rest → 2dp hover → 1dp
|
lands on the card itself. Elevation is separate from the tint — M3 gives each variant its own
|
||||||
focus/pressed; filled and outlined 0dp rest → 1dp hover → 0dp focus/pressed) — so it is drawn
|
per-state box-shadow (elevated 1dp rest → 2dp hover → 1dp focus/pressed; filled and outlined
|
||||||
directly on `[data-md-card]`, never inside the shared class. Its corner does not move, because
|
0dp rest → 1dp hover → 0dp focus/pressed) — so it is drawn directly on `[data-md-card]`, never
|
||||||
|
inside the shared class. Its corner does not move, because
|
||||||
M3 gives a card one shape (docs/audits/m3-alignment/containment.md, C-13, C-23).
|
M3 gives a card one shape (docs/audits/m3-alignment/containment.md, C-13, C-23).
|
||||||
|
|
||||||
`data-md-dragged` is M3's dragged card: the top of a card's elevation scale — 8dp elevated,
|
`data-md-dragged` is M3's dragged card, row or not: the top of a card's elevation scale — 8dp
|
||||||
6dp filled and outlined — under the shared class's own 16% dragged tint (it already reads
|
elevated, 6dp filled and outlined — under the shared class's own 16% dragged tint (it already
|
||||||
`data-md-dragged`, foundation/interaction.css). Nothing in the browser tells a card it is
|
reads `data-md-dragged`, foundation/interaction.css). Nothing in the browser tells a card it is
|
||||||
being carried, so the application sets the attribute when its drag starts and takes it off on
|
being carried, so the application sets the attribute when its drag starts and takes it off on
|
||||||
drop. M3 requires a single-pointer alternative beside any drag, so keep the same reorder or
|
drop. M3 requires a single-pointer alternative beside any drag, so keep the same reorder or
|
||||||
delete actions in a menu on the card
|
delete actions in a menu on the card
|
||||||
@@ -71,7 +72,8 @@
|
|||||||
'role' => $role,
|
'role' => $role,
|
||||||
'aria-label' => $actionable && filled($title) ? $title : null,
|
'aria-label' => $actionable && filled($title) ? $title : null,
|
||||||
], fn ($value): bool => $value !== null))->class([
|
], fn ($value): bool => $value !== null))->class([
|
||||||
'md-state-layer' => $isRow,
|
// Every card: the application sets `data-md-dragged` from script, after this renders.
|
||||||
|
'md-state-layer',
|
||||||
'md-focus-ring' => $isRow,
|
'md-focus-ring' => $isRow,
|
||||||
]) }}
|
]) }}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -46,9 +46,13 @@ it('passes row attributes through and renders the shared interaction classes for
|
|||||||
->toContain('data-md-list-row')
|
->toContain('data-md-list-row')
|
||||||
->toContain('data-md-list-open')
|
->toContain('data-md-list-open')
|
||||||
->toContain('class="md-state-layer md-focus-ring"')
|
->toContain('class="md-state-layer md-focus-ring"')
|
||||||
|
// Any card can be carried, so each draws the shared layer, which card.css keeps off one
|
||||||
|
// that is neither a row nor dragged.
|
||||||
->and((string) $this->blade('<x-card title="Share">Body</x-card>'))
|
->and((string) $this->blade('<x-card title="Share">Body</x-card>'))
|
||||||
->not->toContain('md-state-layer')
|
->toContain('class="md-state-layer"')
|
||||||
->not->toContain('md-focus-ring');
|
->not->toContain('md-focus-ring')
|
||||||
|
->and(ComponentStylesheet::read('card')->declarations('[data-md-card]:not([data-md-list-row], [data-md-dragged])::before'))
|
||||||
|
->toBe(['display' => 'none']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('makes a directly actionable card the one tab stop, named by its title', function () {
|
it('makes a directly actionable card the one tab stop, named by its title', function () {
|
||||||
|
|||||||
Reference in New Issue
Block a user