Skip to content

Commit 0ac5ab1

Browse files
committed
feat(mdc-banner): component to show messages at the top
Signed-off-by:Vish Desai <shadyvd@hotmail.com>
1 parent eda366c commit 0ac5ab1

File tree

6 files changed

+299
-0
lines changed

6 files changed

+299
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
{{! template-lint-disable require-presentational-children}}
2+
<div
3+
class='mdc-banner'
4+
{{! Add styling classes as necessary }}
5+
{{has-class-if this.centered 'mdc-banner--centered'}}
6+
{{has-class-if this.stacked 'mdc-banner--mobile-stacked'}}
7+
{{has-class-if this.open 'mdc-banner--open'}}
8+
{{! Ensure id is present - we need it for the label }}
9+
{{requires-id ignore=true}}
10+
{{! Accessibility }}
11+
role='banner'
12+
{{! Re-calculate colours as necessary }}
13+
{{on-args-change this.recalcStyles @palette}}
14+
{{! Store reference to the element for DOM manipulation }}
15+
{{store-element this.storeElement}}
16+
{{! HTML attributes added in the calling template }}
17+
...attributes
18+
>
19+
<div class='mdc-banner__content' role='alertdialog' aria-live='assertive'>
20+
{{#if (or this.text this.icon)}}
21+
<div class='mdc-banner__graphic-text-wrapper'>
22+
{{#if this.icon}}
23+
<div
24+
class='mdc-banner__graphic'
25+
role='img'
26+
alt={{this.text}}
27+
>
28+
<MdcIcon
29+
class='mdc-banner__icon'
30+
@icon={{this.icon}}
31+
@palette={{@palette}}
32+
/>
33+
</div>
34+
{{/if}}
35+
36+
{{#if this.text}}
37+
<div class='mdc-banner__text'>
38+
{{this.text}}
39+
</div>
40+
{{/if}}
41+
</div>
42+
{{/if}}
43+
{{#if (or this.primaryActionLabel this.secondaryActionLabel)}}
44+
<div class='mdc-banner__actions'>
45+
{{#if this.secondaryActionLabel}}
46+
<MdcButton
47+
class='mdc-banner__secondary-action'
48+
@text={{this.secondaryActionLabel}}
49+
@palette={{@palette}}
50+
{{on
51+
'click'
52+
(fn this.fireActionEvent 'secondaryAction')
53+
}}
54+
/>
55+
{{/if}}
56+
57+
{{#if this.primaryActionLabel}}
58+
<MdcButton
59+
class='mdc-banner__primary-action'
60+
@text={{this.primaryActionLabel}}
61+
@palette={{@palette}}
62+
{{on 'click' (fn this.fireActionEvent 'primaryAction')}}
63+
/>
64+
{{/if}}
65+
</div>
66+
{{/if}}
67+
</div>
68+
</div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
import Component from '@glimmer/component';
2+
import debugLogger from 'ember-debug-logger';
3+
4+
import { action } from '@ember/object';
5+
import { tracked } from '@glimmer/tracking';
6+
7+
export default class MdcBannerComponent extends Component {
8+
// #region Accessed Services
9+
// #endregion
10+
11+
// #region Tracked Attributes
12+
@tracked open = false;
13+
14+
@tracked centered = false;
15+
@tracked stacked = false;
16+
17+
@tracked text = null;
18+
@tracked icon = null;
19+
20+
@tracked primaryActionLabel = null;
21+
@tracked secondaryActionLabel = null;
22+
// #endregion
23+
24+
// #region Constructor
25+
constructor() {
26+
super(...arguments);
27+
this.#debug?.(`constructor`);
28+
29+
this.#controls.open = this?._open;
30+
}
31+
// #endregion
32+
33+
// #region Lifecycle Hooks
34+
// #endregion
35+
36+
// #region DOM Event Handlers
37+
@action
38+
fireActionEvent(action) {
39+
this.#debug?.(`fireActionEvent: ${action}`);
40+
41+
this?._open?.({
42+
open: false
43+
});
44+
45+
this?._fireEvent?.(action);
46+
}
47+
48+
@action
49+
recalcStyles() {
50+
this.#debug?.(`recalcStyles: re-calculating styling`);
51+
if (!this.#element) return;
52+
53+
// Step 1: Reset
54+
this.#element?.style?.removeProperty?.(
55+
'--mdc-banner-graphic-background-color'
56+
);
57+
58+
this.#element?.style?.removeProperty?.('--mdc-banner-graphic-color');
59+
60+
// Step 2: Style / Palette
61+
const paletteColour = `--mdc-theme-${this?.args?.palette ?? 'primary'}`;
62+
const textColour = `--mdc-theme-on-${this?.args?.palette ?? 'primary'}`;
63+
64+
this.#element?.style?.setProperty?.(
65+
'--mdc-banner-graphic-background-color',
66+
`var(${paletteColour})`
67+
);
68+
69+
this.#element?.style?.setProperty?.(
70+
'--mdc-banner-graphic-color',
71+
`var(${textColour})`
72+
);
73+
}
74+
75+
@action
76+
storeElement(element) {
77+
this.#debug?.(`storeElement: `, element);
78+
this.#element = element;
79+
80+
this?.recalcStyles?.();
81+
this?._fireEvent?.('init');
82+
}
83+
// #endregion
84+
85+
// #region Computed Properties
86+
// #endregion
87+
88+
// #region Private Methods
89+
@action
90+
_fireEvent(name) {
91+
this.#debug?.(`_fireEvent`);
92+
if (!this.#element) return;
93+
94+
const thisEvent = new CustomEvent(name, {
95+
detail: {
96+
id: this.#element?.getAttribute?.('id'),
97+
controls: this.#controls,
98+
status: {
99+
open: this?.open,
100+
101+
centered: this?.centered,
102+
stacked: this?.stacked,
103+
104+
text: this?.text,
105+
icon: this?.icon,
106+
107+
primaryActionLabel: this?.primaryActionLabel,
108+
secondaryActionLabel: this?.secondaryActionLabel
109+
}
110+
}
111+
});
112+
113+
this.#element?.dispatchEvent?.(thisEvent);
114+
}
115+
116+
@action
117+
_open(options) {
118+
this.#debug?.(`_open: `, options);
119+
120+
let shouldFire = false;
121+
122+
if (this?.centered !== options?.centered) {
123+
this.centered = options?.centered ?? false;
124+
shouldFire ||= true;
125+
}
126+
127+
if (this?.stacked !== options?.stacked) {
128+
this.stacked = options?.stacked ?? false;
129+
shouldFire ||= true;
130+
}
131+
132+
if (this?.text !== options?.text) {
133+
this.text = options?.text;
134+
shouldFire ||= true;
135+
}
136+
137+
if (this?.icon !== options?.icon) {
138+
this.icon = options?.icon;
139+
shouldFire ||= true;
140+
}
141+
142+
if (this?.primaryActionLabel !== options?.primaryActionLabel) {
143+
this.primaryActionLabel = options?.primaryActionLabel;
144+
shouldFire ||= true;
145+
}
146+
147+
if (this?.secondaryActionLabel !== options?.secondaryActionLabel) {
148+
this.secondaryActionLabel = options?.secondaryActionLabel;
149+
shouldFire ||= true;
150+
}
151+
152+
if (this?.open !== options?.open) {
153+
this.open = options?.open ?? false;
154+
shouldFire ||= true;
155+
}
156+
157+
if (!shouldFire) return;
158+
159+
this?.recalcStyles?.();
160+
this?._fireEvent?.('statuschange');
161+
}
162+
// #endregion
163+
164+
// #region Default Sub-components
165+
// #endregion
166+
167+
// #region Private Attributes
168+
#debug = debugLogger('component:mdc-banner');
169+
170+
#element = null;
171+
#controls = {};
172+
// #endregion
173+
}

packages/ember-mdc-web/addon/styles/ember-mdc-web.scss

+4
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@
5858
/* TODO: Backdrop component - put in the actual styles */
5959
@use './emdc-backdrop.css';
6060

61+
/* Banner component */
62+
@use '@material/banner/styles' as banner-styles;
63+
@use './emdc-banner.css';
64+
6165
/* Button component(s) - button, fab, icon-button, etc. */
6266
@use '@material/button/mdc-button';
6367
@use '@material/fab/mdc-fab';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
2+
.mdc-banner.mdc-banner--open {
3+
height: 64px;
4+
}
5+
.mdc-banner .mdc-banner__content {
6+
max-width: 100%
7+
}
8+
.mdc-banner .mdc-banner__content .mdc-banner__icon {
9+
position: initial;
10+
top: unset;
11+
font-size: 2rem;
12+
-webkit-transform: none;
13+
transform: none;
14+
}
15+
.mdc-banner .mdc-banner__content .mdc-banner__graphic {
16+
background-color: var(--mdc-banner-graphic-background-color,
17+
var(--mdc-theme-primary, #01579b));
18+
color: var(--mdc-banner-graphic-color, var(--mdc-theme-surface, #fafafa));
19+
}
20+
.mdc-banner.mdc-banner--centered .mdc-banner__content {
21+
max-width: 720px;
22+
}

packages/ember-mdc-web/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@
135135
"main": "addon-main.js",
136136
"app-js": {
137137
"./components/mdc-backdrop/index.js": "./dist/_app_/components/mdc-backdrop/index.js",
138+
"./components/mdc-banner/index.js": "./dist/_app_/components/mdc-banner/index.js",
138139
"./components/mdc-button/index.js": "./dist/_app_/components/mdc-button/index.js",
139140
"./components/mdc-card/content/index.js": "./dist/_app_/components/mdc-card/content/index.js",
140141
"./components/mdc-card/content/media/index.js": "./dist/_app_/components/mdc-card/content/media/index.js",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
.mdc-banner {
2+
&.mdc-banner--open {
3+
height: 64px;
4+
}
5+
6+
& .mdc-banner__content {
7+
max-width: 100%;
8+
9+
& .mdc-banner__icon {
10+
position: initial;
11+
top: unset;
12+
font-size: 2rem;
13+
transform: none;
14+
}
15+
16+
& .mdc-banner__graphic {
17+
background-color: var(
18+
--mdc-banner-graphic-background-color,
19+
var(--mdc-theme-primary, #01579b)
20+
);
21+
color: var(
22+
--mdc-banner-graphic-color,
23+
var(--mdc-theme-surface, #fafafa)
24+
);
25+
}
26+
}
27+
28+
&.mdc-banner--centered .mdc-banner__content {
29+
max-width: 720px;
30+
}
31+
}

0 commit comments

Comments
 (0)