@justeattakeaway/pie-toast-provider 0.0.0 → 0.2.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.
@@ -11,8 +11,59 @@
11
11
  {
12
12
  "kind": "javascript-module",
13
13
  "path": "src/defs.js",
14
- "declarations": [],
15
- "exports": []
14
+ "declarations": [
15
+ {
16
+ "kind": "variable",
17
+ "name": "PRIORITY_ORDER",
18
+ "type": {
19
+ "text": "{\n 'error-actionable': 1,\n error: 2,\n 'warning-actionable': 3,\n 'success-actionable': 4,\n 'info-actionable': 5,\n 'neutral-actionable': 6,\n warning: 7,\n success: 8,\n info: 9,\n neutral: 10,\n}"
20
+ },
21
+ "default": "{\n 'error-actionable': 1,\n error: 2,\n 'warning-actionable': 3,\n 'success-actionable': 4,\n 'info-actionable': 5,\n 'neutral-actionable': 6,\n warning: 7,\n success: 8,\n info: 9,\n neutral: 10,\n}"
22
+ },
23
+ {
24
+ "kind": "variable",
25
+ "name": "defaultProps",
26
+ "type": {
27
+ "text": "DefaultProps"
28
+ },
29
+ "default": "{\n options: {},\n}"
30
+ },
31
+ {
32
+ "kind": "variable",
33
+ "name": "ON_TOAST_PROVIDER_QUEUE_UPDATE_EVENT",
34
+ "type": {
35
+ "text": "string"
36
+ },
37
+ "default": "'pie-toast-provider-queue-update'",
38
+ "description": "Event name for when the toast provider queue is updated."
39
+ }
40
+ ],
41
+ "exports": [
42
+ {
43
+ "kind": "js",
44
+ "name": "PRIORITY_ORDER",
45
+ "declaration": {
46
+ "name": "PRIORITY_ORDER",
47
+ "module": "src/defs.js"
48
+ }
49
+ },
50
+ {
51
+ "kind": "js",
52
+ "name": "defaultProps",
53
+ "declaration": {
54
+ "name": "defaultProps",
55
+ "module": "src/defs.js"
56
+ }
57
+ },
58
+ {
59
+ "kind": "js",
60
+ "name": "ON_TOAST_PROVIDER_QUEUE_UPDATE_EVENT",
61
+ "declaration": {
62
+ "name": "ON_TOAST_PROVIDER_QUEUE_UPDATE_EVENT",
63
+ "module": "src/defs.js"
64
+ }
65
+ }
66
+ ]
16
67
  },
17
68
  {
18
69
  "kind": "javascript-module",
@@ -22,7 +73,119 @@
22
73
  "kind": "class",
23
74
  "description": "",
24
75
  "name": "PieToastProvider",
25
- "members": [],
76
+ "members": [
77
+ {
78
+ "kind": "field",
79
+ "name": "_toasts",
80
+ "type": {
81
+ "text": "ExtendedToastProps[]"
82
+ },
83
+ "privacy": "private",
84
+ "default": "[]"
85
+ },
86
+ {
87
+ "kind": "field",
88
+ "name": "_currentToast",
89
+ "type": {
90
+ "text": "ExtendedToastProps | null"
91
+ },
92
+ "privacy": "private",
93
+ "default": "null"
94
+ },
95
+ {
96
+ "kind": "field",
97
+ "name": "options",
98
+ "privacy": "public",
99
+ "attribute": "options"
100
+ },
101
+ {
102
+ "kind": "method",
103
+ "name": "_dispatchQueueUpdateEvent",
104
+ "privacy": "private",
105
+ "return": {
106
+ "type": {
107
+ "text": "void"
108
+ }
109
+ }
110
+ },
111
+ {
112
+ "kind": "method",
113
+ "name": "getPriority",
114
+ "privacy": "private",
115
+ "return": {
116
+ "type": {
117
+ "text": "number"
118
+ }
119
+ },
120
+ "parameters": [
121
+ {
122
+ "name": "type",
123
+ "default": "toastDefaultProps.variant",
124
+ "type": {
125
+ "text": "string"
126
+ },
127
+ "description": "The variant type of the toast."
128
+ },
129
+ {
130
+ "name": "hasAction",
131
+ "default": "false",
132
+ "description": "Whether the toast has an action.",
133
+ "type": {
134
+ "text": "boolean"
135
+ }
136
+ }
137
+ ],
138
+ "description": "Get the priority for a toast."
139
+ },
140
+ {
141
+ "kind": "method",
142
+ "name": "_dismissToast",
143
+ "privacy": "private",
144
+ "description": "Handles the dismissal of the current toast and displays the next one in the queue (if any)."
145
+ },
146
+ {
147
+ "kind": "method",
148
+ "name": "_showNextToast",
149
+ "privacy": "private",
150
+ "description": "Displays the next toast in the queue, if available."
151
+ },
152
+ {
153
+ "kind": "method",
154
+ "name": "createToast",
155
+ "privacy": "public",
156
+ "parameters": [
157
+ {
158
+ "name": "toast",
159
+ "type": {
160
+ "text": "ToastProps"
161
+ },
162
+ "description": "The toast props to display."
163
+ }
164
+ ],
165
+ "description": "Adds a new toast to the queue and triggers its display if no toast is currently active."
166
+ },
167
+ {
168
+ "kind": "method",
169
+ "name": "clearToasts",
170
+ "privacy": "public",
171
+ "description": "\nClears all toasts from the queue and dismisses the currently visible toast."
172
+ }
173
+ ],
174
+ "events": [
175
+ {
176
+ "type": {
177
+ "text": "CustomEvent"
178
+ },
179
+ "description": "when a toast is added or removed from the queue.",
180
+ "name": "pie-toast-provider-queue-update"
181
+ }
182
+ ],
183
+ "attributes": [
184
+ {
185
+ "name": "options",
186
+ "fieldName": "options"
187
+ }
188
+ ],
26
189
  "mixins": [
27
190
  {
28
191
  "name": "RtlMixin",
@@ -46,6 +209,14 @@
46
209
  "package": "./defs"
47
210
  }
48
211
  },
212
+ {
213
+ "kind": "js",
214
+ "name": "toaster",
215
+ "declaration": {
216
+ "name": "toaster",
217
+ "module": "./toaster"
218
+ }
219
+ },
49
220
  {
50
221
  "kind": "js",
51
222
  "name": "PieToastProvider",
@@ -55,6 +226,31 @@
55
226
  }
56
227
  }
