@justeattakeaway/pie-notification 0.21.25 → 0.23.0

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
@@ -50,6 +50,10 @@ Ideally, you should install the component using the **`@justeattakeaway/pie-webc
50
50
  |-----------|-------------------------------------------------------------------------|
51
51
  | `default` | The default slot is used to pass text into the notification component. |
52
52
  | `icon` | Used to pass in an icon to the notification component. |
53
+ | `leadingAction` | Used to pass a custom `pie-button` for the leading action. Only `pie-button` elements are supported; other elements will be hidden. |
54
+ | `supportingAction` | Used to pass a custom `pie-button` for the supporting action. Only `pie-button` elements are supported; other elements will be hidden. |
55
+
56
+ > **Important:** Do not mix props and slots for action buttons. Use **either** the `leadingAction`/`supportingAction` props **or** the `leadingAction`/`supportingAction` slots — not a combination of both. Additionally, do not provide both a prop-based action and a slotted action for the same slot (e.g. setting the `leadingAction` prop while also slotting a `pie-button` into `leadingAction`).
53
57
 
54
58
  ### CSS Variables
55
59
  This component does not expose any CSS variables for style overrides.
@@ -57,11 +61,13 @@ This component does not expose any CSS variables for style overrides.
57
61
  ### Events
58
62
  | Event | Type | Description |
59
63
  |------------------------------------------------|---------------|------------------------------------------------------------|
60
- | `pie-notification-leading-action-click` | `CustomEvent` | Triggered when the user clicks on the leading action. |
61
- | `pie-notification-supporting-action-click` | `CustomEvent` | Triggered when the user clicks on the supporting action. |
64
+ | `pie-notification-leading-action-click` | `CustomEvent` | Triggered when the user clicks on the leading action. Only emitted for prop-based actions; slotted actions do not emit this event. |
65
+ | `pie-notification-supporting-action-click` | `CustomEvent` | Triggered when the user clicks on the supporting action. Only emitted for prop-based actions; slotted actions do not emit this event. |
62
66
  | `pie-notification-close` | `CustomEvent` | Triggered when the user closes the notification. |
63
67
  | `pie-notification-open` | `CustomEvent` | Triggered when the user opens the notification. |
64
68
 
69
+ > **Note:** When using slotted actions, the `pie-notification-leading-action-click` and `pie-notification-supporting-action-click` events are **not** emitted. Since you provide your own `pie-button`, you should attach click handlers directly to the slotted button.
70
+
65
71
  ## Usage Examples
66
72
 
67
73
  > When using icons, we recommend using [@justeattakeaway/pie-icons-webc](https://www.npmjs.com/package/@justeattakeaway/pie-icons-webc) to ensure consistency with the rest of the design system.
@@ -109,6 +115,86 @@ import { IconPlaceholder } from '@justeattakeaway/pie-icons-webc/dist/react/Icon
109
115
  </PieNotification>
110
116
  ```
111
117
 
118
+ ### With Slotted Actions
119
+
120
+ For more control over action buttons (e.g. adding icons, loading states, or disabled states), you can slot your own `pie-button` elements. Only `pie-button` elements are supported in the action slots; other elements will be hidden.
121
+
122
+ When using slotted actions, `pie-notification-leading-action-click` and `pie-notification-supporting-action-click` events are **not** emitted. Attach click handlers directly to your slotted buttons instead.
123
+
124
+ **For HTML:**
125
+
126
+ ```html
127
+ <pie-notification heading="Item added" variant="success" isOpen>
128
+ Your item has been added to the basket.
129
+ <pie-button
130
+ slot="leadingAction"
131
+ variant="primary"
132
+ size="small-productive"
133
+ onclick="handleConfirm()">
134
+ <icon-plus-circle slot="icon"></icon-plus-circle>
135
+ Confirm
136
+ </pie-button>
137
+ <pie-button
138
+ slot="supportingAction"
139
+ variant="ghost"
140
+ size="small-productive"
141
+ onclick="handleCancel()">
142
+ Cancel
143
+ </pie-button>
144
+ </pie-notification>
145
+ ```
146
+
147
+ **For Native JS Applications, Vue, Angular, Svelte etc.:**
148
+
149
+ ```html
150
+ <!-- Vue templates (using Nuxt 3) -->
151
+ <pie-notification heading="Item added" variant="success" isOpen>
152
+ Your item has been added to the basket.
153
+ <pie-button
154
+ slot="leadingAction"
155
+ variant="primary"
156
+ size="small-productive"
157
+ @click="handleConfirm">
158
+ <icon-plus-circle slot="icon"></icon-plus-circle>
159
+ Confirm
160
+ </pie-button>
161
+ <pie-button
162
+ slot="supportingAction"
163
+ variant="ghost"
164
+ size="small-productive"
165
+ @click="handleCancel">
166
+ Cancel
167
+ </pie-button>
168
+ </pie-notification>
169
+ ```
170
+
171
+ **For React Applications:**
172
+
173
+ ```jsx
174
+ import { PieNotification } from '@justeattakeaway/pie-webc/react/notification.js';
175
+ import { PieButton } from '@justeattakeaway/pie-webc/react/button.js';
176
+ import { IconPlusCircle } from '@justeattakeaway/pie-icons-webc/dist/react/IconPlusCircle.js';
177
+
178
+ <PieNotification heading="Item added" variant="success" isOpen>
179
+ Your item has been added to the basket.
180
+ <PieButton
181
+ slot="leadingAction"
182
+ variant="primary"
183
+ size="small-productive"
184
+ onClick={handleConfirm}>
185
+ <IconPlusCircle slot="icon" />
186
+ Confirm
187
+ </PieButton>
188
+ <PieButton
189
+ slot="supportingAction"
190
+ variant="ghost"
191
+ size="small-productive"
192
+ onClick={handleCancel}>
193
+ Cancel
194
+ </PieButton>
195
+ </PieNotification>
196
+ ```
197
+
112
198
  ### With Link Actions
113
199
 
114
200
  Actions can be rendered as links by providing an `href` property. This is useful when you want to navigate to a URL or trigger a file download.
@@ -90,7 +90,7 @@
90
90
  "type": {
91
91
  "text": "ActionProps"
92
92
  },
93
- "default": "{\r\n text: '',\r\n ariaLabel: '',\r\n size: 'small-productive',\r\n}"
93
+ "default": "{ text: '', ariaLabel: '', size: 'small-productive', }"
94
94
  },
