forked from Cambly/syntax
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Dialog.tsx
110 lines (102 loc) · 2.95 KB
/
Dialog.tsx
1
2
3
4
5
6
7
8
9
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
import React, {
type ReactNode,
forwardRef,
type ReactElement,
useContext,
type ComponentProps,
} from "react";
import colorStyles from "../colors/colors.module.css";
import elevationStyles from "../elevation/elevation.module.css";
import layoutStyles from "../layout.module.css";
import paddingStyles from "../Box/padding.module.css";
import roundingStyles from "../rounding.module.css";
import boxStyles from "../Box/Box.module.css";
import styles from "./Dialog.module.css";
import { Dialog as ReactAriaDialog } from "react-aria-components";
import classNames from "classnames";
import type Box from "../Box/Box";
import { useTheme } from "../ThemeProvider/ThemeProvider";
type DialogSize = "sm" | "md" | "lg";
type DialogRounding = "lg" | "xl";
export type DialogProps = {
/** Test id for the floating dialog */
"data-testid"?: string;
/** aria-label for the dialog */
accessibilityLabel?: string;
/** Content to be shown inside the dialog. */
children?: ReactNode;
/** Optional size of the dialog box */
size?: DialogSize;
};
const sizeToRounding: Record<DialogSize, DialogRounding> = {
sm: "lg",
md: "lg",
lg: "xl",
};
const sizeToPadding: Record<DialogSize, 4 | 5 | 6> = {
sm: 4,
md: 5,
lg: 6,
};
type DialogContextType = {
/** padding of dialog content. overrides \"size\" prop's padding" */
padding?: ComponentProps<typeof Box>["padding"];
};
export const DialogContext = React.createContext<DialogContextType>({});
/**
* Dialog is a display component for showing content in Popovers, Modals, etc...
*
* Example Usage:
```
<Dialog accessibilityLabel="Select some options">
<Box padding={2} maxWidth={400}>
... some content goes here
</Box>
</Dialog>
```
*/
const Dialog = forwardRef<HTMLDivElement, DialogProps>(function Dialog(
props,
ref,
): ReactElement {
const {
"data-testid": dataTestId,
accessibilityLabel,
children,
size = "md",
} = props;
const { padding } = useContext(DialogContext);
const { themeName } = useTheme();
return (
<ReactAriaDialog
ref={ref}
data-testid={dataTestId}
// first thing screen reader reads
// e.g. "<this was the label prop>, dialog, 4 items..."
aria-label={accessibilityLabel}
className={classNames([
boxStyles.box,
boxStyles.flex,
boxStyles.column,
boxStyles.gap4,
boxStyles.relative,
boxStyles.overflowauto,
colorStyles.whiteBackgroundColor,
paddingStyles[`paddingX${padding ?? sizeToPadding[size]}`],
paddingStyles[`paddingY${padding ?? sizeToPadding[size]}`],
roundingStyles[
themeName === "classic"
? (`rounding${sizeToRounding[size]}` as const)
: "roundingmdCambio"
],
elevationStyles.elevation400BoxShadow,
layoutStyles.fullMaxHeight,
layoutStyles.visibilityVisible,
styles.dialog,
])}
>
{children}
</ReactAriaDialog>
);
});
export default Dialog;