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.
111 lines
2.4 KiB
111 lines
2.4 KiB
import { |
|
Done as MUIDoneIcon, |
|
Edit as MUIEditIcon, |
|
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, |
|
BORDER_RADIUS, |
|
DISABLED, |
|
GREY, |
|
} 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 NormalIconButton = styled(MUIIconButton)({ |
|
color: GREY, |
|
}); |
|
|
|
const MAP_TO_VISIBILITY_ICON: IconButtonMapToStateIcon = { |
|
false: MUIVisibilityIcon, |
|
true: MUIVisibilityOffIcon, |
|
}; |
|
|
|
const MAP_TO_EDIT_ICON: IconButtonMapToStateIcon = { |
|
false: MUIEditIcon, |
|
true: MUIDoneIcon, |
|
}; |
|
|
|
const MAP_TO_MAP_PRESET: Record< |
|
IconButtonPresetMapToStateIcon, |
|
IconButtonMapToStateIcon |
|
> = { |
|
edit: MAP_TO_EDIT_ICON, |
|
visibility: MAP_TO_VISIBILITY_ICON, |
|
}; |
|
|
|
const MAP_TO_VARIANT: Record<IconButtonVariant, CreatableComponent> = { |
|
contained: ContainedIconButton, |
|
normal: NormalIconButton, |
|
}; |
|
|
|
const IconButton: FC<IconButtonProps> = ({ |
|
children, |
|
defaultIcon, |
|
iconProps, |
|
mapPreset, |
|
mapToIcon: externalMapToIcon, |
|
state, |
|
variant = 'contained', |
|
...restIconButtonProps |
|
}) => { |
|
const mapToIcon = useMemo<IconButtonMapToStateIcon | undefined>( |
|
() => externalMapToIcon ?? (mapPreset && MAP_TO_MAP_PRESET[mapPreset]), |
|
[externalMapToIcon, mapPreset], |
|
); |
|
|
|
const iconButtonContent = useMemo(() => { |
|
let result: ReactNode; |
|
|
|
if (mapToIcon) { |
|
const iconElementType: CreatableComponent | undefined = state |
|
? mapToIcon[state] ?? defaultIcon |
|
: defaultIcon; |
|
|
|
if (iconElementType) { |
|
result = createElement(iconElementType, iconProps); |
|
} |
|
} else { |
|
result = children; |
|
} |
|
|
|
return result; |
|
}, [children, mapToIcon, state, defaultIcon, iconProps]); |
|
const iconButtonElementType = useMemo( |
|
() => MAP_TO_VARIANT[variant], |
|
[variant], |
|
); |
|
|
|
return createElement( |
|
iconButtonElementType, |
|
restIconButtonProps, |
|
iconButtonContent, |
|
); |
|
}; |
|
|
|
export type { IconButtonProps }; |
|
|
|
export default IconButton;
|
|
|