@justeattakeaway/pie-notification 0.21.25 → 0.22.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": "{\n text: '',\n ariaLabel: '',\n size: 'small-productive',\n}"
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": "{\n variant: 'neutral',\n position: 'inline-content',\n isDismissible: false,\n isCompact: false,\n headingLevel: 'h2',\n hideIcon: false,\n isOpen: true,\n hasStackedActions: false,\n leadingAction: defaultActionButtonProps,\n supportingAction: defaultActionButtonProps,\n}"
102
102
  }
103
103
  ],
104
104
  "exports": [
@@ -216,6 +216,14 @@
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": [
@@ -298,11 +306,23 @@
298
306
  "text": "Array<HTMLElement>"
299
307
  }
300
308
  },
309
+ {
310
+ "kind": "method",
311
+ "name": "renderSupportingAction",
312
+ "privacy": "private",
313
+ "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)."
314
+ },
315
+ {
316
+ "kind": "method",
317
+ "name": "renderLeadingAction",
318
+ "privacy": "private",
319
+ "description": "Renders the leading action from props."
320
+ },
301
321
  {
302
322
  "kind": "method",
303
323
  "name": "renderFooter",
304
324
  "privacy": "private",
305
- "description": "Template for the footer area\r\nCalled within the main render function."
325
+ "description": "Template for the footer area\nCalled within the main render function."
306
326
  },
307
327
  {
308
328
  "kind": "method",
@@ -313,7 +333,7 @@
313
333
  "text": "TemplateResult"
314
334
  }
315
335
  },
316
- "description": "Template for the header area\r\nCalled within the main render function."
336
+ "description": "Template for the header area\nCalled within the main render function."
317
337
  },
318
338
  {
319
339
  "kind": "method",
@@ -330,7 +350,7 @@
330
350
  "text": "TemplateResult | typeof nothing"
331
351
  }
332
352
  },
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."
353
+ "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
354
  },
335
355
  {
336
356
  "kind": "method",
@@ -341,13 +361,13 @@
341
361
  "text": "TemplateResult"
342
362
  }
343
363
  },
344
- "description": "Template for the close button element. Called within the\r\nmain render function."
364
+ "description": "Template for the close button element. Called within the\nmain render function."
345
365
  },
346
366
  {
347
367
  "kind": "method",
348
368
  "name": "handleCloseButton",
349
369
  "privacy": "private",
350
- "description": "It handles the action when user clicks in the close button.\r\nAlso triggers an event when is executed."
370
+ "description": "It handles the action when user clicks in the close button.\nAlso triggers an event when is executed."
351
371
  },
352
372
  {
353
373
  "kind": "method",
@@ -361,7 +381,7 @@
361
381
  }
362
382
  }
363
383
  ],
364
- "description": "It handles the action button action.\r\nAlso triggers an event according to its `actionType`."
384
+ "description": "It handles the action button action.\nAlso triggers an event according to its `actionType`."
365
385
  },
366
386
  {
367
387
  "kind": "method",
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.22.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 = (t, i, e, f) => {
38
+ for (var a = f > 1 ? void 0 : f ? H(i, e) : i, p = t.length - 1, g; p >= 0; p--)
39
+ (g = t[p]) && (a = (f ? g(i, e, a) : g(a)) || a);
40
+ return f && a && G(i, 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
- updated(i) {
51
- i.has("isOpen") && this.isOpen && x(this, V, { targetNotification: this });
50
+ updated(t) {
51
+ t.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: t, leadingAction: i } = this;
61
+ return t && (i != null && i.text) ? this.renderActionButton(t, "supporting") : l;
62
+ }
63
+ /**
64
+ * Renders the leading action from props.
65
+ *
66
+ * @private
67
+ */
68
+ renderLeadingAction() {
69
+ const { leadingAction: t } = this;
70
+ return t ? this.renderActionButton(t, "leading") : l;
52
71
  }
53
72
  /**
54
73
  * Template for the footer area
@@ -58,21 +77,21 @@ 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: t,
81
+ hasStackedActions: i
65
82
  } = this, e = {
66
83
  [`${u}-footer`]: !0,
67
- "is-compact": n,
68
- [`${u}-footer--stacked`]: d && !n
84
+ "is-compact": t,
85
+ [`${u}-footer--stacked`]: i && !t
69
86
  };
70
- return f`
87
+ return d`
71
88
  <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}
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>
76
95
  </footer>
77
96
  `;
78
97
  }
@@ -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: t, headingLevel: i } = this, e = z(i);
106
+ return d`<${e}
107
+ id="${o}-heading"
89
108
  class="${u}-heading"
90
- data-test-id="${t}-heading">
91
- ${i}
92
- </${n}>`;
109
+ data-test-id="${o}-heading">
110
+ ${t}
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
@@ -127,15 +146,15 @@ let a = class extends C {
127
146
  * @private
128
147
  */
129
148
  renderCloseButton() {
130
- var i;
131
- return f`
149
+ var t;
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((t = this.aria) == null ? void 0 : t.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.
@@ -156,8 +175,8 @@ let a = class extends C {
156
175
  *
157
176
  * @private
158
177
  */
159
- handleActionClick(i) {
160
- x(this, i === "leading" ? P : F, { targetNotification: this });
178
+ handleActionClick(t) {
179
+ A(this, t === "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(t, i) {
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
180
- } = 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`
192
+ text: e,
193
+ ariaLabel: f,
194
+ size: a = b.size,
195
+ href: p,
196
+ target: g,
197
+ rel: v,
198
+ download: m
199
+ } = t;
200
+ if (!e)
201
+ return l;
202
+ const y = i === "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(i)}"
209
+ data-test-id="${o}-${i}-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
- variant: i,
205
- position: o,
206
- heading: n,
207
- isDismissible: d,
208
- isCompact: e,
209
- hideIcon: h,
210
- leadingAction: p,
211
- isOpen: k,
223
+ variant: t,
224
+ position: i,
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,
236
+ [`${u}--${t}`]: !0,
218
237
  [`${u}--${i}`]: !0,
219
- [`${u}--${o}`]: !0,
220
- "is-compact": e
221
- }, b = {
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
- 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}
248
+ aria-live="${t === "error" ? "assertive" : "polite"}"
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()}
253
+ <section class="${w(k)}">
254
+ ${p ? l : this.renderIcon()}
237
255
  <article>
238
- ${n ? this.renderNotificationHeading() : s}
256
+ ${e ? this.renderNotificationHeading() : l}
239
257
  <slot></slot>
240
258
  </article>
241
259
  </section>
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/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.22.0",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/justeattakeaway/pie",
@@ -45,12 +45,12 @@
45
45
  "devDependencies": {
46
46
  "@justeattakeaway/pie-components-config": "0.21.1",
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.11",
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,8 +144,12 @@ 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,
@@ -123,8 +159,10 @@ export class PieNotification extends PieElement implements NotificationProps {
123
159
  <footer
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}
162
+ ${this.renderSupportingAction()}
163
+ <slot name="supportingAction"></slot>
164
+ ${this.renderLeadingAction()}
165
+ <slot name="leadingAction"></slot>
128
166
  </footer>
129
167
  `;
130
168
  }
@@ -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;
@@ -318,7 +355,7 @@ export class PieNotification extends PieElement implements NotificationProps {
318
355
  </article>
319
356
  </section>
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