diff --git a/README.md b/README.md index 6150635..428f153 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ Import component and styles in App component | `autoplay` | `boolean` | `false` | Enables auto play of pages | | `autoplayDuration` | `number` | `3000` | Auto play change interval (ms) | | `autoplayDirection` | `string` | `'next'` | Auto play change direction (`next` or `prev`) | +| `pauseOnFocus` | `boolean` | `false` | Pause autoplay on focus | | `dots` | `boolean` | `true` | Current page indicator dots | | `timingFunction` | `string` | `'ease-in-out'` | CSS animation timing function | diff --git a/src/actions/focusable/event.js b/src/actions/focusable/event.js new file mode 100644 index 0000000..a52ddaf --- /dev/null +++ b/src/actions/focusable/event.js @@ -0,0 +1,21 @@ +// focusin event +export function addFocusinEventListener(source, cb) { + source.addEventListener('mouseenter', cb) + source.addEventListener('touchstart', cb) +} +export function removeFocusinEventListener(source, cb) { + source.removeEventListener('mouseenter', cb) + source.removeEventListener('touchstart', cb) +} + +// focusout event +export function addFocusoutEventListener(source, cb) { + source.addEventListener('mouseleave', cb) + source.addEventListener('touchend', cb) + source.addEventListener('touchcancel', cb) +} +export function removeFocusoutEventListener(source, cb) { + source.removeEventListener('mouseleave', cb) + source.removeEventListener('touchend', cb) + source.removeEventListener('touchcancel', cb) +} diff --git a/src/actions/focusable/focusable.js b/src/actions/focusable/focusable.js new file mode 100644 index 0000000..3e13deb --- /dev/null +++ b/src/actions/focusable/focusable.js @@ -0,0 +1,29 @@ +import { createDispatcher } from '../../utils/event' +import { + addFocusinEventListener, + removeFocusinEventListener, + addFocusoutEventListener, + removeFocusoutEventListener, +} from './event' + +export function focusable(node) { + const dispatch = createDispatcher(node) + + function handleFocusin() { + dispatch('focused', { value: true }) + } + + function handleFocusout() { + dispatch('focused', { value: false }) + } + + addFocusinEventListener(node, handleFocusin) + addFocusoutEventListener(node, handleFocusout) + + return { + destroy() { + removeFocusinEventListener(node, handleFocusin) + removeFocusoutEventListener(node, handleFocusout) + }, + } +} diff --git a/src/actions/focusable/index.js b/src/actions/focusable/index.js new file mode 100644 index 0000000..16fa8dd --- /dev/null +++ b/src/actions/focusable/index.js @@ -0,0 +1 @@ +export * from './focusable' diff --git a/src/components/Carousel/Carousel.svelte b/src/components/Carousel/Carousel.svelte index dea8e6c..230a02e 100644 --- a/src/components/Carousel/Carousel.svelte +++ b/src/components/Carousel/Carousel.svelte @@ -5,6 +5,7 @@ import Arrow from '../Arrow/Arrow.svelte' import { NEXT, PREV } from '../../direction' import { swipeable } from '../../actions/swipeable' + import { focusable } from '../../actions/focusable' import { addResizeEventListener, removeResizeEventListener @@ -60,6 +61,11 @@ */ export let autoplayDirection = NEXT + /** + * Pause autoplay on focus + */ + export let pauseOnFocus = false + /** * Current page indicator dots */ @@ -76,6 +82,18 @@ let offset = 0 let pageWindowElement let pagesElement + let focused = false + + let autoplayInterval = null + $: { + if (pauseOnFocus) { + if (focused) { + clearAutoplay() + } else { + applyAutoplay() + } + } + } // used for lazy loading images, preloaded only current, adjacent and cloanable images $: loaded = getAdjacentIndexes(originalCurrentPageIndex, originalPagesCount, infinite) @@ -96,15 +114,16 @@ } function applyAutoplay() { - let interval - if (autoplay) { - interval = setInterval(() => { + if (autoplay && !autoplayInterval) { + autoplayInterval = setInterval(() => { directionFnDescription[autoplayDirection]() }, autoplayDuration) } - return () => { - interval && clearInterval(interval) - } + } + + function clearAutoplay() { + clearInterval(autoplayInterval) + autoplayInterval = null } function addClones() { @@ -128,12 +147,13 @@ infinite && addClones() applyPageSizes() } - cleanupFns.push(applyAutoplay()) + applyAutoplay() addResizeEventListener(applyPageSizes) })() }) onDestroy(() => { + clearAutoplay() removeResizeEventListener(applyPageSizes) cleanupFns.filter(fn => fn && typeof fn === 'function').forEach(fn => fn()) }) @@ -198,6 +218,9 @@ function handleSwipeEnd() { showPage(currentPageIndex, { offsetDelay: 0, animated: true }) } + function handleFocused(event) { + focused = event.detail.value + }