diff --git a/libs/design/callout/src/callout/callout.component.spec.ts b/libs/design/callout/src/callout/callout.component.spec.ts index 2378c4bf47..b0cfc794e9 100644 --- a/libs/design/callout/src/callout/callout.component.spec.ts +++ b/libs/design/callout/src/callout/callout.component.spec.ts @@ -25,7 +25,7 @@ import { DaffCalloutComponent } from './callout.component'; class WrapperComponent { color: DaffPalette; textAlignment: DaffTextAlignment; - compact = false; + compact: boolean; } describe('@daffodil/design/callout | DaffCalloutComponent', () => { @@ -86,6 +86,6 @@ describe('@daffodil/design/callout | DaffCalloutComponent', () => { wrapper.compact = true; fixture.detectChanges(); - expect(component.compact).toEqual(true); + expect(de.nativeElement.classList.contains('daff-compact')).toEqual(true); }); }); diff --git a/libs/design/callout/src/callout/callout.component.ts b/libs/design/callout/src/callout/callout.component.ts index 0bb39ddf4f..dd08ae5d8f 100644 --- a/libs/design/callout/src/callout/callout.component.ts +++ b/libs/design/callout/src/callout/callout.component.ts @@ -7,12 +7,11 @@ import { Renderer2, } from '@angular/core'; +import { DaffCompactableDirective } from '@daffodil/design'; import { DaffArticleEncapsulatedDirective, DaffColorable, daffColorMixin, - DaffCompactable, - daffCompactableMixin, DaffManageContainerLayoutDirective, DaffTextAlignableDirective, } from '@daffodil/design'; @@ -21,10 +20,10 @@ import { * An _elementRef and an instance of renderer2 are needed for the Colorable mixin */ class DaffCalloutBase { - constructor(public _elementRef: ElementRef, public _renderer: Renderer2) {} + constructor(public _elementRef: ElementRef, public _renderer: Renderer2) { } } -const _daffCalloutBase = daffColorMixin(daffCompactableMixin(DaffCalloutBase)); +const _daffCalloutBase = daffColorMixin(DaffCalloutBase); /** * @inheritdoc @@ -36,7 +35,7 @@ const _daffCalloutBase = daffColorMixin(daffCompactableMixin(DaffCalloutBase)); encapsulation: ViewEncapsulation.None, //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: ['color', 'compact'], + inputs: ['color'], hostDirectives: [ { directive: DaffArticleEncapsulatedDirective }, { directive: DaffManageContainerLayoutDirective }, @@ -44,10 +43,14 @@ const _daffCalloutBase = daffColorMixin(daffCompactableMixin(DaffCalloutBase)); directive: DaffTextAlignableDirective, inputs: ['textAlignment'], }, + { + directive: DaffCompactableDirective, + inputs: ['compact'], + }, ], changeDetection: ChangeDetectionStrategy.OnPush, }) -export class DaffCalloutComponent extends _daffCalloutBase implements DaffColorable, DaffCompactable { +export class DaffCalloutComponent extends _daffCalloutBase implements DaffColorable { constructor( private elementRef: ElementRef, private renderer: Renderer2, diff --git a/libs/design/hero/src/hero/hero.component.spec.ts b/libs/design/hero/src/hero/hero.component.spec.ts index e66eb6d800..583e357244 100644 --- a/libs/design/hero/src/hero/hero.component.spec.ts +++ b/libs/design/hero/src/hero/hero.component.spec.ts @@ -22,7 +22,7 @@ import { DaffHeroComponent } from './hero.component'; class WrapperComponent { color: DaffPalette; textAlignment: DaffTextAlignment; - compact = false; + compact: boolean; } describe('@daffodil/design/hero | DaffHeroComponent', () => { @@ -83,6 +83,6 @@ describe('@daffodil/design/hero | DaffHeroComponent', () => { wrapper.compact = true; fixture.detectChanges(); - expect(component.compact).toEqual(true); + expect(de.nativeElement.classList.contains('daff-compact')).toEqual(true); }); }); diff --git a/libs/design/hero/src/hero/hero.component.ts b/libs/design/hero/src/hero/hero.component.ts index 66a434622b..7d8ea922ae 100644 --- a/libs/design/hero/src/hero/hero.component.ts +++ b/libs/design/hero/src/hero/hero.component.ts @@ -5,16 +5,13 @@ import { ChangeDetectionStrategy, HostBinding, Renderer2, - SimpleChanges, - OnChanges, } from '@angular/core'; +import { DaffCompactableDirective } from '@daffodil/design'; import { DaffArticleEncapsulatedDirective, DaffColorable, daffColorMixin, - DaffCompactable, - daffCompactableMixin, DaffManageContainerLayoutDirective, DaffTextAlignableDirective, } from '@daffodil/design'; @@ -26,7 +23,7 @@ class DaffHeroBase { constructor(public _elementRef: ElementRef, public _renderer: Renderer2) {} } -const _daffHeroBase = daffColorMixin(daffCompactableMixin(DaffHeroBase)); +const _daffHeroBase = daffColorMixin(DaffHeroBase); /** * @inheritdoc @@ -38,7 +35,7 @@ const _daffHeroBase = daffColorMixin(daffCompactableMixin(DaffHeroBase)); encapsulation: ViewEncapsulation.None, //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: ['color', 'compact'], + inputs: ['color'], hostDirectives: [ { directive: DaffArticleEncapsulatedDirective }, { directive: DaffManageContainerLayoutDirective }, @@ -46,10 +43,14 @@ const _daffHeroBase = daffColorMixin(daffCompactableMixin(DaffHeroBase)); directive: DaffTextAlignableDirective, inputs: ['textAlignment'], }, + { + directive: DaffCompactableDirective, + inputs: ['compact'], + }, ], changeDetection: ChangeDetectionStrategy.OnPush, }) -export class DaffHeroComponent extends _daffHeroBase implements DaffColorable, DaffCompactable { +export class DaffHeroComponent extends _daffHeroBase implements DaffColorable { constructor( private elementRef: ElementRef, private renderer: Renderer2, diff --git a/libs/design/src/core/compactable/compactable-mixin.ts b/libs/design/src/core/compactable/compactable-mixin.ts deleted file mode 100644 index 8b26fd307b..0000000000 --- a/libs/design/src/core/compactable/compactable-mixin.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { - ElementRef, - Renderer2, -} from '@angular/core'; - -import { Constructor } from '../constructor/constructor'; - -export interface HasElementRef { - _elementRef: ElementRef; - _renderer: Renderer2; -} - -export function -daffCompactableMixin>(Base: T, defaultCompact: boolean = false) { - return class extends Base { - // TODO move this back to private in Typescript 3.1 - _compact: boolean; - - get compact(): boolean { - return this._compact; - } - - set compact(value: boolean) { - // Handles the default compact - const incomingCompact = value || defaultCompact; - - if (incomingCompact === this._compact) { // Only run the dom-render if a change occurs - return; - } - - if (incomingCompact) { - this._renderer.addClass(this._elementRef.nativeElement, `daff-compact`); - } else { - this._renderer.removeClass(this._elementRef.nativeElement, `daff-compact`); - } - - this._compact = incomingCompact; - } - - constructor(...args: any[]) { - super(...args); - this.compact = defaultCompact; - } - }; -} diff --git a/libs/design/src/core/compactable/compactable.directive.spec.ts b/libs/design/src/core/compactable/compactable.directive.spec.ts new file mode 100644 index 0000000000..5bdfc60bbb --- /dev/null +++ b/libs/design/src/core/compactable/compactable.directive.spec.ts @@ -0,0 +1,74 @@ +import { + Component, + DebugElement, +} from '@angular/core'; +import { + waitForAsync, + ComponentFixture, + TestBed, +} from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; + +import { DaffCompactableDirective } from './compactable.directive'; + +@Component({ + template: ` +
`, +}) + +class WrapperComponent { + compact: boolean; +} + +describe('@daffodil/design | DaffCompactableDirective', () => { + let wrapper: WrapperComponent; + let de: DebugElement; + let fixture: ComponentFixture; + let directive: DaffCompactableDirective; + + beforeEach(waitForAsync(() => { + TestBed.configureTestingModule({ + declarations: [ + WrapperComponent, + ], + imports: [ + DaffCompactableDirective, + ], + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(WrapperComponent); + wrapper = fixture.componentInstance; + de = fixture.debugElement.query(By.css('[daffCompactable]')); + + directive = de.injector.get(DaffCompactableDirective); + fixture.detectChanges(); + }); + + it('should create', () => { + expect(wrapper).toBeTruthy(); + expect(directive).toBeTruthy(); + }); + + it('should take compact as an input', () => { + expect(directive.compact).toEqual(wrapper.compact); + }); + + it('should add a class of .daff-compact to the host element if compact is set to true', () => { + wrapper.compact = true; + fixture.detectChanges(); + + expect(de.classes).toEqual(jasmine.objectContaining({ + 'daff-compact': true, + })); + }); + + it('should not add a class of .daff-compact to the host element if compact is set to false', () => { + wrapper.compact = false; + fixture.detectChanges(); + + expect(de.classes['daff-skeleton']).toBeUndefined(); + }); +}); diff --git a/libs/design/src/core/compactable/compactable.directive.ts b/libs/design/src/core/compactable/compactable.directive.ts new file mode 100644 index 0000000000..a263bef6aa --- /dev/null +++ b/libs/design/src/core/compactable/compactable.directive.ts @@ -0,0 +1,14 @@ +import { + Directive, + HostBinding, + Input, +} from '@angular/core'; + +@Directive({ + selector: '[daffCompactable]', + standalone: true, +}) + +export class DaffCompactableDirective { + @Input() @HostBinding('class.daff-compact') compact = false; +} diff --git a/libs/design/src/core/compactable/compactable.spec.ts b/libs/design/src/core/compactable/compactable.spec.ts deleted file mode 100644 index 249f8054c5..0000000000 --- a/libs/design/src/core/compactable/compactable.spec.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { ElementRef } from '@angular/core'; - -import { - daffCompactableMixin, - HasElementRef, -} from './compactable-mixin'; - -class TestingClass implements HasElementRef { - element: HTMLElement = document.createElement('div'); - - _elementRef = new ElementRef(this.element); - _renderer: any = { - addClass: (el: HTMLElement, className: string) => { - el.classList.add(className); - }, - removeClass: (el: HTMLElement, className: string) => { - el.classList.remove(className); - }, - }; -} - -describe('@daffodil/design | daffCompactableMixin', () => { - let instance; - let classWithSkeleton; - - beforeEach(() => { - classWithSkeleton = daffCompactableMixin(TestingClass); - instance = new classWithSkeleton(); - }); - - it('should add a compact property to an existing class', () => { - expect('compact' in instance).toBeTruthy(); - }); - - it('should set compact to false by default', () => { - expect(instance.element.classList.length).toEqual(0); - }); - - describe('when compact is set to true', () => { - it('should set a namespaced compact class', () => { - instance.compact = true; - - expect(instance.element.classList).toContain('daff-compact'); - }); - }); - - describe('when compact is set to false or not specified', () => { - it('should default to no compact class', () => { - instance.compact = false; - expect(instance.element.classList.length).toEqual(0); - - instance.compact = undefined; - expect(instance.element.classList.length).toEqual(0); - }); - }); -}); diff --git a/libs/design/src/core/compactable/public_api.ts b/libs/design/src/core/compactable/public_api.ts index 18481e90f7..a930cfd8ce 100644 --- a/libs/design/src/core/compactable/public_api.ts +++ b/libs/design/src/core/compactable/public_api.ts @@ -1,2 +1,2 @@ export { DaffCompactable } from './compactable'; -export { daffCompactableMixin } from './compactable-mixin'; +export { DaffCompactableDirective } from './compactable.directive';