Skip to content

Commit b88cb9d

Browse files
author
Cathy Siller
committed
feat(toast-notification): add styles for toast notifications
1 parent 0de9dca commit b88cb9d

File tree

12 files changed

+455
-1
lines changed

12 files changed

+455
-1
lines changed

docs/_data/nav.json5

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
{ label: 'Tables', path: 'tables' },
5252
{ label: 'Tabs', path: 'tabs' },
5353
{ label: 'Text Inputs', path: 'text-inputs' },
54+
{ label: 'Toasts', path: 'toasts' },
5455
{ label: 'Tooltips', path: 'tooltips' },
5556
{ label: 'Typography', path: 'typography' },
5657
],
@@ -98,6 +99,7 @@
9899
{ label: '<hx-tile>', path: 'hx-tile' },
99100
{ label: '<hx-tile-description>', path: 'hx-tile-description' },
100101
{ label: '<hx-tile-title>', path: 'hx-tile-title' },
102+
{ label: '<hx-toast>', path: 'hx-toast' },
101103
{ label: '<hx-tooltip>', path: 'hx-tooltip' },
102104
],
103105
},

docs/components/toasts/index.html

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
---
2+
title: Toasts
3+
also:
4+
elements/hx-toast: <hx-toast>
5+
---
6+
{% extends 'component.njk' %}
7+
{% block content %}
8+
<section>
9+
<hx-alert
10+
status="Note"
11+
type="info"
12+
static>
13+
Currently, only CTA and dismiss functionality of the toast itself has been
14+
implemented. Positioning, stacking, animation, etc. functionality will be coming soon.
15+
</hx-alert>
16+
</section>
17+
18+
<section>
19+
<h2 id="demo">Demo</h2>
20+
<div id="vue-toastDemo" class="hxRow" v-cloak>
21+
<div class="hxCol hxSpan-12-xs hxSpan-3-lg hxOrder-2-lg">
22+
<h3>Options</h3>
23+
<p>
24+
<b>Type:</b><br />
25+
<select v-model="type">
26+
<option v-for="_type in types" :value="_type">
27+
{% raw %}{{ _type.label }}{% endraw %}
28+
</option>
29+
</select>
30+
</p>
31+
<p>
32+
<b>CTA:</b><br />
33+
<input
34+
class="hxTextCtrl"
35+
type="text"
36+
v-model="cta" />
37+
</p>
38+
<p>
39+
<b>Content:</b><br />
40+
<textarea class="hxTextCtrl" v-model="content"></textarea>
41+
</p>
42+
</div>
43+
<div class="hxCol hxSpan-12-xs hxSpan-9-lg hxOrder-1-lg">
44+
<div class="demo alert-demo">
45+
<hx-toast
46+
:type="type.value"
47+
:cta="cta"
48+
@submit="onSubmit">
49+
{% raw %}{{content}}{% endraw %}
50+
</hx-toast>
51+
</div>
52+
<pre>{% raw %}{{snippet}}{% endraw %}</pre>
53+
</div>
54+
</div>
55+
</section>
56+
{% endblock %}
57+
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import Util from '../../_util';
2+
3+
if (document.getElementById('vue-toastDemo')) {
4+
const TYPES = [
5+
{ label: 'Default', value: '' },
6+
{ label: 'Info', value: 'info' },
7+
{ label: 'Error', value: 'error' },
8+
{ label: 'Success', value: 'success' },
9+
];
10+
11+
new Vue({
12+
el: '#vue-toastDemo',
13+
data: {
14+
content: 'The password has been reset for [email protected].',
15+
cta: 'try again',
16+
type: TYPES[0],
17+
types: TYPES,
18+
},
19+
methods: {
20+
onSubmit: function () {
21+
alert('Unicorn pigeon puppy pop rainbows delight social pop!');
22+
},
23+
},
24+
computed: {
25+
attrType: function () {
26+
if (this.type.value !== '') {
27+
return `type="${this.type.value}"`;
28+
} else {
29+
return '';
30+
}
31+
},
32+
attrCta: function () {
33+
if (this.cta !== '') {
34+
return `cta="${this.cta}"`;
35+
} else {
36+
return '';
37+
}
38+
},
39+
snippet: function () {
40+
return Util.snippet(`
41+
<hx-toast
42+
${this.attrCta}
43+
${this.attrType}
44+
>
45+
${this.content}
46+
</hx-toast>
47+
`);
48+
},
49+
},
50+
});
51+
}

