1// SwiperJS has a hard time understanding how to deal with keyboard focus and 2// setting the slider positioning. 3// Because we have items with very different widths, and we use "auto" for 4// the actual movement, the focus goes out of sync with the visual visibility. 5// This function is called when the swiper is initialized. 6// We listen on focus within the item wrapper, and when we detect it, we 7// calculate our own transform value, overwriting SwiperJS. 8function swiperWrapperEventInit(swiper) { 9 const swiperWrapper = swiper.el.querySelector(".swiper-wrapper"); 10 11 swiperWrapper.addEventListener("focusin", () => { 12 // SwiperJS really wants to remove the tranisition duraton when not in use, 13 // but we still want it active when using keyboard tabbing. 14 swiperWrapper.style.transitionDuration = "300ms"; 15 16 const activeSlide = swiperWrapper.querySelector(".swiper-slide-active"); 17 18 if (!activeSlide) { 19 return; 20 } 21 22 let currentSibling = activeSlide; 23 let translateWidth = 0; 24 let sideMargins = 0; 25 26 // Finding all previous siblings. 27 while (currentSibling.previousElementSibling) { 28 currentSibling = currentSibling.previousElementSibling; 29 30 // Offset width only gives us the 'inner' width. We also need to get 31 // the side margins. 32 const style = getComputedStyle(currentSibling); 33 sideMargins = 34 parseInt(style.marginLeft, 10) + parseInt(style.marginRight, 10); 35 36 // Set a new translate width, used in transform. 37 translateWidth -= currentSibling.offsetWidth + sideMargins; 38 } 39 40 if (translateWidth === 0) { 41 return; 42 } 43 44 // Calculate a new translate value, for pulling the slider. 45 // We add half of the latest known sidemargin, so the active slide doesn't 46 // go flush against the screen. 47 translateWidth = Math.floor(translateWidth + sideMargins / 2); 48 49 swiper.setTranslate(translateWidth); 50 }); 51} 52 53// We want to make the controls not controllable by keyboard, as it quickly 54// becomes a confusing experience, when the active-slide is not what you get to 55// when you tab along. 56function disableKeyboardNavigation(swiper) { 57 const controls = swiper.el.querySelectorAll(".swiper-next, .swiper-prev"); 58 59 controls.forEach((control) => { 60 // eslint-disable-next-line no-param-reassign 61 control.tabIndex = -1; 62 }); 63} 64 65// Initialize the Swiper library, when the page is ready. 66window.addEventListener("load", () => { 67 // eslint-disable-next-line no-undef, @typescript-eslint/no-unused-vars 68 const swiperInit = new Swiper(".swiper", { 69 slidesPerView: "auto", 70 spaceBetween: "5%", 71 freeMode: true, 72 centeredSlidesBounds: false, 73 on: { 74 afterInit: (swiper) => { 75 swiperWrapperEventInit(swiper); 76 disableKeyboardNavigation(swiper); 77 }, 78 transitionEnd: (swiper) => { 79 disableKeyboardNavigation(swiper); 80 }, 81 }, 82 a11y: { 83 slideRole: "listitem", 84 }, 85 navigation: { 86 nextEl: ".swiper-next", 87 prevEl: ".swiper-prev", 88 }, 89 breakpoints: { 90 1200: { 91 spaceBetween: 82, 92 }, 93 }, 94 }); 95});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.