From 602cd22210d20cf3faf8f24143bd0b4fd1ca7309 Mon Sep 17 00:00:00 2001 From: Christian Quinn Date: Thu, 13 Jan 2022 10:49:16 -0400 Subject: [PATCH 01/25] feat: added skeleton component --- .../src/skeleton/skeleton.component.scss | 45 +++++++++++ .../src/skeleton/skeleton.component.ts | 77 +++++++++++++++++++ .../src/skeleton/skeleton.module.ts | 10 +++ 3 files changed, 132 insertions(+) create mode 100644 projects/components/src/skeleton/skeleton.component.scss create mode 100644 projects/components/src/skeleton/skeleton.component.ts create mode 100644 projects/components/src/skeleton/skeleton.module.ts diff --git a/projects/components/src/skeleton/skeleton.component.scss b/projects/components/src/skeleton/skeleton.component.scss new file mode 100644 index 000000000..1d05bf37b --- /dev/null +++ b/projects/components/src/skeleton/skeleton.component.scss @@ -0,0 +1,45 @@ +.skeleton { + position: relative; + background-color: #dee2e6; + overflow: hidden; + + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + + border-radius: 4px; +} + +.skeleton::after { + content: ''; + animation: skeleton-animation 1.2s infinite; + height: 100%; + left: 0; + position: absolute; + right: 0; + top: 0; + transform: translateX(-100%); + z-index: 1; + background: linear-gradient(90deg, rgba(255, 255, 255, 0), rgba(255, 255, 255, 0.4), rgba(255, 255, 255, 0)); +} + +.skeleton.skeleton-rectangle-text { + border-radius: 6px; +} + +.skeleton.skeleton-circle { + border-radius: 50%; +} + +.skeleton-none::after { + animation: none; +} + +@keyframes skeleton-animation { + from { + transform: translateX(-100%); + } + to { + transform: translateX(100%); + } +} diff --git a/projects/components/src/skeleton/skeleton.component.ts b/projects/components/src/skeleton/skeleton.component.ts new file mode 100644 index 000000000..cef66fd1a --- /dev/null +++ b/projects/components/src/skeleton/skeleton.component.ts @@ -0,0 +1,77 @@ +import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core'; + +interface ContainerClass { + skeleton: boolean; + 'skeleton-circle': boolean; + 'skeleton-rectangle-text': boolean; + 'skeleton-none': boolean; +} + +// TODO ENG-7872 type def container style +// TODO ENG-7872 strongly type with enums config options +@Component({ + selector: 'ht-skeleton', + template: `
`, + changeDetection: ChangeDetectionStrategy.OnPush, + styleUrls: ['./skeleton.scss'] +}) +export class SkeletonComponent implements OnInit { + // Inline styles + @Input() public style: any; // Must be any for spread operator + + @Input() public shapeStyle: string = 'rectangle'; + + @Input() public animation: string = 'wave'; + + @Input() public size: string = ''; + + @Input() public width: string = ''; + + @Input() public height: string = ''; + + public ngOnInit() { + // Set default dimensions for shapes + switch (this.shapeStyle) { + case 'rectangle': // Could remove this + this.width = this.width ? this.width : '80%'; + this.height = this.height ? this.height : '80%'; + break; + case 'rectangle-text': + this.width = this.width ? this.width : '80%'; + this.height = this.height ? this.height : '1.3rem'; + break; + case 'circle': + this.width = this.width ? this.width : '3rem'; + this.height = this.height ? this.height : '3rem'; + break; + default: + this.width = this.width ? this.width : '80%'; + this.height = this.height ? this.height : '80%'; + } + } + + public containerClass(): ContainerClass { + return { + skeleton: true, + 'skeleton-circle': this.shapeStyle === 'circle', + 'skeleton-rectangle-text': this.shapeStyle === 'rectangle-text', + 'skeleton-none': this.animation === 'none' + }; + } + + public containerStyle() { + if (!!this.size) { + return { + ...this.style, + width: this.size, + height: this.size + }; + } else { + return { + ...this.style, + width: this.width, + height: this.height + }; + } + } +} diff --git a/projects/components/src/skeleton/skeleton.module.ts b/projects/components/src/skeleton/skeleton.module.ts new file mode 100644 index 000000000..c95e0b242 --- /dev/null +++ b/projects/components/src/skeleton/skeleton.module.ts @@ -0,0 +1,10 @@ +import { NgModule } from '@angular/core'; +import { SkeletonComponent } from './skeleton.component'; +import { CommonModule } from '@angular/common'; + +@NgModule({ + declarations: [SkeletonComponent], + imports: [CommonModule], + exports: [SkeletonComponent] +}) +export class SkeletonModule {} From 3a3d19b5adc2ceb72ddf6b657581f2ec5b407564 Mon Sep 17 00:00:00 2001 From: Christian Quinn Date: Thu, 13 Jan 2022 10:49:16 -0400 Subject: [PATCH 02/25] feat: added skeleton component From cba76a7993ceda8eb4e7a729e5a6a04c16a81705 Mon Sep 17 00:00:00 2001 From: Christian Quinn Date: Thu, 13 Jan 2022 12:30:57 -0400 Subject: [PATCH 03/25] fix: integrating skeleton component with loader --- projects/components/src/load-async/load-async.module.ts | 3 ++- .../src/load-async/loader/loader.component.scss | 9 +++++---- .../components/src/load-async/loader/loader.component.ts | 4 +++- projects/components/src/skeleton/skeleton.component.ts | 3 ++- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/projects/components/src/load-async/load-async.module.ts b/projects/components/src/load-async/load-async.module.ts index 11a9b3e76..6f0fa4bb5 100644 --- a/projects/components/src/load-async/load-async.module.ts +++ b/projects/components/src/load-async/load-async.module.ts @@ -5,10 +5,11 @@ import { MessageDisplayModule } from '../message-display/message-display.module' import { LoadAsyncDirective } from './load-async.directive'; import { LoaderComponent } from './loader/loader.component'; import { LoadAsyncWrapperComponent } from './wrapper/load-async-wrapper.component'; +import { SkeletonModule } from '../skeleton/skeleton.module'; @NgModule({ declarations: [LoadAsyncDirective, LoadAsyncWrapperComponent, LoaderComponent], - imports: [CommonModule, IconModule, MessageDisplayModule], + imports: [CommonModule, IconModule, MessageDisplayModule, SkeletonModule], exports: [LoadAsyncDirective] }) export class LoadAsyncModule {} diff --git a/projects/components/src/load-async/loader/loader.component.scss b/projects/components/src/load-async/loader/loader.component.scss index f9c88ac07..4d7906d69 100644 --- a/projects/components/src/load-async/loader/loader.component.scss +++ b/projects/components/src/load-async/loader/loader.component.scss @@ -3,10 +3,11 @@ .ht-loader { width: 100%; height: 100%; - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; + + //display: flex; + //flex-direction: column; + //justify-content: center; + //align-items: center; .page { height: 50px; diff --git a/projects/components/src/load-async/loader/loader.component.ts b/projects/components/src/load-async/loader/loader.component.ts index 04f697ec0..a91af92a1 100644 --- a/projects/components/src/load-async/loader/loader.component.ts +++ b/projects/components/src/load-async/loader/loader.component.ts @@ -2,13 +2,15 @@ import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/c import { ImagesAssetPath } from '@hypertrace/assets-library'; import { LoaderType } from '../load-async.service'; +// TODO 7872 put display class on img when its displayed to center it @Component({ selector: 'ht-loader', styleUrls: ['./loader.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, template: `
- + +
` }) diff --git a/projects/components/src/skeleton/skeleton.component.ts b/projects/components/src/skeleton/skeleton.component.ts index cef66fd1a..e722891a8 100644 --- a/projects/components/src/skeleton/skeleton.component.ts +++ b/projects/components/src/skeleton/skeleton.component.ts @@ -9,11 +9,12 @@ interface ContainerClass { // TODO ENG-7872 type def container style // TODO ENG-7872 strongly type with enums config options +// TODO ENG-7872 replace styles with any predefined @Component({ selector: 'ht-skeleton', template: `
`, changeDetection: ChangeDetectionStrategy.OnPush, - styleUrls: ['./skeleton.scss'] + styleUrls: ['./skeleton.component.scss'] }) export class SkeletonComponent implements OnInit { // Inline styles From e81d1df354603e22c8dea4035cfa052f743e0ba3 Mon Sep 17 00:00:00 2001 From: Christian Quinn Date: Thu, 13 Jan 2022 16:29:14 -0400 Subject: [PATCH 04/25] style: adding loader types and fixing display --- .../src/load-async/load-async.service.ts | 6 +++- .../load-async/loader/loader.component.scss | 12 ++++---- .../src/load-async/loader/loader.component.ts | 30 ++++++++++++++++--- 3 files changed, 38 insertions(+), 10 deletions(-) diff --git a/projects/components/src/load-async/load-async.service.ts b/projects/components/src/load-async/load-async.service.ts index f745c9df1..5786670e5 100644 --- a/projects/components/src/load-async/load-async.service.ts +++ b/projects/components/src/load-async/load-async.service.ts @@ -62,7 +62,11 @@ export type AsyncState = LoadingAsyncState | SuccessAsyncState | NoDataOrErrorAs export const enum LoaderType { Spinner = 'spinner', ExpandableRow = 'expandable-row', - Page = 'page' + Page = 'page', + Rectangle = 'rectangle', + RectangleText = 'rectangle-text', + Square = 'square', + Circle = 'circle' } interface LoadingAsyncState { diff --git a/projects/components/src/load-async/loader/loader.component.scss b/projects/components/src/load-async/loader/loader.component.scss index 4d7906d69..5317ef04f 100644 --- a/projects/components/src/load-async/loader/loader.component.scss +++ b/projects/components/src/load-async/loader/loader.component.scss @@ -4,11 +4,6 @@ width: 100%; height: 100%; - //display: flex; - //flex-direction: column; - //justify-content: center; - //align-items: center; - .page { height: 50px; width: 50px; @@ -24,3 +19,10 @@ width: auto; } } + +.flex-centered { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} diff --git a/projects/components/src/load-async/loader/loader.component.ts b/projects/components/src/load-async/loader/loader.component.ts index a91af92a1..daf85fb8e 100644 --- a/projects/components/src/load-async/loader/loader.component.ts +++ b/projects/components/src/load-async/loader/loader.component.ts @@ -2,15 +2,27 @@ import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/c import { ImagesAssetPath } from '@hypertrace/assets-library'; import { LoaderType } from '../load-async.service'; -// TODO 7872 put display class on img when its displayed to center it +// TODO 7872 add configs to switch cases + @Component({ selector: 'ht-loader', styleUrls: ['./loader.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, template: ` -
- - +
+ + + + + +
` }) @@ -35,4 +47,14 @@ export class LoaderComponent implements OnChanges { return ImagesAssetPath.LoaderSpinner; } } + + public containerDisplayClass(): { 'flex-centered': boolean } { + // return { 'flex-centered': false } + return { + 'flex-centered': + this.currentLoaderType === LoaderType.ExpandableRow || + this.currentLoaderType === LoaderType.Spinner || + this.currentLoaderType === LoaderType.Page + }; + } } From e879a4e224ac3cd053be5a05a880923217da88e4 Mon Sep 17 00:00:00 2001 From: Christian Quinn Date: Thu, 13 Jan 2022 21:29:06 -0400 Subject: [PATCH 05/25] feat: added skeleton shapes and styling --- .../src/load-async/load-async.service.ts | 5 +- .../src/load-async/loader/loader.component.ts | 63 +++++++----- .../wrapper/load-async-wrapper.component.ts | 2 +- .../src/skeleton/skeleton.component.scss | 97 ++++++++++++++++--- .../src/skeleton/skeleton.component.ts | 91 ++++++++--------- 5 files changed, 167 insertions(+), 91 deletions(-) diff --git a/projects/components/src/load-async/load-async.service.ts b/projects/components/src/load-async/load-async.service.ts index 5786670e5..89b341ec4 100644 --- a/projects/components/src/load-async/load-async.service.ts +++ b/projects/components/src/load-async/load-async.service.ts @@ -66,7 +66,9 @@ export const enum LoaderType { Rectangle = 'rectangle', RectangleText = 'rectangle-text', Square = 'square', - Circle = 'circle' + Circle = 'circle', + TableRow = 'table-row', + ListItem = 'list-item' } interface LoadingAsyncState { @@ -84,6 +86,7 @@ interface NoDataOrErrorAsyncState { interface LoadingStateConfig { loaderType?: LoaderType; + repeatCount?: number; } interface NoDataOrErrorStateConfig { diff --git a/projects/components/src/load-async/loader/loader.component.ts b/projects/components/src/load-async/loader/loader.component.ts index daf85fb8e..67752af67 100644 --- a/projects/components/src/load-async/loader/loader.component.ts +++ b/projects/components/src/load-async/loader/loader.component.ts @@ -1,28 +1,21 @@ import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core'; import { ImagesAssetPath } from '@hypertrace/assets-library'; import { LoaderType } from '../load-async.service'; - -// TODO 7872 add configs to switch cases +import { SkeletonType } from '../../skeleton/skeleton.component'; @Component({ selector: 'ht-loader', styleUrls: ['./loader.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, template: ` -
- - - - - - +
+ + + + + + +
` }) @@ -30,10 +23,17 @@ export class LoaderComponent implements OnChanges { @Input() public loaderType?: LoaderType; + @Input() + public repeatLoaderCount?: number; + + public skeletonType: SkeletonType = SkeletonType.Rectangle; + public currentLoaderType: LoaderType = LoaderType.Spinner; public ngOnChanges(): void { this.currentLoaderType = this.loaderType ?? LoaderType.Spinner; + + this.skeletonType = this.loaderToSkeletonTypeMap(this.currentLoaderType); } public getImagePathFromType(loaderType: LoaderType): ImagesAssetPath { @@ -48,13 +48,28 @@ export class LoaderComponent implements OnChanges { } } - public containerDisplayClass(): { 'flex-centered': boolean } { - // return { 'flex-centered': false } - return { - 'flex-centered': - this.currentLoaderType === LoaderType.ExpandableRow || - this.currentLoaderType === LoaderType.Spinner || - this.currentLoaderType === LoaderType.Page - }; + public loaderToSkeletonTypeMap(curLoaderType: LoaderType): SkeletonType { + switch (curLoaderType) { + case LoaderType.RectangleText: + return SkeletonType.RectangleText; + case LoaderType.Circle: + return SkeletonType.Circle; + case LoaderType.Square: + return SkeletonType.Square; + case LoaderType.TableRow: + return SkeletonType.TableRow; + case LoaderType.ListItem: + return SkeletonType.ListItem; + default: + return SkeletonType.Rectangle; + } + } + + public oldLoaderType(): boolean { + return ( + this.currentLoaderType === LoaderType.ExpandableRow || + this.currentLoaderType === LoaderType.Spinner || + this.currentLoaderType === LoaderType.Page + ); } } diff --git a/projects/components/src/load-async/wrapper/load-async-wrapper.component.ts b/projects/components/src/load-async/wrapper/load-async-wrapper.component.ts index 13c3b268c..96dcffb1f 100644 --- a/projects/components/src/load-async/wrapper/load-async-wrapper.component.ts +++ b/projects/components/src/load-async/wrapper/load-async-wrapper.component.ts @@ -14,7 +14,7 @@ export const ASYNC_WRAPPER_PARAMETERS$ = new InjectionToken - + diff --git a/projects/components/src/skeleton/skeleton.component.scss b/projects/components/src/skeleton/skeleton.component.scss index 1d05bf37b..5c4eb43a8 100644 --- a/projects/components/src/skeleton/skeleton.component.scss +++ b/projects/components/src/skeleton/skeleton.component.scss @@ -1,3 +1,22 @@ +@mixin loading-animation { + content: ''; + animation: skeleton-animation 1.2s infinite; + height: 100%; + left: 0; + position: absolute; + right: 0; + top: 0; + transform: translateX(-100%); + z-index: 1; + background: linear-gradient(90deg, rgba(255, 255, 255, 0), rgba(255, 255, 255, 0.4), rgba(255, 255, 255, 0)); +} + +@mixin initial-location { + top: initial; + left: initial; + transform: initial; +} + .skeleton { position: relative; background-color: #dee2e6; @@ -7,32 +26,82 @@ left: 50%; transform: translate(-50%, -50%); - border-radius: 4px; + border-radius: 6px; } .skeleton::after { - content: ''; - animation: skeleton-animation 1.2s infinite; - height: 100%; - left: 0; - position: absolute; - right: 0; - top: 0; - transform: translateX(-100%); - z-index: 1; - background: linear-gradient(90deg, rgba(255, 255, 255, 0), rgba(255, 255, 255, 0.4), rgba(255, 255, 255, 0)); + @include loading-animation; +} + +.skeleton.skeleton-rectangle { + height: 80%; + width: 80%; } .skeleton.skeleton-rectangle-text { - border-radius: 6px; + height: 1.3rem; + width: 90%; } .skeleton.skeleton-circle { + width: 2rem; + height: 2rem; border-radius: 50%; } -.skeleton-none::after { - animation: none; +.skeleton.skeleton-square { + width: 3rem; + height: 3rem; +} + +.skeleton.skeleton-table-row { + height: 1.3rem; + width: 90%; + + @include initial-location; +} + +.skeleton.skeleton-repeating { + margin-top: 1rem; +} + +.skeleton.skeleton-list-item { + background-color: rgb(255, 255, 255); + @include initial-location; + display: flex; + justify-content: flex-start; + + .item-circle { + background-color: #dee2e6; + height: 2rem; + width: 2rem; + border-radius: 50%; + } + .item-circle::after { + @include loading-animation; + } + + .item-column { + display: flex; + flex-direction: column; + padding-left: 1rem; + width: 100%; + } + + .item-column > div { + background-color: #dee2e6; + height: 0.9rem; + border-radius: 6px; + width: 90%; + + &:last-child { + margin-top: 5px; + width: 80%; + } + } + .item-column > div::after { + @include loading-animation; + } } @keyframes skeleton-animation { diff --git a/projects/components/src/skeleton/skeleton.component.ts b/projects/components/src/skeleton/skeleton.component.ts index e722891a8..12ddc400e 100644 --- a/projects/components/src/skeleton/skeleton.component.ts +++ b/projects/components/src/skeleton/skeleton.component.ts @@ -2,77 +2,66 @@ import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core interface ContainerClass { skeleton: boolean; + 'skeleton-rectangle': boolean; + 'skeleton-square': boolean; 'skeleton-circle': boolean; 'skeleton-rectangle-text': boolean; - 'skeleton-none': boolean; + 'skeleton-table-row': boolean; + 'skeleton-list-item': boolean; + 'skeleton-repeating': boolean; +} + +export const enum SkeletonType { + Rectangle = 'rectangle', + RectangleText = 'rectangle-text', + Square = 'square', + Circle = 'circle', + TableRow = 'table-row', + ListItem = 'list-item' } -// TODO ENG-7872 type def container style -// TODO ENG-7872 strongly type with enums config options -// TODO ENG-7872 replace styles with any predefined @Component({ selector: 'ht-skeleton', - template: `
`, + template: ` + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styleUrls: ['./skeleton.component.scss'] }) export class SkeletonComponent implements OnInit { - // Inline styles - @Input() public style: any; // Must be any for spread operator + @Input() public shapeStyle: SkeletonType = SkeletonType.Rectangle; - @Input() public shapeStyle: string = 'rectangle'; - - @Input() public animation: string = 'wave'; + @Input() public repeat: number = 1; @Input() public size: string = ''; - @Input() public width: string = ''; - - @Input() public height: string = ''; - - public ngOnInit() { - // Set default dimensions for shapes - switch (this.shapeStyle) { - case 'rectangle': // Could remove this - this.width = this.width ? this.width : '80%'; - this.height = this.height ? this.height : '80%'; - break; - case 'rectangle-text': - this.width = this.width ? this.width : '80%'; - this.height = this.height ? this.height : '1.3rem'; - break; - case 'circle': - this.width = this.width ? this.width : '3rem'; - this.height = this.height ? this.height : '3rem'; - break; - default: - this.width = this.width ? this.width : '80%'; - this.height = this.height ? this.height : '80%'; - } - } + public ngOnInit() {} public containerClass(): ContainerClass { return { skeleton: true, + 'skeleton-rectangle': this.shapeStyle === 'rectangle', + 'skeleton-square': this.shapeStyle === 'square', 'skeleton-circle': this.shapeStyle === 'circle', 'skeleton-rectangle-text': this.shapeStyle === 'rectangle-text', - 'skeleton-none': this.animation === 'none' + 'skeleton-table-row': this.shapeStyle === 'table-row', + 'skeleton-list-item': this.shapeStyle === 'list-item', + 'skeleton-repeating': this.repeat > 1 }; } - - public containerStyle() { - if (!!this.size) { - return { - ...this.style, - width: this.size, - height: this.size - }; - } else { - return { - ...this.style, - width: this.width, - height: this.height - }; - } - } } From 24015a1055f1b5260865e47db4df0f54e656155e Mon Sep 17 00:00:00 2001 From: Christian Quinn Date: Thu, 13 Jan 2022 21:40:33 -0400 Subject: [PATCH 06/25] fix: linting errors --- projects/components/src/load-async/load-async.module.ts | 2 +- .../components/src/load-async/loader/loader.component.ts | 2 +- projects/components/src/skeleton/skeleton.component.ts | 6 ++---- projects/components/src/skeleton/skeleton.module.ts | 2 +- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/projects/components/src/load-async/load-async.module.ts b/projects/components/src/load-async/load-async.module.ts index 6f0fa4bb5..5c1ecea58 100644 --- a/projects/components/src/load-async/load-async.module.ts +++ b/projects/components/src/load-async/load-async.module.ts @@ -2,10 +2,10 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { IconModule } from '../icon/icon.module'; import { MessageDisplayModule } from '../message-display/message-display.module'; +import { SkeletonModule } from '../skeleton/skeleton.module'; import { LoadAsyncDirective } from './load-async.directive'; import { LoaderComponent } from './loader/loader.component'; import { LoadAsyncWrapperComponent } from './wrapper/load-async-wrapper.component'; -import { SkeletonModule } from '../skeleton/skeleton.module'; @NgModule({ declarations: [LoadAsyncDirective, LoadAsyncWrapperComponent, LoaderComponent], diff --git a/projects/components/src/load-async/loader/loader.component.ts b/projects/components/src/load-async/loader/loader.component.ts index 67752af67..af40fc155 100644 --- a/projects/components/src/load-async/loader/loader.component.ts +++ b/projects/components/src/load-async/loader/loader.component.ts @@ -1,7 +1,7 @@ import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core'; import { ImagesAssetPath } from '@hypertrace/assets-library'; -import { LoaderType } from '../load-async.service'; import { SkeletonType } from '../../skeleton/skeleton.component'; +import { LoaderType } from '../load-async.service'; @Component({ selector: 'ht-loader', diff --git a/projects/components/src/skeleton/skeleton.component.ts b/projects/components/src/skeleton/skeleton.component.ts index 12ddc400e..42dd9cc36 100644 --- a/projects/components/src/skeleton/skeleton.component.ts +++ b/projects/components/src/skeleton/skeleton.component.ts @@ -1,4 +1,4 @@ -import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core'; +import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; interface ContainerClass { skeleton: boolean; @@ -43,15 +43,13 @@ export const enum SkeletonType { changeDetection: ChangeDetectionStrategy.OnPush, styleUrls: ['./skeleton.component.scss'] }) -export class SkeletonComponent implements OnInit { +export class SkeletonComponent { @Input() public shapeStyle: SkeletonType = SkeletonType.Rectangle; @Input() public repeat: number = 1; @Input() public size: string = ''; - public ngOnInit() {} - public containerClass(): ContainerClass { return { skeleton: true, diff --git a/projects/components/src/skeleton/skeleton.module.ts b/projects/components/src/skeleton/skeleton.module.ts index c95e0b242..c4ee4d08e 100644 --- a/projects/components/src/skeleton/skeleton.module.ts +++ b/projects/components/src/skeleton/skeleton.module.ts @@ -1,6 +1,6 @@ +import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { SkeletonComponent } from './skeleton.component'; -import { CommonModule } from '@angular/common'; @NgModule({ declarations: [SkeletonComponent], From 3ef1fe2aebd0224350813a6e921f3d0025bd4029 Mon Sep 17 00:00:00 2001 From: Christian Quinn Date: Fri, 14 Jan 2022 11:04:15 -0400 Subject: [PATCH 07/25] style: minor style adjustments to skeletons --- .../components/src/skeleton/skeleton.component.scss | 10 ++++++---- projects/components/src/skeleton/skeleton.component.ts | 1 + 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/projects/components/src/skeleton/skeleton.component.scss b/projects/components/src/skeleton/skeleton.component.scss index 5c4eb43a8..747216d21 100644 --- a/projects/components/src/skeleton/skeleton.component.scss +++ b/projects/components/src/skeleton/skeleton.component.scss @@ -39,8 +39,10 @@ } .skeleton.skeleton-rectangle-text { + @include initial-location; height: 1.3rem; width: 90%; + margin: 10px; } .skeleton.skeleton-circle { @@ -50,15 +52,15 @@ } .skeleton.skeleton-square { - width: 3rem; - height: 3rem; + width: 2rem; + height: 2rem; } .skeleton.skeleton-table-row { + @include initial-location; height: 1.3rem; width: 90%; - - @include initial-location; + margin-left: 10px; } .skeleton.skeleton-repeating { diff --git a/projects/components/src/skeleton/skeleton.component.ts b/projects/components/src/skeleton/skeleton.component.ts index 42dd9cc36..2ac1b5336 100644 --- a/projects/components/src/skeleton/skeleton.component.ts +++ b/projects/components/src/skeleton/skeleton.component.ts @@ -20,6 +20,7 @@ export const enum SkeletonType { ListItem = 'list-item' } +// TODO 7872 Allow circle and donut to take the height of parent, with equal width. @Component({ selector: 'ht-skeleton', template: ` From 5fd455a2df7b3eac7be24dbd7801ae34110ad3c8 Mon Sep 17 00:00:00 2001 From: Christian Quinn Date: Fri, 14 Jan 2022 15:20:20 -0400 Subject: [PATCH 08/25] feat: added donut skeleton shape --- .../src/load-async/load-async.service.ts | 3 +- .../src/load-async/loader/loader.component.ts | 2 + .../src/skeleton/skeleton.component.scss | 70 +++++++++++++++---- .../src/skeleton/skeleton.component.ts | 6 +- 4 files changed, 65 insertions(+), 16 deletions(-) diff --git a/projects/components/src/load-async/load-async.service.ts b/projects/components/src/load-async/load-async.service.ts index 89b341ec4..ba688bc01 100644 --- a/projects/components/src/load-async/load-async.service.ts +++ b/projects/components/src/load-async/load-async.service.ts @@ -68,7 +68,8 @@ export const enum LoaderType { Square = 'square', Circle = 'circle', TableRow = 'table-row', - ListItem = 'list-item' + ListItem = 'list-item', + Donut = 'donut' } interface LoadingAsyncState { diff --git a/projects/components/src/load-async/loader/loader.component.ts b/projects/components/src/load-async/loader/loader.component.ts index af40fc155..97c2c13a0 100644 --- a/projects/components/src/load-async/loader/loader.component.ts +++ b/projects/components/src/load-async/loader/loader.component.ts @@ -60,6 +60,8 @@ export class LoaderComponent implements OnChanges { return SkeletonType.TableRow; case LoaderType.ListItem: return SkeletonType.ListItem; + case LoaderType.Donut: + return SkeletonType.Donut; default: return SkeletonType.Rectangle; } diff --git a/projects/components/src/skeleton/skeleton.component.scss b/projects/components/src/skeleton/skeleton.component.scss index 747216d21..3f5875a28 100644 --- a/projects/components/src/skeleton/skeleton.component.scss +++ b/projects/components/src/skeleton/skeleton.component.scss @@ -10,6 +10,34 @@ z-index: 1; background: linear-gradient(90deg, rgba(255, 255, 255, 0), rgba(255, 255, 255, 0.4), rgba(255, 255, 255, 0)); } +@keyframes skeleton-animation { + from { + transform: translateX(-100%); + } + to { + transform: translateX(100%); + } +} + +@mixin donut-animation { + content: ''; + animation: donut-spin 1.2s linear infinite; + transform-origin: 50% 0%; + height: 100%; + width: 100%; + position: absolute; + top: 50%; + left: 0; + background: linear-gradient(90deg, rgba(255, 255, 255, 0), rgba(255, 255, 255, 0.4), rgba(255, 255, 255, 0)); +} +@keyframes donut-spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} @mixin initial-location { top: initial; @@ -17,15 +45,17 @@ transform: initial; } -.skeleton { - position: relative; - background-color: #dee2e6; - overflow: hidden; - +@mixin block-parent-center { top: 50%; left: 50%; transform: translate(-50%, -50%); +} +.skeleton { + @include block-parent-center; + position: relative; + background-color: #dee2e6; + overflow: hidden; border-radius: 6px; } @@ -63,6 +93,27 @@ margin-left: 10px; } +.skeleton.skeleton-donut { + display: inline-block; + background-color: #dee2e6; + border-radius: 50%; + width: 40%; + padding-bottom: 40%; + + .donut-inner { + @include block-parent-center; + width: 70%; + height: 70%; + position: absolute; + background-color: white; + z-index: 1; + border-radius: 50%; + } +} +.skeleton.skeleton-donut::after { + @include donut-animation; +} + .skeleton.skeleton-repeating { margin-top: 1rem; } @@ -105,12 +156,3 @@ @include loading-animation; } } - -@keyframes skeleton-animation { - from { - transform: translateX(-100%); - } - to { - transform: translateX(100%); - } -} diff --git a/projects/components/src/skeleton/skeleton.component.ts b/projects/components/src/skeleton/skeleton.component.ts index 2ac1b5336..d93f4b39d 100644 --- a/projects/components/src/skeleton/skeleton.component.ts +++ b/projects/components/src/skeleton/skeleton.component.ts @@ -9,6 +9,7 @@ interface ContainerClass { 'skeleton-table-row': boolean; 'skeleton-list-item': boolean; 'skeleton-repeating': boolean; + 'skeleton-donut': boolean; } export const enum SkeletonType { @@ -17,7 +18,8 @@ export const enum SkeletonType { Square = 'square', Circle = 'circle', TableRow = 'table-row', - ListItem = 'list-item' + ListItem = 'list-item', + Donut = 'donut' } // TODO 7872 Allow circle and donut to take the height of parent, with equal width. @@ -30,6 +32,7 @@ export const enum SkeletonType {
+
@@ -60,6 +63,7 @@ export class SkeletonComponent { 'skeleton-rectangle-text': this.shapeStyle === 'rectangle-text', 'skeleton-table-row': this.shapeStyle === 'table-row', 'skeleton-list-item': this.shapeStyle === 'list-item', + 'skeleton-donut': this.shapeStyle === 'donut', 'skeleton-repeating': this.repeat > 1 }; } From 91a4832ab4a73da3e0c67b9d6f0d2582c69ec173 Mon Sep 17 00:00:00 2001 From: Christian Quinn Date: Fri, 14 Jan 2022 18:51:29 -0400 Subject: [PATCH 09/25] fix: requested changes --- .../src/load-async/loader/loader.component.ts | 23 ++- .../src/skeleton/skeleton.component.scss | 165 +++++++++--------- .../src/skeleton/skeleton.component.ts | 108 +++++++----- 3 files changed, 158 insertions(+), 138 deletions(-) diff --git a/projects/components/src/load-async/loader/loader.component.ts b/projects/components/src/load-async/loader/loader.component.ts index 97c2c13a0..6953603a6 100644 --- a/projects/components/src/load-async/loader/loader.component.ts +++ b/projects/components/src/load-async/loader/loader.component.ts @@ -8,8 +8,8 @@ import { LoaderType } from '../load-async.service'; styleUrls: ['./loader.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, template: ` -
- +
+ @@ -30,10 +30,17 @@ export class LoaderComponent implements OnChanges { public currentLoaderType: LoaderType = LoaderType.Spinner; + public isOldLoaderType: boolean = false; + public ngOnChanges(): void { this.currentLoaderType = this.loaderType ?? LoaderType.Spinner; - this.skeletonType = this.loaderToSkeletonTypeMap(this.currentLoaderType); + this.isOldLoaderType = + this.currentLoaderType === LoaderType.ExpandableRow || + this.currentLoaderType === LoaderType.Spinner || + this.currentLoaderType === LoaderType.Page; + + this.skeletonType = this.getSkeletonTypeForLoader(this.currentLoaderType); } public getImagePathFromType(loaderType: LoaderType): ImagesAssetPath { @@ -48,7 +55,7 @@ export class LoaderComponent implements OnChanges { } } - public loaderToSkeletonTypeMap(curLoaderType: LoaderType): SkeletonType { + public getSkeletonTypeForLoader(curLoaderType: LoaderType): SkeletonType { switch (curLoaderType) { case LoaderType.RectangleText: return SkeletonType.RectangleText; @@ -66,12 +73,4 @@ export class LoaderComponent implements OnChanges { return SkeletonType.Rectangle; } } - - public oldLoaderType(): boolean { - return ( - this.currentLoaderType === LoaderType.ExpandableRow || - this.currentLoaderType === LoaderType.Spinner || - this.currentLoaderType === LoaderType.Page - ); - } } diff --git a/projects/components/src/skeleton/skeleton.component.scss b/projects/components/src/skeleton/skeleton.component.scss index 3f5875a28..15831dd32 100644 --- a/projects/components/src/skeleton/skeleton.component.scss +++ b/projects/components/src/skeleton/skeleton.component.scss @@ -1,3 +1,5 @@ +@import 'color-palette'; + @mixin loading-animation { content: ''; animation: skeleton-animation 1.2s infinite; @@ -53,106 +55,107 @@ .skeleton { @include block-parent-center; + &::after { + @include loading-animation; + } position: relative; - background-color: #dee2e6; + background-color: $gray-2; overflow: hidden; border-radius: 6px; -} - -.skeleton::after { - @include loading-animation; -} -.skeleton.skeleton-rectangle { - height: 80%; - width: 80%; -} - -.skeleton.skeleton-rectangle-text { - @include initial-location; - height: 1.3rem; - width: 90%; - margin: 10px; -} - -.skeleton.skeleton-circle { - width: 2rem; - height: 2rem; - border-radius: 50%; -} - -.skeleton.skeleton-square { - width: 2rem; - height: 2rem; -} + &.skeleton-rectangle { + height: 80%; + width: 80%; + } -.skeleton.skeleton-table-row { - @include initial-location; - height: 1.3rem; - width: 90%; - margin-left: 10px; -} + &.skeleton-rectangle-text { + @include initial-location; + height: 1.3rem; + width: 90%; + margin: 10px; + } -.skeleton.skeleton-donut { - display: inline-block; - background-color: #dee2e6; - border-radius: 50%; - width: 40%; - padding-bottom: 40%; - - .donut-inner { - @include block-parent-center; - width: 70%; - height: 70%; - position: absolute; - background-color: white; - z-index: 1; + &.skeleton-circle { + width: 2rem; + height: 2rem; border-radius: 50%; } -} -.skeleton.skeleton-donut::after { - @include donut-animation; -} -.skeleton.skeleton-repeating { - margin-top: 1rem; -} + &.skeleton-square { + width: 2rem; + height: 2rem; + } -.skeleton.skeleton-list-item { - background-color: rgb(255, 255, 255); - @include initial-location; - display: flex; - justify-content: flex-start; + &.skeleton-table-row { + @include initial-location; + height: 1.3rem; + width: 90%; + margin-left: 10px; + } - .item-circle { - background-color: #dee2e6; - height: 2rem; - width: 2rem; + &.skeleton-donut { + display: inline-block; + background-color: $gray-2; border-radius: 50%; + width: 40%; + padding-bottom: 40%; + + .donut-inner { + @include block-parent-center; + width: 70%; + height: 70%; + position: absolute; + background-color: white; + z-index: 1; + border-radius: 50%; + } } - .item-circle::after { - @include loading-animation; + + &.skeleton-donut::after { + @include donut-animation; } - .item-column { + &.skeleton-list-item { + @include initial-location; + background-color: white; display: flex; - flex-direction: column; - padding-left: 1rem; - width: 100%; - } + justify-content: flex-start; - .item-column > div { - background-color: #dee2e6; - height: 0.9rem; - border-radius: 6px; - width: 90%; + .item-circle { + background-color: $gray-2; + height: 2.5rem; + width: 2.5rem; + border-radius: 50%; + } + .item-circle::after { + @include loading-animation; + } + + .item-column { + display: flex; + flex-direction: column; + padding-left: 1rem; + width: 100%; + + .item-line { + background-color: $gray-2; + height: 0.7rem; + border-radius: 6px; + width: 90%; + + &:last-child { + margin-top: 5px; + width: 80%; + } + } + } - &:last-child { - margin-top: 5px; - width: 80%; + .item-column > div::after { + @include loading-animation; } } - .item-column > div::after { - @include loading-animation; + + &.skeleton-repeating { + margin-top: 1rem; } } diff --git a/projects/components/src/skeleton/skeleton.component.ts b/projects/components/src/skeleton/skeleton.component.ts index d93f4b39d..406d86bc2 100644 --- a/projects/components/src/skeleton/skeleton.component.ts +++ b/projects/components/src/skeleton/skeleton.component.ts @@ -1,43 +1,22 @@ -import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; +import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core'; -interface ContainerClass { - skeleton: boolean; - 'skeleton-rectangle': boolean; - 'skeleton-square': boolean; - 'skeleton-circle': boolean; - 'skeleton-rectangle-text': boolean; - 'skeleton-table-row': boolean; - 'skeleton-list-item': boolean; - 'skeleton-repeating': boolean; - 'skeleton-donut': boolean; -} - -export const enum SkeletonType { - Rectangle = 'rectangle', - RectangleText = 'rectangle-text', - Square = 'square', - Circle = 'circle', - TableRow = 'table-row', - ListItem = 'list-item', - Donut = 'donut' -} - -// TODO 7872 Allow circle and donut to take the height of parent, with equal width. @Component({ selector: 'ht-skeleton', template: ` - + -
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
+
+
@@ -47,24 +26,63 @@ export const enum SkeletonType { changeDetection: ChangeDetectionStrategy.OnPush, styleUrls: ['./skeleton.component.scss'] }) -export class SkeletonComponent { - @Input() public shapeStyle: SkeletonType = SkeletonType.Rectangle; +export class SkeletonComponent implements OnChanges { + @Input() + public shapeStyle: SkeletonType = SkeletonType.Rectangle; + + @Input() + public repeat: number = 1; + + @Input() + public size: string = ''; + + public numberOfIterations: Array = Array(1).fill(1); - @Input() public repeat: number = 1; + public containerClass: ContainerClass; - @Input() public size: string = ''; + constructor() { + this.containerClass = this.getContainerClass(); + } + + ngOnChanges() { + this.numberOfIterations = this.repeat ? Array(this.repeat).fill(1) : Array(this.repeat).fill(1); + + this.containerClass = this.getContainerClass(); + } - public containerClass(): ContainerClass { + public getContainerClass(): ContainerClass { return { skeleton: true, - 'skeleton-rectangle': this.shapeStyle === 'rectangle', - 'skeleton-square': this.shapeStyle === 'square', - 'skeleton-circle': this.shapeStyle === 'circle', - 'skeleton-rectangle-text': this.shapeStyle === 'rectangle-text', - 'skeleton-table-row': this.shapeStyle === 'table-row', - 'skeleton-list-item': this.shapeStyle === 'list-item', - 'skeleton-donut': this.shapeStyle === 'donut', + 'skeleton-rectangle': this.shapeStyle === SkeletonType.Rectangle, + 'skeleton-square': this.shapeStyle === SkeletonType.Square, + 'skeleton-circle': this.shapeStyle === SkeletonType.Circle, + 'skeleton-rectangle-text': this.shapeStyle === SkeletonType.RectangleText, + 'skeleton-table-row': this.shapeStyle === SkeletonType.TableRow, + 'skeleton-list-item': this.shapeStyle === SkeletonType.ListItem, + 'skeleton-donut': this.shapeStyle === SkeletonType.Donut, 'skeleton-repeating': this.repeat > 1 }; } } + +interface ContainerClass { + skeleton: boolean; + 'skeleton-rectangle': boolean; + 'skeleton-square': boolean; + 'skeleton-circle': boolean; + 'skeleton-rectangle-text': boolean; + 'skeleton-table-row': boolean; + 'skeleton-list-item': boolean; + 'skeleton-repeating': boolean; + 'skeleton-donut': boolean; +} + +export const enum SkeletonType { + Rectangle = 'rectangle', + RectangleText = 'rectangle-text', + Square = 'square', + Circle = 'circle', + TableRow = 'table-row', + ListItem = 'list-item', + Donut = 'donut' +} From bf2b846c24559df8f0b23e5a76e02c3cb7191e12 Mon Sep 17 00:00:00 2001 From: Christian Quinn Date: Fri, 14 Jan 2022 19:04:02 -0400 Subject: [PATCH 10/25] fix: linting fixes --- projects/components/src/skeleton/skeleton.component.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/projects/components/src/skeleton/skeleton.component.ts b/projects/components/src/skeleton/skeleton.component.ts index 406d86bc2..276750776 100644 --- a/projects/components/src/skeleton/skeleton.component.ts +++ b/projects/components/src/skeleton/skeleton.component.ts @@ -36,16 +36,16 @@ export class SkeletonComponent implements OnChanges { @Input() public size: string = ''; - public numberOfIterations: Array = Array(1).fill(1); + public numberOfIterations: number[] = Array(1).fill(1); public containerClass: ContainerClass; - constructor() { + public constructor() { this.containerClass = this.getContainerClass(); } - ngOnChanges() { - this.numberOfIterations = this.repeat ? Array(this.repeat).fill(1) : Array(this.repeat).fill(1); + public ngOnChanges(): void { + this.numberOfIterations = Array(this.repeat).fill(1); this.containerClass = this.getContainerClass(); } From a6f5b7ecbadc3786c742d25cac95dafb54263f5b Mon Sep 17 00:00:00 2001 From: Christian Quinn Date: Sun, 16 Jan 2022 12:55:49 -0400 Subject: [PATCH 11/25] fix: default isOldLoaderFlag to true --- projects/components/src/load-async/loader/loader.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/components/src/load-async/loader/loader.component.ts b/projects/components/src/load-async/loader/loader.component.ts index 6953603a6..18ce920fc 100644 --- a/projects/components/src/load-async/loader/loader.component.ts +++ b/projects/components/src/load-async/loader/loader.component.ts @@ -30,7 +30,7 @@ export class LoaderComponent implements OnChanges { public currentLoaderType: LoaderType = LoaderType.Spinner; - public isOldLoaderType: boolean = false; + public isOldLoaderType: boolean = true; public ngOnChanges(): void { this.currentLoaderType = this.loaderType ?? LoaderType.Spinner; From 10483396cb5b477b870f2a3e55cb17d1e7c60cf2 Mon Sep 17 00:00:00 2001 From: Christian Quinn Date: Sun, 16 Jan 2022 16:00:23 -0400 Subject: [PATCH 12/25] fix: requested changes --- .../components/src/load-async/loader/loader.component.ts | 8 +++++++- projects/components/src/skeleton/skeleton.component.ts | 7 ++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/projects/components/src/load-async/loader/loader.component.ts b/projects/components/src/load-async/loader/loader.component.ts index 18ce920fc..7d4f2dba6 100644 --- a/projects/components/src/load-async/loader/loader.component.ts +++ b/projects/components/src/load-async/loader/loader.component.ts @@ -2,6 +2,7 @@ import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/c import { ImagesAssetPath } from '@hypertrace/assets-library'; import { SkeletonType } from '../../skeleton/skeleton.component'; import { LoaderType } from '../load-async.service'; +import { assertUnreachable } from '@hypertrace/common'; @Component({ selector: 'ht-loader', @@ -69,8 +70,13 @@ export class LoaderComponent implements OnChanges { return SkeletonType.ListItem; case LoaderType.Donut: return SkeletonType.Donut; - default: + case LoaderType.Rectangle: + case LoaderType.ExpandableRow: + case LoaderType.Page: + case LoaderType.Spinner: return SkeletonType.Rectangle; + default: + return assertUnreachable(curLoaderType); } } } diff --git a/projects/components/src/skeleton/skeleton.component.ts b/projects/components/src/skeleton/skeleton.component.ts index 276750776..fe48f7169 100644 --- a/projects/components/src/skeleton/skeleton.component.ts +++ b/projects/components/src/skeleton/skeleton.component.ts @@ -31,10 +31,7 @@ export class SkeletonComponent implements OnChanges { public shapeStyle: SkeletonType = SkeletonType.Rectangle; @Input() - public repeat: number = 1; - - @Input() - public size: string = ''; + public repeat: number | undefined = 1; public numberOfIterations: number[] = Array(1).fill(1); @@ -60,7 +57,7 @@ export class SkeletonComponent implements OnChanges { 'skeleton-table-row': this.shapeStyle === SkeletonType.TableRow, 'skeleton-list-item': this.shapeStyle === SkeletonType.ListItem, 'skeleton-donut': this.shapeStyle === SkeletonType.Donut, - 'skeleton-repeating': this.repeat > 1 + 'skeleton-repeating': !!(this.repeat && this.repeat > 1) }; } } From 3d048dd19cb83c7efbaae2cafe0972fab38f8c74 Mon Sep 17 00:00:00 2001 From: Christian Quinn Date: Mon, 17 Jan 2022 09:28:40 -0400 Subject: [PATCH 13/25] test: updated for loader component changes --- .../loader/loader.component.test.ts | 133 ++++++++++++++++++ 1 file changed, 133 insertions(+) diff --git a/projects/components/src/load-async/loader/loader.component.test.ts b/projects/components/src/load-async/loader/loader.component.test.ts index 5a22da4ea..b714dd51c 100644 --- a/projects/components/src/load-async/loader/loader.component.test.ts +++ b/projects/components/src/load-async/loader/loader.component.test.ts @@ -3,12 +3,15 @@ import { ImagesAssetPath } from '@hypertrace/assets-library'; import { createHostFactory, SpectatorHost } from '@ngneat/spectator/jest'; import { LoaderType } from '../load-async.service'; import { LoaderComponent } from './loader.component'; +import { MockComponent } from 'ng-mocks'; +import { SkeletonComponent, SkeletonType } from '../../skeleton/skeleton.component'; describe('Loader component', () => { let spectator: SpectatorHost; const createHost = createHostFactory({ component: LoaderComponent, + declarations: [MockComponent(SkeletonComponent)], imports: [CommonModule] }); @@ -16,6 +19,7 @@ describe('Loader component', () => { spectator = createHost(``); expect(spectator.query('.ht-loader')).toExist(); + expect(spectator.query('.ht-loader')).toHaveClass('flex-centered'); expect(spectator.query('.ht-loader img')).toExist(); expect(spectator.query('.ht-loader img')).toHaveClass(LoaderType.Page); expect(spectator.query('.ht-loader img')).toHaveAttribute('src', ImagesAssetPath.LoaderPage); @@ -25,6 +29,7 @@ describe('Loader component', () => { spectator = createHost(``); expect(spectator.query('.ht-loader')).toExist(); + expect(spectator.query('.ht-loader')).toHaveClass('flex-centered'); expect(spectator.query('.ht-loader img')).toExist(); expect(spectator.query('.ht-loader img')).toHaveClass(LoaderType.Spinner); expect(spectator.query('.ht-loader img')).toHaveAttribute('src', ImagesAssetPath.LoaderSpinner); @@ -34,6 +39,7 @@ describe('Loader component', () => { spectator = createHost(``); expect(spectator.query('.ht-loader')).toExist(); + expect(spectator.query('.ht-loader')).toHaveClass('flex-centered'); expect(spectator.query('.ht-loader img')).toExist(); expect(spectator.query('.ht-loader img')).toHaveClass(LoaderType.Spinner); expect(spectator.query('.ht-loader img')).toHaveAttribute('src', ImagesAssetPath.LoaderSpinner); @@ -43,8 +49,135 @@ describe('Loader component', () => { spectator = createHost(``); expect(spectator.query('.ht-loader')).toExist(); + expect(spectator.query('.ht-loader')).toHaveClass('flex-centered'); expect(spectator.query('.ht-loader img')).toExist(); expect(spectator.query('.ht-loader img')).toHaveClass(LoaderType.ExpandableRow); expect(spectator.query('.ht-loader img')).toHaveAttribute('src', ImagesAssetPath.LoaderExpandableRow); }); + + test('Should use old loader type by default', () => { + spectator = createHost(``); + + expect(spectator.component.isOldLoaderType).toBe(true); + expect(spectator.query(SkeletonComponent)).not.toExist(); + }); + + test('Should use corresponding skeleton component for loader type rectangle', () => { + spectator = createHost( + ``, + { + hostProps: { + repeatLoaderCount: '1' + } + } + ); + + expect(spectator.query('.ht-loader')).toExist(); + expect(spectator.query('.ht-loader')).not.toHaveClass('flex-centered'); + expect(spectator.query(SkeletonComponent)).toExist(); + expect(spectator.query(SkeletonComponent)).toHaveAttribute('shapeStyle', SkeletonType.Rectangle); + expect(spectator.query(SkeletonComponent)).toHaveAttribute('repeat', '1'); + }); + + test('Should use corresponding skeleton component for loader type rectangle text', () => { + spectator = createHost( + ``, + { + hostProps: { + repeatLoaderCount: '1' + } + } + ); + + expect(spectator.query('.ht-loader')).toExist(); + expect(spectator.query('.ht-loader')).not.toHaveClass('flex-centered'); + expect(spectator.query(SkeletonComponent)).toExist(); + expect(spectator.query(SkeletonComponent)).toHaveAttribute('shapeStyle', SkeletonType.RectangleText); + expect(spectator.query(SkeletonComponent)).toHaveAttribute('repeat', '1'); + }); + + test('Should use corresponding skeleton component for loader type circle', () => { + spectator = createHost( + ``, + { + hostProps: { + repeatLoaderCount: '1' + } + } + ); + + expect(spectator.query('.ht-loader')).toExist(); + expect(spectator.query('.ht-loader')).not.toHaveClass('flex-centered'); + expect(spectator.query(SkeletonComponent)).toExist(); + expect(spectator.query(SkeletonComponent)).toHaveAttribute('shapeStyle', SkeletonType.Circle); + expect(spectator.query(SkeletonComponent)).toHaveAttribute('repeat', '1'); + }); + + test('Should use corresponding skeleton component for loader type square', () => { + spectator = createHost( + ``, + { + hostProps: { + repeatLoaderCount: '1' + } + } + ); + + expect(spectator.query('.ht-loader')).toExist(); + expect(spectator.query('.ht-loader')).not.toHaveClass('flex-centered'); + expect(spectator.query(SkeletonComponent)).toExist(); + expect(spectator.query(SkeletonComponent)).toHaveAttribute('shapeStyle', SkeletonType.Square); + expect(spectator.query(SkeletonComponent)).toHaveAttribute('repeat', '1'); + }); + + test('Should use corresponding skeleton component for loader type table row', () => { + spectator = createHost( + ``, + { + hostProps: { + repeatLoaderCount: '4' + } + } + ); + + expect(spectator.query('.ht-loader')).toExist(); + expect(spectator.query('.ht-loader')).not.toHaveClass('flex-centered'); + expect(spectator.query(SkeletonComponent)).toExist(); + expect(spectator.query(SkeletonComponent)).toHaveAttribute('shapeStyle', SkeletonType.TableRow); + expect(spectator.query(SkeletonComponent)).toHaveAttribute('repeat', '4'); + }); + + test('Should use corresponding skeleton component for loader type donut', () => { + spectator = createHost( + ``, + { + hostProps: { + repeatLoaderCount: '1' + } + } + ); + + expect(spectator.query('.ht-loader')).toExist(); + expect(spectator.query('.ht-loader')).not.toHaveClass('flex-centered'); + expect(spectator.query(SkeletonComponent)).toExist(); + expect(spectator.query(SkeletonComponent)).toHaveAttribute('shapeStyle', SkeletonType.Donut); + expect(spectator.query(SkeletonComponent)).toHaveAttribute('repeat', '1'); + }); + + test('Should use corresponding skeleton component for loader type list item', () => { + spectator = createHost( + ``, + { + hostProps: { + repeatLoaderCount: '1' + } + } + ); + + expect(spectator.query('.ht-loader')).toExist(); + expect(spectator.query('.ht-loader')).not.toHaveClass('flex-centered'); + expect(spectator.query(SkeletonComponent)).toExist(); + expect(spectator.query(SkeletonComponent)).toHaveAttribute('shapeStyle', SkeletonType.ListItem); + expect(spectator.query(SkeletonComponent)).toHaveAttribute('repeat', '1'); + }); }); From dbdd5cfba8ab93ee27504d13abf1bb4dcaf4e40e Mon Sep 17 00:00:00 2001 From: Christian Quinn Date: Mon, 17 Jan 2022 10:17:30 -0400 Subject: [PATCH 14/25] fix: appeasing linter --- .../components/src/load-async/loader/loader.component.test.ts | 4 ++-- projects/components/src/load-async/loader/loader.component.ts | 2 +- projects/components/src/skeleton/skeleton.component.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/projects/components/src/load-async/loader/loader.component.test.ts b/projects/components/src/load-async/loader/loader.component.test.ts index b714dd51c..767f6718c 100644 --- a/projects/components/src/load-async/loader/loader.component.test.ts +++ b/projects/components/src/load-async/loader/loader.component.test.ts @@ -1,10 +1,10 @@ import { CommonModule } from '@angular/common'; import { ImagesAssetPath } from '@hypertrace/assets-library'; import { createHostFactory, SpectatorHost } from '@ngneat/spectator/jest'; -import { LoaderType } from '../load-async.service'; -import { LoaderComponent } from './loader.component'; import { MockComponent } from 'ng-mocks'; import { SkeletonComponent, SkeletonType } from '../../skeleton/skeleton.component'; +import { LoaderType } from '../load-async.service'; +import { LoaderComponent } from './loader.component'; describe('Loader component', () => { let spectator: SpectatorHost; diff --git a/projects/components/src/load-async/loader/loader.component.ts b/projects/components/src/load-async/loader/loader.component.ts index 7d4f2dba6..a078acf93 100644 --- a/projects/components/src/load-async/loader/loader.component.ts +++ b/projects/components/src/load-async/loader/loader.component.ts @@ -1,8 +1,8 @@ import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core'; import { ImagesAssetPath } from '@hypertrace/assets-library'; +import { assertUnreachable } from '@hypertrace/common'; import { SkeletonType } from '../../skeleton/skeleton.component'; import { LoaderType } from '../load-async.service'; -import { assertUnreachable } from '@hypertrace/common'; @Component({ selector: 'ht-loader', diff --git a/projects/components/src/skeleton/skeleton.component.ts b/projects/components/src/skeleton/skeleton.component.ts index fe48f7169..79ed06dc2 100644 --- a/projects/components/src/skeleton/skeleton.component.ts +++ b/projects/components/src/skeleton/skeleton.component.ts @@ -57,7 +57,7 @@ export class SkeletonComponent implements OnChanges { 'skeleton-table-row': this.shapeStyle === SkeletonType.TableRow, 'skeleton-list-item': this.shapeStyle === SkeletonType.ListItem, 'skeleton-donut': this.shapeStyle === SkeletonType.Donut, - 'skeleton-repeating': !!(this.repeat && this.repeat > 1) + 'skeleton-repeating': this.repeat !== undefined && this.repeat > 1 }; } } From 6d90a7681bc5b7791dae1b389bee4d3979e0baa8 Mon Sep 17 00:00:00 2001 From: Christian Quinn Date: Mon, 17 Jan 2022 16:18:25 -0400 Subject: [PATCH 15/25] test: skeleton component testing --- .../src/skeleton/skeleton.component.test.ts | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 projects/components/src/skeleton/skeleton.component.test.ts diff --git a/projects/components/src/skeleton/skeleton.component.test.ts b/projects/components/src/skeleton/skeleton.component.test.ts new file mode 100644 index 000000000..500b903f3 --- /dev/null +++ b/projects/components/src/skeleton/skeleton.component.test.ts @@ -0,0 +1,70 @@ +import { createHostFactory, SpectatorHost } from '@ngneat/spectator/jest'; +import { SkeletonComponent, SkeletonType } from './skeleton.component'; + +describe('Skeleton Component', () => { + const createHost = createHostFactory({ + component: SkeletonComponent + }); + + let spectator: SpectatorHost; + + test('Should only be one skeleton element by default', () => { + spectator = createHost(``); + + expect(spectator.query('.skeleton.skeleton-rectangle')).toExist(); + expect(spectator.query('.skeleton-repeating')).not.toExist(); + expect(spectator.queryAll('.skeleton.skeleton-rectangle').length).toEqual(1); + }); + + test('Should display number of skeleton elements equal to the repeat input', () => { + spectator = createHost(``); + spectator.setHostInput({ repeat: 3 }); + + expect(spectator.query('.skeleton.skeleton-list-item')).toExist(); + expect(spectator.query('.skeleton .item-circle')).toExist(); + expect(spectator.queryAll('.skeleton.skeleton-repeating')).toHaveLength(3); + }); + + test('Should match the skeleton type to the corresponding element', () => { + const skeletonInputData: { type: SkeletonType; repeat: number }[] = [ + { + type: SkeletonType.Donut, + repeat: 1 + }, + { + type: SkeletonType.RectangleText, + repeat: 2 + }, + { + type: SkeletonType.Rectangle, + repeat: 1 + }, + { + type: SkeletonType.Circle, + repeat: 1 + }, + { + type: SkeletonType.TableRow, + repeat: 3 + }, + { + type: SkeletonType.Square, + repeat: 1 + }, + { + type: SkeletonType.ListItem, + repeat: 2 + } + ]; + spectator = createHost(``); + + skeletonInputData.forEach(testConfig => { + spectator.setHostInput({ shapeStyle: testConfig.type }); + spectator.setHostInput({ repeat: testConfig.repeat }); + + const shapeContainerClass = `.skeleton-${testConfig.type}`; + expect(spectator.query(shapeContainerClass)).toExist(); + expect(spectator.queryAll(shapeContainerClass)).toHaveLength(testConfig.repeat); + }); + }); +}); From 91c7214de1464b8a9a83bef14579c40b3185df39 Mon Sep 17 00:00:00 2001 From: Christian Quinn Date: Tue, 18 Jan 2022 15:32:40 -0400 Subject: [PATCH 16/25] refactor: requested changes --- .../src/load-async/loader/loader.component.ts | 31 +++++++++++-------- .../wrapper/load-async-wrapper.component.ts | 2 +- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/projects/components/src/load-async/loader/loader.component.ts b/projects/components/src/load-async/loader/loader.component.ts index a078acf93..c1fa4864f 100644 --- a/projects/components/src/load-async/loader/loader.component.ts +++ b/projects/components/src/load-async/loader/loader.component.ts @@ -1,4 +1,4 @@ -import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core'; +import { ChangeDetectionStrategy, Component, Input, OnChanges, SimpleChanges } from '@angular/core'; import { ImagesAssetPath } from '@hypertrace/assets-library'; import { assertUnreachable } from '@hypertrace/common'; import { SkeletonType } from '../../skeleton/skeleton.component'; @@ -10,12 +10,12 @@ import { LoaderType } from '../load-async.service'; changeDetection: ChangeDetectionStrategy.OnPush, template: `
- - + + - - + +
` @@ -25,23 +25,28 @@ export class LoaderComponent implements OnChanges { public loaderType?: LoaderType; @Input() - public repeatLoaderCount?: number; + public repeatCount?: number; public skeletonType: SkeletonType = SkeletonType.Rectangle; public currentLoaderType: LoaderType = LoaderType.Spinner; + public imagePath: string = ''; + public isOldLoaderType: boolean = true; - public ngOnChanges(): void { - this.currentLoaderType = this.loaderType ?? LoaderType.Spinner; + public ngOnChanges(changes: SimpleChanges): void { + if (changes.loaderType) { + this.currentLoaderType = this.loaderType ?? LoaderType.Spinner; + this.imagePath = this.getImagePathFromType(this.currentLoaderType); - this.isOldLoaderType = - this.currentLoaderType === LoaderType.ExpandableRow || - this.currentLoaderType === LoaderType.Spinner || - this.currentLoaderType === LoaderType.Page; + this.isOldLoaderType = + this.currentLoaderType === LoaderType.ExpandableRow || + this.currentLoaderType === LoaderType.Spinner || + this.currentLoaderType === LoaderType.Page; - this.skeletonType = this.getSkeletonTypeForLoader(this.currentLoaderType); + this.skeletonType = this.getSkeletonTypeForLoader(this.currentLoaderType); + } } public getImagePathFromType(loaderType: LoaderType): ImagesAssetPath { diff --git a/projects/components/src/load-async/wrapper/load-async-wrapper.component.ts b/projects/components/src/load-async/wrapper/load-async-wrapper.component.ts index 96dcffb1f..bc222e0c0 100644 --- a/projects/components/src/load-async/wrapper/load-async-wrapper.component.ts +++ b/projects/components/src/load-async/wrapper/load-async-wrapper.component.ts @@ -14,7 +14,7 @@ export const ASYNC_WRAPPER_PARAMETERS$ = new InjectionToken - + From 17b08ee7766bbb6cb4d9360155a9eddb8ce58c7f Mon Sep 17 00:00:00 2001 From: Christian Quinn Date: Tue, 18 Jan 2022 15:47:02 -0400 Subject: [PATCH 17/25] fix: appeasing linter --- .../components/src/load-async/loader/loader.component.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/projects/components/src/load-async/loader/loader.component.ts b/projects/components/src/load-async/loader/loader.component.ts index c1fa4864f..69c431bf8 100644 --- a/projects/components/src/load-async/loader/loader.component.ts +++ b/projects/components/src/load-async/loader/loader.component.ts @@ -1,6 +1,6 @@ -import { ChangeDetectionStrategy, Component, Input, OnChanges, SimpleChanges } from '@angular/core'; +import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core'; import { ImagesAssetPath } from '@hypertrace/assets-library'; -import { assertUnreachable } from '@hypertrace/common'; +import { assertUnreachable, TypedSimpleChanges } from '@hypertrace/common'; import { SkeletonType } from '../../skeleton/skeleton.component'; import { LoaderType } from '../load-async.service'; @@ -35,7 +35,7 @@ export class LoaderComponent implements OnChanges { public isOldLoaderType: boolean = true; - public ngOnChanges(changes: SimpleChanges): void { + public ngOnChanges(changes: TypedSimpleChanges): void { if (changes.loaderType) { this.currentLoaderType = this.loaderType ?? LoaderType.Spinner; this.imagePath = this.getImagePathFromType(this.currentLoaderType); From 86212a4b638cd0192235feb8604b4ff9f58d0f71 Mon Sep 17 00:00:00 2001 From: Christian Quinn Date: Tue, 18 Jan 2022 16:09:02 -0400 Subject: [PATCH 18/25] refactor: tests to account for requested changes --- .../loader/loader.component.test.ts | 35 +++++++++---------- .../src/load-async/loader/loader.component.ts | 5 +-- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/projects/components/src/load-async/loader/loader.component.test.ts b/projects/components/src/load-async/loader/loader.component.test.ts index 767f6718c..17553cde9 100644 --- a/projects/components/src/load-async/loader/loader.component.test.ts +++ b/projects/components/src/load-async/loader/loader.component.test.ts @@ -64,10 +64,10 @@ describe('Loader component', () => { test('Should use corresponding skeleton component for loader type rectangle', () => { spectator = createHost( - ``, + ``, { hostProps: { - repeatLoaderCount: '1' + repeatCount: '1' } } ); @@ -81,10 +81,10 @@ describe('Loader component', () => { test('Should use corresponding skeleton component for loader type rectangle text', () => { spectator = createHost( - ``, + ``, { hostProps: { - repeatLoaderCount: '1' + repeatCount: '1' } } ); @@ -98,10 +98,10 @@ describe('Loader component', () => { test('Should use corresponding skeleton component for loader type circle', () => { spectator = createHost( - ``, + ``, { hostProps: { - repeatLoaderCount: '1' + repeatCount: '1' } } ); @@ -115,10 +115,10 @@ describe('Loader component', () => { test('Should use corresponding skeleton component for loader type square', () => { spectator = createHost( - ``, + ``, { hostProps: { - repeatLoaderCount: '1' + repeatCount: '1' } } ); @@ -132,10 +132,10 @@ describe('Loader component', () => { test('Should use corresponding skeleton component for loader type table row', () => { spectator = createHost( - ``, + ``, { hostProps: { - repeatLoaderCount: '4' + repeatCount: '4' } } ); @@ -148,14 +148,11 @@ describe('Loader component', () => { }); test('Should use corresponding skeleton component for loader type donut', () => { - spectator = createHost( - ``, - { - hostProps: { - repeatLoaderCount: '1' - } + spectator = createHost(``, { + hostProps: { + repeatCount: '1' } - ); + }); expect(spectator.query('.ht-loader')).toExist(); expect(spectator.query('.ht-loader')).not.toHaveClass('flex-centered'); @@ -166,10 +163,10 @@ describe('Loader component', () => { test('Should use corresponding skeleton component for loader type list item', () => { spectator = createHost( - ``, + ``, { hostProps: { - repeatLoaderCount: '1' + repeatCount: '1' } } ); diff --git a/projects/components/src/load-async/loader/loader.component.ts b/projects/components/src/load-async/loader/loader.component.ts index 69c431bf8..443ece36a 100644 --- a/projects/components/src/load-async/loader/loader.component.ts +++ b/projects/components/src/load-async/loader/loader.component.ts @@ -31,14 +31,13 @@ export class LoaderComponent implements OnChanges { public currentLoaderType: LoaderType = LoaderType.Spinner; - public imagePath: string = ''; + public imagePath: ImagesAssetPath = ImagesAssetPath.LoaderSpinner; public isOldLoaderType: boolean = true; public ngOnChanges(changes: TypedSimpleChanges): void { if (changes.loaderType) { this.currentLoaderType = this.loaderType ?? LoaderType.Spinner; - this.imagePath = this.getImagePathFromType(this.currentLoaderType); this.isOldLoaderType = this.currentLoaderType === LoaderType.ExpandableRow || @@ -47,6 +46,8 @@ export class LoaderComponent implements OnChanges { this.skeletonType = this.getSkeletonTypeForLoader(this.currentLoaderType); } + + this.imagePath = this.getImagePathFromType(this.currentLoaderType); } public getImagePathFromType(loaderType: LoaderType): ImagesAssetPath { From 8f19a6d6e59317230181f2b4926e4878b4e85c2b Mon Sep 17 00:00:00 2001 From: Christian Quinn Date: Wed, 19 Jan 2022 09:55:48 -0400 Subject: [PATCH 19/25] refactor: some of requested changes --- .../src/load-async/load-async.service.ts | 2 +- .../loader/loader.component.test.ts | 79 +++++++++++-------- .../src/load-async/loader/loader.component.ts | 33 ++++---- .../src/skeleton/skeleton.component.scss | 18 ++--- .../src/skeleton/skeleton.component.test.ts | 21 +++-- .../src/skeleton/skeleton.component.ts | 42 +++------- 6 files changed, 93 insertions(+), 102 deletions(-) diff --git a/projects/components/src/load-async/load-async.service.ts b/projects/components/src/load-async/load-async.service.ts index ba688bc01..39da64a14 100644 --- a/projects/components/src/load-async/load-async.service.ts +++ b/projects/components/src/load-async/load-async.service.ts @@ -64,7 +64,7 @@ export const enum LoaderType { ExpandableRow = 'expandable-row', Page = 'page', Rectangle = 'rectangle', - RectangleText = 'rectangle-text', + Text = 'text', Square = 'square', Circle = 'circle', TableRow = 'table-row', diff --git a/projects/components/src/load-async/loader/loader.component.test.ts b/projects/components/src/load-async/loader/loader.component.test.ts index 17553cde9..eea4924f5 100644 --- a/projects/components/src/load-async/loader/loader.component.test.ts +++ b/projects/components/src/load-async/loader/loader.component.test.ts @@ -67,33 +67,34 @@ describe('Loader component', () => { ``, { hostProps: { - repeatCount: '1' + repeatCount: 1 } } ); expect(spectator.query('.ht-loader')).toExist(); expect(spectator.query('.ht-loader')).not.toHaveClass('flex-centered'); - expect(spectator.query(SkeletonComponent)).toExist(); - expect(spectator.query(SkeletonComponent)).toHaveAttribute('shapeStyle', SkeletonType.Rectangle); - expect(spectator.query(SkeletonComponent)).toHaveAttribute('repeat', '1'); + + const skeletonComponent = spectator.query(SkeletonComponent); + expect(skeletonComponent).toExist(); + expect(skeletonComponent).toHaveAttribute('shapeStyle', SkeletonType.Rectangle); + expect(skeletonComponent?.repeat).toEqual(1); }); test('Should use corresponding skeleton component for loader type rectangle text', () => { - spectator = createHost( - ``, - { - hostProps: { - repeatCount: '1' - } + spectator = createHost(``, { + hostProps: { + repeatCount: 1 } - ); + }); expect(spectator.query('.ht-loader')).toExist(); expect(spectator.query('.ht-loader')).not.toHaveClass('flex-centered'); - expect(spectator.query(SkeletonComponent)).toExist(); - expect(spectator.query(SkeletonComponent)).toHaveAttribute('shapeStyle', SkeletonType.RectangleText); - expect(spectator.query(SkeletonComponent)).toHaveAttribute('repeat', '1'); + + const skeletonComponent = spectator.query(SkeletonComponent); + expect(skeletonComponent).toExist(); + expect(skeletonComponent).toHaveAttribute('shapeStyle', SkeletonType.Text); + expect(skeletonComponent?.repeat).toEqual(1); }); test('Should use corresponding skeleton component for loader type circle', () => { @@ -101,16 +102,18 @@ describe('Loader component', () => { ``, { hostProps: { - repeatCount: '1' + repeatCount: 1 } } ); expect(spectator.query('.ht-loader')).toExist(); expect(spectator.query('.ht-loader')).not.toHaveClass('flex-centered'); - expect(spectator.query(SkeletonComponent)).toExist(); - expect(spectator.query(SkeletonComponent)).toHaveAttribute('shapeStyle', SkeletonType.Circle); - expect(spectator.query(SkeletonComponent)).toHaveAttribute('repeat', '1'); + + const skeletonComponent = spectator.query(SkeletonComponent); + expect(skeletonComponent).toExist(); + expect(skeletonComponent).toHaveAttribute('shapeStyle', SkeletonType.Circle); + expect(skeletonComponent?.repeat).toEqual(1); }); test('Should use corresponding skeleton component for loader type square', () => { @@ -118,16 +121,18 @@ describe('Loader component', () => { ``, { hostProps: { - repeatCount: '1' + repeatCount: 1 } } ); expect(spectator.query('.ht-loader')).toExist(); expect(spectator.query('.ht-loader')).not.toHaveClass('flex-centered'); - expect(spectator.query(SkeletonComponent)).toExist(); - expect(spectator.query(SkeletonComponent)).toHaveAttribute('shapeStyle', SkeletonType.Square); - expect(spectator.query(SkeletonComponent)).toHaveAttribute('repeat', '1'); + + const skeletonComponent = spectator.query(SkeletonComponent); + expect(skeletonComponent).toExist(); + expect(skeletonComponent).toHaveAttribute('shapeStyle', SkeletonType.Square); + expect(skeletonComponent?.repeat).toEqual(1); }); test('Should use corresponding skeleton component for loader type table row', () => { @@ -135,30 +140,34 @@ describe('Loader component', () => { ``, { hostProps: { - repeatCount: '4' + repeatCount: 4 } } ); expect(spectator.query('.ht-loader')).toExist(); expect(spectator.query('.ht-loader')).not.toHaveClass('flex-centered'); - expect(spectator.query(SkeletonComponent)).toExist(); - expect(spectator.query(SkeletonComponent)).toHaveAttribute('shapeStyle', SkeletonType.TableRow); - expect(spectator.query(SkeletonComponent)).toHaveAttribute('repeat', '4'); + + const skeletonComponent = spectator.query(SkeletonComponent); + expect(skeletonComponent).toExist(); + expect(skeletonComponent).toHaveAttribute('shapeStyle', SkeletonType.TableRow); + expect(skeletonComponent?.repeat).toEqual(4); }); test('Should use corresponding skeleton component for loader type donut', () => { spectator = createHost(``, { hostProps: { - repeatCount: '1' + repeatCount: 1 } }); expect(spectator.query('.ht-loader')).toExist(); expect(spectator.query('.ht-loader')).not.toHaveClass('flex-centered'); - expect(spectator.query(SkeletonComponent)).toExist(); - expect(spectator.query(SkeletonComponent)).toHaveAttribute('shapeStyle', SkeletonType.Donut); - expect(spectator.query(SkeletonComponent)).toHaveAttribute('repeat', '1'); + + const skeletonComponent = spectator.query(SkeletonComponent); + expect(skeletonComponent).toExist(); + expect(skeletonComponent).toHaveAttribute('shapeStyle', SkeletonType.Donut); + expect(skeletonComponent?.repeat).toEqual(1); }); test('Should use corresponding skeleton component for loader type list item', () => { @@ -166,15 +175,17 @@ describe('Loader component', () => { ``, { hostProps: { - repeatCount: '1' + repeatCount: 1 } } ); expect(spectator.query('.ht-loader')).toExist(); expect(spectator.query('.ht-loader')).not.toHaveClass('flex-centered'); - expect(spectator.query(SkeletonComponent)).toExist(); - expect(spectator.query(SkeletonComponent)).toHaveAttribute('shapeStyle', SkeletonType.ListItem); - expect(spectator.query(SkeletonComponent)).toHaveAttribute('repeat', '1'); + + const skeletonComponent = spectator.query(SkeletonComponent); + expect(skeletonComponent).toExist(); + expect(skeletonComponent).toHaveAttribute('shapeStyle', SkeletonType.ListItem); + expect(skeletonComponent?.repeat).toEqual(1); }); }); diff --git a/projects/components/src/load-async/loader/loader.component.ts b/projects/components/src/load-async/loader/loader.component.ts index 443ece36a..a460aa0cc 100644 --- a/projects/components/src/load-async/loader/loader.component.ts +++ b/projects/components/src/load-async/loader/loader.component.ts @@ -1,6 +1,5 @@ import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core'; import { ImagesAssetPath } from '@hypertrace/assets-library'; -import { assertUnreachable, TypedSimpleChanges } from '@hypertrace/common'; import { SkeletonType } from '../../skeleton/skeleton.component'; import { LoaderType } from '../load-async.service'; @@ -35,19 +34,20 @@ export class LoaderComponent implements OnChanges { public isOldLoaderType: boolean = true; - public ngOnChanges(changes: TypedSimpleChanges): void { - if (changes.loaderType) { - this.currentLoaderType = this.loaderType ?? LoaderType.Spinner; - - this.isOldLoaderType = - this.currentLoaderType === LoaderType.ExpandableRow || - this.currentLoaderType === LoaderType.Spinner || - this.currentLoaderType === LoaderType.Page; + public ngOnChanges(): void { + this.currentLoaderType = this.loaderType ?? LoaderType.Spinner; + if ( + this.currentLoaderType === LoaderType.ExpandableRow || + this.currentLoaderType === LoaderType.Spinner || + this.currentLoaderType === LoaderType.Page + ) { + this.isOldLoaderType = true; + this.imagePath = this.getImagePathFromType(this.currentLoaderType); + } else { this.skeletonType = this.getSkeletonTypeForLoader(this.currentLoaderType); + this.isOldLoaderType = false; } - - this.imagePath = this.getImagePathFromType(this.currentLoaderType); } public getImagePathFromType(loaderType: LoaderType): ImagesAssetPath { @@ -64,8 +64,8 @@ export class LoaderComponent implements OnChanges { public getSkeletonTypeForLoader(curLoaderType: LoaderType): SkeletonType { switch (curLoaderType) { - case LoaderType.RectangleText: - return SkeletonType.RectangleText; + case LoaderType.Text: + return SkeletonType.Text; case LoaderType.Circle: return SkeletonType.Circle; case LoaderType.Square: @@ -76,13 +76,8 @@ export class LoaderComponent implements OnChanges { return SkeletonType.ListItem; case LoaderType.Donut: return SkeletonType.Donut; - case LoaderType.Rectangle: - case LoaderType.ExpandableRow: - case LoaderType.Page: - case LoaderType.Spinner: - return SkeletonType.Rectangle; default: - return assertUnreachable(curLoaderType); + return SkeletonType.Rectangle; } } } diff --git a/projects/components/src/skeleton/skeleton.component.scss b/projects/components/src/skeleton/skeleton.component.scss index 15831dd32..24b196237 100644 --- a/projects/components/src/skeleton/skeleton.component.scss +++ b/projects/components/src/skeleton/skeleton.component.scss @@ -63,37 +63,37 @@ overflow: hidden; border-radius: 6px; - &.skeleton-rectangle { + &.rectangle { height: 80%; width: 80%; } - &.skeleton-rectangle-text { + &.text { @include initial-location; height: 1.3rem; width: 90%; margin: 10px; } - &.skeleton-circle { + &.circle { width: 2rem; height: 2rem; border-radius: 50%; } - &.skeleton-square { + &.square { width: 2rem; height: 2rem; } - &.skeleton-table-row { + &.table-row { @include initial-location; height: 1.3rem; width: 90%; margin-left: 10px; } - &.skeleton-donut { + &.donut { display: inline-block; background-color: $gray-2; border-radius: 50%; @@ -111,11 +111,11 @@ } } - &.skeleton-donut::after { + &.donut::after { @include donut-animation; } - &.skeleton-list-item { + &.list-item { @include initial-location; background-color: white; display: flex; @@ -155,7 +155,7 @@ } } - &.skeleton-repeating { + &.repeating { margin-top: 1rem; } } diff --git a/projects/components/src/skeleton/skeleton.component.test.ts b/projects/components/src/skeleton/skeleton.component.test.ts index 500b903f3..7c1a49f84 100644 --- a/projects/components/src/skeleton/skeleton.component.test.ts +++ b/projects/components/src/skeleton/skeleton.component.test.ts @@ -11,18 +11,18 @@ describe('Skeleton Component', () => { test('Should only be one skeleton element by default', () => { spectator = createHost(``); - expect(spectator.query('.skeleton.skeleton-rectangle')).toExist(); - expect(spectator.query('.skeleton-repeating')).not.toExist(); - expect(spectator.queryAll('.skeleton.skeleton-rectangle').length).toEqual(1); + expect(spectator.query('.skeleton.rectangle')).toExist(); + expect(spectator.query('.repeating')).not.toExist(); + expect(spectator.queryAll('.skeleton.rectangle').length).toEqual(1); }); test('Should display number of skeleton elements equal to the repeat input', () => { spectator = createHost(``); spectator.setHostInput({ repeat: 3 }); - expect(spectator.query('.skeleton.skeleton-list-item')).toExist(); + expect(spectator.query('.skeleton.list-item')).toExist(); expect(spectator.query('.skeleton .item-circle')).toExist(); - expect(spectator.queryAll('.skeleton.skeleton-repeating')).toHaveLength(3); + expect(spectator.queryAll('.skeleton.repeating')).toHaveLength(3); }); test('Should match the skeleton type to the corresponding element', () => { @@ -32,7 +32,7 @@ describe('Skeleton Component', () => { repeat: 1 }, { - type: SkeletonType.RectangleText, + type: SkeletonType.Text, repeat: 2 }, { @@ -56,13 +56,18 @@ describe('Skeleton Component', () => { repeat: 2 } ]; - spectator = createHost(``); + spectator = createHost(``, { + hostProps: { + shapeStyle: SkeletonType.Donut, + repeat: 1 + } + }); skeletonInputData.forEach(testConfig => { spectator.setHostInput({ shapeStyle: testConfig.type }); spectator.setHostInput({ repeat: testConfig.repeat }); - const shapeContainerClass = `.skeleton-${testConfig.type}`; + const shapeContainerClass = `.${testConfig.type}`; expect(spectator.query(shapeContainerClass)).toExist(); expect(spectator.queryAll(shapeContainerClass)).toHaveLength(testConfig.repeat); }); diff --git a/projects/components/src/skeleton/skeleton.component.ts b/projects/components/src/skeleton/skeleton.component.ts index 79ed06dc2..384b68d44 100644 --- a/projects/components/src/skeleton/skeleton.component.ts +++ b/projects/components/src/skeleton/skeleton.component.ts @@ -5,10 +5,6 @@ import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/c template: ` -
-
-
-
@@ -19,7 +15,7 @@ import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/c
-
+
`, @@ -35,7 +31,7 @@ export class SkeletonComponent implements OnChanges { public numberOfIterations: number[] = Array(1).fill(1); - public containerClass: ContainerClass; + public containerClass: string[]; public constructor() { this.containerClass = this.getContainerClass(); @@ -47,36 +43,20 @@ export class SkeletonComponent implements OnChanges { this.containerClass = this.getContainerClass(); } - public getContainerClass(): ContainerClass { - return { - skeleton: true, - 'skeleton-rectangle': this.shapeStyle === SkeletonType.Rectangle, - 'skeleton-square': this.shapeStyle === SkeletonType.Square, - 'skeleton-circle': this.shapeStyle === SkeletonType.Circle, - 'skeleton-rectangle-text': this.shapeStyle === SkeletonType.RectangleText, - 'skeleton-table-row': this.shapeStyle === SkeletonType.TableRow, - 'skeleton-list-item': this.shapeStyle === SkeletonType.ListItem, - 'skeleton-donut': this.shapeStyle === SkeletonType.Donut, - 'skeleton-repeating': this.repeat !== undefined && this.repeat > 1 - }; - } -} + public getContainerClass(): string[] { + const classes = ['skeleton', this.shapeStyle]; -interface ContainerClass { - skeleton: boolean; - 'skeleton-rectangle': boolean; - 'skeleton-square': boolean; - 'skeleton-circle': boolean; - 'skeleton-rectangle-text': boolean; - 'skeleton-table-row': boolean; - 'skeleton-list-item': boolean; - 'skeleton-repeating': boolean; - 'skeleton-donut': boolean; + if (this.repeat !== undefined && this.repeat > 1) { + classes.push('repeating'); + } + + return classes; + } } export const enum SkeletonType { Rectangle = 'rectangle', - RectangleText = 'rectangle-text', + Text = 'text', Square = 'square', Circle = 'circle', TableRow = 'table-row', From 48418e00f1bb537912efa6085f14ee2f9a75895f Mon Sep 17 00:00:00 2001 From: Christian Quinn Date: Wed, 19 Jan 2022 10:29:08 -0400 Subject: [PATCH 20/25] refactor: to appease linter with switch --- .../src/load-async/loader/loader.component.ts | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/projects/components/src/load-async/loader/loader.component.ts b/projects/components/src/load-async/loader/loader.component.ts index a460aa0cc..3ad69c96a 100644 --- a/projects/components/src/load-async/loader/loader.component.ts +++ b/projects/components/src/load-async/loader/loader.component.ts @@ -37,16 +37,16 @@ export class LoaderComponent implements OnChanges { public ngOnChanges(): void { this.currentLoaderType = this.loaderType ?? LoaderType.Spinner; - if ( - this.currentLoaderType === LoaderType.ExpandableRow || - this.currentLoaderType === LoaderType.Spinner || - this.currentLoaderType === LoaderType.Page - ) { - this.isOldLoaderType = true; - this.imagePath = this.getImagePathFromType(this.currentLoaderType); - } else { - this.skeletonType = this.getSkeletonTypeForLoader(this.currentLoaderType); - this.isOldLoaderType = false; + switch (this.currentLoaderType) { + case LoaderType.Spinner: + case LoaderType.ExpandableRow: + case LoaderType.Page: + this.isOldLoaderType = true; + this.imagePath = this.getImagePathFromType(this.currentLoaderType); + break; + default: + this.skeletonType = this.getSkeletonTypeForLoader(this.currentLoaderType); + this.isOldLoaderType = false; } } From c99cebef22b4a8e8a4cb853af3ef491835e9be1f Mon Sep 17 00:00:00 2001 From: Christian Quinn Date: Wed, 19 Jan 2022 16:41:41 -0400 Subject: [PATCH 21/25] refactor: requested changes --- .../src/load-async/load-async.service.ts | 15 ++-- .../loader/loader.component.test.ts | 80 ++++--------------- .../src/load-async/loader/loader.component.ts | 72 ++++++++--------- .../wrapper/load-async-wrapper.component.ts | 2 +- projects/components/src/public-api.ts | 3 + .../src/skeleton/skeleton.component.test.ts | 29 +++---- .../src/skeleton/skeleton.component.ts | 21 +++-- 7 files changed, 84 insertions(+), 138 deletions(-) diff --git a/projects/components/src/load-async/load-async.service.ts b/projects/components/src/load-async/load-async.service.ts index 39da64a14..f6b120e24 100644 --- a/projects/components/src/load-async/load-async.service.ts +++ b/projects/components/src/load-async/load-async.service.ts @@ -4,6 +4,7 @@ import { CustomError } from '@hypertrace/common'; import { Observable, of } from 'rxjs'; import { catchError, defaultIfEmpty, map, startWith } from 'rxjs/operators'; import { LoadAsyncStateType } from './load-async-state.type'; +import { SkeletonType } from '../skeleton/skeleton.component'; @Injectable({ providedIn: 'root' }) export class LoadAsyncService { @@ -59,17 +60,12 @@ export interface LoadAsyncConfig { export type AsyncState = LoadingAsyncState | SuccessAsyncState | NoDataOrErrorAsyncState; -export const enum LoaderType { +export type LoaderType = ImgLoaderType | SkeletonType; + +export const enum ImgLoaderType { Spinner = 'spinner', ExpandableRow = 'expandable-row', - Page = 'page', - Rectangle = 'rectangle', - Text = 'text', - Square = 'square', - Circle = 'circle', - TableRow = 'table-row', - ListItem = 'list-item', - Donut = 'donut' + Page = 'page' } interface LoadingAsyncState { @@ -87,7 +83,6 @@ interface NoDataOrErrorAsyncState { interface LoadingStateConfig { loaderType?: LoaderType; - repeatCount?: number; } interface NoDataOrErrorStateConfig { diff --git a/projects/components/src/load-async/loader/loader.component.test.ts b/projects/components/src/load-async/loader/loader.component.test.ts index eea4924f5..0d9d58675 100644 --- a/projects/components/src/load-async/loader/loader.component.test.ts +++ b/projects/components/src/load-async/loader/loader.component.test.ts @@ -3,7 +3,7 @@ import { ImagesAssetPath } from '@hypertrace/assets-library'; import { createHostFactory, SpectatorHost } from '@ngneat/spectator/jest'; import { MockComponent } from 'ng-mocks'; import { SkeletonComponent, SkeletonType } from '../../skeleton/skeleton.component'; -import { LoaderType } from '../load-async.service'; +import { ImgLoaderType } from '../load-async.service'; import { LoaderComponent } from './loader.component'; describe('Loader component', () => { @@ -16,12 +16,12 @@ describe('Loader component', () => { }); test('Loader component when loader type is page', () => { - spectator = createHost(``); + spectator = createHost(``); expect(spectator.query('.ht-loader')).toExist(); expect(spectator.query('.ht-loader')).toHaveClass('flex-centered'); expect(spectator.query('.ht-loader img')).toExist(); - expect(spectator.query('.ht-loader img')).toHaveClass(LoaderType.Page); + expect(spectator.query('.ht-loader img')).toHaveClass(ImgLoaderType.Page); expect(spectator.query('.ht-loader img')).toHaveAttribute('src', ImagesAssetPath.LoaderPage); }); @@ -31,27 +31,27 @@ describe('Loader component', () => { expect(spectator.query('.ht-loader')).toExist(); expect(spectator.query('.ht-loader')).toHaveClass('flex-centered'); expect(spectator.query('.ht-loader img')).toExist(); - expect(spectator.query('.ht-loader img')).toHaveClass(LoaderType.Spinner); + expect(spectator.query('.ht-loader img')).toHaveClass(ImgLoaderType.Spinner); expect(spectator.query('.ht-loader img')).toHaveAttribute('src', ImagesAssetPath.LoaderSpinner); }); test('Loader component when loader type is spinner', () => { - spectator = createHost(``); + spectator = createHost(``); expect(spectator.query('.ht-loader')).toExist(); expect(spectator.query('.ht-loader')).toHaveClass('flex-centered'); expect(spectator.query('.ht-loader img')).toExist(); - expect(spectator.query('.ht-loader img')).toHaveClass(LoaderType.Spinner); + expect(spectator.query('.ht-loader img')).toHaveClass(ImgLoaderType.Spinner); expect(spectator.query('.ht-loader img')).toHaveAttribute('src', ImagesAssetPath.LoaderSpinner); }); test('Loader component loader type is expandable row', () => { - spectator = createHost(``); + spectator = createHost(``); expect(spectator.query('.ht-loader')).toExist(); expect(spectator.query('.ht-loader')).toHaveClass('flex-centered'); expect(spectator.query('.ht-loader img')).toExist(); - expect(spectator.query('.ht-loader img')).toHaveClass(LoaderType.ExpandableRow); + expect(spectator.query('.ht-loader img')).toHaveClass(ImgLoaderType.ExpandableRow); expect(spectator.query('.ht-loader img')).toHaveAttribute('src', ImagesAssetPath.LoaderExpandableRow); }); @@ -63,14 +63,7 @@ describe('Loader component', () => { }); test('Should use corresponding skeleton component for loader type rectangle', () => { - spectator = createHost( - ``, - { - hostProps: { - repeatCount: 1 - } - } - ); + spectator = createHost(``); expect(spectator.query('.ht-loader')).toExist(); expect(spectator.query('.ht-loader')).not.toHaveClass('flex-centered'); @@ -78,15 +71,10 @@ describe('Loader component', () => { const skeletonComponent = spectator.query(SkeletonComponent); expect(skeletonComponent).toExist(); expect(skeletonComponent).toHaveAttribute('shapeStyle', SkeletonType.Rectangle); - expect(skeletonComponent?.repeat).toEqual(1); }); test('Should use corresponding skeleton component for loader type rectangle text', () => { - spectator = createHost(``, { - hostProps: { - repeatCount: 1 - } - }); + spectator = createHost(``); expect(spectator.query('.ht-loader')).toExist(); expect(spectator.query('.ht-loader')).not.toHaveClass('flex-centered'); @@ -94,18 +82,10 @@ describe('Loader component', () => { const skeletonComponent = spectator.query(SkeletonComponent); expect(skeletonComponent).toExist(); expect(skeletonComponent).toHaveAttribute('shapeStyle', SkeletonType.Text); - expect(skeletonComponent?.repeat).toEqual(1); }); test('Should use corresponding skeleton component for loader type circle', () => { - spectator = createHost( - ``, - { - hostProps: { - repeatCount: 1 - } - } - ); + spectator = createHost(``); expect(spectator.query('.ht-loader')).toExist(); expect(spectator.query('.ht-loader')).not.toHaveClass('flex-centered'); @@ -113,18 +93,10 @@ describe('Loader component', () => { const skeletonComponent = spectator.query(SkeletonComponent); expect(skeletonComponent).toExist(); expect(skeletonComponent).toHaveAttribute('shapeStyle', SkeletonType.Circle); - expect(skeletonComponent?.repeat).toEqual(1); }); test('Should use corresponding skeleton component for loader type square', () => { - spectator = createHost( - ``, - { - hostProps: { - repeatCount: 1 - } - } - ); + spectator = createHost(``); expect(spectator.query('.ht-loader')).toExist(); expect(spectator.query('.ht-loader')).not.toHaveClass('flex-centered'); @@ -132,18 +104,10 @@ describe('Loader component', () => { const skeletonComponent = spectator.query(SkeletonComponent); expect(skeletonComponent).toExist(); expect(skeletonComponent).toHaveAttribute('shapeStyle', SkeletonType.Square); - expect(skeletonComponent?.repeat).toEqual(1); }); test('Should use corresponding skeleton component for loader type table row', () => { - spectator = createHost( - ``, - { - hostProps: { - repeatCount: 4 - } - } - ); + spectator = createHost(``); expect(spectator.query('.ht-loader')).toExist(); expect(spectator.query('.ht-loader')).not.toHaveClass('flex-centered'); @@ -151,15 +115,10 @@ describe('Loader component', () => { const skeletonComponent = spectator.query(SkeletonComponent); expect(skeletonComponent).toExist(); expect(skeletonComponent).toHaveAttribute('shapeStyle', SkeletonType.TableRow); - expect(skeletonComponent?.repeat).toEqual(4); }); test('Should use corresponding skeleton component for loader type donut', () => { - spectator = createHost(``, { - hostProps: { - repeatCount: 1 - } - }); + spectator = createHost(``); expect(spectator.query('.ht-loader')).toExist(); expect(spectator.query('.ht-loader')).not.toHaveClass('flex-centered'); @@ -167,18 +126,10 @@ describe('Loader component', () => { const skeletonComponent = spectator.query(SkeletonComponent); expect(skeletonComponent).toExist(); expect(skeletonComponent).toHaveAttribute('shapeStyle', SkeletonType.Donut); - expect(skeletonComponent?.repeat).toEqual(1); }); test('Should use corresponding skeleton component for loader type list item', () => { - spectator = createHost( - ``, - { - hostProps: { - repeatCount: 1 - } - } - ); + spectator = createHost(``); expect(spectator.query('.ht-loader')).toExist(); expect(spectator.query('.ht-loader')).not.toHaveClass('flex-centered'); @@ -186,6 +137,5 @@ describe('Loader component', () => { const skeletonComponent = spectator.query(SkeletonComponent); expect(skeletonComponent).toExist(); expect(skeletonComponent).toHaveAttribute('shapeStyle', SkeletonType.ListItem); - expect(skeletonComponent?.repeat).toEqual(1); }); }); diff --git a/projects/components/src/load-async/loader/loader.component.ts b/projects/components/src/load-async/loader/loader.component.ts index 3ad69c96a..9695e95e6 100644 --- a/projects/components/src/load-async/loader/loader.component.ts +++ b/projects/components/src/load-async/loader/loader.component.ts @@ -1,7 +1,8 @@ import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core'; import { ImagesAssetPath } from '@hypertrace/assets-library'; import { SkeletonType } from '../../skeleton/skeleton.component'; -import { LoaderType } from '../load-async.service'; +import { ImgLoaderType, LoaderType } from '../load-async.service'; +import { assertUnreachable } from '@hypertrace/common'; @Component({ selector: 'ht-loader', @@ -10,7 +11,7 @@ import { LoaderType } from '../load-async.service'; template: `
- + @@ -23,61 +24,54 @@ export class LoaderComponent implements OnChanges { @Input() public loaderType?: LoaderType; - @Input() - public repeatCount?: number; - public skeletonType: SkeletonType = SkeletonType.Rectangle; - public currentLoaderType: LoaderType = LoaderType.Spinner; + public currentLoaderType: LoaderType = ImgLoaderType.Spinner; public imagePath: ImagesAssetPath = ImagesAssetPath.LoaderSpinner; public isOldLoaderType: boolean = true; public ngOnChanges(): void { - this.currentLoaderType = this.loaderType ?? LoaderType.Spinner; + this.currentLoaderType = this.loaderType ?? ImgLoaderType.Spinner; - switch (this.currentLoaderType) { - case LoaderType.Spinner: - case LoaderType.ExpandableRow: - case LoaderType.Page: - this.isOldLoaderType = true; - this.imagePath = this.getImagePathFromType(this.currentLoaderType); - break; - default: - this.skeletonType = this.getSkeletonTypeForLoader(this.currentLoaderType); - this.isOldLoaderType = false; + if (this.determineIfOldLoaderType(this.currentLoaderType)) { + this.isOldLoaderType = true; + this.imagePath = this.getImagePathFromType(this.currentLoaderType as ImgLoaderType); + } else { + this.isOldLoaderType = false; + this.skeletonType = this.currentLoaderType as SkeletonType; } } - public getImagePathFromType(loaderType: LoaderType): ImagesAssetPath { + public determineIfOldLoaderType(loaderType: LoaderType) { switch (loaderType) { - case LoaderType.ExpandableRow: - return ImagesAssetPath.LoaderExpandableRow; - case LoaderType.Page: - return ImagesAssetPath.LoaderPage; - case LoaderType.Spinner: + case ImgLoaderType.Spinner: + case ImgLoaderType.ExpandableRow: + case ImgLoaderType.Page: + return true; + case SkeletonType.Circle: + case SkeletonType.Text: + case SkeletonType.ListItem: + case SkeletonType.Rectangle: + case SkeletonType.Square: + case SkeletonType.TableRow: + case SkeletonType.Donut: + return false; default: - return ImagesAssetPath.LoaderSpinner; + return assertUnreachable(loaderType); } } - public getSkeletonTypeForLoader(curLoaderType: LoaderType): SkeletonType { - switch (curLoaderType) { - case LoaderType.Text: - return SkeletonType.Text; - case LoaderType.Circle: - return SkeletonType.Circle; - case LoaderType.Square: - return SkeletonType.Square; - case LoaderType.TableRow: - return SkeletonType.TableRow; - case LoaderType.ListItem: - return SkeletonType.ListItem; - case LoaderType.Donut: - return SkeletonType.Donut; + public getImagePathFromType(loaderType: ImgLoaderType): ImagesAssetPath { + switch (loaderType) { + case ImgLoaderType.ExpandableRow: + return ImagesAssetPath.LoaderExpandableRow; + case ImgLoaderType.Page: + return ImagesAssetPath.LoaderPage; + case ImgLoaderType.Spinner: default: - return SkeletonType.Rectangle; + return ImagesAssetPath.LoaderSpinner; } } } diff --git a/projects/components/src/load-async/wrapper/load-async-wrapper.component.ts b/projects/components/src/load-async/wrapper/load-async-wrapper.component.ts index bc222e0c0..13c3b268c 100644 --- a/projects/components/src/load-async/wrapper/load-async-wrapper.component.ts +++ b/projects/components/src/load-async/wrapper/load-async-wrapper.component.ts @@ -14,7 +14,7 @@ export const ASYNC_WRAPPER_PARAMETERS$ = new InjectionToken - + diff --git a/projects/components/src/public-api.ts b/projects/components/src/public-api.ts index 3d030055d..d4400cb0f 100644 --- a/projects/components/src/public-api.ts +++ b/projects/components/src/public-api.ts @@ -181,6 +181,9 @@ export * from './load-async/load-async.module'; export * from './load-async/load-async.service'; export * from './load-async/load-async-state.type'; +// Skeleton +export * from './skeleton/skeleton.component'; + // Message Display export { MessageDisplayComponent } from './message-display/message-display.component'; export { MessageDisplayModule } from './message-display/message-display.module'; diff --git a/projects/components/src/skeleton/skeleton.component.test.ts b/projects/components/src/skeleton/skeleton.component.test.ts index 7c1a49f84..fa9171c65 100644 --- a/projects/components/src/skeleton/skeleton.component.test.ts +++ b/projects/components/src/skeleton/skeleton.component.test.ts @@ -17,59 +17,56 @@ describe('Skeleton Component', () => { }); test('Should display number of skeleton elements equal to the repeat input', () => { - spectator = createHost(``); - spectator.setHostInput({ repeat: 3 }); + spectator = createHost(``); expect(spectator.query('.skeleton.list-item')).toExist(); expect(spectator.query('.skeleton .item-circle')).toExist(); - expect(spectator.queryAll('.skeleton.repeating')).toHaveLength(3); + expect(spectator.queryAll('.skeleton.repeating')).toHaveLength(4); }); test('Should match the skeleton type to the corresponding element', () => { - const skeletonInputData: { type: SkeletonType; repeat: number }[] = [ + const skeletonInputData: { type: SkeletonType; expectedRepeat: number }[] = [ { type: SkeletonType.Donut, - repeat: 1 + expectedRepeat: 1 }, { type: SkeletonType.Text, - repeat: 2 + expectedRepeat: 1 }, { type: SkeletonType.Rectangle, - repeat: 1 + expectedRepeat: 1 }, { type: SkeletonType.Circle, - repeat: 1 + expectedRepeat: 1 }, { type: SkeletonType.TableRow, - repeat: 3 + expectedRepeat: 5 }, { type: SkeletonType.Square, - repeat: 1 + expectedRepeat: 1 }, { type: SkeletonType.ListItem, - repeat: 2 + expectedRepeat: 4 } ]; - spectator = createHost(``, { + spectator = createHost(``, { hostProps: { - shapeStyle: SkeletonType.Donut, - repeat: 1 + shapeStyle: SkeletonType.Donut } }); skeletonInputData.forEach(testConfig => { spectator.setHostInput({ shapeStyle: testConfig.type }); - spectator.setHostInput({ repeat: testConfig.repeat }); const shapeContainerClass = `.${testConfig.type}`; expect(spectator.query(shapeContainerClass)).toExist(); - expect(spectator.queryAll(shapeContainerClass)).toHaveLength(testConfig.repeat); + expect(spectator.queryAll(shapeContainerClass)).toHaveLength(testConfig.expectedRepeat); }); }); }); diff --git a/projects/components/src/skeleton/skeleton.component.ts b/projects/components/src/skeleton/skeleton.component.ts index 384b68d44..368b3f0f6 100644 --- a/projects/components/src/skeleton/skeleton.component.ts +++ b/projects/components/src/skeleton/skeleton.component.ts @@ -3,7 +3,7 @@ import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/c @Component({ selector: 'ht-skeleton', template: ` - +
@@ -26,10 +26,7 @@ export class SkeletonComponent implements OnChanges { @Input() public shapeStyle: SkeletonType = SkeletonType.Rectangle; - @Input() - public repeat: number | undefined = 1; - - public numberOfIterations: number[] = Array(1).fill(1); + public iterationsArray: number[] = Array(1).fill(1); public containerClass: string[]; @@ -38,15 +35,25 @@ export class SkeletonComponent implements OnChanges { } public ngOnChanges(): void { - this.numberOfIterations = Array(this.repeat).fill(1); + this.iterationsArray = this.getIterationsArray(); this.containerClass = this.getContainerClass(); } + public getIterationsArray(): number[] { + if (this.shapeStyle === SkeletonType.TableRow) { + return Array(5).fill(1); + } else if (this.shapeStyle === SkeletonType.ListItem) { + return Array(4).fill(1); + } else { + return Array(1).fill(1); + } + } + public getContainerClass(): string[] { const classes = ['skeleton', this.shapeStyle]; - if (this.repeat !== undefined && this.repeat > 1) { + if (this.shapeStyle === SkeletonType.TableRow || this.shapeStyle === SkeletonType.ListItem) { classes.push('repeating'); } From 429fc039c3864e7ef44afbf0642c085c18bc5729 Mon Sep 17 00:00:00 2001 From: Christian Quinn Date: Wed, 19 Jan 2022 16:59:08 -0400 Subject: [PATCH 22/25] refactor: linter --- .../components/src/load-async/load-async.service.ts | 2 +- .../src/load-async/loader/loader.component.ts | 4 ++-- .../components/src/skeleton/skeleton.component.ts | 13 +++++++------ 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/projects/components/src/load-async/load-async.service.ts b/projects/components/src/load-async/load-async.service.ts index f6b120e24..84773c159 100644 --- a/projects/components/src/load-async/load-async.service.ts +++ b/projects/components/src/load-async/load-async.service.ts @@ -3,8 +3,8 @@ import { IconType } from '@hypertrace/assets-library'; import { CustomError } from '@hypertrace/common'; import { Observable, of } from 'rxjs'; import { catchError, defaultIfEmpty, map, startWith } from 'rxjs/operators'; -import { LoadAsyncStateType } from './load-async-state.type'; import { SkeletonType } from '../skeleton/skeleton.component'; +import { LoadAsyncStateType } from './load-async-state.type'; @Injectable({ providedIn: 'root' }) export class LoadAsyncService { diff --git a/projects/components/src/load-async/loader/loader.component.ts b/projects/components/src/load-async/loader/loader.component.ts index 9695e95e6..c9bb5b483 100644 --- a/projects/components/src/load-async/loader/loader.component.ts +++ b/projects/components/src/load-async/loader/loader.component.ts @@ -1,8 +1,8 @@ import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core'; import { ImagesAssetPath } from '@hypertrace/assets-library'; +import { assertUnreachable } from '@hypertrace/common'; import { SkeletonType } from '../../skeleton/skeleton.component'; import { ImgLoaderType, LoaderType } from '../load-async.service'; -import { assertUnreachable } from '@hypertrace/common'; @Component({ selector: 'ht-loader', @@ -44,7 +44,7 @@ export class LoaderComponent implements OnChanges { } } - public determineIfOldLoaderType(loaderType: LoaderType) { + public determineIfOldLoaderType(loaderType: LoaderType): boolean { switch (loaderType) { case ImgLoaderType.Spinner: case ImgLoaderType.ExpandableRow: diff --git a/projects/components/src/skeleton/skeleton.component.ts b/projects/components/src/skeleton/skeleton.component.ts index 368b3f0f6..f32080e1d 100644 --- a/projects/components/src/skeleton/skeleton.component.ts +++ b/projects/components/src/skeleton/skeleton.component.ts @@ -41,12 +41,13 @@ export class SkeletonComponent implements OnChanges { } public getIterationsArray(): number[] { - if (this.shapeStyle === SkeletonType.TableRow) { - return Array(5).fill(1); - } else if (this.shapeStyle === SkeletonType.ListItem) { - return Array(4).fill(1); - } else { - return Array(1).fill(1); + switch (this.shapeStyle) { + case SkeletonType.TableRow: + return Array(5).fill(1); + case SkeletonType.ListItem: + return Array(4).fill(1); + default: + return Array(1).fill(1); } } From 12f004794a0febd25a465e9a5f20a54f61a12052 Mon Sep 17 00:00:00 2001 From: Christian Quinn Date: Wed, 19 Jan 2022 18:42:54 -0400 Subject: [PATCH 23/25] refactor: requested changes --- .../src/load-async/load-async.service.ts | 14 +++-- .../loader/loader.component.test.ts | 44 +++++++------- .../src/load-async/loader/loader.component.ts | 59 ++++++++++++------- projects/components/src/public-api.ts | 3 - .../src/skeleton/skeleton.component.test.ts | 8 +-- .../src/skeleton/skeleton.component.ts | 16 +++-- 6 files changed, 84 insertions(+), 60 deletions(-) diff --git a/projects/components/src/load-async/load-async.service.ts b/projects/components/src/load-async/load-async.service.ts index 84773c159..11074ccec 100644 --- a/projects/components/src/load-async/load-async.service.ts +++ b/projects/components/src/load-async/load-async.service.ts @@ -3,7 +3,6 @@ import { IconType } from '@hypertrace/assets-library'; import { CustomError } from '@hypertrace/common'; import { Observable, of } from 'rxjs'; import { catchError, defaultIfEmpty, map, startWith } from 'rxjs/operators'; -import { SkeletonType } from '../skeleton/skeleton.component'; import { LoadAsyncStateType } from './load-async-state.type'; @Injectable({ providedIn: 'root' }) @@ -60,12 +59,17 @@ export interface LoadAsyncConfig { export type AsyncState = LoadingAsyncState | SuccessAsyncState | NoDataOrErrorAsyncState; -export type LoaderType = ImgLoaderType | SkeletonType; - -export const enum ImgLoaderType { +export const enum LoaderType { Spinner = 'spinner', ExpandableRow = 'expandable-row', - Page = 'page' + Page = 'page', + Rectangle = 'rectangle', + Text = 'text', + Square = 'square', + Circle = 'circle', + TableRow = 'table-row', + ListItem = 'list-item', + Donut = 'donut' } interface LoadingAsyncState { diff --git a/projects/components/src/load-async/loader/loader.component.test.ts b/projects/components/src/load-async/loader/loader.component.test.ts index 0d9d58675..a0da5e322 100644 --- a/projects/components/src/load-async/loader/loader.component.test.ts +++ b/projects/components/src/load-async/loader/loader.component.test.ts @@ -3,7 +3,7 @@ import { ImagesAssetPath } from '@hypertrace/assets-library'; import { createHostFactory, SpectatorHost } from '@ngneat/spectator/jest'; import { MockComponent } from 'ng-mocks'; import { SkeletonComponent, SkeletonType } from '../../skeleton/skeleton.component'; -import { ImgLoaderType } from '../load-async.service'; +import { LoaderType } from '../load-async.service'; import { LoaderComponent } from './loader.component'; describe('Loader component', () => { @@ -16,12 +16,12 @@ describe('Loader component', () => { }); test('Loader component when loader type is page', () => { - spectator = createHost(``); + spectator = createHost(``); expect(spectator.query('.ht-loader')).toExist(); expect(spectator.query('.ht-loader')).toHaveClass('flex-centered'); expect(spectator.query('.ht-loader img')).toExist(); - expect(spectator.query('.ht-loader img')).toHaveClass(ImgLoaderType.Page); + expect(spectator.query('.ht-loader img')).toHaveClass(LoaderType.Page); expect(spectator.query('.ht-loader img')).toHaveAttribute('src', ImagesAssetPath.LoaderPage); }); @@ -31,27 +31,27 @@ describe('Loader component', () => { expect(spectator.query('.ht-loader')).toExist(); expect(spectator.query('.ht-loader')).toHaveClass('flex-centered'); expect(spectator.query('.ht-loader img')).toExist(); - expect(spectator.query('.ht-loader img')).toHaveClass(ImgLoaderType.Spinner); + expect(spectator.query('.ht-loader img')).toHaveClass(LoaderType.Spinner); expect(spectator.query('.ht-loader img')).toHaveAttribute('src', ImagesAssetPath.LoaderSpinner); }); test('Loader component when loader type is spinner', () => { - spectator = createHost(``); + spectator = createHost(``); expect(spectator.query('.ht-loader')).toExist(); expect(spectator.query('.ht-loader')).toHaveClass('flex-centered'); expect(spectator.query('.ht-loader img')).toExist(); - expect(spectator.query('.ht-loader img')).toHaveClass(ImgLoaderType.Spinner); + expect(spectator.query('.ht-loader img')).toHaveClass(LoaderType.Spinner); expect(spectator.query('.ht-loader img')).toHaveAttribute('src', ImagesAssetPath.LoaderSpinner); }); test('Loader component loader type is expandable row', () => { - spectator = createHost(``); + spectator = createHost(``); expect(spectator.query('.ht-loader')).toExist(); expect(spectator.query('.ht-loader')).toHaveClass('flex-centered'); expect(spectator.query('.ht-loader img')).toExist(); - expect(spectator.query('.ht-loader img')).toHaveClass(ImgLoaderType.ExpandableRow); + expect(spectator.query('.ht-loader img')).toHaveClass(LoaderType.ExpandableRow); expect(spectator.query('.ht-loader img')).toHaveAttribute('src', ImagesAssetPath.LoaderExpandableRow); }); @@ -63,79 +63,79 @@ describe('Loader component', () => { }); test('Should use corresponding skeleton component for loader type rectangle', () => { - spectator = createHost(``); + spectator = createHost(``); expect(spectator.query('.ht-loader')).toExist(); expect(spectator.query('.ht-loader')).not.toHaveClass('flex-centered'); const skeletonComponent = spectator.query(SkeletonComponent); expect(skeletonComponent).toExist(); - expect(skeletonComponent).toHaveAttribute('shapeStyle', SkeletonType.Rectangle); + expect(skeletonComponent).toHaveAttribute('skeletonType', SkeletonType.Rectangle); }); test('Should use corresponding skeleton component for loader type rectangle text', () => { - spectator = createHost(``); + spectator = createHost(``); expect(spectator.query('.ht-loader')).toExist(); expect(spectator.query('.ht-loader')).not.toHaveClass('flex-centered'); const skeletonComponent = spectator.query(SkeletonComponent); expect(skeletonComponent).toExist(); - expect(skeletonComponent).toHaveAttribute('shapeStyle', SkeletonType.Text); + expect(skeletonComponent).toHaveAttribute('skeletonType', SkeletonType.Text); }); test('Should use corresponding skeleton component for loader type circle', () => { - spectator = createHost(``); + spectator = createHost(``); expect(spectator.query('.ht-loader')).toExist(); expect(spectator.query('.ht-loader')).not.toHaveClass('flex-centered'); const skeletonComponent = spectator.query(SkeletonComponent); expect(skeletonComponent).toExist(); - expect(skeletonComponent).toHaveAttribute('shapeStyle', SkeletonType.Circle); + expect(skeletonComponent).toHaveAttribute('skeletonType', SkeletonType.Circle); }); test('Should use corresponding skeleton component for loader type square', () => { - spectator = createHost(``); + spectator = createHost(``); expect(spectator.query('.ht-loader')).toExist(); expect(spectator.query('.ht-loader')).not.toHaveClass('flex-centered'); const skeletonComponent = spectator.query(SkeletonComponent); expect(skeletonComponent).toExist(); - expect(skeletonComponent).toHaveAttribute('shapeStyle', SkeletonType.Square); + expect(skeletonComponent).toHaveAttribute('skeletonType', SkeletonType.Square); }); test('Should use corresponding skeleton component for loader type table row', () => { - spectator = createHost(``); + spectator = createHost(``); expect(spectator.query('.ht-loader')).toExist(); expect(spectator.query('.ht-loader')).not.toHaveClass('flex-centered'); const skeletonComponent = spectator.query(SkeletonComponent); expect(skeletonComponent).toExist(); - expect(skeletonComponent).toHaveAttribute('shapeStyle', SkeletonType.TableRow); + expect(skeletonComponent).toHaveAttribute('skeletonType', SkeletonType.TableRow); }); test('Should use corresponding skeleton component for loader type donut', () => { - spectator = createHost(``); + spectator = createHost(``); expect(spectator.query('.ht-loader')).toExist(); expect(spectator.query('.ht-loader')).not.toHaveClass('flex-centered'); const skeletonComponent = spectator.query(SkeletonComponent); expect(skeletonComponent).toExist(); - expect(skeletonComponent).toHaveAttribute('shapeStyle', SkeletonType.Donut); + expect(skeletonComponent).toHaveAttribute('skeletonType', SkeletonType.Donut); }); test('Should use corresponding skeleton component for loader type list item', () => { - spectator = createHost(``); + spectator = createHost(``); expect(spectator.query('.ht-loader')).toExist(); expect(spectator.query('.ht-loader')).not.toHaveClass('flex-centered'); const skeletonComponent = spectator.query(SkeletonComponent); expect(skeletonComponent).toExist(); - expect(skeletonComponent).toHaveAttribute('shapeStyle', SkeletonType.ListItem); + expect(skeletonComponent).toHaveAttribute('skeletonType', SkeletonType.ListItem); }); }); diff --git a/projects/components/src/load-async/loader/loader.component.ts b/projects/components/src/load-async/loader/loader.component.ts index c9bb5b483..b1a0ad038 100644 --- a/projects/components/src/load-async/loader/loader.component.ts +++ b/projects/components/src/load-async/loader/loader.component.ts @@ -2,7 +2,7 @@ import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/c import { ImagesAssetPath } from '@hypertrace/assets-library'; import { assertUnreachable } from '@hypertrace/common'; import { SkeletonType } from '../../skeleton/skeleton.component'; -import { ImgLoaderType, LoaderType } from '../load-async.service'; +import { LoaderType } from '../load-async.service'; @Component({ selector: 'ht-loader', @@ -11,7 +11,7 @@ import { ImgLoaderType, LoaderType } from '../load-async.service'; template: `
- + @@ -26,52 +26,71 @@ export class LoaderComponent implements OnChanges { public skeletonType: SkeletonType = SkeletonType.Rectangle; - public currentLoaderType: LoaderType = ImgLoaderType.Spinner; + public currentLoaderType: LoaderType = LoaderType.Spinner; public imagePath: ImagesAssetPath = ImagesAssetPath.LoaderSpinner; public isOldLoaderType: boolean = true; public ngOnChanges(): void { - this.currentLoaderType = this.loaderType ?? ImgLoaderType.Spinner; + this.currentLoaderType = this.loaderType ?? LoaderType.Spinner; if (this.determineIfOldLoaderType(this.currentLoaderType)) { this.isOldLoaderType = true; - this.imagePath = this.getImagePathFromType(this.currentLoaderType as ImgLoaderType); + this.imagePath = this.getImagePathFromType(this.currentLoaderType); } else { this.isOldLoaderType = false; - this.skeletonType = this.currentLoaderType as SkeletonType; + this.skeletonType = this.getSkeletonTypeForLoader(this.currentLoaderType); } } public determineIfOldLoaderType(loaderType: LoaderType): boolean { switch (loaderType) { - case ImgLoaderType.Spinner: - case ImgLoaderType.ExpandableRow: - case ImgLoaderType.Page: + case LoaderType.Spinner: + case LoaderType.ExpandableRow: + case LoaderType.Page: return true; - case SkeletonType.Circle: - case SkeletonType.Text: - case SkeletonType.ListItem: - case SkeletonType.Rectangle: - case SkeletonType.Square: - case SkeletonType.TableRow: - case SkeletonType.Donut: + case LoaderType.Circle: + case LoaderType.Text: + case LoaderType.ListItem: + case LoaderType.Rectangle: + case LoaderType.Square: + case LoaderType.TableRow: + case LoaderType.Donut: return false; default: return assertUnreachable(loaderType); } } - public getImagePathFromType(loaderType: ImgLoaderType): ImagesAssetPath { + public getImagePathFromType(loaderType: LoaderType): ImagesAssetPath { switch (loaderType) { - case ImgLoaderType.ExpandableRow: + case LoaderType.ExpandableRow: return ImagesAssetPath.LoaderExpandableRow; - case ImgLoaderType.Page: + case LoaderType.Page: return ImagesAssetPath.LoaderPage; - case ImgLoaderType.Spinner: + case LoaderType.Spinner: default: return ImagesAssetPath.LoaderSpinner; } } + + public getSkeletonTypeForLoader(curLoaderType: LoaderType): SkeletonType { + switch (curLoaderType) { + case LoaderType.Text: + return SkeletonType.Text; + case LoaderType.Circle: + return SkeletonType.Circle; + case LoaderType.Square: + return SkeletonType.Square; + case LoaderType.TableRow: + return SkeletonType.TableRow; + case LoaderType.ListItem: + return SkeletonType.ListItem; + case LoaderType.Donut: + return SkeletonType.Donut; + default: + return SkeletonType.Rectangle; + } + } } diff --git a/projects/components/src/public-api.ts b/projects/components/src/public-api.ts index d4400cb0f..3d030055d 100644 --- a/projects/components/src/public-api.ts +++ b/projects/components/src/public-api.ts @@ -181,9 +181,6 @@ export * from './load-async/load-async.module'; export * from './load-async/load-async.service'; export * from './load-async/load-async-state.type'; -// Skeleton -export * from './skeleton/skeleton.component'; - // Message Display export { MessageDisplayComponent } from './message-display/message-display.component'; export { MessageDisplayModule } from './message-display/message-display.module'; diff --git a/projects/components/src/skeleton/skeleton.component.test.ts b/projects/components/src/skeleton/skeleton.component.test.ts index fa9171c65..ef539c146 100644 --- a/projects/components/src/skeleton/skeleton.component.test.ts +++ b/projects/components/src/skeleton/skeleton.component.test.ts @@ -17,7 +17,7 @@ describe('Skeleton Component', () => { }); test('Should display number of skeleton elements equal to the repeat input', () => { - spectator = createHost(``); + spectator = createHost(``); expect(spectator.query('.skeleton.list-item')).toExist(); expect(spectator.query('.skeleton .item-circle')).toExist(); @@ -55,14 +55,14 @@ describe('Skeleton Component', () => { expectedRepeat: 4 } ]; - spectator = createHost(``, { + spectator = createHost(``, { hostProps: { - shapeStyle: SkeletonType.Donut + skeletonType: SkeletonType.Donut } }); skeletonInputData.forEach(testConfig => { - spectator.setHostInput({ shapeStyle: testConfig.type }); + spectator.setHostInput({ skeletonType: testConfig.type }); const shapeContainerClass = `.${testConfig.type}`; expect(spectator.query(shapeContainerClass)).toExist(); diff --git a/projects/components/src/skeleton/skeleton.component.ts b/projects/components/src/skeleton/skeleton.component.ts index f32080e1d..3e9c80acc 100644 --- a/projects/components/src/skeleton/skeleton.component.ts +++ b/projects/components/src/skeleton/skeleton.component.ts @@ -4,7 +4,7 @@ import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/c selector: 'ht-skeleton', template: ` - +
@@ -24,12 +24,16 @@ import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/c }) export class SkeletonComponent implements OnChanges { @Input() - public shapeStyle: SkeletonType = SkeletonType.Rectangle; + public skeletonType: SkeletonType = SkeletonType.Rectangle; public iterationsArray: number[] = Array(1).fill(1); public containerClass: string[]; + public static skeletonClass: string = 'skeleton'; + + public static repeatingClass: string = 'repeating'; + public constructor() { this.containerClass = this.getContainerClass(); } @@ -41,7 +45,7 @@ export class SkeletonComponent implements OnChanges { } public getIterationsArray(): number[] { - switch (this.shapeStyle) { + switch (this.skeletonType) { case SkeletonType.TableRow: return Array(5).fill(1); case SkeletonType.ListItem: @@ -52,10 +56,10 @@ export class SkeletonComponent implements OnChanges { } public getContainerClass(): string[] { - const classes = ['skeleton', this.shapeStyle]; + const classes = [SkeletonComponent.skeletonClass, this.skeletonType]; - if (this.shapeStyle === SkeletonType.TableRow || this.shapeStyle === SkeletonType.ListItem) { - classes.push('repeating'); + if (this.skeletonType === SkeletonType.TableRow || this.skeletonType === SkeletonType.ListItem) { + classes.push(SkeletonComponent.repeatingClass); } return classes; From 6a07033fa5166b3df866a267b36c5d3865d0387a Mon Sep 17 00:00:00 2001 From: Christian Quinn Date: Wed, 19 Jan 2022 18:56:31 -0400 Subject: [PATCH 24/25] refactor: naming change --- projects/components/src/skeleton/skeleton.component.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/projects/components/src/skeleton/skeleton.component.ts b/projects/components/src/skeleton/skeleton.component.ts index 3e9c80acc..b7c61b3d7 100644 --- a/projects/components/src/skeleton/skeleton.component.ts +++ b/projects/components/src/skeleton/skeleton.component.ts @@ -30,9 +30,9 @@ export class SkeletonComponent implements OnChanges { public containerClass: string[]; - public static skeletonClass: string = 'skeleton'; + private static readonly SKELETON_CLASS_NAME: string = 'skeleton'; - public static repeatingClass: string = 'repeating'; + private static readonly REPEATING_CLASS_NAME: string = 'repeating'; public constructor() { this.containerClass = this.getContainerClass(); @@ -56,10 +56,10 @@ export class SkeletonComponent implements OnChanges { } public getContainerClass(): string[] { - const classes = [SkeletonComponent.skeletonClass, this.skeletonType]; + const classes = [SkeletonComponent.SKELETON_CLASS_NAME, this.skeletonType]; if (this.skeletonType === SkeletonType.TableRow || this.skeletonType === SkeletonType.ListItem) { - classes.push(SkeletonComponent.repeatingClass); + classes.push(SkeletonComponent.REPEATING_CLASS_NAME); } return classes; From 65a867e4b110e6fd3564a98ab3508a614f79965e Mon Sep 17 00:00:00 2001 From: Christian Quinn Date: Wed, 19 Jan 2022 19:19:10 -0400 Subject: [PATCH 25/25] refactor: name placement to after class definition --- projects/components/src/skeleton/skeleton.component.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/projects/components/src/skeleton/skeleton.component.ts b/projects/components/src/skeleton/skeleton.component.ts index b7c61b3d7..0df006dba 100644 --- a/projects/components/src/skeleton/skeleton.component.ts +++ b/projects/components/src/skeleton/skeleton.component.ts @@ -23,6 +23,9 @@ import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/c styleUrls: ['./skeleton.component.scss'] }) export class SkeletonComponent implements OnChanges { + private static readonly SKELETON_CLASS_NAME: string = 'skeleton'; + private static readonly REPEATING_CLASS_NAME: string = 'repeating'; + @Input() public skeletonType: SkeletonType = SkeletonType.Rectangle; @@ -30,10 +33,6 @@ export class SkeletonComponent implements OnChanges { public containerClass: string[]; - private static readonly SKELETON_CLASS_NAME: string = 'skeleton'; - - private static readonly REPEATING_CLASS_NAME: string = 'repeating'; - public constructor() { this.containerClass = this.getContainerClass(); }