95
95
  {
96
96
  "kind": "variable",
@@ -98,7 +98,7 @@
98
98
  "type": {
99
99
  "text": "DefaultProps"
100
100
  },
101
- "default": "{\r\n variant: 'neutral',\r\n position: 'inline-content',\r\n isDismissible: false,\r\n isCompact: false,\r\n headingLevel: 'h2',\r\n hideIcon: false,\r\n isOpen: true,\r\n hasStackedActions: false,\r\n leadingAction: defaultActionButtonProps,\r\n supportingAction: defaultActionButtonProps,\r\n}"
101
+ "default": "{ variant: 'neutral', position: 'inline-content', isDismissible: false, isCompact: false, headingLevel: 'h2', hideIcon: false, isOpen: true, hasStackedActions: false, leadingAction: defaultActionButtonProps, supportingAction: defaultActionButtonProps, }"
102
102
  }
103
103
  ],
104
104
  "exports": [
@@ -216,33 +216,47 @@
216
216
  {
217
217
  "description": "The icon slot",
218
218
  "name": "icon"
219
+ },
220
+ {
221
+ "description": "An optional slot for a custom `pie-button` to replace the prop-based leading action button.",
222
+ "name": "leadingAction"
223
+ },
224
+ {
225
+ "description": "An optional slot for a custom `pie-button` to replace the prop-based supporting action button.",
226
+ "name": "supportingAction"
219
227
  }
220
228
  ],
221
229
  "members": [
222
230
  {
223
231
  "kind": "field",
224
232
  "name": "isOpen",
225
- "privacy": "public"
233
+ "privacy": "public",
234
+ "attribute": "isOpen"
226
235
  },
227
236
  {
228
237
  "kind": "field",
229
238
  "name": "variant",
230
- "privacy": "public"
239
+ "privacy": "public",
240
+ "attribute": "variant"
231
241
  },
232
242
  {
233
243
  "kind": "field",
234
244
  "name": "position",
235
- "privacy": "public"
245
+ "privacy": "public",
246
+ "attribute": "position"
236
247
  },
237
248
  {
238
249
  "kind": "field",
239
250
  "name": "isDismissible",
240
- "privacy": "public"
251
+ "privacy": "public",
252
+ "attribute": "isDismissible"
241
253
  },
242
254
  {
243
255
  "kind": "field",
244
256
  "name": "isCompact",
245
- "privacy": "public"
257
+ "privacy": "public",
258
+ "attribute": "isCompact",
259
+ "reflects": true
246
260
  },
247
261
  {
248
262
  "kind": "field",
@@ -250,17 +264,20 @@
250
264
  "type": {
251
265
  "text": "NotificationProps['heading']"
252
266
  },
253
- "privacy": "public"
267
+ "privacy": "public",
268
+ "attribute": "heading"
254
269
  },
255
270
  {
256
271
  "kind": "field",
257
272
  "name": "headingLevel",
258
- "privacy": "public"
273
+ "privacy": "public",
274
+ "attribute": "headingLevel"
259
275
  },
260
276
  {
261
277
  "kind": "field",
262
278
  "name": "hideIcon",
263
- "privacy": "public"
279
+ "privacy": "public",
280
+ "attribute": "hideIcon"
264
281
  },
265
282
  {
266
283
  "kind": "field",
@@ -268,7 +285,8 @@
268
285
  "type": {
269
286
  "text": "NotificationProps['leadingAction']"
270
287
  },
271
- "privacy": "public"
288
+ "privacy": "public",
289
+ "attribute": "leadingAction"
272
290
  },
273
291
  {
274
292
  "kind": "field",
@@ -276,12 +294,15 @@
276
294
  "type": {
277
295
  "text": "NotificationProps['supportingAction']"
278
296
  },
279
- "privacy": "public"
297
+ "privacy": "public",
298
+ "attribute": "supportingAction"
280
299
  },
281
300
  {
282
301
  "kind": "field",
283
302
  "name": "hasStackedActions",
284
- "privacy": "public"
303
+ "privacy": "public",
304
+ "attribute": "hasStackedActions",
305
+ "reflects": true
285
306
  },
286
307
  {
287
308
  "kind": "field",
@@ -289,7 +310,8 @@
289
310
  "type": {
290
311
  "text": "NotificationProps['aria']"
291
312
  },
292
- "privacy": "public"
313
+ "privacy": "public",
314
+ "attribute": "aria"
293
315
  },
294
316
  {
295
317
  "kind": "field",
@@ -298,11 +320,23 @@
298
320
  "text": "Array<HTMLElement>"
299
321
  }
300
322
  },
323
+ {
324
+ "kind": "method",
325
+ "name": "renderSupportingAction",
326
+ "privacy": "private",
327
+ "description": "Renders the supporting action - either from slot or props.\nSupporting action only renders when a leading action is also present (via prop or slot)."
328
+ },
329
+ {
330
+ "kind": "method",
331
+ "name": "renderLeadingAction",
332
+ "privacy": "private",
333
+ "description": "Renders the leading action from props."
334
+ },
301
335
  {
302
336
  "kind": "method",
303
337
  "name": "renderFooter",
304
338
  "privacy": "private",
305
- "description": "Template for the footer area\r\nCalled within the main render function."
339
+ "description": "Template for the footer area\nCalled within the main render function."
306
340
  },
307
341
  {
308
342
  "kind": "method",
@@ -313,7 +347,7 @@
313
347
  "text": "TemplateResult"
314
348
  }
315
349
  },
316
- "description": "Template for the header area\r\nCalled within the main render function."
350
+ "description": "Template for the header area\nCalled within the main render function."
317
351
  },
318
352
  {
319
353
  "kind": "method",
@@ -330,7 +364,7 @@
330
364
  "text": "TemplateResult | typeof nothing"
331
365
  }
332
366
  },
333
- "description": "Template for the heading icon area.\r\nIt can return an icon provided externally via named slot or it can return a default icon according to the chosen variant if defined.\r\nCalled within the main render function."
367
+ "description": "Template for the heading icon area.\nIt can return an icon provided externally via named slot or it can return a default icon according to the chosen variant if defined.\nCalled within the main render function."
334
368
  },
335
369
  {
336
370
  "kind": "method",
@@ -341,13 +375,13 @@
341
375
  "text": "TemplateResult"
342
376
  }
343
377
  },
344
- "description": "Template for the close button element. Called within the\r\nmain render function."
378
+ "description": "Template for the close button element. Called within the\nmain render function."
345
379
  },
346
380
  {
347
381
  "kind": "method",
348
382
  "name": "handleCloseButton",
349
383
  "privacy": "private",
350
- "description": "It handles the action when user clicks in the close button.\r\nAlso triggers an event when is executed."
384
+ "description": "It handles the action when user clicks in the close button.\nAlso triggers an event when is executed."
351
385
  },
352
386
  {
353
387
  "kind": "method",
@@ -361,7 +395,7 @@
361
395
  }
362
396
  }
363
397
  ],
364
- "description": "It handles the action button action.\r\nAlso triggers an event according to its `actionType`."
398
+ "description": "It handles the action button action.\nAlso triggers an event according to its `actionType`."
365
399
  },
366
400
  {
367
401
  "kind": "method",
@@ -421,6 +455,68 @@
421
455
  "name": "pie-notification-open"
422
456
  }
