UNPKG

@alyle/ui

Version:

Minimal Design, a set of components for Angular

421 lines (416 loc) 22.6 kB
import { __decorate } from 'tslib'; import * as i0 from '@angular/core'; import { Input, forwardRef, ContentChildren, ViewChild, ChangeDetectionStrategy, Component, inject, Directive, NgModule } from '@angular/core'; import * as i1 from '@alyle/ui'; import { DirAlias, keyframesUniqueId, shadowBuilder, st2c, StyleCollection, StyleRenderer, Style, LyCommonModule } from '@alyle/ui'; import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { color } from '@alyle/ui/color'; import * as i2 from '@angular/cdk/platform'; import * as i3 from '@angular/common'; import { CommonModule } from '@angular/common'; /** Default interval in ms */ const DEFAULT_INTERVAL = 7000; const DEFAULT_AUTOPLAY = true; const DEFAULT_HAS_PROGRESS_BAR = false; const STYLE_PRIORITY = -2; const STYLES = (theme, ref) => { const dir = theme.getDirection(DirAlias.before); const right = dir === 'right' ? 180 : 0; const left = dir === 'left' ? 180 : 0; const carousel = ref.selectorsOf(STYLES); const barAnimation = keyframesUniqueId.next(); const { after, before } = theme; const arrow = `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='48' viewBox='0 -960 960 960' width='48'%3E%3Cpath style='fill:currentColor' d='M315.5-117 285-146.5 620.5-481 285-815.5l30.5-29.5 364 364-364 364Z'/%3E%3C/svg%3E")`; return { $priority: STYLE_PRIORITY, $global: (_className) => `@keyframes ${barAnimation}{0%{transform:translateX(0%);}100%{transform:translateX(${dir === 'left' ? '-' : ''}100%);}}`, root: () => (_className) => `${_className}{display:block;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;position:relative;}${_className} ${carousel.actions}.right{${after}:0;transform:rotate(${right}deg);}${_className} ${carousel.actions}.left{${before}:0;transform:rotate(${left}deg);}${_className} svg{display:block;fill:currentColor;}${st2c(((theme.carousel && theme.carousel.root && (theme.carousel.root instanceof StyleCollection ? theme.carousel.root.setTransformer(fn => fn(carousel)) : theme.carousel.root(carousel)))), `${_className}`)}`, actions: (_className) => `${_className}{position:absolute;top:0;bottom:0;height:100%;width:16%;cursor:pointer;color:${color(0xffffff, 0.87)};will-change:transform;}`, actionIcon: (_className) => `${_className}::after{position:absolute;content:'';top:0;left:0;right:0;bottom:0;margin:auto;background-color:currentColor;mask-image:${arrow};-webkit-mask-image:${arrow};mask-repeat:no-repeat;-webkit-mask-repeat:no-repeat;mask-position:50%;-webkit-mask-position:50%;mask-size:100% 100%;-webkit-mask-size:100% 100%;height:100%;width:48px;}`, slideContainer: (_className) => `${_className}{overflow:hidden;display:block;width:100%;height:100%;position:relative;touch-action:pan-y !important;}`, slide: (_className) => `${_className}{display:flex;width:100%;height:100%;will-change:transform;}${_className} > ly-carousel-item{width:100%;flex-shrink:0;position:relative;background-size:cover;background-position:center;background-repeat:no-repeat;}`, slideContent: (_className) => `${_className}{display:flex;}`, slideAnim: (_className) => `${_className} > div{transition:transform 750ms cubic-bezier(.1,1,0.5,1);}`, slideNoEvent: (_className) => `${_className}>div{touch-action:initial !important;-webkit-user-drag:initial !important;}`, indicators: () => (_className) => `${_className}{padding:0;position:absolute;bottom:0;left:0;right:0;margin:0;box-sizing:border-box;display:flex;align-items:center;justify-content:center;height:48px;}`, indicator: () => (_className) => `${_className}{display:inline-block;border-radius:50%;cursor:pointer;position:relative;padding:.5em;outline:none;}`, indicatorIcon: () => (_className) => `${_className}{transition:300ms cubic-bezier(0.65,0.05,0.36,1);width:1em;height:1em;transform:scale(.5);border-radius:50%;will-change:transform;display:block;opacity:.65;box-shadow:${shadowBuilder(8, color(0xffffff, 0.87))};background:${color(0xffffff, 0.87)};}`, indicatorActive: () => (_className) => `${_className} ${carousel.indicatorIcon}{transform:scale(1);opacity:1;}`, barContainer: (_className) => `${_className}{background:${theme.background.primary.default.alpha(.25)};height:4px;position:absolute;bottom:0;width:100%;}`, bar: (_className) => `${_className}{height:4px;position:absolute;bottom:0;width:100%;animation-name:${barAnimation};animation-timing-function:linear;animation-iteration-count:infinite;background:${theme.text.primary};}` }; }; /** @docs-private */ var CarouselMode; (function (CarouselMode) { /** full */ CarouselMode[CarouselMode["default"] = 0] = "default"; CarouselMode[CarouselMode["inline"] = 1] = "inline"; })(CarouselMode || (CarouselMode = {})); class LyCarousel { set darkIcon(val) { const newVal = coerceBooleanProperty(val); if (newVal !== this._darkIcon) { this._darkIcon = newVal; } } get darkIcon() { return this._darkIcon; } /** @internal */ get _isIntervalFn() { return !!this._intervalFn; } /** * It will pause the slide change when the mouse cursor passes * through the carousel. */ get pauseOnHover() { return this._pauseOnHover; } set pauseOnHover(val) { const newVal = coerceBooleanProperty(val); this._pauseOnHover = newVal; } set touch(val) { const newVal = coerceBooleanProperty(val); this._touch = newVal; if (newVal) { this._renderer.removeClass(this._el.nativeElement, this.classes.slideNoEvent); } else { this._renderer.addClass(this._el.nativeElement, this.classes.slideNoEvent); } } get touch() { return this._touch; } set autoplay(val) { const newVal = coerceBooleanProperty(val); this._autoplay = newVal; if (newVal) { this._resetInterval(); } else { this.stop(); } } get autoplay() { return this._autoplay; } set hasProgressBar(val) { const newVal = coerceBooleanProperty(val); this._hasProgressBar = newVal; } get hasProgressBar() { return this._hasProgressBar; } set interval(val) { this._interval = val; this._resetInterval(); } get interval() { return this._interval; } set hasNavigationArrows(val) { this._hasNavigationArrows = coerceBooleanProperty(val); } get hasNavigationArrows() { return this._hasNavigationArrows; } set hasNavigationIndicators(val) { this._hasNavigationIndicators = coerceBooleanProperty(val); } get hasNavigationIndicators() { return this._hasNavigationIndicators; } constructor(_el, _cd, _theme, _renderer, sRenderer, _platform) { this._el = _el; this._cd = _cd; this._theme = _theme; this._renderer = _renderer; this.sRenderer = sRenderer; this._platform = _platform; /** @docs-private */ this.classes = this.sRenderer.renderSheet(STYLES, true); this._intervalFn = null; /** @docs-private */ this.mode = CarouselMode.default; this.selectedIndex = 0; this.darkIconActived = false; this._interval = DEFAULT_INTERVAL; /** Emits whenever the component is destroyed. */ this._destroy = new Subject(); this._hasNavigationArrows = true; this._hasNavigationIndicators = true; } ngOnInit() { if (!this.touch) { this.touch = false; } if (this.autoplay == null) { this.autoplay = DEFAULT_AUTOPLAY; } if (this.hasProgressBar == null) { this.hasProgressBar = DEFAULT_HAS_PROGRESS_BAR; } } ngAfterViewInit() { this._renderer.addClass(this.slideContainer.nativeElement, this.classes.slideContainer); if (this._platform.isBrowser) { this._renderer.addClass(this.slideContainer.nativeElement, this.classes.slideAnim); } this.lyItems.changes.pipe(takeUntil(this._destroy)).subscribe(() => this._markForCheck()); this._select(this.selectedIndex); } ngOnDestroy() { this._destroy.next(); this._destroy.complete(); if (this._platform.isBrowser) { this.stop(); } } _onMouseEnter() { if (this.pauseOnHover) { this.stop(); } } _onMouseLeave() { if (this.pauseOnHover) { this._resetInterval(); } } /** @docs-private */ _onDragStart() { this.stop(); this._renderer.removeClass(this.slideContainer.nativeElement, this.classes.slideAnim); this._selectedElement = this.lyItems.find((_item, index) => index === this.selectedIndex)._nativeElement; } _onDrag(e) { const rect = this._selectedElement.getBoundingClientRect(); if (Math.abs(e.deltaX) < rect.width) { this._onPan(e.deltaX); } else { this._onPan(rect.width * Math.sign(e.deltaX)); } } _onDragEnd(e) { const rect = this._selectedElement.getBoundingClientRect(); const dir = this._theme.variables.getDirection(DirAlias.before); this._renderer.addClass(this.slideContainer.nativeElement, this.classes.slideAnim); this._select(this.selectedIndex); if (Math.abs(e.deltaX) > rect.width / 2) { if (0 > e.deltaX) { this.next(); } else if (0 < e.deltaX) { this.prev(); } } else if (e.additionalEvent) { const eventName = e.additionalEvent; if (Math.abs(e.velocity) >= 0.25) { if (eventName === 'slideleft') { if (dir === 'left') { this.next(); } else { this.prev(); } } else if (eventName === 'slideright') { if (dir === 'right') { this.next(); } else { this.prev(); } } } } this._renderer.removeStyle(this._slide.nativeElement, 'transform'); } _onDragCancel() { this._renderer.addClass(this.slideContainer.nativeElement, this.classes.slideAnim); this._select(this.selectedIndex); this._resetInterval(); } _select(val, notResetInterval) { this.selectedIndex = val; if (this.mode === CarouselMode.default) { this._slideClass = this._theme.addStyle(`lyCarousel.select:${val.toString(32)}`, (theme) => { const sign = theme.getDirection(DirAlias.before) === 'left' ? -1 : 1; return { transform: `translateX(${100 * val * sign}%)` }; }, this._slide.nativeElement, this._slideClass, STYLE_PRIORITY); } const darkIcon = this.lyItems.toArray()[val].darkIcon; this.darkIconActived = darkIcon ?? this.darkIcon; if (!notResetInterval) { if (this.autoplay && !this.pauseOnHover) { this._resetInterval(); } } } prev() { const len = this.lyItems.length - 1; const prev = this.selectedIndex - 1; this._select(prev < 0 ? len : prev); } next(notResetInterval) { const len = this.lyItems.length - 1; const next = this.selectedIndex + 1; this._select(next > len ? 0 : next, notResetInterval); } stop() { if (this._intervalFn !== null) { clearInterval(this._intervalFn); this._intervalFn = null; } } _resetInterval() { if (this._platform.isBrowser) { this.stop(); this._restartProgressBarAnimation(); this._markForCheck(); this._intervalFn = setInterval(() => { this.next(true); this._restartProgressBarAnimation(); this._markForCheck(); }, this.interval); } } _restartProgressBarAnimation() { if (this.hasProgressBar && this._progressBar) { const el = this._progressBar.nativeElement; // Hack for restart animation el.style.animationName = 'øfakeName'; window.getComputedStyle(el).getPropertyValue('opacity'); el.style.animationName = ''; } } _onPan(x) { const sign = this._theme.variables.getDirection(DirAlias.before) === 'left' ? -1 : 1; this._renderer.setStyle(this._slide.nativeElement, 'transform', `translateX(calc(${sign * 100 * this.selectedIndex}% + ${x}px))`); } _markForCheck() { this._cd.markForCheck(); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: LyCarousel, deps: [{ token: i0.ElementRef }, { token: i0.ChangeDetectorRef }, { token: i1.LyTheme2 }, { token: i0.Renderer2 }, { token: i1.StyleRenderer }, { token: i2.Platform }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.10", type: LyCarousel, isStandalone: false, selector: "ly-carousel", inputs: { mode: "mode", selectedIndex: "selectedIndex", darkIcon: "darkIcon", pauseOnHover: "pauseOnHover", touch: "touch", autoplay: "autoplay", hasProgressBar: "hasProgressBar", interval: "interval", hasNavigationArrows: "hasNavigationArrows", hasNavigationIndicators: "hasNavigationIndicators" }, host: { listeners: { "mouseenter": "_onMouseEnter()", "mouseleave": "_onMouseLeave()" } }, providers: [ StyleRenderer ], queries: [{ propertyName: "lyItems", predicate: i0.forwardRef(() => LyCarouselItem) }], viewQueries: [{ propertyName: "slideContainer", first: true, predicate: ["slideContainer"], descendants: true }, { propertyName: "_slide", first: true, predicate: ["_slide"], descendants: true }, { propertyName: "_progressBar", first: true, predicate: ["_progressBar"], descendants: true }], ngImport: i0, template: "<div\n(slidestart)=\"touch && _onDragStart()\"\n(slideleft)=\"touch && _onDrag($event)\"\n(slideright)=\"touch && _onDrag($event)\"\n(slidecancel)=\"touch && _onDragCancel()\"\n(slideend)=\"touch && _onDragEnd($event)\"\n#slideContainer\n>\n <div #_slide [className]=\"classes.slide\">\n <ng-content></ng-content>\n </div>\n <ol [className]=\"classes.indicators\" *ngIf=\"lyItems.length !== 1 && hasNavigationIndicators\">\n <li\n *ngFor=\"let item of lyItems; index as i\"\n [ngClass]=\"[classes.indicator, selectedIndex == i ? classes.indicatorActive : '']\"\n (click)=\"_select(i)\"\n >\n <span\n [class]=\"classes.indicatorIcon\"\n ></span>\n </li>\n </ol>\n <div *ngIf=\"hasNavigationArrows\" [class]=\"[classes.actions, classes.actionIcon, 'left']\" (click)=\"prev()\">\n </div>\n <div *ngIf=\"hasNavigationArrows\" [class]=\"[classes.actions, classes.actionIcon, 'right']\" (click)=\"next()\">\n </div>\n <div\n [className]=\"classes.barContainer\"\n *ngIf=\"hasProgressBar && _isIntervalFn && interval && autoplay\"\n >\n <div\n [className]=\"classes.bar\"\n #_progressBar\n [style.animation-duration]=\"interval + 'ms'\"\n ></div>\n </div>\n</div>", dependencies: [{ kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); } } __decorate([ Style((_val, _media) => (_theme, selectors) => { const $$ = selectors(STYLES); return (_className) => `${_className} ${$$.actionIcon},${_className} ${$$.indicatorIcon}{filter:invert(0.9);}`; }) ], LyCarousel.prototype, "darkIconActived", void 0); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: LyCarousel, decorators: [{ type: Component, args: [{ selector: 'ly-carousel', changeDetection: ChangeDetectionStrategy.OnPush, preserveWhitespaces: false, host: { '(mouseenter)': '_onMouseEnter()', '(mouseleave)': '_onMouseLeave()' }, providers: [ StyleRenderer ], standalone: false, template: "<div\n(slidestart)=\"touch && _onDragStart()\"\n(slideleft)=\"touch && _onDrag($event)\"\n(slideright)=\"touch && _onDrag($event)\"\n(slidecancel)=\"touch && _onDragCancel()\"\n(slideend)=\"touch && _onDragEnd($event)\"\n#slideContainer\n>\n <div #_slide [className]=\"classes.slide\">\n <ng-content></ng-content>\n </div>\n <ol [className]=\"classes.indicators\" *ngIf=\"lyItems.length !== 1 && hasNavigationIndicators\">\n <li\n *ngFor=\"let item of lyItems; index as i\"\n [ngClass]=\"[classes.indicator, selectedIndex == i ? classes.indicatorActive : '']\"\n (click)=\"_select(i)\"\n >\n <span\n [class]=\"classes.indicatorIcon\"\n ></span>\n </li>\n </ol>\n <div *ngIf=\"hasNavigationArrows\" [class]=\"[classes.actions, classes.actionIcon, 'left']\" (click)=\"prev()\">\n </div>\n <div *ngIf=\"hasNavigationArrows\" [class]=\"[classes.actions, classes.actionIcon, 'right']\" (click)=\"next()\">\n </div>\n <div\n [className]=\"classes.barContainer\"\n *ngIf=\"hasProgressBar && _isIntervalFn && interval && autoplay\"\n >\n <div\n [className]=\"classes.bar\"\n #_progressBar\n [style.animation-duration]=\"interval + 'ms'\"\n ></div>\n </div>\n</div>" }] }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }, { type: i1.LyTheme2 }, { type: i0.Renderer2 }, { type: i1.StyleRenderer }, { type: i2.Platform }], propDecorators: { slideContainer: [{ type: ViewChild, args: ['slideContainer'] }], _slide: [{ type: ViewChild, args: ['_slide'] }], _progressBar: [{ type: ViewChild, args: ['_progressBar'] }], lyItems: [{ type: ContentChildren, args: [forwardRef(() => LyCarouselItem)] }], mode: [{ type: Input }], selectedIndex: [{ type: Input }], darkIconActived: [], darkIcon: [{ type: Input }], pauseOnHover: [{ type: Input }], touch: [{ type: Input }], autoplay: [{ type: Input }], hasProgressBar: [{ type: Input }], interval: [{ type: Input }], hasNavigationArrows: [{ type: Input }], hasNavigationIndicators: [{ type: Input }] } }); class LyCarouselItem { set darkIcon(val) { if (val == null) { this._darkIcon = null; } else { this._darkIcon = coerceBooleanProperty(val); } } get darkIcon() { return this._darkIcon; } set srcImg(value) { this._className = this._theme.addStyle(`ly-carousel-img:${value}`, (`background-image: url('${value}')`), this._nativeElement, this._className, STYLE_PRIORITY); } constructor(_theme, _el) { this._theme = _theme; this.sRenderer = inject(StyleRenderer); this._darkIcon = null; this._nativeElement = _el.nativeElement; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: LyCarouselItem, deps: [{ token: i1.LyTheme2 }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.10", type: LyCarouselItem, isStandalone: false, selector: "ly-carousel-item", inputs: { darkIcon: "darkIcon", srcImg: "srcImg" }, providers: [ StyleRenderer ], ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: LyCarouselItem, decorators: [{ type: Directive, args: [{ selector: 'ly-carousel-item', providers: [ StyleRenderer ], standalone: false }] }], ctorParameters: () => [{ type: i1.LyTheme2 }, { type: i0.ElementRef }], propDecorators: { darkIcon: [{ type: Input }], srcImg: [{ type: Input }] } }); class LyCarouselModule { static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: LyCarouselModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); } static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.10", ngImport: i0, type: LyCarouselModule, declarations: [LyCarouselItem, LyCarousel], imports: [CommonModule, LyCommonModule], exports: [LyCarouselItem, LyCarousel, LyCommonModule] }); } static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: LyCarouselModule, imports: [CommonModule, LyCommonModule, LyCommonModule] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: LyCarouselModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule, LyCommonModule], exports: [LyCarouselItem, LyCarousel, LyCommonModule], declarations: [LyCarouselItem, LyCarousel] }] }] }); /** * Generated bundle index. Do not edit. */ export { CarouselMode, LyCarousel, LyCarouselItem, LyCarouselModule, STYLES }; //# sourceMappingURL=alyle-ui-carousel.mjs.map