57
228
  ]
229
+ },
230
+ {
231
+ "kind": "javascript-module",
232
+ "path": "src/toaster.js",
233
+ "declarations": [
234
+ {
235
+ "kind": "variable",
236
+ "name": "toaster",
237
+ "type": {
238
+ "text": "object"
239
+ },
240
+ "default": "{\n _getToastProvider (): PieToastProvider | null {\n const toastProviders = document.querySelectorAll('pie-toast-provider');\n\n if (toastProviders.length === 0) {\n console.error('The pie-toast component requires a pie-toast-provider element present in the DOM.');\n return null;\n }\n\n if (toastProviders.length > 1) {\n console.error('Multiple pie-toast-provider are found in the DOM. Only one provider is supported currently and should be registered at the root of the app.');\n return null;\n }\n\n return toastProviders[0];\n },\n create (toast: ExtendedToastProps) {\n const toastProvider = this._getToastProvider();\n if (!toastProvider) return;\n\n toastProvider.createToast(toast);\n },\n clearAll () {\n const toastProvider = this._getToastProvider();\n if (!toastProvider) return;\n\n toastProvider.clearToasts();\n },\n}",
241
+ "description": "Singleton toaster interface for global access."
242
+ }
243
+ ],
244
+ "exports": [
245
+ {
246
+ "kind": "js",
247
+ "name": "toaster",
248
+ "declaration": {
249
+ "name": "toaster",
250
+ "module": "src/toaster.js"
251
+ }
252
+ }
253
+ ]
58
254
  }
59
255
  ]
60
256
  }
package/dist/index.d.ts CHANGED
@@ -1,20 +1,108 @@
1
+ import { ComponentDefaultProps } from '@justeattakeaway/pie-webc-core';
1
2
  import type { CSSResult } from 'lit';
2
3
  import type { GenericConstructor } from '@justeattakeaway/pie-webc-core';
3
4
  import type { LitElement } from 'lit';
5
+ import type { PropertyValues } from 'lit';
4
6
  import type { RTLInterface } from '@justeattakeaway/pie-webc-core';
5
7
  import type { TemplateResult } from 'lit-html';
8
+ import { ToastProps } from '@justeattakeaway/pie-toast';
9
+
10
+ export declare type DefaultProps = ComponentDefaultProps<ToastProviderProps>;
11
+
12
+ export declare const defaultProps: DefaultProps;
13
+
14
+ export declare interface ExtendedToastProps extends ToastProps {
15
+ /**
16
+ * Triggered when the user interacts with the close icon or when the toast auto dismiss.
17
+ */
18
+ onPieToastClose?: () => void;
19
+ /**
20
+ * Triggered when the toast is opened.
21
+ */
22
+ onPieToastOpen?: () => void;
23
+ /**
24
+ * Triggered when the user interacts with the leading action.
25
+ */
26
+ onPieToastLeadingActionClick?: (event: Event) => void;
27
+ }
28
+
29
+ /**
30
+ * Event name for when the toast provider queue is updated.
31
+ *
32
+ * @constant
33
+ */
34
+ export declare const ON_TOAST_PROVIDER_QUEUE_UPDATE_EVENT = "pie-toast-provider-queue-update";
6
35
 
