@justeattakeaway/pie-modal 0.12.0 → 0.14.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.
@@ -1,6 +1,9 @@
1
+ import { RTLComponentProps } from '@justeattakeaway/pie-webc-core';
2
+ import { Variant } from '@justeattakeaway/pie-button/src/defs.ts';
1
3
  export declare const headingLevels: readonly ["h1", "h2", "h3", "h4", "h5", "h6"];
2
4
  export declare const sizes: readonly ["small", "medium", "large"];
3
- export interface ModalProps {
5
+ export declare const positions: readonly ["top", "center"];
6
+ export interface ModalProps extends RTLComponentProps {
4
7
  /**
5
8
  * The text to display in the modal's heading.
6
9
  */
@@ -25,6 +28,14 @@ export interface ModalProps {
25
28
  *
26
29
  */
27
30
  isDismissible: boolean;
31
+ /**
32
+ * When true, displays a loading spinner in the modal.
33
+ */
34
+ isLoading: boolean;
35
+ /**
36
+ * When true, the modal will have a back button. This currently behaves the same as the close button.
37
+ */
38
+ hasBackButton: boolean;
28
39
  /**
29
40
  * This controls whether a *medium-sized* modal will cover the full width of the page when below the mid breakpoint.
30
41
  */
@@ -37,6 +48,25 @@ export interface ModalProps {
37
48
  * The size of the modal; this controls how wide it will appear on the page.
38
49
  */
39
50
  size: typeof sizes[number];
51
+ /**
52
+ * The leading action configuration for the modal.
53
+ */
54
+ leadingAction: {
55
+ /**
56
+ * The text to display for the leading action button.
57
+ */
58
+ text: string;
59
+ /**
60
+ * The variant of the leading action button.
61
+ * Default: 'primary'
62
+ */
63
+ variant?: Variant;
64
+ /**
65
+ * The ARIA label for the leading action button.
66
+ */
67
+ ariaLabel?: string;
68
+ };
69
+ position: typeof positions[number];
40
70
  }
41
71
  /**
42
72
  * Event name for when the modal is closed.
@@ -50,4 +80,10 @@ export declare const ON_MODAL_CLOSE_EVENT = "pie-modal-close";
50
80
  * @constant
51
81
  */
52
82
  export declare const ON_MODAL_OPEN_EVENT = "pie-modal-open";
83
+ /**
84
+ * Event name for when the modal back button is clicked.
85
+ *
86
+ * @constant
87
+ */
88
+ export declare const ON_MODAL_BACK_EVENT = "pie-modal-back";
53
89
  //# sourceMappingURL=defs.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"defs.d.ts","sourceRoot":"","sources":["../../../src/defs.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa,+CAAgD,CAAC;AAC3E,eAAO,MAAM,KAAK,uCAAwC,CAAC;AAE3D,MAAM,WAAW,UAAU;IACvB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,YAAY,EAAE,OAAO,aAAa,CAAC,MAAM,CAAC,CAAC;IAE3C;;OAEG;IACH,MAAM,EAAE,OAAO,CAAC;IAEhB;;;;;;;;;;OAUG;IACH,aAAa,EAAE,OAAO,CAAC;IAEvB;;OAEG;IACH,mBAAmB,EAAE,OAAO,CAAC;IAE7B;;OAEG;IACH,6BAA6B,CAAC,EAAE,MAAM,CAAC;IAEvC;;OAEG;IACH,IAAI,EAAE,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC;CAC9B;AAED;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,oBAAoB,CAAC;AAEtD;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,mBAAmB,CAAC"}
1
+ {"version":3,"file":"defs.d.ts","sourceRoot":"","sources":["../../../src/defs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,OAAO,EAAE,MAAM,yCAAyC,CAAC;AAElE,eAAO,MAAM,aAAa,+CAAgD,CAAC;AAC3E,eAAO,MAAM,KAAK,uCAAwC,CAAC;AAC3D,eAAO,MAAM,SAAS,4BAA6B,CAAC;AAEpD,MAAM,WAAW,UAAW,SAAQ,iBAAiB;IACjD;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,YAAY,EAAE,OAAO,aAAa,CAAC,MAAM,CAAC,CAAC;IAE3C;;OAEG;IACH,MAAM,EAAE,OAAO,CAAC;IAEhB;;;;;;;;;;OAUG;IACH,aAAa,EAAE,OAAO,CAAC;IAEvB;;OAEG;IACH,SAAS,EAAE,OAAO,CAAC;IAEnB;;OAEG;IACH,aAAa,EAAE,OAAO,CAAC;IAEvB;;OAEG;IACH,mBAAmB,EAAE,OAAO,CAAC;IAE7B;;OAEG;IACH,6BAA6B,CAAC,EAAE,MAAM,CAAC;IAEvC;;OAEG;IACH,IAAI,EAAE,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC;IAE3B;;OAEG;IACH,aAAa,EAAE;QACX;;WAEG;QACH,IAAI,EAAE,MAAM,CAAC;QAEb;;;WAGG;QACH,OAAO,CAAC,EAAE,OAAO,CAAC;QAElB;;WAEG;QACH,SAAS,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;IAKF,QAAQ,EAAE,OAAO,SAAS,CAAC,MAAM,CAAC,CAAC;CACtC;AAED;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,oBAAoB,CAAC;AAEtD;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,mBAAmB,CAAC;AAEpD;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,mBAAmB,CAAC"}
@@ -1,25 +1,37 @@
1
1
  import { LitElement, TemplateResult } from 'lit';
2
2
  import type { DependentMap } from '@justeattakeaway/pie-webc-core';
3
+ import { Variant } from '@justeattakeaway/pie-button/src/defs.ts';
3
4
  import { ModalProps, headingLevels, sizes } from './defs';
4
5
  export { type ModalProps, headingLevels, sizes };
5
6
  declare const componentSelector = "pie-modal";
6
7
  declare const PieModal_base: (new (...args: any[]) => {
7
- dir: string;
8
+ dir: "ltr" | "rtl" | "auto";
8
9
  isRTL: boolean;
9
10
  }) & typeof LitElement;
10
11
  /**
11
12
  * @event {CustomEvent} pie-modal-open - when the modal is opened.
12
13
  * @event {CustomEvent} pie-modal-close - when the modal is closed.
14
+ * @event {CustomEvent} pie-modal-back - when the modal back button is clicked.
13
15
  */
14
16
  export declare class PieModal extends PieModal_base implements ModalProps {
15
17
  heading: string;
16
18
  headingLevel: ModalProps['headingLevel'];
17
19
  isDismissible: boolean;
20
+ hasBackButton: boolean;
18
21
  isFullWidthBelowMid: boolean;
19
22
  isOpen: boolean;
23
+ isLoading: boolean;
20
24
  returnFocusAfterCloseSelector?: string;
21
25
  size: ModalProps['size'];
22
- _dialog?: HTMLDialogElement;
26
+ leadingAction: {
27
+ text: string;
28
+ variant?: Variant;
29
+ ariaLabel?: string;
30
+ };
31
+ position: ModalProps['position'];
32
+ private _dialog?;
33
+ private _backButtonClicked;
34
+ static styles: import("lit").CSSResult;
23
35
  constructor();
24
36
  connectedCallback(): void;
25
37
  disconnectedCallback(): void;
@@ -45,9 +57,32 @@ export declare class PieModal extends PieModal_base implements ModalProps {
45
57
  /**
46
58
  * Return focus to the specified element, providing the selector is valid
47
59
  * and the chosen element can be found.
48
- * Fails silently.
49
60
  */
50
61
  private _returnFocus;
62
+ /**
63
+ * Template for the close button element. Called within the
64
+ * main render function.
65
+ *
66
+ * @private
67
+ */
68
+ private renderCloseButton;
69
+ /**
70
+ * Template for the back button element. Called within the
71
+ * main render function.
72
+ *
73
+ * @private
74
+ */
75
+ private renderBackButton;
76
+ /**
77
+ * Render leadingAction button depending on prop availability.
78
+ *
79
+ * 1. If the prop `leadingAction` is not provided, the button is not rendered.
80
+ * 2. If the prop `leadingAction` is provided but any of the optional properties
81
+ * are not provided, they fall back to their default values.
82
+ *
83
+ * @private
84
+ */
85
+ private renderLeadingAction;
51
86
  render(): TemplateResult;
52
87
  /**
53
88
  * Dismisses the modal on backdrop click if `isDismissible` is `true`.
@@ -66,14 +101,6 @@ export declare class PieModal extends PieModal_base implements ModalProps {
66
101
  * @param {string} eventType
67
102
  */
68
103
  private _dispatchModalCustomEvent;
69
- /**
70
- * Template for the close button element. Called within the
71
- * main render function.
72
- *
73
- * @private
74
- */
75
- private renderCloseButton;
76
- static styles: import("lit").CSSResult;
77
104
  }
78
105
  declare global {
79
106
  interface HTMLElementTagNameMap {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,UAAU,EAAW,cAAc,EACtC,MAAM,KAAK,CAAC;AAMb,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAEnE,OAAO,iDAAiD,CAAC;AAEzD,OAAO,EACH,UAAU,EACV,aAAa,EAGb,KAAK,EACR,MAAM,QAAQ,CAAC;AAGhB,OAAO,EAAE,KAAK,UAAU,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC;AAEjD,QAAA,MAAM,iBAAiB,cAAc,CAAC;;;;;AAEtC;;;GAGG;AACH,qBAAa,QAAS,SAAQ,aAAqB,YAAW,UAAU;IAG7D,OAAO,EAAG,MAAM,CAAC;IAIjB,YAAY,EAAE,UAAU,CAAC,cAAc,CAAC,CAAQ;IAGhD,aAAa,UAAS;IAGtB,mBAAmB,UAAS;IAG5B,MAAM,UAAS;IAGf,6BAA6B,CAAC,EAAE,MAAM,CAAC;IAIvC,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,CAAY;IAGvC,OAAO,CAAC,EAAE,iBAAiB,CAAC;;IAOhC,iBAAiB,IAAM,IAAI;IAM3B,oBAAoB,IAAM,IAAI;IAM9B,YAAY,CAAE,iBAAiB,EAAE,YAAY,CAAC,UAAU,CAAC,GAAI,IAAI;IASjE,OAAO,CAAE,iBAAiB,EAAE,YAAY,CAAC,UAAU,CAAC,GAAI,IAAI;IAI5D;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAS1B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAM1B;;;;;OAKG;IACH,OAAO,CAAC,wBAAwB,CAI9B;IAGF,OAAO,CAAC,kCAAkC;IAU1C,OAAO,CAAC,4BAA4B;IAYpC;;;;OAIG;IACH,OAAO,CAAC,YAAY;IAQpB,MAAM;IA2BN;;;OAGG;IACH,OAAO,CAAC,yBAAyB,CAyB/B;IAEF;;;;;;;;;;OAUG;IACH,OAAO,CAAC,yBAAyB,CAO/B;IAEF;;;;;OAKG;IACH,OAAO,CAAC,iBAAiB;IAWzB,MAAM,CAAC,MAAM,0BAAqB;CACrC;AAID,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,qBAAqB;QAC3B,CAAC,iBAAiB,CAAC,EAAE,QAAQ,CAAC;KACjC;CACJ"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,UAAU,EAAW,cAAc,EACtC,MAAM,KAAK,CAAC;AAMb,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAEnE,OAAO,iDAAiD,CAAC;AACzD,OAAO,uDAAuD,CAAC;AAC/D,OAAO,wDAAwD,CAAC;AAChE,OAAO,EAAE,OAAO,EAAE,MAAM,yCAAyC,CAAC;AAGlE,OAAO,EACH,UAAU,EACV,aAAa,EAIb,KAAK,EAER,MAAM,QAAQ,CAAC;AAGhB,OAAO,EAAE,KAAK,UAAU,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC;AAEjD,QAAA,MAAM,iBAAiB,cAAc,CAAC;;;;;AAEtC;;;;GAIG;AACH,qBAAa,QAAS,SAAQ,aAAqB,YAAW,UAAU;IAG7D,OAAO,EAAG,MAAM,CAAC;IAIjB,YAAY,EAAE,UAAU,CAAC,cAAc,CAAC,CAAQ;IAGhD,aAAa,UAAS;IAGtB,aAAa,UAAS;IAGtB,mBAAmB,UAAS;IAG5B,MAAM,UAAS;IAGf,SAAS,UAAS;IAGlB,6BAA6B,CAAC,EAAE,MAAM,CAAC;IAIvC,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,CAAY;IAGpC,aAAa,EAAG;QACnB,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;IAGK,QAAQ,EAAE,UAAU,CAAC,UAAU,CAAC,CAAY;IAGnD,OAAO,CAAC,OAAO,CAAC,CAAoB;IAEpC,OAAO,CAAC,kBAAkB,CAAS;IAGnC,MAAM,CAAC,MAAM,0BAAqB;;IAOlC,iBAAiB,IAAM,IAAI;IAO3B,oBAAoB,IAAM,IAAI;IAO9B,YAAY,CAAE,iBAAiB,EAAE,YAAY,CAAC,UAAU,CAAC,GAAI,IAAI;IASjE,OAAO,CAAE,iBAAiB,EAAE,YAAY,CAAC,UAAU,CAAC,GAAI,IAAI;IAI5D;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAS1B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAM1B;;;;;OAKG;IACH,OAAO,CAAC,wBAAwB,CAI9B;IAGF,OAAO,CAAC,kCAAkC;IAU1C,OAAO,CAAC,4BAA4B;IAkBpC;;;OAGG;IACH,OAAO,CAAC,YAAY;IAQpB;;;;;OAKG;IACH,OAAO,CAAC,iBAAiB;IAUzB;;;;;OAKG;IACH,OAAO,CAAC,gBAAgB;IAYxB;;;;;;;;OAQG;IACH,OAAO,CAAC,mBAAmB;IAmBpB,MAAM;IAoDb;;;OAGG;IACH,OAAO,CAAC,yBAAyB,CAyB/B;IAEF;;;;;;;;;;OAUG;IACH,OAAO,CAAC,yBAAyB,CAO/B;CACL;AAID,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,qBAAqB;QAC3B,CAAC,iBAAiB,CAAC,EAAE,QAAQ,CAAC;KACjC;CACJ"}
@@ -1,7 +1,8 @@
1
1
  import { EventName } from '@lit-labs/react';
2
2
  import { PieModal as PieModalReact } from './index';
3
3
  export declare const PieModal: import("@lit-labs/react").ReactWebComponent<PieModalReact, {
4
- onpiemodalopen: EventName<CustomEvent<any>>;
5
- onpiemodalclose: EventName<CustomEvent<any>>;
4
+ onPieModalOpen: EventName<CustomEvent<any>>;
5
+ onPieModalClose: EventName<CustomEvent<any>>;
6
+ onPieModalBack: EventName<CustomEvent<any>>;
6
7
  }>;
7
8
  //# sourceMappingURL=react.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../../../src/react.ts"],"names":[],"mappings":"AAEA,OAAO,EAAmB,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAE,QAAQ,IAAI,aAAa,EAAE,MAAM,SAAS,CAAC;AAEpD,eAAO,MAAM,QAAQ;;;EASnB,CAAC"}
1
+ {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../../../src/react.ts"],"names":[],"mappings":"AAEA,OAAO,EAAmB,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAE,QAAQ,IAAI,aAAa,EAAE,MAAM,SAAS,CAAC;AAEpD,eAAO,MAAM,QAAQ;;;;EAUnB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@justeattakeaway/pie-modal",
3
- "version": "0.12.0",
3
+ "version": "0.14.0",
4
4
  "description": "PIE design system modal built using web components",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -21,6 +21,7 @@
21
21
  "author": "JustEatTakeaway - Design System Web Team",
22
22
  "license": "Apache-2.0",
23
23
  "devDependencies": {
24
+ "@justeattakeaway/pie-button": "workspace:*",
24
25
  "@justeattakeaway/pie-components-config": "workspace:*",
25
26
  "@justeattakeaway/pie-icon-button": "workspace:*",
26
27
  "@justeattakeaway/pie-icons-webc": "workspace:*",
package/src/defs.ts CHANGED
@@ -1,7 +1,11 @@
1
+ import { RTLComponentProps } from '@justeattakeaway/pie-webc-core';
2
+ import { Variant } from '@justeattakeaway/pie-button/src/defs.ts';
3
+
1
4
  export const headingLevels = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'] as const;
2
5
  export const sizes = ['small', 'medium', 'large'] as const;
6
+ export const positions = ['top', 'center'] as const;
3
7
 
4
- export interface ModalProps {
8
+ export interface ModalProps extends RTLComponentProps {
5
9
  /**
6
10
  * The text to display in the modal's heading.
7
11
  */
@@ -30,6 +34,16 @@ export interface ModalProps {
30
34
  */
31
35
  isDismissible: boolean;
32
36
 
37
+ /**
38
+ * When true, displays a loading spinner in the modal.
39
+ */
40
+ isLoading: boolean;
41
+
42
+ /**
43
+ * When true, the modal will have a back button. This currently behaves the same as the close button.
44
+ */
45
+ hasBackButton: boolean;
46
+
33
47
  /**
34
48
  * This controls whether a *medium-sized* modal will cover the full width of the page when below the mid breakpoint.
35
49
  */
@@ -44,6 +58,32 @@ export interface ModalProps {
44
58
  * The size of the modal; this controls how wide it will appear on the page.
45
59
  */
46
60
  size: typeof sizes[number];
61
+
62
+ /**
63
+ * The leading action configuration for the modal.
64
+ */
65
+ leadingAction: {
66
+ /**
67
+ * The text to display for the leading action button.
68
+ */
69
+ text: string;
70
+
71
+ /**
72
+ * The variant of the leading action button.
73
+ * Default: 'primary'
74
+ */
75
+ variant?: Variant;
76
+
77
+ /**
78
+ * The ARIA label for the leading action button.
79
+ */
80
+ ariaLabel?: string;
81
+ };
82
+
83
+ /*
84
+ * The position of the modal; this controls where it will appear on the page.
85
+ */
86
+ position: typeof positions[number];
47
87
  }
48
88
 
49
89
  /**
@@ -59,3 +99,10 @@ export const ON_MODAL_CLOSE_EVENT = 'pie-modal-close';
59
99
  * @constant
60
100
  */
61
101
  export const ON_MODAL_OPEN_EVENT = 'pie-modal-open';
102
+
103
+ /**
104
+ * Event name for when the modal back button is clicked.
105
+ *
106
+ * @constant
107
+ */
108
+ export const ON_MODAL_BACK_EVENT = 'pie-modal-back';
package/src/index.ts CHANGED
@@ -9,13 +9,19 @@ import {
9
9
  import type { DependentMap } from '@justeattakeaway/pie-webc-core';
10
10
  import { disableBodyScroll, enableBodyScroll } from 'body-scroll-lock';
11
11
  import '@justeattakeaway/pie-icons-webc/icons/IconClose';
12
+ import '@justeattakeaway/pie-icons-webc/icons/IconChevronLeft';
13
+ import '@justeattakeaway/pie-icons-webc/icons/IconChevronRight';
14
+ import { Variant } from '@justeattakeaway/pie-button/src/defs.ts';
15
+
12
16
  import styles from './modal.scss?inline';
13
17
  import {
14
18
  ModalProps,
15
19
  headingLevels,
16
20
  ON_MODAL_CLOSE_EVENT,
17
21
  ON_MODAL_OPEN_EVENT,
22
+ ON_MODAL_BACK_EVENT,
18
23
  sizes,
24
+ positions,
19
25
  } from './defs';
20
26
 
21
27
  // Valid values available to consumers
@@ -26,6 +32,7 @@ const componentSelector = 'pie-modal';
26
32
  /**
27
33
  * @event {CustomEvent} pie-modal-open - when the modal is opened.
28
34
  * @event {CustomEvent} pie-modal-close - when the modal is closed.
35
+ * @event {CustomEvent} pie-modal-back - when the modal back button is clicked.
29
36
  */
30
37
  export class PieModal extends RtlMixin(LitElement) implements ModalProps {
31
38
  @property({ type: String })
@@ -39,12 +46,18 @@ export class PieModal extends RtlMixin(LitElement) implements ModalProps {
39
46
  @property({ type: Boolean, reflect: true })
40
47
  public isDismissible = false;
41
48
 
49
+ @property({ type: Boolean })
50
+ public hasBackButton = false;
51
+
42
52
  @property({ type: Boolean })
43
53
  public isFullWidthBelowMid = false;
44
54
 
45
55
  @property({ type: Boolean })
46
56
  public isOpen = false;
47
57
 
58
+ @property({ type: Boolean, reflect: true })
59
+ public isLoading = false;
60
+
48
61
  @property()
49
62
  public returnFocusAfterCloseSelector?: string;
50
63
 
@@ -52,8 +65,23 @@ export class PieModal extends RtlMixin(LitElement) implements ModalProps {
52
65
  @validPropertyValues(componentSelector, sizes, 'medium')
53
66
  public size: ModalProps['size'] = 'medium';
54
67
 
68
+ @property()
69
+ public leadingAction!: {
70
+ text: string;
71
+ variant?: Variant;
72
+ ariaLabel?: string;
73
+ };
74
+
75
+ @validPropertyValues(componentSelector, positions, 'center')
76
+ public position: ModalProps['position'] = 'center';
77
+
55
78
  @query('dialog')
56
- _dialog?: HTMLDialogElement;
79
+ private _dialog?: HTMLDialogElement;
80
+
81
+ private _backButtonClicked = false;
82
+
83
+ // Renders a `CSSResult` generated from SCSS by Vite
84
+ static styles = unsafeCSS(styles);
57
85
 
58
86
  constructor () {
59
87
  super();
@@ -64,11 +92,13 @@ export class PieModal extends RtlMixin(LitElement) implements ModalProps {
64
92
  super.connectedCallback();
65
93
  document.addEventListener(ON_MODAL_OPEN_EVENT, this._handleModalOpened.bind(this));
66
94
  document.addEventListener(ON_MODAL_CLOSE_EVENT, this._handleModalClosed.bind(this));
95
+ document.addEventListener(ON_MODAL_BACK_EVENT, this._handleModalClosed.bind(this));
67
96
  }
68
97
 
69
98
  disconnectedCallback () : void {
70
99
  document.removeEventListener(ON_MODAL_OPEN_EVENT, this._handleModalOpened.bind(this));
71
100
  document.removeEventListener(ON_MODAL_CLOSE_EVENT, this._handleModalClosed.bind(this));
101
+ document.removeEventListener(ON_MODAL_BACK_EVENT, this._handleModalClosed.bind(this));
72
102
  super.disconnectedCallback();
73
103
  }
74
104
 
@@ -130,11 +160,17 @@ export class PieModal extends RtlMixin(LitElement) implements ModalProps {
130
160
 
131
161
  // Handles changes to the modal isOpen property by dispatching any appropriate events
132
162
  private _handleModalOpenStateChanged (changedProperties: DependentMap<ModalProps>) : void {
133
- const previousValue = changedProperties.get('isOpen');
134
-
135
- if (previousValue !== undefined) {
136
- if (previousValue) {
137
- this._dispatchModalCustomEvent(ON_MODAL_CLOSE_EVENT);
163
+ const wasPreviouslyOpen = changedProperties.get('isOpen');
164
+
165
+ if (wasPreviouslyOpen !== undefined) {
166
+ if (wasPreviouslyOpen) {
167
+ if (this._backButtonClicked) {
168
+ // Reset the flag
169
+ this._backButtonClicked = false;
170
+ this._dispatchModalCustomEvent(ON_MODAL_BACK_EVENT);
171
+ } else {
172
+ this._dispatchModalCustomEvent(ON_MODAL_CLOSE_EVENT);
173
+ }
138
174
  } else {
139
175
  this._dispatchModalCustomEvent(ON_MODAL_OPEN_EVENT);
140
176
  }
@@ -144,7 +180,6 @@ export class PieModal extends RtlMixin(LitElement) implements ModalProps {
144
180
  /**
145
181
  * Return focus to the specified element, providing the selector is valid
146
182
  * and the chosen element can be found.
147
- * Fails silently.
148
183
  */
149
184
  private _returnFocus () : void {
150
185
  const selector = this.returnFocusAfterCloseSelector?.trim();
@@ -154,31 +189,118 @@ export class PieModal extends RtlMixin(LitElement) implements ModalProps {
154
189
  }
155
190
  }
156
191
 
157
- render () {
192
+ /**
193
+ * Template for the close button element. Called within the
194
+ * main render function.
195
+ *
196
+ * @private
197
+ */
198
+ private renderCloseButton (): TemplateResult {
199
+ return html`
200
+ <pie-icon-button
201
+ @click="${() => { this.isOpen = false; }}"
202
+ variant="ghost-secondary"
203
+ class="c-modal-closeBtn"
204
+ data-test-id="modal-close-button"><icon-close /></pie-icon-button>
205
+ `;
206
+ }
207
+
208
+ /**
209
+ * Template for the back button element. Called within the
210
+ * main render function.
211
+ *
212
+ * @private
213
+ */
214
+ private renderBackButton () : TemplateResult {
215
+ return html`
216
+ <pie-icon-button
217
+ @click="${() => { this._backButtonClicked = true; this.isOpen = false; }}"
218
+ variant="ghost-secondary"
219
+ class="c-modal-backBtn"
220
+ data-test-id="modal-back-button">
221
+ ${this.isRTL ? html`<icon-chevron-right />` : html`<icon-chevron-left />`}
222
+ </pie-icon-button>
223
+ `;
224
+ }
225
+
226
+ /**
227
+ * Render leadingAction button depending on prop availability.
228
+ *
229
+ * 1. If the prop `leadingAction` is not provided, the button is not rendered.
230
+ * 2. If the prop `leadingAction` is provided but any of the optional properties
231
+ * are not provided, they fall back to their default values.
232
+ *
233
+ * @private
234
+ */
235
+ private renderLeadingAction (): TemplateResult | typeof nothing {
236
+ const { text = 'Confirm', variant = 'primary', ariaLabel } = this.leadingAction;
237
+
238
+ if (!text) {
239
+ return nothing;
240
+ }
241
+
242
+ return html`
243
+ <pie-button
244
+ variant="${variant}"
245
+ aria-label="${ariaLabel || nothing}"
246
+ type="submit"
247
+ @click="${() => this._dialog?.close('leading')}"
248
+ data-test-id="modal-leading-action">
249
+ ${text}
250
+ </pie-button>
251
+ `;
252
+ }
253
+
254
+ public render () {
158
255
  const {
256
+ hasBackButton,
159
257
  heading,
160
258
  headingLevel = 'h2',
161
- size,
259
+ isDismissible,
162
260
  isFullWidthBelowMid,
261
+ isLoading,
262
+ size,
263
+ leadingAction,
264
+ position,
163
265
  } = this;
164
266
 
165
267
  const headingTag = unsafeStatic(headingLevel);
166
268
 
167
269
  return html`
168
- <dialog
169
- id="dialog"
170
- class="c-modal"
171
- size="${size}"
172
- ?isFullWidthBelowMid=${isFullWidthBelowMid}>
173
- <header>
174
- <${headingTag} class="c-modal-heading">${heading}</${headingTag}>
175
- ${this.isDismissible ? this.renderCloseButton() : nothing}
176
- </header>
177
- <article class="c-modal-content">
270
+ <dialog
271
+ id="dialog"
272
+ class="c-modal"
273
+ data-test-id="pie-modal"
274
+ size="${size}"
275
+ position="${position}"
276
+ ?hasBackButton=${hasBackButton}
277
+ ?isDismissible=${isDismissible}
278
+ ?isFullWidthBelowMid=${isFullWidthBelowMid}
279
+ ?isLoading=${isLoading}
280
+ data-test-id="pie-modal">
281
+ <header class="c-modal-header">
282
+ ${hasBackButton ? this.renderBackButton() : nothing}
283
+ <${headingTag} class="c-modal-heading">
284
+ ${heading}
285
+ </${headingTag}>
286
+ ${isDismissible ? this.renderCloseButton() : nothing}
287
+ </header>
288
+ <article class="c-modal-content c-modal-content--scrollable">
289
+ <div class="c-modal-contentInner">
178
290
  <slot></slot>
179
- </article>
180
- </dialog>
181
- `;
291
+ </div>
292
+ </article>
293
+ <footer class="c-modal-footer">
294
+ ${leadingAction ? this.renderLeadingAction() : nothing}
295
+ <pie-button
296
+ variant="ghost"
297
+ type="reset"
298
+ @click="${() => this._dialog?.close('supporting')}"
299
+ data-test-id="modal-supporting-action">
300
+ Cancel
301
+ </pie-button>
302
+ </footer>
303
+ </dialog>`;
182
304
  }
183
305
 
184
306
  /**
@@ -231,25 +353,6 @@ export class PieModal extends RtlMixin(LitElement) implements ModalProps {
231
353
 
232
354
  this.dispatchEvent(event);
233
355
  };
234
-
235
- /**
236
- * Template for the close button element. Called within the
237
- * main render function.
238
- *
239
- * @private
240
- */
241
- private renderCloseButton (): TemplateResult {
242
- return html`
243
- <pie-icon-button
244
- @click="${() => { this.isOpen = false; }}"
245
- variant="ghost-secondary"
246
- class="c-modal-closeBtn"
247
- data-test-id="modal-close-button"><icon-close /></pie-icon-button>
248
- `;
249
- }
250
-
251
- // Renders a `CSSResult` generated from SCSS by Vite
252
- static styles = unsafeCSS(styles);
253
356
  }
254
357
 
255
358
  customElements.define(componentSelector, PieModal);