423
457
  ],
458
+ "attributes": [
459
+ {
460
+ "name": "isOpen",
461
+ "fieldName": "isOpen"
462
+ },
463
+ {
464
+ "name": "variant",
465
+ "fieldName": "variant"
466
+ },
467
+ {
468
+ "name": "position",
469
+ "fieldName": "position"
470
+ },
471
+ {
472
+ "name": "isDismissible",
473
+ "fieldName": "isDismissible"
474
+ },
475
+ {
476
+ "name": "isCompact",
477
+ "fieldName": "isCompact"
478
+ },
479
+ {
480
+ "name": "heading",
481
+ "type": {
482
+ "text": "NotificationProps['heading']"
483
+ },
484
+ "fieldName": "heading"
485
+ },
486
+ {
487
+ "name": "headingLevel",
488
+ "fieldName": "headingLevel"
489
+ },
490
+ {
491
+ "name": "hideIcon",
492
+ "fieldName": "hideIcon"
493
+ },
494
+ {
495
+ "name": "leadingAction",
496
+ "type": {
497
+ "text": "NotificationProps['leadingAction']"
498
+ },
499
+ "fieldName": "leadingAction"
500
+ },
501
+ {
502
+ "name": "supportingAction",
503
+ "type": {
504
+ "text": "NotificationProps['supportingAction']"
505
+ },
506
+ "fieldName": "supportingAction"
507
+ },
508
+ {
509
+ "name": "hasStackedActions",
510
+ "fieldName": "hasStackedActions"
511
+ },
512
+ {
513
+ "name": "aria",
514
+ "type": {
515
+ "text": "NotificationProps['aria']"
516
+ },
517
+ "fieldName": "aria"
518
+ }
519
+ ],
424
520
  "superclass": {
425
521
  "name": "PieElement",
426
522
  "package": "@justeattakeaway/pie-webc-core/src/internals/PieElement"
@@ -435,7 +531,7 @@
435
531
  "name": "*",
436
532
  "declaration": {
437
533
  "name": "*",
438
- "package": "./defs"
534
+ "module": "src/defs"
439
535
  }
440
536
  },
