@justeattakeaway/pie-notification 0.3.2 → 0.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -73,7 +73,12 @@ import { PieNotification } from '@justeattakeaway/pie-notification/dist/react';
73
73
 
74
74
  | Property | Type | Default | Description |
75
75
  |---|---|---|---|
76
- | - | - | - | - |
76
+ | isOpen | `Boolean` | true | When true, the notification is set to be open and visible |
77
+ | variant | `String`| neutral | Set the variant of the notification. Available variants: `neutral`, `neutral-alternative`, `info`, `success`, `warning`, `error` |
78
+ | compact | `Boolean` | false | When true, the footer aligns to the header and icons which makes the component compact. |
79
+ | heading | `String` | - | The text to display in the notification\'s heading. |
80
+ | headingLevel | `String` | h2 | The HTML heading tag to use for the notification\'s heading. Can from h2 to h6. The font size is kept the same for all heading levels. Available heading levels: `h2`,`h3`,`h4`,`h5`,`h6` |
81
+ | hideIcon | `Boolean` | false | Option to hide the icon regardless its variant or if user provided an icon. |
77
82
 
78
83
  In your markup or JSX, you can then use these to set the properties for the `pie-notification` component:
79
84
 
@@ -11,8 +11,42 @@
11
11
  {
12
12
  "kind": "javascript-module",
13
13
  "path": "src/defs.js",
14
- "declarations": [],
15
- "exports": []
14
+ "declarations": [
15
+ {
16
+ "kind": "variable",
17
+ "name": "variants",
18
+ "type": {
19
+ "text": "['neutral', 'neutral-alternative', 'info', 'success', 'warning', 'error']"
20
+ },
21
+ "default": "['neutral', 'neutral-alternative', 'info', 'success', 'warning', 'error']"
22
+ },
23
+ {
24
+ "kind": "variable",
25
+ "name": "headingLevels",
26
+ "type": {
27
+ "text": "['h2', 'h3', 'h4', 'h5', 'h6']"
28
+ },
29
+ "default": "['h2', 'h3', 'h4', 'h5', 'h6']"
30
+ }
31
+ ],
32
+ "exports": [
33
+ {
34
+ "kind": "js",
35
+ "name": "variants",
36
+ "declaration": {
37
+ "name": "variants",
38
+ "module": "src/defs.js"
39
+ }
40
+ },
41
+ {
42
+ "kind": "js",
43
+ "name": "headingLevels",
44
+ "declaration": {
45
+ "name": "headingLevels",
46
+ "module": "src/defs.js"
47
+ }
48
+ }
49
+ ]
16
50
  },
