diff --git a/resources/js/carousel.js b/resources/js/carousel.js index c1260e8e..0d199027 100644 --- a/resources/js/carousel.js +++ b/resources/js/carousel.js @@ -808,6 +808,7 @@ document.addEventListener('alpine:init', () => { strategy: null, snaps: [], maxScroll: 0, + focalInset: 0, rtl: false, vertical: false, measured: false, @@ -1027,6 +1028,11 @@ document.addEventListener('alpine:init', () => { // moved or faded, so every item stays at strategy.itemSize. const still = state.reducedMotion.matches + // Content padding shrinks every keyline near the ends (Strategy.kt's + // createShiftedKeylineListForContentPadding), so an item at the focal size can still + // carry a small inset there: that inset, not zero, is "fully open" for isMasked(). + state.focalInset = still ? 0 : clamp((size - (firstFocal(keylines)?.size ?? size)) / 2, 0, size / 2) + state.items.forEach((item, index) => { const center = index * (size + strategy.itemSpacing) + size / 2 - scroll const before = keylineBefore(keylines, center) @@ -1220,7 +1226,7 @@ document.addEventListener('alpine:init', () => { return item.left < row.left - 1 || item.right > row.right + 1 } - return parseFloat(state.items[index].surface.style.getPropertyValue('--material-carousel-inset')) > 0.5 + return parseFloat(state.items[index].surface.style.getPropertyValue('--material-carousel-inset')) > state.focalInset + 0.5 }, destroy() { diff --git a/tests/Browser/CarouselTest.php b/tests/Browser/CarouselTest.php index 9b45d8f1..792f4761 100644 --- a/tests/Browser/CarouselTest.php +++ b/tests/Browser/CarouselTest.php @@ -145,9 +145,18 @@ it('snaps a scroll that stops between items onto an item', function () { JS)); }); -it('brings a partly hidden item into focus when it is pressed', function () { +it('brings a partly hidden item into focus when it is pressed, and leaves an open one where it is', function () { $page = carouselShowcase() - ->assertScript(onCarousel(0, 'return ! open(4)')); + ->assertScript(onCarousel(0, 'return open(1) && ! open(4)')); + + // Item 1 rests at the large size, short only of the content padding's share: focusing or + // pressing it moves nothing. + $page->script(onCarousel(0, 'items[1].focus(); items[1].querySelector(\'[data-material-carousel-content]\').click()')); + + $page->assertScript(onCarousel(0, <<<'JS' + await pause(400) + return scroller.scrollLeft === 0 && open(1) + JS)); $page->script(onCarousel(0, 'items[4].querySelector(\'[data-material-carousel-content]\').click()'));