@pautena/react-design-system 0.4.8 → 0.5.1

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.
Files changed (126) hide show
  1. package/dist/cjs/index.js +4 -4
  2. package/dist/cjs/index.js.map +1 -1
  3. package/dist/cjs/types/components/alerts/expandable-alert/expandable-alert.d.ts +11 -0
  4. package/dist/cjs/types/components/alerts/expandable-alert/index.d.ts +1 -0
  5. package/dist/cjs/types/components/alerts/index.d.ts +1 -0
  6. package/dist/cjs/types/components/data-display/board/board.d.ts +10 -0
  7. package/dist/cjs/types/components/data-display/board/index.d.ts +1 -0
  8. package/dist/cjs/types/components/data-display/index.d.ts +2 -0
  9. package/dist/cjs/types/components/data-display/markdown/index.d.ts +1 -0
  10. package/dist/cjs/types/components/data-display/markdown/markdown.d.ts +7 -0
  11. package/dist/cjs/types/components/dialogs/bootstrap-dialog/bootstrap-dialog.d.ts +2 -0
  12. package/dist/cjs/types/components/dialogs/bootstrap-dialog/index.d.ts +1 -0
  13. package/dist/cjs/types/components/dialogs/confirm-dialog/confirm-dialog.d.ts +10 -0
  14. package/dist/cjs/types/components/dialogs/confirm-dialog/index.d.ts +1 -0
  15. package/dist/cjs/types/components/dialogs/dialog-hooks/index.d.ts +1 -0
  16. package/dist/cjs/types/components/dialogs/dialog-hooks/use-dialog.d.ts +7 -0
  17. package/dist/cjs/types/components/dialogs/dialog.types.d.ts +26 -0
  18. package/dist/cjs/types/components/dialogs/form-dialog/form-dialog.d.ts +10 -0
  19. package/dist/cjs/types/components/dialogs/form-dialog/index.d.ts +1 -0
  20. package/dist/cjs/types/components/dialogs/index.d.ts +5 -0
  21. package/dist/cjs/types/components/index.d.ts +2 -0
  22. package/dist/cjs/types/components/inputs/enhanced-autocomplete/enhanced-autocomplete.d.ts +10 -0
  23. package/dist/cjs/types/components/inputs/enhanced-autocomplete/index.d.ts +1 -0
  24. package/dist/cjs/types/components/inputs/enhanced-text-field/enhanced-text-field.d.ts +7 -0
  25. package/dist/cjs/types/components/inputs/enhanced-text-field/index.d.ts +1 -0
  26. package/dist/cjs/types/components/inputs/index.d.ts +1 -0
  27. package/dist/cjs/types/components/inputs/search-input/index.d.ts +1 -0
  28. package/dist/cjs/types/components/inputs/search-input/search-input.d.ts +19 -0
  29. package/dist/cjs/types/utils/forms.d.ts +2 -0
  30. package/dist/esm/index.js +4 -4
  31. package/dist/esm/index.js.map +1 -1
  32. package/dist/esm/types/components/alerts/expandable-alert/expandable-alert.d.ts +11 -0
  33. package/dist/esm/types/components/alerts/expandable-alert/index.d.ts +1 -0
  34. package/dist/esm/types/components/alerts/index.d.ts +1 -0
  35. package/dist/esm/types/components/data-display/board/board.d.ts +10 -0
  36. package/dist/esm/types/components/data-display/board/index.d.ts +1 -0
  37. package/dist/esm/types/components/data-display/index.d.ts +2 -0
  38. package/dist/esm/types/components/data-display/markdown/index.d.ts +1 -0
  39. package/dist/esm/types/components/data-display/markdown/markdown.d.ts +7 -0
  40. package/dist/esm/types/components/dialogs/bootstrap-dialog/bootstrap-dialog.d.ts +2 -0
  41. package/dist/esm/types/components/dialogs/bootstrap-dialog/index.d.ts +1 -0
  42. package/dist/esm/types/components/dialogs/confirm-dialog/confirm-dialog.d.ts +10 -0
  43. package/dist/esm/types/components/dialogs/confirm-dialog/index.d.ts +1 -0
  44. package/dist/esm/types/components/dialogs/dialog-hooks/index.d.ts +1 -0
  45. package/dist/esm/types/components/dialogs/dialog-hooks/use-dialog.d.ts +7 -0
  46. package/dist/esm/types/components/dialogs/dialog.types.d.ts +26 -0
  47. package/dist/esm/types/components/dialogs/form-dialog/form-dialog.d.ts +10 -0
  48. package/dist/esm/types/components/dialogs/form-dialog/index.d.ts +1 -0
  49. package/dist/esm/types/components/dialogs/index.d.ts +5 -0
  50. package/dist/esm/types/components/index.d.ts +2 -0
  51. package/dist/esm/types/components/inputs/enhanced-autocomplete/enhanced-autocomplete.d.ts +10 -0
  52. package/dist/esm/types/components/inputs/enhanced-autocomplete/index.d.ts +1 -0
  53. package/dist/esm/types/components/inputs/enhanced-text-field/enhanced-text-field.d.ts +7 -0
  54. package/dist/esm/types/components/inputs/enhanced-text-field/index.d.ts +1 -0
  55. package/dist/esm/types/components/inputs/index.d.ts +1 -0
  56. package/dist/esm/types/components/inputs/search-input/index.d.ts +1 -0
  57. package/dist/esm/types/components/inputs/search-input/search-input.d.ts +19 -0
  58. package/dist/esm/types/utils/forms.d.ts +2 -0
  59. package/dist/index.d.ts +95 -6
  60. package/package.json +34 -32
  61. package/src/components/alerts/alerts.stories.mdx +10 -0
  62. package/src/components/alerts/expandable-alert/expandable-alert.stories.tsx +48 -0
  63. package/src/components/alerts/expandable-alert/expandable-alert.test.tsx +114 -0
  64. package/src/components/alerts/expandable-alert/expandable-alert.tsx +71 -0
  65. package/src/components/alerts/expandable-alert/index.ts +1 -0
  66. package/src/components/alerts/index.ts +1 -0
  67. package/src/components/components.stories.mdx +2 -0
  68. package/src/components/data-display/board/board.stories.tsx +54 -0
  69. package/src/components/data-display/board/board.test.tsx +100 -0
  70. package/src/components/data-display/board/board.tsx +63 -0
  71. package/src/components/data-display/board/index.ts +1 -0
  72. package/src/components/data-display/data-display.stories.mdx +2 -0
  73. package/src/components/data-display/index.ts +2 -0
  74. package/src/components/data-display/markdown/index.ts +1 -0
  75. package/src/components/data-display/markdown/markdown.stories.tsx +25 -0
  76. package/src/components/data-display/markdown/markdown.test.tsx +64 -0
  77. package/src/components/data-display/markdown/markdown.tsx +38 -0
  78. package/src/components/dialogs/bootstrap-dialog/bootstrap-dialog.stories.tsx +81 -0
  79. package/src/components/dialogs/bootstrap-dialog/bootstrap-dialog.test.tsx +233 -0
  80. package/src/components/dialogs/bootstrap-dialog/bootstrap-dialog.tsx +95 -0
  81. package/src/components/dialogs/bootstrap-dialog/index.ts +1 -0
  82. package/src/components/dialogs/confirm-dialog/confirm-dialog.stories.tsx +43 -0
  83. package/src/components/dialogs/confirm-dialog/confirm-dialog.test.tsx +150 -0
  84. package/src/components/dialogs/confirm-dialog/confirm-dialog.tsx +51 -0
  85. package/src/components/dialogs/confirm-dialog/index.ts +1 -0
  86. package/src/components/dialogs/dialog-hooks/index.ts +1 -0
  87. package/src/components/dialogs/dialog-hooks/use-dialog.ts +10 -0
  88. package/src/components/dialogs/dialog.types.ts +27 -0
  89. package/src/components/dialogs/dialogs.stories.mdx +12 -0
  90. package/src/components/dialogs/form-dialog/form-dialog.stories.tsx +52 -0
  91. package/src/components/dialogs/form-dialog/form-dialog.test.tsx +164 -0
  92. package/src/components/dialogs/form-dialog/form-dialog.tsx +63 -0
  93. package/src/components/dialogs/form-dialog/index.ts +1 -0
  94. package/src/components/dialogs/index.ts +5 -0
  95. package/src/components/index.ts +2 -0
  96. package/src/components/inputs/enhanced-autocomplete/enhanced-autocomplete.stories.tsx +109 -0
  97. package/src/components/inputs/enhanced-autocomplete/enhanced-autocomplete.test.tsx +74 -0
  98. package/src/components/inputs/enhanced-autocomplete/enhanced-autocomplete.tsx +64 -0
  99. package/src/components/inputs/enhanced-autocomplete/index.ts +1 -0
  100. package/src/components/inputs/enhanced-text-field/enhanced-text-field.stories.tsx +120 -0
  101. package/src/components/inputs/enhanced-text-field/enhanced-text-field.test.tsx +63 -0
  102. package/src/components/inputs/enhanced-text-field/enhanced-text-field.tsx +101 -0
  103. package/src/components/inputs/enhanced-text-field/index.ts +1 -0
  104. package/src/components/inputs/index.ts +1 -0
  105. package/src/components/inputs/inputs.stories.mdx +3 -0
  106. package/src/components/inputs/search-input/index.ts +1 -0
  107. package/src/components/inputs/search-input/search-input.stories.tsx +57 -0
  108. package/src/components/inputs/search-input/search-input.test.tsx +165 -0
  109. package/src/components/inputs/search-input/search-input.tsx +218 -0
  110. package/src/components/value-displays/value-datetime/value-datetime.test.tsx +17 -8
  111. package/src/components/value-displays/value-datetime/value-datetime.tsx +23 -20
  112. package/src/components/value-displays/value-rating/value-rating.tsx +1 -1
  113. package/src/components/value-displays/value-text/value-text.tsx +1 -1
  114. package/src/generators/generators.mock.ts +3 -14
  115. package/src/generators/model-form/model-form.tsx +3 -6
  116. package/src/storybook.tsx +51 -4
  117. package/src/tests/actions.ts +2 -1
  118. package/src/tests/assertions.ts +50 -5
  119. package/src/tests/datatable-placeholder/datatable-placeholder.tsx +2 -4
  120. package/src/tests/mocks/markdown.mock.ts +25 -0
  121. package/src/types/index.d.ts +6 -0
  122. package/src/utils/forms.ts +11 -0
  123. package/dist/cjs/types/generators/generators.model.test.d.ts +0 -1
  124. package/dist/cjs/types/utils/arrays.test.d.ts +0 -1
  125. package/dist/esm/types/generators/generators.model.test.d.ts +0 -1
  126. package/dist/esm/types/utils/arrays.test.d.ts +0 -1
