Skip to content

Commit

Permalink
feat(notification): allow configuration of default options (#636)
Browse files Browse the repository at this point in the history
* feat(notification-alert): allow configuration of default options

* fix(core): implement review notes

* fix(core): move notification interfaces, add autoClose type

* feat(notification-alert): allow configuration of default options

* fix(core): implement review notes

* fix(core): move notification interfaces, add autoClose type

* chore: resolve conflicts

* chore: fix build

Co-authored-by: Dima Karimov <[email protected]>
Co-authored-by: Vladimir <[email protected]>
  • Loading branch information
3 people authored Oct 14, 2021
1 parent 1aa6b16 commit d89e523
Show file tree
Hide file tree
Showing 34 changed files with 673 additions and 98 deletions.
17 changes: 12 additions & 5 deletions projects/core/components/notification/notification.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@ import {
Output,
} from '@angular/core';
import {tuiDefaultProp} from '@taiga-ui/cdk';
import {TuiNotification} from '@taiga-ui/core/enums';
import {TUI_CLOSE_WORD} from '@taiga-ui/core/tokens';
import {
NotificationTokenOptions,
TUI_CLOSE_WORD,
TUI_NOTIFICATION_OPTIONS,
} from '@taiga-ui/core/tokens';
import {Observable} from 'rxjs';

export const STATUS_ICON = {
Expand All @@ -30,17 +33,21 @@ export class TuiNotificationComponent {
@Input()
@HostBinding('class._has-icon')
@tuiDefaultProp()
hasIcon = true;
hasIcon = this.options.hasIcon;

@Input()
@HostBinding('attr.data-tui-host-status')
@tuiDefaultProp()
status: 'info' | 'error' | 'warning' | 'success' = TuiNotification.Info;
status: 'info' | 'error' | 'warning' | 'success' = this.options.status;

@Output()
readonly close = new EventEmitter<void>();

constructor(@Inject(TUI_CLOSE_WORD) readonly closeWord$: Observable<string>) {}
constructor(
@Inject(TUI_CLOSE_WORD) readonly closeWord$: Observable<string>,
@Inject(TUI_NOTIFICATION_OPTIONS)
public readonly options: NotificationTokenOptions,
) {}

get icon(): string {
return STATUS_ICON[this.status];
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import {Component, DebugElement, ViewChild} from '@angular/core';
import {ComponentFixture, TestBed} from '@angular/core/testing';
import {NoopAnimationsModule} from '@angular/platform-browser/animations';
import {
TUI_NOTIFICATION_DEFAULT_OPTIONS,
TUI_NOTIFICATION_OPTIONS,
} from '@taiga-ui/core/tokens';
import {PageObject} from '@taiga-ui/testing';
import {configureTestSuite} from 'ng-bullet';
import {TuiNotification} from '../../../enums/notification';
Expand Down Expand Up @@ -106,3 +110,61 @@ describe('Notification', () => {
});
});
});

describe('Notification with TUI_NOTIFICATION_OPTIONS', () => {
@Component({
template: `
<tui-notification>Short simple informational message</tui-notification>
`,
})
class TestComponent {
@ViewChild(TuiNotificationComponent, {static: false})
component: TuiNotificationComponent;
}

const status = TuiNotification.Error;
const hasIcon = false;

let fixture: ComponentFixture<TestComponent>;
let testComponent: TestComponent;
let pageObject: PageObject<TestComponent>;

function getIcon(): DebugElement {
return pageObject.getByAutomationId('tui-notification__icon')!;
}

configureTestSuite(() => {
TestBed.configureTestingModule({
imports: [NoopAnimationsModule, TuiNotificationModule],
declarations: [TestComponent],
providers: [
TuiSvgService,
{
provide: TUI_NOTIFICATION_OPTIONS,
useValue: {
...TUI_NOTIFICATION_DEFAULT_OPTIONS,
status,
hasIcon,
},
},
],
});
});

beforeEach(() => {
fixture = TestBed.createComponent(TestComponent);
pageObject = new PageObject(fixture);
testComponent = fixture.componentInstance;
fixture.detectChanges();
});

describe('icon', () => {
it('chosen correctly depending on the status', () => {
expect(testComponent.component.icon).toBe(STATUS_ICON[status]);
});

it('when hasIcon = false is absent', () => {
expect(getIcon()).toBeNull();
});
});
});
1 change: 1 addition & 0 deletions projects/core/interfaces/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ export * from './icon-error';
export * from './number-format-settings';
export * from './value-content-context';
export * from './with-optional-min-max';
export * from './notification-options';
20 changes: 20 additions & 0 deletions projects/core/interfaces/notification-options.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import {TuiContextWithImplicit} from '@taiga-ui/cdk';
import {TuiNotification} from '@taiga-ui/core/enums';
import {PolymorpheusContent} from '@tinkoff/ng-polymorpheus';

export type TuiNotificationAutoClose =
| boolean
| number
| ((status: TuiNotification) => number | boolean);

export interface TuiNotificationOptions {
readonly label?: PolymorpheusContent<TuiContextWithImplicit<TuiNotification>>;
readonly status?: TuiNotification;
readonly hasIcon?: boolean;
readonly autoClose?: TuiNotificationAutoClose;
readonly hasCloseButton?: boolean;
}