docs/docs.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import './components/search/search-demo';
1616
import './components/status-pills/status-demo';
1717
import './components/stepper/stepper-demo';
1818
import './components/tables/table-demo';
19+
import './components/toasts/toast-demo';
1920
import './components/tooltips/tooltip-demo';
2021

2122
(function () {

docs/elements/hx-toast/index.html

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
---
2+
title: <hx-toast>
3+
also:
4+
components/toasts: Toasts
5+
---
6+
{% extends 'element.njk' %}
7+
{% block content %}
8+
9+
<section>
10+
<p>
11+
The custom <code>{{page.title}}</code> element provides a user
12+
with information for action outside of the user's current context.
13+
</p>
14+
15+
<hx-dl class="hxBox-md metadata">
16+
<hx-def>
17+
<hx-dt>Permitted Parents</hx-dt>
18+
<hx-dd>any</hx-dd>
19+
</hx-def>
20+
<hx-def>
21+
<hx-dt>Permitted Children</hx-dt>
22+
<hx-dd>phrasing content</hx-dd>
23+
</hx-def>
24+
<hx-def>
25+
<hx-dt>Events</hx-dt>
26+
<hx-dd>
27+
Any of the following:
28+
<ul>
29+
<li>
30+
<code>dismiss</code> <small>(cancelable)</small> - User clicks "X" to dismiss the toast.
31+
</li>
32+
<li><code>submit</code> - User clicks CTA</li>
33+
</ul>
34+
</hx-dd>
35+
</hx-def>
36+
</hx-dl>
37+
</section>
38+
39+
<section>
40+
<h2 id="methods">Methods</h2>
41+
<dl>
42+
<dt>dismiss()</dt>
43+
<dd>Dismisses the toast.</dd>
44+
</dl>
45+
</section>
46+
{% endblock %}
47+
48+
{% block attributes %}
49+
<dl>
50+
<dt>cta {String} (optional)</dt>
51+
<dd>
52+
Set the text of the CTA button.
53+
If absent or blank, the CTA button will not be displayed.
54+
</dd>
55+
56+
<dt>type {Enum&lt;String&gt;} (optional)</dt>
57+
<dd>
58+
Identifies the type of toast. Valid values are as follows:
59+
<ul>
60+
<li><code>info</code></li>
61+
<li><code>error</code></li>
62+
<li><code>success</code></li>
63+
</ul>
64+
</dd>
65+
</dl>
66+
{% endblock %}
67+
68+
{% block properties %}
69+
<dl>
70+
<dt>cta{String}</dt>
71+
<dd>
72+
Manipulates the <code>cta</code> attribute.
73+
</dd>
74+
75+
<dt>type{String}</dt>
76+
<dd>
77+
Manipulates the <code>type</code> attribute.
78+
</dd>
79+
</dl>
80+
{% endblock %}

src/helix-ui/elements.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,5 @@ export { HXTabElement } from './elements/HXTabElement.js';
1818
export { HXTablistElement } from './elements/HXTablistElement.js';
1919
export { HXTabpanelElement } from './elements/HXTabpanelElement.js';
2020
export { HXTabsetElement } from './elements/HXTabsetElement.js';
21+
export { HXToastElement } from './elements/HXToastElement.js';
2122
export { HXTooltipElement } from './elements/HXTooltipElement.js';

src/helix-ui/elements/HXElement.less

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
@import (reference) "vars";
22

3-
* {
3+
*, *::before, *::after {
44
box-sizing: border-box;
55
color: inherit;
66
font: inherit;
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<div id="wrapper">
2+
<div id="icon-wrapper">
3+
<hx-icon id="icon" type="info-circle"></hx-icon>
4+
</div>
5+
<div id="content">
6+
<div>
7+
<slot></slot>
8+
</div>
9+
<button id="cta" type="button"></button>
10+
</div>
11+
<button id="dismiss" type="button">
12+
<hx-icon type="times"></hx-icon>
13+
</button>
14+
</div>
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import { HXElement } from './HXElement';
2+
import shadowHtml from './HXToastElement.html';
3+
import shadowStyles from './HXToastElement.less';
4+
5+
const tagName = 'hx-toast';
6+
const template = document.createElement('template');
7+
const ICONS = {
8+
'error': 'exclamation-circle',
9+
'info': 'info-circle',
10+
'success': 'checkmark',
11+
};
12+
13+
template.innerHTML = `
14+
<style>${shadowStyles}</style>
15+
${shadowHtml}
16+
`;
17+
18+
export class HXToastElement extends HXElement {
19+
static get is () {
20+
return tagName;
21+
}
22+
23+
constructor () {
24+
super(tagName, template);
25+
this._onDismiss = this._onDismiss.bind(this);
26+
this._onSubmit = this._onSubmit.bind(this);
27+
}
28+
29+
connectedCallback () {
30+
this.$upgradeProperty('cta');
31+
this.$upgradeProperty('type');
32+
33+
this._btnCta.addEventListener('click', this._onSubmit);
34+
this._btnDismiss.addEventListener('click', this._onDismiss);
35+
}
36+
37+
disconnectedCallback () {
38+
this._btnCta.removeEventListener('click', this._onSubmit);
39+
this._btnDismiss.removeEventListener('click', this._onDismiss);
40+
}
41+
42+
static get observedAttributes () {
43+
return [
44+
'cta',
45+
'type',
46+
];
47+
}//observedAttributes
48+
49+
attributeChangedCallback (attr, oldVal, newVal) {
50+
let hasValue = (newVal !== null);
51+
switch (attr) {
52+
case 'cta':
53+
this._btnCta.textContent = (hasValue ? newVal : '');
54+
break;
55+
56+
case 'type':
57+
if (hasValue) {
58+
this._elIcon.type = (ICONS[newVal] || ICONS['info']);
59+
} else {
60+
this._elIcon.type = ICONS['info'];
61+
}
62+
break;
63+
}
64+
}//attributeChangedCallback()
65+
66+
// GETTERS
67+
get cta () {
68+
return this.getAttribute('cta');
69+
}
70+
71+
get type () {
72+
return this.getAttribute('type');
73+
}
74+
75+
// SETTERS
76+
set cta (value) {
77+
if (value) {
78+
this.setAttribute('cta', value);
79+
} else {
80+
this.removeAttribute('cta');
81+
}
82+
}
83+
84+
set type (value) {
85+
if (value) {
86+
this.setAttribute('type', value);
87+
} else {
88+
this.removeAttribute('type');
89+
}
90+
}
91+
92+
// PUBLIC METHODS
93+
dismiss () {
94+
this.remove();
95+
}
96+
97+
// PRIVATE METHODS
98+
_onDismiss (evt) {
99+
evt.preventDefault();
100+
101+
if (this.$emit('dismiss')) {
102+
// only if event was not canceled by consumer
103+
this.dismiss();
104+
}
105+
}
106+
107+
_onSubmit (evt) {
108+
evt.preventDefault();
109+
this.$emit('submit');
110+
}
111+
112+
// PRIVATE GETTERS
113+
get _elIcon () {
114+
return this.shadowRoot.getElementById('icon');
115+
}
116+
117+
get _btnCta () {
118+
return this.shadowRoot.getElementById('cta');
119+
}
120+
121+
get _btnDismiss () {
122+
return this.shadowRoot.getElementById('dismiss');
123+
}
124+
}

0 commit comments

Comments
 (0)