Skip to content

Commit 3e38703

Browse files
authored
Merge pull request #110 from yaswanth-deriv/yaswanth/FEQ-1786_Added_Dialog_component
[FEQ]Yaswanth/FEQ-1786-Added_Dialog_component
2 parents 2d767a4 + ef0e1bd commit 3e38703

File tree

8 files changed

+241
-0
lines changed

8 files changed

+241
-0
lines changed

src/components/Dialog/Dialog.scss

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.deriv-dialog{
2+
min-width:440px;
3+
height:auto;
4+
padding: 10px;
5+
}

src/components/Dialog/DialogBody.tsx

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import React from "react"
2+
import { Modal } from "../Modal"
3+
4+
export const DialogBody = ({ children, className,...rest }: React.ComponentProps<typeof Modal.Body>) => {
5+
return (
6+
<Modal.Body className={className} {...rest}>
7+
{children}
8+
</Modal.Body>
9+
)
10+
}
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import React from "react"
2+
import { Modal } from "../Modal"
3+
4+
export const DialogFooter = ({ className, children,...rest }: React.ComponentProps<typeof Modal.Footer>) => {
5+
return (
6+
<Modal.Footer hideBorder className={className} {...rest}>
7+
{children}
8+
</Modal.Footer>
9+
)
10+
}
+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import React,{ ReactNode } from "react"
2+
import { Modal } from "../Modal"
3+
import { Text } from "../Text"
4+
5+
type TDialogHeaderProps = Omit<React.ComponentProps<typeof Modal.Header>,"hideBorder"> & {
6+
hideCloseIcon?: boolean;
7+
title?: ReactNode;
8+
textClassName?: string
9+
}
10+
11+
export const DialogHeader = ({ className, hideCloseIcon = true, title, textClassName,...rest }: TDialogHeaderProps) => {
12+
return (
13+
<Modal.Header hideBorder hideCloseIcon={hideCloseIcon} className={className} {...rest}>
14+
<Text as='div' weight='bold' className={textClassName}>
15+
{title}
16+
</Text>
17+
</Modal.Header>
18+
)
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import React from "react";
2+
import { render, screen } from "@testing-library/react";
3+
import userEvent from "@testing-library/user-event";
4+
import { Dialog } from "..";
5+
import { DialogHeader } from "../DialogHeader";
6+
7+
describe("Dialog component", () => {
8+
it("should render the basic dialog without header, footer and body", () => {
9+
render(
10+
<Dialog isOpen={true}>
11+
<p>This is some dialog content</p>
12+
</Dialog>,
13+
);
14+
15+
const dialog = screen.getByText("This is some dialog content");
16+
17+
expect(dialog).toBeInTheDocument();
18+
});
19+
20+
it("should render dialog header", () => {
21+
render(
22+
<Dialog isOpen={true}>
23+
<Dialog.Header hideCloseIcon={false} title={"Dialog Title"} />
24+
</Dialog>,
25+
);
26+
27+
const dialogHeader = screen.getByText("Dialog Title");
28+
const dialogCloseIcon = screen.queryByTestId("dt-close-icon");
29+
30+
expect(dialogHeader).toBeInTheDocument();
31+
expect(dialogCloseIcon).toBeDefined();
32+
});
33+
34+
it("should render the dialog header without close icon ", () => {
35+
render(
36+
<Dialog isOpen={true}>
37+
<Dialog.Header hideCloseIcon={true} title={"Dialog Title"} />
38+
</Dialog>,
39+
);
40+
41+
const dialogHeader = screen.getByText("Dialog Title");
42+
const dialogCloseIcon = screen.queryByTestId("dt-close-icon");
43+
44+
expect(dialogHeader).toBeInTheDocument();
45+
expect(dialogCloseIcon).not.toBeInTheDocument();
46+
});
47+
48+
49+
it("should render dialog Footer", () => {
50+
render(
51+
<Dialog isOpen={true}>
52+
<Dialog.Footer>Dialog Footer</Dialog.Footer>
53+
</Dialog>,
54+
);
55+
56+
const dialogFooter = screen.getByText("Dialog Footer");
57+
58+
expect(dialogFooter).toBeInTheDocument();
59+
});
60+
61+
it("should close the modal when the close button in header is clicked", async () => {
62+
render(
63+
<Dialog isOpen={true}>
64+
<DialogHeader title={" Modal Title"} hideCloseIcon={false}></DialogHeader>
65+
<Dialog.Body>
66+
<p>This is some dialog content</p>
67+
</Dialog.Body>
68+
</Dialog>,
69+
);
70+
71+
const modal = await screen.getByText("This is some dialog content");
72+
73+
const modalCloseIcon = screen.getByTestId("dt-close-icon");
74+
75+
await userEvent.click(modalCloseIcon);
76+
77+
expect(modal).toBeInTheDocument();
78+
});
79+
});

src/components/Dialog/index.tsx

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import React from "react"
2+
import clsx from "clsx"
3+
import { Modal } from "../Modal"
4+
import { DialogHeader } from "./DialogHeader"
5+
import { DialogBody } from "./DialogBody"
6+
import { DialogFooter } from "./DialogFooter"
7+
import "./Dialog.scss"
8+
9+
type TDialogProps = React.ComponentProps<typeof Modal> &{
10+
className?:string
11+
}
12+
13+
export const Dialog = ({ children,className,...rest }: TDialogProps) => {
14+
return (
15+
<Modal className={clsx("deriv-dialog",className)} {...rest}>
16+
{children}
17+
</Modal>
18+
)
19+
}
20+
21+
Dialog.Header = DialogHeader;
22+
Dialog.Body = DialogBody;
23+
Dialog.Footer = DialogFooter;
24+
Dialog.setAppElement = Modal.setAppElement;

src/main.ts

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ export { ActionScreen } from "./components/ActionScreen";
22
export { Button } from "./components/Button";
33
export { Checkbox } from "./components/Checkbox";
44
export { Divider } from "./components/Divider";
5+
export { Dialog } from "./components/Dialog"
56
export { Dropdown } from "./components/Dropdown";
67
export { InlineMessage } from "./components/InlineMessage";
78
export { Input } from "./components/Input";

stories/Dialog.stories.tsx

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import type { Meta, StoryObj } from "@storybook/react";
2+
import { Dialog } from "../src/main";
3+
import { Button } from "../src/main";
4+
5+
6+
const meta = {
7+
title: "Components/Dialog",
8+
component: Dialog,
9+
parameters: {
10+
layout: "centered",
11+
},
12+
tags: ["autodocs"],
13+
args: {
14+
children: <p>This is basic dialog</p>,
15+
isOpen:true
16+
},
17+
argTypes: {
18+
children: {
19+
description: "The content of the modal.you can use the `Dialog.Header`, `Dialog.Body`, and `Dialog.Footer` components to structure the content of the modal.",
20+
control: false
21+
},
22+
}
23+
} satisfies Meta<typeof Dialog>;
24+
25+
export default meta;
26+
type Story = StoryObj<typeof meta>;
27+
28+
export const Default: Story = {
29+
name: "Default Dialog",
30+
render : ()=>{
31+
return (
32+
<>
33+
<Dialog isOpen={true}>
34+
<Dialog.Header>title</Dialog.Header>
35+
<Dialog.Body>body</Dialog.Body>
36+
<Dialog.Footer>
37+
<Button color="black">cancel</Button>
38+
<Button>ok</Button>
39+
</Dialog.Footer>
40+
</Dialog>
41+
</>
42+
)
43+
}
44+
};
45+
46+
export const HideHeaderCloseIcon: Story = {
47+
name: "Hide Close Icon",
48+
render : ()=>{
49+
return (
50+
<>
51+
<Dialog isOpen={true}>
52+
<Dialog.Header hideCloseIcon >title</Dialog.Header>
53+
<Dialog.Body>body</Dialog.Body>
54+
<Dialog.Footer>
55+
<Button color="black">cancel</Button>
56+
<Button>ok</Button>
57+
</Dialog.Footer>
58+
</Dialog>
59+
</>
60+
)
61+
}
62+
};
63+
64+
export const NoHeader: Story = {
65+
name: "Hide Header",
66+
render : ()=>{
67+
return (
68+
<>
69+
<Dialog isOpen={true}>
70+
<Dialog.Body>body</Dialog.Body>
71+
<Dialog.Footer>
72+
<Button color="black">cancel</Button>
73+
<Button>ok</Button>
74+
</Dialog.Footer>
75+
</Dialog>
76+
</>
77+
)
78+
}
79+
};
80+
81+
export const NoFooter: Story = {
82+
name: "Hide Footer",
83+
render : ()=>{
84+
return (
85+
<>
86+
<Dialog isOpen={true}>
87+
<Dialog.Header>title</Dialog.Header>
88+
<Dialog.Body>body</Dialog.Body>
89+
</Dialog>
90+
</>
91+
)
92+
}
93+
};

0 commit comments

Comments
 (0)