import React, { useEffect, useRef } from 'react';
import { Swiper as SwiperClass, SwiperOptions } from 'swiper/types';
import { Swiper, SwiperSlide } from 'swiper/react';
import { Navigation, Pagination } from 'swiper/modules';
// Swiper CSS
import 'swiper/css';
import 'swiper/css/navigation';
import 'swiper/css/pagination';
interface AccessibleSwiperProps extends Omit<SwiperOptions, 'a11y'> {
children: React.ReactNode;
onSlideChange?: (swiper: SwiperClass) => void;
}
const AccessibleSwiper: React.FC<AccessibleSwiperProps> = ({ children, onSlideChange, ...swiperProps }) => {
const swiperRef = useRef<SwiperClass | null>(null);
useEffect(() => {
if (swiperRef.current) {
const swiper = swiperRef.current;
const updateSlideVisibility = () => {
swiper.slides.forEach((slide, index) => {
if (index >= swiper.activeIndex && index < swiper.activeIndex + (swiper.params.slidesPerView as number)) {
slide.removeAttribute('inert');
} else {
slide.setAttribute('inert', '');
}
});
};
const focusFirstInteractiveElement = () => {
const activeSlide = swiper.slides[swiper.activeIndex] as HTMLElement;
const interactiveElements = activeSlide.querySelectorAll<HTMLElement>(
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
);
const firstInteractiveElement = Array.from(interactiveElements).find(element =>
!element.hasAttribute('disabled') &&
element.getAttribute('aria-hidden') !== 'true' &&
!element.hasAttribute('inert')
);
if (firstInteractiveElement) {
firstInteractiveElement.focus();
}
};
const handleSlideChange = () => {
updateSlideVisibility();
focusFirstInteractiveElement();
if (onSlideChange) {
onSlideChange(swiper);
}
};
swiper.on('slideChange', handleSlideChange);
// 초기 상태 설정
updateSlideVisibility();
return () => {
swiper.off('slideChange', handleSlideChange);
};
}
}, [onSlideChange]);
const defaultSwiperOptions: SwiperOptions = {
modules: [Navigation, Pagination],
slidesPerView: 1,
spaceBetween: 30,
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev',
},
pagination: {
el: '.swiper-pagination',
clickable: true,
},
a11y: false, // Swiper의 기본 접근성 옵션 비활성화
};
return (
<Swiper
{...defaultSwiperOptions}
{...swiperProps}
onSwiper={(swiper) => {
swiperRef.current = swiper;
if (swiperProps.onSwiper) {
swiperProps.onSwiper(swiper);
}
}}
>
{children}
<div className="swiper-button-next" aria-label="다음 슬라이드"></div>
<div className="swiper-button-prev" aria-label="이전 슬라이드"></div>
<div className="swiper-pagination"></div>
</Swiper>
);
};
export default AccessibleSwiper;