7
36
  /**
8
37
  * @tagname pie-toast-provider
38
+ * @event {CustomEvent} pie-toast-provider-queue-update - when a toast is added or removed from the queue.
9
39
  */
10
40
  export declare class PieToastProvider extends PieToastProvider_base implements ToastProviderProps {
41
+ private _toasts;
42
+ private _currentToast;
43
+ options: Partial<ExtendedToastProps>;
44
+ updated(changedProperties: PropertyValues<this>): void;
45
+ private _dispatchQueueUpdateEvent;
46
+ /**
47
+ * Get the priority for a toast.
48
+ * @param {string} type - The variant type of the toast.
49
+ * @param {boolean} hasAction - Whether the toast has an action.
50
+ * @returns {number} - The priority based on the variant and action.
51
+ */
52
+ private getPriority;
53
+ /**
54
+ * Handles the dismissal of the current toast and displays the next one in the queue (if any).
55
+ */
56
+ private _dismissToast;
57
+ /**
58
+ * Displays the next toast in the queue, if available.
59
+ */
60
+ private _showNextToast;
61
+ /**
62
+ * Adds a new toast to the queue and triggers its display if no toast is currently active.
63
+ * @param {ToastProps} toast - The toast props to display.
64
+ */
65
+ createToast(toast: ExtendedToastProps): void;
66
+ /**
67
+ *
68
+ * Clears all toasts from the queue and dismisses the currently visible toast.
69
+ */
70
+ clearToasts(): void;
11
71
  render(): TemplateResult<1>;
12
72
  static styles: CSSResult;
13
73
  }
14
74
 
15
75
  declare const PieToastProvider_base: GenericConstructor<RTLInterface> & typeof LitElement;
16
76
 
77
+ export declare type Priority = keyof typeof PRIORITY_ORDER;
78
+
79
+ export declare const PRIORITY_ORDER: {
80
+ readonly 'error-actionable': 1;
81
+ readonly error: 2;
82
+ readonly 'warning-actionable': 3;
83
+ readonly 'success-actionable': 4;
84
+ readonly 'info-actionable': 5;
85
+ readonly 'neutral-actionable': 6;
86
+ readonly warning: 7;
87
+ readonly success: 8;
88
+ readonly info: 9;
89
+ readonly neutral: 10;
90
+ };
91
+
92
+ /**
93
+ * Singleton toaster interface for global access.
94
+ */
95
+ export declare const toaster: {
96
+ _getToastProvider(): PieToastProvider | null;
97
+ create(toast: ExtendedToastProps): void;
98
+ clearAll(): void;
99
+ };
100
+
17
101
  export declare interface ToastProviderProps {
102
+ /**
103
+ * Default options for all toasts; accepts all toast props.
104
+ */
105
+ options?: Partial<ExtendedToastProps>;
18
106
  }
19
107
 
20
108
  export { }
