Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
06a9302
#31 : Add ProgressManager
vadimkorr Jul 1, 2021
9d00b1b
#31 : Add ProgressManager to carousel component
vadimkorr Jul 1, 2021
53a6a94
#31 : Add Progress component
vadimkorr Jul 1, 2021
9d4c624
#31 : Add Progress to carousel
vadimkorr Jul 1, 2021
892550f
#31 : Add todo comments
vadimkorr Jul 1, 2021
3f9f6c1
#31 : Update progress manager
vadimkorr Jul 2, 2021
ecca0c3
#31 : Fix swipe
vadimkorr Jul 2, 2021
903f665
#31 : Add progress indicator prop
vadimkorr Jul 2, 2021
8bc04bc
#31 : Fix story, convert value to number
vadimkorr Jul 2, 2021
deafbfb
#31 : Move setIntervalImmediate to utils
vadimkorr Jul 2, 2021
5f2a4c2
#31 : Wait animation finish
vadimkorr Jul 2, 2021
6dee586
#31 : Update progress position
vadimkorr Jul 2, 2021
158a748
#31 : Reset progress on destroy
vadimkorr Jul 2, 2021
e49556a
#31 : Code cleanup
vadimkorr Jul 2, 2021
a9515ed
#31 : Fix non infinite case
vadimkorr Jul 2, 2021
17e2e60
#31 : Update colors, set reversed progress indicator
vadimkorr Jul 2, 2021
a6a73d5
#31 : Fix storybook autoplayDirection
vadimkorr Jul 3, 2021
7ace64b
#31 : Fix autoplay progress for non infinite case
vadimkorr Jul 3, 2021
76766e9
#31 : Fix progress value prop
vadimkorr Jul 3, 2021
68f9f5d
#31 : Add progress storybook
vadimkorr Jul 3, 2021
1cca216
#31 : Move shared css vars to parent component
vadimkorr Jul 3, 2021
04d1558
#31 : Rename onValueChange -> onProgressValueChange
vadimkorr Jul 3, 2021
930ec9f
#31 : Add new demos
vadimkorr Jul 3, 2021
ac21022
#31 : Fix spelling 'auto play' -> autoplay
vadimkorr Jul 3, 2021
293798c
#31 : Extend docs
vadimkorr Jul 3, 2021
4ada913
#31 : Add unit tests
vadimkorr Jul 3, 2021
a9e8784
Merge branch 'main' into feature/#31_Show-pause-indicator
vadimkorr Jul 7, 2021
b70c1d6
#31 : Use step ms instead of steps count
vadimkorr Jul 7, 2021
922244b
Merge branch 'main' into feature/#31_Show-pause-indicator
vadimkorr Jul 15, 2021
8c03229
#31 : Code cleanup
vadimkorr Jul 15, 2021
aa52abb
#31 : Rename applyAutoplay -> applyAutoplayIfNeeded
vadimkorr Jul 15, 2021
3a68ec1
#31 : Rename delaysMs -> delayMs
vadimkorr Jul 15, 2021
3093984
#31 : Add comments
vadimkorr Jul 15, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
}
}]
],
"plugins": [
"@babel/plugin-proposal-class-properties"
],
"env": {
"test": {
"presets": [["@babel/preset-env"]]
Expand Down
25 changes: 13 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
109 changes: 83 additions & 26 deletions src/components/Carousel/Carousel.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -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()
}
}

/**
Expand Down Expand Up @@ -67,6 +86,11 @@
*/
export let pauseOnFocus = false

/**
* Show autoplay duration progress indicator
*/
export let autoplayProgressVisible = false

/**
* Current page indicator dots
*/
Expand Down Expand Up @@ -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()
}
}
}
Expand All @@ -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]
Expand All @@ -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]
Expand All @@ -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())
})
Expand Down Expand Up @@ -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 })
}
Expand All @@ -235,7 +279,7 @@
store.prev({ infinite, pagesCount })
offsetPage(animated)
const jumped = jumpIfNeeded()
!jumped && applyAutoplay()
!jumped && applyAutoplayIfNeeded({ delayMs: _duration })
}, { animated })
}
function showNextPage(options) {
Expand All @@ -244,7 +288,7 @@
store.next({ infinite, pagesCount })
offsetPage(animated)
const jumped = jumpIfNeeded()
!jumped && applyAutoplay()
!jumped && applyAutoplayIfNeeded({ delayMs: _duration })
}, { animated })
}

