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.

151 lines
3.4 KiB

import {
Delete as MUIDeleteIcon,
Add as MUIAddIcon,
Close as MUICloseIcon,
Done as MUIDoneIcon,
Edit as MUIEditIcon,
PlayCircle as MUIPlayCircleIcon,
Visibility as MUIVisibilityIcon,
VisibilityOff as MUIVisibilityOffIcon,
} from '@mui/icons-material';
import {
IconButton as MUIIconButton,
IconButtonProps as MUIIconButtonProps,
inputClasses as muiInputClasses,
styled,
} from '@mui/material';
import { createElement, FC, ReactNode, useMemo } from 'react';
import {
BLACK,
BLUE,
BORDER_RADIUS,
DISABLED,
GREY,
RED,
} from '../../lib/consts/DEFAULT_THEME';
type IconButtonProps = IconButtonOptionalProps & MUIIconButtonProps;
const ContainedIconButton = styled(MUIIconButton)({
borderRadius: BORDER_RADIUS,
backgroundColor: GREY,
color: BLACK,
'&:hover': {
backgroundColor: `${GREY}F0`,
},
[`&.${muiInputClasses.disabled}`]: {
backgroundColor: DISABLED,
},
});
const RedContainedIconButton = styled(ContainedIconButton)({
backgroundColor: RED,
color: GREY,
'&:hover': {
backgroundColor: `${RED}F0`,
},
});
const NormalIconButton = styled(MUIIconButton)({
color: GREY,
});
const MAP_TO_ADD_ICON: IconButtonMapToStateIconBundle = {
none: { iconType: MUIAddIcon },
};
const MAP_TO_CLOSE_ICON: IconButtonMapToStateIconBundle = {
none: { iconType: MUICloseIcon },
};
const MAP_TO_DELETE_ICON: IconButtonMapToStateIconBundle = {
none: { iconType: MUIDeleteIcon },
};
const MAP_TO_EDIT_ICON: IconButtonMapToStateIconBundle = {
false: { iconType: MUIEditIcon },
true: { iconType: MUIDoneIcon, iconProps: { sx: { color: BLUE } } },
};
const MAP_TO_PLAY_ICON: IconButtonMapToStateIconBundle = {
none: { iconType: MUIPlayCircleIcon },
};
const MAP_TO_VISIBILITY_ICON: IconButtonMapToStateIconBundle = {
false: { iconType: MUIVisibilityIcon },
true: { iconType: MUIVisibilityOffIcon },
};
const MAP_TO_MAP_PRESET: Record<
IconButtonPresetMapToStateIconBundle,
IconButtonMapToStateIconBundle
> = {
add: MAP_TO_ADD_ICON,
close: MAP_TO_CLOSE_ICON,
delete: MAP_TO_DELETE_ICON,
edit: MAP_TO_EDIT_ICON,
play: MAP_TO_PLAY_ICON,
visibility: MAP_TO_VISIBILITY_ICON,
};
const MAP_TO_VARIANT: Record<IconButtonVariant, CreatableComponent> = {
contained: ContainedIconButton,
normal: NormalIconButton,
redcontained: RedContainedIconButton,
};
const IconButton: FC<IconButtonProps> = ({
children,
defaultIcon,
iconProps,
mapPreset,
mapToIcon: externalMapToIcon,
state = 'none',
variant = 'contained',
...restIconButtonProps
}) => {
const mapToIcon = useMemo<IconButtonMapToStateIconBundle | undefined>(
() => externalMapToIcon ?? (mapPreset && MAP_TO_MAP_PRESET[mapPreset]),
[externalMapToIcon, mapPreset],
);
const iconButtonContent = useMemo(() => {
let result: ReactNode;
if (mapToIcon) {
const { iconType, iconProps: presetIconProps } = mapToIcon[state] ?? {
iconType: defaultIcon,
};
if (iconType) {
result = createElement(iconType, {
...presetIconProps,
...iconProps,
});
}
} else {
result = children;
}
return result;
}, [mapToIcon, state, defaultIcon, iconProps, children]);
const iconButtonElementType = useMemo(
() => MAP_TO_VARIANT[variant],
[variant],
);
return createElement(
iconButtonElementType,
restIconButtonProps,
iconButtonContent,
);
};
export type { IconButtonProps };
export default IconButton;