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.
143 lines
3.5 KiB
143 lines
3.5 KiB
import { Box as MUIBox, BoxProps as MUIBoxProps } from '@mui/material'; |
|
import { FC, useMemo } from 'react'; |
|
|
|
type FlexBoxDirection = 'column' | 'row'; |
|
|
|
type FlexBoxSpacing = number | string; |
|
|
|
type FlexBoxOptionalPropsWithDefault = { |
|
fullWidth?: boolean; |
|
growFirst?: boolean; |
|
row?: boolean; |
|
spacing?: FlexBoxSpacing; |
|
xs?: FlexBoxDirection; |
|
}; |
|
|
|
type FlexBoxOptionalPropsWithoutDefault = { |
|
columnSpacing?: FlexBoxSpacing; |
|
rowSpacing?: FlexBoxSpacing; |
|
lg?: FlexBoxDirection; |
|
md?: FlexBoxDirection; |
|
sm?: FlexBoxDirection; |
|
xl?: FlexBoxDirection; |
|
}; |
|
|
|
type FlexBoxOptionalProps = FlexBoxOptionalPropsWithDefault & |
|
FlexBoxOptionalPropsWithoutDefault; |
|
|
|
type FlexBoxProps = MUIBoxProps & FlexBoxOptionalProps; |
|
|
|
const FLEX_BOX_DEFAULT_PROPS: Required<FlexBoxOptionalPropsWithDefault> & |
|
FlexBoxOptionalPropsWithoutDefault = { |
|
columnSpacing: undefined, |
|
fullWidth: false, |
|
growFirst: false, |
|
row: false, |
|
rowSpacing: undefined, |
|
lg: undefined, |
|
md: undefined, |
|
sm: undefined, |
|
spacing: '1em', |
|
xl: undefined, |
|
xs: 'column', |
|
}; |
|
|
|
const FlexBox: FC<FlexBoxProps> = ({ |
|
fullWidth, |
|
growFirst, |
|
lg: dLg = FLEX_BOX_DEFAULT_PROPS.lg, |
|
md: dMd = FLEX_BOX_DEFAULT_PROPS.md, |
|
row: isRow, |
|
sm: dSm = FLEX_BOX_DEFAULT_PROPS.sm, |
|
spacing = FLEX_BOX_DEFAULT_PROPS.spacing, |
|
sx, |
|
xl: dXl = FLEX_BOX_DEFAULT_PROPS.xl, |
|
xs: dXs = FLEX_BOX_DEFAULT_PROPS.xs, |
|
// Input props that depend on other input props. |
|
columnSpacing = spacing, |
|
rowSpacing = spacing, |
|
...muiBoxRestProps |
|
}) => { |
|
const xs = useMemo(() => (isRow ? 'row' : dXs), [dXs, isRow]); |
|
const sm = useMemo(() => dSm || xs, [dSm, xs]); |
|
const md = useMemo(() => dMd || sm, [dMd, sm]); |
|
const lg = useMemo(() => dLg || md, [dLg, md]); |
|
const xl = useMemo(() => dXl || lg, [dXl, lg]); |
|
|
|
const mapToSx: Record< |
|
FlexBoxDirection, |
|
{ |
|
alignItems: string; |
|
marginLeft: FlexBoxSpacing; |
|
marginTop: FlexBoxSpacing; |
|
} |
|
> = useMemo( |
|
() => ({ |
|
column: { |
|
alignItems: 'normal', |
|
marginLeft: 0, |
|
marginTop: columnSpacing, |
|
}, |
|
row: { |
|
alignItems: 'center', |
|
marginLeft: rowSpacing, |
|
marginTop: 0, |
|
}, |
|
}), |
|
[columnSpacing, rowSpacing], |
|
); |
|
const firstChildFlexGrow = useMemo( |
|
() => (growFirst ? 1 : undefined), |
|
[growFirst], |
|
); |
|
const width = useMemo(() => (fullWidth ? '100%' : undefined), [fullWidth]); |
|
|
|
return ( |
|
<MUIBox |
|
{...{ |
|
...muiBoxRestProps, |
|
sx: { |
|
alignItems: { |
|
xs: mapToSx[xs].alignItems, |
|
sm: mapToSx[sm].alignItems, |
|
md: mapToSx[md].alignItems, |
|
lg: mapToSx[lg].alignItems, |
|
xl: mapToSx[xl].alignItems, |
|
}, |
|
display: 'flex', |
|
flexDirection: { xs, sm, md, lg, xl }, |
|
width, |
|
|
|
'& > :first-child': { |
|
flexGrow: firstChildFlexGrow, |
|
}, |
|
|
|
'& > :not(:first-child)': { |
|
marginLeft: { |
|
xs: mapToSx[xs].marginLeft, |
|
sm: mapToSx[sm].marginLeft, |
|
md: mapToSx[md].marginLeft, |
|
lg: mapToSx[lg].marginLeft, |
|
xl: mapToSx[xl].marginLeft, |
|
}, |
|
marginTop: { |
|
xs: mapToSx[xs].marginTop, |
|
sm: mapToSx[sm].marginTop, |
|
md: mapToSx[md].marginTop, |
|
lg: mapToSx[lg].marginTop, |
|
xl: mapToSx[xl].marginTop, |
|
}, |
|
}, |
|
|
|
...sx, |
|
}, |
|
}} |
|
/> |
|
); |
|
}; |
|
|
|
FlexBox.defaultProps = FLEX_BOX_DEFAULT_PROPS; |
|
|
|
export type { FlexBoxProps }; |
|
|
|
export default FlexBox;
|
|
|