@justeattakeaway/pie-modal 0.13.0 → 0.16.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/.eslintignore +6 -0
- package/.turbo/turbo-build.log +4 -4
- package/CHANGELOG.md +47 -0
- package/README.md +17 -15
- package/dist/index.js +1070 -200
- package/dist/react.js +0 -0
- package/dist/types/index.d.ts +0 -0
- package/dist/types/packages/components/pie-modal/src/defs.d.ts +50 -8
- package/dist/types/packages/components/pie-modal/src/defs.d.ts.map +1 -1
- package/dist/types/packages/components/pie-modal/src/index.d.ts +36 -3
- package/dist/types/packages/components/pie-modal/src/index.d.ts.map +1 -1
- package/dist/types/packages/components/pie-modal/src/react.d.ts +0 -0
- package/dist/types/packages/components/pie-modal/src/react.d.ts.map +0 -0
- package/dist/types/react.d.ts +0 -0
- package/package.json +3 -1
- package/playwright/index.ts +1 -1
- package/playwright-lit-visual.config.ts +0 -1
- package/playwright-lit.config.ts +1 -2
- package/src/defs.ts +62 -7
- package/src/index.ts +145 -37
- package/src/modal.scss +107 -19
- package/test/component/pie-modal.spec.ts +273 -12
- package/test/helpers/index.ts +2 -0
- package/test/visual/pie-modal.spec.ts +376 -85
- package/tsconfig.json +1 -1
package/dist/react.js
CHANGED
|
File without changes
|
package/dist/types/index.d.ts
CHANGED
|
File without changes
|
|
@@ -1,7 +1,40 @@
|
|
|
1
1
|
import { RTLComponentProps } from '@justeattakeaway/pie-webc-core';
|
|
2
|
+
import { Variant } from '@justeattakeaway/pie-button/src/defs.ts';
|
|
2
3
|
export declare const headingLevels: readonly ["h1", "h2", "h3", "h4", "h5", "h6"];
|
|
3
4
|
export declare const sizes: readonly ["small", "medium", "large"];
|
|
4
|
-
export
|
|
5
|
+
export declare const positions: readonly ["top", "center"];
|
|
6
|
+
export type AriaProps = {
|
|
7
|
+
close?: string;
|
|
8
|
+
back?: string;
|
|
9
|
+
loading?: string;
|
|
10
|
+
};
|
|
11
|
+
export type ActionProps = {
|
|
12
|
+
/**
|
|
13
|
+
* The text to display inside the button.
|
|
14
|
+
*/
|
|
15
|
+
text: string;
|
|
16
|
+
/**
|
|
17
|
+
* The button variant.
|
|
18
|
+
*/
|
|
19
|
+
variant?: Variant;
|
|
20
|
+
/**
|
|
21
|
+
* The ARIA label for the button.
|
|
22
|
+
*/
|
|
23
|
+
ariaLabel?: string;
|
|
24
|
+
};
|
|
25
|
+
export type ModalProps = RTLComponentProps & {
|
|
26
|
+
/**
|
|
27
|
+
* The ARIA labels used for the modal close and back buttons, as well as loading state.
|
|
28
|
+
*/
|
|
29
|
+
aria?: AriaProps;
|
|
30
|
+
/**
|
|
31
|
+
* When true, the modal will have a back button. This currently behaves the same as the close button.
|
|
32
|
+
*/
|
|
33
|
+
hasBackButton: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* When true, the modal will have a back button. This currently behaves the same as the close button.
|
|
36
|
+
*/
|
|
37
|
+
hasStackedActions: boolean;
|
|
5
38
|
/**
|
|
6
39
|
* The text to display in the modal's heading.
|
|
7
40
|
*/
|
|
@@ -27,17 +60,22 @@ export interface ModalProps extends RTLComponentProps {
|
|
|
27
60
|
*/
|
|
28
61
|
isDismissible: boolean;
|
|
29
62
|
/**
|
|
30
|
-
* When
|
|
63
|
+
* When false, the modal footer will scroll with the content inside the modal body.
|
|
31
64
|
*/
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* When true, the modal will have a back button. This currently behaves the same as the close button.
|
|
35
|
-
*/
|
|
36
|
-
hasBackButton: boolean;
|
|
65
|
+
isFooterPinned: boolean;
|
|
37
66
|
/**
|
|
38
67
|
* This controls whether a *medium-sized* modal will cover the full width of the page when below the mid breakpoint.
|
|
39
68
|
*/
|
|
40
69
|
isFullWidthBelowMid: boolean;
|
|
70
|
+
/**
|
|
71
|
+
* When true, displays a loading spinner in the modal.
|
|
72
|
+
*/
|
|
73
|
+
isLoading: boolean;
|
|
74
|
+
/**
|
|
75
|
+
* The leading action configuration for the modal.
|
|
76
|
+
*/
|
|
77
|
+
leadingAction: ActionProps;
|
|
78
|
+
position: typeof positions[number];
|
|
41
79
|
/**
|
|
42
80
|
* The selector for the element that you would like focus to be returned to when the modal is closed, e.g., #skipToMain
|
|
43
81
|
*/
|
|
@@ -46,7 +84,11 @@ export interface ModalProps extends RTLComponentProps {
|
|
|
46
84
|
* The size of the modal; this controls how wide it will appear on the page.
|
|
47
85
|
*/
|
|
48
86
|
size: typeof sizes[number];
|
|
49
|
-
|
|
87
|
+
/**
|
|
88
|
+
* The supporting action configuration for the modal.
|
|
89
|
+
*/
|
|
90
|
+
supportingAction: ActionProps;
|
|
91
|
+
};
|
|
50
92
|
/**
|
|
51
93
|
* Event name for when the modal is closed.
|
|
52
94
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defs.d.ts","sourceRoot":"","sources":["../../../src/defs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,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,MAAM,SAAS,GAAG;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IAClB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,iBAAiB,GAAG;IACzC;;OAEG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC;IAEjB;;OAEG;IACH,aAAa,EAAE,OAAO,CAAC;IAEvB;;OAEG;IACH,iBAAiB,EAAE,OAAO,CAAC;IAE3B;;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,cAAc,EAAE,OAAO,CAAC;IAExB;;OAEG;IACH,mBAAmB,EAAE,OAAO,CAAC;IAE7B;;OAEG;IACH,SAAS,EAAE,OAAO,CAAC;IAEnB;;OAEG;IACH,aAAa,EAAE,WAAW,CAAC;IAK3B,QAAQ,EAAE,OAAO,SAAS,CAAC,MAAM,CAAC,CAAC;IAEnC;;OAEG;IACH,6BAA6B,CAAC,EAAE,MAAM,CAAC;IAEvC;;OAEG;IACH,IAAI,EAAE,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC;IAE3B;;OAEG;IACH,gBAAgB,EAAE,WAAW,CAAC;CACjC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,oBAAoB,CAAC;AAEtD;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,mBAAmB,CAAC;AAEpD;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,mBAAmB,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { LitElement, TemplateResult } from 'lit';
|
|
2
2
|
import type { DependentMap } from '@justeattakeaway/pie-webc-core';
|
|
3
|
-
import { ModalProps, headingLevels, sizes } from './defs';
|
|
3
|
+
import { type AriaProps, type ActionProps, type ModalProps, headingLevels, sizes } from './defs';
|
|
4
4
|
export { type ModalProps, headingLevels, sizes };
|
|
5
5
|
declare const componentSelector = "pie-modal";
|
|
6
6
|
declare const PieModal_base: (new (...args: any[]) => {
|
|
@@ -13,15 +13,21 @@ declare const PieModal_base: (new (...args: any[]) => {
|
|
|
13
13
|
* @event {CustomEvent} pie-modal-back - when the modal back button is clicked.
|
|
14
14
|
*/
|
|
15
15
|
export declare class PieModal extends PieModal_base implements ModalProps {
|
|
16
|
+
aria: AriaProps;
|
|
16
17
|
heading: string;
|
|
17
18
|
headingLevel: ModalProps['headingLevel'];
|
|
18
|
-
isDismissible: boolean;
|
|
19
19
|
hasBackButton: boolean;
|
|
20
|
+
hasStackedActions: boolean;
|
|
21
|
+
isDismissible: boolean;
|
|
22
|
+
isFooterPinned: boolean;
|
|
20
23
|
isFullWidthBelowMid: boolean;
|
|
21
|
-
isOpen: boolean;
|
|
22
24
|
isLoading: boolean;
|
|
25
|
+
isOpen: boolean;
|
|
26
|
+
leadingAction: ActionProps;
|
|
27
|
+
position: ModalProps['position'];
|
|
23
28
|
returnFocusAfterCloseSelector?: string;
|
|
24
29
|
size: ModalProps['size'];
|
|
30
|
+
supportingAction: ActionProps;
|
|
25
31
|
private _dialog?;
|
|
26
32
|
private _backButtonClicked;
|
|
27
33
|
static styles: import("lit").CSSResult;
|
|
@@ -66,6 +72,33 @@ export declare class PieModal extends PieModal_base implements ModalProps {
|
|
|
66
72
|
* @private
|
|
67
73
|
*/
|
|
68
74
|
private renderBackButton;
|
|
75
|
+
/**
|
|
76
|
+
* Render leadingAction button depending on prop availability.
|
|
77
|
+
*
|
|
78
|
+
* 1. If the prop `leadingAction` is not provided, the button is not rendered.
|
|
79
|
+
* 2. If the prop `leadingAction` is provided but any of the optional properties
|
|
80
|
+
* are not provided, they fall back to their default values.
|
|
81
|
+
*
|
|
82
|
+
* @private
|
|
83
|
+
*/
|
|
84
|
+
private renderLeadingAction;
|
|
85
|
+
/**
|
|
86
|
+
* Render supportingAction button depending on prop availability.
|
|
87
|
+
*
|
|
88
|
+
* 1. If the prop `supportingAction` is not provided, the button is not rendered.
|
|
89
|
+
* 2. If the prop `supportingAction` is provided but any of the optional properties
|
|
90
|
+
* are not provided, they fall back to their default values.
|
|
91
|
+
* 3. If `supportingAction` is provided but not `leadingAction`, log a warning and do
|
|
92
|
+
* not render `supportingAction`.
|
|
93
|
+
*
|
|
94
|
+
* @private
|
|
95
|
+
*/
|
|
96
|
+
private renderSupportingAction;
|
|
97
|
+
/**
|
|
98
|
+
* Renders the modal inner content and footer of the modal.
|
|
99
|
+
* @private
|
|
100
|
+
*/
|
|
101
|
+
private renderModalContentAndFooter;
|
|
69
102
|
render(): TemplateResult;
|
|
70
103
|
/**
|
|
71
104
|
* Dismisses the modal on backdrop click if `isDismissible` is `true`.
|
|
@@ -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,
|
|
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,yDAAyD,CAAC;AACjE,OAAO,+DAA+D,CAAC;AACvE,OAAO,gEAAgE,CAAC;AAGxE,OAAO,EACH,KAAK,SAAS,EACd,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,aAAa,EAEb,KAAK,EAIR,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;IAE7D,IAAI,EAAG,SAAS,CAAC;IAIjB,OAAO,EAAG,MAAM,CAAC;IAIjB,YAAY,EAAE,UAAU,CAAC,cAAc,CAAC,CAAQ;IAGhD,aAAa,UAAS;IAGtB,iBAAiB,UAAS;IAG1B,aAAa,UAAS;IAGtB,cAAc,UAAQ;IAGtB,mBAAmB,UAAS;IAG5B,SAAS,UAAS;IAGlB,MAAM,UAAS;IAGf,aAAa,EAAG,WAAW,CAAC;IAI5B,QAAQ,EAAE,UAAU,CAAC,UAAU,CAAC,CAAY;IAG5C,6BAA6B,CAAC,EAAE,MAAM,CAAC;IAIvC,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,CAAY;IAGpC,gBAAgB,EAAG,WAAW,CAAC;IAGtC,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;IAYzB;;;;;OAKG;IACH,OAAO,CAAC,gBAAgB;IAaxB;;;;;;;;OAQG;IACH,OAAO,CAAC,mBAAmB;IAoB3B;;;;;;;;;;OAUG;IACH,OAAO,CAAC,sBAAsB;IAyB9B;;;OAGG;IACH,OAAO,CAAC,2BAA2B;IAa5B,MAAM;IAuDb;;;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"}
|
|
File without changes
|
|
File without changes
|
package/dist/types/react.d.ts
CHANGED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@justeattakeaway/pie-modal",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"description": "PIE design system modal built using web components",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
"types": "dist/types/index.d.ts",
|
|
9
9
|
"scripts": {
|
|
10
10
|
"build": "yarn build:wrapper pie-modal && run -T vite build",
|
|
11
|
+
"lint:scripts": "run -T eslint .",
|
|
12
|
+
"lint:scripts:fix": "run -T eslint . --fix",
|
|
11
13
|
"lint:style": "run -T stylelint ./src/**/*.{css,scss}",
|
|
12
14
|
"lint:style:fix": "yarn lint:style --fix",
|
|
13
15
|
"watch": "run -T vite build --watch",
|
package/playwright/index.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
//Import common styles here
|
|
1
|
+
// Import common styles here
|
package/playwright-lit.config.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { defineConfig } from '@sand4rt/experimental-ct-web';
|
|
2
|
-
import { getPlaywrightConfig } from '@justeattakeaway/pie-components-config'
|
|
2
|
+
import { getPlaywrightConfig } from '@justeattakeaway/pie-components-config';
|
|
3
3
|
|
|
4
|
-
// @ts-ignore
|
|
5
4
|
export default defineConfig(getPlaywrightConfig());
|
package/src/defs.ts
CHANGED
|
@@ -1,9 +1,49 @@
|
|
|
1
1
|
import { RTLComponentProps } from '@justeattakeaway/pie-webc-core';
|
|
2
|
+
import { Variant } from '@justeattakeaway/pie-button/src/defs.ts';
|
|
2
3
|
|
|
3
4
|
export const headingLevels = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'] as const;
|
|
4
5
|
export const sizes = ['small', 'medium', 'large'] as const;
|
|
6
|
+
export const positions = ['top', 'center'] as const;
|
|
7
|
+
|
|
8
|
+
export type AriaProps = {
|
|
9
|
+
close?: string;
|
|
10
|
+
back?: string;
|
|
11
|
+
loading?: string;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export type ActionProps = {
|
|
15
|
+
/**
|
|
16
|
+
* The text to display inside the button.
|
|
17
|
+
*/
|
|
18
|
+
text: string;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The button variant.
|
|
22
|
+
*/
|
|
23
|
+
variant?: Variant;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The ARIA label for the button.
|
|
27
|
+
*/
|
|
28
|
+
ariaLabel?: string;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export type ModalProps = RTLComponentProps & {
|
|
32
|
+
/**
|
|
33
|
+
* The ARIA labels used for the modal close and back buttons, as well as loading state.
|
|
34
|
+
*/
|
|
35
|
+
aria?: AriaProps;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* When true, the modal will have a back button. This currently behaves the same as the close button.
|
|
39
|
+
*/
|
|
40
|
+
hasBackButton: boolean;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* When true, the modal will have a back button. This currently behaves the same as the close button.
|
|
44
|
+
*/
|
|
45
|
+
hasStackedActions: boolean;
|
|
5
46
|
|
|
6
|
-
export interface ModalProps extends RTLComponentProps {
|
|
7
47
|
/**
|
|
8
48
|
* The text to display in the modal's heading.
|
|
9
49
|
*/
|
|
@@ -32,20 +72,30 @@ export interface ModalProps extends RTLComponentProps {
|
|
|
32
72
|
*/
|
|
33
73
|
isDismissible: boolean;
|
|
34
74
|
|
|
75
|
+
/**
|
|
76
|
+
* When false, the modal footer will scroll with the content inside the modal body.
|
|
77
|
+
*/
|
|
78
|
+
isFooterPinned: boolean;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* This controls whether a *medium-sized* modal will cover the full width of the page when below the mid breakpoint.
|
|
82
|
+
*/
|
|
83
|
+
isFullWidthBelowMid: boolean;
|
|
84
|
+
|
|
35
85
|
/**
|
|
36
86
|
* When true, displays a loading spinner in the modal.
|
|
37
87
|
*/
|
|
38
88
|
isLoading: boolean;
|
|
39
89
|
|
|
40
90
|
/**
|
|
41
|
-
*
|
|
91
|
+
* The leading action configuration for the modal.
|
|
42
92
|
*/
|
|
43
|
-
|
|
93
|
+
leadingAction: ActionProps;
|
|
44
94
|
|
|
45
|
-
|
|
46
|
-
*
|
|
95
|
+
/*
|
|
96
|
+
* The position of the modal; this controls where it will appear on the page.
|
|
47
97
|
*/
|
|
48
|
-
|
|
98
|
+
position: typeof positions[number];
|
|
49
99
|
|
|
50
100
|
/**
|
|
51
101
|
* The selector for the element that you would like focus to be returned to when the modal is closed, e.g., #skipToMain
|
|
@@ -56,7 +106,12 @@ export interface ModalProps extends RTLComponentProps {
|
|
|
56
106
|
* The size of the modal; this controls how wide it will appear on the page.
|
|
57
107
|
*/
|
|
58
108
|
size: typeof sizes[number];
|
|
59
|
-
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* The supporting action configuration for the modal.
|
|
112
|
+
*/
|
|
113
|
+
supportingAction: ActionProps;
|
|
114
|
+
};
|
|
60
115
|
|
|
61
116
|
/**
|
|
62
117
|
* Event name for when the modal is closed.
|
package/src/index.ts
CHANGED
|
@@ -4,22 +4,25 @@ import {
|
|
|
4
4
|
import { html, unsafeStatic } from 'lit/static-html.js';
|
|
5
5
|
import { property, query } from 'lit/decorators.js';
|
|
6
6
|
import {
|
|
7
|
-
RtlMixin, validPropertyValues,
|
|
7
|
+
requiredProperty, RtlMixin, validPropertyValues,
|
|
8
8
|
} from '@justeattakeaway/pie-webc-core';
|
|
9
9
|
import type { DependentMap } from '@justeattakeaway/pie-webc-core';
|
|
10
10
|
import { disableBodyScroll, enableBodyScroll } from 'body-scroll-lock';
|
|
11
|
-
import '@justeattakeaway/pie-icons-webc/icons/IconClose';
|
|
12
|
-
import '@justeattakeaway/pie-icons-webc/icons/IconChevronLeft';
|
|
13
|
-
import '@justeattakeaway/pie-icons-webc/icons/IconChevronRight';
|
|
11
|
+
import '@justeattakeaway/pie-icons-webc/dist/icons/IconClose.js';
|
|
12
|
+
import '@justeattakeaway/pie-icons-webc/dist/icons/IconChevronLeft.js';
|
|
13
|
+
import '@justeattakeaway/pie-icons-webc/dist/icons/IconChevronRight.js';
|
|
14
14
|
|
|
15
15
|
import styles from './modal.scss?inline';
|
|
16
16
|
import {
|
|
17
|
-
|
|
17
|
+
type AriaProps,
|
|
18
|
+
type ActionProps,
|
|
19
|
+
type ModalProps,
|
|
18
20
|
headingLevels,
|
|
21
|
+
positions,
|
|
22
|
+
sizes,
|
|
23
|
+
ON_MODAL_BACK_EVENT,
|
|
19
24
|
ON_MODAL_CLOSE_EVENT,
|
|
20
25
|
ON_MODAL_OPEN_EVENT,
|
|
21
|
-
ON_MODAL_BACK_EVENT,
|
|
22
|
-
sizes,
|
|
23
26
|
} from './defs';
|
|
24
27
|
|
|
25
28
|
// Valid values available to consumers
|
|
@@ -33,6 +36,9 @@ const componentSelector = 'pie-modal';
|
|
|
33
36
|
* @event {CustomEvent} pie-modal-back - when the modal back button is clicked.
|
|
34
37
|
*/
|
|
35
38
|
export class PieModal extends RtlMixin(LitElement) implements ModalProps {
|
|
39
|
+
@property({ type: Object })
|
|
40
|
+
public aria!: AriaProps;
|
|
41
|
+
|
|
36
42
|
@property({ type: String })
|
|
37
43
|
@requiredProperty(componentSelector)
|
|
38
44
|
public heading!: string;
|
|
@@ -41,20 +47,33 @@ export class PieModal extends RtlMixin(LitElement) implements ModalProps {
|
|
|
41
47
|
@validPropertyValues(componentSelector, headingLevels, 'h2')
|
|
42
48
|
public headingLevel: ModalProps['headingLevel'] = 'h2';
|
|
43
49
|
|
|
50
|
+
@property({ type: Boolean })
|
|
51
|
+
public hasBackButton = false;
|
|
52
|
+
|
|
53
|
+
@property({ type: Boolean })
|
|
54
|
+
public hasStackedActions = false;
|
|
55
|
+
|
|
44
56
|
@property({ type: Boolean, reflect: true })
|
|
45
57
|
public isDismissible = false;
|
|
46
58
|
|
|
47
59
|
@property({ type: Boolean })
|
|
48
|
-
public
|
|
60
|
+
public isFooterPinned = true;
|
|
49
61
|
|
|
50
62
|
@property({ type: Boolean })
|
|
51
63
|
public isFullWidthBelowMid = false;
|
|
52
64
|
|
|
65
|
+
@property({ type: Boolean, reflect: true })
|
|
66
|
+
public isLoading = false;
|
|
67
|
+
|
|
53
68
|
@property({ type: Boolean })
|
|
54
69
|
public isOpen = false;
|
|
55
70
|
|
|
56
|
-
@property({ type:
|
|
57
|
-
public
|
|
71
|
+
@property({ type: Object })
|
|
72
|
+
public leadingAction!: ActionProps;
|
|
73
|
+
|
|
74
|
+
@property()
|
|
75
|
+
@validPropertyValues(componentSelector, positions, 'center')
|
|
76
|
+
public position: ModalProps['position'] = 'center';
|
|
58
77
|
|
|
59
78
|
@property()
|
|
60
79
|
public returnFocusAfterCloseSelector?: string;
|
|
@@ -63,6 +82,9 @@ export class PieModal extends RtlMixin(LitElement) implements ModalProps {
|
|
|
63
82
|
@validPropertyValues(componentSelector, sizes, 'medium')
|
|
64
83
|
public size: ModalProps['size'] = 'medium';
|
|
65
84
|
|
|
85
|
+
@property({ type: Object })
|
|
86
|
+
public supportingAction!: ActionProps;
|
|
87
|
+
|
|
66
88
|
@query('dialog')
|
|
67
89
|
private _dialog?: HTMLDialogElement;
|
|
68
90
|
|
|
@@ -189,8 +211,10 @@ export class PieModal extends RtlMixin(LitElement) implements ModalProps {
|
|
|
189
211
|
@click="${() => { this.isOpen = false; }}"
|
|
190
212
|
variant="ghost-secondary"
|
|
191
213
|
class="c-modal-closeBtn"
|
|
192
|
-
|
|
193
|
-
|
|
214
|
+
aria-label="${this.aria?.close || nothing}"
|
|
215
|
+
data-test-id="modal-close-button">
|
|
216
|
+
<icon-close></icon-close>
|
|
217
|
+
</pie-icon-button>`;
|
|
194
218
|
}
|
|
195
219
|
|
|
196
220
|
/**
|
|
@@ -205,21 +229,110 @@ export class PieModal extends RtlMixin(LitElement) implements ModalProps {
|
|
|
205
229
|
@click="${() => { this._backButtonClicked = true; this.isOpen = false; }}"
|
|
206
230
|
variant="ghost-secondary"
|
|
207
231
|
class="c-modal-backBtn"
|
|
232
|
+
aria-label="${this.aria?.back || nothing}"
|
|
208
233
|
data-test-id="modal-back-button">
|
|
209
|
-
${this.isRTL ? html`<icon-chevron-right
|
|
234
|
+
${this.isRTL ? html`<icon-chevron-right></icon-chevron-right>` : html`<icon-chevron-left></icon-chevron-left>`}
|
|
210
235
|
</pie-icon-button>
|
|
211
236
|
`;
|
|
212
237
|
}
|
|
213
238
|
|
|
239
|
+
/**
|
|
240
|
+
* Render leadingAction button depending on prop availability.
|
|
241
|
+
*
|
|
242
|
+
* 1. If the prop `leadingAction` is not provided, the button is not rendered.
|
|
243
|
+
* 2. If the prop `leadingAction` is provided but any of the optional properties
|
|
244
|
+
* are not provided, they fall back to their default values.
|
|
245
|
+
*
|
|
246
|
+
* @private
|
|
247
|
+
*/
|
|
248
|
+
private renderLeadingAction () : TemplateResult | typeof nothing {
|
|
249
|
+
const { text, variant = 'primary', ariaLabel } = this.leadingAction;
|
|
250
|
+
|
|
251
|
+
if (!text) {
|
|
252
|
+
return nothing;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return html`
|
|
256
|
+
<pie-button
|
|
257
|
+
variant="${variant}"
|
|
258
|
+
aria-label="${ariaLabel || nothing}"
|
|
259
|
+
type="submit"
|
|
260
|
+
?isFullWidth="${this.hasStackedActions}"
|
|
261
|
+
@click="${() => this._dialog?.close('leading')}"
|
|
262
|
+
data-test-id="modal-leading-action">
|
|
263
|
+
${text}
|
|
264
|
+
</pie-button>
|
|
265
|
+
`;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Render supportingAction button depending on prop availability.
|
|
270
|
+
*
|
|
271
|
+
* 1. If the prop `supportingAction` is not provided, the button is not rendered.
|
|
272
|
+
* 2. If the prop `supportingAction` is provided but any of the optional properties
|
|
273
|
+
* are not provided, they fall back to their default values.
|
|
274
|
+
* 3. If `supportingAction` is provided but not `leadingAction`, log a warning and do
|
|
275
|
+
* not render `supportingAction`.
|
|
276
|
+
*
|
|
277
|
+
* @private
|
|
278
|
+
*/
|
|
279
|
+
private renderSupportingAction (): TemplateResult | typeof nothing {
|
|
280
|
+
const { text, variant = 'ghost', ariaLabel } = this.supportingAction;
|
|
281
|
+
|
|
282
|
+
if (!text) {
|
|
283
|
+
return nothing;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (!this.leadingAction) {
|
|
287
|
+
console.warn('Use `leadingAction` instead of `supportingAction`. `supportingAction` is being ignored.');
|
|
288
|
+
return nothing;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
return html`
|
|
292
|
+
<pie-button
|
|
293
|
+
variant="${variant}"
|
|
294
|
+
aria-label="${ariaLabel || nothing}"
|
|
295
|
+
type="reset"
|
|
296
|
+
?isFullWidth="${this.hasStackedActions}"
|
|
297
|
+
@click="${() => this._dialog?.close('supporting')}"
|
|
298
|
+
data-test-id="modal-supporting-action">
|
|
299
|
+
${text}
|
|
300
|
+
</pie-button>
|
|
301
|
+
`;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Renders the modal inner content and footer of the modal.
|
|
306
|
+
* @private
|
|
307
|
+
*/
|
|
308
|
+
private renderModalContentAndFooter (): TemplateResult {
|
|
309
|
+
return html`
|
|
310
|
+
<article class="c-modal-content c-modal-content--scrollable">
|
|
311
|
+
<div class="c-modal-contentInner">
|
|
312
|
+
<slot></slot>
|
|
313
|
+
</div>
|
|
314
|
+
</article>
|
|
315
|
+
<footer class="c-modal-footer">
|
|
316
|
+
${this.leadingAction ? this.renderLeadingAction() : nothing}
|
|
317
|
+
${this.supportingAction ? this.renderSupportingAction() : nothing}
|
|
318
|
+
</footer>`;
|
|
319
|
+
}
|
|
320
|
+
|
|
214
321
|
public render () {
|
|
215
322
|
const {
|
|
323
|
+
aria,
|
|
216
324
|
hasBackButton,
|
|
325
|
+
hasStackedActions,
|
|
217
326
|
heading,
|
|
218
327
|
headingLevel = 'h2',
|
|
219
328
|
isDismissible,
|
|
329
|
+
isFooterPinned,
|
|
220
330
|
isFullWidthBelowMid,
|
|
221
331
|
isLoading,
|
|
332
|
+
leadingAction,
|
|
333
|
+
position,
|
|
222
334
|
size,
|
|
335
|
+
supportingAction,
|
|
223
336
|
} = this;
|
|
224
337
|
|
|
225
338
|
const headingTag = unsafeStatic(headingLevel);
|
|
@@ -229,10 +342,16 @@ export class PieModal extends RtlMixin(LitElement) implements ModalProps {
|
|
|
229
342
|
id="dialog"
|
|
230
343
|
class="c-modal"
|
|
231
344
|
size="${size}"
|
|
345
|
+
position="${position}"
|
|
346
|
+
?hasActions=${leadingAction || supportingAction}
|
|
232
347
|
?hasBackButton=${hasBackButton}
|
|
348
|
+
?hasStackedActions=${hasStackedActions}
|
|
233
349
|
?isDismissible=${isDismissible}
|
|
350
|
+
?isFooterPinned=${isFooterPinned}
|
|
234
351
|
?isFullWidthBelowMid=${isFullWidthBelowMid}
|
|
235
352
|
?isLoading=${isLoading}
|
|
353
|
+
aria-busy="${isLoading ? 'true' : 'false'}"
|
|
354
|
+
aria-label="${(isLoading && aria?.loading) || nothing}"
|
|
236
355
|
data-test-id="pie-modal">
|
|
237
356
|
<header class="c-modal-header">
|
|
238
357
|
${hasBackButton ? this.renderBackButton() : nothing}
|
|
@@ -241,27 +360,16 @@ export class PieModal extends RtlMixin(LitElement) implements ModalProps {
|
|
|
241
360
|
</${headingTag}>
|
|
242
361
|
${isDismissible ? this.renderCloseButton() : nothing}
|
|
243
362
|
</header>
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
data-test-id="modal-leading-action">
|
|
255
|
-
Confirm
|
|
256
|
-
</pie-button>
|
|
257
|
-
<pie-button
|
|
258
|
-
variant="ghost"
|
|
259
|
-
type="reset"
|
|
260
|
-
@click="${() => this._dialog?.close('supporting')}"
|
|
261
|
-
data-test-id="modal-supporting-action">
|
|
262
|
-
Cancel
|
|
263
|
-
</pie-button>
|
|
264
|
-
</footer>
|
|
363
|
+
${
|
|
364
|
+
// We need to wrap the remaining content in a shared scrollable container if the footer is not pinned
|
|
365
|
+
isFooterPinned
|
|
366
|
+
? this.renderModalContentAndFooter()
|
|
367
|
+
: html`
|
|
368
|
+
<div class="c-modal-scrollContainer">
|
|
369
|
+
${this.renderModalContentAndFooter()}
|
|
370
|
+
</div>
|
|
371
|
+
`
|
|
372
|
+
}
|
|
265
373
|
</dialog>`;
|
|
266
374
|
}
|
|
267
375
|
|
|
@@ -287,9 +395,9 @@ export class PieModal extends RtlMixin(LitElement) implements ModalProps {
|
|
|
287
395
|
}
|
|
288
396
|
|
|
289
397
|
const isClickOutsideDialog = event.clientY < top ||
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
398
|
+
event.clientY > bottom ||
|
|
399
|
+
event.clientX < left ||
|
|
400
|
+
event.clientX > right;
|
|
293
401
|
|
|
294
402
|
if (isClickOutsideDialog) {
|
|
295
403
|
this.isOpen = false;
|