@covalent/core
Version:
Core Teradata UI Platform for layouts, icons, custom components and themes. This should be added as a dependency for any project that wants to use layouts, icons and themes for Angular Material.
780 lines (772 loc) • 33.8 kB
JavaScript
import * as i0 from '@angular/core';
import { inject, ElementRef, ChangeDetectorRef, Component, ComponentFactoryResolver, Injector, Injectable, Optional, SkipSelf, ViewContainerRef, TemplateRef, Directive, Input, NgModule } from '@angular/core';
import { tdFadeInOutAnimation } from '@covalent/core/common';
import { CdkPortalOutlet, ComponentPortal, TemplatePortal } from '@angular/cdk/portal';
import { MatProgressBar } from '@angular/material/progress-bar';
import { MatProgressSpinner } from '@angular/material/progress-spinner';
import * as i1 from '@angular/common';
import { CommonModule } from '@angular/common';
import { Overlay, OverlayConfig } from '@angular/cdk/overlay';
import { Subject } from 'rxjs';
import { distinctUntilChanged } from 'rxjs/operators';
function TdLoadingComponent_mat_progress_spinner_2_Template(rf, ctx) { if (rf & 1) {
i0.ɵɵelement(0, "mat-progress-spinner", 5);
} if (rf & 2) {
const ctx_r0 = i0.ɵɵnextContext();
i0.ɵɵproperty("mode", ctx_r0.mode)("value", ctx_r0.value)("color", ctx_r0.color)("diameter", ctx_r0.getCircleDiameter())("strokeWidth", ctx_r0.getCircleStrokeWidth());
} }
function TdLoadingComponent_mat_progress_bar_3_Template(rf, ctx) { if (rf & 1) {
i0.ɵɵelement(0, "mat-progress-bar", 6);
} if (rf & 2) {
const ctx_r0 = i0.ɵɵnextContext();
i0.ɵɵproperty("mode", ctx_r0.mode)("value", ctx_r0.value)("color", ctx_r0.color);
} }
function TdLoadingComponent_ng_template_4_Template(rf, ctx) { }
var LoadingType;
(function (LoadingType) {
LoadingType["Circular"] = "circular";
LoadingType["Linear"] = "linear";
})(LoadingType || (LoadingType = {}));
var LoadingMode;
(function (LoadingMode) {
LoadingMode["Determinate"] = "determinate";
LoadingMode["Indeterminate"] = "indeterminate";
})(LoadingMode || (LoadingMode = {}));
var LoadingStrategy;
(function (LoadingStrategy) {
LoadingStrategy["Overlay"] = "overlay";
LoadingStrategy["Replace"] = "replace";
})(LoadingStrategy || (LoadingStrategy = {}));
var LoadingStyle;
(function (LoadingStyle) {
LoadingStyle["FullScreen"] = "fullscreen";
LoadingStyle["Overlay"] = "overlay";
LoadingStyle["None"] = "none";
})(LoadingStyle || (LoadingStyle = {}));
const TD_CIRCLE_DIAMETER = 40;
class TdLoadingComponent {
_elementRef = inject(ElementRef);
_changeDetectorRef = inject(ChangeDetectorRef);
_mode = LoadingMode.Indeterminate;
_defaultMode = LoadingMode.Indeterminate;
_value = 0;
_circleDiameter = TD_CIRCLE_DIAMETER;
/**
* Flag for animation
*/
animation = false;
/**
* Content injected into loading component.
*/
content;
/**
* Sets mode of [TdLoadingComponent] to LoadingMode.Determinate or LoadingMode.Indeterminate
*/
set mode(mode) {
this._defaultMode = mode;
}
get mode() {
return this._mode;
}
/**
* Sets value of [TdLoadingComponent] if mode is 'LoadingMode.Determinate'
*/
set value(value) {
this._value = value;
// Check for changes for `OnPush` change detection
this._changeDetectorRef.markForCheck();
}
get value() {
return this._value;
}
style = LoadingStyle.None;
/**
* height: number
* Sets height of [TdLoadingComponent].
*/
height = 100;
/**
* type: LoadingType
* Sets type of [TdLoadingComponent] rendered.
*/
type = LoadingType.Circular;
/**
* color: primary' | 'accent' | 'warn'
* Sets theme color of [TdLoadingComponent] rendered.
*/
color = 'primary';
ngDoCheck() {
// When overlay is used and the host width has a value greater than 1px
// set the circle diameter when possible incase the loading component was rendered in a hidden state
if (this.isOverlay() && this._hostHeight() > 1 && this.animation) {
this._setCircleDiameter();
this._changeDetectorRef.markForCheck();
}
}
getHeight() {
// Ignore height if style is `overlay` or `fullscreen`.
// Add height if child elements have a height and style is `none`, else return default height.
if (this.isOverlay() || this.isFullScreen()) {
return undefined;
}
else {
return this.height ? `${this.height}px` : '150px';
}
}
getCircleDiameter() {
return this._circleDiameter;
}
getCircleStrokeWidth() {
// we calculate the stroke width by setting it as 10% of its diameter
const strokeWidth = this.getCircleDiameter() / 10;
return Math.abs(strokeWidth);
}
isCircular() {
return this.type === LoadingType.Circular;
}
isLinear() {
return this.type === LoadingType.Linear;
}
isFullScreen() {
return this.style === LoadingStyle.FullScreen;
}
isOverlay() {
return this.style === LoadingStyle.Overlay;
}
/**
* Starts in animation and returns an observable for completition event.
*/
show() {
/* need to switch back to the selected mode, so we have saved it in another variable
* and then recover it. (issue with protractor)
*/
this._mode = this._defaultMode;
// Set values before the animations starts
this._setCircleDiameter();
// Check for changes for `OnPush` change detection
this.animation = true;
this._changeDetectorRef.markForCheck();
}
/**
* Starts out animation and returns an observable for completition event.
*/
hide() {
this.animation = false;
/* need to switch back and forth from determinate/indeterminate so the setInterval()
* inside mat-progress-spinner stops and protractor doesnt timeout waiting to sync.
*/
this._mode = LoadingMode.Determinate;
// Check for changes for `OnPush` change detection
/* little hack to reset the loader value and animation before removing it from DOM
* else, the loader will appear with prev value when its registered again
* and will do an animation going prev value to 0.
*/
this.value = 0;
// Check for changes for `OnPush` change detection
this._changeDetectorRef.markForCheck();
}
/**
* Calculate the proper diameter for the circle and set it
*/
_setCircleDiameter() {
// we set a default diameter of 100 since this is the default in material
let diameter = TD_CIRCLE_DIAMETER;
// if height is provided, then we take that as diameter
if (this.height) {
diameter = this.height;
// else if its not provided, then we take the host height
}
else if (this.height === undefined) {
diameter = this._hostHeight();
}
// if the diameter is over TD_CIRCLE_DIAMETER, we set TD_CIRCLE_DIAMETER
if (diameter <= TD_CIRCLE_DIAMETER) {
this._circleDiameter = Math.floor(diameter);
}
else {
this._circleDiameter = TD_CIRCLE_DIAMETER;
}
}
/**
* Returns the host height of the loading component
*/
_hostHeight() {
if (this._elementRef.nativeElement) {
return (this._elementRef.nativeElement).getBoundingClientRect().height;
}
return 0;
}
static ɵfac = function TdLoadingComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || TdLoadingComponent)(); };
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: TdLoadingComponent, selectors: [["td-loading"]], decls: 5, vars: 14, consts: [[1, "td-loading-wrapper"], [1, "td-loading"], [3, "mode", "value", "color", "diameter", "strokeWidth", 4, "ngIf"], [3, "mode", "value", "color", 4, "ngIf"], [3, "cdkPortalOutlet"], [3, "mode", "value", "color", "diameter", "strokeWidth"], [3, "mode", "value", "color"]], template: function TdLoadingComponent_Template(rf, ctx) { if (rf & 1) {
i0.ɵɵelementStart(0, "div", 0)(1, "div", 1);
i0.ɵɵtemplate(2, TdLoadingComponent_mat_progress_spinner_2_Template, 1, 5, "mat-progress-spinner", 2)(3, TdLoadingComponent_mat_progress_bar_3_Template, 1, 3, "mat-progress-bar", 3);
i0.ɵɵelementEnd();
i0.ɵɵtemplate(4, TdLoadingComponent_ng_template_4_Template, 0, 0, "ng-template", 4);
i0.ɵɵelementEnd();
} if (rf & 2) {
i0.ɵɵstyleProp("min-height", ctx.getHeight());
i0.ɵɵclassProp("td-overlay-circular", (ctx.isOverlay() || ctx.isFullScreen()) && !ctx.isLinear())("td-overlay", ctx.isOverlay() || ctx.isFullScreen())("td-fullscreen", ctx.isFullScreen());
i0.ɵɵadvance();
i0.ɵɵstyleProp("min-height", ctx.getHeight());
i0.ɵɵproperty("@tdFadeInOut", ctx.animation);
i0.ɵɵadvance();
i0.ɵɵproperty("ngIf", ctx.isCircular());
i0.ɵɵadvance();
i0.ɵɵproperty("ngIf", ctx.isLinear());
i0.ɵɵadvance();
i0.ɵɵproperty("cdkPortalOutlet", ctx.content);
} }, dependencies: [CommonModule, i1.NgIf, MatProgressBar, MatProgressSpinner, CdkPortalOutlet], styles: [".td-loading-wrapper[_ngcontent-%COMP%]{position:relative;display:block}.td-loading-wrapper.td-fullscreen[_ngcontent-%COMP%]{position:inherit}.td-loading-wrapper[_ngcontent-%COMP%] .td-loading[_ngcontent-%COMP%]{box-sizing:border-box;display:flex;flex-direction:row;align-items:center;align-content:center;max-width:100%;justify-content:center;flex:1}.td-loading-wrapper.td-overlay[_ngcontent-%COMP%] .td-loading[_ngcontent-%COMP%]{position:absolute;margin:0;top:0;left:0;right:0;z-index:1000}.td-loading-wrapper.td-overlay[_ngcontent-%COMP%] .td-loading[_ngcontent-%COMP%] mat-progress-bar[_ngcontent-%COMP%]{position:absolute;top:0;left:0;right:0}.td-loading-wrapper.td-overlay-circular[_ngcontent-%COMP%] .td-loading[_ngcontent-%COMP%]{bottom:0}"], data: { animation: [tdFadeInOutAnimation] } });
}
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(TdLoadingComponent, [{
type: Component,
args: [{ selector: 'td-loading', animations: [tdFadeInOutAnimation], imports: [CommonModule, MatProgressBar, MatProgressSpinner, CdkPortalOutlet], template: "<div\n class=\"td-loading-wrapper\"\n [style.min-height]=\"getHeight()\"\n [class.td-overlay-circular]=\"(isOverlay() || isFullScreen()) && !isLinear()\"\n [class.td-overlay]=\"isOverlay() || isFullScreen()\"\n [class.td-fullscreen]=\"isFullScreen()\"\n>\n <div\n [@tdFadeInOut]=\"animation\"\n [style.min-height]=\"getHeight()\"\n class=\"td-loading\"\n >\n <mat-progress-spinner\n *ngIf=\"isCircular()\"\n [mode]=\"mode\"\n [value]=\"value\"\n [color]=\"color\"\n [diameter]=\"getCircleDiameter()\"\n [strokeWidth]=\"getCircleStrokeWidth()\"\n ></mat-progress-spinner>\n <mat-progress-bar\n *ngIf=\"isLinear()\"\n [mode]=\"mode\"\n [value]=\"value\"\n [color]=\"color\"\n ></mat-progress-bar>\n </div>\n <ng-template [cdkPortalOutlet]=\"content\"></ng-template>\n</div>\n", styles: [".td-loading-wrapper{position:relative;display:block}.td-loading-wrapper.td-fullscreen{position:inherit}.td-loading-wrapper .td-loading{box-sizing:border-box;display:flex;flex-direction:row;align-items:center;align-content:center;max-width:100%;justify-content:center;flex:1}.td-loading-wrapper.td-overlay .td-loading{position:absolute;margin:0;top:0;left:0;right:0;z-index:1000}.td-loading-wrapper.td-overlay .td-loading mat-progress-bar{position:absolute;top:0;left:0;right:0}.td-loading-wrapper.td-overlay-circular .td-loading{bottom:0}\n"] }]
}], null, null); })();
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(TdLoadingComponent, { className: "TdLoadingComponent", filePath: "loading.component.ts", lineNumber: 44 }); })();
/**
* NOTE: @internal usage only.
*/
class TdLoadingFactory {
_componentFactoryResolver = inject(ComponentFactoryResolver);
_overlay = inject(Overlay);
_injector = inject(Injector);
/**
* Uses material `Overlay` services to create a DOM element and attach the loading component
* into it. Leveraging the state and configuration from it.
*
* Saves a reference in context to be called when registering/resolving the loading element.
*/
createFullScreenComponent(options) {
options.height = undefined;
options.style = LoadingStyle.FullScreen;
const loadingRef = this._initializeContext();
let loading = false;
let overlayRef;
loadingRef.observable
.pipe(distinctUntilChanged())
.subscribe((registered) => {
if (registered > 0 && !loading) {
loading = true;
overlayRef = this._createOverlay();
loadingRef.componentRef = overlayRef.attach(new ComponentPortal(TdLoadingComponent));
this._mapOptions(options, loadingRef.componentRef?.instance);
loadingRef.componentRef?.instance.show();
loadingRef.componentRef?.changeDetectorRef.detectChanges();
}
else if (registered <= 0 && loading) {
loading = false;
loadingRef.componentRef?.instance.hide();
loadingRef.componentRef?.destroy();
overlayRef.detach();
overlayRef.dispose();
}
});
return loadingRef;
}
/**
* Creates a loading component dynamically and attaches it into the given viewContainerRef.
* Leverages TemplatePortals from material to inject the template inside of it so it fits
* perfectly when overlaying it.
*
* Saves a reference in context to be called when registering/resolving the loading element.
*/
createOverlayComponent(options, viewContainerRef, templateRef) {
options.height = undefined;
options.style = LoadingStyle.Overlay;
const loadingRef = this._createComponent(options);
let loading = false;
if (loadingRef.componentRef) {
loadingRef.componentRef.instance.content = new TemplatePortal(templateRef, viewContainerRef);
viewContainerRef.clear();
viewContainerRef.insert(loadingRef.componentRef?.hostView, 0);
}
loadingRef.observable
.pipe(distinctUntilChanged())
.subscribe((registered) => {
if (registered > 0 && !loading) {
loading = true;
loadingRef.componentRef?.instance.show();
}
else if (registered <= 0 && loading) {
loading = false;
loadingRef.componentRef?.instance.hide();
}
});
return loadingRef;
}
/**
* Creates a loading component dynamically and attaches it into the given viewContainerRef.
* Replaces the template with the loading component depending if it was registered or resolved.
*
* Saves a reference in context to be called when registering/resolving the loading element.
*/
createReplaceComponent(options, viewContainerRef, templateRef, context) {
const nativeElement = (templateRef.elementRef.nativeElement);
options.height = nativeElement.nextElementSibling
? nativeElement.nextElementSibling.scrollHeight
: undefined;
options.style = LoadingStyle.None;
const loadingRef = this._createComponent(options);
let loading = false;
// passing context so when the template is attached, we can keep the reference of the variables
const contentRef = viewContainerRef.createEmbeddedView(templateRef, context);
loadingRef.observable
.pipe(distinctUntilChanged())
.subscribe((registered) => {
if (registered > 0 && !loading && loadingRef.componentRef) {
loading = true;
// detach the content and attach the loader if loader is there
const index = viewContainerRef.indexOf(loadingRef.componentRef.hostView);
if (index < 0) {
viewContainerRef.detach(viewContainerRef.indexOf(contentRef));
viewContainerRef.insert(loadingRef.componentRef.hostView, 0);
}
loadingRef.componentRef?.instance.show();
}
else if (registered <= 0 && loading && loadingRef.componentRef) {
loading = false;
loadingRef.componentRef?.instance.hide();
// detach loader and attach the content if content is there
const index = viewContainerRef.indexOf(contentRef);
if (index < 0) {
viewContainerRef.detach(viewContainerRef.indexOf(loadingRef.componentRef.hostView));
viewContainerRef.insert(contentRef, 0);
}
/**
* Need to call "markForCheck" and "detectChanges" on attached template, so its detected by parent component when attached
* with "OnPush" change detection
*/
contentRef.detectChanges();
contentRef.markForCheck();
}
});
return loadingRef;
}
/**
* Creates a fullscreen overlay for the loading usage.
*/
_createOverlay() {
const state = new OverlayConfig();
state.hasBackdrop = false;
state.positionStrategy = this._overlay
.position()
.global()
.centerHorizontally()
.centerVertically();
return this._overlay.create(state);
}
/**
* Creates a generic component dynamically waiting to be attached to a viewContainerRef.
*/
_createComponent(options) {
const compRef = this._initializeContext();
compRef.componentRef = this._componentFactoryResolver
.resolveComponentFactory(TdLoadingComponent)
.create(this._injector);
this._mapOptions(options, compRef.componentRef.instance);
return compRef;
}
/**
* Initialize context for loading component.
*/
_initializeContext() {
const subject = new Subject();
return {
observable: subject.asObservable(),
subject,
componentRef: undefined,
times: 0,
};
}
/**
* Maps configuration to the loading component instance.
*/
_mapOptions(options, instance) {
if (options.style) {
instance.style = options.style;
}
if (options.type !== undefined) {
instance.type = options.type;
}
if (options.height !== undefined) {
instance.height = options.height;
}
if (options.mode !== undefined) {
instance.mode = options.mode;
}
if (options.color !== undefined) {
instance.color = options.color;
}
}
static ɵfac = function TdLoadingFactory_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || TdLoadingFactory)(); };
static ɵprov = /*@__PURE__*/ i0.ɵɵdefineInjectable({ token: TdLoadingFactory, factory: TdLoadingFactory.ɵfac });
}
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(TdLoadingFactory, [{
type: Injectable
}], null, null); })();
function LOADING_FACTORY_PROVIDER_FACTORY(parent) {
return parent || new TdLoadingFactory();
}
const LOADING_FACTORY_PROVIDER = {
// If there is already a service available, use that. Otherwise, provide a new one.
provide: TdLoadingFactory,
deps: [
[new Optional(), new SkipSelf(), TdLoadingFactory],
ComponentFactoryResolver,
Overlay,
Injector,
],
useFactory: LOADING_FACTORY_PROVIDER_FACTORY,
};
class TdLoadingConfig {
name;
type;
mode;
color;
constructor(config) {
this.name = config.name;
if (!this.name) {
throw Error('Name is required for [TdLoading] configuration.');
}
this.mode = config.mode ? config.mode : LoadingMode.Indeterminate;
this.type = config.type ? config.type : LoadingType.Circular;
this.color = config.color ? config.color : 'primary';
}
}
class TdLoadingDirectiveConfig extends TdLoadingConfig {
strategy;
constructor(config) {
super(config);
this.strategy = config.strategy ? config.strategy : LoadingStrategy.Replace;
}
}
class TdLoadingService {
_loadingFactory = inject(TdLoadingFactory);
_context = {};
_timeouts = {};
constructor() {
this.create({
name: 'td-loading-main',
});
}
/**
* params:
* - config: ILoadingDirectiveConfig
* - viewContainerRef: ViewContainerRef
* - templateRef: TemplateRef<Object>
*
* Creates an replace loading mask and attaches it to the viewContainerRef.
* Replaces the templateRef with the mask when a request is registered on it.
*
* NOTE: @internal usage only.
*/
createComponent(config, viewContainerRef, templateRef, context) {
const directiveConfig = new TdLoadingDirectiveConfig(config);
if (this._context[directiveConfig.name]) {
throw Error(`Name duplication: [TdLoading] directive has a name conflict with ${directiveConfig.name}.`);
}
if (directiveConfig.strategy === LoadingStrategy.Overlay) {
this._context[directiveConfig.name] =
this._loadingFactory.createOverlayComponent(directiveConfig, viewContainerRef, templateRef);
}
else {
this._context[directiveConfig.name] =
this._loadingFactory.createReplaceComponent(directiveConfig, viewContainerRef, templateRef, context);
}
return this._context[directiveConfig.name];
}
/**
* params:
* - config: ITdLoadingConfig
*
* Creates a fullscreen loading mask and attaches it to the DOM with the given configuration.
* Only displayed when the mask has a request registered on it.
*/
create(config) {
const fullscreenConfig = new TdLoadingConfig(config);
this.removeComponent(fullscreenConfig.name);
this._context[fullscreenConfig.name] =
this._loadingFactory.createFullScreenComponent(fullscreenConfig);
}
/**
* params:
* - name: string
*
* Removes `loading` component from service context.
*/
removeComponent(name) {
if (this._context[name]) {
this._context[name].subject.unsubscribe();
if (this._context[name].componentRef) {
this._context[name].componentRef?.destroy();
}
delete this._context[name];
}
}
/**
* params:
* - name: string
* - registers?: number
* returns: true if successful
*
* Resolves a request for the loading mask referenced by the name parameter.
* Can optionally pass registers argument to set a number of register calls.
*
* If no paramemeters are used, then default main mask will be used.
*
* e.g. loadingService.register()
*/
register(name = 'td-loading-main', registers = 1) {
// try registering into the service if the loading component has been instanciated or if it exists.
if (this._context[name]) {
registers = registers < 1 ? 1 : registers;
this._context[name].times += registers;
this._context[name].subject.next(this._context[name].times);
return true;
}
else {
// if it doesnt exist, set a timeout so its registered after change detection happens
// this in case "register" occured on the `ngOnInit` lifehook cycle.
if (!this._timeouts[name]) {
this._timeouts[name] = setTimeout(() => {
this.register(name, registers);
});
}
else {
// if it timeout occured and still doesnt exist, it means the tiemout wasnt needed so we clear it.
this._clearTimeout(name);
}
}
return false;
}
/**
* params:
* - name: string
* - resolves?: number
* returns: true if successful
*
* Resolves a request for the loading mask referenced by the name parameter.
* Can optionally pass resolves argument to set a number of resolve calls.
*
* If no paramemeters are used, then default main mask will be used.
*
* e.g. loadingService.resolve()
*/
resolve(name = 'td-loading-main', resolves = 1) {
// clear timeout if the loading component is "resolved" before its "registered"
this._clearTimeout(name);
if (this._context[name]) {
resolves = resolves < 1 ? 1 : resolves;
if (this._context[name].times) {
let times = this._context[name].times;
times -= resolves;
this._context[name].times = times < 0 ? 0 : times;
}
this._context[name].subject?.next(this._context[name].times);
return true;
}
return false;
}
/**
* params:
* - name: string
* returns: true if successful
*
* Resolves all request for the loading mask referenced by the name parameter.
*
* If no paramemeters are used, then default main mask will be used.
*
* e.g. loadingService.resolveAll()
*/
resolveAll(name = 'td-loading-main') {
// clear timeout if the loading component is "resolved" before its "registered"
this._clearTimeout(name);
if (this._context[name]) {
this._context[name].times = 0;
this._context[name].subject?.next(this._context[name].times);
return true;
}
return false;
}
/**
* params:
* - name: string
* - value: number
* returns: true if successful
*
* Set value on a loading mask referenced by the name parameter.
* Usage only available if its mode is 'determinate' and if loading is showing.
*/
setValue(name, value) {
if (this._context[name]) {
const instance = this._context[name].componentRef?.instance;
if (instance.mode === LoadingMode.Determinate && instance.animation) {
instance.value = value;
return true;
}
}
return false;
}
/**
* Clears timeout linked to the name.
* @param name Name of the loading component to be cleared
*/
_clearTimeout(name) {
clearTimeout(this._timeouts[name]);
delete this._timeouts[name];
}
static ɵfac = function TdLoadingService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || TdLoadingService)(); };
static ɵprov = /*@__PURE__*/ i0.ɵɵdefineInjectable({ token: TdLoadingService, factory: TdLoadingService.ɵfac });
}
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(TdLoadingService, [{
type: Injectable
}], () => [], null); })();
function LOADING_PROVIDER_FACTORY(parent) {
return parent || new TdLoadingService();
}
const LOADING_PROVIDER = {
// If there is already a service available, use that. Otherwise, provide a new one.
provide: TdLoadingService,
deps: [[new Optional(), new SkipSelf(), TdLoadingService], TdLoadingFactory],
useFactory: LOADING_PROVIDER_FACTORY,
};
/**
* Context class for variable reference
*/
class TdLoadingContext {
$implicit = undefined;
tdLoading = undefined;
}
// Constant for generation of the id for the next component
let TD_LOADING_NEXT_ID = 0;
class TdLoadingDirective {
_viewContainerRef = inject(ViewContainerRef);
_templateRef = inject(TemplateRef);
_loadingService = inject(TdLoadingService);
_context = new TdLoadingContext();
_loadingRef;
/**
* tdLoading: string
* Name reference of the loading mask, used to register/resolve requests to the mask.
*/
name;
/**
* tdLoadingUntil?: any
* If its null, undefined or false it will be used to register requests to the mask.
* Else if its any value that can be resolved as true, it will resolve the mask.
* [name] is optional when using [until], but can still be used to register/resolve it manually.
*/
set until(until) {
if (!this.name) {
this.name = 'td-loading-until-' + TD_LOADING_NEXT_ID++;
}
this._context.$implicit = this._context.tdLoading = until;
if (!until) {
this._loadingService.register(this.name);
}
else {
this._loadingService.resolveAll(this.name);
}
}
/**
* tdLoadingType?: LoadingType or ['linear' | 'circular']
* Sets the type of loading mask depending on value.
* Defaults to [LoadingType.Circular | 'circular'].
*/
type = LoadingType.Circular;
/**
* tdLoadingMode?: LoadingMode or ['determinate' | 'indeterminate']
* Sets the mode of loading mask depending on value.
* Defaults to [LoadingMode.Indeterminate | 'indeterminate'].
*/
mode = LoadingMode.Indeterminate;
/**
* tdLoadingStrategy?: LoadingStrategy or ['replace' | 'overlay']
* Sets the strategy of loading mask depending on value.
* Defaults to [LoadingMode.Replace | 'replace'].
*/
strategy = LoadingStrategy.Replace;
/**
* tdLoadingColor?: "primary" | "accent" | "warn"
* Sets the theme color of the loading component. Defaults to "primary"
*/
color = 'primary';
/**
* Registers component in the DOM, so it will be available when calling resolve/register.
*/
ngOnInit() {
this._registerComponent();
}
/**
* Remove component when directive is destroyed.
*/
ngOnDestroy() {
this._loadingService.removeComponent(this.name);
this._loadingRef = undefined;
}
/**
* Creates [TdLoadingComponent] and attaches it to this directive's [ViewContainerRef].
* Passes this directive's [TemplateRef] to modify DOM depending on loading `strategy`.
*/
_registerComponent() {
if (!this.name) {
throw new Error('Name is needed to register loading directive');
}
// Check if `TdLoadingComponent` has been created before trying to add one again.
// There is a weird edge case when using `[routerLinkActive]` that calls the `ngOnInit` twice in a row
if (!this._loadingRef) {
this._loadingRef = this._loadingService.createComponent({
name: this.name,
type: this.type,
mode: this.mode,
color: this.color,
strategy: this.strategy,
}, this._viewContainerRef, this._templateRef, this._context);
}
}
static ɵfac = function TdLoadingDirective_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || TdLoadingDirective)(); };
static ɵdir = /*@__PURE__*/ i0.ɵɵdefineDirective({ type: TdLoadingDirective, selectors: [["", "tdLoading", ""]], inputs: { name: [0, "tdLoading", "name"], until: [0, "tdLoadingUntil", "until"], type: [0, "tdLoadingType", "type"], mode: [0, "tdLoadingMode", "mode"], strategy: [0, "tdLoadingStrategy", "strategy"], color: [0, "tdLoadingColor", "color"] } });
}
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(TdLoadingDirective, [{
type: Directive,
args: [{
selector: '[tdLoading]',
}]
}], null, { name: [{
type: Input,
args: ['tdLoading']
}], until: [{
type: Input,
args: ['tdLoadingUntil']
}], type: [{
type: Input,
args: ['tdLoadingType']
}], mode: [{
type: Input,
args: ['tdLoadingMode']
}], strategy: [{
type: Input,
args: ['tdLoadingStrategy']
}], color: [{
type: Input,
args: ['tdLoadingColor']
}] }); })();
const TD_LOADING = [TdLoadingComponent, TdLoadingDirective];
class CovalentLoadingModule {
static ɵfac = function CovalentLoadingModule_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || CovalentLoadingModule)(); };
static ɵmod = /*@__PURE__*/ i0.ɵɵdefineNgModule({ type: CovalentLoadingModule });
static ɵinj = /*@__PURE__*/ i0.ɵɵdefineInjector({ providers: [LOADING_FACTORY_PROVIDER, LOADING_PROVIDER], imports: [TdLoadingComponent] });
}
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(CovalentLoadingModule, [{
type: NgModule,
args: [{
imports: [TD_LOADING],
exports: [TD_LOADING],
providers: [LOADING_FACTORY_PROVIDER, LOADING_PROVIDER],
}]
}], null, null); })();
(function () { (typeof ngJitMode === "undefined" || ngJitMode) && i0.ɵɵsetNgModuleScope(CovalentLoadingModule, { imports: [TdLoadingComponent, TdLoadingDirective], exports: [TdLoadingComponent, TdLoadingDirective] }); })();
/**
* Generated bundle index. Do not edit.
*/
export { CovalentLoadingModule, LOADING_FACTORY_PROVIDER, LOADING_FACTORY_PROVIDER_FACTORY, LOADING_PROVIDER, LOADING_PROVIDER_FACTORY, LoadingMode, LoadingStrategy, LoadingStyle, LoadingType, TD_CIRCLE_DIAMETER, TdLoadingComponent, TdLoadingConfig, TdLoadingContext, TdLoadingDirective, TdLoadingDirectiveConfig, TdLoadingFactory, TdLoadingService };
//# sourceMappingURL=covalent-core-loading.mjs.map