Skip to content

Commit f062540

Browse files
committed
fix(carousel): missing swipe interactions on touchscreen devices
1 parent 701ecd2 commit f062540

File tree

1 file changed

+33
-1
lines changed

1 file changed

+33
-1
lines changed

projects/coreui-angular/src/lib/carousel/carousel/carousel.component.ts

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
OnInit,
1111
Output
1212
} from '@angular/core';
13-
import { Subscription } from 'rxjs';
13+
import { fromEvent, Subscription, withLatestFrom, zipWith } from 'rxjs';
1414

1515
import { IntersectionService } from '../../services/intersection.service';
1616
import { IListenersConfig, ListenersService } from '../../services/listeners.service';
@@ -58,6 +58,12 @@ export class CarouselComponent implements OnInit, OnDestroy, AfterContentInit {
5858
* @type {'hover' | 'focus' | 'click'}
5959
*/
6060
@Input() pause: Triggers | Triggers[] | false = 'hover';
61+
/**
62+
* Support left/right swipe interactions on touchscreen devices.
63+
* @type boolean
64+
* @default true
65+
*/
66+
@Input() touch: boolean = true;
6167
/**
6268
* Set type of the transition.
6369
* @type {'slide' | 'crossfade'}
@@ -90,6 +96,7 @@ export class CarouselComponent implements OnInit, OnDestroy, AfterContentInit {
9096
private timerId!: any;
9197
private intersectingSubscription?: Subscription;
9298
private activeItemInterval = 0;
99+
private swipeSubscription?: Subscription;
93100

94101
constructor(
95102
@Inject(CarouselConfig) private config: CarouselConfig,
@@ -110,13 +117,15 @@ export class CarouselComponent implements OnInit, OnDestroy, AfterContentInit {
110117
this.clearListeners();
111118
this.carouselStateSubscribe(false);
112119
this.intersectionServiceSubscribe(false);
120+
this.swipeSubscribe(false);
113121
}
114122

115123
ngAfterContentInit(): void {
116124
this.intersectionService.createIntersectionObserver(this.hostElement);
117125
this.intersectionServiceSubscribe();
118126
this.carouselState.state = { activeItemIndex: this.activeIndex, animate: this.animate };
119127
this.setListeners();
128+
this.swipeSubscribe();
120129
}
121130

122131
private setListeners(): void {
@@ -140,9 +149,11 @@ export class CarouselComponent implements OnInit, OnDestroy, AfterContentInit {
140149
set visible(value) {
141150
this._visible = value;
142151
}
152+
143153
get visible() {
144154
return this._visible;
145155
}
156+
146157
private _visible: boolean = true;
147158

148159
setTimer(): void {
@@ -185,4 +196,25 @@ export class CarouselComponent implements OnInit, OnDestroy, AfterContentInit {
185196
this.intersectingSubscription?.unsubscribe();
186197
}
187198
}
199+
200+
private swipeSubscribe(subscribe: boolean = true): void {
201+
if (this.touch && subscribe) {
202+
const carouselElement = this.hostElement.nativeElement;
203+
const touchStart$ = fromEvent<TouchEvent>(carouselElement, 'touchstart');
204+
const touchEnd$ = fromEvent<TouchEvent>(carouselElement, 'touchend');
205+
const touchMove$ = fromEvent<TouchEvent>(carouselElement, 'touchmove');
206+
this.swipeSubscription = touchStart$.pipe(zipWith(touchEnd$.pipe(withLatestFrom(touchMove$))))
207+
.subscribe(([touchstart, [touchend, touchmove]]) => {
208+
touchstart.stopPropagation();
209+
touchmove.stopPropagation();
210+
const distanceX = touchstart.touches[0].clientX - touchmove.touches[0].clientX;
211+
if (Math.abs(distanceX) > 0.3 * carouselElement.clientWidth && touchstart.timeStamp <= touchmove.timeStamp) {
212+
const nextIndex = this.carouselState.direction(distanceX > 0 ? 'next' : 'prev');
213+
this.carouselState.state = { activeItemIndex: nextIndex };
214+
}
215+
});
216+
} else {
217+
this.swipeSubscription?.unsubscribe();
218+
}
219+
}
188220
}

0 commit comments

Comments
 (0)