Skip to content

Commit

Permalink
feat(design)!: change daffStatusMixin to a directive (#2941)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: daffStatusMixin has been removed in favor of DaffStatusableDirective. Update usage by using the hostDirective feature.
  • Loading branch information
xelaint authored Jul 30, 2024
1 parent d39a0fb commit 688b92d
Show file tree
Hide file tree
Showing 14 changed files with 207 additions and 259 deletions.
16 changes: 7 additions & 9 deletions libs/design/button/src/button/button.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,17 +207,15 @@ describe('@daffodil/design/button | DaffButtonComponent', () => {
});
});

describe('using the status property of a button', () => {
it('should not set a default status', () => {
expect(component.status).toBeFalsy();
});
it('should take status as an input', () => {
wrapper.status = 'warn';
fixture.detectChanges();

it('should add the class of the defined status to the host element', () => {
wrapper.status = 'warn';
fixture.detectChanges();
expect(de.nativeElement.classList.contains('daff-warn')).toEqual(true);
});

expect(de.nativeElement.classList.contains('daff-warn')).toEqual(true);
});
it('should not set a default status', () => {
expect(component.status).toBeFalsy();
});

describe('using the tabindex property of a button', () => {
Expand Down
13 changes: 8 additions & 5 deletions libs/design/button/src/button/button.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,8 @@ import {
DaffSuffixable,
daffPrefixableMixin,
daffSuffixableMixin,
DaffStatusable,
daffStatusMixin,
DaffArticleEncapsulatedDirective,
DaffStatusableDirective,
} from '@daffodil/design';

import { DaffButtonSizableDirective } from './button-sizable.directive';
Expand All @@ -43,7 +42,7 @@ class DaffButtonBase{
constructor(public _elementRef: ElementRef, public _renderer: Renderer2) {}
}

const _daffButtonBase = daffPrefixableMixin(daffSuffixableMixin(daffColorMixin(daffStatusMixin((DaffButtonBase)))));
const _daffButtonBase = daffPrefixableMixin(daffSuffixableMixin(daffColorMixin((DaffButtonBase))));

export type DaffButtonType = 'daff-button' | 'daff-stroked-button' | 'daff-raised-button' | 'daff-flat-button' | 'daff-icon-button' | 'daff-underline-button' | undefined;

Expand Down Expand Up @@ -78,20 +77,24 @@ enum DaffButtonTypeEnum {
styleUrls: ['./button.component.scss'],
//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', 'status'],
inputs: ['color'],
hostDirectives: [
{ directive: DaffArticleEncapsulatedDirective },
{
directive: DaffButtonSizableDirective,
inputs: ['size'],
},
{
directive: DaffStatusableDirective,
inputs: ['status'],
},
],
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class DaffButtonComponent
extends _daffButtonBase
implements OnInit, DaffPrefixable, DaffSuffixable, DaffColorable, DaffStatusable {
implements OnInit, DaffPrefixable, DaffSuffixable, DaffColorable {

private buttonType: DaffButtonType;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<daff-notification [status]="statusControl.value">
<fa-icon *ngIf="statusControl.value === 'success'" daffPrefix [icon]="faCheck" [fixedWidth]="true"></fa-icon>
<fa-icon *ngIf="statusControl.value === 'warn'" daffPrefix [icon]="faExclamation" [fixedWidth]="true"></fa-icon>
<fa-icon *ngIf="statusControl.value === 'error'" daffPrefix [icon]="faExclamation" [fixedWidth]="true"></fa-icon>
<fa-icon *ngIf="statusControl.value === 'danger'" daffPrefix [icon]="faExclamation" [fixedWidth]="true"></fa-icon>
<div daffNotificationTitle>Title</div>
<div daffNotificationSubtitle>This is the subtitle with information</div>
</daff-notification>

<select [formControl]="statusControl">
<option value="success">Success</option>
<option value="warn">Warn</option>
<option value="error">Error</option>
<option value="danger">Danger</option>
</select>
2 changes: 1 addition & 1 deletion libs/design/notification/src/notification-theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
}
}

&.daff-error {
&.daff-danger {
background: theming.daff-color(theming.$daff-red, 10);
border: 1px solid theming.daff-color(theming.$daff-red, 20);
color: theming.daff-text-contrast(theming.daff-color(theming.$daff-red, 10));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import {
Component,
ContentChild,
DebugElement,
Input,
ViewChild,
} from '@angular/core';
import {
waitForAsync,
Expand All @@ -18,7 +15,6 @@ import {
DaffNotificationComponent,
DaffNotificationOrientation,
} from './notification.component';
import { DaffNotificationActionsDirective } from '../notification-actions/notification-actions.directive';

@Component ({
template: `
Expand Down Expand Up @@ -133,17 +129,11 @@ describe('@daffodil/design/notification | DaffNotificationComponent', () => {
});
});

describe('using the status property of a notification', () => {
it('should not set a default status', () => {
expect(component.status).toBeFalsy();
});

it('should add the class of the defined status to the host element', () => {
wrapper.status = 'warn';
fixture.detectChanges();
it('should take status as an input', () => {
wrapper.status = 'warn';
fixture.detectChanges();

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

describe('setting the orientation of a notification', () => {
Expand Down
40 changes: 12 additions & 28 deletions libs/design/notification/src/notification/notification.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,12 @@ import {
DaffArticleEncapsulatedDirective,
DaffPrefixable,
DaffPrefixDirective,
DaffStatusable,
DaffStatusableDirective,
DaffStatusEnum,
daffStatusMixin,
} from '@daffodil/design';

import { DaffNotificationActionsDirective } from '../notification-actions/notification-actions.directive';

/**
* An _elementRef is needed for the core mixins
*/
class DaffNotificationBase {
constructor(public _elementRef: ElementRef, public _renderer: Renderer2) {}
}

const _daffNotificationBase = daffStatusMixin(DaffNotificationBase);

export type DaffNotificationOrientation = 'horizontal' | 'vertical';

enum DaffNotificationOrientationEnum {
Expand All @@ -47,18 +37,17 @@ enum DaffNotificationOrientationEnum {
selector: 'daff-notification',
templateUrl: './notification.component.html',
styleUrls: ['./notification.component.scss'],
// 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: ['status'],
hostDirectives: [{
directive: DaffArticleEncapsulatedDirective,
}],
hostDirectives: [
{ directive: DaffArticleEncapsulatedDirective },
{
directive: DaffStatusableDirective,
inputs: ['status'],
},
],
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class DaffNotificationComponent
extends _daffNotificationBase
implements DaffPrefixable, DaffStatusable {
export class DaffNotificationComponent implements DaffPrefixable {
faTimes = faTimes;

@ContentChild(DaffPrefixDirective) _prefix: DaffPrefixDirective;
Expand All @@ -74,7 +63,7 @@ export class DaffNotificationComponent
* Sets role to status on all other instances.
*/
@HostBinding('attr.role') get role() {
return this.status === DaffStatusEnum.Warn || this.status === DaffStatusEnum.Danger ? 'alert' : 'status';
return this.statusDirective.status === DaffStatusEnum.Warn || this.statusDirective.status === DaffStatusEnum.Danger ? 'alert' : 'status';
};

@HostBinding('class.vertical') get verticalOrientation() {
Expand All @@ -88,6 +77,8 @@ export class DaffNotificationComponent
/** Whether or not a notification is closable */
@Input() @HostBinding('class.dismissible') dismissible = false;

constructor(private statusDirective: DaffStatusableDirective) {}

private _orientation: DaffNotificationOrientation = DaffNotificationOrientationEnum.Vertical;

@Input()
Expand All @@ -103,13 +94,6 @@ export class DaffNotificationComponent
}
};

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

/**
* Output event triggered when the close icon is clicked.
*/
Expand Down
2 changes: 1 addition & 1 deletion libs/design/src/core/statusable/public_api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ export {
DaffStatus,
DaffStatusEnum,
} from './statusable';
export { daffStatusMixin } from './statusable-mixin';
export { DaffStatusableDirective } from './statusable.directive';
55 changes: 0 additions & 55 deletions libs/design/src/core/statusable/statusable-mixin.ts

This file was deleted.

86 changes: 86 additions & 0 deletions libs/design/src/core/statusable/statusable.directive.spec.ts
Original file line number Diff line number Diff line change
@@ -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 { DaffStatus } from './statusable';
import { DaffStatusableDirective } from './statusable.directive';

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

class WrapperComponent {
status: DaffStatus;
}

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

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

beforeEach(() => {
fixture = TestBed.createComponent(WrapperComponent);
wrapper = fixture.componentInstance;
de = fixture.debugElement.query(By.css('[daffStatusable]'));

directive = de.injector.get(DaffStatusableDirective);
fixture.detectChanges();
});

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

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

it('should add a class of .daff-warn to the host element if status is set to warn', () => {
wrapper.status = 'warn';
fixture.detectChanges();

expect(directive.class).toEqual(jasmine.objectContaining({
'daff-warn': true,
}));
});

it('should add a class of .daff-danger to the host element if status is set to danger', () => {
wrapper.status = 'danger';
fixture.detectChanges();

expect(directive.class).toEqual(jasmine.objectContaining({
'daff-danger': true,
}));
});

it('should add a class of .daff-success to the host element if status is set to success', () => {
wrapper.status = 'success';
fixture.detectChanges();

expect(directive.class).toEqual(jasmine.objectContaining({
'daff-success': true,
}));
});
});
Loading

0 comments on commit 688b92d

Please sign in to comment.