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
78 lines
3.5 KiB
PHP
78 lines
3.5 KiB
PHP
<?php
|
|
|
|
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>');
|
|
|
|
expect($html)
|
|
->toContain('<details')
|
|
->toContain('wire:ignore.self')
|
|
->toContain(' open ')
|
|
->toContain('data-md-collapse')
|
|
->toContain('data-md-variant="filled"')
|
|
->toContain('data-md-collapse-icon')
|
|
->toContain('data-md-collapse-chevron')
|
|
->toContain('How long do links last?')
|
|
->toContain('Until the expiry.')
|
|
->toContain('class="md-state-layer md-focus-ring"');
|
|
});
|
|
|
|
it('has no Alpine on it without a binding', function () {
|
|
$html = (string) $this->blade('<x-collapse title="Advanced" open>Body</x-collapse>');
|
|
|
|
expect($html)
|
|
->toMatch('/<details\s+wire:ignore.self\s+data-md-collapse\s+data-md-variant="plain"\s+open\s+/')
|
|
->not->toContain('x-data')
|
|
->not->toContain('x-modelable')
|
|
->not->toContain('x-on:toggle')
|
|
->and((string) $this->blade('<x-collapse title="Advanced">Body</x-collapse>'))
|
|
->toMatch('/<details\s+wire:ignore.self\s+data-md-collapse\s+data-md-variant="plain"\s+/');
|
|
});
|
|
|
|
it('binds its open state through x-model, drawing the open prop until Alpine starts', function () {
|
|
$html = (string) $this->blade('<x-collapse title="Advanced" x-model="advanced" open>Body</x-collapse>');
|
|
|
|
expect($html)
|
|
->toMatch('/x-data="{ collapseOpen:\s*true\s*}"/')
|
|
->toContain('x-modelable="collapseOpen"')
|
|
->toContain('x-model="advanced"')
|
|
->toContain('x-effect="$el.open = collapseOpen"')
|
|
->toContain('x-on:toggle="collapseOpen = $el.open"')
|
|
->toMatch('/\sopen\s/');
|
|
});
|
|
|
|
it('entangles its open state with a Livewire property and renders open as the property is', function (bool $fineTuning) {
|
|
Livewire::component('collapse-probe', new class extends Component
|
|
{
|
|
public bool $fineTuning = false;
|
|
|
|
public function render(): string
|
|
{
|
|
return '<div><x-collapse title="Fine-tuning" wire:model.live="fineTuning" :open="! $fineTuning">Body</x-collapse></div>';
|
|
}
|
|
});
|
|
|
|
$html = Livewire::test('collapse-probe', ['fineTuning' => $fineTuning])->html();
|
|
|
|
expect($html)
|
|
->toContain(".entangle('fineTuning').live")
|
|
->not->toContain('x-modelable')
|
|
->not->toContain('wire:model');
|
|
|
|
preg_match('/<details[^>]*>/', $html, $tag);
|
|
|
|
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');
|
|
});
|