diff options
Diffstat (limited to 'subprojects/frontend/src/graph/SlideInDialog.tsx')
-rw-r--r-- | subprojects/frontend/src/graph/SlideInDialog.tsx | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/subprojects/frontend/src/graph/SlideInDialog.tsx b/subprojects/frontend/src/graph/SlideInDialog.tsx new file mode 100644 index 00000000..d9060fb0 --- /dev/null +++ b/subprojects/frontend/src/graph/SlideInDialog.tsx | |||
@@ -0,0 +1,109 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2023-2024 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | |||
7 | import CloseIcon from '@mui/icons-material/Close'; | ||
8 | import Button from '@mui/material/Button'; | ||
9 | import IconButton from '@mui/material/IconButton'; | ||
10 | import Typography from '@mui/material/Typography'; | ||
11 | import { styled } from '@mui/material/styles'; | ||
12 | import React, { useId } from 'react'; | ||
13 | |||
14 | const SlideInDialogRoot = styled('div', { | ||
15 | name: 'SlideInDialog-Root', | ||
16 | shouldForwardProp: (propName) => propName !== 'dialog', | ||
17 | })<{ dialog: boolean }>(({ theme, dialog }) => { | ||
18 | return { | ||
19 | maxHeight: '100%', | ||
20 | maxWidth: '100%', | ||
21 | overflow: 'hidden', | ||
22 | display: 'flex', | ||
23 | flexDirection: 'column', | ||
24 | '.SlideInDialog-title': { | ||
25 | display: 'flex', | ||
26 | flexDirection: 'row', | ||
27 | alignItems: 'center', | ||
28 | padding: theme.spacing(1), | ||
29 | paddingLeft: theme.spacing(2), | ||
30 | borderBottom: `1px solid ${theme.palette.divider}`, | ||
31 | '& h2': { | ||
32 | flexGrow: 1, | ||
33 | }, | ||
34 | '.MuiIconButton-root': { | ||
35 | flexGrow: 0, | ||
36 | flexShrink: 0, | ||
37 | marginLeft: theme.spacing(2), | ||
38 | }, | ||
39 | }, | ||
40 | '.MuiFormControlLabel-root': { | ||
41 | marginLeft: 0, | ||
42 | paddingTop: theme.spacing(1), | ||
43 | paddingLeft: theme.spacing(1), | ||
44 | '& + .MuiFormControlLabel-root': { | ||
45 | paddingTop: 0, | ||
46 | }, | ||
47 | }, | ||
48 | '.SlideInDialog-buttons': { | ||
49 | padding: theme.spacing(1), | ||
50 | display: 'flex', | ||
51 | flexDirection: 'row', | ||
52 | justifyContent: 'flex-end', | ||
53 | ...(dialog | ||
54 | ? { | ||
55 | marginTop: theme.spacing(1), | ||
56 | borderTop: `1px solid ${theme.palette.divider}`, | ||
57 | } | ||
58 | : {}), | ||
59 | }, | ||
60 | }; | ||
61 | }); | ||
62 | |||
63 | export default function SlideInDialog({ | ||
64 | close, | ||
65 | dialog, | ||
66 | title, | ||
67 | buttons, | ||
68 | children, | ||
69 | }: { | ||
70 | close: () => void; | ||
71 | dialog?: boolean; | ||
72 | title: string; | ||
73 | buttons: React.ReactNode | ((close: () => void) => React.ReactNode); | ||
74 | children?: React.ReactNode; | ||
75 | }): JSX.Element { | ||
76 | const titleId = useId(); | ||
77 | |||
78 | return ( | ||
79 | <SlideInDialogRoot | ||
80 | dialog={dialog ?? SlideInDialog.defaultProps.dialog} | ||
81 | aria-labelledby={dialog ? titleId : undefined} | ||
82 | > | ||
83 | {dialog && ( | ||
84 | <div className="SlideInDialog-title"> | ||
85 | <Typography variant="h6" component="h2" id={titleId}> | ||
86 | {title} | ||
87 | </Typography> | ||
88 | <IconButton aria-label="Close" onClick={close}> | ||
89 | <CloseIcon /> | ||
90 | </IconButton> | ||
91 | </div> | ||
92 | )} | ||
93 | {children} | ||
94 | <div className="SlideInDialog-buttons"> | ||
95 | {typeof buttons === 'function' ? buttons(close) : buttons} | ||
96 | {!dialog && ( | ||
97 | <Button color="inherit" onClick={close}> | ||
98 | Close | ||
99 | </Button> | ||
100 | )} | ||
101 | </div> | ||
102 | </SlideInDialogRoot> | ||
103 | ); | ||
104 | } | ||
105 | |||
106 | SlideInDialog.defaultProps = { | ||
107 | dialog: false, | ||
108 | children: undefined, | ||
109 | }; | ||