diff --git a/apps/design-land/src/app/app.module.ts b/apps/design-land/src/app/app.module.ts
index 40f47cf614..184398a1a2 100644
--- a/apps/design-land/src/app/app.module.ts
+++ b/apps/design-land/src/app/app.module.ts
@@ -13,7 +13,7 @@ import { DaffButtonModule } from '@daffodil/design/button';
import { DaffLinkSetModule } from '@daffodil/design/link-set';
import { DaffNavbarModule } from '@daffodil/design/navbar';
import { DaffSidebarModule } from '@daffodil/design/sidebar';
-import { DaffToastModule } from '@daffodil/design/toast';
+import { daffProvideToast } from '@daffodil/design/toast';
import { DaffThemeSwitchButtonModule } from '@daffodil/theme-switch';
import { DesignLandAppRoutingModule } from './app-routing.module';
@@ -41,11 +41,11 @@ import { DesignLandTemplateModule } from './core/template/template.module';
FontAwesomeModule,
DesignLandNavModule,
DesignLandTemplateModule,
- DaffToastModule,
],
providers: [
DAFF_THEME_INITIALIZER,
provideHttpClient(withInterceptorsFromDi()),
+ daffProvideToast(),
],
})
export class AppModule { }
diff --git a/apps/design-land/src/app/toast/toast.module.ts b/apps/design-land/src/app/toast/toast.module.ts
index 35b22d28c7..c9e35e68f0 100644
--- a/apps/design-land/src/app/toast/toast.module.ts
+++ b/apps/design-land/src/app/toast/toast.module.ts
@@ -3,7 +3,6 @@ import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { DaffArticleModule } from '@daffodil/design/article';
-import { DaffToastModule } from '@daffodil/design/toast';
import { DesignLandToastRoutingModule } from './toast-routing-module';
import { DesignLandToastComponent } from './toast.component';
@@ -22,7 +21,6 @@ import { DesignLandExampleViewerModule } from '../core/code-preview/container/ex
DesignLandArticleEncapsulatedModule,
DaffArticleModule,
- DaffToastModule,
],
})
export class DesignLandToastModule {}
diff --git a/libs/design/toast/README.md b/libs/design/toast/README.md
index f3931beb93..40f91ab337 100644
--- a/libs/design/toast/README.md
+++ b/libs/design/toast/README.md
@@ -4,10 +4,23 @@ Toasts are small messages designed to mimic push notifications. They are used to
## Overview
Toasts should be used to display temporary messages about actions or events that occured or in need of attention, with no relation to content on a page. For messaging that provide context in close promixity to a piece of content within a page, use the [Notification](/libs/design/notification/README.md) component.
-### Basic Toast
-
-
-
+## Basic Toast
+
+
+## Setting up the component
+`daffProviderToast()` should be added as a provider either in your application's root component for global use or in a specific feature component.
+
+```ts
+import { daffProvideToast } from '@daffodil/design/toast';
+
+@NgModule({
+ providers: [
+ daffProvideToast(),
+ ]
+)}
+
+export class AppModule {}
+```
### Configurations
Toast can be configured by using the `DaffToastService`.
@@ -15,31 +28,93 @@ Toast can be configured by using the `DaffToastService`.
The following is an example of a toast with a duration:
```ts
-constructor(private toastService: DaffToastService) {}
-
-open() {
- this.toast = this.toastService.open({
- title: 'Update Complete',
- message: 'This page has been updated to the newest version.',
- },
- {
- duration: 5000,
- });
+import {
+ ChangeDetectionStrategy,
+ Component,
+} from '@angular/core';
+
+import {
+ DaffToast
+ DaffToastService,
+} from '@daffodil/design/toast';
+
+@Component({
+ selector: 'custom-toast',
+ templateUrl: './custom-toast.component.html',
+ changeDetection: ChangeDetectionStrategy.OnPush,
+ standalone: true,
+})
+export class CustomToastComponent {
+ private toast: DaffToast;
+
+ constructor(private toastService: DaffToastService) {}
+
+ open() {
+ this.toast = this.toastService.open({
+ title: 'Update Complete',
+ message: 'This page has been updated to the newest version.',
+ },
+ {
+ duration: 5000,
+ });
+ }
}
```
The following is an example of a toast with actions:
```ts
-open() {
- this.toast = this.toastService.open({
- title: 'Update Available',
- message: 'A new version of this page is available.',
- actions: [
- { content: 'Update', color: 'theme-contrast', size: 'sm', eventEmitter: this.update },
- { content: 'Remind me later', type: 'flat', size: 'sm', eventEmitter: this.closeToast },
- ]
- });
+import {
+ ChangeDetectionStrategy,
+ Component,
+ EventEmitter,
+ OnInit,
+} from '@angular/core';
+
+import { DAFF_BUTTON_COMPONENTS } from '@daffodil/design/button';
+import {
+ DaffToast,
+ DaffToastAction,
+ DaffToastService,
+} from '@daffodil/design/toast';
+
+@Component({
+ selector: 'action-toast',
+ templateUrl: './action-toast.component.html',
+ changeDetection: ChangeDetectionStrategy.OnPush,
+ standalone: true,
+ imports: [
+ DAFF_BUTTON_COMPONENTS,
+ ],
+})
+export class ActionToastComponent implements OnInit {
+ private toast: DaffToast;
+
+ constructor(private toastService: DaffToastService) {}
+
+ update = new EventEmitter();
+
+ closeToast = new EventEmitter();
+
+ open() {
+ this.toast = this.toastService.open({
+ title: 'Update Available',
+ message: 'A new version of this page is available.',
+ actions: [
+ { content: 'Update', color: 'theme-contrast', size: 'sm', eventEmitter: this.update },
+ { content: 'Remind me later', type: 'flat', size: 'sm', eventEmitter: this.closeToast },
+ ]
+ });
+ }
+
+ ngOnInit() {
+ this.update.subscribe(() => {
+ });
+
+ this.closeToast.subscribe(() => {
+ this.toastService.close(this.toast);
+ });
+ }
}
```
@@ -55,10 +130,10 @@ The following configurations are available in the `DaffToastService`:
The `actions` configurations are based on the properties of the `DaffButtonComponent` (view [Button Documentation](/libs/design/button/README.md)) with the addition of `data` and `eventEmitter`.
-### Dismissal
+## Dismissal
A toast can be dismissed via a timed duration, a close button, or the `ESC` key.
-##### Timed duration
+### Timed duration
A toast with actions will persist until one of the actions have been interacted with, or is dismissed by the close button or the `ESC` key. Actionable toasts should be persistent, but a duration is allowed to be set. If duration must be set, make sure it's long enough for users to engage with the actions.
By default, a toast without actions will be dismissed after `5000ms`. This can be updated by setting `duration` through the `DaffToastService`.
@@ -66,24 +141,24 @@ By default, a toast without actions will be dismissed after `5000ms`. This can b
#### Toast with custom duration
-##### Close button
+### Close button
The close button is shown by default but can be hidden by setting `dismissible: false` through the `DaffToastService`.
-##### Escape Key
+### Escape Key
A toast can be dismissed by using the `ESC` key if it has actions and is focus trapped.
-### Stacking
+## Stacking
A maximum of three toasts can be shown at a time. Toasts are stacked vertically, with the most recent toast displayed on top.
-### Statuses
+## Statuses
The status color of a toast can be updated by using the `status` property.
Supported statuses: `warn | danger | success`
-#### Toast with statuses
+### Toast with statuses
-### Positions
+## Positions
| Property | Value | Default |
| ------------ | ------------------------ | ------- |
@@ -106,10 +181,10 @@ providers: [
The position of a toast on a mobile device will always be on the bottom center.
-#### Toast with configurable positions
+### Toast with configurable positions
-### Accessibility
+## Accessibility
By default, toasts use a `role="status"` to announce messages. It's the equivalent of `aria-live="polite"`, which does not interrupt a user's current activity and waits until they are idle to make the announcement. When a toast has actions, a `role="alertdialog"` is used. The toast will be focus trapped and focus immediately moves to the actions.
Avoid setting a duration on toasts with actions because they will disappear automatically, making it difficult for users to interact with the actions.
\ No newline at end of file
diff --git a/libs/design/toast/examples/src/toast-status/toast-status.component.html b/libs/design/toast/examples/src/toast-status/toast-status.component.html
index db5b3db778..64ec395255 100644
--- a/libs/design/toast/examples/src/toast-status/toast-status.component.html
+++ b/libs/design/toast/examples/src/toast-status/toast-status.component.html
@@ -3,5 +3,5 @@
\ No newline at end of file
diff --git a/libs/design/toast/examples/src/toast-status/toast-status.component.ts b/libs/design/toast/examples/src/toast-status/toast-status.component.ts
index 0bfe08e5a7..c8d3128f50 100644
--- a/libs/design/toast/examples/src/toast-status/toast-status.component.ts
+++ b/libs/design/toast/examples/src/toast-status/toast-status.component.ts
@@ -19,8 +19,9 @@ import {
} from '@daffodil/design/toast';
const status: Record = {
- error: {
+ danger: {
title: 'Server error',
+ message: 'There is a server error.',
},
success: {
title: 'Update complete',
@@ -59,7 +60,7 @@ export class ToastStatusComponent {
...status[this.statusControl.value],
},
{
- duration: this.statusControl.value === 'error' ? undefined : 5000,
+ duration: this.statusControl.value === 'danger' ? undefined : 5000,
},
);
}
diff --git a/libs/design/toast/src/public_api.ts b/libs/design/toast/src/public_api.ts
index df18203755..70fa56f105 100644
--- a/libs/design/toast/src/public_api.ts
+++ b/libs/design/toast/src/public_api.ts
@@ -18,3 +18,4 @@ export * from './toast/toast.component';
export * from './toast-actions/toast-actions.directive';
export * from './toast-title/toast-title.directive';
export * from './toast-message/toast-message.directive';
+export * from './toast/toast-provider';
diff --git a/libs/design/toast/src/service/toast.service.spec.ts b/libs/design/toast/src/service/toast.service.spec.ts
index b17dc0cde4..b9e0087607 100644
--- a/libs/design/toast/src/service/toast.service.spec.ts
+++ b/libs/design/toast/src/service/toast.service.spec.ts
@@ -13,7 +13,6 @@ import {
DaffFocusStackService,
DaffPrefixSuffixModule,
} from '@daffodil/design';
-import { DaffButtonModule } from '@daffodil/design/button';
import { DaffToastPositionService } from './position.service';
import { DaffToastService } from './toast.service';
@@ -32,22 +31,20 @@ describe('@daffodil/design/toast | DaffToastService', () => {
TestBed.configureTestingModule({
imports: [
DaffPrefixSuffixModule,
- DaffButtonModule,
FontAwesomeModule,
PortalModule,
OverlayModule,
NoopAnimationsModule,
- ],
- providers: [
- DaffToastPositionService,
- ],
- declarations: [
+
DaffToastComponent,
DaffToastActionsDirective,
DaffToastTitleDirective,
DaffToastMessageDirective,
DaffToastTemplateComponent,
],
+ providers: [
+ DaffToastPositionService,
+ ],
});
const overlay = TestBed.inject(Overlay);
@@ -73,6 +70,7 @@ describe('@daffodil/design/toast | DaffToastService', () => {
TestBed.inject(BreakpointObserver),
TestBed.inject(DaffToastPositionService),
TestBed.inject(DaffFocusStackService),
+ null,
);
});
diff --git a/libs/design/toast/src/service/toast.service.ts b/libs/design/toast/src/service/toast.service.ts
index 268339dade..45003bc8e4 100644
--- a/libs/design/toast/src/service/toast.service.ts
+++ b/libs/design/toast/src/service/toast.service.ts
@@ -9,13 +9,13 @@ import {
EventEmitter,
Inject,
Injectable,
+ Injector,
OnDestroy,
Optional,
SkipSelf,
} from '@angular/core';
import {
EMPTY,
- interval,
merge,
of,
Subscription,
@@ -49,9 +49,8 @@ import {
DaffToastConfiguration,
} from '../toast/toast-config';
import { DaffToastTemplateComponent } from '../toast/toast-template.component';
-import { DaffToastModule } from '../toast.module';
-@Injectable({ providedIn: DaffToastModule })
+@Injectable()
export class DaffToastService implements OnDestroy {
private _sub: Subscription;
@@ -69,6 +68,7 @@ export class DaffToastService implements OnDestroy {
private mediaQuery: BreakpointObserver,
private toastPosition: DaffToastPositionService,
private focusStack: DaffFocusStackService,
+ private injector: Injector,
) {
this._sub = this.mediaQuery.observe(DaffBreakpoints.MOBILE).pipe(
filter(() => this._overlayRef !== undefined),
@@ -84,7 +84,7 @@ export class DaffToastService implements OnDestroy {
private _attachToastTemplate(
overlayRef: OverlayRef,
): ComponentRef {
- const template = overlayRef.attach(new ComponentPortal(DaffToastTemplateComponent));
+ const template = overlayRef.attach(new ComponentPortal(DaffToastTemplateComponent, null, this.injector));
return template;
}
diff --git a/libs/design/toast/src/toast-actions/toast-actions.directive.spec.ts b/libs/design/toast/src/toast-actions/toast-actions.directive.spec.ts
index 7e613342fd..1ff9a12e32 100644
--- a/libs/design/toast/src/toast-actions/toast-actions.directive.spec.ts
+++ b/libs/design/toast/src/toast-actions/toast-actions.directive.spec.ts
@@ -15,6 +15,10 @@ import { DaffToastActionsDirective } from './toast-actions.directive';
template: `
`,
+ standalone: true,
+ imports: [
+ DaffToastActionsDirective,
+ ],
})
class WrapperComponent {}
@@ -25,8 +29,7 @@ describe('DaffToastActionsDirective', () => {
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
- declarations: [
- DaffToastActionsDirective,
+ imports: [
WrapperComponent,
],
})
diff --git a/libs/design/toast/src/toast-actions/toast-actions.directive.ts b/libs/design/toast/src/toast-actions/toast-actions.directive.ts
index 1aa5a6a5d2..8faf3bc4c2 100644
--- a/libs/design/toast/src/toast-actions/toast-actions.directive.ts
+++ b/libs/design/toast/src/toast-actions/toast-actions.directive.ts
@@ -5,6 +5,7 @@ import {
@Directive({
selector: '[daffToastActions]',
+ standalone: true,
})
export class DaffToastActionsDirective {
diff --git a/libs/design/toast/src/toast-message/toast-message.directive.spec.ts b/libs/design/toast/src/toast-message/toast-message.directive.spec.ts
index e59919d2a6..bede1d47eb 100644
--- a/libs/design/toast/src/toast-message/toast-message.directive.spec.ts
+++ b/libs/design/toast/src/toast-message/toast-message.directive.spec.ts
@@ -15,6 +15,10 @@ import { DaffToastMessageDirective } from './toast-message.directive';
template: `