Skip to content

Commit

Permalink
feat: adding extendsFromRoot option via forRoot() module configur…
Browse files Browse the repository at this point in the history
…ation (#138)
  • Loading branch information
willmendesneto authored Feb 4, 2023
1 parent 88559aa commit a3f96d5
Show file tree
Hide file tree
Showing 6 changed files with 365 additions and 212 deletions.
53 changes: 53 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,59 @@ export class YourAppComponent {}
</div>
```

#### 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 `<ngx-skeleton-loader>` 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 `<ngx-skeleton-loader>` 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
<div class="item">
<ngx-skeleton-loader></ngx-skeleton-loader>
<!-- above line will produce a skeleton component using `height: 30px;`" -->
<ngx-skeleton-loader [theme]="{background: 'blue'}"></ngx-skeleton-loader>
<!-- above line will produce a skeleton component using `height: 30px; background: red;`" -->
<ngx-skeleton-loader [theme]="{height: '50px', background: 'red'}"></ngx-skeleton-loader>
<!-- above line will produce a skeleton component using `height: 50px; background: red;`" -->
</div>
```

## WAI-ARIA values

- loadingText - _default_ `Loading...`: attribute that defines the text value for `aria-valuetext` attribute. Defaults to "Loading..."
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export class NgxSkeletonLoaderComponent implements OnInit, AfterViewInit, OnDest
// eslint-disable-next-line @typescript-eslint/no-explicit-any
items: Array<any>;

constructor(@Inject(NGX_SKELETON_LOADER_CONFIG) @Optional() config?: NgxSkeletonLoaderConfig) {
constructor(@Inject(NGX_SKELETON_LOADER_CONFIG) @Optional() private config?: NgxSkeletonLoaderConfig) {
const {
appearance = 'line',
animation = 'progress',
Expand Down Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ import { NgxSkeletonLoaderModule } from './ngx-skeleton-loader.module';
template: `
<div>
<div class="skeletons-defaults">
<ngx-skeleton-loader></ngx-skeleton-loader>
<ngx-skeleton-loader [theme]="{ width: '70px' }"></ngx-skeleton-loader>
</div>
<div class="skeletons-extended-theme">
<ngx-skeleton-loader [theme]="{ width: '100px', background: 'blue' }"></ngx-skeleton-loader>
</div>
</div>
`,
Expand All @@ -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);
Expand Down
Loading

0 comments on commit a3f96d5

Please sign in to comment.