Skip to content

Commit 7af43e1

Browse files
committed
fix: mark offscreen slides inert (fix #304)
1 parent fa09bbe commit 7af43e1

File tree

3 files changed

+24
-6
lines changed

3 files changed

+24
-6
lines changed

src/modules/Carousel.tsx

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,12 @@ import {
1212
getSlideKey,
1313
hasSlides,
1414
isImageSlide,
15+
makeInertWhen,
1516
parseLengthPercentage,
1617
} from "../utils.js";
1718
import { ImageSlide } from "../components/index.js";
1819
import { useController } from "./Controller/index.js";
19-
import { useLightboxProps, useLightboxState } from "../contexts/index.js";
20+
import { useDocumentContext, useLightboxProps, useLightboxState } from "../contexts/index.js";
2021
import { CLASS_FLEX_CENTER, CLASS_SLIDE_WRAPPER, MODULE_CAROUSEL } from "../consts.js";
2122

2223
function cssPrefix(value?: string) {
@@ -36,14 +37,23 @@ function CarouselSlide({ slide, offset }: CarouselSlideProps) {
3637
const containerRef = React.useRef<HTMLDivElement | null>(null);
3738

3839
const { currentIndex } = useLightboxState();
39-
const { slideRect, close } = useController();
40+
const { slideRect, close, focus } = useController();
4041
const {
4142
render,
4243
carousel: { imageFit, imageProps },
4344
on: { click: onClick },
4445
controller: { closeOnBackdropClick },
4546
styles: { slide: style },
4647
} = useLightboxProps();
48+
const { getOwnerDocument } = useDocumentContext();
49+
50+
const offscreen = offset !== 0;
51+
52+
React.useEffect(() => {
53+
if (offscreen && containerRef.current?.contains(getOwnerDocument().activeElement)) {
54+
focus();
55+
}
56+
}, [offscreen, focus, getOwnerDocument]);
4757

4858
const renderSlide = () => {
4959
let rendered = render.slide?.({ slide, offset, rect: slideRect });
@@ -57,7 +67,7 @@ function CarouselSlide({ slide, offset }: CarouselSlideProps) {
5767
rect={slideRect}
5868
imageFit={imageFit}
5969
imageProps={imageProps}
60-
onClick={offset === 0 ? () => onClick?.({ index: currentIndex }) : undefined}
70+
onClick={!offscreen ? () => onClick?.({ index: currentIndex }) : undefined}
6171
/>
6272
);
6373
}
@@ -93,10 +103,10 @@ function CarouselSlide({ slide, offset }: CarouselSlideProps) {
93103
ref={containerRef}
94104
className={clsx(
95105
cssClass(cssSlidePrefix()),
96-
offset === 0 && cssClass(cssSlidePrefix("current")),
106+
!offscreen && cssClass(cssSlidePrefix("current")),
97107
cssClass(CLASS_FLEX_CENTER),
98108
)}
99-
aria-hidden={offset !== 0}
109+
{...makeInertWhen(offscreen)}
100110
onClick={handleBackdropClick}
101111
style={style}
102112
>

src/modules/Portal.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ export function Portal({ children, animation, styles, className, on, portal, clo
8484
for (let i = 0; i < elements.length; i += 1) {
8585
const element = elements[i];
8686
if (["TEMPLATE", "SCRIPT", "STYLE"].indexOf(element.tagName) === -1 && element !== node) {
87-
cleanup.current.push(setAttribute(element, "inert", "true"));
87+
cleanup.current.push(setAttribute(element, "inert", ""));
8888
cleanup.current.push(setAttribute(element, "aria-hidden", "true"));
8989
}
9090
}

src/utils.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,3 +157,11 @@ export function calculatePreload(carousel: CarouselSettings, slides: Slide[], mi
157157
Math.max(carousel.finite ? slides.length - 1 : Math.floor(slides.length / 2), minimum),
158158
);
159159
}
160+
161+
const isReact19 = Number(React.version.split(".")[0]) >= 19;
162+
163+
// this hack is necessary to support the upcoming breaking change in React 19 - https://github.com/facebook/react/pull/24730
164+
export function makeInertWhen(condition: boolean) {
165+
const legacyValue = condition ? "" : undefined;
166+
return { inert: isReact19 ? condition : legacyValue };
167+
}

0 commit comments

Comments
 (0)