export interface TuiNotificationOptionsWithData<I> extends TuiNotificationOptions {
readonly data: I;
}
1 change: 0 additions & 1 deletion projects/core/modules/notifications/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,5 @@ export * from './notification-alert/notification-alert.module';
export * from './notification-alert/Notification-alert';
export * from './notifications-host/notifications-host.component';
export * from './notification-content-context';
export * from './notification-options';
export * from './notifications.module';
export * from './notifications.service';
Original file line number Diff line number Diff line change
@@ -1,50 +1,38 @@
import {TuiContextWithImplicit} from '@taiga-ui/cdk';
import {TuiNotification} from '@taiga-ui/core/enums';
import {PolymorpheusContent} from '@tinkoff/ng-polymorpheus';
import {Observer} from 'rxjs';
import {TuiNotificationContentContext} from '../notification-content-context';
import {
TuiNotificationOptions,
TuiNotificationOptionsWithData,
} from '../notification-options';
} from '@taiga-ui/core/interfaces';
import {PolymorpheusContent} from '@tinkoff/ng-polymorpheus';
import {Observer} from 'rxjs';
import {TuiNotificationContentContext} from '../notification-content-context';

export class NotificationAlert<O, I> {
readonly status: TuiNotification;
readonly status = this.options.status;

readonly hasIcon: boolean;
readonly hasIcon = this.options.hasIcon;

readonly autoClose: boolean | number;

readonly hasCloseButton: boolean;
readonly hasCloseButton = this.options.hasCloseButton;

readonly label: string;
readonly label: PolymorpheusContent<TuiContextWithImplicit<TuiNotification>> = this
.options.label;

readonly data!: I;

readonly observer: Observer<O>;

readonly content: PolymorpheusContent<TuiNotificationContentContext<O, I>>;

constructor(
observer: Observer<O>,
content: PolymorpheusContent<TuiNotificationContentContext<O, I>>,
options: TuiNotificationOptions | TuiNotificationOptionsWithData<I>,
readonly observer: Observer<O>,
readonly content: PolymorpheusContent<TuiNotificationContentContext<O, I>>,
private readonly options: Required<
TuiNotificationOptions | TuiNotificationOptionsWithData<I>
>,
) {
const {
label = '',
status = TuiNotification.Info,
hasIcon = true,
autoClose = true,
hasCloseButton = true,
} = options;

this.observer = observer;
this.content = content;

this.label = label;
this.status = status;
this.hasIcon = hasIcon;
this.autoClose = autoClose;
this.hasCloseButton = hasCloseButton;
this.autoClose =
typeof this.options.autoClose === 'function'
? this.options.autoClose(this.options.status)
: this.options.autoClose;

if (options && this.withData(options)) {
this.data = options.data;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
OnInit,
} from '@angular/core';
import {isNumber, TuiDestroyService, tuiPure} from '@taiga-ui/cdk';
import {NotificationTokenOptions, TUI_NOTIFICATION_OPTIONS} from '@taiga-ui/core/tokens';
import {fromEvent, timer} from 'rxjs';
import {repeatWhen, takeUntil} from 'rxjs/operators';
import {TuiNotificationContentContext} from '../notification-content-context';
Expand All @@ -23,31 +24,25 @@ export const DEFAULT_ALERT_AUTOCLOSE_TIMEOUT = 3000;
})
export class TuiNotificationAlertComponent<O, I> implements OnInit {
@Input()
item?: NotificationAlert<O, I>;
item!: NotificationAlert<O, I>;

constructor(
@Inject(ElementRef) private readonly elementRef: ElementRef<HTMLElement>,
@Inject(TuiDestroyService) private readonly destroy$: TuiDestroyService,
@Inject(TUI_NOTIFICATION_OPTIONS)
public readonly options: NotificationTokenOptions,
) {}

ngOnInit() {
this.initAutoClose();
}

get safeItem(): NotificationAlert<O, I> {
if (!this.item) {
throw new Error('Notification was created as undefined');
}

return this.item;
}

get context(): TuiNotificationContentContext<O, I> {
return this.calculateContext(this.safeItem);
return this.calculateContext(this.item);
}

closeNotification() {
this.safeItem.observer.complete();
this.item.observer.complete();
}

@tuiPure
Expand Down Expand Up @@ -75,13 +70,13 @@ export class TuiNotificationAlertComponent<O, I> implements OnInit {
}

private initAutoClose() {
if (!this.safeItem.autoClose) {
if (!this.item.autoClose) {
return;
}

timer(
isNumber(this.safeItem.autoClose)
? this.safeItem.autoClose
isNumber(this.item.autoClose)
? this.item.autoClose
: DEFAULT_ALERT_AUTOCLOSE_TIMEOUT,
)
.pipe(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,38 +1,42 @@
<tui-notification
*ngIf="safeItem.hasCloseButton else noClose"
[status]="safeItem.status"
[hasIcon]="safeItem.hasIcon"
*ngIf="item.hasCloseButton else noClose"
[status]="item.status"
[hasIcon]="item.hasIcon"
(close)="closeNotification()"
>
<label
*ngIf="safeItem.label"
*ngIf="item.label"
polymorpheus-outlet
automation-id="tui-notification-alert__heading"
class="heading"
[content]="item.label"
[context]="context"
>
{{safeItem.label}}
</label>
<div
polymorpheus-outlet
automation-id="tui-notification-alert__content"
class="content"
[content]="safeItem.content"
[content]="item.content"
[context]="context"
></div>
</tui-notification>
<ng-template #noClose>
<tui-notification [status]="safeItem.status" [hasIcon]="safeItem.hasIcon">
<tui-notification [status]="item.status" [hasIcon]="item.hasIcon">
<label
*ngIf="safeItem.label"
*ngIf="item.label"
polymorpheus-outlet
automation-id="tui-notification-alert__heading"
class="heading"
[content]="item.label"
[context]="context"
>
{{safeItem.label}}
</label>
<div
polymorpheus-outlet
automation-id="tui-notification-alert__content"
class="content"
[content]="safeItem.content"
[content]="item.content"
[context]="context"
></div>
</tui-notification>
Expand Down
Loading

0 comments on commit d89e523

Please sign in to comment.