Skip to content

Commit

Permalink
feat: add Radio component
Browse files Browse the repository at this point in the history
  • Loading branch information
Jandiasnow committed Apr 12, 2024
1 parent 1e5a0cf commit 14ae57c
Show file tree
Hide file tree
Showing 7 changed files with 376 additions and 0 deletions.
36 changes: 36 additions & 0 deletions src/Radio/demos/Playground.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { StoryBook, useControls, useCreateStore } from '@lobehub/ui';
import { Radio, RadioGroupProps } from '@yuntijs/ui';

export default () => {
const store = useCreateStore();
const options = [
{ label: 'Apple', value: 'Apple' },
{ label: 'Pear', value: 'Pear' },
{ label: 'Orange', value: 'Orange', disabled: true },
];
const control: RadioGroupProps | any = useControls(
{
defaultValue: options[0].value,
disabled: false,
optionType: {
options: ['default', 'button'],
value: 'default',
},
buttonStyle: {
options: ['outline', 'solid'],
value: 'outline',
},
segmented: false,
size: {
options: ['large', 'middle', 'small'],
value: 'middle',
},
},
{ store }
);
return (
<StoryBook levaStore={store}>
<Radio.Group {...control} options={options} />
</StoryBook>
);
};
47 changes: 47 additions & 0 deletions src/Radio/demos/Segmented.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { Radio, Space } from '@yuntijs/ui';

export default () => {
const options = [
{ label: 'Apple', value: 'Apple' },
{ label: 'Pear', value: 'Pear' },
{ label: 'Orange', value: 'Orange', disabled: true },
];
return (
<Space direction="vertical">
<Radio.Group
defaultValue={options[0].value}
optionType="button"
options={options}
segmented={{
bordered: true,
borderRadius: 15,
gap: 15,
}}
/>
<Radio.Group
defaultValue={options[0].value}
optionType="button"
options={options}
segmented={true}
/>
<Radio.Group
buttonStyle="solid"
defaultValue={options[0].value}
optionType="button"
options={options}
segmented={{
bordered: true,
borderRadius: 15,
gap: 15,
}}
/>
<Radio.Group
buttonStyle="solid"
defaultValue={options[0].value}
optionType="button"
options={options}
segmented={true}
/>
</Space>
);
};
21 changes: 21 additions & 0 deletions src/Radio/demos/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Radio, Space } from '@yuntijs/ui';

export default () => {
const options = [
{ label: 'Apple', value: 'Apple' },
{ label: 'Pear', value: 'Pear' },
{ label: 'Orange', value: 'Orange', disabled: true },
];
return (
<Space direction="vertical">
<Radio.Group defaultValue={options[0].value} options={options} />
<Radio.Group defaultValue={options[0].value} optionType="button" options={options} />
<Radio.Group
buttonStyle="solid"
defaultValue={options[0].value}
optionType="button"
options={options}
/>
</Space>
);
};
41 changes: 41 additions & 0 deletions src/Radio/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
nav: Components
group: Data Entry
title: Radio
description: Used to select a single state from multiple options.
---

## Usage

based on antd [Radio](https://ant.design/components/radio-cn/) component.

### Simple usage

```jsx | pure
import { Radio } from '@yuntijs/ui';

export default () => {
const options = [
{ label: 'Apple', value: 'Apple' },
{ label: 'Pear', value: 'Pear' },
{ label: 'Orange', value: 'Orange', disabled: true },
];
return <Radio.Group options={options} defaultValue={options[0].value} />;
};
```

<code src="./demos/index.tsx" center></code>

### Segmented usage

**Set the button style is similar to the Segmented component, Generally used for in-page navigation**

<code src="./demos/Segmented.tsx" center></code>

## Playground

<code src="./demos/Playground.tsx" nopadding></code>

## APIs

<API></API>
55 changes: 55 additions & 0 deletions src/Radio/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { Radio as AntdRadio, type RadioGroupProps as AntdRadioGroupProps, RadioProps } from 'antd';
import AntdGroup from 'antd/es/radio/group';
import type { RadioRef } from 'antd/es/radio/interface';
import React from 'react';

import { useStyles } from './style';

export interface CustomRadioProps {
/**
* @description Set the button style is similar to the Segmented component
* @default 'false'
*/
segmented?:
| {
/**
* @description Set the spacing between buttons
* @default 'true'
*/
gap?: 'small' | 'middle' | 'large' | number | boolean;
/**
* @description Set border-radius of buttons
* @default 'true'
*/
borderRadius?: number | boolean;
/**
* @description Sets whether the button's border is displayed
* @default 'false'
*/
bordered?: boolean;
}
| boolean;
}

export interface RadioGroupProps extends AntdRadioGroupProps, CustomRadioProps {}

type RadioType = React.ForwardRefExoticComponent<RadioProps & React.RefAttributes<RadioRef>> & {
Group: typeof Group;
Button: typeof AntdRadio.Button;
};
export const Radio = AntdRadio as RadioType;

const Group: React.FC<RadioGroupProps> = props => {
const { className, ...otherProps } = props;
if (otherProps.segmented) {
otherProps.optionType = 'button';
}
const { styles, cx } = useStyles(otherProps);

return <AntdGroup {...otherProps} className={cx(styles.custom, className)} />;
};
Radio.Group = Group;

export default Radio;

export { type RadioChangeEvent, type RadioProps } from 'antd';
95 changes: 95 additions & 0 deletions src/Radio/style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { createStyles } from 'antd-style';

import { RadioGroupProps } from './index';

export const useStyles = createStyles(
({ css, token, prefixCls }, { size, segmented }: RadioGroupProps) => {
const gap = (() => {
if (!segmented) {
return 0;
}
if (segmented !== true) {
return segmented.gap;
}
return true;
})();

const borderRadius = (() => {
if (!segmented) {
return;
}
if (segmented !== true) {
return segmented.borderRadius;
}
return true;
})();

const getGapSize = () => {
const gapSizeMap = {
small: token.sizeSM,
middle: token.size,
large: token.sizeLG,
};
if (typeof gap === 'string') {
return gapSizeMap[gap];
}
if (gap === true) {
return size ? gapSizeMap[size] : gapSizeMap['middle'];
}
if (!gap) {
return 0;
}
return gap;
};

const getBorderRadius = () => {
const borderRadiusSizeMap = {
small: token.controlHeightSM,
middle: token.controlHeight,
large: token.controlHeightLG,
};
if (borderRadius === true) {
return size ? borderRadiusSizeMap[size] : borderRadiusSizeMap['middle'];
}
if (borderRadius || borderRadius === 0) {
return borderRadius;
}
};
const borderRadiusStyle =
getBorderRadius() &&
css`
label {
border-inline-start-width: 1px !important;
border-radius: ${getBorderRadius()}px !important;
}
label::before {
display: none !important;
}
`;
const gapStyle = css`
label {
margin-right: ${getGapSize()}px !important;
}
label:last-child {
margin-right: 0 !important;
}
`;
const noBorderd = segmented === true || (segmented && !segmented.bordered);
return {
custom: css`
${borderRadiusStyle}
${gapStyle}
${noBorderd &&
css`
.${prefixCls}-radio-button-wrapper {
border: none !important;
}
.${prefixCls}-radio-button-wrapper-checked {
border: 1px solid ${token.colorPrimary} !important;
}
`}
`,
};
},
{ hashPriority: 'low' }
);

0 comments on commit 14ae57c

Please sign in to comment.