Skip to content

Commit

Permalink
refactor theming of item
Browse files Browse the repository at this point in the history
  • Loading branch information
juliawegmayr committed Jan 23, 2024
1 parent 4f8ad32 commit 2d0a025
Show file tree
Hide file tree
Showing 3 changed files with 155 additions and 117 deletions.
5 changes: 5 additions & 0 deletions .changeset/purple-queens-breathe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@comet/admin": major
---

Delete "secondaryText" from "MenuItemClassKey"
261 changes: 146 additions & 115 deletions packages/admin/admin/src/mui/menu/Item.tsx
Original file line number Diff line number Diff line change
@@ -1,144 +1,175 @@
import { ComponentsOverrides, ListItem, ListItemIcon, ListItemProps, ListItemText, Theme } from "@mui/material";
import { createStyles, WithStyles, withStyles } from "@mui/styles";
import { ListItemButton, ListItemButtonProps, ListItemIcon, ListItemText } from "@mui/material";
import { ComponentsOverrides, css, styled, Theme, useThemeProps } from "@mui/material/styles";
import { ThemedComponentBaseProps } from "helpers/ThemedComponentBaseProps";
import * as React from "react";

import { MenuLevel } from "./CollapsibleItem";
import { MenuContext } from "./Context";

export type MenuItemClassKey = "root" | "level1" | "level2" | "hasIcon" | "hasSecondaryText" | "hasSecondaryAction";
export type MenuItemClassKey = "root" | "level1" | "level2" | "hasIcon" | "hasSecondaryAction";

type OwnerState = Pick<MenuItemProps, "level" | "icon" | "secondaryAction">;

const colors = {
textLevel1: "#242424",
textLevel2: "#17181A",
};

