diff --git a/src/slider/index.html b/src/slider/index.html
index c53dc8a..421a93e 100644
--- a/src/slider/index.html
+++ b/src/slider/index.html
@@ -33,7 +33,7 @@
-
+
@@ -63,7 +63,7 @@
-
+
@@ -92,7 +92,7 @@
-
+
@@ -162,14 +162,14 @@
-
+
-
+
diff --git a/src/slider/style.scss b/src/slider/style.scss
index f78544f..e27b1ec 100644
--- a/src/slider/style.scss
+++ b/src/slider/style.scss
@@ -13,6 +13,10 @@ tp-slider-slides {
position: relative;
display: flex;
align-items: flex-start;
+ overflow-y: visible;
+ overflow-x: auto;
+ scroll-snap-type: x mandatory;
+ scrollbar-width: none;
tp-slider:not([resizing="yes"]) & {
transition-duration: 0.6s;
diff --git a/src/slider/tp-slider.ts b/src/slider/tp-slider.ts
index a5fa1ac..d7d6825 100644
--- a/src/slider/tp-slider.ts
+++ b/src/slider/tp-slider.ts
@@ -15,9 +15,8 @@ export class TPSliderElement extends HTMLElement {
/**
* Properties.
*/
- protected touchStartX: number = 0;
- protected touchStartY: number = 0;
- protected swipeThreshold: number = 200;
+ protected slidesScrollContainer: TPSliderSlidesElement | null;
+ protected slidesScrollContainerRect: DOMRect | {};
protected responsiveSettings: { [ key: string ]: any };
protected allowedResponsiveKeys: string[] = [
'flexible-height',
@@ -29,6 +28,7 @@ export class TPSliderElement extends HTMLElement {
'step',
'responsive',
];
+ protected isProgramaticScroll: boolean = false;
/**
* Constructor.
@@ -36,15 +36,17 @@ export class TPSliderElement extends HTMLElement {
constructor() {
// Initialize parent.
super();
+ this.slidesScrollContainer = this.querySelector( 'tp-slider-slides' );
+ this.slidesScrollContainerRect = this.slidesScrollContainer?.getBoundingClientRect() ?? {};
+
+ // Add event listener to handle current slide attribute on scroll.
+ this.slidesScrollContainer?.addEventListener( 'scroll', this.handleCurrentSlideOnScroll.bind( this ) );
// Set current slide.
if ( ! this.getAttribute( 'current-slide' ) ) {
this.setAttribute( 'current-slide', '1' );
}
- // Threshold Setting.
- this.swipeThreshold = Number( this?.getAttribute( 'swipe-threshold' ) ?? '200' );
-
// Initialize slider.
this.slide();
this.autoSlide();
@@ -65,10 +67,18 @@ export class TPSliderElement extends HTMLElement {
window.addEventListener( 'resize', this.handleResize.bind( this ) );
document.fonts.ready.then( () => this.handleResize() );
}
+ }
- // Touch listeners.
- this.addEventListener( 'touchstart', this.handleTouchStart.bind( this ), { passive: true } );
- this.addEventListener( 'touchend', this.handleTouchEnd.bind( this ) );
+ /**
+ * Flag programmatic scroll to prevent scroll handling.
+ */
+ protected flagProgramaticScroll(): void {
+ // Flag programmatic scroll.
+ this.isProgramaticScroll = true;
+ setTimeout( () => {
+ // Unflag programmatic scroll.
+ this.isProgramaticScroll = false;
+ }, 500 );
}
/**
@@ -92,7 +102,7 @@ export class TPSliderElement extends HTMLElement {
*/
static get observedAttributes(): string[] {
// Observed attributes.
- return [ 'current-slide', 'flexible-height', 'infinite', 'swipe', 'per-view', 'step' ];
+ return [ 'current-slide', 'flexible-height', 'infinite', 'per-view', 'step' ];
}
/**
@@ -331,6 +341,9 @@ export class TPSliderElement extends HTMLElement {
* @protected
*/
protected slide(): void {
+ // Flag programmatic scroll.
+ this.flagProgramaticScroll();
+
// Check if slider is disabled.
if ( 'yes' === this.getAttribute( 'disabled' ) ) {
// Yes, it is. So stop.
@@ -358,7 +371,10 @@ export class TPSliderElement extends HTMLElement {
// Check if behaviour is set to fade and slide on the current slide index is present in the slides array.
if ( 'fade' !== behaviour && slides[ this.currentSlideIndex - 1 ] ) {
// Yes, it is. So slide to the current slide.
- slidesContainer.style.left = `-${ slides[ this.currentSlideIndex - 1 ].offsetLeft }px`;
+ slidesContainer.scroll( {
+ left: slides[ this.currentSlideIndex - 1 ].offsetLeft - slides[ 0 ].offsetLeft,
+ behavior: 'smooth',
+ } );
}
}
@@ -487,6 +503,59 @@ export class TPSliderElement extends HTMLElement {
}
}
+ /**
+ * Handle current slide attribute on scroll.
+ *
+ * This is to handle the case when the user scrolls the slides track
+ * and we need to update the current slide index based on the scroll position.
+ */
+ handleCurrentSlideOnScroll() {
+ // Check if this is a programmatic scroll.
+ if ( this.isProgramaticScroll ) {
+ // Early return to prevent handling programmatic scroll.
+ return;
+ }
+
+ // Check if we have scroll container.
+ if ( ! this.slidesScrollContainer ) {
+ // No scroll container, early return.
+ return;
+ }
+
+ // Get all the slides.
+ const slides : NodeListOf | null = this.querySelectorAll( 'tp-slider-slide' );
+
+ // If no slides.
+ if ( 0 === slides.length ) {
+ // Early return.
+ return;
+ }
+
+ // Check if scroll position is at right end.
+ const isAtRightEnd = Math.abs( this.slidesScrollContainer.scrollLeft + this.slidesScrollContainer.clientWidth - this.slidesScrollContainer.scrollWidth ) < 1;
+
+ // Conditionally set the current slide index based on the scroll position.
+ if ( isAtRightEnd ) {
+ // If the current slide index is equal to the total number of slides, set it to the last slide.
+ this.setCurrentSlide( slides.length );
+ } else {
+ // Loop through all slides and check which slide is intersecting with the left edge of the scroll container.
+ slides.forEach( ( slide: TPSliderSlideElement, index: number ) => {
+ // Get the bounding rectangle of the slide.
+ const slideRect = slide.getBoundingClientRect();
+
+ // Check if the slide is aligned with the left edge of the scroll container.
+ const isAlignedWithLeftEdge = Math.abs( slideRect?.left - ( this.slidesScrollContainerRect as DOMRect ).left ) < 1;
+
+ // Check if the slide is intersecting with the left edge of the scroll container.
+ if ( isAlignedWithLeftEdge ) {
+ // Yes, it is. So set the current slide index.
+ this.setCurrentSlide( index + 1 );
+ }
+ } );
+ }
+ }
+
/**
* Update the height of the slider based on current slide.
*/
@@ -624,64 +693,6 @@ export class TPSliderElement extends HTMLElement {
} );
}
- /**
- * Detect touch start event, and store the starting location.
- *
- * @param {Event} e Touch event.
- *
- * @protected
- */
- protected handleTouchStart( e: TouchEvent ): void {
- // initialize touch start coordinates
- if ( 'yes' === this.getAttribute( 'swipe' ) ) {
- this.touchStartX = e.touches[ 0 ].clientX;
- this.touchStartY = e.touches[ 0 ].clientY;
- }
- }
-
- /**
- * Detect touch end event, and check if it was a left or right swipe.
- *
- * @param {Event} e Touch event.
- *
- * @protected
- */
- protected handleTouchEnd( e: TouchEvent ): void {
- // Early return if swipe is not enabled.
- if ( 'yes' !== this.getAttribute( 'swipe' ) ) {
- // Early return.
- return;
- }
-
- // Calculate the horizontal and vertical distance moved.
- const touchEndX: number = e.changedTouches[ 0 ].clientX;
- const touchEndY: number = e.changedTouches[ 0 ].clientY;
- const swipeDistanceX: number = touchEndX - this.touchStartX;
- const swipeDistanceY: number = touchEndY - this.touchStartY;
-
- // Determine if the swipe is predominantly horizontal or vertical.
- const isHorizontalSwipe: boolean = Math.abs( swipeDistanceX ) > Math.abs( swipeDistanceY );
-
- // If it's not horizontal swipe, return
- if ( ! isHorizontalSwipe ) {
- // Early return.
- return;
- }
-
- // Check if it's a right or left swipe.
- if ( swipeDistanceX > 0 ) {
- // Right-Swipe: Check if horizontal swipe distance is less than the threshold.
- if ( swipeDistanceX < this.swipeThreshold ) {
- this.previous();
- }
- } else if ( swipeDistanceX < 0 ) {
- // Left-Swipe: Check if horizontal swipe distance is less than the threshold.
- if ( swipeDistanceX > -this.swipeThreshold ) {
- this.next();
- }
- }
- }
-
/**
* Auto slide.
*/