Skip to content

Commit

Permalink
refactor(Radio): Upgrade Radio Component to Ant Design 5 (#32004)
Browse files Browse the repository at this point in the history
  • Loading branch information
EnxDev authored Jan 31, 2025
1 parent 1c1494d commit 468bb5f
Show file tree
Hide file tree
Showing 17 changed files with 294 additions and 200 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@

import { useCallback, useState, FormEvent } from 'react';

import { Radio } from 'src/components/Radio';
import { RadioChangeEvent, AsyncSelect } from 'src/components';
import { Radio, RadioChangeEvent } from 'src/components/Radio';
import { AsyncSelect } from 'src/components';
import { Input } from 'src/components/Input';
import StyledModal from 'src/components/Modal';
import Button from 'src/components/Button';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,33 +32,21 @@ export const useDisplayModeToggle = () => {
<div
css={(theme: SupersetTheme) => css`
margin-bottom: ${theme.gridUnit * 6}px;
.ant-radio-button-wrapper-checked:not(
.ant-radio-button-wrapper-disabled
):focus-within {
box-shadow: none;
}
`}
data-test="drill-by-display-toggle"
>
<Radio.Group
<Radio.GroupWrapper
onChange={({ target: { value } }) => {
setDrillByDisplayMode(value);
}}
defaultValue={DrillByType.Chart}
>
<Radio.Button
value={DrillByType.Chart}
data-test="drill-by-chart-radio"
>
{t('Chart')}
</Radio.Button>
<Radio.Button
value={DrillByType.Table}
data-test="drill-by-table-radio"
>
{t('Table')}
</Radio.Button>
</Radio.Group>
options={[
{ label: t('Chart'), value: DrillByType.Chart },
{ label: t('Table'), value: DrillByType.Table },
]}
optionType="button"
buttonStyle="outline"
/>
</div>
),
[],
Expand Down
149 changes: 124 additions & 25 deletions superset-frontend/src/components/Radio/Radio.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,40 +16,139 @@
* specific language governing permissions and limitations
* under the License.
*/
import { useArgs } from '@storybook/preview-api';
import { Radio } from './index';
import { Space } from 'src/components/Space';
import {
BarChartOutlined,
DotChartOutlined,
LineChartOutlined,
PieChartOutlined,
} from '@ant-design/icons';
import { Radio, RadioProps, RadioGroupWrapperProps } from './index';

export default {
title: 'Radio',
component: Radio,
parameters: {
controls: { hideNoControlsWarning: true },
},
argTypes: {
theme: {
table: {
disable: true,
},
},
checked: { control: 'boolean' },
disabled: { control: 'boolean' },
tags: ['autodocs'],
};

const RadioArgsType = {
value: {
control: 'text',
description: 'The value of the radio button.',
},
disabled: {
control: 'boolean',
description: 'Whether the radio button is disabled or not.',
},
checked: {
control: 'boolean',
description: 'The checked state of the radio button.',
},
};

export const SupersetRadio = () => {
const [{ checked, ...rest }, updateArgs] = useArgs();
return (
<Radio
checked={checked}
onChange={() => updateArgs({ checked: !checked })}
{...rest}
>
Example
</Radio>
);
const radioGroupWrapperArgsType = {
onChange: { action: 'changed' },
disabled: { control: 'boolean' },
size: {
control: 'select',
options: ['small', 'middle', 'large'],
},
options: { control: 'object' },
'spaceConfig.direction': {
control: 'select',
options: ['horizontal', 'vertical'],
description: 'Direction of the Space layout',
if: { arg: 'enableSpaceConfig', truthy: true },
},
'spaceConfig.size': {
control: 'select',
options: ['small', 'middle', 'large'],
description: 'Layout size Space',
if: { arg: 'enableSpaceConfig', truthy: true },
},
'spaceConfig.align': {
control: 'select',
options: ['start', 'center', 'end'],
description: 'Alignment of the Space layout',
if: { arg: 'enableSpaceConfig', truthy: true },
},
'spaceConfig.wrap': {
control: 'boolean',
description:
'Controls whether the items inside the Space component should wrap to the next line when space is insufficient',
if: { arg: 'enableSpaceConfig', truthy: true },
},
};

SupersetRadio.args = {
export const RadioStory = {
args: {
value: 'radio1',
disabled: false,
checked: false,
children: 'Radio',
},
argTypes: RadioArgsType,
};

export const RadioButtonStory = (args: RadioProps) => (
<Radio.Button {...args}>Radio Button</Radio.Button>
);
RadioButtonStory.args = {
value: 'button1',
disabled: false,
checked: false,
};
RadioButtonStory.argTypes = RadioArgsType;

export const RadioGroupWithOptionsStory = (args: RadioGroupWrapperProps) => (
<Radio.GroupWrapper {...args} />
);
RadioGroupWithOptionsStory.args = {
spaceConfig: {
direction: 'vertical',
size: 'middle',
align: 'center',
wrap: false,
},
size: 'middle',
options: [
{
value: 1,
label: (
<Space align="center" direction="vertical">
<LineChartOutlined style={{ fontSize: 18 }} />
LineChart
</Space>
),
},
{
value: 2,
label: (
<Space align="center" direction="vertical">
<DotChartOutlined style={{ fontSize: 18 }} />
DotChart
</Space>
),
},
{
value: 3,
label: (
<Space align="center" direction="vertical">
<BarChartOutlined style={{ fontSize: 18 }} />
BarChart
</Space>
),
},
{
value: 4,
label: (
<Space align="center" direction="vertical">
<PieChartOutlined style={{ fontSize: 18 }} />
PieChart
</Space>
),
},
],
disabled: false,
};
RadioGroupWithOptionsStory.argTypes = radioGroupWrapperArgsType;
80 changes: 41 additions & 39 deletions superset-frontend/src/components/Radio/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,46 +16,48 @@
* specific language governing permissions and limitations
* under the License.
*/
import { styled } from '@superset-ui/core';
import { Radio as AntdRadio } from 'antd';
import { Radio as Antd5Radio, CheckboxOptionType } from 'antd-v5';
import type {
RadioChangeEvent,
RadioProps,
RadioGroupProps,
} from 'antd-v5/lib/radio';

const StyledRadio = styled(AntdRadio)`
.ant-radio-inner {
top: -1px;
left: 2px;
width: ${({ theme }) => theme.gridUnit * 4}px;
height: ${({ theme }) => theme.gridUnit * 4}px;
border-width: 2px;
border-color: ${({ theme }) => theme.colors.grayscale.light2};
}
import { Space, SpaceProps } from 'src/components/Space';

.ant-radio.ant-radio-checked {
.ant-radio-inner {
border-width: ${({ theme }) => theme.gridUnit + 1}px;
border-color: ${({ theme }) => theme.colors.primary.base};
}
export type RadioGroupWrapperProps = RadioGroupProps & {
spaceConfig?: {
direction?: SpaceProps['direction'];
size?: SpaceProps['size'];
align?: SpaceProps['align'];
wrap?: SpaceProps['wrap'];
};
options: CheckboxOptionType[];
};

.ant-radio-inner::after {
background-color: ${({ theme }) => theme.colors.grayscale.light5};
top: 0;
left: 0;
width: ${({ theme }) => theme.gridUnit + 2}px;
height: ${({ theme }) => theme.gridUnit + 2}px;
}
}
.ant-radio:hover,
.ant-radio:focus {
.ant-radio-inner {
border-color: ${({ theme }) => theme.colors.primary.dark1};
}
}
`;
const StyledGroup = styled(AntdRadio.Group)`
font-size: inherit;
`;

export const Radio = Object.assign(StyledRadio, {
Group: StyledGroup,
Button: AntdRadio.Button,
const RadioGroup = ({
spaceConfig,
options,
...props
}: RadioGroupWrapperProps) => {
const content = options.map((option: CheckboxOptionType) => (
<Radio key={option.value} value={option.value}>
{option.label}
</Radio>
));
return (
<Radio.Group {...props}>
{spaceConfig ? <Space {...spaceConfig}>{content}</Space> : content}
</Radio.Group>
);
};
export type {
RadioChangeEvent,
RadioGroupProps,
RadioProps,
CheckboxOptionType,
};
export const Radio = Object.assign(Antd5Radio, {
GroupWrapper: RadioGroup,
Button: Antd5Radio.Button,
});
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import { useState } from 'react';
import { css, useTheme } from '@superset-ui/core';
import { Radio } from 'src/components/Radio';
import { Space } from 'src/components/Space';
import Icons from 'src/components/Icons';
import Popover from 'src/components/Popover';

Expand Down Expand Up @@ -56,21 +55,20 @@ function HeaderWithRadioGroup(props: HeaderWithRadioGroupProps) {
>
{groupTitle}
</div>
<Radio.Group
<Radio.GroupWrapper
spaceConfig={{
direction: 'vertical',
size: 4,
wrap: false,
align: 'start',
}}
value={value}
onChange={e => {
onChange(e.target.value);
setPopoverVisible(false);
}}
>
<Space direction="vertical">
{groupOptions.map(option => (
<Radio key={option.value} value={option.value}>
{option.label}
</Radio>
))}
</Space>
</Radio.Group>
options={groupOptions}
/>
</div>
}
placement="bottomLeft"
Expand Down
Loading

0 comments on commit 468bb5f

Please sign in to comment.