17
51
  {
18
52
  "kind": "javascript-module",
@@ -22,7 +56,280 @@
22
56
  "kind": "class",
23
57
  "description": "",
24
58
  "name": "PieNotification",
25
- "members": [],
59
+ "members": [
60
+ {
61
+ "kind": "field",
62
+ "name": "isOpen",
63
+ "type": {
64
+ "text": "boolean"
65
+ },
66
+ "privacy": "public",
67
+ "default": "true",
68
+ "attribute": "isOpen"
69
+ },
70
+ {
71
+ "kind": "field",
72
+ "name": "variant",
73
+ "type": {
74
+ "text": "NonNullable<NotificationProps['variant']>"
75
+ },
76
+ "privacy": "public",
77
+ "default": "'neutral'",
78
+ "attribute": "variant"
79
+ },
80
+ {
81
+ "kind": "field",
82
+ "name": "isCompact",
83
+ "type": {
84
+ "text": "boolean"
85
+ },
86
+ "privacy": "public",
87
+ "default": "false",
88
+ "attribute": "isCompact"
89
+ },
90
+ {
91
+ "kind": "field",
92
+ "name": "heading",
93
+ "type": {
94
+ "text": "string"
95
+ },
96
+ "privacy": "public",
97
+ "attribute": "heading"
98
+ },
99
+ {
100
+ "kind": "field",
101
+ "name": "headingLevel",
102
+ "type": {
103
+ "text": "NonNullable<NotificationProps['headingLevel']>"
104
+ },
105
+ "privacy": "public",
106
+ "default": "'h2'",
107
+ "attribute": "headingLevel"
108
+ },
109
+ {
110
+ "kind": "field",
111
+ "name": "hideIcon",
112
+ "type": {
113
+ "text": "boolean"
114
+ },
115
+ "privacy": "public",
116
+ "default": "false",
117
+ "attribute": "hideIcon"
118
+ },
119
+ {
120
+ "kind": "field",
121
+ "name": "hideCloseIcon",
122
+ "type": {
123
+ "text": "boolean"
124
+ },
125
+ "privacy": "public",
126
+ "default": "false",
127
+ "attribute": "hideCloseIcon"
128
+ },
129
+ {
130
+ "kind": "field",
131
+ "name": "_iconSlot",
132
+ "type": {
133
+ "text": "Array<HTMLElement>"
134
+ }
135
+ },
136
+ {
137
+ "kind": "field",
138
+ "name": "_hasExternalIcon",
139
+ "type": {
140
+ "text": "boolean"
141
+ },
142
+ "privacy": "protected",
143
+ "default": "false"
144
+ },
145
+ {
146
+ "kind": "field",
147
+ "name": "_hasIconClass",
148
+ "type": {
149
+ "text": "boolean"
150
+ },
151
+ "privacy": "protected",
152
+ "default": "false"
153
+ },
154
+ {
155
+ "kind": "method",
156
+ "name": "updateIconProperties",
157
+ "privacy": "private",
158
+ "description": "Method responsible to check if an external icon has been provided.\nIt reads from icon slot if there is an external icon as well check if variant has default icon."
159
+ },
160
+ {
161
+ "kind": "method",
162
+ "name": "renderFooter",
163
+ "privacy": "private",
164
+ "description": "Template for the footer area\nCalled within the main render function."
165
+ },
166
+ {
167
+ "kind": "method",
168
+ "name": "renderNotificationHeading",
169
+ "privacy": "private",
170
+ "return": {
171
+ "type": {
172
+ "text": "TemplateResult"
173
+ }
174
+ },
175
+ "parameters": [
176
+ {
177
+ "name": "heading",
178
+ "type": {
179
+ "text": "NotificationProps['heading']"
180
+ }
181
+ },
182
+ {
183
+ "name": "headingTag",
184
+ "type": {
185
+ "text": "StaticValue"
186
+ }
187
+ }
188
+ ],
189
+ "description": "Template for the header area\nCalled within the main render function."
190
+ },
191
+ {
192
+ "kind": "method",
193
+ "name": "variantHasDefaultIcon",
194
+ "privacy": "private",
195
+ "parameters": [
196
+ {
197
+ "name": "variant",
198
+ "type": {
199
+ "text": "NonNullable<NotificationProps['variant']>"
200
+ }
201
+ }
202
+ ],
203
+ "description": "Util method that returns a boolean if variant has a default icon."
204
+ },
205
+ {
206
+ "kind": "method",
207
+ "name": "getDefaultVariantIcon",
208
+ "privacy": "private",
209
+ "parameters": [
210
+ {
211
+ "name": "variant",
212
+ "type": {
213
+ "text": "NonNullable<NotificationProps['variant']>"
214
+ }
215
+ }
216
+ ],
217
+ "description": "Util method that returns an icon from a variant that has default icon."
218
+ },
219
+ {
220
+ "kind": "method",
221
+ "name": "renderIconVariant",
222
+ "privacy": "private",
223
+ "parameters": [
224
+ {
225
+ "name": "variant",
226
+ "type": {
227
+ "text": "NonNullable<NotificationProps['variant']>"
228
+ }
229
+ }
230
+ ],
231
+ "description": "Util method that returns a template with a default icon according to the chosen variant.\nCalled within the renderIcon method."
232
+ },
233
+ {
234
+ "kind": "method",
235
+ "name": "renderIcon",
236
+ "privacy": "private",
237
+ "return": {
238
+ "type": {
239
+ "text": "TemplateResult | typeof nothing"
240
+ }
241
+ },
242
+ "parameters": [
243
+ {
244
+ "name": "variant",
245
+ "type": {
246
+ "text": "NonNullable<NotificationProps['variant']>"
247
+ }
248
+ },
249
+ {
250
+ "name": "hasExternalIcon",
251
+ "type": {
252
+ "text": "boolean"
253
+ }
254
+ },
255
+ {
256
+ "name": "hasIconClass",
257
+ "type": {
258
+ "text": "boolean"
259
+ }
260
+ }
261
+ ],
262
+ "description": "Template for the heading icon area.\nIt can return an icon provided externally via named slot or it can return an default icon according to the chosen variant.\nCalled within the main render function."
263
+ },
264
+ {
265
+ "kind": "method",
266
+ "name": "renderCloseButton",
267
+ "privacy": "private",
268
+ "return": {
269
+ "type": {
270
+ "text": "TemplateResult"
271
+ }
272
+ },
273
+ "description": "Template for the close button element. Called within the\nmain render function."
274
+ }
275
+ ],
276
+ "attributes": [
277
+ {
278
+ "name": "isOpen",
279
+ "type": {
280
+ "text": "boolean"
281
+ },
282
+ "default": "true",
283
+ "fieldName": "isOpen"
284
+ },
285
+ {
286
+ "name": "variant",
287
+ "type": {
288
+ "text": "NonNullable<NotificationProps['variant']>"
289
+ },
290
+ "default": "'neutral'",
291
+ "fieldName": "variant"
292
+ },
293
+ {
294
+ "name": "isCompact",
295
+ "type": {
296
+ "text": "boolean"
297
+ },
298
+ "default": "false",
299
+ "fieldName": "isCompact"
300
+ },
301
+ {
302
+ "name": "heading",
303
+ "type": {
304
+ "text": "string"
305
+ },
306
+ "fieldName": "heading"
307
+ },
308
+ {
309
+ "name": "headingLevel",
310
+ "type": {
311
+ "text": "NonNullable<NotificationProps['headingLevel']>"
312
+ },
313
+ "default": "'h2'",
314
+ "fieldName": "headingLevel"
315
+ },
316
+ {
317
+ "name": "hideIcon",
318
+ "type": {
319
+ "text": "boolean"
320
+ },
321
+ "default": "false",
322
+ "fieldName": "hideIcon"
323
+ },
324
+ {
325
+ "name": "hideCloseIcon",
326
+ "type": {
327
+ "text": "boolean"
328
+ },
329
+ "default": "false",
330
+ "fieldName": "hideCloseIcon"
331
+ }
332
+ ],
26
333
  "superclass": {
27
334
  "name": "LitElement",
28
335
  "package": "lit"
package/dist/index.d.ts CHANGED
@@ -1,16 +1,131 @@
1
1
  import type { CSSResult } from 'lit';
2
2
  import type { LitElement } from 'lit';
3
- import type { TemplateResult } from 'lit-html';
3
+ import type { PropertyValues } from 'lit';
4
+ import type { TemplateResult } from 'lit';
5
+
6
+ export declare const headingLevels: readonly ["h2", "h3", "h4", "h5", "h6"];
4
7
 
5
8
  export declare interface NotificationProps {
9
+ /**
10
+ * Set the variant of the notification.
11
+ */
12
+ variant?: typeof variants[number];
13
+ /**
14
+ * When true, the footer aligns to the header and icons which makes the component compact.
15
+ */
16
+ isCompact?: boolean;
17
+ /**
18
+ * The text to display in the notification's heading.
19
+ */
20
+ heading?: string;
21
+ /**
22
+ * The HTML heading tag to use for the notification's heading. Can be h1-h6.
23
+ */
24
+ headingLevel?: typeof headingLevels[number];
25
+ /**
26
+ * Option to hide the icon regardless its variant or if user provided an icon.
27
+ */
28
+ hideIcon?: boolean;
29
+ /**
30
+ * When true, the notification is set to be open and visible.
31
+ */
32
+ isOpen?: boolean;
6
33
  }
7
34
 
8
35
  /**
9
36
  * @tagname pie-notification
10
37
  */
11
38
  export declare class PieNotification extends LitElement implements NotificationProps {
12
- render(): TemplateResult<1>;
39
+ isOpen: boolean;
40
+ variant: NonNullable<NotificationProps['variant']>;
41
+ isCompact: boolean;
42
+ heading: string;
43
+ headingLevel: NonNullable<NotificationProps['headingLevel']>;
44
+ hideIcon: boolean;
45
+ hideCloseIcon: boolean;
46
+ _iconSlot: Array<HTMLElement>;
47
+ protected _hasExternalIcon: boolean;
48
+ protected _hasIconClass: boolean;
13
49
  static styles: CSSResult;
50
+ /**
51
+ * Lifecycle method executed after component renders.
52
+ */
53
+ protected firstUpdated(): void;
54
+ /**
55
+ * Lifecycle method executed when component is about to update.
56
+ * It update icon properties if variant has changes.
57
+ */
58
+ protected willUpdate(_changedProperties: PropertyValues<this>): void;
59
+ /**
60
+ * Method responsible to check if an external icon has been provided.
61
+ * It reads from icon slot if there is an external icon as well check if variant has default icon.
62
+ *
63
+ * @private
64
+ */
65
+ private updateIconProperties;
66
+ /**
67
+ * Template for the footer area
68
+ * Called within the main render function.
69
+ *
70
+ * @private
71
+ */
72
+ private renderFooter;
73
+ /**
74
+ * Template for the header area
75
+ * Called within the main render function.
76
+ *
77
+ * @param {NotificationProps['heading']} heading
78
+ * @param {StaticValue} headingTag
79
+ *
80
+ * @private
81
+ */
82
+ private renderNotificationHeading;
83
+ /**
84
+ * Util method that returns a boolean if variant has a default icon.
85
+ *
86
+ * @param {NonNullable<NotificationProps['variant']>} variant
87
+ *
88
+ * @private
89
+ */
90
+ private variantHasDefaultIcon;
91
+ /**
92
+ * Util method that returns an icon from a variant that has default icon.
93
+ *
94
+ * @param {NonNullable<NotificationProps['variant']>} variant
95
+ *
96
+ * @private
97
+ */
98
+ private getDefaultVariantIcon;
99
+ /**
100
+ * Util method that returns a template with a default icon according to the chosen variant.
101
+ * Called within the renderIcon method.
102
+ *
103
+ * @param {NonNullable<NotificationProps['variant']>} variant
104
+ *
105
+ * @private
106
+ */
107
+ private renderIconVariant;
108
+ /**
109
+ * Template for the heading icon area.
110
+ * It can return an icon provided externally via named slot or it can return an default icon according to the chosen variant.
111
+ * Called within the main render function.
112
+ *
113
+ * @param {NonNullable<NotificationProps['variant']>} variant
114
+ * @param {boolean} hasExternalIcon
115
+ *
116
+ * @private
117
+ */
118
+ private renderIcon;
119
+ /**
120
+ * Template for the close button element. Called within the
121
+ * main render function.
122
+ *
123
+ * @private
124
+ */
125
+ private renderCloseButton;
126
+ render(): TemplateResult;
14
127
  }
15
128
 
129
+ export declare const variants: readonly ["neutral", "neutral-alternative", "info", "success", "warning", "error"];
130
+
16
131
  export { }
package/dist/index.js CHANGED
@@ -1,13 +1,213 @@
1
- import { unsafeCSS as e, LitElement as o, html as i } from "lit";
2
- import { defineCustomElement as n } from "@justeattakeaway/pie-webc-core";
3
- const s = "", r = "pie-notification";
4
- class t extends o {
1
+ import { unsafeCSS as m, LitElement as $, nothing as d } from "lit";
2
+ import { html as r, unsafeStatic as b } from "lit/static-html.js";
3
+ import { validPropertyValues as u, defineCustomElement as I } from "@justeattakeaway/pie-webc-core";
4
+ import { property as l, queryAssignedElements as y, state as v } from "lit/decorators.js";
5
+ import "@justeattakeaway/pie-icon-button";
6
+ import "@justeattakeaway/pie-icons-webc/IconClose";
7
+ import "@justeattakeaway/pie-icons-webc/IconInfoCircle";
8
+ import "@justeattakeaway/pie-icons-webc/IconAlertCircle";
9
+ import "@justeattakeaway/pie-icons-webc/IconAlertTriangle";
10
+ import "@justeattakeaway/pie-icons-webc/IconCheckCircle";
11
+ const x = ["neutral", "neutral-alternative", "info", "success", "warning", "error"], z = ["h2", "h3", "h4", "h5", "h6"], _ = `*,*:before,*:after{box-sizing:border-box}.c-notification{--notification-border-radius: var(--dt-radius-rounded-c);--notification-background-color: var(--dt-color-container-subtle);--notification-direction: column;--notification-icon-size-override: 22px;--notification-heading-font-size: calc(var(--dt-font-size-20) * 1px);--notification-heading-line-height: calc(var(--dt-font-size-20-line-height) * 1px);--notification-font-size: calc(var(--dt-font-size-16) * 1px);--notification-line-height: calc(var(--dt-font-size-16-line-height) * 1px);--notification-icon-fill: var(--dt-color-content-default);padding:var(--dt-spacing-d);border-radius:var(--notification-border-radius);background-color:var(--notification-background-color);position:relative;display:flex;flex-direction:var(--notification-direction);gap:var(--dt-spacing-d);font-size:var(--notification-font-size);line-height:var(--notification-line-height)}.c-notification h1,.c-notification h2,.c-notification h3,.c-notification h4,.c-notification h5,.c-notification h6{margin:0;font-size:var(--notification-heading-font-size);line-height:var(--notification-heading-line-height)}.c-notification[is-compact=true]{--notification-direction: row}.c-notification[variant=neutral-alternative]{--notification-background-color: var(--dt-color-container-default)}.c-notification[variant=info]{--notification-background-color: var(--dt-color-support-info-02);--notification-icon-fill: var(--dt-color-blue)}.c-notification[variant=success]{--notification-background-color: var(--dt-color-support-positive-02)}.c-notification[variant=warning]{--notification-background-color: var(--dt-color-support-warning-02)}.c-notification[variant=error]{--notification-background-color: var(--dt-color-support-error-02);--notification-icon-fill: var(--dt-color-red)}.c-notification-content-section{display:flex;flex-direction:row}.c-notification-content-section .has-icon{margin-inline-end:var(--dt-spacing-c)}.c-notification-heading-icon{padding-block-start:var(--dt-spacing-a);color:var(--notification-icon-fill)}.c-notification-icon-close{position:absolute;inset-block-start:var(--dt-spacing-b);inset-inline-end:var(--dt-spacing-b)}
12
+ `;
13
+ var C = Object.defineProperty, w = Object.getOwnPropertyDescriptor, a = (p, i, t, c) => {
14
+ for (var e = c > 1 ? void 0 : c ? w(i, t) : i, f = p.length - 1, h; f >= 0; f--)
15
+ (h = p[f]) && (e = (c ? h(i, t, e) : h(e)) || e);
16
+ return c && e && C(i, t, e), e;
17
+ };
18
+ const o = "pie-notification", s = "c-notification";
19
+ class n extends $ {
20
+ constructor() {
21
+ super(...arguments), this.isOpen = !0, this.variant = "neutral", this.isCompact = !1, this.headingLevel = "h2", this.hideIcon = !1, this.hideCloseIcon = !1, this._hasExternalIcon = !1, this._hasIconClass = !1;
22
+ }
23
+ /**
24
+ * Lifecycle method executed after component renders.
25
+ */
26
+ firstUpdated() {
27
+ this.updateIconProperties();
28
+ }
29
+ /**
30
+ * Lifecycle method executed when component is about to update.
31
+ * It update icon properties if variant has changes.
32
+ */
33
+ willUpdate(i) {
34
+ i.has("variant") && this.updateIconProperties();
35
+ }
36
+ /**
37
+ * Method responsible to check if an external icon has been provided.
38
+ * It reads from icon slot if there is an external icon as well check if variant has default icon.
39
+ *
40
+ * @private
41
+ */
42
+ updateIconProperties() {
43
+ this._hasExternalIcon = this._iconSlot.length > 0, this._hasIconClass = this._hasExternalIcon || this.variantHasDefaultIcon(this.variant);
44
+ }
45
+ /**
46
+ * Template for the footer area
47
+ * Called within the main render function.
48
+ *
49
+ * @private
50
+ */
51
+ renderFooter() {
52
+ return r`
53
+ <footer class="${s}-footer"></footer>
54
+ `;
55
+ }
56
+ /**
57
+ * Template for the header area
58
+ * Called within the main render function.
59
+ *
60
+ * @param {NotificationProps['heading']} heading
61
+ * @param {StaticValue} headingTag
62
+ *
63
+ * @private
64
+ */
65
+ renderNotificationHeading(i, t) {
66
+ return r`
67
+ <header class="${s}-header" data-test-id="${o}-header">
68
+ <${t} class="${s}-heading" data-test-id="${o}-heading">${i}</${t}>
69
+ </header>
70
+ `;
71
+ }
72
+ /**
73
+ * Util method that returns a boolean if variant has a default icon.
74
+ *
75
+ * @param {NonNullable<NotificationProps['variant']>} variant
76
+ *
77
+ * @private
78
+ */
79
+ variantHasDefaultIcon(i) {
80
+ return ["info", "success", "warning", "error"].includes(i);
81
+ }
82
+ /**
83
+ * Util method that returns an icon from a variant that has default icon.
84
+ *
85
+ * @param {NonNullable<NotificationProps['variant']>} variant
86
+ *
87
+ * @private
88
+ */
89
+ getDefaultVariantIcon(i) {
90
+ switch (i) {
91
+ case "info":
92
+ return r`<icon-info-circle size="s" data-test-id="${o}-heading-icon-info"></icon-info-circle>`;
93
+ case "success":
94
+ return r`<icon-check-circle size="s" data-test-id="${o}-heading-icon-success"></icon-check-circle>`;
95
+ case "warning":
96
+ return r`<icon-alert-triangle size="s" data-test-id="${o}-heading-icon-warning"></icon-alert-triangle>`;
97
+ case "error":
98
+ return r`<icon-alert-circle size="s" data-test-id="${o}-heading-icon-error"></icon-alert-circle>`;
99
+ default:
100
+ return d;
101
+ }
102
+ }
103
+ /**
104
+ * Util method that returns a template with a default icon according to the chosen variant.
105
+ * Called within the renderIcon method.
106
+ *
107
+ * @param {NonNullable<NotificationProps['variant']>} variant
108
+ *
109
+ * @private
110
+ */
111
+ renderIconVariant(i) {
112
+ return this.variantHasDefaultIcon(i) ? this.getDefaultVariantIcon(i) : d;
113
+ }
114
+ /**
115
+ * Template for the heading icon area.
116
+ * It can return an icon provided externally via named slot or it can return an default icon according to the chosen variant.
117
+ * Called within the main render function.
118
+ *
119
+ * @param {NonNullable<NotificationProps['variant']>} variant
120
+ * @param {boolean} hasExternalIcon
121
+ *
122
+ * @private
123
+ */
124
+ renderIcon(i, t, c) {
125
+ return r`
126
+ <div data-test-id="${o}-icon-area" class="${c ? "has-icon " : ""}${s}-heading-icon">
127
+ ${t ? d : this.renderIconVariant(i)}
128
+ <slot name="icon"></slot>
129
+ </div>
130
+ `;
131
+ }
132
+ /**
133
+ * Template for the close button element. Called within the
134
+ * main render function.
135
+ *
136
+ * @private
137
+ */
138
+ renderCloseButton() {
139
+ return r`
140
+ <pie-icon-button
141
+ variant="ghost-secondary"
142
+ size="small"
143
+ class="${s}-icon-close"
144
+ data-test-id="${o}-icon-close"
145
+ >
146
+ <icon-close></icon-close>
147
+ </pie-icon-button>`;
148
+ }
5
149
  render() {
6
- return i`<h1 data-test-id="pie-notification">Hello world!</h1>`;
150
+ const {
151
+ variant: i,
152
+ heading: t,
153
+ headingLevel: c,
154
+ isCompact: e,
155
+ _hasExternalIcon: f,
156
+ hideIcon: h,
157
+ _hasIconClass: g
158
+ } = this;
159
+ return r`
160
+ <div data-test-id="${o}" class="${s}" variant="${i}" is-compact="${e}">
161
+ ${e ? d : this.renderCloseButton()}
162
+
163
+ <section class="${s}-content-section">
164
+ ${h ? d : this.renderIcon(i, f, g)}
165
+ <article>
166
+ ${t ? this.renderNotificationHeading(t, b(c)) : d}
167
+ <slot></slot>
168
+ </article>
169
+ </section>
170
+
171
+ ${this.renderFooter()}
172
+ </div>`;
7
173
  }
8
174
  }
9
- t.styles = e(s);
10
- n(r, t);
175
+ n.styles = m(_);
176
+ a([
177
+ l({ type: Boolean })
178
+ ], n.prototype, "isOpen", 2);
179
+ a([
180
+ l(),
181
+ u(o, x, "neutral")
182
+ ], n.prototype, "variant", 2);
183
+ a([
184
+ l({ type: Boolean })
185
+ ], n.prototype, "isCompact", 2);
186
+ a([
187
+ l({ type: String })
188
+ ], n.prototype, "heading", 2);
189
+ a([
190
+ l(),
191
+ u(o, z, "h2")
192
+ ], n.prototype, "headingLevel", 2);
193
+ a([
194
+ l({ type: Boolean })
195
+ ], n.prototype, "hideIcon", 2);
196
+ a([
197
+ l({ type: Boolean })
198
+ ], n.prototype, "hideCloseIcon", 2);
199
+ a([
200
+ y({ slot: "icon" })
201
+ ], n.prototype, "_iconSlot", 2);
202
+ a([
203
+ v()
204
+ ], n.prototype, "_hasExternalIcon", 2);
205
+ a([
206
+ v()
207
+ ], n.prototype, "_hasIconClass", 2);
208
+ I(o, n);
11
209
  export {
12
- t as PieNotification
210
+ n as PieNotification,
211
+ z as headingLevels,
212
+ x as variants
13
213
  };
package/dist/react.d.ts CHANGED
@@ -1,9 +1,36 @@
1
1
  import type { CSSResult } from 'lit';
2
2
  import type { LitElement } from 'lit';
3
+ import type { PropertyValues } from 'lit';
3
4
  import * as React_2 from 'react';
4
- import type { TemplateResult } from 'lit-html';
5
+ import type { TemplateResult } from 'lit';
6
+
7
+ export declare const headingLevels: readonly ["h2", "h3", "h4", "h5", "h6"];
5
8
 
6
9
  export declare interface NotificationProps {
10
+ /**
11
+ * Set the variant of the notification.
12
+ */
13
+ variant?: typeof variants[number];
14
+ /**
15
+ * When true, the footer aligns to the header and icons which makes the component compact.
16
+ */
17
+ isCompact?: boolean;
18
+ /**
19
+ * The text to display in the notification's heading.
20
+ */
21
+ heading?: string;
22
+ /**
23
+ * The HTML heading tag to use for the notification's heading. Can be h1-h6.
24
+ */
25
+ headingLevel?: typeof headingLevels[number];
26
+ /**
27
+ * Option to hide the icon regardless its variant or if user provided an icon.
28
+ */
29
+ hideIcon?: boolean;
30
+ /**
31
+ * When true, the notification is set to be open and visible.
32
+ */
33
+ isOpen?: boolean;
7
34
  }
8
35
 
9
36
  export declare const PieNotification: React_2.ForwardRefExoticComponent<NotificationProps & React_2.RefAttributes<PieNotification_2> & ReactBaseType>;
@@ -12,10 +39,98 @@ export declare const PieNotification: React_2.ForwardRefExoticComponent<Notifica
12
39
  * @tagname pie-notification
13
40
  */
14
41
  declare class PieNotification_2 extends LitElement implements NotificationProps {
15
- render(): TemplateResult<1>;
42
+ isOpen: boolean;
43
+ variant: NonNullable<NotificationProps['variant']>;
44
+ isCompact: boolean;
45
+ heading: string;
46
+ headingLevel: NonNullable<NotificationProps['headingLevel']>;
47
+ hideIcon: boolean;
48
+ hideCloseIcon: boolean;
49
+ _iconSlot: Array<HTMLElement>;
50
+ protected _hasExternalIcon: boolean;
51
+ protected _hasIconClass: boolean;
16
52
  static styles: CSSResult;
53
+ /**
54
+ * Lifecycle method executed after component renders.
55
+ */
56
+ protected firstUpdated(): void;
57
+ /**
58
+ * Lifecycle method executed when component is about to update.
59
+ * It update icon properties if variant has changes.
60
+ */
61
+ protected willUpdate(_changedProperties: PropertyValues<this>): void;
62
+ /**
63
+ * Method responsible to check if an external icon has been provided.
64
+ * It reads from icon slot if there is an external icon as well check if variant has default icon.
65
+ *
66
+ * @private
67
+ */
68
+ private updateIconProperties;
69
+ /**
70
+ * Template for the footer area
71
+ * Called within the main render function.
72
+ *
73
+ * @private
74
+ */
75
+ private renderFooter;
76
+ /**
77
+ * Template for the header area
78
+ * Called within the main render function.
79
+ *
80
+ * @param {NotificationProps['heading']} heading
81
+ * @param {StaticValue} headingTag
82
+ *
83
+ * @private
84
+ */
85
+ private renderNotificationHeading;
86
+ /**
87
+ * Util method that returns a boolean if variant has a default icon.
88
+ *
89
+ * @param {NonNullable<NotificationProps['variant']>} variant
90
+ *
91
+ * @private
92
+ */
93
+ private variantHasDefaultIcon;
94
+ /**
95
+ * Util method that returns an icon from a variant that has default icon.
96
+ *
97
+ * @param {NonNullable<NotificationProps['variant']>} variant
98
+ *
99
+ * @private
100
+ */
101
+ private getDefaultVariantIcon;
102
+ /**
103
+ * Util method that returns a template with a default icon according to the chosen variant.
104
+ * Called within the renderIcon method.
105
+ *
106
+ * @param {NonNullable<NotificationProps['variant']>} variant
107
+ *
108
+ * @private
109
+ */
110
+ private renderIconVariant;
111
+ /**
112
+ * Template for the heading icon area.
113
+ * It can return an icon provided externally via named slot or it can return an default icon according to the chosen variant.
114
+ * Called within the main render function.
115
+ *
116
+ * @param {NonNullable<NotificationProps['variant']>} variant
117
+ * @param {boolean} hasExternalIcon
118
+ *
119
+ * @private
120
+ */
121
+ private renderIcon;
122
+ /**
123
+ * Template for the close button element. Called within the
124
+ * main render function.
125
+ *
126
+ * @private
127
+ */
128
+ private renderCloseButton;
129
+ render(): TemplateResult;
17
130
  }
18
131
 
19
132
  declare type ReactBaseType = React_2.HTMLAttributes<HTMLDivElement>;
20
133
 
134
+ export declare const variants: readonly ["neutral", "neutral-alternative", "info", "success", "warning", "error"];
135
+
21
136
  export { }
package/dist/react.js CHANGED
@@ -1,15 +1,26 @@
1
1
  import * as i from "react";
2
2
  import { createComponent as t } from "@lit/react";
3
3
  import { PieNotification as o } from "./index.js";
4
+ import { headingLevels as C, variants as R } from "./index.js";
4
5
  import "lit";
6
+ import "lit/static-html.js";
5
7
  import "@justeattakeaway/pie-webc-core";
8
+ import "lit/decorators.js";
9
+ import "@justeattakeaway/pie-icon-button";
10
+ import "@justeattakeaway/pie-icons-webc/IconClose";
11
+ import "@justeattakeaway/pie-icons-webc/IconInfoCircle";
12
+ import "@justeattakeaway/pie-icons-webc/IconAlertCircle";
13
+ import "@justeattakeaway/pie-icons-webc/IconAlertTriangle";
14
+ import "@justeattakeaway/pie-icons-webc/IconCheckCircle";
6
15
  const e = t({
7
16
  displayName: "PieNotification",
8
17
  elementClass: o,
9
18
  react: i,
10
19
  tagName: "pie-notification",
11
20
  events: {}
12
- }), r = e;
21
+ }), d = e;
13
22
  export {
14
- r as PieNotification
23
+ d as PieNotification,
24
+ C as headingLevels,
25
+ R as variants
15
26
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@justeattakeaway/pie-notification",
3
3
  "description": "PIE Design System Notification built using Web Components",
4
- "version": "0.3.2",
4
+ "version": "0.3.4",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.js",
@@ -37,7 +37,9 @@
37
37
  "cem-plugin-module-file-extensions": "0.0.5"
38
38
  },
39
39
  "dependencies": {
40
- "@justeattakeaway/pie-webc-core": "0.18.0"
40
+ "@justeattakeaway/pie-icon-button": "0.27.2",
41
+ "@justeattakeaway/pie-icons-webc": "0.17.2",
42
+ "@justeattakeaway/pie-webc-core": "0.19.0"
41
43
  },
42
44
  "volta": {
43
45
  "extends": "../../../package.json"
package/src/defs.ts CHANGED
@@ -1,3 +1,34 @@
1
- // TODO - please remove the eslint disable comment below when you add props to this interface
2
- // eslint-disable-next-line @typescript-eslint/no-empty-interface
3
- export interface NotificationProps {}
1
+ export const variants = ['neutral', 'neutral-alternative', 'info', 'success', 'warning', 'error'] as const;
2
+ export const headingLevels = ['h2', 'h3', 'h4', 'h5', 'h6'] as const;
3
+
4
+ export interface NotificationProps {
5
+ /**
6
+ * Set the variant of the notification.
7
+ */
8
+ variant?: typeof variants[number];
9
+
10
+ /**
11
+ * When true, the footer aligns to the header and icons which makes the component compact.
12
+ */
13
+ isCompact?: boolean;
14
+
15
+ /**
16
+ * The text to display in the notification's heading.
17
+ */
18
+ heading?: string;
19
+
20
+ /**
21
+ * The HTML heading tag to use for the notification's heading. Can be h1-h6.
22
+ */
23
+ headingLevel?: typeof headingLevels[number];
24
+
25
+ /**
26
+ * Option to hide the icon regardless its variant or if user provided an icon.
27
+ */
28
+ hideIcon?: boolean;
29
+
30
+ /**
31
+ * When true, the notification is set to be open and visible.
32
+ */
33
+ isOpen?: boolean;
34
+ }
package/src/index.ts CHANGED
@@ -1,24 +1,238 @@
1
- import { LitElement, html, unsafeCSS } from 'lit';
2
-
3
- import { defineCustomElement } from '@justeattakeaway/pie-webc-core';
1
+ import {
2
+ unsafeCSS,
3
+ nothing,
4
+ LitElement,
5
+ type TemplateResult,
6
+ type PropertyValues,
7
+ } from 'lit';
8
+ import { type StaticValue, html, unsafeStatic } from 'lit/static-html.js';
9
+ import { defineCustomElement, validPropertyValues } from '@justeattakeaway/pie-webc-core';
10
+ import { property, queryAssignedElements, state } from 'lit/decorators.js';
11
+ import { type NotificationProps, variants, headingLevels } from './defs';
4
12
  import styles from './notification.scss?inline';
5
- import { NotificationProps } from './defs';
13
+
14
+ import '@justeattakeaway/pie-icon-button';
15
+ import '@justeattakeaway/pie-icons-webc/IconClose';
16
+ import '@justeattakeaway/pie-icons-webc/IconInfoCircle';
17
+ import '@justeattakeaway/pie-icons-webc/IconAlertCircle';
18
+ import '@justeattakeaway/pie-icons-webc/IconAlertTriangle';
19
+ import '@justeattakeaway/pie-icons-webc/IconCheckCircle';
6
20
 
7
21
  // Valid values available to consumers
8
22
  export * from './defs';
9
23
 
10
24
  const componentSelector = 'pie-notification';
25
+ const componentClass = 'c-notification';
11
26
 
12
27
  /**
13
28
  * @tagname pie-notification
14
29
  */
15
30
  export class PieNotification extends LitElement implements NotificationProps {
16
- render () {
17
- return html`<h1 data-test-id="pie-notification">Hello world!</h1>`;
18
- }
31
+ @property({ type: Boolean })
32
+ public isOpen = true;
33
+
34
+ @property()
35
+ @validPropertyValues(componentSelector, variants, 'neutral')
36
+ public variant: NonNullable<NotificationProps['variant']> = 'neutral';
37
+
38
+ @property({ type: Boolean })
39
+ public isCompact = false;
40
+
41
+ @property({ type: String })
42
+ public heading!: string;
43
+
44
+ @property()
45
+ @validPropertyValues(componentSelector, headingLevels, 'h2')
46
+ public headingLevel: NonNullable<NotificationProps['headingLevel']> = 'h2';
47
+
48
+ @property({ type: Boolean })
49
+ public hideIcon = false;
50
+
51
+ @property({ type: Boolean })
52
+ public hideCloseIcon = false;
53
+
54
+ @queryAssignedElements({ slot: 'icon' }) _iconSlot!: Array<HTMLElement>;
55
+
56
+ @state()
57
+ protected _hasExternalIcon = false;
58
+
59
+ @state()
60
+ protected _hasIconClass = false;
19
61
 
20
62
  // Renders a `CSSResult` generated from SCSS by Vite
21
63
  static styles = unsafeCSS(styles);
64
+
65
+ /**
66
+ * Lifecycle method executed after component renders.
67
+ */
68
+ protected firstUpdated (): void {
69
+ this.updateIconProperties();
70
+ }
71
+
72
+ /**
73
+ * Lifecycle method executed when component is about to update.
74
+ * It update icon properties if variant has changes.
75
+ */
76
+ protected willUpdate (_changedProperties: PropertyValues<this>): void {
77
+ if (_changedProperties.has('variant')) {
78
+ this.updateIconProperties();
79
+ }
80
+ }
81
+
82
+ /**
83
+ * Method responsible to check if an external icon has been provided.
84
+ * It reads from icon slot if there is an external icon as well check if variant has default icon.
85
+ *
86
+ * @private
87
+ */
88
+ private updateIconProperties () {
89
+ this._hasExternalIcon = this._iconSlot.length > 0;
90
+ this._hasIconClass = this._hasExternalIcon || this.variantHasDefaultIcon(this.variant);
91
+ }
92
+
93
+ /**
94
+ * Template for the footer area
95
+ * Called within the main render function.
96
+ *
97
+ * @private
98
+ */
99
+ private renderFooter () {
100
+ return html`
101
+ <footer class="${componentClass}-footer"></footer>
102
+ `;
103
+ }
104
+
105
+ /**
106
+ * Template for the header area
107
+ * Called within the main render function.
108
+ *
109
+ * @param {NotificationProps['heading']} heading
110
+ * @param {StaticValue} headingTag
111
+ *
112
+ * @private
113
+ */
114
+ private renderNotificationHeading (heading: NotificationProps['heading'], headingTag: StaticValue): TemplateResult {
115
+ return html`
116
+ <header class="${componentClass}-header" data-test-id="${componentSelector}-header">
117
+ <${headingTag} class="${componentClass}-heading" data-test-id="${componentSelector}-heading">${heading}</${headingTag}>
118
+ </header>
119
+ `;
120
+ }
121
+
122
+ /**
123
+ * Util method that returns a boolean if variant has a default icon.
124
+ *
125
+ * @param {NonNullable<NotificationProps['variant']>} variant
126
+ *
127
+ * @private
128
+ */
129
+ private variantHasDefaultIcon (variant: NonNullable<NotificationProps['variant']>) {
130
+ const validVariants = ['info', 'success', 'warning', 'error'];
131
+
132
+ return validVariants.includes(variant);
133
+ }
134
+
135
+ /**
136
+ * Util method that returns an icon from a variant that has default icon.
137
+ *
138
+ * @param {NonNullable<NotificationProps['variant']>} variant
139
+ *
140
+ * @private
141
+ */
142
+ private getDefaultVariantIcon (variant: NonNullable<NotificationProps['variant']>) {
143
+ switch (variant) {
144
+ case 'info':
145
+ return html`<icon-info-circle size="s" data-test-id="${componentSelector}-heading-icon-info"></icon-info-circle>`;
146
+ case 'success':
147
+ return html`<icon-check-circle size="s" data-test-id="${componentSelector}-heading-icon-success"></icon-check-circle>`;
148
+ case 'warning':
149
+ return html`<icon-alert-triangle size="s" data-test-id="${componentSelector}-heading-icon-warning"></icon-alert-triangle>`;
150
+ case 'error':
151
+ return html`<icon-alert-circle size="s" data-test-id="${componentSelector}-heading-icon-error"></icon-alert-circle>`;
152
+ default:
153
+ return nothing as never;
154
+ }
155
+ }
156
+
157
+ /**
158
+ * Util method that returns a template with a default icon according to the chosen variant.
159
+ * Called within the renderIcon method.
160
+ *
161
+ * @param {NonNullable<NotificationProps['variant']>} variant
162
+ *
163
+ * @private
164
+ */
165
+ private renderIconVariant (variant: NonNullable<NotificationProps['variant']>) {
166
+ if (this.variantHasDefaultIcon(variant)) {
167
+ return this.getDefaultVariantIcon(variant);
168
+ }
169
+
170
+ return nothing;
171
+ }
172
+
173
+ /**
174
+ * Template for the heading icon area.
175
+ * It can return an icon provided externally via named slot or it can return an default icon according to the chosen variant.
176
+ * Called within the main render function.
177
+ *
178
+ * @param {NonNullable<NotificationProps['variant']>} variant
179
+ * @param {boolean} hasExternalIcon
180
+ *
181
+ * @private
182
+ */
183
+ private renderIcon (variant: NonNullable<NotificationProps['variant']>, hasExternalIcon: boolean, hasIconClass: boolean): TemplateResult | typeof nothing {
184
+ return html`
185
+ <div data-test-id="${componentSelector}-icon-area" class="${hasIconClass ? 'has-icon ' : ''}${componentClass}-heading-icon">
186
+ ${!hasExternalIcon ? this.renderIconVariant(variant) : nothing}
187
+ <slot name="icon"></slot>
188
+ </div>
189
+ `;
190
+ }
191
+
192
+ /**
193
+ * Template for the close button element. Called within the
194
+ * main render function.
195
+ *
196
+ * @private
197
+ */
198
+ private renderCloseButton (): TemplateResult {
199
+ return html`
200
+ <pie-icon-button
201
+ variant="ghost-secondary"
202
+ size="small"
203
+ class="${componentClass}-icon-close"
204
+ data-test-id="${componentSelector}-icon-close"
205
+ >
206
+ <icon-close></icon-close>
207
+ </pie-icon-button>`;
208
+ }
209
+
210
+ render () {
211
+ const {
212
+ variant,
213
+ heading,
214
+ headingLevel,
215
+ isCompact,
216
+ _hasExternalIcon,
217
+ hideIcon,
218
+ _hasIconClass,
219
+ } = this;
220
+
221
+ return html`
222
+ <div data-test-id="${componentSelector}" class="${componentClass}" variant="${variant}" is-compact="${isCompact}">
223
+ ${!isCompact ? this.renderCloseButton() : nothing}
224
+
225
+ <section class="${componentClass}-content-section">
226
+ ${!hideIcon ? this.renderIcon(variant, _hasExternalIcon, _hasIconClass) : nothing}
227
+ <article>
228
+ ${heading ? this.renderNotificationHeading(heading, unsafeStatic(headingLevel)) : nothing}
229
+ <slot></slot>
230
+ </article>
231
+ </section>
232
+
233
+ ${this.renderFooter()}
234
+ </div>`;
235
+ }
22
236
  }
23
237
 
24
238
  defineCustomElement(componentSelector, PieNotification);
@@ -1 +1,86 @@
1
1
  @use '@justeattakeaway/pie-css/scss' as p;
2
+
3
+ *,
4
+ *:before,
5
+ *:after {
6
+ box-sizing: border-box;
7
+ }
8
+
9
+ .c-notification {
10
+ --notification-border-radius: var(--dt-radius-rounded-c);
11
+ --notification-background-color: var(--dt-color-container-subtle);
12
+ --notification-direction: column;
13
+ --notification-icon-size-override: 22px;
14
+ --notification-heading-font-size: #{p.font-size(--dt-font-size-20)};
15
+ --notification-heading-line-height: calc(var(--dt-font-size-20-line-height) * 1px);
16
+ --notification-font-size: #{p.font-size(--dt-font-size-16)};
17
+ --notification-line-height: calc(var(--dt-font-size-16-line-height) * 1px);
18
+ --notification-icon-fill: var(--dt-color-content-default);
19
+
20
+ padding: var(--dt-spacing-d);
21
+ border-radius: var(--notification-border-radius);
22
+ background-color: var(--notification-background-color);
23
+ position: relative;
24
+ display: flex;
25
+ flex-direction: var(--notification-direction);
26
+ gap: var(--dt-spacing-d);
27
+ font-size: var(--notification-font-size);
28
+ line-height: var(--notification-line-height);
29
+
30
+ h1,
31
+ h2,
32
+ h3,
33
+ h4,
34
+ h5,
35
+ h6 {
36
+ margin: 0;
37
+ font-size: var(--notification-heading-font-size);
38
+ line-height: var(--notification-heading-line-height);
39
+ }
40
+
41
+ &[is-compact='true'] {
42
+ --notification-direction: row;
43
+ }
44
+
45
+ &[variant='neutral-alternative'] {
46
+ --notification-background-color: var(--dt-color-container-default);
47
+ }
48
+
49
+ &[variant='info'] {
50
+ --notification-background-color: var(--dt-color-support-info-02);
51
+ --notification-icon-fill: var(--dt-color-blue);
52
+ }
53
+
54
+ &[variant='success'] {
55
+ --notification-background-color: var(--dt-color-support-positive-02);
56
+ }
57
+
58
+ &[variant='warning'] {
59
+ --notification-background-color: var(--dt-color-support-warning-02);
60
+ }
61
+
62
+ &[variant='error'] {
63
+ --notification-background-color: var(--dt-color-support-error-02);
64
+ --notification-icon-fill: var(--dt-color-red);
65
+ }
66
+
67
+ &-content-section {
68
+ display: flex;
69
+ flex-direction: row;
70
+
71
+ .has-icon {
72
+ margin-inline-end: var(--dt-spacing-c);
73
+ }
74
+ }
75
+
76
+ &-heading-icon {
77
+ padding-block-start: var(--dt-spacing-a);
78
+ color: var(--notification-icon-fill);
79
+ }
80
+
81
+ &-icon-close {
82
+ position: absolute;
83
+ inset-block-start: var(--dt-spacing-b);
84
+ inset-inline-end: var(--dt-spacing-b);
85
+ }
86
+ }