@@ -0,0 +1,233 @@
1
+ import { DialogContentText } from "@mui/material";
2
+ import React from "react";
3
+ import { render, screen } from "~/tests/testing-library";
4
+ import { BootstrapDialog } from "./bootstrap-dialog";
5
+ import userEvent from "@testing-library/user-event";
6
+ import { DialogAction } from "../dialog.types";
7
+
8
+ interface DialogRenderArgs {
9
+ open: boolean;
10
+ disabled?: boolean;
11
+ cancelable?: boolean;
12
+ acceptable?: boolean;
13
+ callCloseWhenCancel?: boolean;
14
+ actions?: DialogAction[];
15
+ acceptText?: string;
16
+ cancelText?: string;
17
+ loading?: boolean;
18
+ }
19
+
20
+ describe("BootstrapDialog", () => {
21
+ const createMockActions = () => {
22
+ const onClickAction1 = jest.fn();
23
+ const onClickAction2 = jest.fn();
24
+ const actions: DialogAction[] = [
25
+ {
26
+ id: "action1",
27
+ text: "Action 1",
28
+ color: "error",
29
+ onClick: onClickAction1,
30
+ },
31
+ {
32
+ id: "action2",
33
+ text: "Action 2",
34
+ onClick: onClickAction2,
35
+ },
36
+ ];
37
+ return { actions, onClickAction1, onClickAction2 };
38
+ };
39
+
40
+ const renderComponent = ({
41
+ open,
42
+ disabled,
43
+ cancelable,
44
+ acceptable,
45
+ callCloseWhenCancel,
46
+ acceptText,
47
+ cancelText,
48
+ actions,
49
+ loading,
50
+ }: DialogRenderArgs) => {
51
+ const onClose = jest.fn();
52
+ const onCancel = jest.fn();
53
+ const onAccept = jest.fn();
54
+
55
+ render(
56
+ <BootstrapDialog
57
+ open={open}
58
+ disabled={disabled}
59
+ cancelable={cancelable}
60
+ acceptable={acceptable}
61
+ callCloseWhenCancel={callCloseWhenCancel}
62
+ actions={actions}
63
+ title="lorem ipsum"
64
+ onClose={onClose}
65
+ onCancel={onCancel}
66
+ onAccept={onAccept}
67
+ cancelText={cancelText}
68
+ acceptText={acceptText}
69
+ loading={loading}
70
+ >
71
+ <DialogContentText>This is the content</DialogContentText>
72
+ </BootstrapDialog>,
73
+ );
74
+
75
+ return { onClose, onCancel, onAccept };
76
+ };
77
+
78
+ it("should render the dialog if open is true", () => {
79
+ renderComponent({ open: true });
80
+
81
+ expect(screen.getByRole("dialog")).toBeVisible();
82
+ });
83
+
84
+ it("shouldn't render the dialog if open is false", () => {
85
+ renderComponent({ open: false });
86
+
87
+ expect(screen.queryByRole("dialog")).not.toBeInTheDocument();
88
+ });
89
+
90
+ it("should render the title", () => {
91
+ renderComponent({ open: true });
92
+
93
+ expect(screen.getByText("lorem ipsum")).toBeVisible();
94
+ });
95
+
96
+ it("should render the children content", () => {
97
+ renderComponent({ open: true });
98
+
99
+ expect(screen.getByText(/this is the content/i)).toBeVisible();
100
+ });
101
+
102
+ it("should call onClose if the close button is clicked", async () => {
103
+ const { onClose } = renderComponent({ open: true });
104
+
105
+ await userEvent.click(screen.getByRole("button", { name: "close" }));
106
+
107
+ expect(onClose).toHaveBeenCalledTimes(1);
108
+ });
109
+
110
+ describe("disabled", () => {
111
+ it("should have the close button as disabled", () => {
112
+ renderComponent({ open: true, disabled: true });
113
+
114
+ expect(screen.getByRole("button", { name: "close" })).toBeDisabled();
115
+ });
116
+
117
+ it("should have the Cancel button as disabled", () => {
118
+ renderComponent({ open: true, disabled: true, cancelable: true });
119
+
120
+ expect(screen.getByRole("button", { name: /cancel/i })).toBeDisabled();
121
+ });
122
+
123
+ it("should have the accept button as disabled", () => {
124
+ renderComponent({ open: true, disabled: true, acceptable: true });
125
+
126
+ expect(screen.getByRole("button", { name: /accept/i })).toBeDisabled();
127
+ });
128
+
129
+ it("should have the actions button as disabled", () => {
130
+ const { actions } = createMockActions();
131
+ renderComponent({ open: true, disabled: true, actions });
132
+
133
+ expect(screen.getByRole("button", { name: /action 1/i })).toBeDisabled();
134
+ expect(screen.getByRole("button", { name: /action 2/i })).toBeDisabled();
135
+ });
136
+ });
137
+
138
+ it("should be able to change the cancel button text", () => {
139
+ renderComponent({ open: true, cancelable: true, cancelText: "updated cancel" });
140
+
141
+ expect(screen.getByRole("button", { name: /updated cancel/i })).toBeVisible();
142
+ });
143
+
144
+ it("should be able to change the accept button text", () => {
145
+ renderComponent({ open: true, acceptable: true, acceptText: "updated accept" });
146
+
147
+ expect(screen.getByRole("button", { name: /updated accept/i })).toBeVisible();
148
+ });
149
+
150
+ it("should call onCancel if the cancel button is clicked", async () => {
151
+ const { onCancel } = renderComponent({ open: true, cancelable: true });
152
+
153
+ await userEvent.click(screen.getByRole("button", { name: /cancel/i }));
154
+
155
+ expect(onCancel).toHaveBeenCalledTimes(1);
156
+ });
157
+
158
+ it("should call onAccept if the accept button is clicked", async () => {
159
+ const { onAccept } = renderComponent({ open: true, acceptable: true });
160
+
161
+ await userEvent.click(screen.getByRole("button", { name: /accept/i }));
162
+
163
+ expect(onAccept).toHaveBeenCalledTimes(1);
164
+ });
165
+
166
+ describe("callCloseWhenCancel", () => {
167
+ it("should call onClose when call cancel if is true", async () => {
168
+ const { onClose } = renderComponent({
169
+ open: true,
170
+ cancelable: true,
171
+ callCloseWhenCancel: true,
172
+ });
173
+
174
+ await userEvent.click(screen.getByRole("button", { name: /cancel/i }));
175
+
176
+ expect(onClose).toHaveBeenCalledTimes(1);
177
+ });
178
+
179
+ it("shouln't call onClose when call cancel if is false", async () => {
180
+ const { onClose } = renderComponent({
181
+ open: true,
182
+ cancelable: true,
183
+ callCloseWhenCancel: false,
184
+ });
185
+
186
+ await userEvent.click(screen.getByRole("button", { name: /cancel/i }));
187
+
188
+ expect(onClose).not.toHaveBeenCalled();
189
+ });
190
+ });
191
+
192
+ describe("actions", () => {
193
+ it("should render a button for each action", () => {
194
+ const { actions } = createMockActions();
195
+ renderComponent({ open: true, cancelable: true, callCloseWhenCancel: false, actions });
196
+
197
+ expect(screen.getByRole("button", { name: /action 1/i })).toBeVisible();
198
+ expect(screen.getByRole("button", { name: /action 2/i })).toBeVisible();
199
+ });
200
+
201
+ it("should call the action 1 click listener if the action 1 is clicked", async () => {
202
+ const { actions, onClickAction1 } = createMockActions();
203
+ renderComponent({ open: true, cancelable: true, callCloseWhenCancel: false, actions });
204
+
205
+ await userEvent.click(screen.getByRole("button", { name: /action 1/i }));
206
+
207
+ expect(onClickAction1).toHaveBeenCalledTimes(1);
208
+ });
209
+
210
+ it("should call the action 1 click listener if the action 2 is clicked", async () => {
211
+ const { actions, onClickAction2 } = createMockActions();
212
+ renderComponent({ open: true, cancelable: true, callCloseWhenCancel: false, actions });
213
+
214
+ await userEvent.click(screen.getByRole("button", { name: /action 2/i }));
215
+
216
+ expect(onClickAction2).toHaveBeenCalledTimes(1);
217
+ });
218
+ });
219
+
220
+ describe("loading", () => {
221
+ it("should render a loading indicator if acceptable is true and loading is true", () => {
222
+ renderComponent({ open: true, acceptable: true, loading: true });
223
+
224
+ expect(screen.getByRole("progressbar")).toBeVisible();
225
+ });
226
+
227
+ it("should render a loading indicator if acceptable is false and loading is true", () => {
228
+ renderComponent({ open: true, acceptable: false, loading: true });
229
+
230
+ expect(screen.getByRole("progressbar")).toBeVisible();
231
+ });
232
+ });
233
+ });
@@ -0,0 +1,95 @@
1
+ import {
2
+ Dialog,
3
+ DialogTitle,
4
+ DialogActions,
5
+ Button,
6
+ IconButton,
7
+ DialogContent,
8
+ Box,
9
+ CircularProgress,
10
+ } from "@mui/material";
11
+ import { LoadingButton } from "@mui/lab";
12
+ import CloseIcon from "@mui/icons-material/Close";
13
+ import React from "react";
14
+ import { BootstrapDialogDialogProps } from "../dialog.types";
15
+
16
+ export const BootstrapDialog = ({
17
+ open,
18
+ title,
19
+ component,
20
+ componentProps = {},
21
+ disabled,
22
+ actions = [],
23
+ children,
24
+ loading,
25
+ cancelable,
26
+ callCloseWhenCancel = true,
27
+ acceptable,
28
+ acceptText = "Accept",
29
+ cancelText = "Cancel",
30
+ onAccept,
31
+ onCancel = () => null,
32
+ onClose,
33
+ acceptType = "button",
34
+ }: BootstrapDialogDialogProps) => {
35
+ const hasActions = actions.length > 0 || acceptable || cancelable;
36
+
37
+ return (
38
+ <Dialog open={open} onClose={onClose}>
39
+ <DialogTitle sx={{ display: "flex", alignItems: "center" }}>
40
+ {title}
41
+ {loading && !acceptable && (
42
+ <CircularProgress size={20} sx={{ ml: 2, color: (theme) => theme.palette.grey[500] }} />
43
+ )}
44
+ <IconButton
45
+ disabled={disabled}
46
+ aria-label="close"
47
+ onClick={onClose}
48
+ sx={{
49
+ position: "absolute",
50
+ right: 8,
51
+ top: 8,
52
+ color: (theme) => theme.palette.grey[500],
53
+ }}
54
+ >
55
+ <CloseIcon />
56
+ </IconButton>
57
+ </DialogTitle>
58
+ <Box component={component} {...componentProps}>
59
+ <DialogContent dividers>{children}</DialogContent>
60
+ {hasActions && (
61
+ <DialogActions>
62
+ {actions.map(({ id, text, type = "button", onClick, color = "primary" }) => (
63
+ <Button key={id} type={type} disabled={disabled} onClick={onClick} color={color}>
64
+ {text}
65
+ </Button>
66
+ ))}
67
+ {cancelable && (
68
+ <Button
69
+ color="error"
70
+ disabled={disabled}
71
+ onClick={() => {
72
+ onCancel();
73
+ callCloseWhenCancel && onClose();
74
+ }}
75
+ >
76
+ {cancelText}
77
+ </Button>
78
+ )}
79
+
80
+ {acceptable && (
81
+ <LoadingButton
82
+ type={acceptType}
83
+ loading={loading}
84
+ disabled={disabled}
85
+ onClick={onAccept}
86
+ >
87
+ {acceptText}
88
+ </LoadingButton>
89
+ )}
90
+ </DialogActions>
91
+ )}
92
+ </Box>
93
+ </Dialog>
94
+ );
95
+ };
@@ -0,0 +1 @@
1
+ export * from "./bootstrap-dialog";
@@ -0,0 +1,43 @@
1
+ import { DialogContentText } from "@mui/material";
2
+ import { ComponentMeta, ComponentStory } from "@storybook/react";
3
+ import { loremIpsum } from "lorem-ipsum";
4
+ import React from "react";
5
+ import { StoryDialogManager } from "~/storybook";
6
+ import { ConfirmDialog } from "./confirm-dialog";
7
+
8
+ export default {
9
+ title: "Components/Dialogs/ConfirmDialog",
10
+ component: ConfirmDialog,
11
+ parameters: {
12
+ layout: "centered",
13
+ },
14
+ } as ComponentMeta<typeof ConfirmDialog>;
15
+
16
+ const Template: ComponentStory<typeof ConfirmDialog> = (args) => (
17
+ <StoryDialogManager component={ConfirmDialog} args={args} />
18
+ );
19
+ export const Default = Template.bind({});
20
+ Default.args = {
21
+ open: true,
22
+ title: "Lorem ipsum",
23
+ children: <DialogContentText>{loremIpsum({ count: 1, units: "paragraph" })}</DialogContentText>,
24
+ };
25
+
26
+ export const Loading = Template.bind({});
27
+ Loading.args = {
28
+ ...Default.args,
29
+ loading: true,
30
+ };
31
+
32
+ export const Disabled = Template.bind({});
33
+ Disabled.args = {
34
+ ...Default.args,
35
+ disabled: true,
36
+ };
37
+
38
+ export const CustomButtonText = Template.bind({});
39
+ CustomButtonText.args = {
40
+ ...Default.args,
41
+ confirmText: "Create token",
42
+ cancelText: "Don't create a token",
43
+ };
@@ -0,0 +1,150 @@
1
+ import { DialogContentText } from "@mui/material";
2
+ import React from "react";
3
+ import { render, screen } from "~/tests/testing-library";
4
+ import { ConfirmDialog } from "./confirm-dialog";
5
+ import userEvent from "@testing-library/user-event";
6
+
7
+ interface DialogRenderArgs {
8
+ open: boolean;
9
+ disabled?: boolean;
10
+ confirmText?: string;
11
+ cancelText?: string;
12
+ loading?: boolean;
13
+ content?: string | string[];
14
+ }
15
+
16
+ describe("ConfirmDialog", () => {
17
+ const renderComponent = ({
18
+ open,
19
+ disabled,
20
+ confirmText,
21
+ cancelText,
22
+ loading,
23
+ }: DialogRenderArgs) => {
24
+ const onCancel = jest.fn();
25
+ const onConfirm = jest.fn();
26
+
27
+ render(
28
+ <ConfirmDialog
29
+ open={open}
30
+ disabled={disabled}
31
+ loading={loading}
32
+ title="lorem ipsum"
33
+ onCancel={onCancel}
34
+ onConfirm={onConfirm}
35
+ cancelText={cancelText}
36
+ confirmText={confirmText}
37
+ >
38
+ <DialogContentText>This is the content</DialogContentText>
39
+ </ConfirmDialog>,
40
+ );
41
+
42
+ return { onCancel, onConfirm };
43
+ };
44
+
45
+ it("should render the dialog if open is true", () => {
46
+ renderComponent({ open: true });
47
+
48
+ expect(screen.getByRole("dialog")).toBeVisible();
49
+ });
50
+
51
+ it("shouldn't render the dialog if open is false", () => {
52
+ renderComponent({ open: false });
53
+
54
+ expect(screen.queryByRole("dialog")).not.toBeInTheDocument();
55
+ });
56
+
57
+ it("should render the title", () => {
58
+ renderComponent({ open: true });
59
+
60
+ expect(screen.getByText("lorem ipsum")).toBeVisible();
61
+ });
62
+
63
+ it("should render the children content", () => {
64
+ renderComponent({ open: true });
65
+
66
+ expect(screen.getByText(/this is the content/i)).toBeVisible();
67
+ });
68
+
69
+ it("should call onCancel if the close button is clicked", async () => {
70
+ const { onCancel } = renderComponent({ open: true });
71
+
72
+ await userEvent.click(screen.getByRole("button", { name: "close" }));
73
+
74
+ expect(onCancel).toHaveBeenCalledTimes(1);
75
+ });
76
+
77
+ it("should call onCancel if the cancel button is clicked", async () => {
78
+ const { onCancel } = renderComponent({ open: true });
79
+
80
+ await userEvent.click(screen.getByRole("button", { name: /cancel/i }));
81
+
82
+ expect(onCancel).toHaveBeenCalledTimes(1);
83
+ });
84
+
85
+ it("should call onConfirm if the confirm button is clicked", async () => {
86
+ const { onConfirm } = renderComponent({ open: true });
87
+
88
+ await userEvent.click(screen.getByRole("button", { name: /confirm/i }));
89
+
90
+ expect(onConfirm).toHaveBeenCalledTimes(1);
91
+ });
92
+
93
+ describe("disabled", () => {
94
+ it("should have the close button as disabled", () => {
95
+ renderComponent({ open: true, disabled: true });
96
+
97
+ expect(screen.getByRole("button", { name: "close" })).toBeDisabled();
98
+ });
99
+
100
+ it("should have the Cancel button as disabled", () => {
101
+ renderComponent({ open: true, disabled: true });
102
+
103
+ expect(screen.getByRole("button", { name: /cancel/i })).toBeDisabled();
104
+ });
105
+
106
+ it("should have the confirm button as disabled", () => {
107
+ renderComponent({ open: true, disabled: true });
108
+
109
+ expect(screen.getByRole("button", { name: /confirm/i })).toBeDisabled();
110
+ });
111
+ });
112
+
113
+ it("should be able to change the cancel button text", () => {
114
+ renderComponent({ open: true, cancelText: "updated cancel" });
115
+
116
+ expect(screen.getByRole("button", { name: /updated cancel/i })).toBeVisible();
117
+ });
118
+
119
+ it("should be able to change the confirm button text", () => {
120
+ renderComponent({ open: true, confirmText: "updated confirm" });
121
+
122
+ expect(screen.getByRole("button", { name: /updated confirm/i })).toBeVisible();
123
+ });
124
+
125
+ describe("loading", () => {
126
+ it("should render a loading indicator if is true", async () => {
127
+ renderComponent({ open: true, loading: true });
128
+
129
+ expect(screen.getByRole("progressbar")).toBeVisible();
130
+ });
131
+
132
+ it("should have the close button as disabled", () => {
133
+ renderComponent({ open: true, loading: true });
134
+
135
+ expect(screen.getByRole("button", { name: "close" })).toBeDisabled();
136
+ });
137
+
138
+ it("should have the Cancel button as disabled", () => {
139
+ renderComponent({ open: true, loading: true });
140
+
141
+ expect(screen.getByRole("button", { name: /cancel/i })).toBeDisabled();
142
+ });
143
+
144
+ it("should have the confirm button as disabled", () => {
145
+ renderComponent({ open: true, loading: true });
146
+
147
+ expect(screen.getByRole("button", { name: /confirm/i })).toBeDisabled();
148
+ });
149
+ });
150
+ });
@@ -0,0 +1,51 @@
1
+ import React from "react";
2
+ import { BootstrapDialog } from "../bootstrap-dialog";
3
+ import { BootstrapDialogDialogProps } from "../dialog.types";
4
+
5
+ type OmitBaseDialogProps =
6
+ | "cancelable"
7
+ | "acceptable"
8
+ | "onAccept"
9
+ | "onCancel"
10
+ | "onClose"
11
+ | "actions"
12
+ | "callCloseWhenCancel"
13
+ | "component"
14
+ | "acceptType";
15
+ export interface ConfirmDialogProps extends Omit<BootstrapDialogDialogProps, OmitBaseDialogProps> {
16
+ confirmText?: string;
17
+ canceText?: string;
18
+ onCancel: () => void;
19
+ onConfirm: () => void;
20
+ }
21
+
22
+ export const ConfirmDialog = ({
23
+ open,
24
+ title,
25
+ loading,
26
+ disabled,
27
+ confirmText = "Confirm",
28
+ cancelText = "Cancel",
29
+ children,
30
+ onConfirm,
31
+ onCancel,
32
+ }: ConfirmDialogProps) => {
33
+ return (
34
+ <BootstrapDialog
35
+ title={title}
36
+ loading={loading}
37
+ disabled={loading || disabled}
38
+ open={open}
39
+ onClose={onCancel}
40
+ acceptable
41
+ cancelable
42
+ callCloseWhenCancel={false}
43
+ acceptText={confirmText}
44
+ cancelText={cancelText}
45
+ onCancel={onCancel}
46
+ onAccept={onConfirm}
47
+ >
48
+ {children}
49
+ </BootstrapDialog>
50
+ );
51
+ };
@@ -0,0 +1 @@
1
+ export * from "./confirm-dialog";
@@ -0,0 +1 @@
1
+ export * from "./use-dialog";
@@ -0,0 +1,10 @@
1
+ import { useState } from "react";
2
+
3
+ export const useDialog = (intialOpen = false) => {
4
+ const [isOpen, setIsOpen] = useState(intialOpen);
5
+
6
+ const open = () => setIsOpen(true);
7
+ const close = () => setIsOpen(false);
8
+
9
+ return { isOpen, open, close, setIsOpen };
10
+ };
@@ -0,0 +1,27 @@
1
+ import { PropsWithChildren } from "react";
2
+
3
+ export interface DialogAction {
4
+ id: string;
5
+ text: string;
6
+ type?: "button" | "submit";
7
+ color?: "inherit" | "primary" | "secondary" | "success" | "error" | "info" | "warning";
8
+ onClick?: () => void;
9
+ }
10
+ export type BootstrapDialogDialogProps = PropsWithChildren<{
11
+ open: boolean;
12
+ title: string;
13
+ loading?: boolean;
14
+ disabled?: boolean;
15
+ cancelable?: boolean;
16
+ acceptable?: boolean;
17
+ callCloseWhenCancel?: boolean;
18
+ actions?: DialogAction[];
19
+ cancelText?: string;
20
+ acceptText?: string;
21
+ acceptType?: "button" | "submit";
22
+ onClose: () => void;
23
+ onCancel?: () => void;
24
+ onAccept?: () => void;
25
+ component?: React.ElementType;
26
+ componentProps?: any;
27
+ }>;
@@ -0,0 +1,12 @@
1
+ import { Meta } from '@storybook/addon-docs';
2
+ import LinkTo from '@storybook/addon-links/react';
3
+
4
+ <Meta title="Components/Drawers/Introduction" />
5
+
6
+ # Drawers
7
+
8
+ <ul>
9
+ <li><LinkTo kind="Components/Dialogs/ConfirmDialog">ConfirmDialog</LinkTo></li>
10
+ <li><LinkTo kind="Components/Dialogs/FormDialog">FormDialog</LinkTo></li>
11
+ <li><LinkTo kind="Components/Dialogs/BootstrapDialog">BootstrapDialog</LinkTo></li>
12
+ </ul>
@@ -0,0 +1,52 @@
1
+ import { Grid, TextField } from "@mui/material";
2
+ import { ComponentMeta, ComponentStory } from "@storybook/react";
3
+ import React from "react";
4
+ import { StoryDialogManager } from "~/storybook";
5
+ import { FormDialog } from "./form-dialog";
6
+
7
+ export default {
8
+ title: "Components/Dialogs/FormDialog",
9
+ component: FormDialog,
10
+ parameters: {
11
+ layout: "centered",
12
+ },
13
+ } as ComponentMeta<typeof FormDialog>;
14
+
15
+ const Template: ComponentStory<typeof FormDialog> = (args) => (
16
+ <StoryDialogManager component={FormDialog} args={args} />
17
+ );
18
+
19
+ export const Default = Template.bind({});
20
+ Default.args = {
21
+ open: true,
22
+ title: "Lorem ipsum",
23
+ children: (
24
+ <Grid container spacing={2}>
25
+ <Grid item xs={12}>
26
+ <TextField name="message" label="Message" fullWidth required variant="outlined" />
27
+ </Grid>
28
+ <Grid item xs={12}>
29
+ <TextField name="amount" label="Amount" fullWidth required variant="outlined" />
30
+ </Grid>
31
+ </Grid>
32
+ ),
33
+ };
34
+
35
+ export const Loading = Template.bind({});
36
+ Loading.args = {
37
+ ...Default.args,
38
+ loading: true,
39
+ };
40
+
41
+ export const Disabled = Template.bind({});
42
+ Disabled.args = {
43
+ ...Default.args,
44
+ disabled: true,
45
+ };
46
+
47
+ export const CustomButtonText = Template.bind({});
48
+ CustomButtonText.args = {
49
+ ...Default.args,
50
+ submitText: "Create token",
51
+ cancelText: "Don't create a token",
52
+ };