])*>/');
});
it('counts the slides of a carousel inside a slide on their own', function () {
$html = (string) $this->blade(<<<'BLADE'
1
2
3
Two
BLADE);
expect($html)
->toContain('aria-label="1 of 3"')
->toContain('aria-label="3 of 3"')
->toContain('aria-label="1 of 2"')
->toContain('aria-label="2 of 2"');
});
it('browses many by default: 186px items that snap one at a time, 205px high', function () {
$html = (string) $this->blade('
A');
expect($html)
->toContain('data-material-carousel="multi-browse"')
->toContain('aria-label="Carousel"')
->toContain('--material-carousel-item-width: 186px; --material-carousel-slot: 186px; --material-carousel-height: 205px')
->toContain('x-ref="probe"')
->toContain('data-padding="16"')
->toContain('data-padding-end="16"')
->toContain('h-[calc(var(--material-carousel-height)+1rem)] py-2')
->toContain('snap-x snap-mandatory')
->toContain('snap-start snap-always')
->toContain('rounded-corner-xl')
->toContain('[clip-path:inset(0_var(--material-carousel-inset,0px)_round_var(--md-sys-shape-corner-xl))]')
->not->toContain('data-centered');
});
it('takes the item width in pixels or as a CSS length, and a height and padding', function () {
expect((string) $this->blade('
A'))
->toContain('--material-carousel-item-width: 220px; --material-carousel-slot: 220px; --material-carousel-height: 18rem')
->toContain('data-padding="24"')
->and((string) $this->blade('
A'))
->toContain('data-padding="16"')
->toContain('data-padding-end="0"')
->and((string) $this->blade('
A'))
->toContain('--material-carousel-item-width: 40%;');
});
it('lays out a hero that fills the width unless capped, centred on request', function () {
$filled = (string) $this->blade('
A');
expect($filled)
->toContain('data-material-carousel="hero"')
->toContain('data-centered')
->toContain('--material-carousel-slot: calc(100% - 64px)')
->toContain('snap-x snap-mandatory')
->not->toContain('x-ref="probe"')
->not->toContain('--material-carousel-item-width')
->and((string) $this->blade('
A'))
->toContain('--material-carousel-item-width: 600px')
->toContain('x-ref="probe"')
->not->toContain('data-centered');
});
it('leaves an uncontained carousel unsnapped, and a full-screen one a page wide', function () {
expect((string) $this->blade('
A'))
->toContain('data-material-carousel="uncontained"')
->toContain('--material-carousel-item-width: 180px')
->not->toContain('snap-mandatory')
->and((string) $this->blade('
A'))
->toContain('data-material-carousel="full-screen"')
->toContain('--material-carousel-slot: 100%')
->toContain('snap-mandatory')
->not->toContain('x-ref="probe"')
->not->toContain('data-centered')
->and((string) $this->blade('
A'))
->toContain('data-material-carousel="multi-browse"');
});
it('offers previous and next buttons for fine pointers, always, or never', function () {
$auto = (string) $this->blade('
A');
preg_match('/id="(material-carousel-[a-z0-9]+)"/', $auto, $scroller);
expect($auto)
->toContain('hidden pointer-fine:flex')
->toContain('aria-label="Previous"')
->toContain('aria-label="Next"')
->toContain('x-on:click="previous()"')
->toContain('x-on:click="next()"')
->toContain("aria-controls=\"{$scroller[1]}\"")
->toContain('rtl:-scale-x-100')
->and(substr_count($auto, "aria-controls=\"{$scroller[1]}\""))->toBe(2);
expect((string) $this->blade('
A'))
->toContain('aria-label="Next"')
->not->toContain('pointer-fine:flex');
expect((string) $this->blade('
A'))
->not->toContain('aria-label="Previous"')
->not->toContain('aria-label="Next"');
});
it('lays a label over an item on a scrim, and passes attributes to the item', function () {
$html = (string) $this->blade('

');
expect($html)
->toContain('data-material-carousel-item')
->toContain('wire:key="lake"')
->toContain('data-material-carousel-label')
->toContain('Lake Constance')
->toContain('from-scrim/60')
->toContain('type-title-md text-inverse-on-surface')
->toContain('[&>img]:size-full [&>img]:object-cover')
->and((string) $this->blade('
A'))
->not->toContain('data-material-carousel-label');
});