Local modifications to ClusterLabs/Anvil by Alteeve
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

102 lines
2.8 KiB

import {
ExpandLess as ExpandLessIcon,
ExpandMore as ExpandMoreIcon,
} from '@mui/icons-material';
import { Box, IconButton } from '@mui/material';
import { FC, ReactNode, useMemo, useState } from 'react';
import { GREY } from '../../lib/consts/DEFAULT_THEME';
import FlexBox from '../FlexBox';
import InnerPanel from './InnerPanel';
import InnerPanelBody from './InnerPanelBody';
import InnerPanelHeader from './InnerPanelHeader';
import Spinner from '../Spinner';
import { BodyText } from '../Text';
type ExpandablePanelOptionalProps = {
expandInitially?: boolean;
loading?: boolean;
showHeaderSpinner?: boolean;
};
type ExpandablePanelProps = ExpandablePanelOptionalProps & {
header: ReactNode;
};
const EXPANDABLE_PANEL_DEFAULT_PROPS: Required<ExpandablePanelOptionalProps> = {
expandInitially: false,
loading: false,
showHeaderSpinner: false,
};
const HEADER_SPINNER_LENGTH = '1.2em';
const ExpandablePanel: FC<ExpandablePanelProps> = ({
children,
expandInitially:
isExpandInitially = EXPANDABLE_PANEL_DEFAULT_PROPS.expandInitially,
header,
loading: isLoading = EXPANDABLE_PANEL_DEFAULT_PROPS.loading,
showHeaderSpinner:
isShowHeaderSpinner = EXPANDABLE_PANEL_DEFAULT_PROPS.showHeaderSpinner,
}) => {
const [isExpand, setIsExpand] = useState<boolean>(isExpandInitially);
const expandButtonIcon = useMemo(
() => (isExpand ? <ExpandLessIcon /> : <ExpandMoreIcon />),
[isExpand],
);
const contentHeight = useMemo(() => (isExpand ? 'auto' : '.2em'), [isExpand]);
const headerElement = useMemo(
() => (typeof header === 'string' ? <BodyText>{header}</BodyText> : header),
[header],
);
const headerSpinner = useMemo(
() =>
isShowHeaderSpinner && !isExpand && isLoading ? (
<Spinner
progressProps={{
style: {
height: HEADER_SPINNER_LENGTH,
width: HEADER_SPINNER_LENGTH,
},
}}
/>
) : undefined,
[isExpand, isLoading, isShowHeaderSpinner],
);
const content = useMemo(
() =>
isExpand && isLoading ? (
<Spinner sx={{ margin: '1em 0' }} />
) : (
<InnerPanelBody>{children}</InnerPanelBody>
),
[children, isExpand, isLoading],
);
return (
<InnerPanel>
<InnerPanelHeader>
<FlexBox row>
{headerElement}
{headerSpinner}
</FlexBox>
<IconButton
onClick={() => {
setIsExpand((previous) => !previous);
}}
sx={{ color: GREY, padding: '.2em' }}
>
{expandButtonIcon}
</IconButton>
</InnerPanelHeader>
<Box sx={{ height: contentHeight, overflowY: 'hidden' }}>{content}</Box>
</InnerPanel>
);
};
ExpandablePanel.defaultProps = EXPANDABLE_PANEL_DEFAULT_PROPS;
export default ExpandablePanel;