package/dist/index.js CHANGED
@@ -1,13 +1,140 @@
1
- import { LitElement as o, html as s, unsafeCSS as n } from "lit";
2
- import { RtlMixin as r, defineCustomElement as i } from "@justeattakeaway/pie-webc-core";
3
- const l = "*,*:after,*:before{box-sizing:inherit}", m = "pie-toast-provider", e = class e extends r(o) {
1
+ import { LitElement as _, html as u, nothing as v, unsafeCSS as m } from "lit";
2
+ import { state as f, property as T } from "lit/decorators.js";
3
+ import { ifDefined as g } from "lit/directives/if-defined.js";
4
+ import { RtlMixin as y, dispatchCustomEvent as P, defineCustomElement as b } from "@justeattakeaway/pie-webc-core";
5
+ import { defaultProps as h } from "@justeattakeaway/pie-toast";
6
+ const $ = "*,*:after,*:before{box-sizing:inherit}.c-toast-provider{--toast-provider-offset: var(--dt-spacing-d);position:absolute;inset-inline-start:var(--toast-provider-offset);inset-block-end:var(--toast-provider-offset)}@media (min-width: 769px){.c-toast-provider{--toast-offset: var(--dt-spacing-e)}}", A = {
7
+ "error-actionable": 1,
8
+ error: 2,
9
+ "warning-actionable": 3,
10
+ "success-actionable": 4,
11
+ "info-actionable": 5,
12
+ "neutral-actionable": 6,
13
+ warning: 7,
14
+ success: 8,
15
+ info: 9,
16
+ neutral: 10
17
+ }, E = {
18
+ options: {}
19
+ }, x = "pie-toast-provider-queue-update", N = {
20
+ _getToastProvider() {
21
+ const s = document.querySelectorAll("pie-toast-provider");
22
+ return s.length === 0 ? (console.error("The pie-toast component requires a pie-toast-provider element present in the DOM."), null) : s.length > 1 ? (console.error("Multiple pie-toast-provider are found in the DOM. Only one provider is supported currently and should be registered at the root of the app."), null) : s[0];
23
+ },
24
+ create(s) {
25
+ const t = this._getToastProvider();
26
+ t && t.createToast(s);
27
+ },
28
+ clearAll() {
29
+ const s = this._getToastProvider();
30
+ s && s.clearToasts();
31
+ }
32
+ };
33
+ var O = Object.defineProperty, p = (s, t, e, r) => {
34
+ for (var o = void 0, a = s.length - 1, n; a >= 0; a--)
35
+ (n = s[a]) && (o = n(t, e, o) || o);
36
+ return o && O(t, e, o), o;
37
+ };
38
+ const D = "pie-toast-provider", l = class l extends y(_) {
39
+ constructor() {
40
+ super(...arguments), this._toasts = [], this._currentToast = null, this.options = E.options;
41
+ }
42
+ updated(t) {
43
+ t.has("_toasts") && this._dispatchQueueUpdateEvent();
44
+ }
45
+ _dispatchQueueUpdateEvent() {
46
+ P(
47
+ this,
48
+ x,
49
+ this._toasts
50
+ );
51
+ }
52
+ /**
53
+ * Get the priority for a toast.
54
+ * @param {string} type - The variant type of the toast.
55
+ * @param {boolean} hasAction - Whether the toast has an action.
56
+ * @returns {number} - The priority based on the variant and action.
57
+ */
58
+ getPriority(t = h.variant, e = !1) {
59
+ const r = `${t}${e ? "-actionable" : ""}`;
60
+ return A[r];
61
+ }
62
+ /**
63
+ * Handles the dismissal of the current toast and displays the next one in the queue (if any).
64
+ */
65
+ _dismissToast() {
66
+ var t, e;
67
+ (e = (t = this._currentToast) == null ? void 0 : t.onPieToastClose) == null || e.call(t), this._currentToast = null, requestAnimationFrame(() => {
68
+ this._showNextToast();
69
+ });
70
+ }
71
+ /**
72
+ * Displays the next toast in the queue, if available.
73
+ */
74
+ _showNextToast() {
75
+ if (this._toasts.length > 0) {
76
+ const [t, ...e] = this._toasts;
77
+ this._currentToast = t, this._toasts = e;
78
+ } else
79
+ this._currentToast = null;
80
+ }
81
+ /**
82
+ * Adds a new toast to the queue and triggers its display if no toast is currently active.
83
+ * @param {ToastProps} toast - The toast props to display.
84
+ */
85
+ createToast(t) {
86
+ const e = { ...h, ...this.options, ...t };
87
+ this._toasts = [...this._toasts, e].sort((r, o) => {
88
+ var c, d;
89
+ const a = this.getPriority(o.variant, !!((c = o.leadingAction) != null && c.text));
90
+ return this.getPriority(r.variant, !!((d = r.leadingAction) != null && d.text)) - a;
91
+ }), this._currentToast || this._showNextToast();
92
+ }
93
+ /**
94
+ *
95
+ * Clears all toasts from the queue and dismisses the currently visible toast.
96
+ */
97
+ clearToasts() {
98
+ this._toasts = [], this._currentToast = null;
99
+ }
4
100
  render() {
5
- return s`<h1 data-test-id="pie-toast-provider">Hello world!</h1>`;
101
+ const { _currentToast: t, _dismissToast: e } = this;
102
+ return u`
103
+ <div class="c-toast-provider" data-test-id="pie-toast-provider">
104
+ ${t && u`
105
+ <pie-toast
106
+ message="${t.message}"
107
+ variant="${g(t.variant)}"
108
+ ?isStrong="${t.isStrong}"
109
+ ?isDismissible="${t.isDismissible}"
110
+ ?isMultiline="${t.isMultiline}"
111
+ .leadingAction="${t.leadingAction}"
112
+ .duration="${typeof t.duration > "u" ? v : t.duration}"
113
+ @pie-toast-close="${e}"
114
+ @pie-toast-open="${t.onPieToastOpen}"
115
+ @pie-toast-leading-action-click="${t.onPieToastLeadingActionClick}">
116
+ </pie-toast>
117
+ `}
118
+ </div>
119
+ `;
6
120
  }
7
121
  };
8
- e.styles = n(l);
9
- let t = e;
10
- i(m, t);
122
+ l.styles = m($);
123
+ let i = l;
124
+ p([
125
+ f()
126
+ ], i.prototype, "_toasts");
127
+ p([
128
+ f()
129
+ ], i.prototype, "_currentToast");
130
+ p([
131
+ T({ type: Object })
132
+ ], i.prototype, "options");
133
+ b(D, i);
11
134
  export {
12
- t as PieToastProvider
135
+ x as ON_TOAST_PROVIDER_QUEUE_UPDATE_EVENT,
136
+ A as PRIORITY_ORDER,
137
+ i as PieToastProvider,
138
+ E as defaultProps,
139
+ N as toaster
13
140
  };
package/dist/react.d.ts CHANGED
@@ -1,25 +1,108 @@
1
+ import { ComponentDefaultProps } from '@justeattakeaway/pie-webc-core';
1
2
  import type { CSSResult } from 'lit';
2
3
  import type { GenericConstructor } from '@justeattakeaway/pie-webc-core';
3
4
  import type { LitElement } from 'lit';
5
+ import type { PropertyValues } from 'lit';
4
6
  import * as React_2 from 'react';
5
7
  import type { RTLInterface } from '@justeattakeaway/pie-webc-core';
6
8
  import type { TemplateResult } from 'lit-html';
9
+ import { ToastProps } from '@justeattakeaway/pie-toast';
7
10
 
8
- export declare const PieToastProvider: React_2.ForwardRefExoticComponent<ToastProviderProps & React_2.RefAttributes<PieToastProvider_2> & ReactBaseType>;
11
+ export declare type DefaultProps = ComponentDefaultProps<ToastProviderProps>;
12
+
13
+ export declare const defaultProps: DefaultProps;
14
+
15
+ export declare interface ExtendedToastProps extends ToastProps {
16
+ /**
17
+ * Triggered when the user interacts with the close icon or when the toast auto dismiss.
18
+ */
19
+ onPieToastClose?: () => void;
20
+ /**
21
+ * Triggered when the toast is opened.
22
+ */
23
+ onPieToastOpen?: () => void;
24
+ /**
25
+ * Triggered when the user interacts with the leading action.
26
+ */
27
+ onPieToastLeadingActionClick?: (event: Event) => void;
28
+ }
29
+
30
+ /**
31
+ * Event name for when the toast provider queue is updated.
32
+ *
33
+ * @constant
34
+ */
35
+ export declare const ON_TOAST_PROVIDER_QUEUE_UPDATE_EVENT = "pie-toast-provider-queue-update";
36
+
37
+ export declare const PieToastProvider: React_2.ForwardRefExoticComponent<ToastProviderProps & React_2.RefAttributes<PieToastProvider_2> & PieToastProviderEvents & ReactBaseType>;
9
38
 
10
39
  /**
11
40
  * @tagname pie-toast-provider
41
+ * @event {CustomEvent} pie-toast-provider-queue-update - when a toast is added or removed from the queue.
12
42
  */
13
43
  declare class PieToastProvider_2 extends PieToastProvider_base implements ToastProviderProps {
44
+ private _toasts;
45
+ private _currentToast;
46
+ options: Partial<ExtendedToastProps>;
47
+ updated(changedProperties: PropertyValues<this>): void;
48
+ private _dispatchQueueUpdateEvent;
49
+ /**
50
+ * Get the priority for a toast.
51
+ * @param {string} type - The variant type of the toast.
52
+ * @param {boolean} hasAction - Whether the toast has an action.
53
+ * @returns {number} - The priority based on the variant and action.
54
+ */
55
+ private getPriority;
56
+ /**
57
+ * Handles the dismissal of the current toast and displays the next one in the queue (if any).
58
+ */
59
+ private _dismissToast;
60
+ /**
61
+ * Displays the next toast in the queue, if available.
62
+ */
63
+ private _showNextToast;
64
+ /**
65
+ * Adds a new toast to the queue and triggers its display if no toast is currently active.
66
+ * @param {ToastProps} toast - The toast props to display.
67
+ */
68
+ createToast(toast: ExtendedToastProps): void;
69
+ /**
70
+ *
71
+ * Clears all toasts from the queue and dismisses the currently visible toast.
72
+ */
73
+ clearToasts(): void;
14
74
  render(): TemplateResult<1>;
15
75
  static styles: CSSResult;
16
76
  }
17
77
 
18
78
  declare const PieToastProvider_base: GenericConstructor<RTLInterface> & typeof LitElement;
19
79
 
80
+ declare type PieToastProviderEvents = {
81
+ onPieToastProviderQueueUpdate?: (event: CustomEvent) => void;
82
+ };
83
+
84
+ export declare type Priority = keyof typeof PRIORITY_ORDER;
85
+
86
+ export declare const PRIORITY_ORDER: {
87
+ readonly 'error-actionable': 1;
88
+ readonly error: 2;
89
+ readonly 'warning-actionable': 3;
90
+ readonly 'success-actionable': 4;
91
+ readonly 'info-actionable': 5;
92
+ readonly 'neutral-actionable': 6;
93
+ readonly warning: 7;
94
+ readonly success: 8;
95
+ readonly info: 9;
96
+ readonly neutral: 10;
97
+ };
98
+
20
99
  declare type ReactBaseType = React_2.HTMLAttributes<HTMLElement>;
21
100
 
22
101
  export declare interface ToastProviderProps {
102
+ /**
103
+ * Default options for all toasts; accepts all toast props.
104
+ */
105
+ options?: Partial<ExtendedToastProps>;
23
106
  }
24
107
 
25
108
  export { }
package/dist/react.js CHANGED
@@ -1,13 +1,20 @@
1
1
  import * as e from "react";
2
2
  import { createComponent as o } from "@lit/react";
3
3
  import { PieToastProvider as r } from "./index.js";
4
+ import { ON_TOAST_PROVIDER_QUEUE_UPDATE_EVENT as d, PRIORITY_ORDER as m, defaultProps as T } from "./index.js";
4
5
  const t = o({
5
6
  displayName: "PieToastProvider",
6
7
  elementClass: r,
7
8
  react: e,
8
9
  tagName: "pie-toast-provider",
9
- events: {}
10
+ events: {
11
+ onPieToastProviderQueueUpdate: "pie-toast-provider-queue-update"
12
+ // when a toast is added or removed from the queue.
13
+ }
10
14
  }), s = t;
11
15
  export {
12
- s as PieToastProvider
16
+ d as ON_TOAST_PROVIDER_QUEUE_UPDATE_EVENT,
17
+ m as PRIORITY_ORDER,
18
+ s as PieToastProvider,
19
+ T as defaultProps
13
20
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@justeattakeaway/pie-toast-provider",
3
3
  "description": "PIE Design System Toast Provider built using Web Components",
4
- "version": "0.0.0",
4
+ "version": "0.2.0",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.js",
@@ -13,7 +13,7 @@
13
13
  "**/*.d.ts"
14
14
  ],
15
15
  "pieMetadata": {
16
- "componentStatus": "alpha"
16
+ "componentStatus": "beta"
17
17
  },
18
18
  "scripts": {
19
19
  "build": "run -T vite build",
@@ -41,6 +41,7 @@
41
41
  "cem-plugin-module-file-extensions": "0.0.5"
42
42
  },
43
43
  "dependencies": {
44
+ "@justeattakeaway/pie-toast": "0.7.0",
44
45
  "@justeattakeaway/pie-webc-core": "0.24.2"
45
46
  },
46
47
  "volta": {
package/src/defs.ts CHANGED
@@ -1,3 +1,56 @@
1
- // TODO - please remove the eslint disable comment below when you add props to this interface
2
- // eslint-disable-next-line @typescript-eslint/no-empty-interface
3
- export interface ToastProviderProps {}
1
+ import { type ToastProps } from '@justeattakeaway/pie-toast';
2
+
3
+ import { type ComponentDefaultProps } from '@justeattakeaway/pie-webc-core';
4
+
5
+ export const PRIORITY_ORDER = {
6
+ 'error-actionable': 1,
7
+ error: 2,
8
+ 'warning-actionable': 3,
9
+ 'success-actionable': 4,
10
+ 'info-actionable': 5,
11
+ 'neutral-actionable': 6,
12
+ warning: 7,
13
+ success: 8,
14
+ info: 9,
15
+ neutral: 10,
16
+ } as const;
17
+
18
+ export type Priority = keyof typeof PRIORITY_ORDER;
19
+
20
+ export interface ExtendedToastProps extends ToastProps {
21
+ /**
22
+ * Triggered when the user interacts with the close icon or when the toast auto dismiss.
23
+ */
24
+ onPieToastClose?: () => void;
25
+
26
+ /**
27
+ * Triggered when the toast is opened.
28
+ */
29
+ onPieToastOpen?: () => void;
30
+
31
+ /**
32
+ * Triggered when the user interacts with the leading action.
33
+ */
34
+ onPieToastLeadingActionClick?: (event: Event) => void;
35
+ }
36
+
37
+ export interface ToastProviderProps {
38
+ /**
39
+ * Default options for all toasts; accepts all toast props.
40
+ */
41
+ options?: Partial<ExtendedToastProps>;
42
+ }
43
+
44
+ export type DefaultProps = ComponentDefaultProps<ToastProviderProps>;
45
+
46
+ export const defaultProps: DefaultProps = {
47
+ options: {},
48
+ };
49
+
50
+ /**
51
+ * Event name for when the toast provider queue is updated.
52
+ *
53
+ * @constant
54
+ */
55
+
56
+ export const ON_TOAST_PROVIDER_QUEUE_UPDATE_EVENT = 'pie-toast-provider-queue-update';
package/src/index.ts CHANGED
@@ -1,20 +1,144 @@
1
- import { LitElement, html, unsafeCSS } from 'lit';
2
- import { RtlMixin, defineCustomElement } from '@justeattakeaway/pie-webc-core';
3
-
1
+ import {
2
+ LitElement,
3
+ html,
4
+ nothing,
5
+ unsafeCSS,
6
+ type PropertyValues,
7
+ } from 'lit';
8
+ import { state, property } from 'lit/decorators.js';
9
+ import { ifDefined } from 'lit/directives/if-defined.js';
10
+ import {
11
+ RtlMixin,
12
+ defineCustomElement,
13
+ dispatchCustomEvent,
14
+ } from '@justeattakeaway/pie-webc-core';
15
+ import { defaultProps as toastDefaultProps } from '@justeattakeaway/pie-toast';
4
16
  import styles from './toast-provider.scss?inline';
5
- import { type ToastProviderProps } from './defs';
17
+ import {
18
+ defaultProps,
19
+ PRIORITY_ORDER,
20
+ type Priority,
21
+ type ToastProviderProps,
22
+ type ExtendedToastProps,
23
+ ON_TOAST_PROVIDER_QUEUE_UPDATE_EVENT,
24
+ } from './defs';
6
25
 
7
26
  // Valid values available to consumers
8
27
  export * from './defs';
28
+ export { toaster } from './toaster';
9
29
 
10
30
  const componentSelector = 'pie-toast-provider';
11
31
 
12
32
  /**
13
33
  * @tagname pie-toast-provider
34
+ * @event {CustomEvent} pie-toast-provider-queue-update - when a toast is added or removed from the queue.
14
35
  */
15
36
  export class PieToastProvider extends RtlMixin(LitElement) implements ToastProviderProps {
37
+ @state()
38
+ private _toasts: ExtendedToastProps[] = [];
39
+
40
+ @state()
41
+ private _currentToast: ExtendedToastProps | null = null;
42
+
43
+ @property({ type: Object })
44
+ public options = defaultProps.options;
45
+
46
+ updated (changedProperties: PropertyValues<this>): void {
47
+ if (changedProperties.has('_toasts' as keyof PieToastProvider)) {
48
+ this._dispatchQueueUpdateEvent();
49
+ }
50
+ }
51
+
52
+ private _dispatchQueueUpdateEvent (): void {
53
+ dispatchCustomEvent(
54
+ this, ON_TOAST_PROVIDER_QUEUE_UPDATE_EVENT,
55
+ this._toasts,
56
+ );
57
+ }
58
+
59
+ /**
60
+ * Get the priority for a toast.
61
+ * @param {string} type - The variant type of the toast.
62
+ * @param {boolean} hasAction - Whether the toast has an action.
63
+ * @returns {number} - The priority based on the variant and action.
64
+ */
65
+ private getPriority (type: ExtendedToastProps['variant'] = toastDefaultProps.variant, hasAction = false): number {
66
+ const key: Priority = `${type}${hasAction ? '-actionable' : ''}`;
67
+ return PRIORITY_ORDER[key];
68
+ }
69
+
70
+ /**
71
+ * Handles the dismissal of the current toast and displays the next one in the queue (if any).
72
+ */
73
+ private _dismissToast () {
74
+ this._currentToast?.onPieToastClose?.();
75
+ this._currentToast = null;
76
+ requestAnimationFrame(() => { this._showNextToast(); });
77
+ }
78
+
79
+ /**
80
+ * Displays the next toast in the queue, if available.
81
+ */
82
+ private _showNextToast () {
83
+ if (this._toasts.length > 0) {
84
+ const [nextToast, ...remainingToasts] = this._toasts;
85
+ this._currentToast = nextToast;
86
+ this._toasts = remainingToasts;
87
+ } else {
88
+ this._currentToast = null;
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Adds a new toast to the queue and triggers its display if no toast is currently active.
94
+ * @param {ToastProps} toast - The toast props to display.
95
+ */
96
+ public createToast (toast: ExtendedToastProps) {
97
+ const newToast = { ...toastDefaultProps, ...this.options, ...toast };
98
+
99
+ this._toasts = [...this._toasts, newToast].sort((a, b) => {
100
+ const priorityB = this.getPriority(b.variant, !!b.leadingAction?.text);
101
+ const priorityA = this.getPriority(a.variant, !!a.leadingAction?.text);
102
+
103
+ return priorityA - priorityB;
104
+ });
105
+
106
+ if (!this._currentToast) {
107
+ this._showNextToast();
108
+ }
109
+ }
110
+
111
+ /**
112
+ *
113
+ * Clears all toasts from the queue and dismisses the currently visible toast.
114
+ */
115
+ public clearToasts () {
116
+ this._toasts = [];
117
+ this._currentToast = null;
118
+ }
119
+
16
120
  render () {
17
- return html`<h1 data-test-id="pie-toast-provider">Hello world!</h1>`;
121
+ const { _currentToast, _dismissToast } = this;
122
+
123
+ return html`
124
+ <div class="c-toast-provider" data-test-id="pie-toast-provider">
125
+ ${_currentToast &&
126
+ html`
127
+ <pie-toast
128
+ message="${_currentToast.message}"
129
+ variant="${ifDefined(_currentToast.variant)}"
130
+ ?isStrong="${_currentToast.isStrong}"
131
+ ?isDismissible="${_currentToast.isDismissible}"
132
+ ?isMultiline="${_currentToast.isMultiline}"
133
+ .leadingAction="${_currentToast.leadingAction}"
134
+ .duration="${typeof _currentToast.duration === 'undefined' ? nothing : _currentToast.duration}"
135
+ @pie-toast-close="${_dismissToast}"
136
+ @pie-toast-open="${_currentToast.onPieToastOpen}"
137
+ @pie-toast-leading-action-click="${_currentToast.onPieToastLeadingActionClick}">
138
+ </pie-toast>
139
+ `}
140
+ </div>
141
+ `;
18
142
  }
19
143
 
20
144
  // Renders a `CSSResult` generated from SCSS by Vite
@@ -28,3 +152,4 @@ declare global {
28
152
  [componentSelector]: PieToastProvider;
29
153
  }
30
154
  }
155
+
package/src/react.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import { createComponent } from '@lit/react';
2
+ import { createComponent, type EventName } from '@lit/react';
3
3
  import { PieToastProvider as PieToastProviderLit } from './index';
4
4
  import { type ToastProviderProps } from './defs';
5
5
 
@@ -10,10 +10,16 @@ const PieToastProviderReact = createComponent({
10
10
  elementClass: PieToastProviderLit,
11
11
  react: React,
12
12
  tagName: 'pie-toast-provider',
13
- events: {},
13
+ events: {
14
+ onPieToastProviderQueueUpdate: 'pie-toast-provider-queue-update' as EventName<CustomEvent>, // when a toast is added or removed from the queue.
15
+ },
14
16
  });
15
17
 
16
18
  type ReactBaseType = React.HTMLAttributes<HTMLElement>
17
19
 
20
+ type PieToastProviderEvents = {
21
+ onPieToastProviderQueueUpdate?: (event: CustomEvent) => void;
22
+ };
23
+
18
24
  export const PieToastProvider = PieToastProviderReact as React.ForwardRefExoticComponent<React.PropsWithoutRef<ToastProviderProps>
19
- & React.RefAttributes<PieToastProviderLit> & ReactBaseType>;
25
+ & React.RefAttributes<PieToastProviderLit> & PieToastProviderEvents & ReactBaseType>;
@@ -1 +1,15 @@
1
1
  @use '@justeattakeaway/pie-css/scss' as p;
2
+ @use '@justeattakeaway/pie-css/scss/settings' as *;
3
+
4
+
5
+ .c-toast-provider {
6
+ --toast-provider-offset: var(--dt-spacing-d);
7
+
8
+ position: absolute;
9
+ inset-inline-start: var(--toast-provider-offset);
10
+ inset-block-end: var(--toast-provider-offset);
11
+
12
+ @include media('>md') {
13
+ --toast-offset: var(--dt-spacing-e);
14
+ }
15
+ }
package/src/toaster.ts ADDED
@@ -0,0 +1,35 @@
1
+ import { type PieToastProvider } from './index';
2
+ import { type ExtendedToastProps } from './defs';
3
+
4
+ /**
5
+ * Singleton toaster interface for global access.
6
+ */
7
+ export const toaster = {
8
+ _getToastProvider (): PieToastProvider | null {
9
+ const toastProviders = document.querySelectorAll('pie-toast-provider');
10
+
11
+ if (toastProviders.length === 0) {
12
+ console.error('The pie-toast component requires a pie-toast-provider element present in the DOM.');
13
+ return null;
14
+ }
15
+
16
+ if (toastProviders.length > 1) {
17
+ console.error('Multiple pie-toast-provider are found in the DOM. Only one provider is supported currently and should be registered at the root of the app.');
18
+ return null;
19
+ }
20
+
21
+ return toastProviders[0];
22
+ },
23
+ create (toast: ExtendedToastProps) {
24
+ const toastProvider = this._getToastProvider();
25
+ if (!toastProvider) return;
26
+
27
+ toastProvider.createToast(toast);
28
+ },
29
+ clearAll () {
30
+ const toastProvider = this._getToastProvider();
31
+ if (!toastProvider) return;
32
+
33
+ toastProvider.clearToasts();
34
+ },
35
+ };