+ An Alert is an element intended for
+ system-generated messages. It is a live region with important, usually time-sensitive information.
+ The use of this alert component will cause immediate notifications for users with assistive technology. Since alerts
+ are not required to receive focus, it should not be required that the user close the alert.
+
For messages that are the result of a user's actions see the
+ Toast
+ component.)
+
+
+
+ Typically it displays a brief, important message in a way that attracts the user's attention, without interrupting
+ the user's task.
+
+
+
+ There are three types of alerts, each slightly different one from another.
+
+
+
Page
+
It is rectangular (without a radius) and a visible border only at the bottom. Typically
+ only has adjacent whitespace to the bottom of it, meaning it's usually flush to the parent container.
+
+
+ It can have an
+ icon
+ (optional), a
+ title
+ and/or
+ description
+ (required to have at least one of the two), some
+ actions
+ (optional) and a
+ dismiss/close
+ button (optional).
+
+
Inline
+
+ It has a border on all sides and a radius. Typically it has adjacent whitespace on all four sides.
+
+
+ It can have an
+ icon
+ (optional), a
+ title
+ and/or
+ description
+ (required to have at least one of the two), some
+ actions
+ (optional) and a
+ dismiss/close
+ button (optional).
+
+ Notice: the "inline" alert is used to build the
+ Toast
+ component.
+
+
Compact
+
+ It's without border or internal padding, and so it has smaller proportions than the others.
+
+
+ It only contains an
+ icon
+ and
+ description
+ (hence they are both required for this type of alert).
+
The default icon is also slightly different from the other alert types: it's filled instead
+ of outlined.
+
+ Sets the color scheme for
+ background,
+ border,
+ title, and
+ description, which
+ cannot
+ be overridden.
+ color
+ results in a default
+ icon, which
+ can
+ be overridden.
+
+
Acceptable values:
+
+
neutral
+
highlight
+
success
+
warning
+
critical
+
+
+
icon string | false
+
+
Override the default
+ icon
+ name, which is determined by the
+ color
+ argument.
+
Acceptable values: any
+
+ Flight
+ icon name or pass
+ false
+ for no icon.
+
+
+
title string
+
+
The title text in the alert.
+
+
+
description string
+
+
The description text in the alert.
+
+
onDismiss function
+
+
+ The alert can be dismissed by the user. When a function is passed, the "dismiss" button is displayed.
+
+
+
+
...attributes
+
+
...attributes spreading is supported on this component.
+
+
+
+
Contextual components
+
Actions and generic content can optionally be passed into
+ the alert as yielded components, using the
+ Button,
+ Link::Standalone,
+ LinkTo::Standalone,
+ Generic
+ keys.
+
+
<[A].Button> yielded component
+
+
It is a yielded
+ HDS::Button
+ component, so it exposes exactly
+ the same API of the
+ Button
+ component, apart from the
+ @size
+ argument that is pre-defined to be
+ small, and the
+ @color
+ argument that accepts only
+ secondary
+ or
+ tertiary.
+
+
<[A].Link::Standalone> yielded component
+
+
It is a yielded
+ HDS::Link::Standalone
+ component, so it exposes exactly
+ the same API of the
+ Link::Standalone
+ component, apart from the
+ @size
+ argument that is pre-defined to be
+ small.
+
+
<[A].LinkTo::Standalone> yielded component
+
+
It is a yielded
+ HDS::LinkTo::Standalone
+ component, so it exposes exactly
+ the same API of the
+ LinkTo::Standalone
+ component, apart from the
+ @size
+ argument that is pre-defined to be
+ small.
+
+
<[A].Generic> yielded component
+
+
It is a very simple component that yields its content (inside a
+ <div>) and accepts
+ ...attributes
+ spreading.
+
Notice: generic the content will appear at the bottom, after title, description and actions, and the
+ developer will need to take care of spacing, layout and styling of the custom content in this case.
+
🚨
+ Important: this method should be used only in special cases and as an escape hatch. If you
+ find yourself in need to use it, we suggest to speak with the design system team to check that the solution is
+ conformant and satifies the accessibility criteria.
+
+ The most basic invocation requires the
+ type,
+ title
+ and/or
+ text
+ arguments to be passed. By default a
+ neutral
+ alert is generated (with a neutral color applied and a specific icon visible).
+
+ A different color can be applied to the alert using the
+ color
+ argument. This will also determine the icon default used in the alert (unless overwritten, see below).
+
+ In some cases the alert needs to be dismissable. In this case you have to pass a callback function to the
+ onDismiss
+ argument. This will also automatically add a "dismiss/close" button to the alert, that when clicked will execute the
+ callback function.
+
+
+ 🚨
+ Important: the actual implementation of what happens to the alert when the callback function is
+ invoked is left to the developer (this will likely depent on the type of alert, on the context of where it's used,
+ on the specific use case, etc.).
+
Actions can optionally be passed to component using one of the suggested
+ Button,
+ Link::Standalone
+ or
+ LinkTo::Standalone
+ contextual components.
It's also possible to insert custom content in the component using the
+ Generic
+ contextual component.
+
+
Notice: the content will appear at the bottom, after title, description and actions,
+ and the developer will need to take care of spacing, layout and styling of the custom content in this case.
+
🚨
+ Important: this method should be used only in special cases and as an escape hatch. If you find
+ yourself in need to use it, we suggest to speak with the design system team to check that the solution is
+ conformant and satifies the accessibility criteria.
+
This component has been designed and implemented with accessibility in mind. When used as
+ designed, there should not be any accessibility issues with this component.
+
+
+ Applicable WCAG Success Criteria (Reference)
+
+
+ This section is for reference only. This component intends to conform to the following WCAG success criteria:
+
👀 Note: the compact alert is borderless, but shown with a dotted border throughout the
+ "Showcase" for clarity.
+
+
Type
+ {{#each @model.TYPES as |type|}}
+
{{capitalize type}}
+
+
+
+
+ {{/each}}
+
+
Color
+
+ {{#each @model.COLORS as |color|}}
+
{{capitalize color}}
+ {{#each @model.TYPES as |type|}}
+
+ {{type}} alert with {{color}} color."
+ />
+
+ {{/each}}
+ {{/each}}
+
+
+
Icon
+
+
+
+
+
+
+
+
Content
+
+
+
+
+
+ strong and em as well as code and links."
+ />
+ Generic contextual component."
+ as |A|
+ >
+
+
+
+
+
+
+
Actions
+
+
+
+
+
+
+
+
+
+
+
+
+
+
This for example could be extra text, specific for
+ a special use case.
+
+
+
+
+
Dismiss
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/components/tests/dummy/app/templates/components/link/cta.hbs b/packages/components/tests/dummy/app/templates/components/link/cta.hbs
index 017cd691a0f..946ad1ac13b 100644
--- a/packages/components/tests/dummy/app/templates/components/link/cta.hbs
+++ b/packages/components/tests/dummy/app/templates/components/link/cta.hbs
@@ -91,7 +91,7 @@
-
+ A Toast is an element intended for
+ messages that are the result of a user's actions
+ (for system-generated messages see the
+ Alert
+ component.).
+
+
+
Typically it displays a brief, temporary notification and it disappears on its own (after a
+ time interval) or as a result of a user interacting with it.
+
+
+
+ It can have an
+ icon
+ (optional), a
+ title
+ and/or
+ description
+ (required to have at least one of the two), some
+ actions
+ (optional) and a
+ dismiss/close
+ button.
+
+ 🚨
+ Important: we provide only the visual styling to this element, so other features like
+ placement, animations/transitions, and what happens on dismiss, will need to be implemented in your app (eg. with
+ an Ember addon).
+
+
Notice: the
+ Hds::Toast
+ component is built out of the
+ Hds::Alert(Inline)
+ component, so it shares the same API. Please refer to
+ the Alert Component API documentation
+ to know more.
+ The most basic invocation requires the
+ type,
+ title
+ and/or
+ text
+ arguments to be passed, and an
+ onDismiss
+ callback function. By default a
+ neutral
+ toast is generated (with a neutral color applied and a specific icon visible).
+
+ A different color can be applied to the toast using the
+ color
+ argument. This will also determine the icon default used in the toast (unless overwritten, see below).
+
Actions can optionally be passed into the component using one of the suggested
+ Button,
+ Link::Standalone
+ or
+ LinkTo::Standalone
+ yielded components.
It's also possible to insert custom content in the
+ Generic
+ contextual component.
+
+
Notice: the content will appear at the bottom, after title, description and actions,
+ and the developer will need to take care of spacing, layout and styling of the custom content in this case.
+
🚨
+ Important: this method should be used only in special cases and as an escape hatch. If you find
+ yourself in need to use it, we suggest to speak with the design system team to check that the solution is
+ conformant and satifies the accessibility criteria.
+
This component has been designed and implemented with accessibility in mind. When used as
+ designed, there should not be any accessibility issues with this component.
+
+
+ Applicable WCAG Success Criteria (Reference)
+
+
+ This section is for reference only. This component intends to conform to the following WCAG success criteria:
+
+
+
+
+
+ strong and em as well as code and links."
+ @onDismiss={{this.noop}}
+ />
+ Generic contextual component."
+ @onDismiss={{this.noop}}
+ as |A|
+ >
+
+
+
+
+
+
+
Actions
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/components/tests/dummy/app/templates/index.hbs b/packages/components/tests/dummy/app/templates/index.hbs
index c02cffee2a0..bdedd771b32 100644
--- a/packages/components/tests/dummy/app/templates/index.hbs
+++ b/packages/components/tests/dummy/app/templates/index.hbs
@@ -32,6 +32,11 @@
Components:
+
+
+ Alert
+
+
Badge
@@ -82,6 +87,11 @@
LinkTo::Standalone
+
+
+ Toast
+
+
Utilities:
diff --git a/packages/components/tests/dummy/public/assets/images/alert-design-usage-part1.png b/packages/components/tests/dummy/public/assets/images/alert-design-usage-part1.png
new file mode 100644
index 00000000000..e8fd5b84322
Binary files /dev/null and b/packages/components/tests/dummy/public/assets/images/alert-design-usage-part1.png differ
diff --git a/packages/components/tests/dummy/public/assets/images/alert-design-usage-part2.png b/packages/components/tests/dummy/public/assets/images/alert-design-usage-part2.png
new file mode 100644
index 00000000000..2f0290df67f
Binary files /dev/null and b/packages/components/tests/dummy/public/assets/images/alert-design-usage-part2.png differ
diff --git a/packages/components/tests/dummy/public/assets/images/toast-design-usage.png b/packages/components/tests/dummy/public/assets/images/toast-design-usage.png
new file mode 100644
index 00000000000..7ae0da031f4
Binary files /dev/null and b/packages/components/tests/dummy/public/assets/images/toast-design-usage.png differ
diff --git a/packages/components/tests/integration/components/hds/alert/index-test.js b/packages/components/tests/integration/components/hds/alert/index-test.js
new file mode 100644
index 00000000000..a2efd261026
--- /dev/null
+++ b/packages/components/tests/integration/components/hds/alert/index-test.js
@@ -0,0 +1,216 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render, resetOnerror, setupOnerror } from '@ember/test-helpers';
+import { hbs } from 'ember-cli-htmlbars';
+
+module('Integration | Component | hds/alert/index', function (hooks) {
+ setupRenderingTest(hooks);
+
+ hooks.afterEach(() => {
+ resetOnerror();
+ });
+
+ test('it renders the alert container', async function (assert) {
+ await render(hbs``);
+ assert.dom(this.element).exists();
+ });
+ test('it should render with a CSS class that matches the component name', async function (assert) {
+ await render(
+ hbs``
+ );
+ assert.dom('#test-alert').hasClass('hds-alert');
+ });
+
+ // TYPE
+
+ test('it should render the correct CSS type class if @type prop is declared', async function (assert) {
+ await render(
+ hbs``
+ );
+ assert.dom('#test-alert').hasClass('hds-alert--type-inline');
+ });
+
+ // ICON
+
+ test('it should render an icon by default depending on the type and color', async function (assert) {
+ // here we don't test all the possible combinations, only some of them as precaution
+ assert.expect(6);
+ await render(hbs``);
+ assert.dom('.flight-icon-info').exists();
+ await render(
+ hbs``
+ );
+ assert.dom('.flight-icon-info-fill').exists();
+ await render(
+ hbs``
+ );
+ assert.dom('.flight-icon-info').exists();
+ await render(
+ hbs``
+ );
+ assert.dom('.flight-icon-check-circle').exists();
+ await render(
+ hbs``
+ );
+ assert.dom('.flight-icon-alert-triangle').exists();
+ await render(
+ hbs``
+ );
+ assert.dom('.flight-icon-alert-diamond').exists();
+ });
+
+ test('if an icon is declared, the icon should render in the component and override the default one', async function (assert) {
+ assert.expect(2);
+ await render(
+ hbs``
+ );
+ assert.dom('.flight-icon-clipboard-copy').exists();
+ await render(
+ hbs``
+ );
+ assert.dom('.flight-icon-clipboard-copy').exists();
+ });
+
+ test('it should display no icon when @icon is set to false', async function (assert) {
+ await render(
+ hbs``
+ );
+ assert.dom('.flight-icon').doesNotExist();
+ });
+
+ // TEXT (TITLE + DESCRIPTION)
+
+ test('it should render the title when the @title argument is provided', async function (assert) {
+ await render(hbs``);
+ assert.dom(this.element).hasText('This is the title');
+ });
+ test('it should render the description when the @description argument is provided', async function (assert) {
+ await render(
+ hbs``
+ );
+ assert.dom(this.element).hasText('This is the description');
+ });
+ test('it should render both the title and the description when both the @title and @description arguments are provided', async function (assert) {
+ assert.expect(2);
+ await render(
+ hbs``
+ );
+ assert.dom('.hds-alert__title').hasText('This is the title');
+ assert.dom('.hds-alert__description').hasText('This is the description');
+ });
+ test('it should render rich HTML when the @description argument contains HTML tags', async function (assert) {
+ assert.expect(8);
+ await render(
+ hbs`strong and em and code and link" />`
+ );
+ assert.dom('.hds-alert__description strong').exists().hasText('strong');
+ assert.dom('.hds-alert__description em').exists().hasText('em');
+ assert.dom('.hds-alert__description code').exists().hasText('code');
+ assert.dom('.hds-alert__description a').exists().hasText('link');
+ });
+
+ // ACTIONS
+
+ test('it should render an Hds::Button component yielded to the "actions" container', async function (assert) {
+ assert.expect(5);
+ await render(
+ hbs``
+ );
+ assert
+ .dom('#test-alert .hds-alert__actions button')
+ .exists()
+ .hasClass('hds-button')
+ .hasClass('hds-button--size-small')
+ .hasClass('hds-button--color-secondary')
+ .hasText('I am a button');
+ });
+ test('it should render an Hds::Link::Standalone component yielded to the "actions" container', async function (assert) {
+ assert.expect(5);
+ await render(
+ hbs``
+ );
+ assert
+ .dom('#test-alert .hds-alert__actions a')
+ .exists()
+ .hasClass('hds-link-standalone')
+ .hasClass('hds-link-standalone--size-small')
+ .hasClass('hds-link-standalone--color-secondary')
+ .hasText('I am a link');
+ });
+
+ // GENERIC
+
+ test('it should render any content passed to the "generic" contextual component', async function (assert) {
+ assert.expect(2);
+ await render(
+ hbs`
test
`
+ );
+ assert.dom('#test-alert .hds-alert__content pre').exists().hasText('test');
+ });
+
+ // DISMISS
+
+ test('it should not render the "dismiss" button by default', async function (assert) {
+ await render(hbs``);
+ assert.dom('button.hds-alert__dismiss').doesNotExist();
+ });
+ test('it should render the "dismiss" button if a callback function is passed to the @onDismiss argument', async function (assert) {
+ this.set('NOOP', () => {});
+ await render(
+ hbs``
+ );
+ assert.dom('button.hds-alert__dismiss').exists();
+ });
+
+ // A11Y
+
+ test('it should render with the correct semantic tags and aria attributes', async function (assert) {
+ await render(
+ hbs``
+ );
+ assert.dom('#test-alert').hasAttribute('role', 'alert');
+ });
+
+ // ASSERTIONS
+
+ test('it should throw an assertion if an incorrect value for @type is provided', async function (assert) {
+ const errorMessage =
+ '@type for "Hds::Alert" must be one of the following: page, inline, compact; received: foo';
+ assert.expect(2);
+ setupOnerror(function (error) {
+ assert.strictEqual(error.message, `Assertion Failed: ${errorMessage}`);
+ });
+ await render(hbs``);
+ assert.throws(function () {
+ throw new Error(errorMessage);
+ });
+ });
+ test('it should throw an assertion if a "compact" alerts is rendered with @icon equal to false', async function (assert) {
+ const errorMessage =
+ '@icon for "Hds::Alert" with @type "compact" is required';
+ assert.expect(2);
+ setupOnerror(function (error) {
+ assert.strictEqual(error.message, `Assertion Failed: ${errorMessage}`);
+ });
+ await render(
+ hbs``
+ );
+ assert.throws(function () {
+ throw new Error(errorMessage);
+ });
+ });
+ test('it should throw an assertion if an incorrect value for @color is provided', async function (assert) {
+ const errorMessage =
+ '@color for "Hds::Alert" must be one of the following: neutral, highlight, success, warning, critical; received: foo';
+ assert.expect(2);
+ setupOnerror(function (error) {
+ assert.strictEqual(error.message, `Assertion Failed: ${errorMessage}`);
+ });
+ await render(
+ hbs``
+ );
+ assert.throws(function () {
+ throw new Error(errorMessage);
+ });
+ });
+});
diff --git a/packages/components/tests/integration/components/hds/toast/index-test.js b/packages/components/tests/integration/components/hds/toast/index-test.js
new file mode 100644
index 00000000000..b68e8dff5a2
--- /dev/null
+++ b/packages/components/tests/integration/components/hds/toast/index-test.js
@@ -0,0 +1,20 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render } from '@ember/test-helpers';
+import { hbs } from 'ember-cli-htmlbars';
+
+module('Integration | Component | hds/toast/index', function (hooks) {
+ setupRenderingTest(hooks);
+
+ // notice: "toast" is a wrapper around the "hds::alert" so we test only very specific things
+
+ test('it renders the "toast"', async function (assert) {
+ await render(hbs``);
+ assert.dom(this.element).exists();
+ });
+
+ test('it should render with a CSS class that matches the component name', async function (assert) {
+ await render(hbs``);
+ assert.dom('#test-toast').hasClass('hds-toast');
+ });
+});