diff --git a/.babelrc b/.babelrc
index cf55185..1c2bd59 100644
--- a/.babelrc
+++ b/.babelrc
@@ -7,6 +7,9 @@
}
}]
],
+ "plugins": [
+ "@babel/plugin-proposal-class-properties"
+ ],
"env": {
"test": {
"presets": [["@babel/preset-env"]]
diff --git a/README.md b/README.md
index 528b28d..85d3a01 100644
--- a/README.md
+++ b/README.md
@@ -34,18 +34,19 @@ Import component
```
## Props
-| Prop | Type | Default | Description |
-|----------------------|------------|-----------------|-----------------------------------------------|
-| `arrows` | `boolean` | `true` | Enable Next/Prev arrows |
-| `infinite` | `boolean` | `true` | Infinite looping |
-| `initialPageIndex` | `number` | `0` | Page to start on |
-| `duration` | `number` | `500` | Transition duration (ms) |
-| `autoplay` | `boolean` | `false` | Enables autoplay of pages |
-| `autoplayDuration` | `number` | `3000` | Autoplay change interval (ms) |
-| `autoplayDirection` | `string` | `'next'` | Autoplay 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 |
+| Prop | Type | Default | Description |
+|---------------------------|------------|-----------------|-----------------------------------------------|
+| `arrows` | `boolean` | `true` | Enable Next/Prev arrows |
+| `infinite` | `boolean` | `true` | Infinite looping |
+| `initialPageIndex` | `number` | `0` | Page to start on |
+| `duration` | `number` | `500` | Transition duration (ms) |
+| `autoplay` | `boolean` | `false` | Enables auto play of pages |
+| `autoplayDuration` | `number` | `3000` | Autoplay change interval (ms) |
+| `autoplayDirection` | `string` | `'next'` | Autoplay change direction (`next` or `prev`) |
+| `pauseOnFocus` | `boolean` | `false` | Pause autoplay on focus |
+| `autoplayProgressVisible` | `boolean` | `false` | Show autoplay duration progress indicator |
+| `dots` | `boolean` | `true` | Current page indicator dots |
+| `timingFunction` | `string` | `'ease-in-out'` | CSS animation timing function |
## Events
diff --git a/src/components/Carousel/Carousel.svelte b/src/components/Carousel/Carousel.svelte
index 6aa01b1..21d0393 100644
--- a/src/components/Carousel/Carousel.svelte
+++ b/src/components/Carousel/Carousel.svelte
@@ -3,6 +3,7 @@
import { createStore } from '../../store'
import Dots from '../Dots/Dots.svelte'
import Arrow from '../Arrow/Arrow.svelte'
+ import Progress from '../Progress/Progress.svelte'
import { NEXT, PREV } from '../../direction'
import { swipeable } from '../../actions/swipeable'
import { focusable } from '../../actions/focusable'
@@ -12,12 +13,30 @@
} from '../../utils/event'
import { getAdjacentIndexes } from '../../utils/page'
import { get } from '../../utils/object'
+ import { ProgressManager } from '../../utils/ProgressManager.js'
const dispatch = createEventDispatcher()
+ const autoplayDirectionFnDescription = {
+ [NEXT]: () => {
+ progressManager.start(() => {
+ showNextPage()
+ })
+ },
+ [PREV]: () => {
+ progressManager.start(() => {
+ showPrevPage()
+ })
+ }
+ }
+
const directionFnDescription = {
- [NEXT]: showNextPage,
- [PREV]: showPrevPage
+ [NEXT]: () => {
+ showNextPage()
+ },
+ [PREV]: () => {
+ showPrevPage()
+ }
}
/**
@@ -67,6 +86,11 @@
*/
export let pauseOnFocus = false
+ /**
+ * Show autoplay duration progress indicator
+ */
+ export let autoplayProgressVisible = false
+
/**
* Current page indicator dots
*/
@@ -103,13 +127,20 @@
let pagesElement
let focused = false
- let autoplayInterval = null
+ let progressValue
+ const progressManager = new ProgressManager({
+ autoplayDuration,
+ onProgressValueChange: (value) => {
+ progressValue = 1 - value
+ }
+ })
+
$: {
if (pauseOnFocus) {
if (focused) {
- clearAutoplay()
+ progressManager.pause()
} else {
- applyAutoplay()
+ progressManager.resume()
}
}
}
@@ -130,19 +161,6 @@
offsetPage(false)
}
-
- function applyAutoplay() {
- if (autoplay && !autoplayInterval) {
- autoplayInterval = setInterval(() => {
- directionFnDescription[autoplayDirection]()
- }, autoplayDuration)
- }
- }
-
- function clearAutoplay() {
- clearInterval(autoplayInterval)
- autoplayInterval = null
- }
function addClones() {
const first = pagesElement.children[0]
@@ -151,13 +169,38 @@
pagesElement.append(first.cloneNode(true))
}
+ function applyAutoplayIfNeeded(options) {
+ // prevent progress change if not infinite for first and last page
+ if (
+ !infinite && (
+ (autoplayDirection === NEXT && currentPageIndex === pagesCount - 1) ||
+ (autoplayDirection === PREV && currentPageIndex === 0)
+ )
+ ) {
+ progressManager.reset()
+ return
+ }
+ if (autoplay) {
+ const delayMs = get(options, 'delayMs', 0)
+ if (delayMs) {
+ setTimeout(() => {
+ autoplayDirectionFnDescription[autoplayDirection]()
+ }, delayMs)
+ } else {
+ autoplayDirectionFnDescription[autoplayDirection]()
+ }
+ }
+ }
+
let cleanupFns = []
+
onMount(() => {
(async () => {
await tick()
cleanupFns.push(store.subscribe(value => {
currentPageIndex = value.currentPageIndex
}))
+ cleanupFns.push(() => progressManager.reset())
if (pagesElement && pageWindowElement) {
// load first and last child to clone them
loaded = [0, pagesElement.children.length - 1]
@@ -167,13 +210,14 @@
store.init(initialPageIndex + Number(infinite))
applyPageSizes()
}
- applyAutoplay()
+
+ applyAutoplayIfNeeded()
+
addResizeEventListener(applyPageSizes)
})()
})
onDestroy(() => {
- clearAutoplay()
removeResizeEventListener(applyPageSizes)
cleanupFns.filter(fn => fn && typeof fn === 'function').forEach(fn => fn())
})
@@ -218,14 +262,14 @@
function showPage(pageIndex, options) {
const animated = get(options, 'animated', true)
- const offsetDelayMs = get(options, 'offsetDelayMs', true)
+ const offsetDelayMs = get(options, 'offsetDelayMs', 0)
safeChangePage(() => {
store.moveToPage({ pageIndex, pagesCount })
// delayed page transition, used for infinite autoplay to jump to real page
setTimeout(() => {
offsetPage(animated)
const jumped = jumpIfNeeded()
- !jumped && applyAutoplay()
+ !jumped && applyAutoplayIfNeeded({ delayMs: _duration }) // while offset animation is in progress (delayMs = _duration ms) wait for it
}, offsetDelayMs)
}, { animated })
}
@@ -235,7 +279,7 @@
store.prev({ infinite, pagesCount })
offsetPage(animated)
const jumped = jumpIfNeeded()
- !jumped && applyAutoplay()
+ !jumped && applyAutoplayIfNeeded({ delayMs: _duration })
}, { animated })
}
function showNextPage(options) {
@@ -244,7 +288,7 @@
store.next({ infinite, pagesCount })
offsetPage(animated)
const jumped = jumpIfNeeded()
- !jumped && applyAutoplay()
+ !jumped && applyAutoplayIfNeeded({ delayMs: _duration })
}, { animated })
}
@@ -300,7 +344,12 @@
bind:this={pagesElement}
>