diff --git a/packages/embla-carousel-auto-scroll/src/components/AutoScroll.ts b/packages/embla-carousel-auto-scroll/src/components/AutoScroll.ts index 4e49d81a2..485aef165 100644 --- a/packages/embla-carousel-auto-scroll/src/components/AutoScroll.ts +++ b/packages/embla-carousel-auto-scroll/src/components/AutoScroll.ts @@ -83,10 +83,7 @@ function AutoScroll(userOptions: AutoScrollOptionsType = {}): AutoScrollType { } if (options.stopOnFocusIn) { - eventStore.add(container, 'focusin', () => { - stopScroll() - emblaApi.scrollTo(emblaApi.selectedScrollSnap(), true) - }) + emblaApi.on('slideFocusStart', stopScroll) if (!options.stopOnInteraction) { eventStore.add(container, 'focusout', startScroll) @@ -100,6 +97,7 @@ function AutoScroll(userOptions: AutoScrollOptionsType = {}): AutoScrollType { emblaApi .off('pointerDown', stopScroll) .off('pointerUp', startScrollOnSettle) + .off('slideFocusStart', stopScroll) .off('settle', onSettle) stopScroll() destroyed = true diff --git a/packages/embla-carousel-autoplay/src/components/Autoplay.ts b/packages/embla-carousel-autoplay/src/components/Autoplay.ts index 1baa6a887..86e9fff17 100644 --- a/packages/embla-carousel-autoplay/src/components/Autoplay.ts +++ b/packages/embla-carousel-autoplay/src/components/Autoplay.ts @@ -79,7 +79,7 @@ function Autoplay(userOptions: AutoplayOptionsType = {}): AutoplayType { } if (options.stopOnFocusIn) { - eventStore.add(container, 'focusin', stopTimer) + emblaApi.on('slideFocusStart', stopTimer) if (!options.stopOnInteraction) { eventStore.add(container, 'focusout', startTimer) @@ -92,7 +92,10 @@ function Autoplay(userOptions: AutoplayOptionsType = {}): AutoplayType { } function destroy(): void { - emblaApi.off('pointerDown', stopTimer).off('pointerUp', startTimer) + emblaApi + .off('pointerDown', stopTimer) + .off('pointerUp', startTimer) + .off('slideFocusStart', stopTimer) stopTimer() destroyed = true playing = false diff --git a/packages/embla-carousel/src/components/EmblaCarousel.ts b/packages/embla-carousel/src/components/EmblaCarousel.ts index 9b8148737..b620cb814 100644 --- a/packages/embla-carousel/src/components/EmblaCarousel.ts +++ b/packages/embla-carousel/src/components/EmblaCarousel.ts @@ -112,7 +112,7 @@ function EmblaCarousel( engine.translate.to(engine.location.get()) engine.animation.init() engine.slidesInView.init() - engine.slideFocus.init() + engine.slideFocus.init(self) engine.eventHandler.init(self) engine.resizeHandler.init(self) engine.slidesHandler.init(self) diff --git a/packages/embla-carousel/src/components/EventHandler.ts b/packages/embla-carousel/src/components/EventHandler.ts index aa911d748..cc2c1e942 100644 --- a/packages/embla-carousel/src/components/EventHandler.ts +++ b/packages/embla-carousel/src/components/EventHandler.ts @@ -17,6 +17,7 @@ export interface EmblaEventListType { destroy: 'destroy' reInit: 'reInit' resize: 'resize' + slideFocusStart: 'slideFocusStart' slideFocus: 'slideFocus' } diff --git a/packages/embla-carousel/src/components/SlideFocus.ts b/packages/embla-carousel/src/components/SlideFocus.ts index e00e467f3..a4547418e 100644 --- a/packages/embla-carousel/src/components/SlideFocus.ts +++ b/packages/embla-carousel/src/components/SlideFocus.ts @@ -1,3 +1,4 @@ +import { EmblaCarouselType } from './EmblaCarousel' import { EventHandlerType } from './EventHandler' import { EventStoreType } from './EventStore' import { ScrollBodyType } from './ScrollBody' @@ -5,12 +6,15 @@ import { ScrollToType } from './ScrollTo' import { SlideRegistryType } from './SlideRegistry' import { isBoolean, isNumber } from './utils' -type FocusHandlerCallbackType = () => void +type FocusHandlerCallbackType = ( + emblaApi: EmblaCarouselType, + evt: FocusEvent +) => boolean | void export type FocusHandlerOptionType = boolean | FocusHandlerCallbackType export type SlideFocusType = { - init: () => void + init: (emblaApi: EmblaCarouselType) => void } export function SlideFocus( @@ -23,45 +27,51 @@ export function SlideFocus( eventHandler: EventHandlerType, watchFocus: FocusHandlerOptionType ): SlideFocusType { + const focusListenerOptions = { passive: true, capture: true } let lastTabPressTime = 0 - function init(): void { + function init(emblaApi: EmblaCarouselType): void { if (!watchFocus) return - eventStore.add(document, 'keydown', registerTabPress, false) - slides.forEach(addSlideFocusEvent) - } - - function registerTabPress(event: KeyboardEvent): void { - if (event.code === 'Tab') lastTabPressTime = new Date().getTime() - } - - function addSlideFocusEvent(slide: HTMLElement): void { - const defaultFocusHandler = (): void => { + const defaultCallback = (index: number): void => { const nowTime = new Date().getTime() const diffTime = nowTime - lastTabPressTime if (diffTime > 10) return + eventHandler.emit('slideFocusStart') root.scrollLeft = 0 - const index = slides.indexOf(slide) + const group = slideRegistry.findIndex((group) => group.includes(index)) if (!isNumber(group)) return scrollBody.useDuration(0) scrollTo.index(group, 0) + eventHandler.emit('slideFocus') } - const focus = isBoolean(watchFocus) ? defaultFocusHandler : watchFocus + eventStore.add(document, 'keydown', registerTabPress, false) - eventStore.add(slide, 'focus', focus, { - passive: true, - capture: true + slides.forEach((slide, slideIndex) => { + eventStore.add( + slide, + 'focus', + (evt: FocusEvent) => { + if (isBoolean(watchFocus) || watchFocus(emblaApi, evt)) { + defaultCallback(slideIndex) + } + }, + focusListenerOptions + ) }) } + function registerTabPress(event: KeyboardEvent): void { + if (event.code === 'Tab') lastTabPressTime = new Date().getTime() + } + const self: SlideFocusType = { init }