diff options
Diffstat (limited to 'subprojects/frontend/src/graph/SlideInPanel.tsx')
-rw-r--r-- | subprojects/frontend/src/graph/SlideInPanel.tsx | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/subprojects/frontend/src/graph/SlideInPanel.tsx b/subprojects/frontend/src/graph/SlideInPanel.tsx new file mode 100644 index 00000000..2c189b5b --- /dev/null +++ b/subprojects/frontend/src/graph/SlideInPanel.tsx | |||
@@ -0,0 +1,97 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2023-2024 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | |||
7 | import Dialog from '@mui/material/Dialog'; | ||
8 | import IconButton from '@mui/material/IconButton'; | ||
9 | import Paper from '@mui/material/Paper'; | ||
10 | import Slide from '@mui/material/Slide'; | ||
11 | import { styled } from '@mui/material/styles'; | ||
12 | import React, { useCallback, useId, useState } from 'react'; | ||
13 | |||
14 | import SlideInDialog from './SlideInDialog'; | ||
15 | |||
16 | const SlideInPanelRoot = styled('div', { | ||
17 | name: 'SlideInPanel-Root', | ||
18 | shouldForwardProp: (propName) => propName !== 'anchor', | ||
19 | })<{ anchor: 'left' | 'right' }>(({ theme, anchor }) => ({ | ||
20 | position: 'absolute', | ||
21 | padding: theme.spacing(1), | ||
22 | top: 0, | ||
23 | [anchor]: 0, | ||
24 | maxHeight: '100%', | ||
25 | maxWidth: '100%', | ||
26 | overflow: 'hidden', | ||
27 | display: 'flex', | ||
28 | flexDirection: 'column', | ||
29 | alignItems: anchor === 'left' ? 'start' : 'end', | ||
30 | '.SlideInPanel-drawer': { | ||
31 | overflow: 'hidden', | ||
32 | display: 'flex', | ||
33 | maxWidth: '100%', | ||
34 | margin: theme.spacing(1), | ||
35 | }, | ||
36 | })); | ||
37 | |||
38 | export default function SlideInPanel({ | ||
39 | anchor, | ||
40 | dialog, | ||
41 | title, | ||
42 | icon, | ||
43 | iconLabel, | ||
44 | buttons, | ||
45 | children, | ||
46 | }: { | ||
47 | anchor: 'left' | 'right'; | ||
48 | dialog: boolean; | ||
49 | title: string; | ||
50 | icon: (show: boolean) => React.ReactNode; | ||
51 | iconLabel: string; | ||
52 | buttons: React.ReactNode | ((close: () => void) => React.ReactNode); | ||
53 | children?: React.ReactNode; | ||
54 | }): JSX.Element { | ||
55 | const id = useId(); | ||
56 | const [show, setShow] = useState(false); | ||
57 | const close = useCallback(() => setShow(false), []); | ||
58 | |||
59 | return ( | ||
60 | <SlideInPanelRoot anchor={anchor}> | ||
61 | <IconButton | ||
62 | role="switch" | ||
63 | aria-checked={show} | ||
64 | aria-controls={dialog ? undefined : id} | ||
65 | aria-label={iconLabel} | ||
66 | onClick={() => setShow(!show)} | ||
67 | > | ||
68 | {icon(show)} | ||
69 | </IconButton> | ||
70 | {dialog ? ( | ||
71 | <Dialog open={show} onClose={close} maxWidth="xl"> | ||
72 | <SlideInDialog close={close} dialog title={title} buttons={buttons}> | ||
73 | {children} | ||
74 | </SlideInDialog> | ||
75 | </Dialog> | ||
76 | ) : ( | ||
77 | <Slide | ||
78 | direction={anchor === 'left' ? 'right' : 'left'} | ||
79 | in={show} | ||
80 | id={id} | ||
81 | mountOnEnter | ||
82 | unmountOnExit | ||
83 | > | ||
84 | <Paper className="SlideInPanel-drawer" elevation={4}> | ||
85 | <SlideInDialog close={close} title={title} buttons={buttons}> | ||
86 | {children} | ||
87 | </SlideInDialog> | ||
88 | </Paper> | ||
89 | </Slide> | ||
90 | )} | ||
91 | </SlideInPanelRoot> | ||
92 | ); | ||
93 | } | ||
94 | |||
95 | SlideInPanel.defaultProps = { | ||
96 | children: undefined, | ||
97 | }; | ||