Skip to content

Instantly share code, notes, and snippets.

@dimitur2204
Last active June 5, 2024 20:00
Show Gist options
  • Save dimitur2204/3a54af0a32cdcb7cded30b69ff2928a0 to your computer and use it in GitHub Desktop.
Save dimitur2204/3a54af0a32cdcb7cded30b69ff2928a0 to your computer and use it in GitHub Desktop.
MUI Radio with MUI Collapse Content (also accessible <3)
import React from 'react'
import {
Box,
BoxProps,
Collapse,
FormControl,
FormControlLabel,
Radio,
RadioGroup,
RadioGroupProps,
} from '@mui/material'
import { CardGiftcard, Check, Cyclone } from '@mui/icons-material'
import { styled } from '@mui/material/styles'
// Theme is a MUI theme object with an addedproperty of borders
// { borders: { semiRound: '4px' } }
import theme from 'common/theme'
export const BaseRadioAccordionItem = styled(Box)(() => ({
'&:first-child': {
borderBottom: `1px solid ${theme.borders.dark}`,
borderTopLeftRadius: theme.borders.semiRound,
borderTopRightRadius: theme.borders.semiRound,
},
'&:not(:last-child)': {
borderBottom: `1px solid ${theme.borders.dark}`,
},
'&:last-child': {
borderBottomLeftRadius: theme.borders.semiRound,
borderBottomRightRadius: theme.borders.semiRound,
},
padding: theme.spacing(2),
margin: 0,
cursor: 'pointer',
}))
export const DisabledRadioAccordionItem = styled(BaseRadioAccordionItem)(() => ({
opacity: 0.7,
backgroundColor: `${theme.palette.grey[300]} !important`,
pointerEvents: 'none',
}))
interface RadioAccordionItemProps extends BoxProps {
control: React.ReactNode
icon: React.ReactNode
content?: React.ReactNode
selected?: boolean
disabled?: boolean
}
// Temporarily here for testing until the components starts being used
export const testRadioOptions: Option[] = [
{
value: 'card',
label: 'Card',
icon: <Check sx={{ width: 80, height: 80 }} />,
content: <div>Card content</div>,
},
{
value: 'bank',
label: 'Bank',
icon: <Cyclone sx={{ width: 80, height: 80 }} />,
content: <div>Bank content</div>,
},
{
value: 'paypal',
label: 'PayPal',
icon: <CardGiftcard sx={{ width: 80, height: 80 }} />,
content: <div>Paypal content</div>,
},
]
function RadioAccordionItem({
control,
icon,
selected,
content,
disabled,
...rest
}: RadioAccordionItemProps) {
let StyledRadioAccordionItem = BaseRadioAccordionItem
if (disabled) {
StyledRadioAccordionItem = DisabledRadioAccordionItem
}
return (
<StyledRadioAccordionItem {...rest}>
<Box display="flex" justifyContent="space-between" alignItems="center">
{control}
{icon}
</Box>
<Collapse unmountOnExit in={selected}>
{content}
</Collapse>
</StyledRadioAccordionItem>
)
}
type Option = {
value: string
label: string
content: React.ReactNode
icon: React.ReactNode
}
export interface RadioAccordionGroupProps extends RadioGroupProps {
options: Option[]
defaultValue?: string
}
function RadioAccordionGroup({ options, defaultValue }: RadioAccordionGroupProps) {
const [value, setValue] = React.useState(defaultValue)
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setValue(event.target.value)
}
return (
<FormControl>
<RadioGroup
aria-labelledby="TODO: Label by the title"
name="controlled-radio-buttons-group"
value={value}
onChange={handleChange}
sx={{
border: `1px solid ${theme.palette.primary.main}`,
borderRadius: theme.borders.semiRound,
}}>
{options.map((option) => (
<RadioAccordionItem
key={option.value}
onClick={() => setValue(option.value)}
control={
<FormControlLabel value={option.value} control={<Radio />} label={option.label} />
}
icon={option.icon}
selected={value === option.value}
content={option.content}
/>
))}
</RadioGroup>
</FormControl>
)
}
export default RadioAccordionGroup
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment