Merge pull request #32 from hashicorp/chore-notifications

Add notification component
This commit is contained in:
Susmitha Girumala authored and GitHub committed 2020-05-29 15:04:35 -04:00
commit 5ebb880b50
8 files changed
+308

No files matched your search

@@ -0,0 +1,38 @@
import Component from '@ember/component';
import layout from '../../templates/components/rose/notification';
import { computed } from '@ember/object';
/**
* An accessible alert notification component that displays an icon,
* a heading, and optional block content. Notifications may be static or
* dismissible. To make a notification dismissible, pass in a
* `@dismiss` function.
*/
export default Component.extend({
layout,
tagName: '',
/**
* Returns an icon name based on the notification style.
* @type {string}
*/
@computed('style')
get icon() {
let icon = 'info-circle-fill';
switch(this.style) {
case 'failure':
icon = 'cancel-square-fill';
break;
case 'success':
icon = 'check-circle-fill';
break;
case 'warning':
icon = 'alert-triangle';
break;
}
return icon;
}
});
@@ -0,0 +1,84 @@
import { Meta, Story, Preview } from '@storybook/addon-docs/blocks';
import { hbs } from 'ember-cli-htmlbars';
import { action } from '@storybook/addon-actions';
import { text, boolean, select } from '@storybook/addon-knobs';
<Meta title="Rose|Notification" component="Notification" />
# Notification
Notifications come in four semantic styles: `info` (default), `success`,
`warning`, and `failure`. Heading text is required. Additional block content
is optional.
Notifications may be made dismissible by passing a `@dismiss` function into
the component. Dismissible notifications _must_ also have `@dismissText`.
This component does not handle dismissal though. Be sure your `@dismiss`
handler takes appropriate action and hides the notification.
```htmlbars
<Rose::Notification
@style="info"
@heading="Alert Notification"
@dismiss={{dismissHandler}}
@dismissText="Dismiss"
>
An error occurred.
</Rose::Notification>
```
<Preview>
<Story name="Basic Notification">{{
template: hbs`
<Rose::Notification
@style="info"
@heading="Notification without dismissal"
>
Some useful information.
</Rose::Notification>
`,
context: {}
}}</Story>
</Preview>
<Preview>
<Story name="Basic Notifications with Dismissal" height="30rem">{{
template: hbs`
<Rose::Notification
@style="info"
@heading="Dismissible Notification"
@dismiss={{dismiss}}
@dismissText="Dismiss"
>
Some useful information.
</Rose::Notification>
<Rose::Notification
@style="success"
@heading="Success"
@dismiss={{dismiss}}
@dismissText="Dismiss"
>
Good job!
</Rose::Notification>
<Rose::Notification
@style="warning"
@heading="Warning"
@dismiss={{dismiss}}
@dismissText="Dismiss"
>
Careful now.
</Rose::Notification>
<Rose::Notification
@style="failure"
@heading="Error"
@dismiss={{dismiss}}
@dismissText="Dismiss"
>
An error occurred.
</Rose::Notification>
`,
context: {
dismiss: action('dismiss'),
}
}}</Story>
</Preview>
@@ -1,3 +1,4 @@
@import 'button';
@import 'form';
@import 'header';
@import 'notification';
@@ -0,0 +1,105 @@
@use '../variables/sizing';
@use '../utilities/type';
.rose-notification {
$s: sizing.rems(s); // 12
$xs: sizing.rems(xs); // 8
$xxs: sizing.rems(xxs); // 4
$xxxs: sizing.rems(xxxs); // 2
$xxxxs: sizing.rems(xxxxs); // 1
position: relative;
padding: sizing.rems(m);
margin-bottom: sizing.rems(m);
border: sizing.rems(xxxxs) solid;
border-radius: $xxxs;
box-shadow: 0 $xs $s rgba(var(--stark-components), var(--opacity-3)),
0 $xxs $xxs rgba(var(--stark-components), var(--opacity-4));
.rose-notification-icon {
position: relative;
top: $xxxxs;
}
.rose-notification-header {
@include type.type(m, semibold);
}
.rose-notification-body {
@include type.type(s);
// hack alert, because the icons are still hard to work with
margin-left: sizing.rems(m) + $xxs;
}
.rose-notification-dismiss {
position: absolute;
color: currentColor;
background-color: transparent;
border-radius: $xxxs;
border: 0;
padding: 0;
cursor: pointer;
top: sizing.rems(s);
right: sizing.rems(s);
.rose-icon {
display: block;
padding: $xxs;
}
.rose-notification-dismiss-text {
position: absolute;
top: -1000px;
left: -1000px;
width: 1px;
height: 1px;
opacity: 0;
}
&:hover {
background-color: rgba(var(--stark-components), var(--opacity-3))
}
&:active {
background-color: rgba(var(--stark-components), var(--opacity-2))
}
}
--icon-color: var(--info);
--header-color: var(--info-starker-1);
--border-color: var(--info-subtler-1);
--background-color: var(--info-subtler-3);
border-color: var(--border-color);
background-color: var(--background-color);
.rose-notification-icon {
color: var(--icon-color);
}
.rose-notification-header {
color: var(--header-color);
}
&.is-failure {
--icon-color: var(--failure);
--header-color: var(--failure);
--border-color: var(--failure-subtler-1);
--background-color: var(--failure-subtler-2);
}
&.is-success {
--icon-color: var(--success);
--header-color: var(--success-starker-1);
--border-color: var(--success-subtler-1);
--background-color: var(--success-subtler-2);
}
&.is-warning {
--icon-color: var(--warning);
--header-color: var(--warning-starker-1);
--border-color: var(--warning-subtler-1);
--background-color: var(--warning-subtler-2);
}
}
@@ -0,0 +1,37 @@
<section
...attributes
class="rose-notification is-{{@style}}{{if @dismiss " is-dismissible"}}"
role="alert"
aria-live="{{if @dismiss "assertive"}}"
aria-atomic="true"
>
<header class="rose-notification-header">
<Rose::Icon
class="rose-notification-icon"
@name={{this.icon}}
@size="medium" />
{{@heading}}
</header>
<div class="rose-notification-body">
{{yield}}
</div>
{{#if @dismiss}}
<button
type="button"
class="rose-notification-dismiss"
title={{@dismissText}}
{{on "click" @dismiss}}
>
<Rose::Icon
@name="cancel-plain"
@size="medium" />
<span class="rose-notification-dismiss-text">
{{@dismissText}}
</span>
</button>
{{/if}}
</section>
@@ -0,0 +1 @@
export { default } from 'rose/components/rose/notification';
@@ -30,6 +30,15 @@
Dummy app index template
<Rose::Notification
@style="failure"
@heading="Error"
@dismiss={{this.actionHandler}}
@dismissText="Dismiss"
>
An error occurred.
</Rose::Notification>
<h2>Icon</h2>
<Rose::Icon @name="alert-circle-fill" />
<Rose::Icon @name="alert-circle-fill" @size="medium" />
@@ -0,0 +1,33 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render, find, click } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
module('Integration | Component | rose/notification', function(hooks) {
setupRenderingTest(hooks);
test('it renders', async function(assert) {
await render(hbs`
<Rose::Notification
@style="info"
@heading="Alert Notification"
>
An error occurred.
</Rose::Notification>
`);
assert.ok(find('.rose-notification'));
assert.equal(find('.rose-notification-body').textContent.trim(), 'An error occurred.');
});
test('it has optional dismiss button which triggers a function', async function(assert) {
assert.expect(1);
this.dismiss = () => assert.ok(true, 'dismiss clicked');
await render(hbs`
<Rose::Notification
@style="info"
@heading="Alert Notification"
@dismiss={{this.dismiss}} />
`);
await click('.rose-notification-dismiss');
});
});