1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-04-10 01:16:39 +02:00
unleash.unleash/frontend/src/component/common/SidePanelList/SidePanelList.tsx

138 lines
4.5 KiB
TypeScript

import { styled } from '@mui/material';
import { ReactNode, useState } from 'react';
import { SidePanelListHeader } from './SidePanelListHeader';
import { SidePanelListItem } from './SidePanelListItem';
const StyledSidePanelListWrapper = styled('div')({
display: 'flex',
flexDirection: 'column',
width: '100%',
});
const StyledSidePanelListBody = styled('div')({
display: 'flex',
flexDirection: 'row',
});
const StyledSidePanelHalf = styled('div')({
display: 'flex',
flexDirection: 'column',
flex: 1,
});
const StyledSidePanelHalfLeft = styled(StyledSidePanelHalf, {
shouldForwardProp: (prop) => prop !== 'height' && prop !== 'maxWidth',
})<{ height?: number; maxWidth?: number }>(({ theme, height, maxWidth }) => ({
border: `1px solid ${theme.palette.divider}`,
borderTop: 0,
borderBottomLeftRadius: theme.shape.borderRadiusMedium,
overflow: 'auto',
...(height && { height }),
...(maxWidth && { maxWidth }),
}));
const StyledSidePanelHalfRight = styled(StyledSidePanelHalf)(({ theme }) => ({
border: `1px solid ${theme.palette.divider}`,
borderTop: 0,
borderLeft: 0,
borderBottomRightRadius: theme.shape.borderRadiusMedium,
}));
type ColumnAlignment = 'start' | 'end' | 'center';
export const StyledSidePanelListColumn = styled('div', {
shouldForwardProp: (prop) => prop !== 'maxWidth' && prop !== 'align',
})<{ maxWidth?: number; align?: ColumnAlignment }>(
({ theme, maxWidth, align = 'start' }) => ({
display: 'flex',
flex: 1,
padding: theme.spacing(2),
fontSize: theme.fontSizes.smallBody,
justifyContent: align,
...(maxWidth && { maxWidth }),
textAlign: align,
alignItems: 'center',
}),
);
export type SidePanelListColumn<T> = {
header: string;
maxWidth?: number;
align?: ColumnAlignment;
cell: (item: T) => ReactNode;
};
interface ISidePanelListProps<T> {
items: T[];
columns: SidePanelListColumn<T>[];
sidePanelHeader: string;
renderContent: (item: T) => ReactNode;
renderItem?: (item: T, children: ReactNode) => ReactNode;
height?: number;
listEnd?: ReactNode;
}
export const SidePanelList = <T extends { id: string | number }>({
items,
columns,
sidePanelHeader,
renderContent,
renderItem = (_, children) => children,
height,
listEnd,
}: ISidePanelListProps<T>) => {
const [selectedItem, setSelectedItem] = useState<T>(items[0]);
if (items.length === 0) {
return null;
}
const activeItem = selectedItem || items[0];
const leftPanelMaxWidth = columns.every(({ maxWidth }) => Boolean(maxWidth))
? columns.reduce((acc, { maxWidth }) => acc + (maxWidth || 0), 0)
: undefined;
return (
<StyledSidePanelListWrapper>
<SidePanelListHeader
columns={columns}
sidePanelHeader={sidePanelHeader}
leftPanelMaxWidth={leftPanelMaxWidth}
/>
<StyledSidePanelListBody>
<StyledSidePanelHalfLeft
height={height}
maxWidth={leftPanelMaxWidth}
>
{items.map((item) =>
renderItem(
item,
<SidePanelListItem
key={item.id}
selected={activeItem.id === item.id}
onClick={() => setSelectedItem(item)}
>
{columns.map(
({ header, maxWidth, align, cell }) => (
<StyledSidePanelListColumn
key={header}
maxWidth={maxWidth}
align={align}
>
{cell(item)}
</StyledSidePanelListColumn>
),
)}
</SidePanelListItem>,
),
)}
{listEnd}
</StyledSidePanelHalfLeft>
<StyledSidePanelHalfRight>
{renderContent(activeItem)}
</StyledSidePanelHalfRight>
</StyledSidePanelListBody>
</StyledSidePanelListWrapper>
);
};