Skip to content

Commit

Permalink
feat(design): change daffSkeletonMixin to a directive
Browse files Browse the repository at this point in the history
  • Loading branch information
xelaint committed Jul 18, 2024
1 parent 7fd12a8 commit c58c263
Show file tree
Hide file tree
Showing 11 changed files with 116 additions and 156 deletions.
7 changes: 5 additions & 2 deletions libs/design/image/src/image/image.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,11 @@ describe('@daffodil/design/image | DaffImageComponent', () => {
expect(component.height).toEqual(100);
});

it('should be able to take `skeleton` as an input', () => {
expect(component.skeleton).toEqual(wrapper.skeleton);
it('should take skeleton as an input', () => {
wrapper.skeleton = true;
fixture.detectChanges();

expect(de.nativeElement.classList.contains('daff-skeleton')).toEqual(true);
});

it('should throw an error when src is invalid', () => {
Expand Down
33 changes: 7 additions & 26 deletions libs/design/image/src/image/image.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,12 @@ import {
Input,
EventEmitter,
OnInit,
ElementRef,
Renderer2,
Output,
HostBinding,
} from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';

import {
daffSkeletonableMixin,
DaffSkeletonable,
} from '@daffodil/design';
import { DaffSkeletonableDirective } from '@daffodil/design';
import { daffThumbnailCompatToken } from '@daffodil/design/media-gallery';

const validateProperty = (object: Record<string, any>, prop: string) => {
Expand All @@ -38,15 +33,6 @@ const validateProperties = (object: Record<string, any>, props: string[]) => {
}
};

/**
* An _elementRef is needed for the GolfGhostable mixin
*/
class DaffImageBase {
constructor(public _elementRef: ElementRef, public _renderer: Renderer2) { }
}

const _daffImageBase = daffSkeletonableMixin(DaffImageBase);

@Component({
selector: 'daff-image',
templateUrl: './image.component.html',
Expand All @@ -58,11 +44,12 @@ const _daffImageBase = daffSkeletonableMixin(DaffImageBase);
provide: daffThumbnailCompatToken, useExisting: DaffImageComponent,
},
],
// todo(damienwebdev): remove once decorators hit stage 3 - https://github.com/microsoft/TypeScript/issues/7342
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
inputs: ['skeleton'],
hostDirectives: [{
directive: DaffSkeletonableDirective,
inputs: ['skeleton'],
}],
})
export class DaffImageComponent extends _daffImageBase implements OnInit, DaffSkeletonable {
export class DaffImageComponent implements OnInit {

private _src: string;

Expand Down Expand Up @@ -119,13 +106,7 @@ export class DaffImageComponent extends _daffImageBase implements OnInit, DaffSk
validateProperties(this, ['src', 'alt', 'width', 'height']);
}

constructor(
private sanitizer: DomSanitizer,
private elementRef: ElementRef,
private renderer: Renderer2,
) {
super(elementRef, renderer);
}
constructor(private sanitizer: DomSanitizer) {}

/**
* @docs-private
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,11 @@ describe('@daffodil/design/media-gallery | DaffMediaGalleryComponent', () => {
expect(component.name).toEqual(stubName);
});

it('should take a skeleton as input', () => {
expect(component.skeleton).toEqual(wrapper.skeleton);
it('should take skeleton as an input', () => {
wrapper.skeleton = true;
fixture.detectChanges();

expect(de.nativeElement.classList.contains('daff-skeleton')).toEqual(true);
});

it('should remove the gallery from the registry when the gallery is destroyed', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,11 @@ import {
Input,
OnInit,
OnDestroy,
ElementRef,
Renderer2,
} from '@angular/core';

import {
daffSkeletonableMixin,
DaffSkeletonable,
DaffArticleEncapsulatedDirective,
DaffSkeletonableDirective,
} from '@daffodil/design';

import { DaffMediaGalleryRegistration } from '../helpers/media-gallery-registration.interface';
Expand All @@ -21,15 +18,6 @@ import { DaffMediaGalleryRegistry } from '../registry/media-gallery.registry';

let uniqueGalleryId = 0;

/**
* An _elementRef and an instance of renderer2 are needed for the link set mixins
*/
class DaffMediaGalleryBase {
constructor(public _elementRef: ElementRef, public _renderer: Renderer2) {}
}

const _daffMediaGalleryBase = daffSkeletonableMixin((DaffMediaGalleryBase));

@Component({
selector: 'daff-media-gallery',
templateUrl: './media-gallery.component.html',
Expand All @@ -42,11 +30,15 @@ const _daffMediaGalleryBase = daffSkeletonableMixin((DaffMediaGalleryBase));
// todo(damienwebdev): remove once decorators hit stage 3 - https://github.com/microsoft/TypeScript/issues/7342
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
inputs: ['skeleton'],
hostDirectives: [{
directive: DaffArticleEncapsulatedDirective,
}],
hostDirectives: [
{ directive: DaffArticleEncapsulatedDirective },
{
directive: DaffSkeletonableDirective,
inputs: ['skeleton'],
},
],
})
export class DaffMediaGalleryComponent extends _daffMediaGalleryBase implements DaffMediaGalleryRegistration, DaffSkeletonable, OnInit, OnDestroy {
export class DaffMediaGalleryComponent implements DaffMediaGalleryRegistration, OnInit, OnDestroy {
/**
* Adds a class for styling the media gallery
*/
Expand All @@ -57,13 +49,8 @@ export class DaffMediaGalleryComponent extends _daffMediaGalleryBase implements
*/
@Input() name = `${uniqueGalleryId}`;

constructor(
private elementRef: ElementRef,
private renderer: Renderer2,
private registry: DaffMediaGalleryRegistry,
) {
super(elementRef, renderer);
uniqueGalleryId++;
constructor(private registry: DaffMediaGalleryRegistry) {
uniqueGalleryId++;
}

ngOnInit() {
Expand Down
2 changes: 1 addition & 1 deletion libs/design/scss/state/skeleton/_mixins.scss
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

&::before {
animation-name: loading;
animation-duration: 1500ms;
animation-duration: 1000ms;
animation-timing-function: linear;
animation-iteration-count: infinite;
animation-direction: alternate;
Expand Down
2 changes: 1 addition & 1 deletion libs/design/src/core/skeletonable/public_api.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export { DaffSkeletonable } from './skeletonable';
export { daffSkeletonableMixin } from './skeletonable-mixin';
export { DaffSkeletonableDirective } from './skeletonable.directive';
45 changes: 0 additions & 45 deletions libs/design/src/core/skeletonable/skeletonable-mixin.ts

This file was deleted.

72 changes: 72 additions & 0 deletions libs/design/src/core/skeletonable/skeletonable.directive.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import {
Component,
DebugElement,
} from '@angular/core';
import {
waitForAsync,
ComponentFixture,
TestBed,
} from '@angular/core/testing';
import { By } from '@angular/platform-browser';

import { DaffSkeletonableDirective } from './skeletonable.directive';

@Component({
template: `
<div daffSkeletonable
[skeleton]="skeleton">
</div>`,
})

class WrapperComponent {
skeleton: boolean;
}

describe('@daffodil/design | DaffSkeletonableDirective', () => {
let wrapper: WrapperComponent;
let de: DebugElement;
let fixture: ComponentFixture<WrapperComponent>;
let directive: DaffSkeletonableDirective;

beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [
WrapperComponent,
],
imports: [
DaffSkeletonableDirective,
],
})
.compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(WrapperComponent);
wrapper = fixture.componentInstance;
de = fixture.debugElement.query(By.css('[daffSkeletonable]'));
directive = de.injector.get(DaffSkeletonableDirective);
fixture.detectChanges();
});

it('should create', () => {
expect(wrapper).toBeTruthy();
expect(directive).toBeTruthy();
});

it('should take skeleton as an input', () => {
expect(directive.skeleton).toEqual(wrapper.skeleton);
});

it('should add a class of "daff-skeleton" to the host element when skeleton is true', () => {
wrapper.skeleton = true;
fixture.detectChanges();

expect(de.classes).toEqual(jasmine.objectContaining({
'daff-skeleton': true,
}));
});

it('should not add a class of "daff-skeleton" to the host element when skeleton is false', () => {
expect(de.classes['daff-skeleton']).toBeUndefined();
});
});
14 changes: 14 additions & 0 deletions libs/design/src/core/skeletonable/skeletonable.directive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import {
Directive,
HostBinding,
Input,
} from '@angular/core';

@Directive({
selector: '[daffSkeletonable]',
standalone: true,
})

export class DaffSkeletonableDirective {
@Input() @HostBinding('class.daff-skeleton') skeleton = false;
}
54 changes: 0 additions & 54 deletions libs/design/src/core/skeletonable/skeletonable.spec.ts

This file was deleted.

1 change: 0 additions & 1 deletion libs/design/src/core/skeletonable/skeletonable.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
/**
* An interface for giving a component the ability to display a skeleton/loading UI.
* In order to be skeletonable, our class must implement this property.
*/
export interface DaffSkeletonable {
skeleton: boolean;
Expand Down

0 comments on commit c58c263

Please sign in to comment.