441
537
  {
package/dist/index.d.ts CHANGED
@@ -145,6 +145,8 @@ export declare const ON_NOTIFICATION_SUPPORTING_ACTION_CLICK_EVENT = "pie-notifi
145
145
  * @event {CustomEvent} pie-notification-open - When the notification is opened.
146
146
  * @slot - Default slot
147
147
  * @slot icon - The icon slot
148
+ * @slot leadingAction - An optional slot for a custom `pie-button` to replace the prop-based leading action button.
149
+ * @slot supportingAction - An optional slot for a custom `pie-button` to replace the prop-based supporting action button.
148
150
  */
149
151
  export declare class PieNotification extends PieElement implements NotificationProps {
150
152
  isOpen: boolean;
@@ -166,6 +168,19 @@ export declare class PieNotification extends PieElement implements NotificationP
166
168
  * It dispatches an event if notification is opened.
167
169
  */
168
170
  protected updated(_changedProperties: PropertyValues<this>): void;
171
+ /**
172
+ * Renders the supporting action - either from slot or props.
173
+ * Supporting action only renders when a leading action is also present (via prop or slot).
174
+ *
175
+ * @private
176
+ */
177
+ private renderSupportingAction;
178
+ /**
179
+ * Renders the leading action from props.
180
+ *
181
+ * @private
182
+ */
183
+ private renderLeadingAction;
169
184
  /**
170
185
  * Template for the footer area
171
186
  * Called within the main render function.
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
1
- import { LitElement as A, unsafeCSS as I, nothing as s } from "lit";
2
- import { classMap as O } from "lit/directives/class-map.js";
3
- import { html as f, unsafeStatic as z } from "lit/static-html.js";
4
- import { validPropertyValues as N, safeCustomElement as _, dispatchCustomEvent as x } from "@justeattakeaway/pie-webc-core";
5
- import { property as r, queryAssignedElements as S } from "lit/decorators.js";
6
- import { ifDefined as g } from "lit/directives/if-defined.js";
1
+ import { LitElement as N, unsafeCSS as I, nothing as l } from "lit";
2
+ import { classMap as w } from "lit/directives/class-map.js";
3
+ import { html as d, unsafeStatic as z } from "lit/static-html.js";
4
+ import { validPropertyValues as O, safeCustomElement as S, dispatchCustomEvent as A } from "@justeattakeaway/pie-webc-core";
5
+ import { property as r, queryAssignedElements as _ } from "lit/decorators.js";
6
+ import { ifDefined as h } from "lit/directives/if-defined.js";
7
7
  import "@justeattakeaway/pie-button";
8
8
  import "@justeattakeaway/pie-icon-button";
9
9
  import "@justeattakeaway/pie-icons-webc/dist/IconAlertCircle.js";
@@ -11,18 +11,18 @@ import "@justeattakeaway/pie-icons-webc/dist/IconAlertTriangle.js";
11
11
  import "@justeattakeaway/pie-icons-webc/dist/IconCheckCircle.js";
12
12
  import "@justeattakeaway/pie-icons-webc/dist/IconClose.js";
13
13
  import "@justeattakeaway/pie-icons-webc/dist/IconInfoCircle.js";
14
- const y = class y extends A {
14
+ const $ = class $ extends N {
15
15
  willUpdate() {
16
- this.getAttribute("v") || this.setAttribute("v", y.v);
16
+ this.getAttribute("v") || this.setAttribute("v", $.v);
17
17
  }
18
18
  };
19
- y.v = "0.21.25";
20
- let C = y;
21
- const E = ["neutral", "neutral-alternative", "info", "success", "warning", "error", "translucent"], L = ["h2", "h3", "h4", "h5", "h6"], T = ["inline-content", "full-width"], B = ["small-productive", "xsmall"], t = "pie-notification", u = "c-notification", D = `${t}-close`, V = `${t}-open`, P = `${t}-leading-action-click`, F = `${t}-supporting-action-click`, $ = {
19
+ $.v = "0.23.0";
20
+ let C = $;
21
+ const E = ["neutral", "neutral-alternative", "info", "success", "warning", "error", "translucent"], L = ["h2", "h3", "h4", "h5", "h6"], T = ["inline-content", "full-width"], B = ["small-productive", "xsmall"], o = "pie-notification", u = "c-notification", D = `${o}-close`, V = `${o}-open`, P = `${o}-leading-action-click`, F = `${o}-supporting-action-click`, b = {
22
22
  text: "",
23
23
  ariaLabel: "",
24
24
  size: "small-productive"
25
- }, l = {
25
+ }, s = {
26
26
  variant: "neutral",
27
27
  position: "inline-content",
28
28
  isDismissible: !1,
@@ -31,24 +31,43 @@ const E = ["neutral", "neutral-alternative", "info", "success", "warning", "erro
31
31
  hideIcon: !1,
32
32
  isOpen: !0,
33
33
  hasStackedActions: !1,
34
- leadingAction: $,
35
- supportingAction: $
36
- }, j = "*,*:after,*:before{box-sizing:inherit}:host{display:block}.c-notification{--notification-border-radius: var(--dt-radius-rounded-c);--notification-background-color: var(--dt-color-container-subtle);--notification-direction: column;--notification-heading-font-family: var(--dt-font-heading-s-family);--notification-heading-font-size: calc(var(--dt-font-heading-s-size--narrow) * 1px);--notification-heading-line-height: calc(var(--dt-font-heading-s-line-height--narrow) * 1px);--notification-heading-font-weight: var(--dt-font-heading-s-weight);--notification-font-family: var(--dt-font-body-l-family);--notification-font-size: calc(var(--dt-font-body-l-size) * 1px);--notification-line-height: calc(var(--dt-font-body-l-line-height) * 1px);--notification-font-weight: var(--dt-font-body-l-weight);--notification-close-icon-offset: var(--dt-spacing-b);--notification-icon-fill: var(--dt-color-content-inverse);--notification-icon-background-color: var(--dt-color-container-inverse);--icon-size-override: 24px;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-family:var(--notification-font-family);font-size:var(--notification-font-size);line-height:var(--notification-line-height);font-weight:var(--notification-font-weight);color:var(--dt-color-content-default)}.c-notification.is-compact{--notification-direction: row}.c-notification.c-notification--full-width{--notification-border-radius: var(--dt-radius-rounded-none)}.c-notification.c-notification--neutral-alternative{--notification-background-color: var(--dt-color-container-default)}.c-notification.c-notification--info{--notification-background-color: var(--dt-color-support-info-tonal);--notification-icon-background-color: var(--dt-color-support-info)}.c-notification.c-notification--success{--notification-background-color: var(--dt-color-support-positive-tonal);--notification-icon-background-color: var(--dt-color-support-positive)}.c-notification.c-notification--warning{--notification-background-color: var(--dt-color-support-warning-tonal);--notification-icon-background-color: var(--dt-color-support-warning);--notification-icon-fill: var(--dt-color-content-dark)}.c-notification.c-notification--error{--notification-background-color: var(--dt-color-support-error-tonal);--notification-icon-background-color: var(--dt-color-support-error);--notification-icon-fill: var(--dt-color-content-light)}.c-notification.c-notification--translucent{--notification-background-color: var(--dt-color-container-prominent);-webkit-backdrop-filter:blur(var(--dt-blur-prominent));backdrop-filter:blur(var(--dt-blur-prominent))}.c-notification-heading{margin:0;margin-block-end:var(--dt-spacing-a);font-family:var(--notification-heading-font-family);font-size:var(--notification-heading-font-size);line-height:var(--notification-heading-line-height);font-weight:var(--notification-heading-font-weight)}@media (min-width: 769px){.c-notification-heading{--notification-heading-font-size: calc(var(--dt-font-heading-s-size--wide) * 1px);--notification-heading-line-height: calc(var(--dt-font-heading-s-line-height--wide) * 1px)}}.c-notification-content-section{display:flex;flex-direction:row;align-items:center;gap:var(--dt-spacing-c)}.c-notification-content-section.is-dismissible{max-width:calc(100% - var(--notification-close-icon-offset) - 40px)}.c-notification-icon-close{position:absolute;inset-block-start:var(--notification-close-icon-offset);inset-inline-end:var(--notification-close-icon-offset)}.c-notification-footer{display:flex;flex-direction:row;justify-content:flex-end;gap:var(--dt-spacing-d)}.c-notification-footer.is-compact{align-self:center;margin-inline-start:auto}@media (max-width: 767px){.c-notification-footer.c-notification-footer--stacked{flex-direction:column-reverse}}@media (min-width: 768px){.c-notification-footer.c-notification-footer--stacked>pie-button{width:auto}}.icon,::slotted([slot=icon]){display:inline-flex;align-self:flex-start;background-color:var(--notification-icon-background-color);color:var(--notification-icon-fill);border-radius:var(--dt-radius-rounded-b);padding:var(--dt-spacing-a)}";
37
- var G = Object.defineProperty, H = Object.getOwnPropertyDescriptor, c = (i, o, n, d) => {
38
- for (var e = d > 1 ? void 0 : d ? H(o, n) : o, h = i.length - 1, p; h >= 0; h--)
39
- (p = i[h]) && (e = (d ? p(o, n, e) : p(e)) || e);
40
- return d && e && G(o, n, e), e;
34
+ leadingAction: b,
35
+ supportingAction: b
36
+ }, j = "*,*:after,*:before{box-sizing:inherit}:host{display:block}.c-notification{--notification-border-radius: var(--dt-radius-rounded-c);--notification-background-color: var(--dt-color-container-subtle);--notification-direction: column;--notification-heading-font-family: var(--dt-font-heading-s-family);--notification-heading-font-size: calc(var(--dt-font-heading-s-size--narrow) * 1px);--notification-heading-line-height: calc(var(--dt-font-heading-s-line-height--narrow) * 1px);--notification-heading-font-weight: var(--dt-font-heading-s-weight);--notification-font-family: var(--dt-font-body-l-family);--notification-font-size: calc(var(--dt-font-body-l-size) * 1px);--notification-line-height: calc(var(--dt-font-body-l-line-height) * 1px);--notification-font-weight: var(--dt-font-body-l-weight);--notification-close-icon-offset: var(--dt-spacing-b);--notification-icon-fill: var(--dt-color-content-inverse);--notification-icon-background-color: var(--dt-color-container-inverse);--icon-size-override: 24px;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);font-family:var(--notification-font-family);font-size:var(--notification-font-size);line-height:var(--notification-line-height);font-weight:var(--notification-font-weight);color:var(--dt-color-content-default)}.c-notification.is-compact{--notification-direction: row}.c-notification.c-notification--full-width{--notification-border-radius: var(--dt-radius-rounded-none)}.c-notification.c-notification--neutral-alternative{--notification-background-color: var(--dt-color-container-default)}.c-notification.c-notification--info{--notification-background-color: var(--dt-color-support-info-tonal);--notification-icon-background-color: var(--dt-color-support-info)}.c-notification.c-notification--success{--notification-background-color: var(--dt-color-support-positive-tonal);--notification-icon-background-color: var(--dt-color-support-positive)}.c-notification.c-notification--warning{--notification-background-color: var(--dt-color-support-warning-tonal);--notification-icon-background-color: var(--dt-color-support-warning);--notification-icon-fill: var(--dt-color-content-dark)}.c-notification.c-notification--error{--notification-background-color: var(--dt-color-support-error-tonal);--notification-icon-background-color: var(--dt-color-support-error);--notification-icon-fill: var(--dt-color-content-light)}.c-notification.c-notification--translucent{--notification-background-color: var(--dt-color-container-prominent);-webkit-backdrop-filter:blur(var(--dt-blur-prominent));backdrop-filter:blur(var(--dt-blur-prominent))}.c-notification-heading{margin:0;margin-block-end:var(--dt-spacing-a);font-family:var(--notification-heading-font-family);font-size:var(--notification-heading-font-size);line-height:var(--notification-heading-line-height);font-weight:var(--notification-heading-font-weight)}@media (min-width: 769px){.c-notification-heading{--notification-heading-font-size: calc(var(--dt-font-heading-s-size--wide) * 1px);--notification-heading-line-height: calc(var(--dt-font-heading-s-line-height--wide) * 1px)}}.c-notification-content-section{display:flex;flex-direction:row;align-items:center;gap:var(--dt-spacing-c)}.c-notification-content-section.is-dismissible{max-width:calc(100% - var(--notification-close-icon-offset) - 40px)}.c-notification-icon-close{position:absolute;inset-block-start:var(--notification-close-icon-offset);inset-inline-end:var(--notification-close-icon-offset)}.c-notification-footer{display:flex;flex-direction:row;justify-content:flex-end;gap:var(--dt-spacing-d)}.c-notification-footer pie-button,.c-notification-footer ::slotted(pie-button){margin-block-start:var(--dt-spacing-d)}.c-notification-footer.is-compact{align-self:center;margin-inline-start:auto}@media (max-width: 767px){.c-notification-footer.c-notification-footer--stacked{flex-direction:column-reverse;gap:0}.c-notification-footer.c-notification-footer--stacked ::slotted(pie-button){--btn-inline-size: 100%}}@media (min-width: 768px){.c-notification-footer.c-notification-footer--stacked>pie-button{width:auto}}.c-notification-footer ::slotted(:not(pie-button)){display:none}:host([isCompact]) .c-notification-footer pie-button,:host([isCompact]) .c-notification-footer ::slotted(pie-button){margin-block-start:0}.icon,::slotted([slot=icon]){display:inline-flex;align-self:flex-start;background-color:var(--notification-icon-background-color);color:var(--notification-icon-fill);border-radius:var(--dt-radius-rounded-b);padding:var(--dt-spacing-a)}";
37
+ var G = Object.defineProperty, H = Object.getOwnPropertyDescriptor, c = (i, t, e, f) => {
38
+ for (var a = f > 1 ? void 0 : f ? H(t, e) : t, p = i.length - 1, g; p >= 0; p--)
39
+ (g = i[p]) && (a = (f ? g(t, e, a) : g(a)) || a);
40
+ return f && a && G(t, e, a), a;
41
41
  };
42
- let a = class extends C {
42
+ let n = class extends C {
43
43
  constructor() {
44
- super(...arguments), this.isOpen = l.isOpen, this.variant = l.variant, this.position = l.position, this.isDismissible = l.isDismissible, this.isCompact = l.isCompact, this.headingLevel = l.headingLevel, this.hideIcon = l.hideIcon, this.hasStackedActions = l.hasStackedActions;
44
+ super(...arguments), this.isOpen = s.isOpen, this.variant = s.variant, this.position = s.position, this.isDismissible = s.isDismissible, this.isCompact = s.isCompact, this.headingLevel = s.headingLevel, this.hideIcon = s.hideIcon, this.hasStackedActions = s.hasStackedActions;
45
45
  }
46
46
  /**
47
47
  * Lifecycle method executed when component is updated.
48
48
  * It dispatches an event if notification is opened.
49
49
  */
50
50
  updated(i) {
51
- i.has("isOpen") && this.isOpen && x(this, V, { targetNotification: this });
51
+ i.has("isOpen") && this.isOpen && A(this, V, { targetNotification: this });
52
+ }
53
+ /**
54
+ * Renders the supporting action - either from slot or props.
55
+ * Supporting action only renders when a leading action is also present (via prop or slot).
56
+ *
57
+ * @private
58
+ */
59
+ renderSupportingAction() {
60
+ const { supportingAction: i, leadingAction: t } = this;
61
+ return i && (t != null && t.text) ? this.renderActionButton(i, "supporting") : l;
62
+ }
63
+ /**
64
+ * Renders the leading action from props.
65
+ *
66
+ * @private
67
+ */
68
+ renderLeadingAction() {
69
+ const { leadingAction: i } = this;
70
+ return i ? this.renderActionButton(i, "leading") : l;
52
71
  }
53
72
  /**
54
73
  * Template for the footer area
@@ -58,22 +77,22 @@ let a = class extends C {
58
77
  */
59
78
  renderFooter() {
60
79
  const {
61
- leadingAction: i,
62
- supportingAction: o,
63
- isCompact: n,
64
- hasStackedActions: d
80
+ isCompact: i,
81
+ hasStackedActions: t
65
82
  } = this, e = {
66
83
  [`${u}-footer`]: !0,
67
- "is-compact": n,
68
- [`${u}-footer--stacked`]: d && !n
84
+ "is-compact": i,
85
+ [`${u}-footer--stacked`]: t && !i
69
86
  };
70
- return f`
71
- <footer
72
- class="${O(e)}"
73
- data-test-id="${t}-footer">
74
- ${o ? this.renderActionButton(o, "supporting") : s}
75
- ${i ? this.renderActionButton(i, "leading") : s}
76
- </footer>
87
+ return d`
88
+ <div
89
+ class="${w(e)}"
90
+ data-test-id="${o}-footer">
91
+ ${this.renderSupportingAction()}
92
+ <slot name="supportingAction"></slot>
93
+ ${this.renderLeadingAction()}
94
+ <slot name="leadingAction"></slot>
95
+ </div>
77
96
  `;
78
97
  }
79
98
  /**
@@ -83,13 +102,13 @@ let a = class extends C {
83
102
  * @private
84
103
  */
85
104
  renderNotificationHeading() {
86
- const { heading: i, headingLevel: o } = this, n = z(o);
87
- return f`<${n}
88
- id="${t}-heading"
105
+ const { heading: i, headingLevel: t } = this, e = z(t);
106
+ return d`<${e}
107
+ id="${o}-heading"
89
108
  class="${u}-heading"
90
- data-test-id="${t}-heading">
109
+ data-test-id="${o}-heading">
91
110
  ${i}
92
- </${n}>`;
111
+ </${e}>`;
93
112
  }
94
113
  /**
95
114
  * Util method that returns an icon from a variant that has default icon.
@@ -99,15 +118,15 @@ let a = class extends C {
99
118
  getDefaultVariantIcon() {
100
119
  switch (this.variant) {
101
120
  case "info":
102
- return f`<icon-info-circle class="icon" size="m" data-test-id="${t}-heading-icon-info"></icon-info-circle>`;
121
+ return d`<icon-info-circle class="icon" size="m" data-test-id="${o}-heading-icon-info"></icon-info-circle>`;
103
122
  case "success":
104
- return f`<icon-check-circle class="icon" size="m" data-test-id="${t}-heading-icon-success"></icon-check-circle>`;
123
+ return d`<icon-check-circle class="icon" size="m" data-test-id="${o}-heading-icon-success"></icon-check-circle>`;
105
124
  case "warning":
106
- return f`<icon-alert-triangle class="icon" size="m" data-test-id="${t}-heading-icon-warning"></icon-alert-triangle>`;
125
+ return d`<icon-alert-triangle class="icon" size="m" data-test-id="${o}-heading-icon-warning"></icon-alert-triangle>`;
107
126
  case "error":
108
- return f`<icon-alert-circle class="icon" size="m" data-test-id="${t}-heading-icon-error"></icon-alert-circle>`;
127
+ return d`<icon-alert-circle class="icon" size="m" data-test-id="${o}-heading-icon-error"></icon-alert-circle>`;
109
128
  default:
110
- return s;
129
+ return l;
111
130
  }
112
131
  }
113
132
  /**
@@ -118,7 +137,7 @@ let a = class extends C {
118
137
  * @private
119
138
  */
120
139
  renderIcon() {
121
- return f`<slot name="icon">${this.getDefaultVariantIcon()}</slot>`;
140
+ return d`<slot name="icon">${this.getDefaultVariantIcon()}</slot>`;
122
141
  }
123
142
  /**
124
143
  * Template for the close button element. Called within the
@@ -128,14 +147,14 @@ let a = class extends C {
128
147
  */
129
148
  renderCloseButton() {
130
149
  var i;
131
- return f`
150
+ return d`
132
151
  <pie-icon-button
133
152
  variant="ghost-secondary"
134
153
  size="small"
135
154
  class="${u}-icon-close"
136
- data-test-id="${t}-icon-close"
155
+ data-test-id="${o}-icon-close"
137
156
  @click="${this.handleCloseButton}"
138
- aria-label="${g((i = this.aria) == null ? void 0 : i.close)}">
157
+ aria-label="${h((i = this.aria) == null ? void 0 : i.close)}">
139
158
  <icon-close></icon-close>
140
159
  </pie-icon-button>`;
141
160
  }
@@ -146,7 +165,7 @@ let a = class extends C {
146
165
  * @private
147
166
  */
148
167
  handleCloseButton() {
149
- this.isOpen = !1, x(this, D, { targetNotification: this });
168
+ this.isOpen = !1, A(this, D, { targetNotification: this });
150
169
  }
151
170
  /**
152
171
  * It handles the action button action.
@@ -157,7 +176,7 @@ let a = class extends C {
157
176
  * @private
158
177
  */
159
178
  handleActionClick(i) {
160
- x(this, i === "leading" ? P : F, { targetNotification: this });
179
+ A(this, i === "leading" ? P : F, { targetNotification: this });
161
180
  }
162
181
  /**
163
182
  * Render the action button depending on action type and its action.
@@ -168,139 +187,138 @@ let a = class extends C {
168
187
  * @returns {TemplateResult | typeof nothing} - The rendered action button or nothing if the action text is not defined.
169
188
  * @private
170
189
  */
171
- renderActionButton(i, o) {
190
+ renderActionButton(i, t) {
172
191
  const {
173
- text: n,
174
- ariaLabel: d,
175
- size: e = $.size,
176
- href: h,
177
- target: p,
178
- rel: k,
179
- download: v
192
+ text: e,
193
+ ariaLabel: f,
194
+ size: a = b.size,
195
+ href: p,
196
+ target: g,
197
+ rel: v,
198
+ download: m
180
199
  } = i;
181
- if (!n)
182
- return s;
183
- const m = o === "leading" ? "primary" : "ghost", w = e && B.includes(e) ? e : $.size, b = !!h;
184
- return f`
200
+ if (!e)
201
+ return l;
202
+ const y = t === "leading" ? "primary" : "ghost", k = a && B.includes(a) ? a : b.size, x = !!p;
203
+ return d`
185
204
  <pie-button
186
- variant="${m}"
187
- size="${g(w)}"
188
- aria-label="${g(d)}"
189
- @click="${() => this.handleActionClick(o)}"
190
- data-test-id="${t}-${o}-action"
205
+ variant="${y}"
206
+ size="${h(k)}"
207
+ aria-label="${h(f)}"
208
+ @click="${() => this.handleActionClick(t)}"
209
+ data-test-id="${o}-${t}-action"
191
210
  ?isFullWidth="${this.hasStackedActions}"
192
- tag="${b ? "a" : "button"}"
193
- type="${b ? s : "button"}"
194
- href="${g(h)}"
195
- target="${g(p)}"
196
- rel="${g(k)}"
197
- download="${g(v)}">
198
- ${n}
211
+ tag="${x ? "a" : "button"}"
212
+ type="${x ? l : "button"}"
213
+ href="${h(p)}"
214
+ target="${h(g)}"
215
+ rel="${h(v)}"
216
+ download="${h(m)}">
217
+ ${e}
199
218
  </pie-button>
200
219
  `;
201
220
  }
202
221
  render() {
203
222
  const {
204
223
  variant: i,
205
- position: o,
206
- heading: n,
207
- isDismissible: d,
208
- isCompact: e,
209
- hideIcon: h,
210
- leadingAction: p,
211
- isOpen: k,
224
+ position: t,
225
+ heading: e,
226
+ isDismissible: f,
227
+ isCompact: a,
228
+ hideIcon: p,
229
+ isOpen: g,
212
230
  aria: v
213
231
  } = this;
214
- if (!k)
215
- return s;
216
- const m = d && !e, w = {
232
+ if (!g)
233
+ return l;
234
+ const m = f && !a, y = {
217
235
  [u]: !0,
218
236
  [`${u}--${i}`]: !0,
219
- [`${u}--${o}`]: !0,
220
- "is-compact": e
221
- }, b = {
237
+ [`${u}--${t}`]: !0,
238
+ "is-compact": a
239
+ }, k = {
222
240
  [`${u}-content-section`]: !0,
223
241
  "is-dismissible": m
224
242
  };
225
- return f`
243
+ return d`
226
244
  <div
227
- data-test-id="${t}"
228
- class="${O(w)}"
245
+ data-test-id="${o}"
246
+ class="${w(y)}"
229
247
  role="region"
230
248
  aria-live="${i === "error" ? "assertive" : "polite"}"
231
- aria-labelledby="${n ? `${t}-heading` : s}"
232
- aria-label="${!n && g(v == null ? void 0 : v.label)}">
233
- ${m ? this.renderCloseButton() : s}
249
+ aria-labelledby="${e ? `${o}-heading` : l}"
250
+ aria-label="${!e && h(v == null ? void 0 : v.label)}">
251
+ ${m ? this.renderCloseButton() : l}
234
252
 
235
- <section class="${O(b)}">
236
- ${h ? s : this.renderIcon()}
237
- <article>
238
- ${n ? this.renderNotificationHeading() : s}
253
+ <div class="${w(k)}">
254
+ ${p ? l : this.renderIcon()}
255
+ <div>
256
+ ${e ? this.renderNotificationHeading() : l}
239
257
  <slot></slot>
240
- </article>
241
- </section>
258
+ </div>
259
+ </div>
242
260
 
243
- ${p != null && p.text ? this.renderFooter() : s}
261
+ ${this.renderFooter()}
244
262
  </div>`;
245
263
  }
246
264
  };
247
- a.styles = I(j);
265
+ n.styles = I(j);
248
266
  c([
249
267
  r({ type: Boolean })
250
- ], a.prototype, "isOpen", 2);
268
+ ], n.prototype, "isOpen", 2);
251
269
  c([
252
270
  r({ type: String }),
253
- N(t, E, l.variant)
254
- ], a.prototype, "variant", 2);
271
+ O(o, E, s.variant)
272
+ ], n.prototype, "variant", 2);
255
273
  c([
256
274
  r({ type: String }),
257
- N(t, T, l.position)
258
- ], a.prototype, "position", 2);
275
+ O(o, T, s.position)
276
+ ], n.prototype, "position", 2);
259
277
  c([
260
278
  r({ type: Boolean })
261
- ], a.prototype, "isDismissible", 2);
279
+ ], n.prototype, "isDismissible", 2);
262
280
  c([
263
- r({ type: Boolean })
264
- ], a.prototype, "isCompact", 2);
281
+ r({ type: Boolean, reflect: !0 })
282
+ ], n.prototype, "isCompact", 2);
265
283
  c([
266
284
  r({ type: String })
267
- ], a.prototype, "heading", 2);
285
+ ], n.prototype, "heading", 2);
268
286
  c([
269
287
  r({ type: String }),
270
- N(t, L, l.headingLevel)
271
- ], a.prototype, "headingLevel", 2);
288
+ O(o, L, s.headingLevel)
289
+ ], n.prototype, "headingLevel", 2);
272
290
  c([
273
291
  r({ type: Boolean })
274
- ], a.prototype, "hideIcon", 2);
292
+ ], n.prototype, "hideIcon", 2);
275
293
  c([
276
294
  r({ type: Object })
277
- ], a.prototype, "leadingAction", 2);
295
+ ], n.prototype, "leadingAction", 2);
278
296
  c([
279
297
  r({ type: Object })
280
- ], a.prototype, "supportingAction", 2);
298
+ ], n.prototype, "supportingAction", 2);
281
299
  c([
282
- r({ type: Boolean })
283
- ], a.prototype, "hasStackedActions", 2);
300
+ r({ type: Boolean, reflect: !0 })
301
+ ], n.prototype, "hasStackedActions", 2);
284
302
  c([
285
303
  r({ type: Object })
286
- ], a.prototype, "aria", 2);
304
+ ], n.prototype, "aria", 2);
287
305
  c([
288
- S({ slot: "icon" })
289
- ], a.prototype, "_iconSlot", 2);
290
- a = c([
291
- _("pie-notification")
292
- ], a);
306
+ _({ slot: "icon" })
307
+ ], n.prototype, "_iconSlot", 2);
308
+ n = c([
309
+ S("pie-notification")
310
+ ], n);
293
311
  export {
294
312
  D as ON_NOTIFICATION_CLOSE_EVENT,
295
313
  P as ON_NOTIFICATION_LEADING_ACTION_CLICK_EVENT,
296
314
  V as ON_NOTIFICATION_OPEN_EVENT,
297
315
  F as ON_NOTIFICATION_SUPPORTING_ACTION_CLICK_EVENT,
298
- a as PieNotification,
316
+ n as PieNotification,
299
317
  B as actionSizes,
300
318
  u as componentClass,
301
- t as componentSelector,
302
- $ as defaultActionButtonProps,
303
- l as defaultProps,
319
+ o as componentSelector,
320
+ b as defaultActionButtonProps,
321
+ s as defaultProps,
304
322
  L as headingLevels,
305
323
  T as positions,
306
324
  E as variants
package/dist/react.d.ts CHANGED
@@ -148,6 +148,8 @@ export declare const PieNotification: React_2.ForwardRefExoticComponent<React_2.
148
148
  * @event {CustomEvent} pie-notification-open - When the notification is opened.
149
149
  * @slot - Default slot
150
150
  * @slot icon - The icon slot
151
+ * @slot leadingAction - An optional slot for a custom `pie-button` to replace the prop-based leading action button.
152
+ * @slot supportingAction - An optional slot for a custom `pie-button` to replace the prop-based supporting action button.
151
153
  */
152
154
  declare class PieNotification_2 extends PieElement implements NotificationProps {
153
155
  isOpen: boolean;
@@ -169,6 +171,19 @@ declare class PieNotification_2 extends PieElement implements NotificationProps
169
171
  * It dispatches an event if notification is opened.
170
172
  */
171
173
  protected updated(_changedProperties: PropertyValues<this>): void;
174
+ /**
175
+ * Renders the supporting action - either from slot or props.
176
+ * Supporting action only renders when a leading action is also present (via prop or slot).
177
+ *
178
+ * @private
179
+ */
180
+ private renderSupportingAction;
181
+ /**
182
+ * Renders the leading action from props.
183
+ *
184
+ * @private
185
+ */
186
+ private renderLeadingAction;
172
187
  /**
173
188
  * Template for the footer area
174
189
  * Called within the main render function.
package/dist/react.js CHANGED
File without changes
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.21.25",
4
+ "version": "0.23.0",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/justeattakeaway/pie",
@@ -43,14 +43,14 @@
43
43
  "author": "Just Eat Takeaway.com - Design System Team",
44
44
  "license": "Apache-2.0",
45
45
  "devDependencies": {
46
- "@justeattakeaway/pie-components-config": "0.21.1",
46
+ "@justeattakeaway/pie-components-config": "0.21.2",
47
47
  "@justeattakeaway/pie-css": "1.1.1",
48
- "@justeattakeaway/pie-monorepo-utils": "0.9.0",
48
+ "@justeattakeaway/pie-monorepo-utils": "0.9.1",
49
49
  "@justeattakeaway/pie-wrapper-react": "0.14.4"
50
50
  },
51
51
  "dependencies": {
52
- "@justeattakeaway/pie-icon-button": "2.7.10",
53
- "@justeattakeaway/pie-icons-webc": "1.22.0",
52
+ "@justeattakeaway/pie-icon-button": "2.7.12",
53
+ "@justeattakeaway/pie-icons-webc": "1.23.0",
54
54
  "@justeattakeaway/pie-webc-core": "14.0.1"
55
55
  },
56
56
  "volta": {
package/src/index.ts CHANGED
@@ -47,6 +47,8 @@ export * from './defs';
47
47
  * @event {CustomEvent} pie-notification-open - When the notification is opened.
48
48
  * @slot - Default slot
49
49
  * @slot icon - The icon slot
50
+ * @slot leadingAction - An optional slot for a custom `pie-button` to replace the prop-based leading action button.
51
+ * @slot supportingAction - An optional slot for a custom `pie-button` to replace the prop-based supporting action button.
50
52
  */
51
53
  @safeCustomElement('pie-notification')
52
54
  export class PieNotification extends PieElement implements NotificationProps {
@@ -64,7 +66,7 @@ export class PieNotification extends PieElement implements NotificationProps {
64
66
  @property({ type: Boolean })
65
67
  public isDismissible = defaultProps.isDismissible;
66
68
 
67
- @property({ type: Boolean })
69
+ @property({ type: Boolean, reflect: true })
68
70
  public isCompact = defaultProps.isCompact;
69
71
 
70
72
  @property({ type: String })
@@ -83,7 +85,7 @@ export class PieNotification extends PieElement implements NotificationProps {
83
85
  @property({ type: Object })
84
86
  public supportingAction: NotificationProps['supportingAction'];
85
87
 
86
- @property({ type: Boolean })
88
+ @property({ type: Boolean, reflect: true })
87
89
  public hasStackedActions = defaultProps.hasStackedActions;
88
90
 
89
91
  @property({ type: Object })
@@ -104,6 +106,36 @@ export class PieNotification extends PieElement implements NotificationProps {
104
106
  }
105
107
  }
106
108
 
109
+ /**
110
+ * Renders the supporting action - either from slot or props.
111
+ * Supporting action only renders when a leading action is also present (via prop or slot).
112
+ *
113
+ * @private
114
+ */
115
+ private renderSupportingAction () {
116
+ const { supportingAction, leadingAction } = this;
117
+
118
+ if (supportingAction && leadingAction?.text) {
119
+ return this.renderActionButton(supportingAction, 'supporting');
120
+ }
121
+
122
+ return nothing;
123
+ }
124
+
125
+ /**
126
+ * Renders the leading action from props.
127
+ *
128
+ * @private
129
+ */
130
+ private renderLeadingAction () {
131
+ const { leadingAction } = this;
132
+ if (leadingAction) {
133
+ return this.renderActionButton(leadingAction, 'leading');
134
+ }
135
+
136
+ return nothing;
137
+ }
138
+
107
139
  /**
108
140
  * Template for the footer area
109
141
  * Called within the main render function.
@@ -112,20 +144,26 @@ export class PieNotification extends PieElement implements NotificationProps {
112
144
  */
113
145
  private renderFooter () {
114
146
  const {
115
- leadingAction, supportingAction, isCompact, hasStackedActions,
147
+ isCompact, hasStackedActions,
116
148
  } = this;
149
+
150
+ // The footer is always rendered so that action slots exist in the DOM.
151
+ // When no buttons are present (prop or slotted), the footer collapses
152
+ // to zero height because spacing is applied via margin on the buttons themselves.
117
153
  const classes = {
118
154
  [`${componentClass}-footer`]: true,
119
155
  'is-compact': isCompact,
120
156
  [`${componentClass}-footer--stacked`]: hasStackedActions && !isCompact,
121
157
  };
122
158
  return html`
123
- <footer
159
+ <div
124
160
  class="${classMap(classes)}"
125
161
  data-test-id="${componentSelector}-footer">
126
- ${supportingAction ? this.renderActionButton(supportingAction, 'supporting') : nothing}
127
- ${leadingAction ? this.renderActionButton(leadingAction, 'leading') : nothing}
128
- </footer>
162
+ ${this.renderSupportingAction()}
163
+ <slot name="supportingAction"></slot>
164
+ ${this.renderLeadingAction()}
165
+ <slot name="leadingAction"></slot>
166
+ </div>
129
167
  `;
130
168
  }
131
169
 
@@ -277,7 +315,6 @@ export class PieNotification extends PieElement implements NotificationProps {
277
315
  isDismissible,
278
316
  isCompact,
279
317
  hideIcon,
280
- leadingAction,
281
318
  isOpen,
282
319
  aria,
283
320
  } = this;
@@ -310,15 +347,15 @@ export class PieNotification extends PieElement implements NotificationProps {
310
347
  aria-label="${!heading && ifDefined(aria?.label)}">
311
348
  ${showCloseButton ? this.renderCloseButton() : nothing}
312
349
 
313
- <section class="${classMap(contentSectionClasses)}">
350
+ <div class="${classMap(contentSectionClasses)}">
314
351
  ${!hideIcon ? this.renderIcon() : nothing}
315
- <article>
352
+ <div>
316
353
  ${heading ? this.renderNotificationHeading() : nothing}
317
354
  <slot></slot>
318
- </article>
319
- </section>
355
+ </div>
356
+ </div>
320
357
 
321
- ${leadingAction?.text ? this.renderFooter() : nothing}
358
+ ${this.renderFooter()}
322
359
  </div>`;
323
360
  }
324
361
  }
@@ -28,7 +28,6 @@
28
28
  position: relative;
29
29
  display: flex;
30
30
  flex-direction: var(--notification-direction);
31
- gap: var(--dt-spacing-d);
32
31
  font-family: var(--notification-font-family);
33
32
  font-size: var(--notification-font-size);
34
33
  line-height: var(--notification-line-height);
@@ -114,6 +113,11 @@
114
113
  justify-content: flex-end;
115
114
  gap: var(--dt-spacing-d);
116
115
 
116
+ pie-button,
117
+ ::slotted(pie-button) {
118
+ margin-block-start: var(--dt-spacing-d);
119
+ }
120
+
117
121
  &.is-compact {
118
122
  align-self: center;
119
123
  margin-inline-start: auto;
@@ -122,6 +126,11 @@
122
126
  &.c-notification-footer--stacked {
123
127
  @include media('<md') {
124
128
  flex-direction: column-reverse;
129
+ gap: 0;
130
+
131
+ ::slotted(pie-button) {
132
+ --btn-inline-size: 100%;
133
+ }
125
134
  }
126
135
 
127
136
  @include media('>=md') {
@@ -130,6 +139,19 @@
130
139
  }
131
140
  }
132
141
  }
142
+
143
+ // Enforce only pie-button in the action slots
144
+ ::slotted(:not(pie-button)) {
145
+ display: none;
146
+ }
147
+ }
148
+ }
149
+
150
+ :host([isCompact]) {
151
+ .c-notification-footer {
152
+ pie-button, ::slotted(pie-button) {
153
+ margin-block-start: 0;
154
+ }
133
155
  }
134
156
  }
135
157