Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(notification): allow configuration of default options #636

Merged
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 =
splincode marked this conversation as resolved.
Show resolved Hide resolved
| 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,35 @@
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 = 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