mirror of https://github.com/ghostfolio/ghostfolio
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
197 lines
20 KiB
197 lines
20 KiB
import * as i0 from '@angular/core';
|
|
import { InjectionToken, inject, input, numberAttribute, computed, isDevMode, ChangeDetectionStrategy, Component, NgModule, makeEnvironmentProviders } from '@angular/core';
|
|
|
|
const NGX_SKELETON_LOADER_CONFIG = new InjectionToken('ngx-skeleton-loader.config');
|
|
|
|
/**
|
|
* The `NgxSkeletonLoaderComponent` is a standalone Angular component that provides a skeleton
|
|
* loader UI element.
|
|
* It can be used to display a loading state before the actual content is available.
|
|
* The component can be configured with various options such as the number of elements, appearance,
|
|
* animation, and theme.
|
|
*/
|
|
class NgxSkeletonLoaderComponent {
|
|
constructor() {
|
|
/**
|
|
* Injects the `NgxSkeletonLoaderConfig` configuration object, which is optional.
|
|
* This configuration object provides various options for customizing the behavior
|
|
* and appearance of the `NgxSkeletonLoaderComponent`.
|
|
*/
|
|
this.#config = inject(NGX_SKELETON_LOADER_CONFIG, { optional: true });
|
|
/**
|
|
* The `count` property is an input that determines the number of skeleton loader elements
|
|
* to display.
|
|
* It is initialized with the value from the `NgxSkeletonLoaderConfig` object, or 1 if the config
|
|
* is not provided.
|
|
* The `transform: numberAttribute` option ensures that the input value is converted to a number.
|
|
*/
|
|
this.count = input(this.#config?.count || 1, { ...(ngDevMode ? { debugName: "count" } : {}), transform: numberAttribute });
|
|
/**
|
|
* The `loadingText` property is an input that determines the text to display while the content
|
|
* is loading.
|
|
* It is initialized with the value from the `NgxSkeletonLoaderConfig` object, or 'Loading...'
|
|
* if the config is not provided.
|
|
*/
|
|
this.loadingText = input(this.#config?.loadingText || 'Loading...', { ...(ngDevMode ? { debugName: "loadingText" } : {}) });
|
|
/**
|
|
* The `appearance` property is an input that determines the visual appearance of the skeleton
|
|
* loader.
|
|
* It is initialized with the value from the `NgxSkeletonLoaderConfig` object, or 'line' if the
|
|
* config is not provided.
|
|
* The available appearance options are defined in the `NgxSkeletonLoaderConfig['appearance']`
|
|
* type.
|
|
*/
|
|
this.appearance = input(this.#config?.appearance || 'line', { ...(ngDevMode ? { debugName: "appearance" } : {}) });
|
|
/**
|
|
* The `animation` property is an input that determines the type of animation to apply to the
|
|
* skeleton loader.
|
|
* It is initialized with the value from the `NgxSkeletonLoaderConfig` object, or 'progress' if
|
|
* the config is not provided.
|
|
* The available animation options are defined in the `NgxSkeletonLoaderConfig['animation']` type.
|
|
*/
|
|
this.animation = input(this.#config?.animation || 'progress', { ...(ngDevMode ? { debugName: "animation" } : {}) });
|
|
/**
|
|
* The `ariaLabel` property is an input that determines the ARIA label to be used for the skeleton
|
|
* loader element. This is useful for providing accessibility information to screen readers.
|
|
* It is initialized with the value from the `NgxSkeletonLoaderConfig` object, or 'loading' if the
|
|
* config is not provided.
|
|
*/
|
|
this.ariaLabel = input(this.#config?.ariaLabel || 'loading', { ...(ngDevMode ? { debugName: "ariaLabel" } : {}) });
|
|
/**
|
|
* The `theme` property is an input that determines the theme configuration for the skeleton
|
|
* loader.
|
|
* It is initialized with the value from the `NgxSkeletonLoaderConfig` object, or `null` if the
|
|
* config is not provided.
|
|
* The theme configuration is defined by the `NgxSkeletonLoaderConfigTheme` type, which allows
|
|
* customizing various aspects of the skeleton loader's appearance, such as colors, animation,
|
|
* etc.
|
|
*/
|
|
this.theme = input(this.#config?.theme || null, { ...(ngDevMode ? { debugName: "theme" } : {}) });
|
|
/**
|
|
* The `size` property is an input that determines the size of the skeleton loader.
|
|
* It is initialized with the value from the `NgxSkeletonLoaderConfig` object, or `null` if the
|
|
* config is not provided.
|
|
* The size can be specified as a number (in pixels) (e.g., '50', '200').
|
|
*/
|
|
this.size = input(this.#config?.size || null, { ...(ngDevMode ? { debugName: "size" } : {}) });
|
|
/**
|
|
* The `measureUnit` property is an input that determines the unit of measurement for the size
|
|
* of the skeleton loader.
|
|
* It is initialized with the value from the `NgxSkeletonLoaderConfig` object, or 'px' if the
|
|
* config is not provided.
|
|
* This allows the size to be specified in different units, such as 'px', 'em', etc.
|
|
*/
|
|
this.measureUnit = input(this.#config?.measureUnit || 'px', { ...(ngDevMode ? { debugName: "measureUnit" } : {}) });
|
|
/**
|
|
* The `items` property is a computed property that generates an array of indices based on the
|
|
* `count` input.
|
|
* If the `appearance` is set to 'custom-content', the `count` is forced to 1 to ensure that the
|
|
* skeleton loader is displayed as a single DOM node, as required by the 'custom-content'
|
|
* appearance.
|
|
* This computed property is used to render the appropriate number of skeleton loader elements.
|
|
*/
|
|
this.items = computed(() => {
|
|
let count = this.count() || 1;
|
|
// Force count to 1 when custom-content is used
|
|
if (this.appearance() === 'custom-content') {
|
|
// Shows error message only in Development
|
|
if (isDevMode() && count !== 1) {
|
|
// eslint-disable-next-line no-console
|
|
console.error(`\`NgxSkeletonLoaderComponent\` enforces elements with "custom-content" appearance as DOM nodes. Forcing "count" to "1".`);
|
|
count = 1;
|
|
}
|
|
}
|
|
return [...Array(count)].map((_, index) => index);
|
|
}, { ...(ngDevMode ? { debugName: "items" } : {}) });
|
|
/**
|
|
* The `squareSize` property is a computed property that calculates the size of the skeleton
|
|
* loader when the appearance is set to 'square'.
|
|
* It checks the `size` input and ensures that it is a valid number or string representing a
|
|
* valid pixel value. If the `size` is not a valid number or string, it returns `null`.
|
|
* If the `appearance` is not 'square', it also returns `null`.
|
|
* This computed property is used to set the width and height of the skeleton loader when it
|
|
* is displayed as a square.
|
|
*/
|
|
this.squareSize = computed(() => {
|
|
const size = this.size();
|
|
if (this.appearance() !== 'square' || (typeof size !== 'number' && typeof size !== 'string')) {
|
|
return null;
|
|
}
|
|
const sizeValueInNumbersOnly = Number(size.toString().trim().replace(/\D/g, ''));
|
|
if (!Number.isInteger(sizeValueInNumbersOnly)) {
|
|
return null;
|
|
}
|
|
return `${sizeValueInNumbersOnly}${this.measureUnit()}`;
|
|
}, { ...(ngDevMode ? { debugName: "squareSize" } : {}) });
|
|
/**
|
|
* A computed property that returns the final theme configuration for the skeleton loader.
|
|
* If the `extendsFromRoot` property is set in the `NgxSkeletonLoaderConfig`, the theme is merged
|
|
* with the root theme configuration. Otherwise, the theme is returned as-is.
|
|
* This allows the skeleton loader to inherit global theme settings while still allowing for
|
|
* component-specific theme customization.
|
|
*/
|
|
this.styles = computed(() => {
|
|
const theme = this.theme();
|
|
const size = this.squareSize();
|
|
if (this.#config?.theme?.extendsFromRoot) {
|
|
return {
|
|
...this.#config?.theme,
|
|
...theme,
|
|
...(size && { width: size, height: size }),
|
|
};
|
|
}
|
|
return {
|
|
...theme,
|
|
...(size && { width: size, height: size }),
|
|
};
|
|
}, { ...(ngDevMode ? { debugName: "styles" } : {}) });
|
|
}
|
|
/**
|
|
* Injects the `NgxSkeletonLoaderConfig` configuration object, which is optional.
|
|
* This configuration object provides various options for customizing the behavior
|
|
* and appearance of the `NgxSkeletonLoaderComponent`.
|
|
*/
|
|
#config;
|
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: NgxSkeletonLoaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.1", type: NgxSkeletonLoaderComponent, isStandalone: true, selector: "ngx-skeleton-loader", inputs: { count: { classPropertyName: "count", publicName: "count", isSignal: true, isRequired: false, transformFunction: null }, loadingText: { classPropertyName: "loadingText", publicName: "loadingText", isSignal: true, isRequired: false, transformFunction: null }, appearance: { classPropertyName: "appearance", publicName: "appearance", isSignal: true, isRequired: false, transformFunction: null }, animation: { classPropertyName: "animation", publicName: "animation", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, theme: { classPropertyName: "theme", publicName: "theme", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, measureUnit: { classPropertyName: "measureUnit", publicName: "measureUnit", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@let appearanceValue = appearance();\n@let animationValue = animation();\n@for (item of items(); track item) {\n <div\n class=\"skeleton-loader\"\n [attr.aria-label]=\"ariaLabel()\"\n aria-busy=\"true\"\n aria-valuemin=\"0\"\n aria-valuemax=\"100\"\n [attr.aria-valuetext]=\"loadingText()\"\n role=\"progressbar\"\n tabindex=\"-1\"\n [class.custom-content]=\"appearanceValue === 'custom-content'\"\n [class.circle]=\"appearanceValue === 'circle'\"\n [class.square]=\"appearanceValue === 'square'\"\n [class.progress]=\"animationValue === 'progress'\"\n [class.progress-dark]=\"animationValue === 'progress-dark'\"\n [class.pulse]=\"animationValue === 'pulse'\"\n [class.pulse-dark]=\"animationValue === 'pulse-dark'\"\n [style]=\"styles()\"\n >\n @if (appearanceValue === 'custom-content') {\n <ng-content></ng-content>\n }\n </div>\n}\n", styles: [".skeleton-loader{--ngx-skeleton-loader-base-color: rgb(239, 241, 246);--ngx-skeleton-loader-light-mode-color: rgba(255, 255, 255, .6);--ngx-skeleton-loader-light-mode-color-to: rgba(255, 255, 255, 0);--ngx-skeleton-loader-dark-mode-color: rgba(0, 0, 0, .2);--ngx-skeleton-loader-dark-mode-color-to: transparent;--ngx-skeleton-loader-animation-duration: 2s;--ngx-skeleton-loader-background-image-light-mode: linear-gradient( 90deg, var(--ngx-skeleton-loader-light-mode-color-to), var(--ngx-skeleton-loader-light-mode-color), var(--ngx-skeleton-loader-light-mode-color-to) );--ngx-skeleton-loader-background-image-dark-mode: linear-gradient( 90deg, var(--ngx-skeleton-loader-dark-mode-color-to), var(--ngx-skeleton-loader-dark-mode-color), var(--ngx-skeleton-loader-dark-mode-color-to) );box-sizing:border-box;overflow:hidden;position:relative;background:var(--ngx-skeleton-loader-base-color) no-repeat;border-radius:4px;width:100%;height:20px;display:inline-block;margin-bottom:10px;will-change:transform}.skeleton-loader:after,.skeleton-loader:before{box-sizing:border-box}.skeleton-loader.circle{width:40px;height:40px;margin:5px;border-radius:50%}.skeleton-loader.square{width:40px;height:40px;margin:5px}.skeleton-loader.progress:after,.skeleton-loader.progress:before,.skeleton-loader.progress-dark:after,.skeleton-loader.progress-dark:before{box-sizing:border-box}.skeleton-loader.progress,.skeleton-loader.progress-dark{transform:translateZ(0)}.skeleton-loader.progress:before,.skeleton-loader.progress-dark:before{animation:progress var(--ngx-skeleton-loader-animation-duration) ease-in-out infinite;background-size:200px 100%;position:absolute;z-index:1;top:0;left:0;width:200px;height:100%;content:\"\"}.skeleton-loader.progress:before{background-image:var(--ngx-skeleton-loader-background-image-light-mode)}.skeleton-loader.progress-dark:before{background-image:var(--ngx-skeleton-loader-background-image-dark-mode)}.skeleton-loader.pulse{animation:pulse var(--ngx-skeleton-loader-animation-duration) cubic-bezier(.4,0,.2,1) infinite;animation-delay:.5s}.skeleton-loader.pulse-dark{background:var(--ngx-skeleton-loader-dark-mode-color);animation:pulse var(--ngx-skeleton-loader-animation-duration) cubic-bezier(.4,0,.2,1) infinite;animation-delay:.5s}.skeleton-loader.custom-content{height:100%;background:none}@media(prefers-reduced-motion:reduce){.skeleton-loader.pulse,.skeleton-loader.progress-dark,.skeleton-loader.pulse-dark,.skeleton-loader.custom-content,.skeleton-loader.progress:before{animation:none}.skeleton-loader.progress:before,.skeleton-loader.progress-dark,.skeleton-loader.pulse-dark,.skeleton-loader.custom-content{background-image:none}}@media screen and (min-device-width:1200px){.skeleton-loader{-webkit-user-select:none;user-select:none;cursor:wait}}@keyframes progress{0%{transform:translate3d(-200px,0,0)}to{transform:translate3d(calc(200px + 100vw),0,0)}}@keyframes pulse{0%{opacity:1}50%{opacity:.4}to{opacity:1}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
}
|
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: NgxSkeletonLoaderComponent, decorators: [{
|
|
type: Component,
|
|
args: [{ selector: 'ngx-skeleton-loader', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, template: "@let appearanceValue = appearance();\n@let animationValue = animation();\n@for (item of items(); track item) {\n <div\n class=\"skeleton-loader\"\n [attr.aria-label]=\"ariaLabel()\"\n aria-busy=\"true\"\n aria-valuemin=\"0\"\n aria-valuemax=\"100\"\n [attr.aria-valuetext]=\"loadingText()\"\n role=\"progressbar\"\n tabindex=\"-1\"\n [class.custom-content]=\"appearanceValue === 'custom-content'\"\n [class.circle]=\"appearanceValue === 'circle'\"\n [class.square]=\"appearanceValue === 'square'\"\n [class.progress]=\"animationValue === 'progress'\"\n [class.progress-dark]=\"animationValue === 'progress-dark'\"\n [class.pulse]=\"animationValue === 'pulse'\"\n [class.pulse-dark]=\"animationValue === 'pulse-dark'\"\n [style]=\"styles()\"\n >\n @if (appearanceValue === 'custom-content') {\n <ng-content></ng-content>\n }\n </div>\n}\n", styles: [".skeleton-loader{--ngx-skeleton-loader-base-color: rgb(239, 241, 246);--ngx-skeleton-loader-light-mode-color: rgba(255, 255, 255, .6);--ngx-skeleton-loader-light-mode-color-to: rgba(255, 255, 255, 0);--ngx-skeleton-loader-dark-mode-color: rgba(0, 0, 0, .2);--ngx-skeleton-loader-dark-mode-color-to: transparent;--ngx-skeleton-loader-animation-duration: 2s;--ngx-skeleton-loader-background-image-light-mode: linear-gradient( 90deg, var(--ngx-skeleton-loader-light-mode-color-to), var(--ngx-skeleton-loader-light-mode-color), var(--ngx-skeleton-loader-light-mode-color-to) );--ngx-skeleton-loader-background-image-dark-mode: linear-gradient( 90deg, var(--ngx-skeleton-loader-dark-mode-color-to), var(--ngx-skeleton-loader-dark-mode-color), var(--ngx-skeleton-loader-dark-mode-color-to) );box-sizing:border-box;overflow:hidden;position:relative;background:var(--ngx-skeleton-loader-base-color) no-repeat;border-radius:4px;width:100%;height:20px;display:inline-block;margin-bottom:10px;will-change:transform}.skeleton-loader:after,.skeleton-loader:before{box-sizing:border-box}.skeleton-loader.circle{width:40px;height:40px;margin:5px;border-radius:50%}.skeleton-loader.square{width:40px;height:40px;margin:5px}.skeleton-loader.progress:after,.skeleton-loader.progress:before,.skeleton-loader.progress-dark:after,.skeleton-loader.progress-dark:before{box-sizing:border-box}.skeleton-loader.progress,.skeleton-loader.progress-dark{transform:translateZ(0)}.skeleton-loader.progress:before,.skeleton-loader.progress-dark:before{animation:progress var(--ngx-skeleton-loader-animation-duration) ease-in-out infinite;background-size:200px 100%;position:absolute;z-index:1;top:0;left:0;width:200px;height:100%;content:\"\"}.skeleton-loader.progress:before{background-image:var(--ngx-skeleton-loader-background-image-light-mode)}.skeleton-loader.progress-dark:before{background-image:var(--ngx-skeleton-loader-background-image-dark-mode)}.skeleton-loader.pulse{animation:pulse var(--ngx-skeleton-loader-animation-duration) cubic-bezier(.4,0,.2,1) infinite;animation-delay:.5s}.skeleton-loader.pulse-dark{background:var(--ngx-skeleton-loader-dark-mode-color);animation:pulse var(--ngx-skeleton-loader-animation-duration) cubic-bezier(.4,0,.2,1) infinite;animation-delay:.5s}.skeleton-loader.custom-content{height:100%;background:none}@media(prefers-reduced-motion:reduce){.skeleton-loader.pulse,.skeleton-loader.progress-dark,.skeleton-loader.pulse-dark,.skeleton-loader.custom-content,.skeleton-loader.progress:before{animation:none}.skeleton-loader.progress:before,.skeleton-loader.progress-dark,.skeleton-loader.pulse-dark,.skeleton-loader.custom-content{background-image:none}}@media screen and (min-device-width:1200px){.skeleton-loader{-webkit-user-select:none;user-select:none;cursor:wait}}@keyframes progress{0%{transform:translate3d(-200px,0,0)}to{transform:translate3d(calc(200px + 100vw),0,0)}}@keyframes pulse{0%{opacity:1}50%{opacity:.4}to{opacity:1}}\n"] }]
|
|
}], propDecorators: { count: [{ type: i0.Input, args: [{ isSignal: true, alias: "count", required: false }] }], loadingText: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadingText", required: false }] }], appearance: [{ type: i0.Input, args: [{ isSignal: true, alias: "appearance", required: false }] }], animation: [{ type: i0.Input, args: [{ isSignal: true, alias: "animation", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], theme: [{ type: i0.Input, args: [{ isSignal: true, alias: "theme", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], measureUnit: [{ type: i0.Input, args: [{ isSignal: true, alias: "measureUnit", required: false }] }] } });
|
|
|
|
class NgxSkeletonLoaderModule {
|
|
static forRoot(config) {
|
|
return {
|
|
ngModule: NgxSkeletonLoaderModule,
|
|
providers: [{ provide: NGX_SKELETON_LOADER_CONFIG, useValue: config }],
|
|
};
|
|
}
|
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: NgxSkeletonLoaderModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.0.1", ngImport: i0, type: NgxSkeletonLoaderModule, imports: [NgxSkeletonLoaderComponent], exports: [NgxSkeletonLoaderComponent] }); }
|
|
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: NgxSkeletonLoaderModule }); }
|
|
}
|
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: NgxSkeletonLoaderModule, decorators: [{
|
|
type: NgModule,
|
|
args: [{
|
|
imports: [NgxSkeletonLoaderComponent],
|
|
exports: [NgxSkeletonLoaderComponent],
|
|
}]
|
|
}] });
|
|
|
|
function provideNgxSkeletonLoader(config) {
|
|
return makeEnvironmentProviders([
|
|
{ provide: NGX_SKELETON_LOADER_CONFIG, useValue: config },
|
|
]);
|
|
}
|
|
|
|
/*
|
|
* Public API Surface of ngx-skeleton-loader
|
|
*/
|
|
|
|
/**
|
|
* Generated bundle index. Do not edit.
|
|
*/
|
|
|
|
export { NGX_SKELETON_LOADER_CONFIG, NgxSkeletonLoaderComponent, NgxSkeletonLoaderModule, provideNgxSkeletonLoader };
|
|
//# sourceMappingURL=ngx-skeleton-loader.mjs.map
|
|
|