UNPKG

ngx-hm-carousel

Version:

A light carousel for Angular, support mobile touch by hammerJs with SSR

769 lines 113 kB
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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