@fpkit/acss 0.5.11 → 0.5.13
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/README.md +514 -18
- package/libs/chunk-23ANBDCR.js +8 -0
- package/libs/chunk-23ANBDCR.js.map +1 -0
- package/libs/chunk-2LTJ7HHX.cjs +18 -0
- package/libs/chunk-2LTJ7HHX.cjs.map +1 -0
- package/libs/chunk-2Y7W75TT.js +9 -0
- package/libs/chunk-2Y7W75TT.js.map +1 -0
- package/libs/chunk-3MKLDCKQ.cjs +31 -0
- package/libs/chunk-3MKLDCKQ.cjs.map +1 -0
- package/libs/chunk-5M57K4SW.js +8 -0
- package/libs/chunk-5M57K4SW.js.map +1 -0
- package/libs/chunk-5S4ORA4C.cjs +15 -0
- package/libs/chunk-5S4ORA4C.cjs.map +1 -0
- package/libs/chunk-772NRB75.js +9 -0
- package/libs/chunk-772NRB75.js.map +1 -0
- package/libs/chunk-AHDJGCG5.cjs +15 -0
- package/libs/chunk-AHDJGCG5.cjs.map +1 -0
- package/libs/chunk-B7F5FS6D.cjs +16 -0
- package/libs/chunk-B7F5FS6D.cjs.map +1 -0
- package/libs/chunk-BHRQBJRY.js +8 -0
- package/libs/chunk-BHRQBJRY.js.map +1 -0
- package/libs/chunk-D4YLRWAO.cjs +18 -0
- package/libs/chunk-D4YLRWAO.cjs.map +1 -0
- package/libs/chunk-ETFLFC2S.js +10 -0
- package/libs/chunk-ETFLFC2S.js.map +1 -0
- package/libs/chunk-G55UJ53G.cjs +16 -0
- package/libs/chunk-G55UJ53G.cjs.map +1 -0
- package/libs/chunk-GZ4QFPRY.js +9 -0
- package/libs/chunk-GZ4QFPRY.js.map +1 -0
- package/libs/chunk-IYUN2EW3.cjs +15 -0
- package/libs/chunk-IYUN2EW3.cjs.map +1 -0
- package/libs/chunk-J32EZPYD.cjs +15 -0
- package/libs/chunk-J32EZPYD.cjs.map +1 -0
- package/libs/chunk-JJ43O4Y5.js +8 -0
- package/libs/chunk-JJ43O4Y5.js.map +1 -0
- package/libs/chunk-KUKIVRC2.js +7 -0
- package/libs/chunk-KUKIVRC2.js.map +1 -0
- package/libs/chunk-L75OQKEI.cjs +13 -0
- package/libs/chunk-L75OQKEI.cjs.map +1 -0
- package/libs/chunk-LT5KZ2QW.cjs +22 -0
- package/libs/chunk-LT5KZ2QW.cjs.map +1 -0
- package/libs/chunk-M5RRNTVX.cjs +15 -0
- package/libs/chunk-M5RRNTVX.cjs.map +1 -0
- package/libs/chunk-NGTJDDFO.js +8 -0
- package/libs/chunk-NGTJDDFO.js.map +1 -0
- package/libs/chunk-OK5QEIMD.cjs +17 -0
- package/libs/chunk-OK5QEIMD.cjs.map +1 -0
- package/libs/chunk-P2DC76ZZ.cjs +18 -0
- package/libs/chunk-P2DC76ZZ.cjs.map +1 -0
- package/libs/chunk-P7TTEYCD.js +7 -0
- package/libs/chunk-P7TTEYCD.js.map +1 -0
- package/libs/chunk-PQ2K3BM6.cjs +17 -0
- package/libs/chunk-PQ2K3BM6.cjs.map +1 -0
- package/libs/chunk-QLZWHAMK.js +8 -0
- package/libs/chunk-QLZWHAMK.js.map +1 -0
- package/libs/chunk-RIVUMPOG.js +8 -0
- package/libs/chunk-RIVUMPOG.js.map +1 -0
- package/libs/chunk-ROZI23GS.cjs +15 -0
- package/libs/chunk-ROZI23GS.cjs.map +1 -0
- package/libs/chunk-S7BABR7Z.cjs +13 -0
- package/libs/chunk-S7BABR7Z.cjs.map +1 -0
- package/libs/chunk-SMYRLO3E.js +8 -0
- package/libs/chunk-SMYRLO3E.js.map +1 -0
- package/libs/chunk-TYRCEX2L.js +8 -0
- package/libs/chunk-TYRCEX2L.js.map +1 -0
- package/libs/chunk-VUH3FXGJ.js +11 -0
- package/libs/chunk-VUH3FXGJ.js.map +1 -0
- package/libs/chunk-XBA562WW.js +8 -0
- package/libs/chunk-XBA562WW.js.map +1 -0
- package/libs/chunk-XTQKWY7W.cjs +32 -0
- package/libs/chunk-XTQKWY7W.cjs.map +1 -0
- package/libs/chunk-ZANSFMTD.js +9 -0
- package/libs/chunk-ZANSFMTD.js.map +1 -0
- package/libs/component-props-a8a2f97e.d.ts +38 -0
- package/libs/components/alert/alert.css +1 -1
- package/libs/components/alert/alert.css.map +1 -1
- package/libs/components/alert/alert.min.css +2 -2
- package/libs/components/badge/badge.css +1 -1
- package/libs/components/badge/badge.css.map +1 -1
- package/libs/components/badge/badge.min.css +2 -2
- package/libs/components/breadcrumbs/breadcrumb.cjs +24 -0
- package/libs/components/breadcrumbs/breadcrumb.cjs.map +1 -0
- package/libs/components/breadcrumbs/breadcrumb.d.cts +290 -0
- package/libs/components/breadcrumbs/breadcrumb.d.ts +290 -0
- package/libs/components/breadcrumbs/breadcrumb.js +5 -0
- package/libs/components/breadcrumbs/breadcrumb.js.map +1 -0
- package/libs/components/button.cjs +19 -0
- package/libs/components/button.cjs.map +1 -0
- package/libs/components/button.d.cts +16 -0
- package/libs/components/button.d.ts +16 -0
- package/libs/components/button.js +4 -0
- package/libs/components/button.js.map +1 -0
- package/libs/components/buttons/button.css +1 -1
- package/libs/components/buttons/button.css.map +1 -1
- package/libs/components/buttons/button.min.css +2 -2
- package/libs/components/card.cjs +31 -0
- package/libs/components/card.cjs.map +1 -0
- package/libs/components/card.d.cts +302 -0
- package/libs/components/card.d.ts +302 -0
- package/libs/components/card.js +4 -0
- package/libs/components/card.js.map +1 -0
- package/libs/components/cards/card.css +1 -1
- package/libs/components/cards/card.css.map +1 -1
- package/libs/components/cards/card.min.css +2 -2
- package/libs/components/details/details.css +1 -1
- package/libs/components/details/details.css.map +1 -1
- package/libs/components/details/details.min.css +2 -2
- package/libs/components/dialog/dialog.cjs +22 -0
- package/libs/components/dialog/dialog.cjs.map +1 -0
- package/libs/components/dialog/dialog.css +1 -1
- package/libs/components/dialog/dialog.css.map +1 -1
- package/libs/components/dialog/dialog.d.cts +105 -0
- package/libs/components/dialog/dialog.d.ts +105 -0
- package/libs/components/dialog/dialog.js +7 -0
- package/libs/components/dialog/dialog.js.map +1 -0
- package/libs/components/dialog/dialog.min.css +2 -2
- package/libs/components/form/fields.cjs +19 -0
- package/libs/components/form/fields.cjs.map +1 -0
- package/libs/components/form/fields.d.cts +24 -0
- package/libs/components/form/fields.d.ts +24 -0
- package/libs/components/form/fields.js +4 -0
- package/libs/components/form/fields.js.map +1 -0
- package/libs/components/form/inputs.cjs +19 -0
- package/libs/components/form/inputs.cjs.map +1 -0
- package/libs/components/form/inputs.d.cts +2 -0
- package/libs/components/form/inputs.d.ts +2 -0
- package/libs/components/form/inputs.js +4 -0
- package/libs/components/form/inputs.js.map +1 -0
- package/libs/components/form/textarea.cjs +19 -0
- package/libs/components/form/textarea.cjs.map +1 -0
- package/libs/components/form/textarea.d.cts +29 -0
- package/libs/components/form/textarea.d.ts +29 -0
- package/libs/components/form/textarea.js +4 -0
- package/libs/components/form/textarea.js.map +1 -0
- package/libs/components/heading/heading.cjs +10 -0
- package/libs/components/heading/heading.cjs.map +1 -0
- package/libs/components/heading/heading.d.cts +3 -0
- package/libs/components/heading/heading.d.ts +3 -0
- package/libs/components/heading/heading.js +4 -0
- package/libs/components/heading/heading.js.map +1 -0
- package/libs/components/icons/icon.cjs +19 -0
- package/libs/components/icons/icon.cjs.map +1 -0
- package/libs/{icons-31ace3de.d.ts → components/icons/icon.d.cts} +151 -61
- package/libs/components/icons/icon.d.ts +445 -0
- package/libs/components/icons/icon.js +4 -0
- package/libs/components/icons/icon.js.map +1 -0
- package/libs/components/images/img.css +1 -1
- package/libs/components/images/img.css.map +1 -1
- package/libs/components/images/img.min.css +2 -2
- package/libs/components/link/link.cjs +19 -0
- package/libs/components/link/link.cjs.map +1 -0
- package/libs/components/link/link.d.cts +19 -0
- package/libs/components/link/link.d.ts +19 -0
- package/libs/components/link/link.js +4 -0
- package/libs/components/link/link.js.map +1 -0
- package/libs/components/list/list.cjs +23 -0
- package/libs/components/list/list.cjs.map +1 -0
- package/libs/components/list/list.d.cts +39 -0
- package/libs/components/list/list.d.ts +39 -0
- package/libs/components/list/list.js +4 -0
- package/libs/components/list/list.js.map +1 -0
- package/libs/components/modal.cjs +14 -0
- package/libs/components/modal.cjs.map +1 -0
- package/libs/components/modal.d.cts +35 -0
- package/libs/components/modal.d.ts +35 -0
- package/libs/components/modal.js +5 -0
- package/libs/components/modal.js.map +1 -0
- package/libs/components/nav/nav.cjs +28 -0
- package/libs/components/nav/nav.cjs.map +1 -0
- package/libs/components/nav/nav.d.cts +44 -0
- package/libs/components/nav/nav.d.ts +44 -0
- package/libs/components/nav/nav.js +5 -0
- package/libs/components/nav/nav.js.map +1 -0
- package/libs/components/popover/popover.cjs +23 -0
- package/libs/components/popover/popover.cjs.map +1 -0
- package/libs/components/popover/popover.d.cts +40 -0
- package/libs/components/popover/popover.d.ts +40 -0
- package/libs/components/popover/popover.js +4 -0
- package/libs/components/popover/popover.js.map +1 -0
- package/libs/components/tables/table.cjs +21 -0
- package/libs/components/tables/table.cjs.map +1 -0
- package/libs/components/tables/table.d.cts +36 -0
- package/libs/components/tables/table.d.ts +36 -0
- package/libs/components/tables/table.js +4 -0
- package/libs/components/tables/table.js.map +1 -0
- package/libs/components/text/text.cjs +23 -0
- package/libs/components/text/text.cjs.map +1 -0
- package/libs/components/text/text.d.cts +30 -0
- package/libs/components/text/text.d.ts +30 -0
- package/libs/components/text/text.js +4 -0
- package/libs/components/text/text.js.map +1 -0
- package/libs/heading-3648c538.d.ts +250 -0
- package/libs/hooks.cjs +7 -0
- package/libs/hooks.d.cts +5 -0
- package/libs/hooks.d.ts +5 -0
- package/libs/hooks.js +3 -0
- package/libs/icons.cjs +3 -2
- package/libs/icons.d.cts +3 -1
- package/libs/icons.d.ts +3 -1
- package/libs/icons.js +2 -1
- package/libs/index.cjs +174 -62
- package/libs/index.cjs.map +1 -1
- package/libs/index.css +1 -1
- package/libs/index.css.map +1 -1
- package/libs/index.d.cts +529 -446
- package/libs/index.d.ts +529 -446
- package/libs/index.js +36 -7
- package/libs/index.js.map +1 -1
- package/libs/inputs-f3a216db.d.ts +45 -0
- package/libs/ui-645f95b5.d.ts +285 -0
- package/package.json +2 -2
- package/src/components/README-UI.mdx +416 -0
- package/src/components/alert/ACCESSIBILITY.md +319 -0
- package/src/components/alert/README.mdx +475 -19
- package/src/components/alert/alert.scss +113 -6
- package/src/components/alert/alert.stories.tsx +372 -0
- package/src/components/alert/alert.test.tsx +762 -0
- package/src/components/alert/alert.tsx +331 -66
- package/src/components/alert/views/alert-actions.tsx +13 -0
- package/src/components/alert/views/alert-content.tsx +17 -0
- package/src/components/alert/views/alert-icon.tsx +53 -0
- package/src/components/alert/views/alert-screen-reader-text.tsx +30 -0
- package/src/components/alert/views/alert-title.tsx +23 -0
- package/src/components/alert/views/alert-view.tsx +158 -0
- package/src/components/alert/views/index.ts +12 -0
- package/src/components/badge/badge.mdx +186 -49
- package/src/components/badge/badge.scss +20 -2
- package/src/components/badge/badge.stories.tsx +160 -14
- package/src/components/badge/badge.test.tsx +179 -0
- package/src/components/badge/badge.tsx +97 -4
- package/src/components/breadcrumbs/README.mdx +364 -45
- package/src/components/breadcrumbs/__snapshots__/breadcrumb.test.tsx.snap +152 -0
- package/src/components/breadcrumbs/breadcrumb.stories.tsx +7 -3
- package/src/components/breadcrumbs/breadcrumb.test.tsx +490 -0
- package/src/components/breadcrumbs/breadcrumb.tsx +427 -170
- package/src/components/button.ts +2 -0
- package/src/components/buttons/button.scss +34 -31
- package/src/components/buttons/button.stories.tsx +35 -0
- package/src/components/card.ts +2 -0
- package/src/components/cards/README.mdx +657 -0
- package/src/components/cards/card.scss +22 -0
- package/src/components/cards/card.stories.tsx +167 -5
- package/src/components/cards/card.test.tsx +360 -20
- package/src/components/cards/card.tsx +200 -79
- package/src/components/cards/card.types.ts +135 -0
- package/src/components/cards/card.utils.ts +79 -0
- package/src/components/details/ACCESSIBILITY-REVIEW-LIVE.md +1050 -0
- package/src/components/details/ACCESSIBILITY-REVIEW.md +502 -0
- package/src/components/details/README.mdx +437 -69
- package/src/components/details/details.scss +16 -0
- package/src/components/details/details.test.tsx +385 -0
- package/src/components/details/details.tsx +101 -69
- package/src/components/details/details.types.ts +76 -0
- package/src/components/dialog/README.mdx +513 -110
- package/src/components/dialog/dialog-modal.tsx +79 -56
- package/src/components/dialog/dialog.scss +53 -3
- package/src/components/dialog/dialog.stories.tsx +10 -7
- package/src/components/dialog/dialog.test.tsx +450 -0
- package/src/components/dialog/dialog.tsx +69 -59
- package/src/components/dialog/dialog.types.ts +133 -0
- package/src/components/dialog/views/dialog-footer.tsx +54 -11
- package/src/components/dialog/views/dialog-header.tsx +20 -15
- package/src/components/heading/heading.stories.tsx +44 -4
- package/src/components/heading/heading.tsx +89 -23
- package/src/components/icons/README.mdx +332 -0
- package/src/components/icons/icon.stories.tsx +74 -1
- package/src/components/icons/icon.tsx +89 -1
- package/src/components/icons/types.ts +47 -0
- package/src/components/images/README.mdx +340 -24
- package/src/components/images/img.scss +19 -3
- package/src/components/images/img.stories.tsx +424 -15
- package/src/components/images/img.test.tsx +354 -25
- package/src/components/images/img.tsx +186 -63
- package/src/components/images/img.types.ts +211 -0
- package/src/components/modal.ts +1 -0
- package/src/components/title/MIGRATION.md +199 -0
- package/src/components/title/README.md +326 -0
- package/src/components/title/README.mdx +452 -0
- package/src/components/title/title.stories.tsx +393 -0
- package/src/components/title/title.test.tsx +251 -0
- package/src/components/title/title.tsx +219 -0
- package/src/components/ui.stories.tsx +894 -0
- package/src/components/ui.test.tsx +559 -0
- package/src/components/ui.tsx +266 -15
- package/src/components/word-count/README.md +240 -0
- package/src/hooks.ts +1 -0
- package/src/index.ts +51 -19
- package/src/sass/_properties.scss +1 -0
- package/src/styles/alert/alert.css +94 -4
- package/src/styles/alert/alert.css.map +1 -1
- package/src/styles/badge/badge.css +20 -2
- package/src/styles/badge/badge.css.map +1 -1
- package/src/styles/buttons/button.css +31 -31
- package/src/styles/buttons/button.css.map +1 -1
- package/src/styles/cards/card.css +16 -0
- package/src/styles/cards/card.css.map +1 -1
- package/src/styles/details/details.css +19 -0
- package/src/styles/details/details.css.map +1 -1
- package/src/styles/dialog/dialog.css +43 -2
- package/src/styles/dialog/dialog.css.map +1 -1
- package/src/styles/images/img.css +15 -3
- package/src/styles/images/img.css.map +1 -1
- package/src/styles/index.css +240 -43
- package/src/styles/index.css.map +1 -1
- package/src/test/setup.d.ts +9 -0
- package/src/test/setup.ts +53 -1
- package/libs/chunk-PWVRDQ3R.js +0 -8
- package/libs/chunk-PWVRDQ3R.js.map +0 -1
- package/libs/chunk-SVS4MX3U.cjs +0 -31
- package/libs/chunk-SVS4MX3U.cjs.map +0 -1
- package/src/components/cards/README.md +0 -80
- package/src/components/dialog/hooks/useClickOutside.ts +0 -33
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { render, screen, waitFor } from "@testing-library/react";
|
|
3
|
+
import userEvent from "@testing-library/user-event";
|
|
4
|
+
import { Dialog } from "./dialog";
|
|
5
|
+
import { DialogModal } from "./dialog-modal";
|
|
6
|
+
|
|
7
|
+
describe("Dialog", () => {
|
|
8
|
+
describe("Controlled Component Behavior", () => {
|
|
9
|
+
it("renders dialog when isOpen is true", () => {
|
|
10
|
+
const onOpenChange = vi.fn();
|
|
11
|
+
render(
|
|
12
|
+
<Dialog isOpen={true} onOpenChange={onOpenChange} dialogTitle="Test Dialog">
|
|
13
|
+
Dialog content
|
|
14
|
+
</Dialog>
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
const dialog = screen.getByRole("dialog");
|
|
18
|
+
expect(dialog).toBeInTheDocument();
|
|
19
|
+
expect(screen.getByText("Test Dialog")).toBeInTheDocument();
|
|
20
|
+
expect(screen.getByText("Dialog content")).toBeInTheDocument();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("does not render dialog when isOpen is false", () => {
|
|
24
|
+
const onOpenChange = vi.fn();
|
|
25
|
+
render(
|
|
26
|
+
<Dialog isOpen={false} onOpenChange={onOpenChange} dialogTitle="Test Dialog">
|
|
27
|
+
Dialog content
|
|
28
|
+
</Dialog>
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
const dialog = screen.queryByRole("dialog");
|
|
32
|
+
// Dialog element exists in DOM but should not have 'open' attribute
|
|
33
|
+
if (dialog) {
|
|
34
|
+
expect(dialog).not.toHaveAttribute("open");
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("calls onOpenChange with false when close button is clicked", async () => {
|
|
39
|
+
const user = userEvent.setup();
|
|
40
|
+
const onOpenChange = vi.fn();
|
|
41
|
+
|
|
42
|
+
render(
|
|
43
|
+
<Dialog isOpen={true} onOpenChange={onOpenChange} dialogTitle="Test Dialog">
|
|
44
|
+
Dialog content
|
|
45
|
+
</Dialog>
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
const closeButton = screen.getByRole("button", { name: /close dialog/i });
|
|
49
|
+
await user.click(closeButton);
|
|
50
|
+
|
|
51
|
+
expect(onOpenChange).toHaveBeenCalledWith(false);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it("calls deprecated onClose callback for backward compatibility", async () => {
|
|
55
|
+
const user = userEvent.setup();
|
|
56
|
+
const onOpenChange = vi.fn();
|
|
57
|
+
const onClose = vi.fn();
|
|
58
|
+
|
|
59
|
+
render(
|
|
60
|
+
<Dialog
|
|
61
|
+
isOpen={true}
|
|
62
|
+
onOpenChange={onOpenChange}
|
|
63
|
+
onClose={onClose}
|
|
64
|
+
dialogTitle="Test Dialog"
|
|
65
|
+
>
|
|
66
|
+
Dialog content
|
|
67
|
+
</Dialog>
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
const closeButton = screen.getByRole("button", { name: /close dialog/i });
|
|
71
|
+
await user.click(closeButton);
|
|
72
|
+
|
|
73
|
+
expect(onOpenChange).toHaveBeenCalledWith(false);
|
|
74
|
+
expect(onClose).toHaveBeenCalled();
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
describe("Modal vs Non-Modal Behavior", () => {
|
|
79
|
+
it("renders as modal dialog by default (role='dialog')", () => {
|
|
80
|
+
const onOpenChange = vi.fn();
|
|
81
|
+
render(
|
|
82
|
+
<Dialog isOpen={true} onOpenChange={onOpenChange} dialogTitle="Modal Dialog">
|
|
83
|
+
Content
|
|
84
|
+
</Dialog>
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
const dialog = screen.getByRole("dialog");
|
|
88
|
+
expect(dialog).toBeInTheDocument();
|
|
89
|
+
expect(dialog).toHaveAttribute("aria-modal", "true");
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it("renders as alert dialog when isAlertDialog is true", () => {
|
|
93
|
+
const onOpenChange = vi.fn();
|
|
94
|
+
render(
|
|
95
|
+
<Dialog
|
|
96
|
+
isOpen={true}
|
|
97
|
+
onOpenChange={onOpenChange}
|
|
98
|
+
dialogTitle="Alert Dialog"
|
|
99
|
+
isAlertDialog={true}
|
|
100
|
+
>
|
|
101
|
+
Alert content
|
|
102
|
+
</Dialog>
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
const dialog = screen.getByRole("alertdialog");
|
|
106
|
+
expect(dialog).toBeInTheDocument();
|
|
107
|
+
// Alert dialogs (inline) should not have aria-modal
|
|
108
|
+
expect(dialog).not.toHaveAttribute("aria-modal", "true");
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
describe("Accessibility (ARIA Attributes)", () => {
|
|
113
|
+
it("links dialog to title with aria-labelledby", () => {
|
|
114
|
+
const onOpenChange = vi.fn();
|
|
115
|
+
render(
|
|
116
|
+
<Dialog isOpen={true} onOpenChange={onOpenChange} dialogTitle="Accessible Dialog">
|
|
117
|
+
Content
|
|
118
|
+
</Dialog>
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
const dialog = screen.getByRole("dialog");
|
|
122
|
+
const title = screen.getByText("Accessible Dialog");
|
|
123
|
+
|
|
124
|
+
expect(dialog).toHaveAttribute("aria-labelledby");
|
|
125
|
+
expect(title).toHaveAttribute("id");
|
|
126
|
+
|
|
127
|
+
const labelledBy = dialog.getAttribute("aria-labelledby");
|
|
128
|
+
const titleId = title.getAttribute("id");
|
|
129
|
+
expect(labelledBy).toBe(titleId);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it("links dialog to content with aria-describedby", () => {
|
|
133
|
+
const onOpenChange = vi.fn();
|
|
134
|
+
render(
|
|
135
|
+
<Dialog isOpen={true} onOpenChange={onOpenChange} dialogTitle="Test Dialog">
|
|
136
|
+
Dialog description
|
|
137
|
+
</Dialog>
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
const dialog = screen.getByRole("dialog");
|
|
141
|
+
const content = screen.getByText("Dialog description").closest("section");
|
|
142
|
+
|
|
143
|
+
expect(dialog).toHaveAttribute("aria-describedby");
|
|
144
|
+
expect(content).toHaveAttribute("id");
|
|
145
|
+
|
|
146
|
+
const describedBy = dialog.getAttribute("aria-describedby");
|
|
147
|
+
const contentId = content?.getAttribute("id");
|
|
148
|
+
expect(describedBy).toBe(contentId);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it("applies custom aria-label when provided", () => {
|
|
152
|
+
const onOpenChange = vi.fn();
|
|
153
|
+
render(
|
|
154
|
+
<Dialog
|
|
155
|
+
isOpen={true}
|
|
156
|
+
onOpenChange={onOpenChange}
|
|
157
|
+
dialogTitle="Dialog"
|
|
158
|
+
dialogLabel="Custom accessible label"
|
|
159
|
+
>
|
|
160
|
+
Content
|
|
161
|
+
</Dialog>
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
const dialog = screen.getByRole("dialog");
|
|
165
|
+
expect(dialog).toHaveAttribute("aria-label", "Custom accessible label");
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it("close button has accessible label", () => {
|
|
169
|
+
const onOpenChange = vi.fn();
|
|
170
|
+
render(
|
|
171
|
+
<Dialog isOpen={true} onOpenChange={onOpenChange} dialogTitle="Test">
|
|
172
|
+
Content
|
|
173
|
+
</Dialog>
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
const closeButton = screen.getByRole("button", { name: /close dialog/i });
|
|
177
|
+
expect(closeButton).toHaveAttribute("aria-label", "Close dialog");
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
describe("Dialog Footer", () => {
|
|
182
|
+
it("shows footer with cancel and confirm buttons by default", () => {
|
|
183
|
+
const onOpenChange = vi.fn();
|
|
184
|
+
const onConfirm = vi.fn();
|
|
185
|
+
|
|
186
|
+
render(
|
|
187
|
+
<Dialog
|
|
188
|
+
isOpen={true}
|
|
189
|
+
onOpenChange={onOpenChange}
|
|
190
|
+
dialogTitle="Confirm Action"
|
|
191
|
+
onConfirm={onConfirm}
|
|
192
|
+
>
|
|
193
|
+
Content
|
|
194
|
+
</Dialog>
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
expect(screen.getByRole("button", { name: /cancel/i })).toBeInTheDocument();
|
|
198
|
+
expect(screen.getByRole("button", { name: /confirm/i })).toBeInTheDocument();
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it("hides footer when hideFooter is true", () => {
|
|
202
|
+
const onOpenChange = vi.fn();
|
|
203
|
+
|
|
204
|
+
render(
|
|
205
|
+
<Dialog
|
|
206
|
+
isOpen={true}
|
|
207
|
+
onOpenChange={onOpenChange}
|
|
208
|
+
dialogTitle="No Footer"
|
|
209
|
+
hideFooter={true}
|
|
210
|
+
>
|
|
211
|
+
Content
|
|
212
|
+
</Dialog>
|
|
213
|
+
);
|
|
214
|
+
|
|
215
|
+
expect(screen.queryByRole("button", { name: /cancel/i })).not.toBeInTheDocument();
|
|
216
|
+
expect(screen.queryByRole("button", { name: /confirm/i })).not.toBeInTheDocument();
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it("calls onConfirm when confirm button is clicked", async () => {
|
|
220
|
+
const user = userEvent.setup();
|
|
221
|
+
const onOpenChange = vi.fn();
|
|
222
|
+
const onConfirm = vi.fn();
|
|
223
|
+
|
|
224
|
+
render(
|
|
225
|
+
<Dialog
|
|
226
|
+
isOpen={true}
|
|
227
|
+
onOpenChange={onOpenChange}
|
|
228
|
+
dialogTitle="Test"
|
|
229
|
+
onConfirm={onConfirm}
|
|
230
|
+
>
|
|
231
|
+
Content
|
|
232
|
+
</Dialog>
|
|
233
|
+
);
|
|
234
|
+
|
|
235
|
+
const confirmButton = screen.getByRole("button", { name: /confirm/i });
|
|
236
|
+
await user.click(confirmButton);
|
|
237
|
+
|
|
238
|
+
expect(onConfirm).toHaveBeenCalled();
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it("uses custom button labels when provided", () => {
|
|
242
|
+
const onOpenChange = vi.fn();
|
|
243
|
+
const onConfirm = vi.fn();
|
|
244
|
+
|
|
245
|
+
render(
|
|
246
|
+
<Dialog
|
|
247
|
+
isOpen={true}
|
|
248
|
+
onOpenChange={onOpenChange}
|
|
249
|
+
dialogTitle="Delete Item"
|
|
250
|
+
onConfirm={onConfirm}
|
|
251
|
+
confirmLabel="Delete"
|
|
252
|
+
cancelLabel="Keep"
|
|
253
|
+
>
|
|
254
|
+
Are you sure?
|
|
255
|
+
</Dialog>
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
expect(screen.getByRole("button", { name: /delete/i })).toBeInTheDocument();
|
|
259
|
+
expect(screen.getByRole("button", { name: /keep/i })).toBeInTheDocument();
|
|
260
|
+
});
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
describe("Custom Styling", () => {
|
|
264
|
+
it("applies custom className", () => {
|
|
265
|
+
const onOpenChange = vi.fn();
|
|
266
|
+
render(
|
|
267
|
+
<Dialog
|
|
268
|
+
isOpen={true}
|
|
269
|
+
onOpenChange={onOpenChange}
|
|
270
|
+
dialogTitle="Styled Dialog"
|
|
271
|
+
className="custom-class"
|
|
272
|
+
>
|
|
273
|
+
Content
|
|
274
|
+
</Dialog>
|
|
275
|
+
);
|
|
276
|
+
|
|
277
|
+
const dialog = screen.getByRole("dialog");
|
|
278
|
+
expect(dialog).toHaveClass("custom-class");
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it("applies custom inline styles", () => {
|
|
282
|
+
const onOpenChange = vi.fn();
|
|
283
|
+
const customStyles = { maxWidth: "600px" };
|
|
284
|
+
|
|
285
|
+
render(
|
|
286
|
+
<Dialog
|
|
287
|
+
isOpen={true}
|
|
288
|
+
onOpenChange={onOpenChange}
|
|
289
|
+
dialogTitle="Custom Styled"
|
|
290
|
+
styles={customStyles}
|
|
291
|
+
>
|
|
292
|
+
Content
|
|
293
|
+
</Dialog>
|
|
294
|
+
);
|
|
295
|
+
|
|
296
|
+
const dialog = screen.getByRole("dialog");
|
|
297
|
+
expect(dialog).toHaveStyle({ maxWidth: "600px" });
|
|
298
|
+
});
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
describe("DialogModal", () => {
|
|
303
|
+
describe("Uncontrolled State Management", () => {
|
|
304
|
+
it("renders trigger button with custom label", () => {
|
|
305
|
+
render(
|
|
306
|
+
<DialogModal dialogTitle="Test" btnLabel="Open My Dialog">
|
|
307
|
+
Content
|
|
308
|
+
</DialogModal>
|
|
309
|
+
);
|
|
310
|
+
|
|
311
|
+
const triggerButton = screen.getByRole("button", { name: /open my dialog/i });
|
|
312
|
+
expect(triggerButton).toBeInTheDocument();
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
it("opens dialog when trigger button is clicked", async () => {
|
|
316
|
+
const user = userEvent.setup();
|
|
317
|
+
|
|
318
|
+
render(
|
|
319
|
+
<DialogModal dialogTitle="Test Dialog" btnLabel="Open">
|
|
320
|
+
Dialog content
|
|
321
|
+
</DialogModal>
|
|
322
|
+
);
|
|
323
|
+
|
|
324
|
+
const triggerButton = screen.getByRole("button", { name: /open/i });
|
|
325
|
+
await user.click(triggerButton);
|
|
326
|
+
|
|
327
|
+
await waitFor(() => {
|
|
328
|
+
expect(screen.getByRole("dialog")).toBeInTheDocument();
|
|
329
|
+
expect(screen.getByText("Dialog content")).toBeInTheDocument();
|
|
330
|
+
});
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
it("closes dialog when close button is clicked", async () => {
|
|
334
|
+
const user = userEvent.setup();
|
|
335
|
+
|
|
336
|
+
render(
|
|
337
|
+
<DialogModal dialogTitle="Test" btnLabel="Open">
|
|
338
|
+
Content
|
|
339
|
+
</DialogModal>
|
|
340
|
+
);
|
|
341
|
+
|
|
342
|
+
const triggerButton = screen.getByRole("button", { name: /open/i });
|
|
343
|
+
await user.click(triggerButton);
|
|
344
|
+
|
|
345
|
+
const closeButton = screen.getByRole("button", { name: /close dialog/i });
|
|
346
|
+
await user.click(closeButton);
|
|
347
|
+
|
|
348
|
+
await waitFor(() => {
|
|
349
|
+
const dialog = screen.queryByRole("dialog");
|
|
350
|
+
// Dialog should not have 'open' attribute when closed
|
|
351
|
+
if (dialog) {
|
|
352
|
+
expect(dialog).not.toHaveAttribute("open");
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
it("calls onClose callback when dialog is closed", async () => {
|
|
358
|
+
const user = userEvent.setup();
|
|
359
|
+
const onClose = vi.fn();
|
|
360
|
+
|
|
361
|
+
render(
|
|
362
|
+
<DialogModal dialogTitle="Test" btnLabel="Open" onClose={onClose}>
|
|
363
|
+
Content
|
|
364
|
+
</DialogModal>
|
|
365
|
+
);
|
|
366
|
+
|
|
367
|
+
const triggerButton = screen.getByRole("button", { name: /open/i });
|
|
368
|
+
await user.click(triggerButton);
|
|
369
|
+
|
|
370
|
+
const closeButton = screen.getByRole("button", { name: /close dialog/i });
|
|
371
|
+
await user.click(closeButton);
|
|
372
|
+
|
|
373
|
+
await waitFor(() => {
|
|
374
|
+
expect(onClose).toHaveBeenCalled();
|
|
375
|
+
});
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
it("calls btnOnClick before opening dialog", async () => {
|
|
379
|
+
const user = userEvent.setup();
|
|
380
|
+
const btnOnClick = vi.fn();
|
|
381
|
+
|
|
382
|
+
render(
|
|
383
|
+
<DialogModal dialogTitle="Test" btnLabel="Open" btnOnClick={btnOnClick}>
|
|
384
|
+
Content
|
|
385
|
+
</DialogModal>
|
|
386
|
+
);
|
|
387
|
+
|
|
388
|
+
const triggerButton = screen.getByRole("button", { name: /open/i });
|
|
389
|
+
await user.click(triggerButton);
|
|
390
|
+
|
|
391
|
+
expect(btnOnClick).toHaveBeenCalled();
|
|
392
|
+
});
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
describe("Focus Restoration", () => {
|
|
396
|
+
it("restores focus to trigger button after dialog closes", async () => {
|
|
397
|
+
const user = userEvent.setup();
|
|
398
|
+
|
|
399
|
+
render(
|
|
400
|
+
<DialogModal dialogTitle="Focus Test" btnLabel="Open Dialog">
|
|
401
|
+
Content
|
|
402
|
+
</DialogModal>
|
|
403
|
+
);
|
|
404
|
+
|
|
405
|
+
const triggerButton = screen.getByRole("button", { name: /open dialog/i });
|
|
406
|
+
await user.click(triggerButton);
|
|
407
|
+
|
|
408
|
+
const closeButton = screen.getByRole("button", { name: /close dialog/i });
|
|
409
|
+
await user.click(closeButton);
|
|
410
|
+
|
|
411
|
+
// Wait for focus restoration (has 100ms delay in DialogModal)
|
|
412
|
+
await waitFor(
|
|
413
|
+
() => {
|
|
414
|
+
// Focus restoration happens after dialog closes
|
|
415
|
+
expect(triggerButton).toHaveFocus();
|
|
416
|
+
},
|
|
417
|
+
{ timeout: 300, interval: 50 }
|
|
418
|
+
);
|
|
419
|
+
});
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
describe("Button Props", () => {
|
|
423
|
+
it("applies custom button size", () => {
|
|
424
|
+
render(
|
|
425
|
+
<DialogModal dialogTitle="Test" btnLabel="Open" btnSize="lg">
|
|
426
|
+
Content
|
|
427
|
+
</DialogModal>
|
|
428
|
+
);
|
|
429
|
+
|
|
430
|
+
const triggerButton = screen.getByRole("button", { name: /open/i });
|
|
431
|
+
expect(triggerButton).toHaveAttribute("data-btn", "lg");
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
it("forwards additional button props", () => {
|
|
435
|
+
render(
|
|
436
|
+
<DialogModal
|
|
437
|
+
dialogTitle="Test"
|
|
438
|
+
btnLabel="Open"
|
|
439
|
+
btnProps={{ "data-testid": "custom-trigger", disabled: false }}
|
|
440
|
+
>
|
|
441
|
+
Content
|
|
442
|
+
</DialogModal>
|
|
443
|
+
);
|
|
444
|
+
|
|
445
|
+
const triggerButton = screen.getByTestId("custom-trigger");
|
|
446
|
+
expect(triggerButton).toBeInTheDocument();
|
|
447
|
+
expect(triggerButton).not.toBeDisabled();
|
|
448
|
+
});
|
|
449
|
+
});
|
|
450
|
+
});
|
|
@@ -1,58 +1,59 @@
|
|
|
1
|
-
import React, { useRef, useEffect,
|
|
1
|
+
import React, { useRef, useEffect, useCallback, useId } from "react";
|
|
2
2
|
import UI from "#components/ui";
|
|
3
3
|
import DialogHeader from "#components/dialog/views/dialog-header";
|
|
4
4
|
import DialogFooter from "#components/dialog/views/dialog-footer";
|
|
5
5
|
import { useDialogClickHandler } from "#hooks/useDialogClickHandler.js";
|
|
6
|
+
import type { DialogProps } from "./dialog.types";
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
|
-
*
|
|
9
|
+
* A controlled dialog component that supports both modal and non-modal (inline alert) modes.
|
|
9
10
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
styles?: CSSProperties;
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Renders a dialog modal component with customizable content and behavior.
|
|
11
|
+
* **Modal Dialog** (default): Uses native `<dialog>` element with `.showModal()` which provides:
|
|
12
|
+
* - Automatic focus trap (Tab cycles within dialog)
|
|
13
|
+
* - Escape key closes dialog (native behavior)
|
|
14
|
+
* - Backdrop overlay with click-to-close
|
|
15
|
+
* - Inert background (page content becomes non-interactive)
|
|
16
|
+
*
|
|
17
|
+
* **Inline Alert Dialog** (`isAlertDialog={true}`): Uses `.show()` for non-modal inline alerts:
|
|
18
|
+
* - No focus trap (page remains interactive)
|
|
19
|
+
* - No escape key behavior
|
|
20
|
+
* - Positioned inline in page flow
|
|
21
|
+
* - User must explicitly close with button
|
|
22
|
+
*
|
|
23
|
+
* @component
|
|
24
|
+
* @example
|
|
25
|
+
* ```tsx
|
|
26
|
+
* // Controlled usage
|
|
27
|
+
* const [open, setOpen] = useState(false);
|
|
28
|
+
* <Dialog
|
|
29
|
+
* isOpen={open}
|
|
30
|
+
* onOpenChange={setOpen}
|
|
31
|
+
* dialogTitle="Confirm Delete"
|
|
32
|
+
* >
|
|
33
|
+
* Are you sure you want to delete this item?
|
|
34
|
+
* </Dialog>
|
|
35
|
+
* ```
|
|
40
36
|
*
|
|
41
|
-
* @param
|
|
42
|
-
* @param
|
|
43
|
-
* @param
|
|
44
|
-
* @param dialogTitle - The title
|
|
45
|
-
* @param
|
|
46
|
-
* @param
|
|
47
|
-
* @param
|
|
48
|
-
* @param
|
|
49
|
-
* @param
|
|
50
|
-
* @param
|
|
51
|
-
* @param
|
|
37
|
+
* @param {DialogProps} props - Component props
|
|
38
|
+
* @param {boolean} props.isOpen - Controls whether the dialog is currently open
|
|
39
|
+
* @param {(open: boolean) => void} props.onOpenChange - Callback fired when dialog open state changes
|
|
40
|
+
* @param {string} props.dialogTitle - The title displayed in the dialog header
|
|
41
|
+
* @param {boolean} [props.isAlertDialog=false] - If true, renders as non-modal inline alert
|
|
42
|
+
* @param {() => void} [props.onClose] - Deprecated: Use onOpenChange. Called when dialog closes.
|
|
43
|
+
* @param {ReactNode} props.children - Content to display inside the dialog body
|
|
44
|
+
* @param {() => void | Promise<void>} [props.onConfirm] - Callback fired when confirm button is clicked
|
|
45
|
+
* @param {string} [props.confirmLabel="Confirm"] - Text label for confirm button
|
|
46
|
+
* @param {string} [props.cancelLabel="Cancel"] - Text label for cancel button
|
|
47
|
+
* @param {boolean} [props.hideFooter=false] - If true, hides the footer with action buttons
|
|
48
|
+
* @param {string} [props.className] - Additional CSS classes to apply
|
|
49
|
+
* @param {string} [props.dialogLabel] - Optional aria-label for the dialog
|
|
50
|
+
* @param {CSSProperties} [props.styles] - Inline styles to apply to dialog element
|
|
51
|
+
* @returns {JSX.Element} A controlled dialog component
|
|
52
52
|
*/
|
|
53
|
-
export const Dialog: React.FC<
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
export const Dialog: React.FC<DialogProps> = ({
|
|
54
|
+
isOpen,
|
|
55
|
+
onOpenChange,
|
|
56
|
+
isAlertDialog = false,
|
|
56
57
|
onClose,
|
|
57
58
|
dialogTitle,
|
|
58
59
|
dialogLabel,
|
|
@@ -61,24 +62,23 @@ export const Dialog: React.FC<DialogModalProps> = ({
|
|
|
61
62
|
confirmLabel = "Confirm",
|
|
62
63
|
cancelLabel = "Cancel",
|
|
63
64
|
className = "",
|
|
64
|
-
hideFooter,
|
|
65
|
+
hideFooter = false,
|
|
65
66
|
styles,
|
|
66
67
|
}) => {
|
|
67
68
|
const dialogRef = useRef<HTMLDialogElement>(null);
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
useEffect(() => {
|
|
71
|
-
setIsOpen(showDialog);
|
|
72
|
-
}, [showDialog]);
|
|
69
|
+
const titleId = useId();
|
|
73
70
|
|
|
71
|
+
// Handle native dialog open/close based on isOpen prop
|
|
74
72
|
useEffect(() => {
|
|
75
73
|
const dialog = dialogRef.current;
|
|
76
74
|
if (!dialog) return;
|
|
77
75
|
|
|
78
76
|
if (isOpen) {
|
|
79
77
|
if (isAlertDialog) {
|
|
78
|
+
// Non-modal inline alert - no focus trap, no backdrop
|
|
80
79
|
dialog.show();
|
|
81
80
|
} else {
|
|
81
|
+
// Modal dialog - native focus trap, escape key, backdrop
|
|
82
82
|
dialog.showModal();
|
|
83
83
|
}
|
|
84
84
|
} else {
|
|
@@ -86,13 +86,18 @@ export const Dialog: React.FC<DialogModalProps> = ({
|
|
|
86
86
|
}
|
|
87
87
|
}, [isOpen, isAlertDialog]);
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
// Handle close event - notify parent via onOpenChange
|
|
90
|
+
const handleClose = useCallback(() => {
|
|
91
|
+
onOpenChange(false);
|
|
92
|
+
// Support deprecated onClose prop for backward compatibility
|
|
90
93
|
if (onClose) onClose();
|
|
91
|
-
|
|
92
|
-
};
|
|
94
|
+
}, [onOpenChange, onClose]);
|
|
93
95
|
|
|
96
|
+
// Handle backdrop clicks (only for modal dialogs)
|
|
94
97
|
const handleClickOutside = useDialogClickHandler(dialogRef, handleClose);
|
|
95
98
|
|
|
99
|
+
const contentId = useId();
|
|
100
|
+
|
|
96
101
|
return (
|
|
97
102
|
<UI
|
|
98
103
|
as="dialog"
|
|
@@ -100,16 +105,19 @@ export const Dialog: React.FC<DialogModalProps> = ({
|
|
|
100
105
|
ref={dialogRef}
|
|
101
106
|
onClose={handleClose}
|
|
102
107
|
onClick={handleClickOutside}
|
|
103
|
-
aria-modal={isOpen ? "true" : undefined}
|
|
104
|
-
|
|
108
|
+
aria-modal={isOpen && !isAlertDialog ? "true" : undefined}
|
|
109
|
+
aria-labelledby={titleId}
|
|
110
|
+
aria-describedby={contentId}
|
|
105
111
|
aria-label={dialogLabel}
|
|
112
|
+
className={`dialog-modal ${className}`.trim()}
|
|
106
113
|
style={styles}
|
|
107
114
|
>
|
|
108
|
-
<DialogHeader dialogTitle={dialogTitle} onClick={handleClose} />
|
|
115
|
+
<DialogHeader dialogTitle={dialogTitle} onClick={handleClose} id={titleId} />
|
|
109
116
|
|
|
110
117
|
<UI
|
|
111
118
|
as="section"
|
|
112
|
-
|
|
119
|
+
id={contentId}
|
|
120
|
+
className="dialog-content"
|
|
113
121
|
onClick={(e: React.MouseEvent) => e.stopPropagation()}
|
|
114
122
|
>
|
|
115
123
|
{children}
|
|
@@ -125,4 +133,6 @@ export const Dialog: React.FC<DialogModalProps> = ({
|
|
|
125
133
|
</UI>
|
|
126
134
|
);
|
|
127
135
|
};
|
|
136
|
+
Dialog.displayName = "Dialog";
|
|
137
|
+
|
|
128
138
|
export default React.memo(Dialog);
|