@hxui/angular
Version:
An Angular library based on the [HXUI design system](https://hxui.io).
1,088 lines (1,066 loc) • 516 kB
JavaScript
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