UNPKG

@hxui/angular

Version:

An Angular library based on the [HXUI design system](https://hxui.io).

1,088 lines (1,066 loc) 516 kB
import * as i0 from '@angular/core'; import { Component, Input, EventEmitter, Output, NgModule, Directive, HostListener, ReflectiveInjector, TemplateRef, ElementRef, Injectable, HostBinding, ContentChildren, forwardRef, ViewChild, ContentChild, ViewChildren, Optional, Inject, ViewContainerRef, Pipe, CUSTOM_ELEMENTS_SCHEMA, LOCALE_ID, ViewEncapsulation, ChangeDetectionStrategy } from '@angular/core'; import * as i1 from '@angular/common'; import { CommonModule, DOCUMENT, getLocaleDayPeriods, FormStyle, TranslationWidth, DatePipe } from '@angular/common'; import { trigger, state, style, transition, animate, keyframes } from '@angular/animations'; import * as i1$2 from '@angular/cdk/overlay'; import { OverlayModule, OverlayConfig } from '@angular/cdk/overlay'; import { TemplatePortal, PortalInjector, ComponentPortal, DomPortalOutlet, PortalModule } from '@angular/cdk/portal'; import * as i1$1 from '@angular/forms'; import { Validators, NG_VALUE_ACCESSOR, NG_VALIDATORS, FormsModule, ReactiveFormsModule } from '@angular/forms'; import moment from 'moment'; import { Subscription, BehaviorSubject, Subject, Observable, from, fromEvent, merge } from 'rxjs'; import { takeUntil, debounceTime, take, mergeMap, filter, toArray, map } from 'rxjs/operators'; import * as i8 from 'ngx-mask'; import { NgxMaskModule } from 'ngx-mask'; import * as i2 from '@angular/cdk/a11y'; import { A11yModule } from '@angular/cdk/a11y'; import * as _ from 'lodash'; import * as i1$3 from 'ngx-toastr'; import { Toast, ToastrModule } from 'ngx-toastr'; import { __decorate } from 'tslib'; import * as i4 from '@angular/cdk/scrolling'; import { ScrollingModule } from '@angular/cdk/scrolling'; import * as i10 from '@angular/router'; import { RouterModule } from '@angular/router'; import * as i3 from '@angular/cdk/bidi'; import sortBy from 'array-sort-by'; class AccordionBodyComponent { } AccordionBodyComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: AccordionBodyComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); AccordionBodyComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: AccordionBodyComponent, selector: "hx-accordion-body, hxa-accordion-body", ngImport: i0, template: `<ng-content></ng-content>`, isInline: true }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: AccordionBodyComponent, decorators: [{ type: Component, args: [{ selector: 'hx-accordion-body, hxa-accordion-body', template: `<ng-content></ng-content>` }] }] }); class AccordionComponent { constructor() { this.cssClass = null; } } AccordionComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: AccordionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); AccordionComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: AccordionComponent, selector: "hx-accordion, hxa-accordion", inputs: { cssClass: "cssClass" }, ngImport: i0, template: ` <div class="hxui-reset"> <ul class="hx-accordion" [ngClass]="cssClass"> <ng-content></ng-content> </ul> </div> `, isInline: true, directives: [{ type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: AccordionComponent, decorators: [{ type: Component, args: [{ selector: 'hx-accordion, hxa-accordion', template: ` <div class="hxui-reset"> <ul class="hx-accordion" [ngClass]="cssClass"> <ng-content></ng-content> </ul> </div> ` }] }], propDecorators: { cssClass: [{ type: Input }] } }); /** * TODO: !BREAKING! align accordion markup for accessibility, * consider using attribute selector * @see {@link https://www.w3.org/TR/wai-aria-practices/#accordion} * @see {@link https://medium.com/javascript-everyday/when-to-use-an-attribute-selector-for-angular-components-7e788ba1bfe7} */ class AccordionContainerComponent { constructor(_changeDetectionRef) { this._changeDetectionRef = _changeDetectionRef; this.expanded = true; this.index = null; this.disabled = false; this.empty = true; this.headerClick = new EventEmitter(); } toggle() { if (this.index !== null) { this.headerClick.emit(this.index); } this.expanded = !this.expanded; this._changeDetectionRef.markForCheck(); } } AccordionContainerComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: AccordionContainerComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); AccordionContainerComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: AccordionContainerComponent, selector: "hx-accordion-container, hxa-accordion-container", inputs: { expanded: "expanded", index: "index", disabled: "disabled", empty: "empty" }, outputs: { headerClick: "headerClick" }, ngImport: i0, template: ` <li class="hx-accordion-container" [class.is-active]="expanded && !disabled" > <a class="hx-accordion-header" [class.is-disabled]="!empty && disabled" (click)="toggle()" > <div class="header-title"> <ng-content select="hx-accordion-header, hxa-accordion-header" ></ng-content> </div> <div class="header-icon" *ngIf="empty"> <i class="hx-icon icon-angle-down" *ngIf="!expanded || disabled"></i> <i class="hx-icon icon-angle-up" *ngIf="expanded && !disabled"></i> </div> </a> <div class="hx-accordion-body" [@slideIn]="expanded && !disabled" *ngIf="expanded && !disabled" > <div class="hx-accordion-body-wrapper"> <ng-content select="hx-accordion-body, hxa-accordion-body" ></ng-content> </div> </div> </li> `, isInline: true, styles: [".hx-accordion{list-style:none;background-color:#fff;border:1px solid rgba(0,0,0,.08);padding:0}.hx-accordion-container{margin-top:0}.hx-accordion-container:not(:last-child){box-shadow:inset 0 -1px #00000014}.hx-accordion-container:not(.is-active) .hx-accordion-header:hover{background-color:#00000005;text-decoration:none;color:#41b987}.hx-accordion-header{color:#2a2c2d;padding:1rem;display:flex;align-items:center;justify-content:space-between;transition:.3s}.hx-accordion-header:hover{color:#2a2c2d;text-decoration:none}.hx-accordion-header .header-icon{transition:.3s;display:flex}.hx-accordion-body{overflow-y:hidden;background-color:#fafafa;transition:.5s;box-shadow:inset 0 1px #00000014}.hx-accordion-body-wrapper{padding:1rem}:host:not(:last-child) .hx-accordion-container{box-shadow:inset 0 -1px #00000014}\n"], directives: [{ type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], animations: [ trigger('slideIn', [ state('*', style({ 'overflow-y': 'hidden' })), state('void', style({ 'overflow-y': 'hidden' })), transition('* => void', [ style({ height: '*' }), animate('0.25s ease-out', style({ height: 0, opacity: 0 })) ]), transition('void => *', [ style({ height: '0' }), animate('0.25s ease-out', style({ height: '*', opacity: 1 })) ]) ]) ] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: AccordionContainerComponent, decorators: [{ type: Component, args: [{ selector: 'hx-accordion-container, hxa-accordion-container', template: ` <li class="hx-accordion-container" [class.is-active]="expanded && !disabled" > <a class="hx-accordion-header" [class.is-disabled]="!empty && disabled" (click)="toggle()" > <div class="header-title"> <ng-content select="hx-accordion-header, hxa-accordion-header" ></ng-content> </div> <div class="header-icon" *ngIf="empty"> <i class="hx-icon icon-angle-down" *ngIf="!expanded || disabled"></i> <i class="hx-icon icon-angle-up" *ngIf="expanded && !disabled"></i> </div> </a> <div class="hx-accordion-body" [@slideIn]="expanded && !disabled" *ngIf="expanded && !disabled" > <div class="hx-accordion-body-wrapper"> <ng-content select="hx-accordion-body, hxa-accordion-body" ></ng-content> </div> </div> </li> `, animations: [ trigger('slideIn', [ state('*', style({ 'overflow-y': 'hidden' })), state('void', style({ 'overflow-y': 'hidden' })), transition('* => void', [ style({ height: '*' }), animate('0.25s ease-out', style({ height: 0, opacity: 0 })) ]), transition('void => *', [ style({ height: '0' }), animate('0.25s ease-out', style({ height: '*', opacity: 1 })) ]) ]) ], styles: [".hx-accordion{list-style:none;background-color:#fff;border:1px solid rgba(0,0,0,.08);padding:0}.hx-accordion-container{margin-top:0}.hx-accordion-container:not(:last-child){box-shadow:inset 0 -1px #00000014}.hx-accordion-container:not(.is-active) .hx-accordion-header:hover{background-color:#00000005;text-decoration:none;color:#41b987}.hx-accordion-header{color:#2a2c2d;padding:1rem;display:flex;align-items:center;justify-content:space-between;transition:.3s}.hx-accordion-header:hover{color:#2a2c2d;text-decoration:none}.hx-accordion-header .header-icon{transition:.3s;display:flex}.hx-accordion-body{overflow-y:hidden;background-color:#fafafa;transition:.5s;box-shadow:inset 0 1px #00000014}.hx-accordion-body-wrapper{padding:1rem}:host:not(:last-child) .hx-accordion-container{box-shadow:inset 0 -1px #00000014}\n"] }] }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }]; }, propDecorators: { expanded: [{ type: Input }], index: [{ type: Input }], disabled: [{ type: Input }], empty: [{ type: Input }], headerClick: [{ type: Output }] } }); class AccordionHeaderComponent { } AccordionHeaderComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: AccordionHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); AccordionHeaderComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: AccordionHeaderComponent, selector: "hx-accordion-header, hxa-accordion-header", ngImport: i0, template: `<ng-content></ng-content>`, isInline: true }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: AccordionHeaderComponent, decorators: [{ type: Component, args: [{ selector: 'hx-accordion-header, hxa-accordion-header', template: `<ng-content></ng-content>` }] }] }); class AccordionModule { } AccordionModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: AccordionModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); AccordionModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: AccordionModule, declarations: [AccordionComponent, AccordionContainerComponent, AccordionHeaderComponent, AccordionBodyComponent], imports: [CommonModule], exports: [AccordionComponent, AccordionContainerComponent, AccordionHeaderComponent, AccordionBodyComponent] }); AccordionModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: AccordionModule, imports: [[CommonModule]] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: AccordionModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule], declarations: [ AccordionComponent, AccordionContainerComponent, AccordionHeaderComponent, AccordionBodyComponent ], exports: [ AccordionComponent, AccordionContainerComponent, AccordionHeaderComponent, AccordionBodyComponent ] }] }] }); class AutoGrowDirective { constructor(element) { this.element = element; } onInput() { this.resize(); } ngAfterViewInit() { const style = this.element.nativeElement.style; style.overflow = 'hidden'; style.height = 'auto'; } resize() { const el = this.element.nativeElement; if (el.style.height === el.scrollHeight + 'px') { return; } el.style.overflow = 'hidden'; el.style.height = 'auto'; el.style.height = `${el.scrollHeight}px`; } } AutoGrowDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: AutoGrowDirective, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); AutoGrowDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.3.11", type: AutoGrowDirective, selector: "textarea[autogrow]", host: { listeners: { "input": "onInput($event.target)" } }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: AutoGrowDirective, decorators: [{ type: Directive, args: [{ selector: 'textarea[autogrow]' }] }], ctorParameters: function () { return [{ type: i0.ElementRef }]; }, propDecorators: { onInput: [{ type: HostListener, args: ['input', ['$event.target']] }] } }); class AutoGrowModule { static forRoot() { return { ngModule: AutoGrowModule, providers: [] }; } } AutoGrowModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: AutoGrowModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); AutoGrowModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: AutoGrowModule, declarations: [AutoGrowDirective], exports: [AutoGrowDirective] }); AutoGrowModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: AutoGrowModule }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: AutoGrowModule, decorators: [{ type: NgModule, args: [{ declarations: [AutoGrowDirective], exports: [AutoGrowDirective] }] }] }); /** * @copyright Valor Software * @copyright Angular ng-bootstrap team */ class Trigger { constructor(open, close) { this.open = open; this.close = close || open; } isManual() { return this.open === 'manual' || this.close === 'manual'; } } const DEFAULT_ALIASES = { hover: ['mouseenter', 'mouseleave'], focus: ['focusin', 'focusout'] }; function parseTriggers(triggers, aliases = DEFAULT_ALIASES) { const trimmedTriggers = (triggers || '').trim(); if (trimmedTriggers.length === 0) { return []; } const parsedTriggers = trimmedTriggers.split(/\s+/) .map((trigger) => trigger.split(':')) .map((triggerPair) => { const alias = aliases[triggerPair[0]] || triggerPair; return new Trigger(alias[0], alias[1]); }); const manualTriggers = parsedTriggers .filter((triggerPair) => triggerPair.isManual()); if (manualTriggers.length > 1) { throw new Error('Triggers parse error: only one manual trigger is allowed'); } if (manualTriggers.length === 1 && parsedTriggers.length > 1) { throw new Error('Triggers parse error: manual trigger can\'t be mixed with other triggers'); } return parsedTriggers; } function listenToTriggers(renderer, target, triggers, showFn, hideFn, toggleFn) { const parsedTriggers = parseTriggers(triggers); const listeners = []; if (parsedTriggers.length === 1 && parsedTriggers[0].isManual()) { return Function.prototype; } parsedTriggers.forEach((trigger) => { if (trigger.open === trigger.close) { listeners.push(renderer.listen(target, trigger.open, toggleFn)); return; } listeners.push(renderer.listen(target, trigger.open, showFn), renderer.listen(target, trigger.close, hideFn)); }); return () => { listeners.forEach((unsubscribeFn) => unsubscribeFn()); }; } class ContentRef { constructor(nodes, viewRef, componentRef) { this.nodes = nodes; this.viewRef = viewRef; this.componentRef = componentRef; } } // todo: add delay support class ComponentLoader { /** * Do not use this directly, it should be instanced via * `ComponentLoadFactory.attach` * @internal * @param _viewContainerRef * @param _elementRef * @param _injector * @param _renderer * @param _componentFactoryResolver * @param _ngZone * @param _posService */ // eslint-disable-next-line constructor(_viewContainerRef, _renderer, _elementRef, _injector, _componentFactoryResolver, _ngZone, _posService) { this.onBeforeShow = new EventEmitter(); this.onShown = new EventEmitter(); this.onBeforeHide = new EventEmitter(); this.onHidden = new EventEmitter(); this._providers = []; this._ngZone = _ngZone; this._injector = _injector; this._renderer = _renderer; this._elementRef = _elementRef; this._posService = _posService; this._viewContainerRef = _viewContainerRef; this._componentFactoryResolver = _componentFactoryResolver; } get isShown() { return !!this._componentRef; } attach(compType) { this._componentFactory = this._componentFactoryResolver.resolveComponentFactory(compType); return this; } // todo: add behaviour: to target element, `body`, custom element to(container) { this.container = container || this.container; return this; } position(opts) { this.attachment = opts.attachment || this.attachment; this._elementRef = opts.target || this._elementRef; return this; } provide(provider) { this._providers.push(provider); return this; } show(opts = {}) { this._subscribePositioning(); if (!this._componentRef) { this.onBeforeShow.emit(); this._contentRef = this._getContentRef(opts.content); const injector = ReflectiveInjector.resolveAndCreate(this._providers, this._injector); this._componentRef = this._viewContainerRef.createComponent(this._componentFactory, 0, injector, this._contentRef.nodes); this.instance = this._componentRef.instance; Object.assign(this._componentRef.instance, opts); if (this.container === 'body' && typeof document !== 'undefined') { document .querySelector(this.container) .appendChild(this._componentRef.location.nativeElement); } // we need to manually invoke change detection since events registered // via // Renderer::listen() are not picked up by change detection with the // OnPush strategy this._componentRef.changeDetectorRef.markForCheck(); this.onShown.emit(this._componentRef.instance); } return this._componentRef; } hide() { if (this._componentRef) { this.onBeforeHide.emit(this._componentRef.instance); this._viewContainerRef.remove(this._viewContainerRef.indexOf(this._componentRef.hostView)); this._componentRef = null; if (this._contentRef.viewRef) { this._viewContainerRef.remove(this._viewContainerRef.indexOf(this._contentRef.viewRef)); this._contentRef = null; } this._componentRef = null; this.onHidden.emit(); } return this; } toggle() { if (this.isShown) { this.hide(); return; } this.show(); } dispose() { if (this.isShown) { this.hide(); } this._unsubscribePositioning(); if (this._unregisterListenersFn) { this._unregisterListenersFn(); } } listen(listenOpts) { this.triggers = listenOpts.triggers || this.triggers; listenOpts.target = listenOpts.target || this._elementRef; listenOpts.show = listenOpts.show || (() => this.show()); listenOpts.hide = listenOpts.hide || (() => this.hide()); listenOpts.toggle = listenOpts.toggle || (() => (this.isShown ? listenOpts.hide() : listenOpts.show())); this._unregisterListenersFn = listenToTriggers(this._renderer, listenOpts.target.nativeElement, this.triggers, listenOpts.show, listenOpts.hide, listenOpts.toggle); return this; } _subscribePositioning() { if (this._zoneSubscription || !this.attachment) { return; } this._zoneSubscription = this._ngZone.onStable.subscribe(() => { if (!this._componentRef) { return; } this._posService.position({ element: this._componentRef.location, target: this._elementRef, attachment: this.attachment, appendToBody: this.container === 'body' }); }); } _unsubscribePositioning() { if (!this._zoneSubscription) { return; } this._zoneSubscription.unsubscribe(); this._zoneSubscription = null; } _getContentRef(content) { if (!content) { return new ContentRef([]); } if (content instanceof TemplateRef) { const viewRef = this._viewContainerRef.createEmbeddedView(content); return new ContentRef([viewRef.rootNodes], viewRef); } return new ContentRef([[this._renderer.createText(`${content}`)]]); } } /** * @copyright Valor Software * @copyright Angular ng-bootstrap team */ // previous version: // https://github.com/angular-ui/bootstrap/blob/07c31d0731f7cb068a1932b8e01d2312b796b4ec/src/position/position.js class Positioning { position(element, round = true) { let elPosition; let parentOffset = { width: 0, height: 0, top: 0, bottom: 0, left: 0, right: 0 }; if (this.getStyle(element, 'position') === 'fixed') { const tempPos = element.getBoundingClientRect(); elPosition = tempPos; } else { const offsetParentEl = this.offsetParent(element); elPosition = this.offset(element, false); if (offsetParentEl !== document.documentElement) { parentOffset = this.offset(offsetParentEl, false); } parentOffset.top += offsetParentEl.clientTop; parentOffset.left += offsetParentEl.clientLeft; } elPosition.top -= parentOffset.top; elPosition.bottom -= parentOffset.top; elPosition.left -= parentOffset.left; elPosition.right -= parentOffset.left; if (round) { elPosition.top = Math.round(elPosition.top); elPosition.bottom = Math.round(elPosition.bottom); elPosition.left = Math.round(elPosition.left); elPosition.right = Math.round(elPosition.right); } return elPosition; } offset(element, round = true) { const elBcr = element.getBoundingClientRect(); const viewportOffset = { top: window.pageYOffset - document.documentElement.clientTop, left: window.pageXOffset - document.documentElement.clientLeft }; const elOffset = { height: elBcr.height || element.offsetHeight, width: elBcr.width || element.offsetWidth, top: elBcr.top + viewportOffset.top, bottom: elBcr.bottom + viewportOffset.top, left: elBcr.left + viewportOffset.left, right: elBcr.right + viewportOffset.left }; if (round) { elOffset.height = Math.round(elOffset.height); elOffset.width = Math.round(elOffset.width); elOffset.top = Math.round(elOffset.top); elOffset.bottom = Math.round(elOffset.bottom); elOffset.left = Math.round(elOffset.left); elOffset.right = Math.round(elOffset.right); } return elOffset; } positionElements(hostElement, targetElement, placement, appendToBody) { const hostElPosition = appendToBody ? this.offset(hostElement, false) : this.position(hostElement, false); const shiftWidth = { left: hostElPosition.left, center: hostElPosition.left + hostElPosition.width / 2 - targetElement.offsetWidth / 2, right: hostElPosition.left + hostElPosition.width }; const shiftHeight = { top: hostElPosition.top, center: hostElPosition.top + hostElPosition.height / 2 - targetElement.offsetHeight / 2, bottom: hostElPosition.top + hostElPosition.height }; const targetElBCR = targetElement.getBoundingClientRect(); const placementPrimary = placement.split(' ')[0] || 'top'; const placementSecondary = placement.split(' ')[1] || 'center'; const targetElPosition = { height: targetElBCR.height || targetElement.offsetHeight, width: targetElBCR.width || targetElement.offsetWidth, top: 0, bottom: targetElBCR.height || targetElement.offsetHeight, left: 0, right: targetElBCR.width || targetElement.offsetWidth }; switch (placementPrimary) { case 'top': targetElPosition.top = hostElPosition.top - targetElement.offsetHeight; targetElPosition.bottom += hostElPosition.top - targetElement.offsetHeight; targetElPosition.left = shiftWidth[placementSecondary]; targetElPosition.right += shiftWidth[placementSecondary]; break; case 'bottom': targetElPosition.top = shiftHeight[placementPrimary]; targetElPosition.bottom += shiftHeight[placementPrimary]; targetElPosition.left = shiftWidth[placementSecondary]; targetElPosition.right += shiftWidth[placementSecondary]; break; case 'left': targetElPosition.top = shiftHeight[placementSecondary]; targetElPosition.bottom += shiftHeight[placementSecondary]; targetElPosition.left = hostElPosition.left - targetElement.offsetWidth; targetElPosition.right += hostElPosition.left - targetElement.offsetWidth; break; case 'right': targetElPosition.top = shiftHeight[placementSecondary]; targetElPosition.bottom += shiftHeight[placementSecondary]; targetElPosition.left = shiftWidth[placementPrimary]; targetElPosition.right += shiftWidth[placementPrimary]; break; } targetElPosition.top = Math.round(targetElPosition.top); targetElPosition.bottom = Math.round(targetElPosition.bottom); targetElPosition.left = Math.round(targetElPosition.left); targetElPosition.right = Math.round(targetElPosition.right); return targetElPosition; } getStyle(element, prop) { return window.getComputedStyle(element)[prop]; } isStaticPositioned(element) { return (this.getStyle(element, 'position') || 'static') === 'static'; } offsetParent(element) { let offsetParentEl = element.offsetParent || document.documentElement; while (offsetParentEl && offsetParentEl !== document.documentElement && this.isStaticPositioned(offsetParentEl)) { offsetParentEl = offsetParentEl.offsetParent; } return offsetParentEl || document.documentElement; } } const positionService = new Positioning(); function positionElements(hostElement, targetElement, placement, appendToBody) { const pos = positionService.positionElements(hostElement, targetElement, placement, appendToBody); targetElement.style.top = `${pos.top}px`; targetElement.style.left = `${pos.left}px`; } class PositioningService { position(options) { const { element, target, attachment, appendToBody } = options; positionElements(this._getHtmlElement(target), this._getHtmlElement(element), attachment, appendToBody); } isElementBelowTheFold(element) { const rect = element.getBoundingClientRect(); return ((rect.top + rect.height) > document.body.clientHeight); } _getHtmlElement(element) { // it means that we got a selector if (typeof element === 'string') { return document.querySelector(element); } if (element instanceof ElementRef) { return element.nativeElement; } return element; } } PositioningService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: PositioningService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); PositioningService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: PositioningService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: PositioningService, decorators: [{ type: Injectable }] }); class ComponentLoaderFactory { constructor(componentFactoryResolver, ngZone, injector, posService) { this._ngZone = ngZone; this._injector = injector; this._posService = posService; this._componentFactoryResolver = componentFactoryResolver; } createLoader(_elementRef, _viewContainerRef, _renderer) { return new ComponentLoader(_viewContainerRef, _renderer, _elementRef, this._injector, this._componentFactoryResolver, this._ngZone, this._posService); } } ComponentLoaderFactory.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: ComponentLoaderFactory, deps: [{ token: i0.ComponentFactoryResolver }, { token: i0.NgZone }, { token: i0.Injector }, { token: PositioningService }], target: i0.ɵɵFactoryTarget.Injectable }); ComponentLoaderFactory.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: ComponentLoaderFactory }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: ComponentLoaderFactory, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: i0.ComponentFactoryResolver }, { type: i0.NgZone }, { type: i0.Injector }, { type: PositioningService }]; } }); class HxComponentRef { } var DisplayMode; (function (DisplayMode) { DisplayMode[DisplayMode["showTab"] = 1] = "showTab"; DisplayMode[DisplayMode["showCustomOnly"] = 2] = "showCustomOnly"; DisplayMode[DisplayMode["showIntervalOnly"] = 3] = "showIntervalOnly"; })(DisplayMode || (DisplayMode = {})); //expanded when more tabs be added var DateSelectionType; (function (DateSelectionType) { DateSelectionType[DateSelectionType["interval"] = 0] = "interval"; DateSelectionType[DateSelectionType["custom"] = 1] = "custom"; })(DateSelectionType || (DateSelectionType = {})); class TextInputDirective { constructor(el) { this.el = el; this.styleLabel(); } onFocus() { this.styleLabelAsFloating(); } onBlur() { this.styleLabel(); } styleLabel(floatingLabel) { // If the element is empty, style the label like a placeholder otherwise float the label above the input if (!floatingLabel && this.el.nativeElement.value.trim().length === 0 && this.el.nativeElement.placeholder.trim().length === 0) { this.styleLabelAsPlaceholder(); } else { this.styleLabelAsFloating(); } } styleLabelAsPlaceholder() { this.isPlaceholder = true; this.isLabel = false; } styleLabelAsFloating() { this.isPlaceholder = false; this.isLabel = true; } } TextInputDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: TextInputDirective, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); TextInputDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.3.11", type: TextInputDirective, selector: "[hxaTextInput]", host: { listeners: { "focus": "onFocus()", "blur": "onBlur()" }, properties: { "class.has-label-placeholder": "this.isPlaceholder", "class.has-label-floating": "this.isLabel" } }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: TextInputDirective, decorators: [{ type: Directive, args: [{ selector: '[hxaTextInput]' }] }], ctorParameters: function () { return [{ type: i0.ElementRef }]; }, propDecorators: { isPlaceholder: [{ type: HostBinding, args: ['class.has-label-placeholder'] }], isLabel: [{ type: HostBinding, args: ['class.has-label-floating'] }], onFocus: [{ type: HostListener, args: ['focus'] }], onBlur: [{ type: HostListener, args: ['blur'] }] } }); /** Default values provider for calendar */ class DatepickerConfig { constructor() { /** dropdown overlay placement */ this.placement = 'bottom'; /** delay in ms before showing the calendar after show is called */ this.showDelay = 0; /** delay in ms before hiding the calendar after hide is called */ this.hideDelay = 0; } } DatepickerConfig.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: DatepickerConfig, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); DatepickerConfig.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: DatepickerConfig }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: DatepickerConfig, decorators: [{ type: Injectable }] }); // eslint-disable-next-line @angular-eslint/directive-selector class TabDirective { // TODO: refactor so that ref to parent 'TabsetComponent' is removed, causing circular refs constructor(tabset, elementRef) { this.elementRef = elementRef; /** fired when tab became active, $event:Tab equals to selected instance of Tab component */ // TODO: change output name // eslint-disable-next-line @angular-eslint/no-output-native this.select = new EventEmitter(); /** fired when tab became inactive, $event:Tab equals to deselected instance of Tab component */ this.deselect = new EventEmitter(); /** fired before tab will be removed, $event:Tab equals to instance of removed tab */ this.removed = new EventEmitter(); this.addClasn = true; this.tabset = tabset; this.tabset.addTab(this); } get active() { return this._active; } set active(active) { if ((this.disabled && active) || !active) { if (!active) { this._active = active; } this.deselect.emit(this); return; } this._active = active; this.select.emit(this); } /** tab active state toggle */ get _() { return !!this._active; } ngOnDestroy() { this.tabset.removeTab(this, { reselect: false, emit: false }); } } TabDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: TabDirective, deps: [{ token: TabsetComponent }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); TabDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.3.11", type: TabDirective, selector: "hx-tab, [hx-tab]", inputs: { heading: "heading", id: "id", disabled: "disabled", removable: "removable", customClass: "customClass", active: "active" }, outputs: { select: "select", deselect: "deselect", removed: "removed" }, host: { properties: { "class.is-active": "this._", "class.hx-tab-pane": "this.addClasn" } }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: TabDirective, decorators: [{ type: Directive, args: [{ selector: 'hx-tab, [hx-tab]' }] }], ctorParameters: function () { return [{ type: TabsetComponent }, { type: i0.ElementRef }]; }, propDecorators: { heading: [{ type: Input }], id: [{ type: Input }], disabled: [{ type: Input }], removable: [{ type: Input }], customClass: [{ type: Input }], active: [{ type: Input }], _: [{ type: HostBinding, args: ['class.is-active'] }], select: [{ type: Output }], deselect: [{ type: Output }], removed: [{ type: Output }], addClasn: [{ type: HostBinding, args: ['class.hx-tab-pane'] }] } }); class TabsetConfig { constructor() { /** provides default navigation context class */ this.type = 'tabs'; } } TabsetConfig.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: TabsetConfig, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); TabsetConfig.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: TabsetConfig }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: TabsetConfig, decorators: [{ type: Injectable }] }); class NgTranscludeDirective { constructor(viewRef) { this.viewRef = viewRef; } set ngTransclude(templateRef) { this._ngTransclude = templateRef; if (templateRef) { this.viewRef.createEmbeddedView(templateRef); } } get ngTransclude() { return this._ngTransclude; } } NgTranscludeDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: NgTranscludeDirective, deps: [{ token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Directive }); NgTranscludeDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.3.11", type: NgTranscludeDirective, selector: "[ngTransclude]", inputs: { ngTransclude: "ngTransclude" }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: NgTranscludeDirective, decorators: [{ type: Directive, args: [{ selector: '[ngTransclude]' }] }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }]; }, propDecorators: { ngTransclude: [{ type: Input }] } }); class TabsetComponent { constructor(config) { /** if true tabs will be placed vertically */ this.vertical = false; /** if true tabs fill the container and have a consistent width */ this.justified = false; this.hasInfo = false; this.stickyHeader = false; this.stickyHeaderOffset = 0; this.tag = 'link'; this.changeFn = async () => true; this.tabs = []; Object.assign(this, config); } /** navigation context class: 'tabs' or 'pills' */ get type() { return this._type; } set type(value) { this._type = value; } ngAfterContentInit() { // get all active tabs const activeTabs = this._tabList.filter(tab => tab.active); // if there is no active tab set, activate the first if (activeTabs.length === 0) { this._selectTab(this._tabList.last); } } _selectTab(tab) { // deactivate all tabs this._tabList.toArray().forEach(tab => (tab.active = false)); // activate the tab the user has clicked on. tab.active = true; } selectTab(tab) { this.changeFn().then(res => !!res && this._selectTab(tab)); } ngOnDestroy() { this.isDestroyed = true; } addTab(tab) { this.tabs.push(tab); tab.active = this.tabs.length === 1 && tab.active !== false; } removeTab(tab, options = { reselect: true, emit: true }) { const index = this.tabs.indexOf(tab); if (index === -1 || this.isDestroyed) { return; } // Select a new tab if the tab to be removed is selected and not destroyed if (options.reselect && tab.active && this.hasAvailableTabs(index)) { const newActiveIndex = this.getClosestTabIndex(index); this.tabs[newActiveIndex].active = true; } if (options.emit) { tab.removed.emit(tab); } this.tabs.splice(index, 1); if (tab.elementRef.nativeElement && tab.elementRef.nativeElement.remove) { tab.elementRef.nativeElement.remove(); } } getStickyHeaderPosition() { return this.stickyHeader ? 'sticky' : 'relative'; } getClosestTabIndex(index) { const tabsLength = this.tabs.length; if (!tabsLength) { return -1; } for (let step = 1; step <= tabsLength; step += 1) { const prevIndex = index - step; const nextIndex = index + step; if (this.tabs[prevIndex] && !this.tabs[prevIndex].disabled) { return prevIndex; } if (this.tabs[nextIndex] && !this.tabs[nextIndex].disabled) { return nextIndex; } } return -1; } hasAvailableTabs(index) { const tabsLength = this.tabs.length; if (!tabsLength) { return false; } for (let i = 0; i < tabsLength; i += 1) { if (!this.tabs[i].disabled && i !== index) { return true; } } return false; } } TabsetComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: TabsetComponent, deps: [{ token: TabsetConfig }], target: i0.ɵɵFactoryTarget.Component }); TabsetComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: TabsetComponent, selector: "hx-tabset", inputs: { vertical: "vertical", justified: "justified", hasInfo: "hasInfo", type: "type", contentCustomClass: "contentCustomClass", stickyHeader: "stickyHeader", stickyHeaderOffset: "stickyHeaderOffset", tag: "tag", changeFn: "changeFn" }, host: { classAttribute: "hx-tab-container" }, queries: [{ propertyName: "_tabList", predicate: i0.forwardRef(function () { return TabDirective; }) }], ngImport: i0, template: ` <ul class="hx-nav hx-nav-{{ type }}" [ngStyle]="{ position: getStickyHeaderPosition(), 'top.rem': stickyHeaderOffset }" [class.is-vertical]="vertical" [class.is-justified]="justified" [class.has-info]="hasInfo" > <li *ngFor="let tab of tabs" [ngClass]="['hx-nav-item', tab.customClass || '']" [class.is-active]="!!tab?.active" [class.is-disabled]="!!tab?.disabled" [class.is-button]="tag === 'button'" > <button *ngIf="tag === 'button'" class="hx-nav-link" [class.is-active]="!!tab?.active" [class.is-disabled]="!!tab?.disabled" [attr.disabled]="!!tab?.disabled ? '' : null" (click)="selectTab(tab)" > <span [ngTransclude]="tab.headingRef">{{ tab.heading }}</span> <span *ngIf="tab.removable"> <span (click)="removeTab(tab)" class="icon close-outline is-small" ></span> </span> </button> <a *ngIf="tag === 'link'" class="hx-nav-link" [class.is-active]="!!tab?.active" [class.is-disabled]="!!tab?.disabled" [attr.disabled]="!!tab?.disabled ? '' : null" (click)="selectTab(tab)" > <span [ngTransclude]="tab.headingRef">{{ tab.heading }}</span> <span *ngIf="tab.removable"> <span (click)="removeTab(tab)" class="icon close-outline is-small" ></span> </span> </a> </li> </ul> <div class="hx-tab-content {{ contentCustomClass }}"> <ng-content></ng-content> </div> `, isInline: true, styles: [":host,ul.hx-nav{background-color:inherit}button.hx-nav-link{border-width:0;border-bottom-width:1px;border-color:transparent;background-color:transparent;line-height:1.5;cursor:pointer}:where(.is-justified) .is-button.hx-nav-item{display:flex}:where(.is-justified .is-button) button.hx-nav-link{display:flex}\n"], directives: [{ type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: NgTranscludeDirective, selector: "[ngTransclude]", inputs: ["ngTransclude"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: TabsetComponent, decorators: [{ type: Component, args: [{ selector: 'hx-tabset', host: { class: 'hx-tab-container', }, template: ` <ul class="hx-nav hx-nav-{{ type }}" [ngStyle]="{ position: getStickyHeaderPosition(), 'top.rem': stickyHeaderOffset }" [class.is-vertical]="vertical" [class.is-justified]="justified" [class.has-info]="hasInfo" > <li *ngFor="let tab of tabs" [ngClass]="['hx-nav-item', tab.customClass || '']" [class.is-active]="!!tab?.active" [class.is-disabled]="!!tab?.disabled" [class.is-button]="tag === 'button'" > <button *ngIf="tag === 'button'" class="hx-nav-link" [class.is-active]="!!tab?.active" [class.is-disabled]="!!tab?.disabled" [attr.disabled]="!!tab?.disabled ? '' : null" (click)="selectTab(tab)" > <span [ngTransclude]="tab.headingRef">{{ tab.heading }}</span> <span *ngIf="tab.removable"> <span (click)="removeTab(tab)" class="icon close-outline is-small" ></span> </span> </button> <a *ngIf="tag === 'link'" class="hx-nav-link" [class.is-active]="!!tab?.ac