From 895da2888e4e8613f2f3dbaa4c150429b0afd85d Mon Sep 17 00:00:00 2001 From: Vlad Tansky Date: Sun, 11 Jul 2021 10:38:58 +0300 Subject: [PATCH] feat(freeMode): init (#4240) --- cypress/integration/modules/free-mode.js | 26 +++ scripts/build-config.js | 1 + src/angular/src/swiper.component.ts | 7 - src/angular/src/utils/params-list.ts | 7 - src/components/core/classes/addClasses.js | 2 +- src/components/core/core-class.js | 2 +- src/components/core/defaults.js | 10 - src/components/core/events/onTouchEnd.js | 179 +---------------- src/components/core/events/onTouchMove.js | 14 +- src/components/free-mode/free-mode.js | 224 ++++++++++++++++++++++ src/components/lazy/lazy.js | 2 +- src/components/mousewheel/mousewheel.js | 2 +- src/react/params-list.js | 7 - src/svelte/params-list.js | 7 - src/swiper.d.ts | 2 + src/types/components/free-mode.d.ts | 76 ++++++++ src/types/components/public-api.d.ts | 1 + src/types/swiper-class.d.ts | 2 + src/types/swiper-events.d.ts | 2 + src/types/swiper-options.d.ts | 52 +---- src/vue/params-list.js | 7 - src/vue/swiper.js | 9 +- 22 files changed, 346 insertions(+), 295 deletions(-) create mode 100644 cypress/integration/modules/free-mode.js create mode 100644 src/components/free-mode/free-mode.js create mode 100644 src/types/components/free-mode.d.ts diff --git a/cypress/integration/modules/free-mode.js b/cypress/integration/modules/free-mode.js new file mode 100644 index 000000000..fc132d69c --- /dev/null +++ b/cypress/integration/modules/free-mode.js @@ -0,0 +1,26 @@ +/// + +context('FreeMode', () => { + beforeEach(() => { + cy.swiperPage(); + }); + + it('freeMode', () => { + cy.initSwiper({ + freeMode: { + enabled: true, + }, + }); + cy.swipeLeft(); + cy.getActiveSlide().should(($el) => { + expect($el[0].offsetLeft).to.be.greaterThan(800); + }); + }); + // it('freeModeMinimumVelocity', () => {}); + // it('freeModeMomentum', () => {}); + // it('freeModeMomentumBounce', () => {}); + // it('freeModeMomentumBounceRatio', () => {}); + // it('freeModeMomentumRatio', () => {}); + // it('freeModeMomentumVelocityRatio', () => {}); + // it('freeModeSticky', () => {}); +}); diff --git a/scripts/build-config.js b/scripts/build-config.js index 1876f5d2a..9467cf531 100644 --- a/scripts/build-config.js +++ b/scripts/build-config.js @@ -19,6 +19,7 @@ module.exports = { 'effect-flip', 'effect-coverflow', 'thumbs', + 'free-mode', 'slides-per-column', ], themeColor: '#007aff', diff --git a/src/angular/src/swiper.component.ts b/src/angular/src/swiper.component.ts index ba9fdd683..37ad5d126 100644 --- a/src/angular/src/swiper.component.ts +++ b/src/angular/src/swiper.component.ts @@ -69,13 +69,6 @@ export class SwiperComponent implements OnInit { @Input() edgeSwipeDetection: boolean | string; @Input() edgeSwipeThreshold: number; @Input() freeMode: SwiperOptions['freeMode']; - @Input() freeModeMomentum: SwiperOptions['freeModeMomentum']; - @Input() freeModeMomentumRatio: SwiperOptions['freeModeMomentumRatio']; - @Input() freeModeMomentumBounce: SwiperOptions['freeModeMomentumBounce']; - @Input() freeModeMomentumBounceRatio: SwiperOptions['freeModeMomentumBounceRatio']; - @Input() freeModeMomentumVelocityRatio: SwiperOptions['freeModeMomentumVelocityRatio']; - @Input() freeModeSticky: SwiperOptions['freeModeSticky']; - @Input() freeModeMinimumVelocity: SwiperOptions['freeModeMinimumVelocity']; @Input() autoHeight: SwiperOptions['autoHeight']; @Input() setWrapperSize: SwiperOptions['setWrapperSize']; @Input() virtualTranslate: SwiperOptions['virtualTranslate']; diff --git a/src/angular/src/utils/params-list.ts b/src/angular/src/utils/params-list.ts index da78adff1..416ca2fa6 100644 --- a/src/angular/src/utils/params-list.ts +++ b/src/angular/src/utils/params-list.ts @@ -18,13 +18,6 @@ export const paramsList = [ '_edgeSwipeDetection', '_edgeSwipeThreshold', '_freeMode', - '_freeModeMomentum', - '_freeModeMomentumRatio', - '_freeModeMomentumBounce', - '_freeModeMomentumBounceRatio', - '_freeModeMomentumVelocityRatio', - '_freeModeSticky', - '_freeModeMinimumVelocity', '_autoHeight', 'setWrapperSize', 'virtualTranslate', diff --git a/src/components/core/classes/addClasses.js b/src/components/core/classes/addClasses.js index b34dfad7e..d865d304a 100644 --- a/src/components/core/classes/addClasses.js +++ b/src/components/core/classes/addClasses.js @@ -22,7 +22,7 @@ export default function addClasses() { 'initialized', params.direction, { 'pointer-events': support.pointerEvents && !support.touch }, - { 'free-mode': params.freeMode }, + { 'free-mode': swiper.params.freeMode && params.freeMode.enabled }, { 'autoheight': params.autoHeight }, { 'rtl': rtl }, { 'multirow': params.slidesPerColumn > 1 }, diff --git a/src/components/core/core-class.js b/src/components/core/core-class.js index cbf73510f..4c28c6aa5 100644 --- a/src/components/core/core-class.js +++ b/src/components/core/core-class.js @@ -375,7 +375,7 @@ class Swiper { swiper.updateSlidesClasses(); } let translated; - if (swiper.params.freeMode) { + if (swiper.params.freeMode && swiper.params.freeMode.enabled) { setTranslate(); if (swiper.params.autoHeight) { swiper.updateAutoHeight(); diff --git a/src/components/core/defaults.js b/src/components/core/defaults.js index c342da3ad..e26d9d171 100644 --- a/src/components/core/defaults.js +++ b/src/components/core/defaults.js @@ -27,16 +27,6 @@ export default { edgeSwipeDetection: false, edgeSwipeThreshold: 20, - // Free mode - freeMode: false, - freeModeMomentum: true, - freeModeMomentumRatio: 1, - freeModeMomentumBounce: true, - freeModeMomentumBounceRatio: 1, - freeModeMomentumVelocityRatio: 1, - freeModeSticky: false, - freeModeMinimumVelocity: 0.02, - // Autoheight autoHeight: false, diff --git a/src/components/core/events/onTouchEnd.js b/src/components/core/events/onTouchEnd.js index a1acd545c..a33cc2054 100644 --- a/src/components/core/events/onTouchEnd.js +++ b/src/components/core/events/onTouchEnd.js @@ -4,7 +4,7 @@ export default function onTouchEnd(event) { const swiper = this; const data = swiper.touchEventsData; - const { params, touches, rtlTranslate: rtl, $wrapperEl, slidesGrid, snapGrid, enabled } = swiper; + const { params, touches, rtlTranslate: rtl, slidesGrid, enabled } = swiper; if (!enabled) return; let e = event; if (e.originalEvent) e = e.originalEvent; @@ -75,181 +75,8 @@ export default function onTouchEnd(event) { return; } - if (params.freeMode) { - if (currentPos < -swiper.minTranslate()) { - swiper.slideTo(swiper.activeIndex); - return; - } - if (currentPos > -swiper.maxTranslate()) { - if (swiper.slides.length < snapGrid.length) { - swiper.slideTo(snapGrid.length - 1); - } else { - swiper.slideTo(swiper.slides.length - 1); - } - return; - } - - if (params.freeModeMomentum) { - if (data.velocities.length > 1) { - const lastMoveEvent = data.velocities.pop(); - const velocityEvent = data.velocities.pop(); - - const distance = lastMoveEvent.position - velocityEvent.position; - const time = lastMoveEvent.time - velocityEvent.time; - swiper.velocity = distance / time; - swiper.velocity /= 2; - if (Math.abs(swiper.velocity) < params.freeModeMinimumVelocity) { - swiper.velocity = 0; - } - // this implies that the user stopped moving a finger then released. - // There would be no events with distance zero, so the last event is stale. - if (time > 150 || now() - lastMoveEvent.time > 300) { - swiper.velocity = 0; - } - } else { - swiper.velocity = 0; - } - swiper.velocity *= params.freeModeMomentumVelocityRatio; - - data.velocities.length = 0; - let momentumDuration = 1000 * params.freeModeMomentumRatio; - const momentumDistance = swiper.velocity * momentumDuration; - - let newPosition = swiper.translate + momentumDistance; - if (rtl) newPosition = -newPosition; - - let doBounce = false; - let afterBouncePosition; - const bounceAmount = Math.abs(swiper.velocity) * 20 * params.freeModeMomentumBounceRatio; - let needsLoopFix; - if (newPosition < swiper.maxTranslate()) { - if (params.freeModeMomentumBounce) { - if (newPosition + swiper.maxTranslate() < -bounceAmount) { - newPosition = swiper.maxTranslate() - bounceAmount; - } - afterBouncePosition = swiper.maxTranslate(); - doBounce = true; - data.allowMomentumBounce = true; - } else { - newPosition = swiper.maxTranslate(); - } - if (params.loop && params.centeredSlides) needsLoopFix = true; - } else if (newPosition > swiper.minTranslate()) { - if (params.freeModeMomentumBounce) { - if (newPosition - swiper.minTranslate() > bounceAmount) { - newPosition = swiper.minTranslate() + bounceAmount; - } - afterBouncePosition = swiper.minTranslate(); - doBounce = true; - data.allowMomentumBounce = true; - } else { - newPosition = swiper.minTranslate(); - } - if (params.loop && params.centeredSlides) needsLoopFix = true; - } else if (params.freeModeSticky) { - let nextSlide; - for (let j = 0; j < snapGrid.length; j += 1) { - if (snapGrid[j] > -newPosition) { - nextSlide = j; - break; - } - } - - if ( - Math.abs(snapGrid[nextSlide] - newPosition) < - Math.abs(snapGrid[nextSlide - 1] - newPosition) || - swiper.swipeDirection === 'next' - ) { - newPosition = snapGrid[nextSlide]; - } else { - newPosition = snapGrid[nextSlide - 1]; - } - newPosition = -newPosition; - } - if (needsLoopFix) { - swiper.once('transitionEnd', () => { - swiper.loopFix(); - }); - } - // Fix duration - if (swiper.velocity !== 0) { - if (rtl) { - momentumDuration = Math.abs((-newPosition - swiper.translate) / swiper.velocity); - } else { - momentumDuration = Math.abs((newPosition - swiper.translate) / swiper.velocity); - } - if (params.freeModeSticky) { - // If freeModeSticky is active and the user ends a swipe with a slow-velocity - // event, then durations can be 20+ seconds to slide one (or zero!) slides. - // It's easy to see this when simulating touch with mouse events. To fix this, - // limit single-slide swipes to the default slide duration. This also has the - // nice side effect of matching slide speed if the user stopped moving before - // lifting finger or mouse vs. moving slowly before lifting the finger/mouse. - // For faster swipes, also apply limits (albeit higher ones). - const moveDistance = Math.abs((rtl ? -newPosition : newPosition) - swiper.translate); - const currentSlideSize = swiper.slidesSizesGrid[swiper.activeIndex]; - if (moveDistance < currentSlideSize) { - momentumDuration = params.speed; - } else if (moveDistance < 2 * currentSlideSize) { - momentumDuration = params.speed * 1.5; - } else { - momentumDuration = params.speed * 2.5; - } - } - } else if (params.freeModeSticky) { - swiper.slideToClosest(); - return; - } - - if (params.freeModeMomentumBounce && doBounce) { - swiper.updateProgress(afterBouncePosition); - swiper.setTransition(momentumDuration); - swiper.setTranslate(newPosition); - swiper.transitionStart(true, swiper.swipeDirection); - swiper.animating = true; - $wrapperEl.transitionEnd(() => { - if (!swiper || swiper.destroyed || !data.allowMomentumBounce) return; - swiper.emit('momentumBounce'); - swiper.setTransition(params.speed); - setTimeout(() => { - swiper.setTranslate(afterBouncePosition); - $wrapperEl.transitionEnd(() => { - if (!swiper || swiper.destroyed) return; - swiper.transitionEnd(); - }); - }, 0); - }); - } else if (swiper.velocity) { - swiper.updateProgress(newPosition); - swiper.setTransition(momentumDuration); - swiper.setTranslate(newPosition); - swiper.transitionStart(true, swiper.swipeDirection); - if (!swiper.animating) { - swiper.animating = true; - $wrapperEl.transitionEnd(() => { - if (!swiper || swiper.destroyed) return; - swiper.transitionEnd(); - }); - } - } else { - swiper.emit('_freeModeNoMomentumRelease'); - swiper.updateProgress(newPosition); - } - - swiper.updateActiveIndex(); - swiper.updateSlidesClasses(); - } else if (params.freeModeSticky) { - swiper.slideToClosest(); - return; - } else if (params.freeMode) { - swiper.emit('_freeModeNoMomentumRelease'); - } - - if (!params.freeModeMomentum || timeDiff >= params.longSwipesMs) { - swiper.updateProgress(); - swiper.updateActiveIndex(); - swiper.updateSlidesClasses(); - } + if (swiper.params.freeMode && params.freeMode.enabled) { + swiper.freeMode.onTouchEnd({ currentPos }); return; } diff --git a/src/components/core/events/onTouchMove.js b/src/components/core/events/onTouchMove.js index 6d4749f77..838212a01 100644 --- a/src/components/core/events/onTouchMove.js +++ b/src/components/core/events/onTouchMove.js @@ -216,18 +216,8 @@ export default function onTouchMove(event) { swiper.updateActiveIndex(); swiper.updateSlidesClasses(); } - if (params.freeMode) { - // Velocity - if (data.velocities.length === 0) { - data.velocities.push({ - position: touches[swiper.isHorizontal() ? 'startX' : 'startY'], - time: data.touchStartTime, - }); - } - data.velocities.push({ - position: touches[swiper.isHorizontal() ? 'currentX' : 'currentY'], - time: now(), - }); + if (swiper.params.freeMode && params.freeMode.enabled) { + swiper.freeMode.onTouchMove(); } // Update progress swiper.updateProgress(data.currentTranslate); diff --git a/src/components/free-mode/free-mode.js b/src/components/free-mode/free-mode.js new file mode 100644 index 000000000..5f6e2d814 --- /dev/null +++ b/src/components/free-mode/free-mode.js @@ -0,0 +1,224 @@ +import { bindModuleMethods, now } from '../../utils/utils'; + +const FreeMode = { + onTouchMove() { + const swiper = this; + const { touchEventsData: data, touches } = swiper; + // Velocity + if (data.velocities.length === 0) { + data.velocities.push({ + position: touches[swiper.isHorizontal() ? 'startX' : 'startY'], + time: data.touchStartTime, + }); + } + data.velocities.push({ + position: touches[swiper.isHorizontal() ? 'currentX' : 'currentY'], + time: now(), + }); + }, + onTouchEnd({ currentPos }) { + const swiper = this; + const { params, $wrapperEl, rtlTranslate: rtl, snapGrid } = swiper; + const data = swiper.touchEventsData; + // Time diff + const touchEndTime = now(); + const timeDiff = touchEndTime - data.touchStartTime; + + if (currentPos < -swiper.minTranslate()) { + swiper.slideTo(swiper.activeIndex); + return; + } + if (currentPos > -swiper.maxTranslate()) { + if (swiper.slides.length < snapGrid.length) { + swiper.slideTo(snapGrid.length - 1); + } else { + swiper.slideTo(swiper.slides.length - 1); + } + return; + } + + if (params.freeMode.momentum) { + if (data.velocities.length > 1) { + const lastMoveEvent = data.velocities.pop(); + const velocityEvent = data.velocities.pop(); + + const distance = lastMoveEvent.position - velocityEvent.position; + const time = lastMoveEvent.time - velocityEvent.time; + swiper.velocity = distance / time; + swiper.velocity /= 2; + if (Math.abs(swiper.velocity) < params.freeMode.minimumVelocity) { + swiper.velocity = 0; + } + // this implies that the user stopped moving a finger then released. + // There would be no events with distance zero, so the last event is stale. + if (time > 150 || now() - lastMoveEvent.time > 300) { + swiper.velocity = 0; + } + } else { + swiper.velocity = 0; + } + swiper.velocity *= params.freeMode.momentumVelocityRatio; + + data.velocities.length = 0; + let momentumDuration = 1000 * params.freeMode.momentumRatio; + const momentumDistance = swiper.velocity * momentumDuration; + + let newPosition = swiper.translate + momentumDistance; + if (rtl) newPosition = -newPosition; + + let doBounce = false; + let afterBouncePosition; + const bounceAmount = Math.abs(swiper.velocity) * 20 * params.freeMode.momentumBounceRatio; + let needsLoopFix; + if (newPosition < swiper.maxTranslate()) { + if (params.freeMode.momentumBounce) { + if (newPosition + swiper.maxTranslate() < -bounceAmount) { + newPosition = swiper.maxTranslate() - bounceAmount; + } + afterBouncePosition = swiper.maxTranslate(); + doBounce = true; + data.allowMomentumBounce = true; + } else { + newPosition = swiper.maxTranslate(); + } + if (params.loop && params.centeredSlides) needsLoopFix = true; + } else if (newPosition > swiper.minTranslate()) { + if (params.freeMode.momentumBounce) { + if (newPosition - swiper.minTranslate() > bounceAmount) { + newPosition = swiper.minTranslate() + bounceAmount; + } + afterBouncePosition = swiper.minTranslate(); + doBounce = true; + data.allowMomentumBounce = true; + } else { + newPosition = swiper.minTranslate(); + } + if (params.loop && params.centeredSlides) needsLoopFix = true; + } else if (params.freeMode.sticky) { + let nextSlide; + for (let j = 0; j < snapGrid.length; j += 1) { + if (snapGrid[j] > -newPosition) { + nextSlide = j; + break; + } + } + + if ( + Math.abs(snapGrid[nextSlide] - newPosition) < + Math.abs(snapGrid[nextSlide - 1] - newPosition) || + swiper.swipeDirection === 'next' + ) { + newPosition = snapGrid[nextSlide]; + } else { + newPosition = snapGrid[nextSlide - 1]; + } + newPosition = -newPosition; + } + if (needsLoopFix) { + swiper.once('transitionEnd', () => { + swiper.loopFix(); + }); + } + // Fix duration + if (swiper.velocity !== 0) { + if (rtl) { + momentumDuration = Math.abs((-newPosition - swiper.translate) / swiper.velocity); + } else { + momentumDuration = Math.abs((newPosition - swiper.translate) / swiper.velocity); + } + if (params.freeMode.sticky) { + // If freeMode.sticky is active and the user ends a swipe with a slow-velocity + // event, then durations can be 20+ seconds to slide one (or zero!) slides. + // It's easy to see this when simulating touch with mouse events. To fix this, + // limit single-slide swipes to the default slide duration. This also has the + // nice side effect of matching slide speed if the user stopped moving before + // lifting finger or mouse vs. moving slowly before lifting the finger/mouse. + // For faster swipes, also apply limits (albeit higher ones). + const moveDistance = Math.abs((rtl ? -newPosition : newPosition) - swiper.translate); + const currentSlideSize = swiper.slidesSizesGrid[swiper.activeIndex]; + if (moveDistance < currentSlideSize) { + momentumDuration = params.speed; + } else if (moveDistance < 2 * currentSlideSize) { + momentumDuration = params.speed * 1.5; + } else { + momentumDuration = params.speed * 2.5; + } + } + } else if (params.freeMode.sticky) { + swiper.slideToClosest(); + return; + } + + if (params.freeMode.momentumBounce && doBounce) { + swiper.updateProgress(afterBouncePosition); + swiper.setTransition(momentumDuration); + swiper.setTranslate(newPosition); + swiper.transitionStart(true, swiper.swipeDirection); + swiper.animating = true; + $wrapperEl.transitionEnd(() => { + if (!swiper || swiper.destroyed || !data.allowMomentumBounce) return; + swiper.emit('momentumBounce'); + swiper.setTransition(params.speed); + setTimeout(() => { + swiper.setTranslate(afterBouncePosition); + $wrapperEl.transitionEnd(() => { + if (!swiper || swiper.destroyed) return; + swiper.transitionEnd(); + }); + }, 0); + }); + } else if (swiper.velocity) { + swiper.emit('_freeModeNoMomentumRelease'); + swiper.updateProgress(newPosition); + swiper.setTransition(momentumDuration); + swiper.setTranslate(newPosition); + swiper.transitionStart(true, swiper.swipeDirection); + if (!swiper.animating) { + swiper.animating = true; + $wrapperEl.transitionEnd(() => { + if (!swiper || swiper.destroyed) return; + swiper.transitionEnd(); + }); + } + } else { + swiper.updateProgress(newPosition); + } + + swiper.updateActiveIndex(); + swiper.updateSlidesClasses(); + } else if (params.freeMode.sticky) { + swiper.slideToClosest(); + return; + } else if (params.freeMode) { + swiper.emit('_freeModeNoMomentumRelease'); + } + + if (!params.freeMode.momentum || timeDiff >= params.longSwipesMs) { + swiper.updateProgress(); + swiper.updateActiveIndex(); + swiper.updateSlidesClasses(); + } + }, +}; + +export default { + name: 'free-mode', + params: { + freeMode: { + enabled: false, + momentum: true, + momentumRatio: 1, + momentumBounce: true, + momentumBounceRatio: 1, + momentumVelocityRatio: 1, + sticky: true, + minimumVelocity: 0.02, + }, + }, + create() { + const swiper = this; + + bindModuleMethods(swiper, { freeMode: FreeMode }); + }, + on: {}, +}; diff --git a/src/components/lazy/lazy.js b/src/components/lazy/lazy.js index ccb41378d..c058b13df 100644 --- a/src/components/lazy/lazy.js +++ b/src/components/lazy/lazy.js @@ -260,7 +260,7 @@ export default { } }, scroll(swiper) { - if (swiper.params.freeMode && !swiper.params.freeModeSticky) { + if (swiper.params.freeMode && !swiper.params.freeMode.sticky) { swiper.lazy.load(); } }, diff --git a/src/components/mousewheel/mousewheel.js b/src/components/mousewheel/mousewheel.js index ac6e2c853..d1591f32c 100644 --- a/src/components/mousewheel/mousewheel.js +++ b/src/components/mousewheel/mousewheel.js @@ -262,7 +262,7 @@ const Mousewheel = { swiper.updateSlidesClasses(); } - if (swiper.params.freeModeSticky) { + if (swiper.params.freeMode.sticky) { // When wheel scrolling starts with sticky (aka snap) enabled, then detect // the end of a momentum scroll by storing recent (N=15?) wheel events. // 1. do all N events have decreasing or same (absolute value) delta? diff --git a/src/react/params-list.js b/src/react/params-list.js index 1b55b6054..789a53da8 100644 --- a/src/react/params-list.js +++ b/src/react/params-list.js @@ -19,13 +19,6 @@ const paramsList = [ '_edgeSwipeDetection', '_edgeSwipeThreshold', '_freeMode', - '_freeModeMomentum', - '_freeModeMomentumRatio', - '_freeModeMomentumBounce', - '_freeModeMomentumBounceRatio', - '_freeModeMomentumVelocityRatio', - '_freeModeSticky', - '_freeModeMinimumVelocity', '_autoHeight', 'setWrapperSize', 'virtualTranslate', diff --git a/src/svelte/params-list.js b/src/svelte/params-list.js index 4fcb0c9ae..f22733d21 100644 --- a/src/svelte/params-list.js +++ b/src/svelte/params-list.js @@ -19,13 +19,6 @@ const paramsList = [ '_edgeSwipeDetection', '_edgeSwipeThreshold', '_freeMode', - '_freeModeMomentum', - '_freeModeMomentumRatio', - '_freeModeMomentumBounce', - '_freeModeMomentumBounceRatio', - '_freeModeMomentumVelocityRatio', - '_freeModeSticky', - '_freeModeMinimumVelocity', '_autoHeight', 'setWrapperSize', 'virtualTranslate', diff --git a/src/swiper.d.ts b/src/swiper.d.ts index 6d03a5ba0..5ca43d0c6 100644 --- a/src/swiper.d.ts +++ b/src/swiper.d.ts @@ -21,6 +21,7 @@ declare const Scrollbar: SwiperComponent; declare const Thumbs: SwiperComponent; declare const Virtual: SwiperComponent; declare const Zoom: SwiperComponent; +declare const FreeMode: SwiperComponent; export default Swiper; export { @@ -45,4 +46,5 @@ export { Thumbs, Virtual, Zoom, + FreeMode, }; diff --git a/src/types/components/free-mode.d.ts b/src/types/components/free-mode.d.ts new file mode 100644 index 000000000..36cd06614 --- /dev/null +++ b/src/types/components/free-mode.d.ts @@ -0,0 +1,76 @@ +import Swiper from '../swiper-class'; + +export interface FreeModeMethods { + /** + * Swiper instance of thumbs swiper + */ + swiper: Swiper; + + /** + * Update thumbs + */ + update(initial: boolean): void; + + /** + * Initialize thumbs + */ + init(): boolean; + + onTouchMove(): void; + onTouchEnd(): void; +} + +export interface FreeModeEvents {} + +export interface FreeModeOptions { + enabled?: boolean; + + /** + * If enabled, then slide will keep moving for a while after you release it + * + * @default true + */ + momentum?: boolean; + + /** + * Higher value produces larger momentum distance after you release slider + * + * @default 1 + */ + momentumRatio?: number; + + /** + * Higher value produces larger momentum velocity after you release slider + * + * @default 1 + */ + momentumVelocityRatio?: number; + + /** + * Set to `false` if you want to disable momentum bounce in free mode + * + * @default true + */ + momentumBounce?: boolean; + + /** + * Higher value produces larger momentum bounce effect + * + * @default 1 + */ + momentumBounceRatio?: number; + + /** + * Minimum touchmove-velocity required to trigger free mode momentum + * + * @default 0.02 + */ + minimumVelocity?: number; + + /** + * Set to enabled to enable snap to slides positions in free mode + * + * @default false + */ + sticky?: boolean; +} diff --git a/src/types/components/public-api.d.ts b/src/types/components/public-api.d.ts index db4517e58..957bd5dd2 100644 --- a/src/types/components/public-api.d.ts +++ b/src/types/components/public-api.d.ts @@ -17,3 +17,4 @@ export * from './scrollbar'; export * from './thumbs'; export * from './virtual'; export * from './zoom'; +export * from './free-mode'; diff --git a/src/types/swiper-class.d.ts b/src/types/swiper-class.d.ts index e16163e5e..51230c204 100644 --- a/src/types/swiper-class.d.ts +++ b/src/types/swiper-class.d.ts @@ -22,6 +22,7 @@ import { ScrollbarMethods } from './components/scrollbar'; import { ThumbsMethods } from './components/thumbs'; import { VirtualMethods } from './components/virtual'; import { ZoomMethods } from './components/zoom'; +import { FreeModeMethods } from './components/free-mode'; interface SwiperClass { /** Add event handler */ @@ -474,6 +475,7 @@ interface Swiper extends SwiperClass { thumbs: ThumbsMethods; virtual: VirtualMethods; zoom: ZoomMethods; + freeMode: FreeModeMethods; } declare class Swiper implements Swiper { diff --git a/src/types/swiper-events.d.ts b/src/types/swiper-events.d.ts index 7e0823e78..cd0e6fc27 100644 --- a/src/types/swiper-events.d.ts +++ b/src/types/swiper-events.d.ts @@ -20,6 +20,7 @@ import { ScrollbarEvents } from './components/scrollbar'; import { ThumbsEvents } from './components/thumbs'; import { VirtualEvents } from './components/virtual'; import { ZoomEvents } from './components/zoom'; +import { FreeModeEvents } from './components/free-mode'; export interface SwiperEvents { // CORE_EVENTS_START @@ -354,3 +355,4 @@ interface SwiperEvents extends ScrollbarEvents {} interface SwiperEvents extends ThumbsEvents {} interface SwiperEvents extends VirtualEvents {} interface SwiperEvents extends ZoomEvents {} +interface SwiperEvents extends FreeModeEvents {} diff --git a/src/types/swiper-options.d.ts b/src/types/swiper-options.d.ts index 804adb6f2..dbc70a8e7 100644 --- a/src/types/swiper-options.d.ts +++ b/src/types/swiper-options.d.ts @@ -17,6 +17,7 @@ import { ScrollbarOptions } from './components/scrollbar'; import { ThumbsOptions } from './components/thumbs'; import { VirtualOptions } from './components/virtual'; import { ZoomOptions } from './components/zoom'; +import { FreeModeOptions } from './components/free-mode'; import { CSSSelector } from './shared'; import { SwiperEvents } from './swiper-events'; @@ -565,56 +566,7 @@ export interface SwiperOptions { * * @default false */ - freeMode?: boolean; - - /** - * If enabled, then slide will keep moving for a while after you release it - * - * @default true - */ - freeModeMomentum?: boolean; - - /** - * Higher value produces larger momentum distance after you release slider - * - * @default 1 - */ - freeModeMomentumRatio?: number; - - /** - * Higher value produces larger momentum velocity after you release slider - * - * @default 1 - */ - freeModeMomentumVelocityRatio?: number; - - /** - * Set to `false` if you want to disable momentum bounce in free mode - * - * @default true - */ - freeModeMomentumBounce?: boolean; - - /** - * Higher value produces larger momentum bounce effect - * - * @default 1 - */ - freeModeMomentumBounceRatio?: number; - - /** - * Minimum touchmove-velocity required to trigger free mode momentum - * - * @default 0.02 - */ - freeModeMinimumVelocity?: number; - - /** - * Set to enabled to enable snap to slides positions in free mode - * - * @default false - */ - freeModeSticky?: boolean; + freeMode?: FreeModeOptions | boolean; // Progress /** diff --git a/src/vue/params-list.js b/src/vue/params-list.js index 1b55b6054..789a53da8 100644 --- a/src/vue/params-list.js +++ b/src/vue/params-list.js @@ -19,13 +19,6 @@ const paramsList = [ '_edgeSwipeDetection', '_edgeSwipeThreshold', '_freeMode', - '_freeModeMomentum', - '_freeModeMomentumRatio', - '_freeModeMomentumBounce', - '_freeModeMomentumBounceRatio', - '_freeModeMomentumVelocityRatio', - '_freeModeSticky', - '_freeModeMinimumVelocity', '_autoHeight', 'setWrapperSize', 'virtualTranslate', diff --git a/src/vue/swiper.js b/src/vue/swiper.js index b0ff66e4c..0a83f9b59 100644 --- a/src/vue/swiper.js +++ b/src/vue/swiper.js @@ -37,14 +37,7 @@ const Swiper = { url: { type: String, default: undefined }, edgeSwipeDetection: { type: [Boolean, String], default: undefined }, edgeSwipeThreshold: { type: Number, default: undefined }, - freeMode: { type: Boolean, default: undefined }, - freeModeMomentum: { type: Boolean, default: undefined }, - freeModeMomentumRatio: { type: Number, default: undefined }, - freeModeMomentumBounce: { type: Boolean, default: undefined }, - freeModeMomentumBounceRatio: { type: Number, default: undefined }, - freeModeMomentumVelocityRatio: { type: Number, default: undefined }, - freeModeSticky: { type: Boolean, default: undefined }, - freeModeMinimumVelocity: { type: Number, default: undefined }, + freeMode: { type: [Boolean, Object], default: undefined }, autoHeight: { type: Boolean, default: undefined }, setWrapperSize: { type: Boolean, default: undefined }, virtualTranslate: { type: Boolean, default: undefined },