Skip to content

Commit

Permalink
feat: Introduce RadioPanel component
Browse files Browse the repository at this point in the history
This commit introduces a RadioPanel component.

JIRA ATLAS-3145
  • Loading branch information
diogoredin committed Aug 31, 2023
1 parent e9c1362 commit ebfbd16
Show file tree
Hide file tree
Showing 5 changed files with 165 additions and 7 deletions.
8 changes: 3 additions & 5 deletions src/components/RadioGroup/Radio.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,14 @@ const StyledInput = styled.input`
`

export interface RadioProps extends InputHTMLAttributes<HTMLInputElement> {
$loading?: boolean
loading?: boolean
}

export const Radio = forwardRef(
(props: RadioProps, ref: Ref<HTMLInputElement>) => (
({ loading, ...props }: RadioProps, ref: Ref<HTMLInputElement>) => (
<Container>
<StyledInput type="radio" ref={ref} {...props} />
<Icon>
{props.$loading ? <Spinner size={16} /> : <Checkmark size={16} />}
</Icon>
<Icon>{loading ? <Spinner size={16} /> : <Checkmark size={16} />}</Icon>
</Container>
)
)
62 changes: 62 additions & 0 deletions src/components/RadioGroup/RadioPanel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import React, { ChangeEvent, ReactNode } from 'react'
import { Panel, PanelBody, PanelContent } from '../Panel'
import styled from '@emotion/styled'
import { Radio, RadioProps } from '../RadioGroup/Radio'
import { fontWeight, space } from '../../theme'
import { Label } from '../Input'

export interface RadioOption
extends Omit<RadioProps, 'id' | 'value' | 'label'> {
id: string
value: string
label: ReactNode
description?: ReactNode
}

export interface RadioPanelProps {
options: RadioOption[]
value: string
name: string
loading: string
onChange: (event: ChangeEvent<HTMLInputElement>) => void
}

const Wrapper = styled.span`
label {
display: grid;
grid-template-columns: ${space[24]} 1fr;
align-items: center;
gap: ${space[16]};
font-weight: ${fontWeight.semiBold};
}
`

export const RadioPanel = ({
name,
value,
options = [],
loading,
onChange,
}: RadioPanelProps) => (
<Panel>
{options.map(({ description = <></>, ...option }) => (
<PanelContent key={option.id}>
<PanelBody>
<Wrapper>
<Label htmlFor={option.id}>
<Radio
name={name}
checked={option.value === value}
loading={loading !== '' && option.value === loading}
onChange={onChange}
{...option}
/>
{option.label}
</Label>
</Wrapper>
{description}
</PanelBody>
</PanelContent>
))}
</Panel>
)
100 changes: 98 additions & 2 deletions src/components/RadioGroup/index.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,33 @@
import React, { useState } from 'react'
import { RadioGroup } from '.'
import styled from '@emotion/styled'
import { color, space } from '../../theme'
import { Text } from '../Text'
import { Checkmark } from '../../icons'
import { Instruction } from '../Instruction'
import { RadioGroup } from './RadioGroup'
import { RadioPanel } from './RadioPanel'

export default {
title: 'Components/Inputs/RadioGroup',
}

export const Basic = () => {
const Price = styled(Text)`
color: ${color.foregroundMuted};
margin-inline-start: ${space[40]};
`

const USPS = styled.div`
margin-block-start: ${space[16]};
margin-block-end: ${space[16]};
`

const USP = styled.div`
display: flex;
gap: ${space[8]};
margin-block-end: ${space[16]};
`

export const Default = () => {
const [value, setValue] = useState('')

return (
Expand All @@ -31,3 +52,78 @@ export const Basic = () => {
/>
)
}

export const WithPanel = () => {
const [value, setValue] = useState('')
const [loading, setLoading] = useState('')

return (
<RadioPanel
name="Ice Cream"
options={[
{
id: '1',
value: '1',
label: 'With chocolate topping',
description: (
<>
<Price>2.00€</Price>
<USPS>
<USP>
<Checkmark size={24} color={color.info} />
<Text as="p">Rich Source of Antioxidants</Text>
</USP>
<USP>
<Checkmark size={24} color={color.info} />
<Text as="p">Heart Health</Text>
</USP>
<USP>
<Checkmark size={24} color={color.info} />
<Text as="p">Improved Mood</Text>
</USP>
</USPS>
</>
),
},
{
id: '2',
value: '2',
label: 'With almonds topping',
description: (
<>
<Price>2.50€</Price>
<USPS>
<USP>
<Checkmark size={24} color={color.info} />
<Text as="p">Nutrient-Rich</Text>
</USP>
<USP>
<Checkmark size={24} color={color.info} />
<Text as="p">Blood Sugar Control</Text>
</USP>
<USP>
<Checkmark size={24} color={color.info} />
<Text as="p">Brain Health</Text>
</USP>
</USPS>
</>
),
},
{
id: '3',
value: '3',
label: 'Without extras',
},
]}
value={value}
loading={loading}
onChange={event => {
setLoading(event.target.value)
setTimeout(() => {
setValue(event.target.value)
setLoading('')
}, 500)
}}
/>
)
}
1 change: 1 addition & 0 deletions src/components/RadioGroup/index.tsx
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { RadioGroup } from './RadioGroup'
export { RadioPanel } from './RadioPanel'
1 change: 1 addition & 0 deletions src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export { Tooltip } from './Tooltip'
export { DatePicker } from './DatePicker'
export { Label } from './Label'
export { RadioGroup } from './RadioGroup'
export { RadioPanel } from './RadioGroup'
export { Instruction } from './Instruction'
export { Textarea } from './Textarea'
export { Input as InputV2 } from './InputV2'
Expand Down

0 comments on commit ebfbd16

Please sign in to comment.