From a3f96d5a94554be1297a9a8df0fe51437d7ab384 Mon Sep 17 00:00:00 2001 From: Will Mendes Date: Sat, 4 Feb 2023 01:03:46 -0300 Subject: [PATCH] feat: adding `extendsFromRoot` option via `forRoot()` module configuration (#138) --- README.md | 53 ++ .../lib/ngx-skeleton-loader-config.types.ts | 2 + .../src/lib/ngx-skeleton-loader.component.ts | 7 +- .../lib/ngx-skeleton-loader.module.spec.ts | 57 ++- src/app/app.component.html | 451 ++++++++++-------- src/app/app.module.ts | 7 +- 6 files changed, 365 insertions(+), 212 deletions(-) diff --git a/README.md b/README.md index 0113a4c..4d1c7db 100644 --- a/README.md +++ b/README.md @@ -118,6 +118,59 @@ export class YourAppComponent {} ``` +#### Extending `theme` via `NgxSkeletonLoaderModule.forRoot()` + +> By default when using `NgxSkeletonLoaderModule.forRoot({ theme: /* ...list of CSS atributes */} })` the application is using this value as source of truth, overriding any local theming passed to `` component via `[theme]` input. Check these steps in case you need to change this behaviour in your app + +This method is also accepting the option of having a global theme and local theme inputs. You can enable it by passing `NgxSkeletonLoaderModule.forRoot({ theme: { extendsFromRoot: true, /* ...list of CSS atributes */} })` in your module. Quite simple, right? 😄 + +By using that configuration in yuor application, you should also be aware that: + +- By default, every `` component will use `theme` coming from `NgxSkeletonLoaderModule.forRoot()` as the source of truth +- If there's any CSS attribute on the component locally which overrides the CSS spec, it combines both themes, but overriding global CSS attributes in favor of local ones. + +As an example: + +```typescript +... +import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; +... + +@NgModule({ + declarations: [ + YourAppComponent + ], + imports: [ + ... + NgxSkeletonLoaderModule.forRoot({ + theme: { + // Enabliong theme combination + extendsFromRoot: true, + // ... list of CSS theme attributes + height: '30px', + }, + }),, + ... + ], + providers: [], + bootstrap: [YourAppComponent] +}) + +export class YourAppComponent {} + +``` + +```html +
+ + + + + + +
+``` + ## WAI-ARIA values - loadingText - _default_ `Loading...`: attribute that defines the text value for `aria-valuetext` attribute. Defaults to "Loading..." diff --git a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader-config.types.ts b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader-config.types.ts index 5724615..e4df69d 100644 --- a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader-config.types.ts +++ b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader-config.types.ts @@ -1,6 +1,8 @@ import { InjectionToken } from '@angular/core'; export type NgxSkeletonLoaderConfigTheme = { + // It enforces a combination of `fromRoot` styles with component `styles` attribute + extendsFromRoot?: boolean; // This is required since ngStyle is using `any` as well // More details in https://angular.io/api/common/NgStyle // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.ts b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.ts index 1f3cc30..a10e91f 100644 --- a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.ts +++ b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.component.ts @@ -51,7 +51,7 @@ export class NgxSkeletonLoaderComponent implements OnInit, AfterViewInit, OnDest // eslint-disable-next-line @typescript-eslint/no-explicit-any items: Array; - constructor(@Inject(NGX_SKELETON_LOADER_CONFIG) @Optional() config?: NgxSkeletonLoaderConfig) { + constructor(@Inject(NGX_SKELETON_LOADER_CONFIG) @Optional() private config?: NgxSkeletonLoaderConfig) { const { appearance = 'line', animation = 'progress', @@ -123,6 +123,11 @@ export class NgxSkeletonLoaderComponent implements OnInit, AfterViewInit, OnDest } this.appearance = ''; } + + if (Boolean(this.config?.theme?.extendsFromRoot) && this.theme !== null) { + // Shows error message only in Development + this.theme = { ...this.config!.theme, ...this.theme }; + } } ngOnChanges(changes: SimpleChanges) { diff --git a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.module.spec.ts b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.module.spec.ts index 1b63ce9..8494278 100644 --- a/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.module.spec.ts +++ b/projects/ngx-skeleton-loader/src/lib/ngx-skeleton-loader.module.spec.ts @@ -8,7 +8,10 @@ import { NgxSkeletonLoaderModule } from './ngx-skeleton-loader.module'; template: `
- + +
+
+
`, @@ -19,20 +22,44 @@ describe('NgxSkeletonLoaderModule method', () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any let fixture: any; - beforeEach( - waitForAsync(() => { - spyOn(console, 'error'); - spyOn(console, 'log'); - spyOn(console, 'warn'); - spyOn(console, 'info'); - fixture = TestBed.configureTestingModule({ - imports: [NgxSkeletonLoaderModule.forRoot({ appearance: 'circle', count: 3 })], - declarations: [ContainerComponent], - providers: [{ provide: PLATFORM_ID, useValue: 'browser' }], - }).createComponent(ContainerComponent); - fixture.detectChanges(); - }), - ); + beforeEach(waitForAsync(() => { + spyOn(console, 'error'); + spyOn(console, 'log'); + spyOn(console, 'warn'); + spyOn(console, 'info'); + fixture = TestBed.configureTestingModule({ + imports: [ + NgxSkeletonLoaderModule.forRoot({ + appearance: 'circle', + count: 3, + theme: { + extendsFromRoot: true, + background: 'red', + }, + }), + ], + declarations: [ContainerComponent], + providers: [{ provide: PLATFORM_ID, useValue: 'browser' }], + }).createComponent(ContainerComponent); + fixture.detectChanges(); + })); + + describe('When #forRoot receives a `theme`', () => { + it('should render skeleton extending theme styles from root and overriding config theming in favour of local theme if local config has any similar CSS attribute', () => { + const skeletonWithTheming = fixture.nativeElement.querySelector( + '.skeletons-extended-theme .skeleton-loader.circle', + ).attributes as NamedNodeMap; + + expect((skeletonWithTheming.getNamedItem('style') as Attr).value).toBe('background: blue; width: 100px;'); + }); + + it('should render skeleton with styles extending/combining theme styles from root if CSS attributes are not similar', () => { + const skeletonWithTheming = fixture.nativeElement.querySelector('.skeletons-defaults .skeleton-loader.circle') + .attributes as NamedNodeMap; + + expect((skeletonWithTheming.getNamedItem('style') as Attr).value).toBe('background: red; width: 70px;'); + }); + }); it('should render the component properly using given forRoot() config', () => { expect(fixture.nativeElement.querySelectorAll('.skeletons-defaults .skeleton-loader.circle').length).toBe(3); diff --git a/src/app/app.component.html b/src/app/app.component.html index 27eea90..fd90900 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -5,8 +5,8 @@

Skeleton Loader Simulation

- Here is a simulation of a skeleton for an user card component. This skeleton - will be replaces in few seconds for an image. + Here is a simulation of a skeleton for an user card component. This skeleton will be replaces in few seconds for an + image.



@@ -14,223 +14,284 @@

Skeleton Loader Simulation

- +
+ src="//user-images.githubusercontent.com/1252570/96255429-9e7e7a00-1002-11eb-9471-1e7fdfc139cd.png" + alt="" + class="content-loaded-image" + /> +
+
+
+ +

Wilson Mendes

-
-
- -

Wilson Mendes

-
-
- -

Hi! It's me

-
+
+ +

Hi! It's me

+
-
-
- -
- -

Line skeletons

- -
- -
+
+
-

Line skeletons with theming

-
- -
+
-

Line skeletons with theming - Changing Colors and Switching Animations

-

You can use the same colors for the other examples

-

- Also, this example will be switching between `pulse` and - `progress-dark` animations -

-

Current value: {{animation}}

- -
- - -
+

Line skeletons

-

Circle skeletons

-
- -
+
+ +
-

Circle skeletons with theming

-
- - -
+

Line skeletons with theming

+
+ +
-

Circle skeletons with mixing theming and `ngStyle` via `[theme]` input

-

Width and height will be switching between 50px and 100px every 5 seconds

-

Current value: {{widthHeightSizeInPixels}}px

-
- - -
+

Line skeletons with theming - Changing Colors and Switching Animations

+

You can use the same colors for the other examples

+

Also, this example will be switching between `pulse` and `progress-dark` animations

+

+ Current value: {{ animation }} +

-

Facebook skeleton example

+
+ + +
+ +

Circle skeletons

+

+ This circle is overriding CSS attribute `height` from `.forRoot()` module's method as an example. So that, it can keep + `height` and `width` with the same values. +

+
+ + +
+ +

Circle skeletons with theming

+
+ + +
+ +

Circle skeletons with mixing theming and `ngStyle` via `[theme]` input

+

Width and height will be switching between 50px and 100px every 5 seconds

+

+ Current value: {{ widthHeightSizeInPixels }}px +

+
+ + +
+ +

Facebook skeleton example

-
-
-
- - +
+
+
+ +
+
+
+ +
+
+
-
-
- +
+ -
-
- - -
-
+ }" + >
-
-
- -
-
- -
-
- -
+
+
-
- -

Animations

- -

Skeletons without animation

- -
- -
- -
- -
- -

Skeleton using `progress` animation

- -
- -
- -
- -
- -

Skeleton using `pulse` animation

- -
- -
- -
- -
- -

Skeleton using `progress-dark` animation

- -
- -
- -

Skeleton using custom-content (SVG for example)

- -
-
- - - - - - - +
+
- -

Skeleton switching values for `animation` and `count` @Input

-

Current values:

-
    -
  • Count: {{count}}
  • -
  • Animation: {{animation}}
  • -
- -
- +
+ +

Animations

+ +

Skeletons without animation

+ +
+ +
+ +
+ +
+ +

Skeleton using `progress` animation

+ +
+ +
+ +
+ +
+ +

Skeleton using `pulse` animation

+ +
+ +
+ +
+ +
+ +

Skeleton using `progress-dark` animation

+ +
+ +
+ +

Skeleton using custom-content (SVG for example)

+ +
+
+ + + + + +
+
+ +

Skeleton switching values for `animation` and `count` @Input

+

Current values:

+
    +
  • + Count: {{ count }} +
  • +
  • + Animation: {{ animation }} +
  • +
+ +
+ + +
diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 604fc70..5beae1c 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -8,7 +8,12 @@ import { NgxSkeletonLoaderModule } from '../../projects/ngx-skeleton-loader/src/ declarations: [AppComponent], imports: [ BrowserModule.withServerTransition({ appId: 'serverApp' }), - NgxSkeletonLoaderModule.forRoot() + NgxSkeletonLoaderModule.forRoot({ + theme: { + extendsFromRoot: true, + height: '30px', + }, + }), ], providers: [], bootstrap: [AppComponent],