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.
63 lines
1.6 KiB
63 lines
1.6 KiB
import { |
|
Check as MUICheckIcon, |
|
Close as MUICloseIcon, |
|
} from '@mui/icons-material'; |
|
import { cloneElement, createElement, FC, ReactElement } from 'react'; |
|
|
|
import { BLUE, PURPLE } from '../lib/consts/DEFAULT_THEME'; |
|
|
|
import FlexBox from './FlexBox'; |
|
import { BodyText, SmallText } from './Text'; |
|
|
|
type StateTypeMap = Pick<MapToType, 'boolean'>; |
|
|
|
type StateMap<TypeName extends keyof StateTypeMap> = Map< |
|
StateTypeMap[TypeName], |
|
ReactElement |
|
>; |
|
|
|
type LabelMap = Record<'small' | 'medium', FC>; |
|
|
|
type StateOptionalProps<TypeName extends keyof StateTypeMap> = { |
|
size?: keyof LabelMap; |
|
stateMap?: StateMap<TypeName>; |
|
}; |
|
|
|
type StateProps<TypeName extends keyof StateTypeMap> = |
|
StateOptionalProps<TypeName> & { |
|
label: string; |
|
state: StateTypeMap[TypeName]; |
|
}; |
|
|
|
const MAP_TO_TEXT_ELEMENT: LabelMap = { |
|
small: SmallText, |
|
medium: BodyText, |
|
}; |
|
|
|
const STATE_DEFAULT_PROPS: Required<StateOptionalProps<'boolean'>> = { |
|
size: 'small', |
|
stateMap: new Map<boolean, ReactElement>([ |
|
[false, <MUICloseIcon key="state-false" sx={{ color: PURPLE }} />], |
|
[true, <MUICheckIcon key="state-true" sx={{ color: BLUE }} />], |
|
]), |
|
}; |
|
|
|
const State = <TypeName extends keyof StateTypeMap>({ |
|
label, |
|
size = STATE_DEFAULT_PROPS.size, |
|
state, |
|
stateMap = STATE_DEFAULT_PROPS.stateMap, |
|
}: StateProps<TypeName>): ReturnType<FC<StateProps<TypeName>>> => { |
|
const stateIcon = stateMap.get(state); |
|
|
|
return ( |
|
<FlexBox row spacing=".3em"> |
|
{stateIcon && cloneElement(stateIcon, { fontSize: size })} |
|
{createElement(MAP_TO_TEXT_ELEMENT[size], {}, label)} |
|
</FlexBox> |
|
); |
|
}; |
|
|
|
State.defaultProps = STATE_DEFAULT_PROPS; |
|
|
|
export default State;
|
|
|