ngx-hm-carousel
Version:
A light carousel for Angular, support mobile touch by hammerJs with SSR
831 lines (825 loc) • 42.2 kB
JavaScript
import * as i0 from '@angular/core';
import { Directive, inject, ViewContainerRef, TemplateRef, input, PLATFORM_ID, DestroyRef, Renderer2, NgZone, ChangeDetectorRef, viewChild, ElementRef, contentChildren, contentChild, computed, signal, effect, forwardRef, Component, ChangeDetectionStrategy } from '@angular/core';
import { DOCUMENT, isPlatformBrowser, NgTemplateOutlet, AsyncPipe } from '@angular/common';
import { toObservable, takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { merge, fromEvent, tap, BehaviorSubject, Subject, forkJoin, filter, switchMap, timer, takeUntil, of, interval, bufferCount } from 'rxjs';
import { resizeObservable } from '@nghedgehog/core';
class NgxHmCarouselItemDirective {
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: NgxHmCarouselItemDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.3", type: NgxHmCarouselItemDirective, isStandalone: true, selector: "[ngx-hm-carousel-item]", ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: NgxHmCarouselItemDirective, decorators: [{
type: Directive,
args: [{
selector: '[ngx-hm-carousel-item]',
standalone: true,
}]
}] });
// TODO: ssr problem should not hide on ssr
// TODO: show number change should recalculate is show and init show number
class NgxHmCarouselDynamicDirective {
_view = inject(ViewContainerRef);
_template = inject((TemplateRef));
index = input(undefined, {
alias: 'ngxHmCarouselDynamic',
});
length = input(0, { alias: 'ngxHmCarouselDynamicLength' });
show = input(1, { alias: 'ngxHmCarouselDynamicShow' });
currentI = input(0, {
alias: 'ngxHmCarouselDynamicIndex',
transform: (value) => {
if (!this.completed) {
const nextI = value + this.show();
const prevI = value - this.show();
if (this.index() === 0 ||
this.index() === this.length() - 1 ||
this.index() === nextI ||
this.index() === prevI ||
this.index() === value) {
this._view.createEmbeddedView(this._template);
this.completed = true;
}
}
return value;
},
});
completed = false;
constructor() {
this._view.clear();
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: NgxHmCarouselDynamicDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "18.2.3", type: NgxHmCarouselDynamicDirective, isStandalone: true, selector: "[ngxHmCarouselDynamic]", inputs: { index: { classPropertyName: "index", publicName: "ngxHmCarouselDynamic", isSignal: true, isRequired: false, transformFunction: null }, length: { classPropertyName: "length", publicName: "ngxHmCarouselDynamicLength", isSignal: true, isRequired: false, transformFunction: null }, show: { classPropertyName: "show", publicName: "ngxHmCarouselDynamicShow", isSignal: true, isRequired: false, transformFunction: null }, currentI: { classPropertyName: "currentI", publicName: "ngxHmCarouselDynamicIndex", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: NgxHmCarouselDynamicDirective, decorators: [{
type: Directive,
args: [{
selector: '[ngxHmCarouselDynamic]',
standalone: true,
}]
}], ctorParameters: () => [] });
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: () => [] });
/**
* Generated bundle index. Do not edit.
*/
export { NgxHmCarouselComponent, NgxHmCarouselDynamicDirective, NgxHmCarouselItemDirective };
//# sourceMappingURL=ngx-hm-carousel.mjs.map