Expand Down Expand Up @@ -300,7 +344,12 @@
bind:this={pagesElement}
>
<slot {loaded}></slot>
</div>
</div>
{#if autoplayProgressVisible}
<div class="sc-carousel-progress__container">
<Progress value={progressValue} />
</div>
{/if}
</div>
{#if arrows}
<slot name="next" {showNextPage}>
Expand Down Expand Up @@ -353,6 +402,7 @@
display: flex;
overflow: hidden;
box-sizing: border-box;
position: relative;
}
.sc-carousel__pages-container {
width: 100%;
Expand All @@ -366,4 +416,11 @@
align-items: center;
justify-content: center;
}
</style>
.sc-carousel-progress__container {
width: 100%;
height: 5px;
background-color: var(--sc-color-rgb-light-50p);
position: absolute;
bottom: 0;
}
</style>
9 changes: 8 additions & 1 deletion src/components/Carousel/stories/CarouselView.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
/**
* CSS animation timing function
*/
export let timingFunction = "ease-in-out";
export let timingFunction = 'ease-in-out';

/**
* Enable Next/Previos arrows
Expand Down Expand Up @@ -46,6 +46,11 @@
*/
export let pauseOnFocus = false

/**
* Show autoplay duration progress indicator
*/
export let autoplayProgressVisible = false

/**
* Current page indicator dots
*/
Expand Down Expand Up @@ -82,6 +87,7 @@
{autoplayDuration}
{autoplayDirection}
{pauseOnFocus}
{autoplayProgressVisible}
{dots}
on:pageChange={
event => console.log(`Current page index: ${event.detail}`)
Expand All @@ -107,6 +113,7 @@
{autoplayDuration}
{autoplayDirection}
{pauseOnFocus}
{autoplayProgressVisible}
{dots}
>
{#each colors2 as { color, text } (color)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
/**
* CSS animation timing function
*/
export let timingFunction = "ease-in-out";
export let timingFunction = 'ease-in-out';

/**
* Enable Next/Previos arrows
Expand Down Expand Up @@ -46,6 +46,11 @@
*/
export let pauseOnFocus = false

/**
* Show autoplay duration progress indicator
*/
export let autoplayProgressVisible = false

/**
* Current page indicator dots
*/
Expand Down Expand Up @@ -76,6 +81,7 @@
{autoplayDuration}
{autoplayDirection}
{pauseOnFocus}
{autoplayProgressVisible}
{dots}
let:showPrevPage
let:showNextPage
Expand Down
10 changes: 8 additions & 2 deletions src/components/Carousel/stories/CarouselViewCustomDots.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
/**
* CSS animation timing function
*/
export let timingFunction = "ease-in-out";
export let timingFunction = 'ease-in-out';

/**
* Enable Next/Previos arrows
Expand Down Expand Up @@ -46,13 +46,18 @@
*/
export let pauseOnFocus = false

/**
* Show autoplay duration progress indicator
*/
export let autoplayProgressVisible = false

/**
* Current page indicator dots
*/
export let dots = true

function onPageChange(event, showPage) {
showPage(event.target.value)
showPage(Number(event.target.value))
}

const colors = [
Expand Down Expand Up @@ -80,6 +85,7 @@
{autoplayDuration}
{autoplayDirection}
{pauseOnFocus}
{autoplayProgressVisible}
{dots}
let:currentPageIndex
let:pagesCount
Expand Down
27 changes: 27 additions & 0 deletions src/components/Progress/Progress.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<script>
import { tweened } from 'svelte/motion';
import { cubicInOut } from 'svelte/easing';

const MAX_PERCENT = 100;

/**
* Progress value, [0, 1]
*/
export let value = 0

$: width = Math.min(Math.max(value * MAX_PERCENT, 0), MAX_PERCENT)
</script>

<div
class="sc-carousel-progress__indicator"
style="
width: {width}%;
"
></div>

<style>
.sc-carousel-progress__indicator {
height: 100%;
background-color: var(--sc-color-hex-dark-50p);
}
</style>
Loading