From 480f4cdaea0d251678f6cb9463d746d7628ce8ca Mon Sep 17 00:00:00 2001 From: hunteroi Date: Tue, 1 Jun 2021 21:11:17 +0200 Subject: [PATCH 01/13] feat: adding config element to forRoot --- .gitignore | 2 +- README.md | 8 +++-- ...ngx-skeleton-loader-config.service.spec.ts | 16 ++++++++++ .../lib/ngx-skeleton-loader-config.service.ts | 15 +++++++++ .../lib/ngx-skeleton-loader-config.types.ts | 25 +++++++++++++++ .../lib/ngx-skeleton-loader.component.spec.ts | 2 +- .../src/lib/ngx-skeleton-loader.component.ts | 31 ++++++++++++------- .../src/lib/ngx-skeleton-loader.module.ts | 8 +++-- .../src/lib/ngx-skeleton-loader.scss | 9 ++---- .../ngx-skeleton-loader/src/public-api.ts | 1 + 10 files changed, 92 insertions(+), 25 deletions(-) create mode 100644 projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader-config.service.spec.ts create mode 100644 projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader-config.service.ts create mode 100644 projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader-config.types.ts diff --git a/.gitignore b/.gitignore index f4f46a5..02d9f09 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,7 @@ /bazel-out # dependencies -/node_modules +**/node_modules # profiling files chrome-profiler-events.json diff --git a/README.md b/README.md index 987ac3f..2d1f9f3 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,8 @@ After that, you can use the `ngx-skeleton-loader` components in your templates, Also, you can import the module in your app by calling `NgxSkeletonLoaderModule.forRoot()` when adding it. So it will be available across your Angular application. +Importing the module this way also allows you to globally configure the default values for the `ngx-skeleton-loader` components in your application. + ```typescript ... import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; @@ -98,7 +100,7 @@ import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; ], imports: [ ... - NgxSkeletonLoaderModule.forRoot(), + NgxSkeletonLoaderModule.forRoot({ animation: 'pulse', loadingText: 'This item is actually loading...' }), ... ], providers: [], @@ -112,6 +114,7 @@ export class YourAppComponent {} ```html
+
``` @@ -125,7 +128,8 @@ You can also define which appearance want to use in your skeleton loader by pass ### Options -- `''` - _default_: it will use it `''` as appearance. At the end, it will render like a line, but line is not a expected appearance to be passed; +- `''` - _default_: it will use it `''` as appearance. At the end, it will render like a line; +- `'line'`: it will render like a line. This is the same behavior than passing an empty string; - `circle`: it will use `circle` as appearance. Great for avatar skeletons, for example :); ## Animations diff --git a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader-config.service.spec.ts b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader-config.service.spec.ts new file mode 100644 index 0000000..99a55c3 --- /dev/null +++ b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader-config.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { NgxSkeletonLoaderConfigService } from './ngx-skeleton-loader-config.service'; + +describe('NgxSkeletonLoaderConfigService', () => { + let service: NgxSkeletonLoaderConfigService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(NgxSkeletonLoaderConfigService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader-config.service.ts b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader-config.service.ts new file mode 100644 index 0000000..b3ffa40 --- /dev/null +++ b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader-config.service.ts @@ -0,0 +1,15 @@ +import { Injectable, Optional } from '@angular/core'; +import { defaultConfig, NgxSkeletonLoaderConfig } from './ngx-skeleton-loader-config.types'; + +@Injectable({ + providedIn: 'root', +}) +export class NgxSkeletonLoaderConfigService { + readonly config: NgxSkeletonLoaderConfig = defaultConfig; + + constructor(@Optional() config: NgxSkeletonLoaderConfig) { + if (config) { + this.config = config; + } + } +} diff --git a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader-config.types.ts b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader-config.types.ts new file mode 100644 index 0000000..f69f0d6 --- /dev/null +++ b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader-config.types.ts @@ -0,0 +1,25 @@ +export type Appearance = 'circle' | 'line' | ''; +export const defaultAppearance: Appearance = ''; + +export type Animation = 'progress' | 'progress-dark' | 'pulse' | 'false' | false; +export const defaultAnimation: Animation = 'progress'; + +export interface Theme { + // This is required since ngStyle is using `any` as well + // More details in https://angular.io/api/common/NgStyle + // tslint:disable-next-line: no-any + [k: string]: any; +} +export const defaultTheme: Theme = {}; + +export const defaultLoadingText = 'Loading...'; +export const defaultCount = 1; + +export class NgxSkeletonLoaderConfig { + appearance?: Appearance = defaultAppearance; + animation?: Animation = defaultAnimation; + theme?: Theme = defaultTheme; + loadingText?: string = defaultLoadingText; + count?: number = defaultCount; +} +export const defaultConfig: NgxSkeletonLoaderConfig = new NgxSkeletonLoaderConfig(); diff --git a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.spec.ts b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.spec.ts index f225ac9..df6e3da 100644 --- a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.spec.ts +++ b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.spec.ts @@ -103,7 +103,7 @@ describe('NgxSkeletonLoaderComponent', () => { it('should console errors if `appearance` is an invalid option and is running in development mode', () => { expect(console.error).toHaveBeenCalledWith( // tslint:disable-next-line: max-line-length - `\`NgxSkeletonLoaderComponent\` need to receive 'appearance' as: circle or empty string. Forcing default to "''".`, + `\`NgxSkeletonLoaderComponent\` need to receive 'appearance' as: circle or line or empty string. Forcing default to "''".`, ); }); diff --git a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.ts b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.ts index 52dc8da..8aa4edc 100644 --- a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.ts +++ b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.ts @@ -10,6 +10,17 @@ import { SimpleChanges, } from '@angular/core'; import { start, end } from 'perf-marks/marks'; +import { NgxSkeletonLoaderConfigService } from './ngx-skeleton-loader-config.service'; +import { + Animation, + Appearance, + defaultAnimation, + defaultAppearance, + defaultCount, + defaultLoadingText, + defaultTheme, + Theme, +} from './ngx-skeleton-loader-config.types'; @Component({ selector: 'ngx-skeleton-loader', @@ -24,25 +35,24 @@ export class NgxSkeletonLoaderComponent implements OnInit, AfterViewInit, OnDest static ngAcceptInputType_animation: boolean | string; @Input() - count = 1; + count: number = this.configService.config.count ?? defaultCount; @Input() - loadingText = 'Loading...'; + loadingText: string = this.configService.config.loadingText ?? defaultLoadingText; @Input() - appearance: 'circle' | '' = ''; + appearance: Appearance = this.configService.config.appearance ?? defaultAppearance; @Input() - animation: 'progress' | 'progress-dark' | 'pulse' | 'false' | false = 'progress'; + animation: Animation = this.configService.config.animation ?? defaultAnimation; - // This is required since ngStyle is using `any` as well - // More details in https://angular.io/api/common/NgStyle - // tslint:disable-next-line: no-any - @Input() theme: { [k: string]: any } = {}; + @Input() theme: Theme = this.configService.config.theme ?? defaultTheme; // tslint:disable-next-line: no-any items: Array = []; + constructor(private configService: NgxSkeletonLoaderConfigService) {} + ngOnInit() { start('NgxSkeletonLoader:Rendered'); start('NgxSkeletonLoader:Loaded'); @@ -61,7 +71,6 @@ export class NgxSkeletonLoaderComponent implements OnInit, AfterViewInit, OnDest } this.count = 1; } - this.items.length = this.count; const allowedAnimations = ['progress', 'progress-dark', 'pulse', 'false']; @@ -77,11 +86,11 @@ export class NgxSkeletonLoaderComponent implements OnInit, AfterViewInit, OnDest this.animation = 'progress'; } - if (['circle', ''].indexOf(String(this.appearance)) === -1) { + if (['circle', 'line', ''].indexOf(String(this.appearance)) === -1) { // Shows error message only in Development if (isDevMode()) { console.error( - `\`NgxSkeletonLoaderComponent\` need to receive 'appearance' as: circle or empty string. Forcing default to "''".`, + `\`NgxSkeletonLoaderComponent\` need to receive 'appearance' as: circle or line or empty string. Forcing default to "''".`, ); } this.appearance = ''; diff --git a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.module.ts b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.module.ts index c07390d..df633f3 100644 --- a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.module.ts +++ b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.module.ts @@ -1,17 +1,19 @@ import { ModuleWithProviders, NgModule } from '@angular/core'; -import { NgxSkeletonLoaderComponent } from './ngx-skeleton-loader.component'; import { CommonModule } from '@angular/common'; +import { NgxSkeletonLoaderComponent } from './ngx-skeleton-loader.component'; +import { defaultConfig, NgxSkeletonLoaderConfig } from './ngx-skeleton-loader-config.types'; + @NgModule({ declarations: [NgxSkeletonLoaderComponent], imports: [CommonModule], exports: [NgxSkeletonLoaderComponent], }) - export class NgxSkeletonLoaderModule { - static forRoot(): ModuleWithProviders { + static forRoot(config: NgxSkeletonLoaderConfig = defaultConfig): ModuleWithProviders { return { ngModule: NgxSkeletonLoaderModule, + providers: [{ provide: NgxSkeletonLoaderConfig, useValue: config }], }; } } diff --git a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.scss b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.scss index 7c5b918..c77d232 100644 --- a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.scss +++ b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.scss @@ -61,7 +61,7 @@ left: 0; width: 200px; height: 100%; - content: ''; + content: ""; } } @@ -78,12 +78,7 @@ &.progress-dark { &:before { - background-image: linear-gradient( - 90deg, - transparent, - rgba(0, 0, 0, 0.2), - transparent - ); + background-image: linear-gradient(90deg, transparent, rgba(0, 0, 0, 0.2), transparent); } } diff --git a/projects/ngx-skeleton-loader/src/public-api.ts b/projects/ngx-skeleton-loader/src/public-api.ts index 713a5b1..d7f6d0c 100644 --- a/projects/ngx-skeleton-loader/src/public-api.ts +++ b/projects/ngx-skeleton-loader/src/public-api.ts @@ -4,3 +4,4 @@ export * from './lib/ngx-skeleton-loader.component'; export * from './lib/ngx-skeleton-loader.module'; +export * from './lib/ngx-skeleton-loader-config.types'; From 8387648f88d98fe6533fbe32bbea4e515f35f592 Mon Sep 17 00:00:00 2001 From: hunteroi Date: Tue, 1 Jun 2021 23:00:06 +0200 Subject: [PATCH 02/13] refactor: global configuration Use an injection token for the module & component configuration --- .../lib/ngx-skeleton-loader-config.service.ts | 12 ++++-- .../lib/ngx-skeleton-loader-config.types.ts | 41 +++++++++---------- .../src/lib/ngx-skeleton-loader.component.ts | 24 ++++------- .../src/lib/ngx-skeleton-loader.module.ts | 12 ++++-- 4 files changed, 45 insertions(+), 44 deletions(-) diff --git a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader-config.service.ts b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader-config.service.ts index b3ffa40..e3c56ac 100644 --- a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader-config.service.ts +++ b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader-config.service.ts @@ -1,13 +1,17 @@ -import { Injectable, Optional } from '@angular/core'; -import { defaultConfig, NgxSkeletonLoaderConfig } from './ngx-skeleton-loader-config.types'; +import { Inject, Injectable, Optional } from '@angular/core'; +import { + DEFAULT_NGX_SKELETON_LOADER_CONFIG, + NgxSkeletonLoaderConfig, + NGX_SKELETON_LOADER_CONFIG, +} from './ngx-skeleton-loader-config.types'; @Injectable({ providedIn: 'root', }) export class NgxSkeletonLoaderConfigService { - readonly config: NgxSkeletonLoaderConfig = defaultConfig; + readonly config: NgxSkeletonLoaderConfig = DEFAULT_NGX_SKELETON_LOADER_CONFIG; - constructor(@Optional() config: NgxSkeletonLoaderConfig) { + constructor(@Inject(NGX_SKELETON_LOADER_CONFIG) @Optional() config: NgxSkeletonLoaderConfig) { if (config) { this.config = config; } diff --git a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader-config.types.ts b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader-config.types.ts index f69f0d6..dde9af5 100644 --- a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader-config.types.ts +++ b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader-config.types.ts @@ -1,25 +1,24 @@ -export type Appearance = 'circle' | 'line' | ''; -export const defaultAppearance: Appearance = ''; +import { InjectionToken } from '@angular/core'; -export type Animation = 'progress' | 'progress-dark' | 'pulse' | 'false' | false; -export const defaultAnimation: Animation = 'progress'; - -export interface Theme { - // This is required since ngStyle is using `any` as well - // More details in https://angular.io/api/common/NgStyle - // tslint:disable-next-line: no-any - [k: string]: any; +export interface NgxSkeletonLoaderConfig { + appearance?: 'circle' | 'line' | ''; + animation?: 'progress' | 'progress-dark' | 'pulse' | 'false' | false; + theme?: { + // This is required since ngStyle is using `any` as well + // More details in https://angular.io/api/common/NgStyle + // tslint:disable-next-line: no-any + [k: string]: any; + }; + loadingText?: string; + count?: number; } -export const defaultTheme: Theme = {}; -export const defaultLoadingText = 'Loading...'; -export const defaultCount = 1; +export const DEFAULT_NGX_SKELETON_LOADER_CONFIG = { + appearance: 'line', + animation: 'progress', + theme: {}, + loadingText: 'Loading...', + count: 1, +} as NgxSkeletonLoaderConfig; -export class NgxSkeletonLoaderConfig { - appearance?: Appearance = defaultAppearance; - animation?: Animation = defaultAnimation; - theme?: Theme = defaultTheme; - loadingText?: string = defaultLoadingText; - count?: number = defaultCount; -} -export const defaultConfig: NgxSkeletonLoaderConfig = new NgxSkeletonLoaderConfig(); +export const NGX_SKELETON_LOADER_CONFIG = new InjectionToken('ngx-skeleton-loader.config'); diff --git a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.ts b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.ts index 8aa4edc..4528517 100644 --- a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.ts +++ b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.ts @@ -11,16 +11,7 @@ import { } from '@angular/core'; import { start, end } from 'perf-marks/marks'; import { NgxSkeletonLoaderConfigService } from './ngx-skeleton-loader-config.service'; -import { - Animation, - Appearance, - defaultAnimation, - defaultAppearance, - defaultCount, - defaultLoadingText, - defaultTheme, - Theme, -} from './ngx-skeleton-loader-config.types'; +import { NgxSkeletonLoaderConfig } from './ngx-skeleton-loader-config.types'; @Component({ selector: 'ngx-skeleton-loader', @@ -35,18 +26,19 @@ export class NgxSkeletonLoaderComponent implements OnInit, AfterViewInit, OnDest static ngAcceptInputType_animation: boolean | string; @Input() - count: number = this.configService.config.count ?? defaultCount; + count: NgxSkeletonLoaderConfig['count'] = this.configService.config.count; @Input() - loadingText: string = this.configService.config.loadingText ?? defaultLoadingText; + loadingText: NgxSkeletonLoaderConfig['loadingText'] = this.configService.config.loadingText; @Input() - appearance: Appearance = this.configService.config.appearance ?? defaultAppearance; + appearance: NgxSkeletonLoaderConfig['appearance'] = this.configService.config.appearance; @Input() - animation: Animation = this.configService.config.animation ?? defaultAnimation; + animation: NgxSkeletonLoaderConfig['animation'] = this.configService.config.animation; - @Input() theme: Theme = this.configService.config.theme ?? defaultTheme; + @Input() + theme: NgxSkeletonLoaderConfig['theme'] = this.configService.config.theme; // tslint:disable-next-line: no-any items: Array = []; @@ -71,7 +63,7 @@ export class NgxSkeletonLoaderComponent implements OnInit, AfterViewInit, OnDest } this.count = 1; } - this.items.length = this.count; + this.items.length = this.count || 1; const allowedAnimations = ['progress', 'progress-dark', 'pulse', 'false']; if (allowedAnimations.indexOf(String(this.animation)) === -1) { diff --git a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.module.ts b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.module.ts index df633f3..ab202bc 100644 --- a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.module.ts +++ b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.module.ts @@ -2,7 +2,11 @@ import { ModuleWithProviders, NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { NgxSkeletonLoaderComponent } from './ngx-skeleton-loader.component'; -import { defaultConfig, NgxSkeletonLoaderConfig } from './ngx-skeleton-loader-config.types'; +import { + DEFAULT_NGX_SKELETON_LOADER_CONFIG, + NgxSkeletonLoaderConfig, + NGX_SKELETON_LOADER_CONFIG, +} from './ngx-skeleton-loader-config.types'; @NgModule({ declarations: [NgxSkeletonLoaderComponent], @@ -10,10 +14,12 @@ import { defaultConfig, NgxSkeletonLoaderConfig } from './ngx-skeleton-loader-co exports: [NgxSkeletonLoaderComponent], }) export class NgxSkeletonLoaderModule { - static forRoot(config: NgxSkeletonLoaderConfig = defaultConfig): ModuleWithProviders { + static forRoot( + config: NgxSkeletonLoaderConfig = DEFAULT_NGX_SKELETON_LOADER_CONFIG, + ): ModuleWithProviders { return { ngModule: NgxSkeletonLoaderModule, - providers: [{ provide: NgxSkeletonLoaderConfig, useValue: config }], + providers: [{ provide: NGX_SKELETON_LOADER_CONFIG, useValue: config }], }; } } From 8b2c1c7b6bc62d20d5a2a874a3342a53f426ba37 Mon Sep 17 00:00:00 2001 From: hunteroi Date: Thu, 3 Jun 2021 23:54:07 +0200 Subject: [PATCH 03/13] revert: revert gitignore & style changes --- .gitignore | 2 +- projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.scss | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 02d9f09..f4f46a5 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,7 @@ /bazel-out # dependencies -**/node_modules +/node_modules # profiling files chrome-profiler-events.json diff --git a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.scss b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.scss index c77d232..ba1b3d9 100644 --- a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.scss +++ b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.scss @@ -61,7 +61,7 @@ left: 0; width: 200px; height: 100%; - content: ""; + content: ''; } } From f11d89c567c70ce68798a5d01909a83e98f67594 Mon Sep 17 00:00:00 2001 From: hunteroi Date: Fri, 4 Jun 2021 00:00:21 +0200 Subject: [PATCH 04/13] refactor: inject config directly in component - Remove service to directly inject the config token in the component and use its values in the constructor - Get rid of the DEFAULT_NGX_SKELETON_LOADER_CONFIG as default values are directly set in the component's constructor - Export theme's type to specific type to avoid errors building in SSR mode --- ...ngx-skeleton-loader-config.service.spec.ts | 16 -------- .../lib/ngx-skeleton-loader-config.service.ts | 19 ---------- .../lib/ngx-skeleton-loader-config.types.ts | 22 ++++------- .../src/lib/ngx-skeleton-loader.component.ts | 38 ++++++++++++++----- .../src/lib/ngx-skeleton-loader.module.ts | 10 +---- 5 files changed, 38 insertions(+), 67 deletions(-) delete mode 100644 projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader-config.service.spec.ts delete mode 100644 projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader-config.service.ts diff --git a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader-config.service.spec.ts b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader-config.service.spec.ts deleted file mode 100644 index 99a55c3..0000000 --- a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader-config.service.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { NgxSkeletonLoaderConfigService } from './ngx-skeleton-loader-config.service'; - -describe('NgxSkeletonLoaderConfigService', () => { - let service: NgxSkeletonLoaderConfigService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(NgxSkeletonLoaderConfigService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader-config.service.ts b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader-config.service.ts deleted file mode 100644 index e3c56ac..0000000 --- a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader-config.service.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Inject, Injectable, Optional } from '@angular/core'; -import { - DEFAULT_NGX_SKELETON_LOADER_CONFIG, - NgxSkeletonLoaderConfig, - NGX_SKELETON_LOADER_CONFIG, -} from './ngx-skeleton-loader-config.types'; - -@Injectable({ - providedIn: 'root', -}) -export class NgxSkeletonLoaderConfigService { - readonly config: NgxSkeletonLoaderConfig = DEFAULT_NGX_SKELETON_LOADER_CONFIG; - - constructor(@Inject(NGX_SKELETON_LOADER_CONFIG) @Optional() config: NgxSkeletonLoaderConfig) { - if (config) { - this.config = config; - } - } -} diff --git a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader-config.types.ts b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader-config.types.ts index dde9af5..64057fb 100644 --- a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader-config.types.ts +++ b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader-config.types.ts @@ -1,24 +1,18 @@ import { InjectionToken } from '@angular/core'; +export type NgxSkeletonLoaderConfigTheme = { + // This is required since ngStyle is using `any` as well + // More details in https://angular.io/api/common/NgStyle + // tslint:disable-next-line: no-any + [k: string]: any; +} | null; + export interface NgxSkeletonLoaderConfig { appearance?: 'circle' | 'line' | ''; animation?: 'progress' | 'progress-dark' | 'pulse' | 'false' | false; - theme?: { - // This is required since ngStyle is using `any` as well - // More details in https://angular.io/api/common/NgStyle - // tslint:disable-next-line: no-any - [k: string]: any; - }; + theme?: NgxSkeletonLoaderConfigTheme; loadingText?: string; count?: number; } -export const DEFAULT_NGX_SKELETON_LOADER_CONFIG = { - appearance: 'line', - animation: 'progress', - theme: {}, - loadingText: 'Loading...', - count: 1, -} as NgxSkeletonLoaderConfig; - export const NGX_SKELETON_LOADER_CONFIG = new InjectionToken('ngx-skeleton-loader.config'); diff --git a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.ts b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.ts index 4528517..86554a2 100644 --- a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.ts +++ b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.ts @@ -8,10 +8,11 @@ import { ChangeDetectionStrategy, OnChanges, SimpleChanges, + Optional, + Inject, } from '@angular/core'; import { start, end } from 'perf-marks/marks'; -import { NgxSkeletonLoaderConfigService } from './ngx-skeleton-loader-config.service'; -import { NgxSkeletonLoaderConfig } from './ngx-skeleton-loader-config.types'; +import { NgxSkeletonLoaderConfig, NgxSkeletonLoaderConfigTheme, NGX_SKELETON_LOADER_CONFIG } from './ngx-skeleton-loader-config.types'; @Component({ selector: 'ngx-skeleton-loader', @@ -26,24 +27,41 @@ export class NgxSkeletonLoaderComponent implements OnInit, AfterViewInit, OnDest static ngAcceptInputType_animation: boolean | string; @Input() - count: NgxSkeletonLoaderConfig['count'] = this.configService.config.count; + count: NgxSkeletonLoaderConfig['count']; @Input() - loadingText: NgxSkeletonLoaderConfig['loadingText'] = this.configService.config.loadingText; + loadingText: NgxSkeletonLoaderConfig['loadingText']; @Input() - appearance: NgxSkeletonLoaderConfig['appearance'] = this.configService.config.appearance; + appearance: NgxSkeletonLoaderConfig['appearance']; @Input() - animation: NgxSkeletonLoaderConfig['animation'] = this.configService.config.animation; + animation: NgxSkeletonLoaderConfig['animation']; @Input() - theme: NgxSkeletonLoaderConfig['theme'] = this.configService.config.theme; + theme: NgxSkeletonLoaderConfigTheme; // tslint:disable-next-line: no-any - items: Array = []; - - constructor(private configService: NgxSkeletonLoaderConfigService) {} + items: Array; + + private config: NgxSkeletonLoaderConfig; + + constructor(@Inject(NGX_SKELETON_LOADER_CONFIG) @Optional() config: NgxSkeletonLoaderConfig) { + this.config = { + appearance: 'line', + animation: 'progress', + theme: {}, + loadingText: 'Loading...', + count: 1, + ...config + }; + this.count = this.config.count; + this.loadingText = this.config.loadingText; + this.appearance = this.config.appearance; + this.animation = this.config.animation; + this.theme = this.config.theme ?? null; + this.items = []; + } ngOnInit() { start('NgxSkeletonLoader:Rendered'); diff --git a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.module.ts b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.module.ts index ab202bc..d8feb7e 100644 --- a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.module.ts +++ b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.module.ts @@ -2,11 +2,7 @@ import { ModuleWithProviders, NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { NgxSkeletonLoaderComponent } from './ngx-skeleton-loader.component'; -import { - DEFAULT_NGX_SKELETON_LOADER_CONFIG, - NgxSkeletonLoaderConfig, - NGX_SKELETON_LOADER_CONFIG, -} from './ngx-skeleton-loader-config.types'; +import { NgxSkeletonLoaderConfig, NGX_SKELETON_LOADER_CONFIG } from './ngx-skeleton-loader-config.types'; @NgModule({ declarations: [NgxSkeletonLoaderComponent], @@ -14,9 +10,7 @@ import { exports: [NgxSkeletonLoaderComponent], }) export class NgxSkeletonLoaderModule { - static forRoot( - config: NgxSkeletonLoaderConfig = DEFAULT_NGX_SKELETON_LOADER_CONFIG, - ): ModuleWithProviders { + static forRoot(config?: NgxSkeletonLoaderConfig): ModuleWithProviders { return { ngModule: NgxSkeletonLoaderModule, providers: [{ provide: NGX_SKELETON_LOADER_CONFIG, useValue: config }], From 2f40b39c5f88727e2e3e78b7a9f0e8be2e30c848 Mon Sep 17 00:00:00 2001 From: hunteroi Date: Fri, 4 Jun 2021 00:01:28 +0200 Subject: [PATCH 05/13] doc(README): improve documentation about custom global configuration --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2d1f9f3..e74b431 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,7 @@ After that, you can use the `ngx-skeleton-loader` components in your templates, Also, you can import the module in your app by calling `NgxSkeletonLoaderModule.forRoot()` when adding it. So it will be available across your Angular application. -Importing the module this way also allows you to globally configure the default values for the `ngx-skeleton-loader` components in your application. +Importing the module this way also allows you to globally configure the default values for the `ngx-skeleton-loader` components in your application, in case you need some different default values for your app. ```typescript ... @@ -129,7 +129,7 @@ You can also define which appearance want to use in your skeleton loader by pass ### Options - `''` - _default_: it will use it `''` as appearance. At the end, it will render like a line; -- `'line'`: it will render like a line. This is the same behavior than passing an empty string; +- `line`: it will render like a line. This is the same behavior as passing an empty string; - `circle`: it will use `circle` as appearance. Great for avatar skeletons, for example :); ## Animations From 952a7a910314b12860f7916b755d87e2dbb97ecc Mon Sep 17 00:00:00 2001 From: hunteroi Date: Fri, 4 Jun 2021 00:09:52 +0200 Subject: [PATCH 06/13] refactor: Use ?? instead of || to avoid breaking change --- .../src/lib/ngx-skeleton-loader.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.ts b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.ts index 86554a2..50ed517 100644 --- a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.ts +++ b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.ts @@ -81,7 +81,7 @@ export class NgxSkeletonLoaderComponent implements OnInit, AfterViewInit, OnDest } this.count = 1; } - this.items.length = this.count || 1; + this.items.length = this.count ?? 1; const allowedAnimations = ['progress', 'progress-dark', 'pulse', 'false']; if (allowedAnimations.indexOf(String(this.animation)) === -1) { From 6f1bbfab3d5735dadce41112cf109330b29a79a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tina=C3=ABl=20Devresse?= <32441291+HunteRoi@users.noreply.github.com> Date: Fri, 4 Jun 2021 00:11:20 +0200 Subject: [PATCH 07/13] revert(SCSS): lint plugin --- .../ngx-skeleton-loader/src/lib/ngx-skeleton-loader.scss | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.scss b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.scss index ba1b3d9..7c5b918 100644 --- a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.scss +++ b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.scss @@ -78,7 +78,12 @@ &.progress-dark { &:before { - background-image: linear-gradient(90deg, transparent, rgba(0, 0, 0, 0.2), transparent); + background-image: linear-gradient( + 90deg, + transparent, + rgba(0, 0, 0, 0.2), + transparent + ); } } From 5ef8e57783c46e9129c9a836de0ab905fd520a1a Mon Sep 17 00:00:00 2001 From: hunteroi Date: Fri, 4 Jun 2021 20:34:10 +0200 Subject: [PATCH 08/13] refactor: change how we deal with configuration and component's attributes --- .../lib/ngx-skeleton-loader-config.types.ts | 10 ++--- .../src/lib/ngx-skeleton-loader.component.ts | 38 ++++++++----------- .../src/lib/ngx-skeleton-loader.module.ts | 2 +- 3 files changed, 22 insertions(+), 28 deletions(-) diff --git a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader-config.types.ts b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader-config.types.ts index 64057fb..eba94ea 100644 --- a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader-config.types.ts +++ b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader-config.types.ts @@ -8,11 +8,11 @@ export type NgxSkeletonLoaderConfigTheme = { } | null; export interface NgxSkeletonLoaderConfig { - appearance?: 'circle' | 'line' | ''; - animation?: 'progress' | 'progress-dark' | 'pulse' | 'false' | false; - theme?: NgxSkeletonLoaderConfigTheme; - loadingText?: string; - count?: number; + appearance: 'circle' | 'line' | ''; + animation: 'progress' | 'progress-dark' | 'pulse' | 'false' | false; + theme: NgxSkeletonLoaderConfigTheme; + loadingText: string; + count: number; } export const NGX_SKELETON_LOADER_CONFIG = new InjectionToken('ngx-skeleton-loader.config'); diff --git a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.ts b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.ts index 50ed517..7e7e134 100644 --- a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.ts +++ b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.ts @@ -12,7 +12,11 @@ import { Inject, } from '@angular/core'; import { start, end } from 'perf-marks/marks'; -import { NgxSkeletonLoaderConfig, NgxSkeletonLoaderConfigTheme, NGX_SKELETON_LOADER_CONFIG } from './ngx-skeleton-loader-config.types'; +import { + NgxSkeletonLoaderConfig, + NgxSkeletonLoaderConfigTheme, + NGX_SKELETON_LOADER_CONFIG, +} from './ngx-skeleton-loader-config.types'; @Component({ selector: 'ngx-skeleton-loader', @@ -27,16 +31,16 @@ export class NgxSkeletonLoaderComponent implements OnInit, AfterViewInit, OnDest static ngAcceptInputType_animation: boolean | string; @Input() - count: NgxSkeletonLoaderConfig['count']; + count: NonNullable; @Input() - loadingText: NgxSkeletonLoaderConfig['loadingText']; + loadingText: NonNullable; @Input() - appearance: NgxSkeletonLoaderConfig['appearance']; + appearance: NonNullable; @Input() - animation: NgxSkeletonLoaderConfig['animation']; + animation: NonNullable; @Input() theme: NgxSkeletonLoaderConfigTheme; @@ -44,22 +48,12 @@ export class NgxSkeletonLoaderComponent implements OnInit, AfterViewInit, OnDest // tslint:disable-next-line: no-any items: Array; - private config: NgxSkeletonLoaderConfig; - - constructor(@Inject(NGX_SKELETON_LOADER_CONFIG) @Optional() config: NgxSkeletonLoaderConfig) { - this.config = { - appearance: 'line', - animation: 'progress', - theme: {}, - loadingText: 'Loading...', - count: 1, - ...config - }; - this.count = this.config.count; - this.loadingText = this.config.loadingText; - this.appearance = this.config.appearance; - this.animation = this.config.animation; - this.theme = this.config.theme ?? null; + constructor(@Inject(NGX_SKELETON_LOADER_CONFIG) @Optional() config?: NgxSkeletonLoaderConfig) { + this.appearance = config?.appearance ?? 'line'; + this.animation = config?.animation ?? 'progress'; + this.theme = config?.theme ?? null; + this.loadingText = config?.loadingText ?? 'Loading...'; + this.count = config?.count ?? 1; this.items = []; } @@ -81,7 +75,7 @@ export class NgxSkeletonLoaderComponent implements OnInit, AfterViewInit, OnDest } this.count = 1; } - this.items.length = this.count ?? 1; + this.items.length = this.count; const allowedAnimations = ['progress', 'progress-dark', 'pulse', 'false']; if (allowedAnimations.indexOf(String(this.animation)) === -1) { diff --git a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.module.ts b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.module.ts index d8feb7e..b5e26d4 100644 --- a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.module.ts +++ b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.module.ts @@ -10,7 +10,7 @@ import { NgxSkeletonLoaderConfig, NGX_SKELETON_LOADER_CONFIG } from './ngx-skele exports: [NgxSkeletonLoaderComponent], }) export class NgxSkeletonLoaderModule { - static forRoot(config?: NgxSkeletonLoaderConfig): ModuleWithProviders { + static forRoot(config?: Partial): ModuleWithProviders { return { ngModule: NgxSkeletonLoaderModule, providers: [{ provide: NGX_SKELETON_LOADER_CONFIG, useValue: config }], From 105a412b0cc79430e91f9d156a572b52e5bbc98c Mon Sep 17 00:00:00 2001 From: hunteroi Date: Fri, 4 Jun 2021 21:00:55 +0200 Subject: [PATCH 09/13] revert(NgxSkeletonLoaderComponent): remove NonNullable as type is already non-optional --- .../src/lib/ngx-skeleton-loader.component.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.ts b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.ts index 7e7e134..408f618 100644 --- a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.ts +++ b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.ts @@ -31,16 +31,16 @@ export class NgxSkeletonLoaderComponent implements OnInit, AfterViewInit, OnDest static ngAcceptInputType_animation: boolean | string; @Input() - count: NonNullable; + count: NgxSkeletonLoaderConfig['count']; @Input() - loadingText: NonNullable; + loadingText: NgxSkeletonLoaderConfig['loadingText']; @Input() - appearance: NonNullable; + appearance: NgxSkeletonLoaderConfig['appearance']; @Input() - animation: NonNullable; + animation: NgxSkeletonLoaderConfig['animation']; @Input() theme: NgxSkeletonLoaderConfigTheme; From ae322ad16ebf23e13ec886765d4b2c9af805d73e Mon Sep 17 00:00:00 2001 From: hunteroi Date: Fri, 4 Jun 2021 21:19:37 +0200 Subject: [PATCH 10/13] Refactor(NgxSkeletonLoaderComponent): destructure config object to reduce bundle size and avoid multiple unnecessary checks --- .../src/lib/ngx-skeleton-loader.component.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.ts b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.ts index 408f618..9de6906 100644 --- a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.ts +++ b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.ts @@ -49,11 +49,12 @@ export class NgxSkeletonLoaderComponent implements OnInit, AfterViewInit, OnDest items: Array; constructor(@Inject(NGX_SKELETON_LOADER_CONFIG) @Optional() config?: NgxSkeletonLoaderConfig) { - this.appearance = config?.appearance ?? 'line'; - this.animation = config?.animation ?? 'progress'; - this.theme = config?.theme ?? null; - this.loadingText = config?.loadingText ?? 'Loading...'; - this.count = config?.count ?? 1; + const { appearance = 'line', animation = 'progress', theme = null, loadingText = 'Loading...', count = 1 } = config || {}; + this.appearance = appearance; + this.animation = animation; + this.theme = theme; + this.loadingText = loadingText; + this.count = count; this.items = []; } From b2c51b63049a0b79c301ab605f499da83c056855 Mon Sep 17 00:00:00 2001 From: hunteroi Date: Fri, 4 Jun 2021 23:02:03 +0200 Subject: [PATCH 11/13] test: add module & components tests for when config is not default one --- .../lib/ngx-skeleton-loader.component.spec.ts | 39 ++++++++++++++++--- .../lib/ngx-skeleton-loader.module.spec.ts | 20 +++++++++- 2 files changed, 52 insertions(+), 7 deletions(-) diff --git a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.spec.ts b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.spec.ts index df6e3da..eadcb79 100644 --- a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.spec.ts +++ b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.spec.ts @@ -1,5 +1,6 @@ import { Component, PLATFORM_ID } from '@angular/core'; import { async as waitForAsync, TestBed } from '@angular/core/testing'; +import { NGX_SKELETON_LOADER_CONFIG } from './ngx-skeleton-loader-config.types'; import { NgxSkeletonLoaderComponent } from './ngx-skeleton-loader.component'; @@ -59,6 +60,10 @@ import { NgxSkeletonLoaderComponent } from './ngx-skeleton-loader.component'; + +
+ +
`, }) @@ -108,12 +113,12 @@ describe('NgxSkeletonLoaderComponent', () => { }); it('should add all relevant WAI-ARIA `aria-` attributes in all ngx-skeleton-loader', () => { - expect(fixture.nativeElement.querySelectorAll('[aria-busy="true"]').length).toBe(14); - expect(fixture.nativeElement.querySelectorAll('[aria-valuemin="0"]').length).toBe(14); - expect(fixture.nativeElement.querySelectorAll('[aria-valuemax="100"]').length).toBe(14); - expect(fixture.nativeElement.querySelectorAll('[aria-valuetext]').length).toBe(14); - expect(fixture.nativeElement.querySelectorAll('[role="progressbar"]').length).toBe(14); - expect(fixture.nativeElement.querySelectorAll('[tabindex="0"]').length).toBe(14); + expect(fixture.nativeElement.querySelectorAll('[aria-busy="true"]').length).toBe(15); + expect(fixture.nativeElement.querySelectorAll('[aria-valuemin="0"]').length).toBe(15); + expect(fixture.nativeElement.querySelectorAll('[aria-valuemax="100"]').length).toBe(15); + expect(fixture.nativeElement.querySelectorAll('[aria-valuetext]').length).toBe(15); + expect(fixture.nativeElement.querySelectorAll('[role="progressbar"]').length).toBe(15); + expect(fixture.nativeElement.querySelectorAll('[tabindex="0"]').length).toBe(15); }); it('should use progress as default animation if `animation` is not passed as component attribute', () => { @@ -190,3 +195,25 @@ describe('NgxSkeletonLoaderComponent', () => { }); }); }); + +describe('NgxSkeletonLoaderComponent2', () => { + // tslint:disable-next-line: no-any + let fixture: any; + + beforeEach( + waitForAsync(() => { + fixture = TestBed.configureTestingModule({ + declarations: [ContainerComponent, NgxSkeletonLoaderComponent], + providers: [ + { provide: PLATFORM_ID, useValue: 'browser' }, + { provide: NGX_SKELETON_LOADER_CONFIG, useValue: { appearance: 'circle', count: 3 }} + ], + }).createComponent(ContainerComponent); + fixture.detectChanges(); + }), + ); + + it('should render skeleton with the provided config', () => { + expect(fixture.nativeElement.querySelectorAll('.skeletons-with-provided-config .loader.circle').length).toBe(3); + }); +}); diff --git a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.module.spec.ts b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.module.spec.ts index 12c96ad..b27cba3 100644 --- a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.module.spec.ts +++ b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.module.spec.ts @@ -15,7 +15,7 @@ import { NgxSkeletonLoaderModule } from './ngx-skeleton-loader.module'; }) class ContainerComponent {} -describe('NgxSkeletonLoaderModule.forRoot() method', () => { +describe('NgxSkeletonLoaderModule method', () => { // tslint:disable-next-line: no-any let fixture: any; @@ -55,3 +55,21 @@ describe('NgxSkeletonLoaderModule.forRoot() method', () => { expect(console.info).toHaveBeenCalledTimes(0); }); }); + +describe('NgxSkeletonLoaderModule.forRoot() method', () => { + // tslint:disable-next-line: no-any + let fixture: any; + + beforeEach(waitForAsync(() => { + fixture = TestBed.configureTestingModule({ + imports: [NgxSkeletonLoaderModule.forRoot({ appearance: 'circle', count: 3 })], + declarations: [ContainerComponent], + providers: [{ provide: PLATFORM_ID, useValue: 'browser' }], + }).createComponent(ContainerComponent); + fixture.detectChanges(); + })); + + it('should render the component properly using given forRoot() config', () => { + expect(fixture.nativeElement.querySelectorAll('.skeletons-defaults .loader.circle').length).toBe(3); + }); +}); From 423ab4b27c336dbebf360c1564ee3bdeb406ca08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tina=C3=ABl=20Devresse?= <32441291+HunteRoi@users.noreply.github.com> Date: Thu, 10 Jun 2021 15:07:15 +0200 Subject: [PATCH 12/13] refactor(NgxSkeletonLoaderModule.spec) Update the tests to use the forRoot configuration --- .../lib/ngx-skeleton-loader.module.spec.ts | 24 +++---------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.module.spec.ts b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.module.spec.ts index b27cba3..a858197 100644 --- a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.module.spec.ts +++ b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.module.spec.ts @@ -26,7 +26,7 @@ describe('NgxSkeletonLoaderModule method', () => { spyOn(console, 'warn'); spyOn(console, 'info'); fixture = TestBed.configureTestingModule({ - imports: [NgxSkeletonLoaderModule], + imports: [NgxSkeletonLoaderModule.forRoot({ appearance: 'circle', count: 3 })], declarations: [ContainerComponent], providers: [{ provide: PLATFORM_ID, useValue: 'browser' }], }).createComponent(ContainerComponent); @@ -34,8 +34,8 @@ describe('NgxSkeletonLoaderModule method', () => { }), ); - it('should render the component properly', () => { - expect(fixture.nativeElement.querySelectorAll('.skeletons-defaults .loader.progress').length).toBe(1); + it('should render the component properly using given forRoot() config', () => { + expect(fixture.nativeElement.querySelectorAll('.skeletons-defaults .loader.circle').length).toBe(3); }); it('should NOT call console.error() method', () => { @@ -55,21 +55,3 @@ describe('NgxSkeletonLoaderModule method', () => { expect(console.info).toHaveBeenCalledTimes(0); }); }); - -describe('NgxSkeletonLoaderModule.forRoot() method', () => { - // tslint:disable-next-line: no-any - let fixture: any; - - beforeEach(waitForAsync(() => { - fixture = TestBed.configureTestingModule({ - imports: [NgxSkeletonLoaderModule.forRoot({ appearance: 'circle', count: 3 })], - declarations: [ContainerComponent], - providers: [{ provide: PLATFORM_ID, useValue: 'browser' }], - }).createComponent(ContainerComponent); - fixture.detectChanges(); - })); - - it('should render the component properly using given forRoot() config', () => { - expect(fixture.nativeElement.querySelectorAll('.skeletons-defaults .loader.circle').length).toBe(3); - }); -}); From 58022ae76cc12c3d21c248bb5d38057ef5639796 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tina=C3=ABl=20Devresse?= <32441291+HunteRoi@users.noreply.github.com> Date: Thu, 10 Jun 2021 20:22:34 +0200 Subject: [PATCH 13/13] refactor(NgxSkeletonLoaderComponent.spec) Change the tests to a single main describe --- .../lib/ngx-skeleton-loader.component.spec.ts | 224 +++++++++--------- 1 file changed, 113 insertions(+), 111 deletions(-) diff --git a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.spec.ts b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.spec.ts index eadcb79..9a05836 100644 --- a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.spec.ts +++ b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.spec.ts @@ -75,145 +75,147 @@ class ContainerComponent { describe('NgxSkeletonLoaderComponent', () => { // tslint:disable-next-line: no-any let fixture: any; - - beforeEach( - waitForAsync(() => { - spyOn(console, 'error'); - fixture = TestBed.configureTestingModule({ - declarations: [ContainerComponent, NgxSkeletonLoaderComponent], - providers: [{ provide: PLATFORM_ID, useValue: 'browser' }], - }).createComponent(ContainerComponent); - fixture.detectChanges(); - }), - ); - - it('should console 3 errors if `animation`, `appearance` and `count` receives invalid options and is running in development mode', () => { - expect(console.error).toHaveBeenCalledTimes(3); - }); - - it('should console errors if `animation` is an invalid option and is running in development mode', () => { - expect(console.error).toHaveBeenCalledWith( - // tslint:disable-next-line: max-line-length - `\`NgxSkeletonLoaderComponent\` need to receive 'animation' as: progress, progress-dark, pulse, false. Forcing default to "progress".`, + beforeEach(() => { + spyOn(console, 'error'); + }); + + describe('When the component uses default configuration', () => { + beforeEach( + waitForAsync(() => { + fixture = TestBed.configureTestingModule({ + declarations: [ContainerComponent, NgxSkeletonLoaderComponent], + providers: [{ provide: PLATFORM_ID, useValue: 'browser' }], + }).createComponent(ContainerComponent); + fixture.detectChanges(); + }), ); - }); - it('should console errors if `count` is an invalid option and is running in development mode', () => { - expect(console.error).toHaveBeenCalledWith( - // tslint:disable-next-line: max-line-length - `\`NgxSkeletonLoaderComponent\` need to receive 'count' a numeric value. Forcing default to "1".`, - ); - }); + it('should console 3 errors if `animation`, `appearance` and `count` receives invalid options and is running in development mode', () => { + expect(console.error).toHaveBeenCalledTimes(3); + }); - it('should console errors if `appearance` is an invalid option and is running in development mode', () => { - expect(console.error).toHaveBeenCalledWith( - // tslint:disable-next-line: max-line-length - `\`NgxSkeletonLoaderComponent\` need to receive 'appearance' as: circle or line or empty string. Forcing default to "''".`, - ); - }); + it('should console errors if `animation` is an invalid option and is running in development mode', () => { + expect(console.error).toHaveBeenCalledWith( + // tslint:disable-next-line: max-line-length + `\`NgxSkeletonLoaderComponent\` need to receive 'animation' as: progress, progress-dark, pulse, false. Forcing default to "progress".`, + ); + }); - it('should add all relevant WAI-ARIA `aria-` attributes in all ngx-skeleton-loader', () => { - expect(fixture.nativeElement.querySelectorAll('[aria-busy="true"]').length).toBe(15); - expect(fixture.nativeElement.querySelectorAll('[aria-valuemin="0"]').length).toBe(15); - expect(fixture.nativeElement.querySelectorAll('[aria-valuemax="100"]').length).toBe(15); - expect(fixture.nativeElement.querySelectorAll('[aria-valuetext]').length).toBe(15); - expect(fixture.nativeElement.querySelectorAll('[role="progressbar"]').length).toBe(15); - expect(fixture.nativeElement.querySelectorAll('[tabindex="0"]').length).toBe(15); - }); + it('should console errors if `count` is an invalid option and is running in development mode', () => { + expect(console.error).toHaveBeenCalledWith( + // tslint:disable-next-line: max-line-length + `\`NgxSkeletonLoaderComponent\` need to receive 'count' a numeric value. Forcing default to "1".`, + ); + }); - it('should use progress as default animation if `animation` is not passed as component attribute', () => { - expect(fixture.nativeElement.querySelectorAll('.skeletons-defaults .loader.progress').length).toBe(1); - }); + it('should console errors if `appearance` is an invalid option and is running in development mode', () => { + expect(console.error).toHaveBeenCalledWith( + // tslint:disable-next-line: max-line-length + `\`NgxSkeletonLoaderComponent\` need to receive 'appearance' as: circle or line or empty string. Forcing default to "''".`, + ); + }); - describe('When skeleton is created using default settings', () => { - it('should render a single skeleton', () => { - expect(fixture.nativeElement.querySelectorAll('.skeletons-defaults .loader').length).toBe(1); + it('should add all relevant WAI-ARIA `aria-` attributes in all ngx-skeleton-loader', () => { + expect(fixture.nativeElement.querySelectorAll('[aria-busy="true"]').length).toBe(15); + expect(fixture.nativeElement.querySelectorAll('[aria-valuemin="0"]').length).toBe(15); + expect(fixture.nativeElement.querySelectorAll('[aria-valuemax="100"]').length).toBe(15); + expect(fixture.nativeElement.querySelectorAll('[aria-valuetext]').length).toBe(15); + expect(fixture.nativeElement.querySelectorAll('[role="progressbar"]').length).toBe(15); + expect(fixture.nativeElement.querySelectorAll('[tabindex="0"]').length).toBe(15); }); - }); - describe('When skeleton is created passing loading text to be used as WAI-ARIA `aria-valuetext`', () => { - it('should render a single skeleton', () => { - expect(fixture.nativeElement.querySelectorAll('[aria-valuetext="Loading. Please wait ..."]').length).toBe(1); + it('should use progress as default animation if `animation` is not passed as component attribute', () => { + expect(fixture.nativeElement.querySelectorAll('.skeletons-defaults .loader.progress').length).toBe(1); }); - }); - describe('When skeleton is created with count', () => { - it('should render skeleton based on given count attribute', () => { - expect(fixture.nativeElement.querySelectorAll('.skeletons-with-count .loader').length).toBe(2); + describe('When skeleton is created using default settings', () => { + it('should render a single skeleton', () => { + expect(fixture.nativeElement.querySelectorAll('.skeletons-defaults .loader').length).toBe(1); + }); }); - }); - describe('When skeleton is created with circle appearance', () => { - it('should add styles based on circle class on the skeleton components', () => { - expect(fixture.nativeElement.querySelectorAll('.skeletons-appearance-circle .loader.circle').length).toBe(1); + describe('When skeleton is created passing loading text to be used as WAI-ARIA `aria-valuetext`', () => { + it('should render a single skeleton', () => { + expect(fixture.nativeElement.querySelectorAll('[aria-valuetext="Loading. Please wait ..."]').length).toBe(1); + }); }); - }); - describe('When skeleton is created without animation', () => { - it('should NOT add progress animation styles based on animation class on the skeleton components', () => { - expect( - fixture.nativeElement.querySelectorAll('.skeletons-animation-no-animation .loader:not(.animation)').length, - ).toBe(1); + describe('When skeleton is created with count', () => { + it('should render skeleton based on given count attribute', () => { + expect(fixture.nativeElement.querySelectorAll('.skeletons-with-count .loader').length).toBe(2); + }); }); - it('should NOT add progress animation styles based on animation class if animation value is passed via binding', () => { - expect( - fixture.nativeElement.querySelectorAll('.skeletons-animation-no-animation-via-binding .loader:not(.animation)') - .length, - ).toBe(1); + describe('When skeleton is created with circle appearance', () => { + it('should add styles based on circle class on the skeleton components', () => { + expect(fixture.nativeElement.querySelectorAll('.skeletons-appearance-circle .loader.circle').length).toBe(1); + }); }); - }); - describe('When skeleton is created using `pulse` as animation', () => { - it('should add pulse animation styles based on animation class on the skeleton components', () => { - expect(fixture.nativeElement.querySelectorAll('.skeletons-animation-pulse .loader.pulse').length).toBe(1); + describe('When skeleton is created without animation', () => { + it('should NOT add progress animation styles based on animation class on the skeleton components', () => { + expect( + fixture.nativeElement.querySelectorAll('.skeletons-animation-no-animation .loader:not(.animation)').length, + ).toBe(1); + }); + + it('should NOT add progress animation styles based on animation class if animation value is passed via binding', () => { + expect( + fixture.nativeElement.querySelectorAll( + '.skeletons-animation-no-animation-via-binding .loader:not(.animation)', + ).length, + ).toBe(1); + }); }); - }); - describe('When skeleton is created using `progress-dark` as animation', () => { - it('should add progress-dark animation styles based on animation class on the skeleton components', () => { - expect( - fixture.nativeElement.querySelectorAll('.skeletons-animation-progress-dark .loader.progress-dark').length, - ).toBe(1); + describe('When skeleton is created using `pulse` as animation', () => { + it('should add pulse animation styles based on animation class on the skeleton components', () => { + expect(fixture.nativeElement.querySelectorAll('.skeletons-animation-pulse .loader.pulse').length).toBe(1); + }); }); - }); - describe('When skeleton is created using `progress` as animation', () => { - it('should add progress animation styles based on animation class on the skeleton components', () => { - expect(fixture.nativeElement.querySelectorAll('.skeletons-animation-progress .loader.progress').length).toBe(1); + describe('When skeleton is created using `progress-dark` as animation', () => { + it('should add progress-dark animation styles based on animation class on the skeleton components', () => { + expect( + fixture.nativeElement.querySelectorAll('.skeletons-animation-progress-dark .loader.progress-dark').length, + ).toBe(1); + }); }); - }); - describe('When skeleton is created with theming', () => { - it('should render skeleton with styles based on theme attribute', () => { - const skeletonWithTheming = fixture.nativeElement.querySelector('.skeletons-with-theming .loader.circle') - .attributes as NamedNodeMap; + describe('When skeleton is created using `progress` as animation', () => { + it('should add progress animation styles based on animation class on the skeleton components', () => { + expect(fixture.nativeElement.querySelectorAll('.skeletons-animation-progress .loader.progress').length).toBe(1); + }); + }); - expect((skeletonWithTheming.getNamedItem('style') as Attr).value).toBe( - 'width: 70px; height: 70px; border-radius: 10px;', - ); + describe('When skeleton is created with theming', () => { + it('should render skeleton with styles based on theme attribute', () => { + const skeletonWithTheming = fixture.nativeElement.querySelector('.skeletons-with-theming .loader.circle') + .attributes as NamedNodeMap; + + expect((skeletonWithTheming.getNamedItem('style') as Attr).value).toBe( + 'width: 70px; height: 70px; border-radius: 10px;', + ); + }); }); }); -}); -describe('NgxSkeletonLoaderComponent2', () => { - // tslint:disable-next-line: no-any - let fixture: any; + describe('When the component receives a different default via module configuration', () => { + beforeEach( + waitForAsync(() => { + fixture = TestBed.configureTestingModule({ + declarations: [ContainerComponent, NgxSkeletonLoaderComponent], + providers: [ + { provide: PLATFORM_ID, useValue: 'browser' }, + { provide: NGX_SKELETON_LOADER_CONFIG, useValue: { appearance: 'circle', count: 3 } }, + ], + }).createComponent(ContainerComponent); + fixture.detectChanges(); + }), + ); - beforeEach( - waitForAsync(() => { - fixture = TestBed.configureTestingModule({ - declarations: [ContainerComponent, NgxSkeletonLoaderComponent], - providers: [ - { provide: PLATFORM_ID, useValue: 'browser' }, - { provide: NGX_SKELETON_LOADER_CONFIG, useValue: { appearance: 'circle', count: 3 }} - ], - }).createComponent(ContainerComponent); - fixture.detectChanges(); - }), - ); - - it('should render skeleton with the provided config', () => { - expect(fixture.nativeElement.querySelectorAll('.skeletons-with-provided-config .loader.circle').length).toBe(3); + it('should render skeleton with the provided config', () => { + expect(fixture.nativeElement.querySelectorAll('.skeletons-with-provided-config .loader.circle').length).toBe(3); + }); }); });