diff --git a/libs/design/callout/src/callout/callout.component.spec.ts b/libs/design/callout/src/callout/callout.component.spec.ts index cab4930d31..2378c4bf47 100644 --- a/libs/design/callout/src/callout/callout.component.spec.ts +++ b/libs/design/callout/src/callout/callout.component.spec.ts @@ -79,47 +79,7 @@ describe('@daffodil/design/callout | DaffCalloutComponent', () => { wrapper.textAlignment = 'left'; fixture.detectChanges(); - expect(component.textAlignment).toEqual('left'); - }); - - describe('setting the textAlignment', () => { - it('should add the class of the defined textAlignment to the host element', () => { - wrapper.textAlignment = 'left'; - fixture.detectChanges(); - - expect(de.nativeElement.classList.contains('daff-left')).toEqual(true); - }); - - it('should set the default textAlignment to left', () => { - expect(component.textAlignment).toEqual('left'); - }); - - describe('when textAlignment="left"', () => { - it('should add a class of "daff-left" to the host element', () => { - wrapper.textAlignment = 'left'; - fixture.detectChanges(); - - expect(de.nativeElement.classList.contains('daff-left')).toBeTruthy(); - }); - }); - - describe('when textAlignment="center"', () => { - it('should add a class of "daff-center" to the host element', () => { - wrapper.textAlignment = 'center'; - fixture.detectChanges(); - - expect(de.nativeElement.classList.contains('daff-center')).toBeTruthy(); - }); - }); - - describe('when textAlignment="right"', () => { - it('should add a class of "daff-right" to the host element', () => { - wrapper.textAlignment = 'right'; - fixture.detectChanges(); - - expect(de.nativeElement.classList.contains('daff-right')).toBeTruthy(); - }); - }); + expect(de.nativeElement.classList.contains('daff-left')).toEqual(true); }); it('should take compact as an input', () => { diff --git a/libs/design/callout/src/callout/callout.component.ts b/libs/design/callout/src/callout/callout.component.ts index fd2fee8ce4..608f779f5b 100644 --- a/libs/design/callout/src/callout/callout.component.ts +++ b/libs/design/callout/src/callout/callout.component.ts @@ -14,8 +14,7 @@ import { DaffCompactable, daffCompactableMixin, DaffManageContainerLayoutDirective, - DaffTextAlignable, - daffTextAlignmentMixin, + DaffTextAlignableDirective, } from '@daffodil/design'; /** @@ -25,7 +24,7 @@ class DaffCalloutBase { constructor(public _elementRef: ElementRef, public _renderer: Renderer2) {} } -const _daffCalloutBase = daffColorMixin(daffCompactableMixin(daffTextAlignmentMixin(DaffCalloutBase, 'left'))); +const _daffCalloutBase = daffColorMixin(daffCompactableMixin(DaffCalloutBase)); /** * @inheritdoc @@ -41,12 +40,22 @@ const _daffCalloutBase = daffColorMixin(daffCompactableMixin(daffTextAlignmentMi hostDirectives: [ { directive: DaffArticleEncapsulatedDirective }, { directive: DaffManageContainerLayoutDirective }, + { + directive: DaffTextAlignableDirective, + inputs: ['textAlignment'], + }, ], changeDetection: ChangeDetectionStrategy.OnPush, }) -export class DaffCalloutComponent extends _daffCalloutBase implements DaffColorable, DaffTextAlignable, DaffCompactable { - constructor(private elementRef: ElementRef, private renderer: Renderer2) { +export class DaffCalloutComponent extends _daffCalloutBase implements DaffColorable, DaffCompactable { + constructor( + private elementRef: ElementRef, + private renderer: Renderer2, + private textAlignable: DaffTextAlignableDirective, + ) { super(elementRef, renderer); + + this.textAlignable.textAlignment = 'left'; } /** diff --git a/libs/design/hero/src/hero/hero.component.spec.ts b/libs/design/hero/src/hero/hero.component.spec.ts index 4c91acbdf9..e66eb6d800 100644 --- a/libs/design/hero/src/hero/hero.component.spec.ts +++ b/libs/design/hero/src/hero/hero.component.spec.ts @@ -76,47 +76,7 @@ describe('@daffodil/design/hero | DaffHeroComponent', () => { wrapper.textAlignment = 'left'; fixture.detectChanges(); - expect(component.textAlignment).toEqual('left'); - }); - - describe('setting the textAlignment', () => { - it('should add the class of the defined textAlignment to the host element', () => { - wrapper.textAlignment = 'left'; - fixture.detectChanges(); - - expect(de.nativeElement.classList.contains('daff-left')).toEqual(true); - }); - - it('should set the default textAlignment to left', () => { - expect(component.textAlignment).toEqual('left'); - }); - - describe('when textAlignment="left"', () => { - it('should add a class of "daff-left" to the host element', () => { - wrapper.textAlignment = 'left'; - fixture.detectChanges(); - - expect(de.nativeElement.classList.contains('daff-left')).toBeTruthy(); - }); - }); - - describe('when textAlignment="center"', () => { - it('should add a class of "daff-center" to the host element', () => { - wrapper.textAlignment = 'center'; - fixture.detectChanges(); - - expect(de.nativeElement.classList.contains('daff-center')).toBeTruthy(); - }); - }); - - describe('when textAlignment="right"', () => { - it('should add a class of "daff-right" to the host element', () => { - wrapper.textAlignment = 'right'; - fixture.detectChanges(); - - expect(de.nativeElement.classList.contains('daff-right')).toBeTruthy(); - }); - }); + expect(de.nativeElement.classList.contains('daff-left')).toEqual(true); }); it('should take compact as an input', () => { diff --git a/libs/design/hero/src/hero/hero.component.ts b/libs/design/hero/src/hero/hero.component.ts index f1bed4b1cf..66a434622b 100644 --- a/libs/design/hero/src/hero/hero.component.ts +++ b/libs/design/hero/src/hero/hero.component.ts @@ -5,6 +5,8 @@ import { ChangeDetectionStrategy, HostBinding, Renderer2, + SimpleChanges, + OnChanges, } from '@angular/core'; import { @@ -14,8 +16,7 @@ import { DaffCompactable, daffCompactableMixin, DaffManageContainerLayoutDirective, - DaffTextAlignable, - daffTextAlignmentMixin, + DaffTextAlignableDirective, } from '@daffodil/design'; /** @@ -25,7 +26,7 @@ class DaffHeroBase { constructor(public _elementRef: ElementRef, public _renderer: Renderer2) {} } -const _daffHeroBase = daffColorMixin(daffCompactableMixin(daffTextAlignmentMixin(DaffHeroBase, 'left'))); +const _daffHeroBase = daffColorMixin(daffCompactableMixin(DaffHeroBase)); /** * @inheritdoc @@ -37,16 +38,26 @@ const _daffHeroBase = daffColorMixin(daffCompactableMixin(daffTextAlignmentMixin 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', 'textAlignment'], + inputs: ['color', 'compact'], hostDirectives: [ { directive: DaffArticleEncapsulatedDirective }, { directive: DaffManageContainerLayoutDirective }, + { + directive: DaffTextAlignableDirective, + inputs: ['textAlignment'], + }, ], changeDetection: ChangeDetectionStrategy.OnPush, }) -export class DaffHeroComponent extends _daffHeroBase implements DaffColorable, DaffTextAlignable, DaffCompactable { - constructor(private elementRef: ElementRef, private renderer: Renderer2) { +export class DaffHeroComponent extends _daffHeroBase implements DaffColorable, DaffCompactable { + constructor( + private elementRef: ElementRef, + private renderer: Renderer2, + private textAlignable: DaffTextAlignableDirective, + ){ super(elementRef, renderer); + + this.textAlignable.defaultAlignment = 'left'; } /** diff --git a/libs/design/src/core/text-alignable/public_api.ts b/libs/design/src/core/text-alignable/public_api.ts index aae756ec96..6e3f3106fa 100644 --- a/libs/design/src/core/text-alignable/public_api.ts +++ b/libs/design/src/core/text-alignable/public_api.ts @@ -3,4 +3,4 @@ export { DaffTextAlignment, DaffTextAlignmentEnum, } from './text-alignable'; -export { daffTextAlignmentMixin } from './text-alignable-mixin'; +export { DaffTextAlignableDirective } from './text-alignable.directive'; diff --git a/libs/design/src/core/text-alignable/text-alignable-mixin.ts b/libs/design/src/core/text-alignable/text-alignable-mixin.ts deleted file mode 100644 index 0e246a4446..0000000000 --- a/libs/design/src/core/text-alignable/text-alignable-mixin.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { - ElementRef, - Input, - Renderer2, -} from '@angular/core'; - -import { DaffTextAlignment } from './text-alignable'; -import { Constructor } from '../constructor/constructor'; - -interface HasElementRef { - _elementRef: ElementRef; - _renderer: Renderer2; -} - -export function -daffTextAlignmentMixin>(Base: T, defaultTextAlignment?: DaffTextAlignment) { - class DaffTextAlignableMixin extends Base { - // TODO move this back to private in Typescript 3.1 - _textAlignment: DaffTextAlignment; - - /** - * Controls text alignment for component-specific UI - */ - get textAlignment(): DaffTextAlignment { - return this._textAlignment; - } - set textAlignment(value: DaffTextAlignment) { - // Handles the default text alignment - const incomingTextAlignment = value || defaultTextAlignment; - - if (incomingTextAlignment === this._textAlignment) { // Only run the dom-render if a change occurs - return; - } - - // Removes the old text alignment - if (this._textAlignment) { - this._renderer.removeClass(this._elementRef.nativeElement, `daff-${this._textAlignment}`); - } - - if (incomingTextAlignment) { - this._renderer.addClass(this._elementRef.nativeElement, `daff-${incomingTextAlignment}`); - } - - this._textAlignment = incomingTextAlignment; - } - - constructor(...args: any[]) { - super(...args); - this.textAlignment = defaultTextAlignment; - } - }; - - // TODO: ugly workaround for https://github.com/microsoft/TypeScript/issues/7342#issuecomment-624298133 - Input()(DaffTextAlignableMixin.prototype, 'textAlignment'); - - return DaffTextAlignableMixin; -} diff --git a/libs/design/src/core/text-alignable/text-alignable.directive.spec.ts b/libs/design/src/core/text-alignable/text-alignable.directive.spec.ts new file mode 100644 index 0000000000..941bf9faac --- /dev/null +++ b/libs/design/src/core/text-alignable/text-alignable.directive.spec.ts @@ -0,0 +1,86 @@ +import { + Component, + DebugElement, +} from '@angular/core'; +import { + waitForAsync, + ComponentFixture, + TestBed, +} from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; + +import { DaffTextAlignment } from './text-alignable'; +import { DaffTextAlignableDirective } from './text-alignable.directive'; + +@Component({ + template: ` +
`, +}) + +class WrapperComponent { + textAlignment: DaffTextAlignment; +} + +describe('@daffodil/design | DaffTextAlignableDirective', () => { + let wrapper: WrapperComponent; + let de: DebugElement; + let fixture: ComponentFixture; + let directive: DaffTextAlignableDirective; + + beforeEach(waitForAsync(() => { + TestBed.configureTestingModule({ + declarations: [ + WrapperComponent, + ], + imports: [ + DaffTextAlignableDirective, + ], + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(WrapperComponent); + wrapper = fixture.componentInstance; + de = fixture.debugElement.query(By.css('[daffTextAlignable]')); + + directive = de.injector.get(DaffTextAlignableDirective); + fixture.detectChanges(); + }); + + it('should create', () => { + expect(wrapper).toBeTruthy(); + expect(directive).toBeTruthy(); + }); + + it('should take textAlignment as an input', () => { + expect(directive.textAlignment).toEqual(wrapper.textAlignment); + }); + + it('should add a class of .daff-left to the host element if textAlignment is set to left', () => { + wrapper.textAlignment = 'left'; + fixture.detectChanges(); + + expect(directive.class).toEqual(jasmine.objectContaining({ + 'daff-left': true, + })); + }); + + it('should add a class of .daff-center to the host element if textAlignment is set to center', () => { + wrapper.textAlignment = 'center'; + fixture.detectChanges(); + + expect(directive.class).toEqual(jasmine.objectContaining({ + 'daff-center': true, + })); + }); + + it('should add a class of .daff-right to the host element if textAlignment is set to right', () => { + wrapper.textAlignment = 'right'; + fixture.detectChanges(); + + expect(directive.class).toEqual(jasmine.objectContaining({ + 'daff-right': true, + })); + }); +}); diff --git a/libs/design/src/core/text-alignable/text-alignable.directive.ts b/libs/design/src/core/text-alignable/text-alignable.directive.ts new file mode 100644 index 0000000000..f2f04fc25b --- /dev/null +++ b/libs/design/src/core/text-alignable/text-alignable.directive.ts @@ -0,0 +1,48 @@ +import { + Directive, + HostBinding, + Input, + OnChanges, + SimpleChanges, +} from '@angular/core'; + +import { + DaffTextAlignable, + DaffTextAlignment, + DaffTextAlignmentEnum, +} from './text-alignable'; + +@Directive({ + selector: '[daffTextAlignable]', + standalone: true, +}) + +export class DaffTextAlignableDirective implements DaffTextAlignable, OnChanges { + /** + * @docs-private + */ + @HostBinding('class') get class() { + return { + 'daff-left': this.textAlignment === DaffTextAlignmentEnum.Left, + 'daff-center': this.textAlignment === DaffTextAlignmentEnum.Center, + 'daff-right': this.textAlignment === DaffTextAlignmentEnum.Right, + }; + } + + /** + * Sets the textAlignment on a component. + */ + @Input() textAlignment: DaffTextAlignment; + + /** + * Sets a default textAlignment. + */ + defaultAlignment: DaffTextAlignment; + + ngOnChanges(changes: SimpleChanges) { + if(!changes.textAlignment.currentValue) { + this.textAlignment = this.defaultAlignment; + } + } +} + diff --git a/libs/design/src/core/text-alignable/text-alignable.spec.ts b/libs/design/src/core/text-alignable/text-alignable.spec.ts deleted file mode 100644 index 23704ad28a..0000000000 --- a/libs/design/src/core/text-alignable/text-alignable.spec.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { ElementRef } from '@angular/core'; - -import { daffTextAlignmentMixin } from './text-alignable-mixin'; - -class TestingClass { - 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 | daffTextAlignmentMixin', () => { - let instance; - let classWithTextAlignment; - - beforeEach(() => { - classWithTextAlignment = daffTextAlignmentMixin(TestingClass); - instance = new classWithTextAlignment(); - }); - - it('should add a text alignment property to an existing class', () => { - expect('textAlignment' in instance).toBeTruthy(); - }); - - it('should allow the consuming class to optionally define a default text alignment', () => { - classWithTextAlignment = daffTextAlignmentMixin(TestingClass, 'center'); - instance = new classWithTextAlignment(); - - expect(instance.textAlignment).toEqual('center'); - expect(instance.element.classList).toContain('daff-center'); - }); - - describe('when a text alignment is specified', () => { - - it('should set a namespaced text alignment class', () => { - instance.textAlignment = 'center'; - - expect(instance.element.classList).toContain('daff-center'); - }); - }); - - describe('when a text alignment is not specified', () => { - - it('should default to no text alignment class', () => { - instance.textAlignment = undefined; - expect(instance.element.classList.length).toEqual(0); - }); - }); - - describe('when `textAlignment` changes', () => { - - beforeEach(() => { - instance.textAlignment = 'center'; - instance.textAlignment = 'left'; - }); - - it('should add the new text alignment class', () => { - expect(instance.element.classList).toContain('daff-left'); - }); - - it('should remove the provious text alignment class', () => { - expect(instance.element.classList).not.toContain('daff-center'); - }); - }); - - describe('when a default text alignment is undefined', () => { - describe('and text alignment is set to null or undefined', () => { - it('should do nothing', () => { - instance.textAlignment = null; - expect(instance.element.classList.value).toEqual(''); - - instance.textAlignment = undefined; - expect(instance.element.classList.value).toEqual(''); - }); - }); - }); - - describe('when a default text alignment is specified', () => { - - beforeEach(() => { - classWithTextAlignment = daffTextAlignmentMixin(TestingClass, 'left'); - instance = new classWithTextAlignment(); - }); - - describe('and text alignment is set to null or undefined', () => { - it('should set text alignment to the default text alignment ', () => { - instance.textAlignment = null; - - expect(instance.textAlignment).toEqual('left'); - expect(instance.element.classList).toContain('daff-left'); - - instance.textAlignment = undefined; - - expect(instance.textAlignment).toEqual('left'); - expect(instance.element.classList).toContain('daff-left'); - }); - }); - }); -}); diff --git a/libs/design/src/core/text-alignable/text-alignable.ts b/libs/design/src/core/text-alignable/text-alignable.ts index 6f4c231850..0c318c0393 100644 --- a/libs/design/src/core/text-alignable/text-alignable.ts +++ b/libs/design/src/core/text-alignable/text-alignable.ts @@ -1,6 +1,5 @@ /** - * An interface for giving a component the ability to customize text alignment for component-specific UI. - * In order to be text alignable, a component class must implement this property. + * Interface for giving a component the ability to customize text alignment for component-specific UI. */ export interface DaffTextAlignable { textAlignment: DaffTextAlignment;