Tie a collapse's padding and chevron to its own parts

Plan step 36 review of 76abdd62. The old view put the filled variant's
16px padding on its own summary and body; the stylesheet matched them as
descendants of any filled collapse, so a plain collapse nested inside
one took the padding too (and an open one turned every nested chevron).
Child combinators now tie each rule to its own <details>. The 12px gap is
a literal like alert.css's, not an average of two spacing tokens.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
This commit is contained in:
Andreas Reinhold / reini
2026-09-14 22:01:22 +02:00
co-authored by Claude Opus 5
parent c298b19e75
commit 21f8ed826c
2 changed files with 17 additions and 7 deletions
+7 -7
View File
@@ -17,9 +17,9 @@
* (foundation/interaction.css) sit on the summary; this file only refines their target — the
* 48px summary height, the icon and chevron colour — never their opacities or ring.
*
* Icon-to-title and title-to-chevron gaps are 12px, midway between two spacing steps
* (`space100` 8px, `space200` 16px); written as their average rather than a bare literal so the
* value still comes from the scale.
* Icon-to-title and title-to-chevron gaps are a literal 12px: the measurement scale has no 12
* (`space125` is 10px), as alert.css's gap. Every part is matched as its own `<details>`' child, so
* a collapse nested in a filled one takes neither its padding nor its turned chevron.
*/
@layer material.reset, material.tokens, material.base, material.layout, material.components, material.text, material.visibility;
@@ -52,7 +52,7 @@
display: flex;
min-block-size: var(--md-sys-measurement-space600);
align-items: center;
gap: calc((var(--md-sys-measurement-space100) + var(--md-sys-measurement-space200)) / 2);
gap: 12px;
border-radius: inherit;
cursor: pointer;
list-style-type: none;
@@ -64,7 +64,7 @@
}
}
[data-md-collapse][data-md-variant='filled'] [data-md-collapse-summary] {
[data-md-collapse][data-md-variant='filled'] > [data-md-collapse-summary] {
padding-inline: var(--md-sys-measurement-space200);
}
@@ -82,7 +82,7 @@
transition: rotate var(--md-sys-motion-spatial-fast-duration) var(--md-sys-motion-spatial-fast);
}
[data-md-collapse][open] [data-md-collapse-chevron] {
[data-md-collapse][open] > [data-md-collapse-summary] > [data-md-collapse-chevron] {
rotate: 180deg;
}
@@ -93,7 +93,7 @@
letter-spacing: var(--md-sys-typescale-body-md-tracking);
}
[data-md-collapse][data-md-variant='filled'] [data-md-collapse-body] {
[data-md-collapse][data-md-variant='filled'] > [data-md-collapse-body] {
padding-inline: var(--md-sys-measurement-space200);
}
}
+10
View File
@@ -2,6 +2,7 @@
use Livewire\Component;
use Livewire\Livewire;
use NoNameWeb\LivewireMaterial\Tests\Support\ComponentStylesheet;
it('discloses on the native details element, kept open through a morph', function () {
$html = (string) $this->blade('<x-collapse title="How long do links last?" icon="schedule" open variant="filled">Until the expiry.</x-collapse>');
@@ -65,3 +66,12 @@ it('entangles its open state with a Livewire property and renders open as the pr
expect(preg_match('/\sopen\s/', $tag[0]) === 1)->toBe($fineTuning);
})->with(['open' => true, 'closed' => false]);
it('draws a filled collapse\'s padding and an open one\'s chevron on its own parts, never a nested collapse\'s', function () {
$css = ComponentStylesheet::read('collapse');
expect($css->declarations("[data-md-collapse][data-md-variant='filled'] > [data-md-collapse-summary]"))->toBe(['padding-inline' => 'var(--md-sys-measurement-space200)'])
->and($css->declarations("[data-md-collapse][data-md-variant='filled'] > [data-md-collapse-body]"))->toBe(['padding-inline' => 'var(--md-sys-measurement-space200)'])
->and($css->declarations('[data-md-collapse][open] > [data-md-collapse-summary] > [data-md-collapse-chevron]'))->toBe(['rotate' => '180deg'])
->and($css->declarations('[data-md-collapse-summary]'))->toHaveKey('gap', '12px');
});