Skip to content

Commit

Permalink
Add custom style of radio button
Browse files Browse the repository at this point in the history
  • Loading branch information
m0neysha committed Aug 30, 2021
1 parent e6eb74e commit f1152e7
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 24 deletions.
68 changes: 46 additions & 22 deletions src/radio/Radio.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,16 @@ import {
radioButtonIconCSS,
radioChildrenCSS,
radioLabelCSS,
customRadioCSS,
} from './styles';
import { useId } from '@react-aria/utils';
import { Text } from '../content';

export type RadioProps = {
/**
* (Optional) For the custom style of radio buttons
*/
type?: 'default' | 'custom';
/**
* One or group of components that will sit under the radio option
*/
Expand Down Expand Up @@ -43,6 +48,7 @@ export type RadioProps = {
function Radio(props: RadioProps) {
const state = useRadioProvider();
const {
type = 'default',
children,
value,
noPadding,
Expand Down Expand Up @@ -83,6 +89,16 @@ function Radio(props: RadioProps) {
}
};

const radioChildren = children
? React.Children.map(
props.children,
child =>
child &&
// @ts-ignore
React.cloneElement(child, { isDisabled })
)
: null;

return (
<label
aria-disabled={isDisabled}
Expand All @@ -106,29 +122,37 @@ function Radio(props: RadioProps) {
ref={inputRef}
/>
</VisuallyHidden>
<Icon
svg={currentRadioButton}
css={radioButtonIconCSS({
isDisabled,
isFocusVisible,
})}
aria-label={value}
aria-hidden={true}
/>
<Text textSize="medium" color={isDisabled ? 'white30' : 'white90'}>
{label}
</Text>
{type === 'default' ? (
<>
<Icon
svg={currentRadioButton}
css={radioButtonIconCSS({
isDisabled,
isFocusVisible,
})}
aria-label={value}
aria-hidden={true}
/>
<Text textSize="medium" color={isDisabled ? 'white30' : 'white90'}>
{label}
</Text>
</>
) : (
<div
className="ac-custom-radio"
css={customRadioCSS({
isDisabled,
isSelected,
})}
aria-label={value}
aria-hidden={true}
>
{type === 'custom' && children && <>{radioChildren}</>}
</div>
)}
</div>
{children && (
<div css={radioChildrenCSS({ isInline })}>
{React.Children.map(
props.children,
child =>
child &&
// @ts-ignore
React.cloneElement(child, { isDisabled })
)}
</div>
{type === 'default' && children && (
<div css={radioChildrenCSS({ isInline })}>{radioChildren}</div>
)}
</label>
);
Expand Down
17 changes: 15 additions & 2 deletions src/radio/RadioGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ import { Text } from '../content';
import { RadioContext } from './context';

export interface RadioGroupProps {
/**
* (Optional) For the custom style of radio buttons
*/
type?: 'default' | 'custom';
children: ReactNode;
/**
* (Optional) For labelling the radio options
Expand All @@ -24,7 +28,7 @@ export interface RadioGroupProps {
}

function RadioGroup(props: RadioGroupProps) {
const { children, label } = props;
const { children, label, type } = props;
const labeledById = useId();

const state = useRadioGroupState(props);
Expand All @@ -47,7 +51,16 @@ function RadioGroup(props: RadioGroupProps) {
{label}
</Text>
)}
<RadioContext.Provider value={state}>{children}</RadioContext.Provider>
<RadioContext.Provider value={state}>
{children &&
React.Children.map(
children,
child =>
child &&
// @ts-ignore
React.cloneElement(child, { type })
)}
</RadioContext.Provider>
</div>
);
}
Expand Down
17 changes: 17 additions & 0 deletions src/radio/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,23 @@ export const radioCSS = ({
}
`;

export const customRadioCSS = ({
isSelected = false,
isDisabled = false,
}: {
isSelected?: boolean;
isDisabled?: boolean;
}) => css`
height: 50px;
width: 100%;
border-radius: 8px;
border: 1px solid
${isSelected ? theme.textColors.white90 : theme.colors.dividerColor};
color: ${isDisabled ? theme.textColors.white30 : theme.textColors.white90};
margin-right: ${theme.spacing.padding4}px;
padding: ${theme.spacing.padding16}px;
`;

export const radioButtonIconCSS = ({
isFocusVisible = false,
isDisabled = false,
Expand Down
32 changes: 32 additions & 0 deletions stories/Radio.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,32 @@ const Template: Story<RadioGroupProps> = args => (
</Card>
);

const CustomExample: Story<RadioGroupProps> = args => (
<Card title="Radio Info" style={{ width: 500 }}>
<RadioGroup type="custom" {...args}>
<Radio value="dogs" label="Dogs">
<Text>Dogs</Text>
</Radio>
<Radio value="cats" label="Cats">
<Text>Cats</Text>
</Radio>
<Radio value="parrot" label="Parrot">
<Text>Parrot</Text>
</Radio>
<Radio
isDisabled
value="frog"
label="Frog"
onClick={e => {
console.log('clicked radio option', e.currentTarget.value);
}}
>
<Text>Frog (isDisabled)</Text>
</Radio>
</RadioGroup>
</Card>
);

export const DefaultWithLabel = Template.bind({});

export const DefaultNoLabel = Template.bind({});
Expand All @@ -38,6 +64,8 @@ export const WithMoreChildren = Template.bind({});

export const Disabled = Template.bind({});

export const Custom = CustomExample.bind({});

const SomeChildren = () => (
<>
<Radio value="dogs" label="Dogs" />
Expand Down Expand Up @@ -89,5 +117,9 @@ DefaultWithLabel.args = {
label: 'Here are some animals',
};

Custom.args = {
defaultValue: 'dogs',
};

// By passing using the Args format for exported stories, you can control the props for a component for reuse in a test
// https://storybook.js.org/docs/react/workflows/unit-testing

0 comments on commit f1152e7

Please sign in to comment.