33 import { createStore } from ' ../../store'
44 import Dots from ' ../Dots/Dots.svelte'
55 import Arrow from ' ../Arrow/Arrow.svelte'
6+ import Progress from ' ../Progress/Progress.svelte'
67 import { NEXT , PREV } from ' ../../direction'
78 import { swipeable } from ' ../../actions/swipeable'
89 import { focusable } from ' ../../actions/focusable'
1213 } from ' ../../utils/event'
1314 import { getAdjacentIndexes } from ' ../../utils/page'
1415 import { get } from ' ../../utils/object'
16+ import { ProgressManager } from ' ../../utils/ProgressManager.js'
1517
1618 const dispatch = createEventDispatcher ()
1719
20+ const autoplayDirectionFnDescription = {
21+ [NEXT ]: () => {
22+ progressManager .start (() => {
23+ showNextPage ()
24+ })
25+ },
26+ [PREV ]: () => {
27+ progressManager .start (() => {
28+ showPrevPage ()
29+ })
30+ }
31+ }
32+
1833 const directionFnDescription = {
19- [NEXT ]: showNextPage,
20- [PREV ]: showPrevPage
34+ [NEXT ]: () => {
35+ showNextPage ()
36+ },
37+ [PREV ]: () => {
38+ showPrevPage ()
39+ }
2140 }
2241
2342 /**
6786 */
6887 export let pauseOnFocus = false
6988
89+ /**
90+ * Show autoplay duration progress indicator
91+ */
92+ export let autoplayProgressVisible = false
93+
7094 /**
7195 * Current page indicator dots
7296 */
103127 let pagesElement
104128 let focused = false
105129
106- let autoplayInterval = null
130+ let progressValue
131+ const progressManager = new ProgressManager ({
132+ autoplayDuration,
133+ onProgressValueChange : (value ) => {
134+ progressValue = 1 - value
135+ }
136+ })
137+
107138 $: {
108139 if (pauseOnFocus) {
109140 if (focused) {
110- clearAutoplay ()
141+ progressManager . pause ()
111142 } else {
112- applyAutoplay ()
143+ progressManager . resume ()
113144 }
114145 }
115146 }
130161
131162 offsetPage (false )
132163 }
133-
134- function applyAutoplay () {
135- if (autoplay && ! autoplayInterval) {
136- autoplayInterval = setInterval (() => {
137- directionFnDescription[autoplayDirection]()
138- }, autoplayDuration)
139- }
140- }
141-
142- function clearAutoplay () {
143- clearInterval (autoplayInterval)
144- autoplayInterval = null
145- }
146164
147165 function addClones () {
148166 const first = pagesElement .children [0 ]
151169 pagesElement .append (first .cloneNode (true ))
152170 }
153171
172+ function applyAutoplayIfNeeded (options ) {
173+ // prevent progress change if not infinite for first and last page
174+ if (
175+ ! infinite && (
176+ (autoplayDirection === NEXT && currentPageIndex === pagesCount - 1 ) ||
177+ (autoplayDirection === PREV && currentPageIndex === 0 )
178+ )
179+ ) {
180+ progressManager .reset ()
181+ return
182+ }
183+ if (autoplay) {
184+ const delayMs = get (options, ' delayMs' , 0 )
185+ if (delayMs) {
186+ setTimeout (() => {
187+ autoplayDirectionFnDescription[autoplayDirection]()
188+ }, delayMs)
189+ } else {
190+ autoplayDirectionFnDescription[autoplayDirection]()
191+ }
192+ }
193+ }
194+
154195 let cleanupFns = []
196+
155197 onMount (() => {
156198 (async () => {
157199 await tick ()
158200 cleanupFns .push (store .subscribe (value => {
159201 currentPageIndex = value .currentPageIndex
160202 }))
203+ cleanupFns .push (() => progressManager .reset ())
161204 if (pagesElement && pageWindowElement) {
162205 // load first and last child to clone them
163206 loaded = [0 , pagesElement .children .length - 1 ]
167210 store .init (initialPageIndex + Number (infinite))
168211 applyPageSizes ()
169212 }
170- applyAutoplay ()
213+
214+ applyAutoplayIfNeeded ()
215+
171216 addResizeEventListener (applyPageSizes)
172217 })()
173218 })
174219
175220 onDestroy (() => {
176- clearAutoplay ()
177221 removeResizeEventListener (applyPageSizes)
178222 cleanupFns .filter (fn => fn && typeof fn === ' function' ).forEach (fn => fn ())
179223 })
218262
219263 function showPage (pageIndex , options ) {
220264 const animated = get (options, ' animated' , true )
221- const offsetDelayMs = get (options, ' offsetDelayMs' , true )
265+ const offsetDelayMs = get (options, ' offsetDelayMs' , 0 )
222266 safeChangePage (() => {
223267 store .moveToPage ({ pageIndex, pagesCount })
224268 // delayed page transition, used for infinite autoplay to jump to real page
225269 setTimeout (() => {
226270 offsetPage (animated)
227271 const jumped = jumpIfNeeded ()
228- ! jumped && applyAutoplay ()
272+ ! jumped && applyAutoplayIfNeeded ({ delayMs : _duration }) // while offset animation is in progress (delayMs = _duration ms) wait for it
229273 }, offsetDelayMs)
230274 }, { animated })
231275 }
235279 store .prev ({ infinite, pagesCount })
236280 offsetPage (animated)
237281 const jumped = jumpIfNeeded ()
238- ! jumped && applyAutoplay ( )
282+ ! jumped && applyAutoplayIfNeeded ({ delayMs : _duration } )
239283 }, { animated })
240284 }
241285 function showNextPage (options ) {
244288 store .next ({ infinite, pagesCount })
245289 offsetPage (animated)
246290 const jumped = jumpIfNeeded ()
247- ! jumped && applyAutoplay ( )
291+ ! jumped && applyAutoplayIfNeeded ({ delayMs : _duration } )
248292 }, { animated })
249293 }
250294
300344 bind:this ={pagesElement }
301345 >
302346 <slot {loaded }></slot >
303- </div >
347+ </div >
348+ {#if autoplayProgressVisible }
349+ <div class =" sc-carousel-progress__container" >
350+ <Progress value ={progressValue } />
351+ </div >
352+ {/if }
304353 </div >
305354 {#if arrows }
306355 <slot name ="next" {showNextPage }>
353402 display : flex ;
354403 overflow : hidden ;
355404 box-sizing : border-box ;
405+ position : relative ;
356406 }
357407 .sc-carousel__pages-container {
358408 width : 100% ;
366416 align-items : center ;
367417 justify-content : center ;
368418 }
369- </style >
419+ .sc-carousel-progress__container {
420+ width : 100% ;
421+ height : 5px ;
422+ background-color : var (--sc-color-rgb-light-50p );
423+ position : absolute ;
424+ bottom : 0 ;
425+ }
426+ </style >
0 commit comments