ngx-hm-carousel
Version:
A light carousel for Angular, support mobile touch by hammerJs with SSR
769 lines • 113 kB
JavaScript
import { AsyncPipe, DOCUMENT, isPlatformBrowser, NgTemplateOutlet, } from '@angular/common';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, computed, contentChild, contentChildren, DestroyRef, effect, ElementRef, forwardRef, inject, input, NgZone, PLATFORM_ID, Renderer2, signal, TemplateRef, viewChild, ViewContainerRef, } from '@angular/core';
import { takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { BehaviorSubject, bufferCount, filter, forkJoin, fromEvent, interval, merge, of, Subject, switchMap, takeUntil, tap, timer, } from 'rxjs';
import { resizeObservable } from '@nghedgehog/core';
import { NgxHmCarouselItemDirective } from './ngx-hm-carousel-item.directive';
import * as i0 from "@angular/core";
export class NgxHmCarouselComponent {
platformId = inject(PLATFORM_ID);
_document = inject(DOCUMENT);
_destroyRef = inject(DestroyRef);
_renderer = inject(Renderer2);
_zone = inject(NgZone);
_cd = inject(ChangeDetectorRef);
container = viewChild.required('containerElm', { read: ElementRef });
btnPrev = viewChild('prev');
btnNext = viewChild('next');
progressContainerElm = viewChild('progress', { read: ElementRef });
// get all item elms
itemElms = contentChildren(NgxHmCarouselItemDirective, {
read: ElementRef,
descendants: true,
});
contentPrev = contentChild('carouselPrev', { read: TemplateRef });
contentNext = contentChild('carouselNext', { read: TemplateRef });
dotElm = contentChild('carouselDot');
progressElm = contentChild('carouselProgress');
infiniteContainer = contentChild('infiniteContainer', {
read: ViewContainerRef,
});
contentContent = contentChild.required('carouselContent', {
read: TemplateRef,
});
/** the data you using with *ngFor, it need when infinite mode or autoplay mode */
data = input([]);
/** when infinite is true, the animation time with item, default is 400. */
aniTime = input(400);
/** this class will add in #containerElm when model change */
aniClass = input('transition');
/**
* this class will add when carousel auto play,
* this default autoplay animation is same as aniClass
*/
aniClassAuto = input(this.aniClass());
/**
* user move picture with the container width rate,
* when more than that rate, it will go to next or prev,
* set false will never move with distance rate,
* default is `0.15`
*/
panBoundary = input(0.15, { alias: 'pan-boundary' });
/** when `show-num` is bigger than 1, the first item align, default is `center` */
align = input('center');
/**
* disable when drag occur the child element will follow touch point.
* default is `false`
*/
notDrag = input(false, { alias: 'not-follow-pan' });
/**
* the event binding state for stop auto play when mouse move over
*/
mouseEnable = input(false, { alias: 'mouse-enable' });
/** each auto play between time */
delay = input(8000, { alias: 'between-delay' });
/** auto play direction, default is `right`. */
direction = input('right', { alias: 'autoplay-direction' });
/** how many number with each scroll, default is `1`. */
scrollNum = input(1, { alias: 'scroll-num' });
/** Could user scroll many item once, simulate with scrollbar, default is `false` */
isDragMany = input(false, { alias: 'drag-many' });
/** Minimal velocity required before recognizing, unit is in px per ms, default `0.3` */
swipeVelocity = input(0.3, { alias: 'swipe-velocity' });
/**
* switch show number with custom logic like css
* @media (min-width: `number`px)
*/
breakpoint = input([]);
/** disable drag event with touch and mouse pan moving, default is `false` */
disableDrag = input(undefined, {
alias: 'disable-drag',
transform: (value) => {
if (this.rootElm) {
if (value) {
this.destroyHammer();
}
else {
this.hammer = this.bindHammer();
}
}
return value;
},
});
/** is the carousel can move infinite */
infinite = input(false, {
alias: 'infinite',
});
/** auto play speed */
speed = input(undefined, {
alias: 'autoplay-speed',
transform: (value) => {
this.speedChange.next(value);
return value;
},
});
/** PinchRecognizer that you want to add to hammer event */
recognizers = input([]);
/** PinchRecognizer that you want to add to hammer event */
stopPanListener = input(false);
_showNum = 1;
/**
* how many number items to show once, default is `1`
* set `auto` to using `[breakpoint]` set value.
*/
showNum = input(this._showNum, {
alias: 'show-num',
transform: (value) => {
if (value === 'auto') {
this.isAutoNum = true;
}
else {
this._showNum = +value;
if (this.rootElm) {
this.setViewWidth();
this.reSetAlignDistance();
}
}
return this._showNum;
},
});
/** is that carousel auto play */
autoplay = input(undefined, {
alias: 'autoplay',
transform: (value) => {
if (isPlatformBrowser(this.platformId)) {
if (this.elms) {
this.progressWidth = 0;
if (value) {
this.doNextSub$ = this.doNext$?.subscribe();
}
else {
if (this.doNextSub$) {
this.doNextSub$.unsubscribe();
}
}
}
}
return value;
},
});
get currentIndex() {
return this._currentIndex;
}
set currentIndex(value) {
// if now index is not equal to save index, do something
if (this.currentIndex !== value) {
// if the value is not contain with the boundary not handler
if (!this.runLoop() &&
!(0 <= value && value <= this.itemElms().length - 1)) {
return;
}
this._currentIndex = value;
if (this.elms) {
if (this.autoplay() && !this.isFromAuto) {
this._zone.runOutsideAngular(() => {
this.stopEvent.next(undefined);
this.callRestart();
});
}
this.drawView(this.currentIndex, this.hasInitWriteValue);
if (this.isDragMany()) {
this.hasInitWriteValue = true;
}
}
if (0 <= this.currentIndex &&
this.currentIndex <= this.itemElms().length - 1) {
this._zone.run(() => {
this.onChange(this.currentIndex);
this._cd.detectChanges();
});
}
}
this.isFromAuto = false;
}
get progressWidth() {
return this._progressWidth;
}
set progressWidth(value) {
const containerElm = this.progressContainerElm();
if (this.progressElm() && containerElm && this.autoplay()) {
this._progressWidth = value;
this._renderer.setStyle(containerElm.nativeElement.children[0], 'width', `${this.progressWidth}%`);
}
}
get grabbing() {
return this._grabbing;
}
set grabbing(value) {
if (this._grabbing !== value) {
// console.log(value);
this._zone.run(() => {
this._grabbing = value;
if (value) {
this._renderer.addClass(this.containerElm, 'grabbing');
}
else {
this.panCount = 0;
this.callRestart();
this._renderer.removeClass(this.containerElm, 'grabbing');
}
this._cd.detectChanges();
});
}
}
// using for check mouse or touchend
leaveObs$ = merge(fromEvent(this._document, 'mouseup'), fromEvent(this._document, 'touchend')).pipe(tap((e) => {
this.grabbing = false;
e.stopPropagation();
e.preventDefault();
}));
hammer;
set left(value) {
if (isPlatformBrowser(this.platformId)) {
this._renderer.setStyle(this.containerElm, 'transform', `translateX(${value}px)`);
}
else {
this._renderer.setStyle(this.containerElm, 'transform', `translateX(${value}%)`);
}
}
get maxRightIndex() {
let addIndex = 0;
switch (this.align()) {
case 'left':
addIndex = 0;
break;
case 'center':
addIndex = this.showNum() - 1;
break;
case 'right':
addIndex = this.showNum() - 1;
break;
}
return this.itemElms().length - 1 - this._showNum + 1 + addIndex;
}
runLoop = computed(() => this.autoplay() || this.infinite());
get lengthOne() {
return this.itemElms().length === 1;
}
get rootElmWidth() {
return isPlatformBrowser(this.platformId)
? this.rootElm.getBoundingClientRect().width
: 100;
}
set containerElmWidth(value) {
this.setStyle(this.containerElm, 'width', value);
}
isFromAuto = true;
isAutoNum = false;
mouseOnContainer = false;
alignDistance = 0;
elmWidth = 0;
rootElm;
containerElm;
elms;
infiniteElmRefs = signal([]);
saveTimeOut$;
doNextSub$;
doNext$;
restart = new BehaviorSubject(null);
speedChange = new BehaviorSubject(5000);
stopEvent = new Subject();
_progressWidth = 0;
_currentIndex = 0;
_grabbing = false;
panCount = 0;
// this variable use for check the init value is write with ngModel,
// when init first, not set with animation
hasInitWriteValue = false;
itemElmsChanges = toObservable(this.itemElms);
constructor() {
effect(() => {
this.infiniteElmRefs().forEach((ref) => {
this.addStyle(ref.rootNodes[0], {
visibility: this.runLoop() ? 'visible' : 'hidden',
});
});
});
const effectRef = effect(() => {
this.rootElm = this.container().nativeElement;
this.containerElm = this.rootElm.children[0];
this.init();
forkJoin([
this.bindClick(),
// when item changed, remove old hammer binding, and reset width
this.itemElmsChanges.pipe(
// detectChanges to change view dots
tap(() => {
if (this.currentIndex > this.itemElms().length - 1) {
// pass the change detection check,
requestAnimationFrame(() => {
this.currentIndex = this.itemElms().length - 1;
});
}
this.destroy();
this.removeInfiniteElm();
this.init();
this.progressWidth = 0;
}), tap(() => this._cd.detectChanges())),
resizeObservable(this.rootElm, () => this.containerResize()),
])
.pipe(takeUntilDestroyed(this._destroyRef))
.subscribe();
// only exec once
effectRef.destroy();
}, {
allowSignalWrites: true,
});
}
ngOnDestroy() {
this.destroy();
}
writeValue(value) {
if (value || value === 0) {
this.currentIndex = value;
this.hasInitWriteValue = true;
}
}
registerOnChange(fn) {
this.onChange = fn;
}
registerOnTouched(fn) {
this.onTouched = fn;
}
onChange = (_) => {
//
};
onTouched = () => {
//
};
init() {
this.initVariable();
this.setViewWidth(true);
this.reSetAlignDistance();
if (!this.disableDrag()) {
this.hammer = this.bindHammer();
}
this.drawView(this.currentIndex, false);
if (isPlatformBrowser(this.platformId) && this.runLoop()) {
this.addInfiniteElm();
}
}
destroy() {
this.destroyHammer();
if (this.autoplay()) {
this.doNextSub$?.unsubscribe();
}
}
destroyHammer() {
if (this.hammer) {
this.hammer.destroy();
}
}
addInfiniteElm() {
const infiniteContainer = this.infiniteContainer();
const showNum = this.showNum();
if (!infiniteContainer || typeof showNum !== 'number')
return;
for (let i = 1; i <= showNum; i++) {
const elm = infiniteContainer.createEmbeddedView(this.contentContent(), {
$implicit: this.data()[this.itemElms().length - i],
index: this.itemElms().length - i,
});
this.addStyle(elm.rootNodes[0], {
position: 'absolute',
// boxShadow: `0 0 0 5000px rgba(200, 75, 75, 0.5) inset`,
transform: `translateX(-${100 * i}%)`,
visibility: this.runLoop() ? 'visible' : 'hidden',
});
this.setStyle(elm.rootNodes[0], 'width', this.elmWidth);
const elm2 = infiniteContainer.createEmbeddedView(this.contentContent(), {
$implicit: this.data()[i - 1],
index: i - 1,
});
this.addStyle(elm2.rootNodes[0], {
// boxShadow: `0 0 0 5000px rgba(200, 75, 75, 0.5) inset`,
position: 'absolute',
right: 0,
top: 0,
transform: `translateX(${100 * i}%)`,
visibility: this.runLoop() ? 'visible' : 'hidden',
});
this.setStyle(elm2.rootNodes[0], 'width', this.elmWidth);
elm.detectChanges();
elm2.detectChanges();
this.infiniteElmRefs.set([...this.infiniteElmRefs(), elm, elm2]);
}
}
removeInfiniteElm() {
this.infiniteElmRefs().forEach((a) => {
a.detach();
a.destroy();
});
if (this.infiniteContainer()) {
this.infiniteContainer().clear();
}
this.infiniteElmRefs.set([]);
}
containerResize() {
this.setViewWidth();
this.reSetAlignDistance();
const showNum = this.showNum();
const touchEnd = typeof showNum === 'number' && showNum >= this.elms.length;
if (this.align() !== 'center' && touchEnd) {
this.currentIndex = 0;
}
this.drawView(this.currentIndex, false);
}
initVariable() {
this._zone.runOutsideAngular(() => {
this.elms = this.itemElms().map((x) => x.nativeElement);
let startEvent = this.restart.asObservable();
let stopEvent = this.stopEvent.asObservable();
if (this.mouseEnable()) {
startEvent = merge(startEvent, fromEvent(this.containerElm, 'mouseleave').pipe(
// when leave, we should reverse grabbing state to set the mouseOn state,
// because when the grabbing, the mask will on, and it will occur leave again
filter(() => !this.grabbing), tap(() => (this.mouseOnContainer = false))));
stopEvent = merge(stopEvent, fromEvent(this.containerElm, 'mouseover').pipe(tap(() => (this.mouseOnContainer = true))));
}
this.doNext$ = startEvent.pipe(
// not using debounceTime, it will stop mouseover event detect, will cause mouse-enable error
// debounceTime(this.delay),
switchMap(() => this.speedChange), switchMap(() => timer(this.delay()).pipe(switchMap(() => this.runProgress(20)), tap(() => {
this.isFromAuto = true;
// console.log('next');
if (this.direction() === 'left') {
this.currentIndex -= this.scrollNum();
}
else {
this.currentIndex += this.scrollNum();
}
}), takeUntil(stopEvent.pipe(tap(() => (this.progressWidth = 0)))))));
if (this.autoplay()) {
this.doNextSub$ = this.doNext$.subscribe();
}
});
}
reSetAlignDistance() {
switch (this.align()) {
case 'center':
this.alignDistance = (this.rootElmWidth - this.elmWidth) / 2;
break;
case 'left':
this.alignDistance = 0;
break;
case 'right':
this.alignDistance = this.rootElmWidth - this.elmWidth;
break;
}
}
setViewWidth(isInit) {
if (this.isAutoNum) {
this._showNum = this.getAutoNum();
}
this._renderer.addClass(this.containerElm, 'grab');
if (isInit) {
// remain one elm height
this._renderer.addClass(this.containerElm, 'ngx-hm-carousel-display-nowrap');
}
this.elmWidth = this.rootElmWidth / this._showNum;
this._renderer.removeClass(this.containerElm, 'ngx-hm-carousel-display-nowrap');
this.containerElmWidth = this.elmWidth * this.elms.length;
this._renderer.setStyle(this.containerElm, 'position', 'relative');
this.infiniteElmRefs().forEach((ref) => {
this.setStyle(ref.rootNodes[0], 'width', this.elmWidth);
});
this.elms.forEach((elm) => {
this.setStyle(elm, 'width', this.elmWidth);
});
}
bindHammer() {
if (!isPlatformBrowser(this.platformId)) {
return null;
}
return this._zone.runOutsideAngular(() => {
const hm = new Hammer.Manager(this.containerElm);
const pan = new Hammer.Pan({
direction: Hammer.DIRECTION_HORIZONTAL,
threshold: 0,
});
hm.add(pan);
hm.on('panleft panright panend pancancel', (e) => {
// console.log(e.type);
if (this.stopPanListener()) {
return;
}
if (this.lengthOne) {
return;
}
this.removeContainerTransition();
if (this.autoplay()) {
this._zone.runOutsideAngular(() => {
this.stopEvent.next(undefined);
});
}
switch (e.type) {
case 'panleft':
case 'panright':
{
this.panCount++;
// only when panmove more than two times, set move
if (this.panCount < 2) {
return;
}
this.grabbing = true;
const showNum = this.showNum();
// When show-num is bigger than length, stop hammer
if (this.align() !== 'center' &&
typeof showNum === 'number' &&
showNum >= this.elms.length) {
this.hammer?.stop(true);
return;
}
// Slow down at the first and last pane.
if (!this.runLoop() && this.outOfBound(e.type)) {
e.deltaX *= 0.2;
}
if (!this.notDrag()) {
this.left =
-this.currentIndex * this.elmWidth +
this.alignDistance +
e.deltaX;
}
// if not drag many, when bigger than half
if (!this.isDragMany()) {
if (Math.abs(e.deltaX) > this.elmWidth * 0.5) {
if (e.deltaX > 0) {
this.currentIndex -= this.scrollNum();
}
else {
this.currentIndex += this.scrollNum();
}
this.hammer?.stop(true);
return;
}
}
}
break;
case 'pancancel':
this.drawView(this.currentIndex);
break;
case 'panend':
{
const panBoundary = this.panBoundary();
// if boundary more than rate
if (panBoundary !== false &&
Math.abs(e.deltaX) > this.elmWidth * panBoundary) {
const moveNum = this.isDragMany()
? Math.ceil(Math.abs(e.deltaX) / this.elmWidth)
: this.scrollNum();
const prevIndex = this.currentIndex - moveNum;
const nextIndex = this.currentIndex + moveNum;
// if right
if (e.deltaX > 0) {
this.goPrev(prevIndex);
// left
}
else {
this.goNext(nextIndex);
}
break;
}
else if (e.velocityX < -this.swipeVelocity() &&
e.distance > 10) {
this.goNext(this.currentIndex + this.scrollNum());
}
else if (e.velocityX > this.swipeVelocity() &&
e.distance > 10) {
this.goPrev(this.currentIndex - this.scrollNum());
}
else {
this.drawView(this.currentIndex);
}
}
break;
}
});
this.recognizers().forEach((recognizer) => {
hm.add(recognizer);
});
return hm;
});
}
goPrev(prevIndex) {
if (!this.runLoop() && prevIndex < 0) {
prevIndex = 0;
this.drawView(0);
}
this.currentIndex = prevIndex;
}
goNext(nextIndex) {
if (!this.runLoop() && nextIndex > this.maxRightIndex) {
nextIndex = this.maxRightIndex;
this.drawView(nextIndex);
}
this.currentIndex = nextIndex;
}
bindClick() {
const nextBtn = this.btnNext();
const prevBtn = this.btnPrev();
if (nextBtn && prevBtn) {
return forkJoin([
fromEvent(nextBtn.nativeElement, 'click').pipe(tap(() => this.currentIndex++)),
fromEvent(prevBtn.nativeElement, 'click').pipe(tap(() => this.currentIndex--)),
]);
}
return of(null);
}
callRestart() {
// if that is autoplay
// if that mouse is not on container( only mouse-enable is true, the state maybe true)
// if now is grabbing, skip this restart, using grabbing change restart
if (this.autoplay() && !this.mouseOnContainer && !this.grabbing) {
this._zone.runOutsideAngular(() => {
this.restart.next(null);
});
}
}
drawView(index, isAnimation = true, isFromAuto = this.isFromAuto) {
// move element only on length is more than 1
if (this.elms.length > 1) {
this.removeContainerTransition();
this.left = -(index * this.elmWidth - this.alignDistance);
if (isAnimation) {
if (isFromAuto) {
this._renderer.addClass(this.containerElm, this.aniClassAuto());
}
else {
this._renderer.addClass(this.containerElm, this.aniClass());
}
// if infinite move to next index with timeout
this.infiniteHandler(index);
}
}
else {
this.left = this.alignDistance;
}
}
removeContainerTransition() {
this._renderer.removeClass(this.containerElm, this.aniClass());
this._renderer.removeClass(this.containerElm, this.aniClassAuto());
}
infiniteHandler(index) {
if (this.runLoop()) {
let state = 0;
state = index < 0 ? -1 : state;
state = index > this.itemElms().length - 1 ? 1 : state;
// index = index % this._showNum;
if (state !== 0) {
switch (state) {
case -1:
this._currentIndex =
(this.itemElms().length + index) % this.itemElms().length;
break;
case 1:
this._currentIndex = index % this.itemElms().length;
break;
}
const isFromAuto = this.isFromAuto;
if (this.saveTimeOut$) {
this.saveTimeOut$.unsubscribe();
}
this.saveTimeOut$ = timer(this.aniTime())
.pipe(switchMap(() => {
// if it is any loop carousel, the next event need wait the timeout complete
if (this.aniTime() === this.speed()) {
this.removeContainerTransition();
this.left =
-((this._currentIndex - state) * this.elmWidth) +
this.alignDistance;
return timer(50).pipe(tap(() => {
this.drawView(this.currentIndex, this.hasInitWriteValue, isFromAuto);
}));
}
else {
this.drawView(this.currentIndex, false);
}
return of(null);
}), takeUntil(this.stopEvent))
.subscribe();
}
}
}
outOfBound(type) {
switch (type) {
case 'panleft':
return this.currentIndex >= this.maxRightIndex;
case 'panright':
return this.currentIndex <= 0;
}
}
runProgress(betweenTime) {
return this._zone.runOutsideAngular(() => {
const speed = this.speed();
const howTimes = speed / betweenTime;
const everyIncrease = (100 / speed) * betweenTime;
return interval(betweenTime).pipe(tap((t) => {
this.progressWidth = (t % howTimes) * everyIncrease;
}), bufferCount(howTimes));
});
}
getAutoNum() {
const currWidth = this.rootElmWidth;
// check user has had set breakpoint
if (this.breakpoint().length > 0) {
// get the last biggest point
const now = this.breakpoint().find((b) => {
return b.width >= currWidth;
});
// if find value, it is current width
if (now) {
return now.number;
}
return this.breakpoint()[this.breakpoint().length - 1].number;
}
// system init show number
const initNum = 3;
// 610
if (currWidth > 300) {
return Math.floor(initNum + currWidth / 200);
}
return initNum;
}
addStyle(elm, style) {
if (style) {
Object.keys(style).forEach((key) => {
const value = style[key];
this._renderer.setStyle(elm, key, value);
});
}
}
setStyle(elm, style, value) {
if (isPlatformBrowser(this.platformId)) {
this._renderer.setStyle(elm, style, `${value}px`);
}
else {
this._renderer.setStyle(elm, style, `${value}%`);
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: NgxHmCarouselComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.3", type: NgxHmCarouselComponent, isStandalone: true, selector: "ngx-hm-carousel", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, aniTime: { classPropertyName: "aniTime", publicName: "aniTime", isSignal: true, isRequired: false, transformFunction: null }, aniClass: { classPropertyName: "aniClass", publicName: "aniClass", isSignal: true, isRequired: false, transformFunction: null }, aniClassAuto: { classPropertyName: "aniClassAuto", publicName: "aniClassAuto", isSignal: true, isRequired: false, transformFunction: null }, panBoundary: { classPropertyName: "panBoundary", publicName: "pan-boundary", isSignal: true, isRequired: false, transformFunction: null }, align: { classPropertyName: "align", publicName: "align", isSignal: true, isRequired: false, transformFunction: null }, notDrag: { classPropertyName: "notDrag", publicName: "not-follow-pan", isSignal: true, isRequired: false, transformFunction: null }, mouseEnable: { classPropertyName: "mouseEnable", publicName: "mouse-enable", isSignal: true, isRequired: false, transformFunction: null }, delay: { classPropertyName: "delay", publicName: "between-delay", isSignal: true, isRequired: false, transformFunction: null }, direction: { classPropertyName: "direction", publicName: "autoplay-direction", isSignal: true, isRequired: false, transformFunction: null }, scrollNum: { classPropertyName: "scrollNum", publicName: "scroll-num", isSignal: true, isRequired: false, transformFunction: null }, isDragMany: { classPropertyName: "isDragMany", publicName: "drag-many", isSignal: true, isRequired: false, transformFunction: null }, swipeVelocity: { classPropertyName: "swipeVelocity", publicName: "swipe-velocity", isSignal: true, isRequired: false, transformFunction: null }, breakpoint: { classPropertyName: "breakpoint", publicName: "breakpoint", isSignal: true, isRequired: false, transformFunction: null }, disableDrag: { classPropertyName: "disableDrag", publicName: "disable-drag", isSignal: true, isRequired: false, transformFunction: null }, infinite: { classPropertyName: "infinite", publicName: "infinite", isSignal: true, isRequired: false, transformFunction: null }, speed: { classPropertyName: "speed", publicName: "autoplay-speed", isSignal: true, isRequired: false, transformFunction: null }, recognizers: { classPropertyName: "recognizers", publicName: "recognizers", isSignal: true, isRequired: false, transformFunction: null }, stopPanListener: { classPropertyName: "stopPanListener", publicName: "stopPanListener", isSignal: true, isRequired: false, transformFunction: null }, showNum: { classPropertyName: "showNum", publicName: "show-num", isSignal: true, isRequired: false, transformFunction: null }, autoplay: { classPropertyName: "autoplay", publicName: "autoplay", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => NgxHmCarouselComponent),
multi: true,
},
], queries: [{ propertyName: "itemElms", predicate: NgxHmCarouselItemDirective, descendants: true, read: ElementRef, isSignal: true }, { propertyName: "contentPrev", first: true, predicate: ["carouselPrev"], descendants: true, read: TemplateRef, isSignal: true }, { propertyName: "contentNext", first: true, predicate: ["carouselNext"], descendants: true, read: TemplateRef, isSignal: true }, { propertyName: "dotElm", first: true, predicate: ["carouselDot"], descendants: true, isSignal: true }, { propertyName: "progressElm", first: true, predicate: ["carouselProgress"], descendants: true, isSignal: true }, { propertyName: "infiniteContainer", first: true, predicate: ["infiniteContainer"], descendants: true, read: ViewContainerRef, isSignal: true }, { propertyName: "contentContent", first: true, predicate: ["carouselContent"], descendants: true, read: TemplateRef, isSignal: true }], viewQueries: [{ propertyName: "container", first: true, predicate: ["containerElm"], descendants: true, read: ElementRef, isSignal: true }, { propertyName: "btnPrev", first: true, predicate: ["prev"], descendants: true, isSignal: true }, { propertyName: "btnNext", first: true, predicate: ["next"], descendants: true, isSignal: true }, { propertyName: "progressContainerElm", first: true, predicate: ["progress"], descendants: true, read: ElementRef, isSignal: true }], ngImport: i0, template: "<div #containerElm class=\"carousel\">\n <!-- main content -->\n <ng-content select=\"[ngx-hm-carousel-container]\" />\n <!-- left -->\n @if (contentPrev(); as prevVar) {\n <div #prev class=\"direction left\">\n <ng-container *ngTemplateOutlet=\"prevVar\" />\n </div>\n }\n <!-- right -->\n @if (contentNext(); as nextVar) {\n <div #next class=\"direction right\">\n <ng-container *ngTemplateOutlet=\"nextVar\" />\n </div>\n }\n <!-- indicators -->\n @if (dotElm(); as dotVar) {\n <ul class=\"indicators\">\n @for (dot of itemElms(); track dot; let i = $index) {\n <li (click)=\"currentIndex = i\">\n <ng-container\n *ngTemplateOutlet=\"\n dotVar;\n context: {\n $implicit: {\n index: i,\n currentIndex: currentIndex\n }\n }\n \"\n />\n </li>\n }\n </ul>\n }\n <!-- progress -->\n @if (autoplay() && progressElm(); as progressVar) {\n <div #progress>\n <ng-container *ngTemplateOutlet=\"progressVar\" />\n </div>\n }\n\n @if (grabbing) {\n <div class=\"mask\">\n @if (leaveObs$ | async) {}\n </div>\n }\n</div>\n", styles: [":host{display:block;height:100%}.ngx-hm-carousel-display-nowrap{display:flex!important;flex-wrap:nowrap!important;flex-direction:row!important;overflow:hidden!important}.carousel{overflow:hidden;position:relative;width:100%;height:100%}.carousel ul.indicators{list-style:none;bottom:1rem;left:0;margin:0;padding:0;position:absolute;text-align:center;width:100%}.carousel ul.indicators li{cursor:pointer;display:inline-block;position:relative;padding:.5rem}.carousel .direction{position:absolute;height:100%;cursor:pointer;display:flex;align-items:center;justify-content:center;top:0}.carousel .direction.left{left:0}.carousel .direction.right{position:absolute;right:0}.grab{cursor:grab}.grabbing{cursor:grabbing}.mask{position:absolute;inset:0}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: NgxHmCarouselComponent, decorators: [{
type: Component,
args: [{ selector: 'ngx-hm-carousel', providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => NgxHmCarouselComponent),
multi: true,
},
], changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [NgTemplateOutlet, AsyncPipe], template: "<div #containerElm class=\"carousel\">\n <!-- main content -->\n <ng-content select=\"[ngx-hm-carousel-container]\" />\n <!-- left -->\n @if (contentPrev(); as prevVar) {\n <div #prev class=\"direction left\">\n <ng-container *ngTemplateOutlet=\"prevVar\" />\n </div>\n }\n <!-- right -->\n @if (contentNext(); as nextVar) {\n <div #next class=\"direction right\">\n <ng-container *ngTemplateOutlet=\"nextVar\" />\n </div>\n }\n <!-- indicators -->\n @if (dotElm(); as dotVar) {\n <ul class=\"indicators\">\n @for (dot of itemElms(); track dot; let i = $index) {\n <li (click)=\"currentIndex = i\">\n <ng-container\n *ngTemplateOutlet=\"\n dotVar;\n context: {\n $implicit: {\n index: i,\n currentIndex: currentIndex\n }\n }\n \"\n />\n </li>\n }\n </ul>\n }\n <!-- progress -->\n @if (autoplay() && progressElm(); as progressVar) {\n <div #progress>\n <ng-container *ngTemplateOutlet=\"progressVar\" />\n </div>\n }\n\n @if (grabbing) {\n <div class=\"mask\">\n @if (leaveObs$ | async) {}\n </div>\n }\n</div>\n", styles: [":host{display:block;height:100%}.ngx-hm-carousel-display-nowrap{display:flex!important;flex-wrap:nowrap!important;flex-direction:row!important;overflow:hidden!important}.carousel{overflow:hidden;position:relative;width:100%;height:100%}.carousel ul.indicators{list-style:none;bottom:1rem;left:0;margin:0;padding:0;position:absolute;text-align:center;width:100%}.carousel ul.indicators li{cursor:pointer;display:inline-block;position:relative;padding:.5rem}.carousel .direction{position:absolute;height:100%;cursor:pointer;display:flex;align-items:center;justify-content:center;top:0}.carousel .direction.left{left:0}.carousel .direction.right{position:absolute;right:0}.grab{cursor:grab}.grabbing{cursor:grabbing}.mask{position:absolute;inset:0}\n"] }]
}], ctorParameters: () => [] });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LWhtLWNhcm91c2VsLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL2xpYnMvYW5ndWxhci9uZ3gtaG0tY2Fyb3VzZWwvc3JjL2xpYi9uZ3gtaG0tY2Fyb3VzZWwuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vbGlicy9hbmd1bGFyL25neC1obS1jYXJvdXNlbC9zcmMvbGliL25neC1obS1jYXJvdXNlbC5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0wsU0FBUyxFQUNULFFBQVEsRUFDUixpQkFBaUIsRUFDakIsZ0JBQWdCLEdBQ2pCLE1BQU0saUJBQWlCLENBQUM7QUFDekIsT0FBTyxFQUNMLHVCQUF1QixFQUN2QixpQkFBaUIsRUFDakIsU0FBUyxFQUNULFFBQVEsRUFDUixZQUFZLEVBQ1osZUFBZSxFQUNmLFVBQVUsRUFDVixNQUFNLEVBQ04sVUFBVSxFQUVWLFVBQVUsRUFDVixNQUFNLEVBQ04sS0FBSyxFQUNMLE1BQU0sRUFFTixXQUFXLEVBQ1gsU0FBUyxFQUNULE1BQU0sRUFDTixXQUFXLEVBQ1gsU0FBUyxFQUNULGdCQUFnQixHQUNqQixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsa0JBQWtCLEVBQUUsWUFBWSxFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDOUUsT0FBTyxFQUF3QixpQkFBaUIsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRXpFLE9BQU8sRUFDTCxlQUFlLEVBQ2YsV0FBVyxFQUNYLE1BQU0sRUFDTixRQUFRLEVBQ1IsU0FBUyxFQUNULFFBQVEsRUFDUixLQUFLLEVBRUwsRUFBRSxFQUNGLE9BQU8sRUFFUCxTQUFTLEVBQ1QsU0FBUyxFQUNULEdBQUcsRUFDSCxLQUFLLEdBQ04sTUFBTSxNQUFNLENBQUM7QUFFZCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUVwRCxPQUFP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