@alyle/ui
Version:
Minimal Design, a set of components for Angular
421 lines (416 loc) • 22.6 kB
JavaScript
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) => ` ${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