const styles = (theme: Theme) =>
createStyles<MenuItemClassKey, MenuItemProps & MuiListItemProps>({
root: {
flexShrink: 0,
"&:after": {
content: "''",
position: "absolute",
top: 0,
right: 0,
bottom: 0,
width: 2,
},
"& [class*='MuiListItemIcon-root']": {
color: colors.textLevel1,
minWidth: 28,
},
"& [class*='MuiListItemText-inset']": {
paddingLeft: 28,
},
"& [class*='MuiSvgIcon-root']": {
fontSize: 16,
},
},
level1: {
borderBottom: `1px solid ${theme.palette.grey[50]}`,
boxSizing: "border-box",
color: colors.textLevel1,
paddingLeft: 20,
paddingRight: 20,
paddingTop: 16,
paddingBottom: 16,
"&[class*='Mui-selected']": {
backgroundColor: theme.palette.grey[50],
color: theme.palette.primary.main,
"&:after": {
backgroundColor: theme.palette.primary.main,
},
"& [class*='MuiListItemIcon-root']": {
color: theme.palette.primary.main,
},
},
"& [class*='MuiListItemText-primary']": {
fontWeight: theme.typography.fontWeightMedium,
fontSize: 16,
lineHeight: "20px",
},
},
level2: {
color: colors.textLevel2,
paddingLeft: 20,
paddingRight: 20,
paddingTop: 10,
paddingBottom: 10,
"&:last-child": {
borderBottom: `1px solid ${theme.palette.grey[50]}`,
boxSizing: "border-box",
},
"&[class*='Mui-selected']": {
backgroundColor: theme.palette.primary.main,
color: "#fff",
"&:after": {
backgroundColor: theme.palette.primary.dark,
},
"&:hover": {
backgroundColor: theme.palette.primary.dark,
},
"& [class*='MuiListItemText-primary']": {
fontWeight: theme.typography.fontWeightBold,
},
},
"& [class*='MuiListItemText-root']": {
margin: 0,
},
"& [class*='MuiListItemText-primary']": {
fontWeight: theme.typography.fontWeightRegular,
fontSize: 14,
lineHeight: "20px",
},
},
hasIcon: {},
hasSecondaryText: {},
hasSecondaryAction: {
paddingRight: 18,
},
});
const Root = styled(ListItemButton, {
name: "CometAdminMenuItem",
slot: "root",
overridesResolver({ ownerState }: { ownerState: OwnerState }, styles) {
return [
styles.root,
ownerState.level === 1 && styles.level1,
ownerState.level === 2 && styles.level2,
ownerState.icon && styles.hasIcon,
ownerState.secondaryAction && styles.hasSecondaryAction,
];
},
})<{ ownerState: OwnerState }>(
({ theme, ownerState }) => css`
flex-shrink: 0;
flex-grow: 0;
&:after {
content: "";
position: absolute;
top: 0;
right: 0;
bottom: 0;
width: 2px;
}
.MuiListItemIcon-root {
color: ${colors.textLevel1};
min-width: 28px;
}
.MuiListItemText-inset {
padding-left: 28px;
}
.MuiSvgIcon-root {
font-size: 16px;
}
${ownerState.level === 1 &&
css`
border-bottom: 1px solid ${theme.palette.grey[50]};
box-sizing: border-box;
color: ${colors.textLevel1};
padding-left: 20px;
padding-right: 20px;
padding-top: 16px;
padding-bottom: 16px;
&.Mui-selected {
background-color: ${theme.palette.grey[50]};
color: ${theme.palette.primary.main};
&:after {
background-color: ${theme.palette.primary.main};
}
.MuiListItemIcon-root {
color: ${theme.palette.primary.main};
}
}
.MuiListItemText-primary {
font-weight: ${theme.typography.fontWeightMedium};
font-size: 16px;
line-height: 20px;
}
`}
${ownerState.level === 2 &&
css`
color: ${colors.textLevel2};
padding-left: 20px;
padding-right: 20px;
padding-top: 10px;
padding-bottom: 10px;
&:last-child {
border-bottom: 1px solid ${theme.palette.grey[50]};
box-sizing: border-box;
}
&.Mui-selected {
background-color: ${theme.palette.primary.main};
color: #fff;
&:after {
background-color: ${theme.palette.primary.dark};
}
&:hover {
background-color: ${theme.palette.primary.dark};
}
&.MuiListItemText-primary {
font-weight: ${theme.typography.fontWeightBold};
}
}
export interface MenuItemProps extends MenuLevel {
.MuiListItemText-root {
margin: 0;
}
.MuiListItemText-primary {
font-weight: ${theme.typography.fontWeightRegular};
font-size: 14px;
line-height: 20px;
}
`};
${ownerState.secondaryAction &&
css`
padding-right: 18px;
`}
`,
);

export interface MenuItemProps extends ThemedComponentBaseProps<{ root: typeof ListItemButton }>, MenuLevel, ListItemButtonProps {
primary: React.ReactNode;
secondary?: React.ReactNode;
icon?: React.ReactElement;
secondaryAction?: React.ReactNode;
secondaryText?: boolean;
}

type MuiListItemProps = Pick<ListItemProps, Exclude<keyof ListItemProps, "innerRef" | "button">> & { component?: React.ElementType };

const Item: React.FC<WithStyles<typeof styles> & MenuItemProps & MuiListItemProps> = ({
classes,
primary,
secondary,
icon,
level = 1,
secondaryAction,
...otherProps
}) => {
const context = React.useContext(MenuContext);
if (!context) throw new Error("Could not find context for menu");
if (level > 2) throw new Error("Maximum nesting level of 2 exceeded.");
export function MenuItem(inProps: MenuItemProps) {
const {
primary,
icon,
level = 1,
secondaryAction,
slotProps,
...otherProps
} = useThemeProps({
props: inProps,
name: "CometAdminMenuItem",
});

const ownerState: OwnerState = {
level,
icon,
secondaryAction,
};

const hasIcon = !!icon;

const listItemClasses = [classes.root];
if (level === 1) listItemClasses.push(classes.level1);
if (level === 2) listItemClasses.push(classes.level2);
if (hasIcon) listItemClasses.push(classes.hasIcon);
if (secondary) listItemClasses.push(classes.hasSecondaryText);
if (secondaryAction) listItemClasses.push(classes.hasSecondaryAction);
const context = React.useContext(MenuContext);
if (!context) throw new Error("Could not find context for menu");
if (level > 2) throw new Error("Maximum nesting level of 2 exceeded.");

return (
<ListItem component="div" button classes={{ root: listItemClasses.join(" ") }} {...otherProps}>
<Root {...slotProps?.root} ownerState={ownerState} {...otherProps}>
{hasIcon && <ListItemIcon>{icon}</ListItemIcon>}
<ListItemText primary={primary} secondary={secondary} inset={!icon} />
<ListItemText primary={primary} inset={!icon} />
{!!secondaryAction && secondaryAction}
</ListItem>
</Root>
);
};

export const MenuItem = withStyles(styles, { name: "CometAdminMenuItem" })(Item);
}

declare module "@mui/material/styles" {
interface ComponentNameToClassKey {
Expand Down
6 changes: 4 additions & 2 deletions packages/admin/admin/src/mui/menu/ItemAnchorLink.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { ListItemProps } from "@mui/material/ListItem";
import { ListItemButtonProps } from "@mui/material";
import * as React from "react";

import { MenuItem, MenuItemProps } from "./Item";

export const MenuItemAnchorLink: React.FC<MenuItemProps & ListItemProps & React.HTMLProps<HTMLAnchorElement>> = (props) => (
export const MenuItemAnchorLink: React.FC<MenuItemProps & ListItemButtonProps & React.HTMLProps<HTMLAnchorElement>> = (props) => (
// @ts-expect-error "component"-property is used as described in the documentation https://mui.com/material-ui/react-list/, but type is missing in ListItemButtonProps

<MenuItem selected={false} component="a" {...props} />
);

0 comments on commit 2d0a025

Please sign in to comment.