diff --git a/src/Radio/demos/Playground.tsx b/src/Radio/demos/Playground.tsx new file mode 100644 index 0000000..5e89660 --- /dev/null +++ b/src/Radio/demos/Playground.tsx @@ -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 ( + + + + ); +}; diff --git a/src/Radio/demos/Segmented.tsx b/src/Radio/demos/Segmented.tsx new file mode 100644 index 0000000..ecce9e2 --- /dev/null +++ b/src/Radio/demos/Segmented.tsx @@ -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 ( + + + + + + + ); +}; diff --git a/src/Radio/demos/index.tsx b/src/Radio/demos/index.tsx new file mode 100644 index 0000000..7f6cbec --- /dev/null +++ b/src/Radio/demos/index.tsx @@ -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 ( + + + + + + ); +}; diff --git a/src/Radio/index.md b/src/Radio/index.md new file mode 100644 index 0000000..88f5bf5 --- /dev/null +++ b/src/Radio/index.md @@ -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 ; +}; +``` + + + +### Segmented usage + +**Set the button style is similar to the Segmented component, Generally used for in-page navigation** + + + +## Playground + + + +## APIs + + diff --git a/src/Radio/index.tsx b/src/Radio/index.tsx new file mode 100644 index 0000000..e3d0529 --- /dev/null +++ b/src/Radio/index.tsx @@ -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> & { + Group: typeof Group; + Button: typeof AntdRadio.Button; +}; +export const Radio = AntdRadio as RadioType; + +const Group: React.FC = props => { + const { className, ...otherProps } = props; + if (otherProps.segmented) { + otherProps.optionType = 'button'; + } + const { styles, cx } = useStyles(otherProps); + + return ; +}; +Radio.Group = Group; + +export default Radio; + +export { type RadioChangeEvent, type RadioProps } from 'antd'; diff --git a/src/Radio/style.ts b/src/Radio/style.ts new file mode 100644 index 0000000..e018e68 --- /dev/null +++ b/src/Radio/style.ts @@ -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' } +); diff --git a/src/index.ts b/src/index.ts index 00f6e19..a033760 100644 --- a/src/index.ts +++ b/src/index.ts @@ -14,6 +14,7 @@ export * from './Divider'; export * from './Drawer'; export * from './Modal'; export * from './notification'; +export * from './Radio'; // ~ antd export { @@ -45,6 +46,7 @@ export { ColorPicker, type ColorPickerProps, type ColProps, // @todo center style + type CountdownProps, DatePicker, type DatePickerProps, Dropdown, @@ -62,6 +64,7 @@ export { type FormListOperation, type FormProps, type FormRule, + type GlobalToken, Grid, Image, ImageProps, @@ -74,6 +77,7 @@ export { type LayoutProps, List, type ListProps, + type MappingAlgorithm, type MentionProps, Mentions, Menu, @@ -83,9 +87,86 @@ export { type MenuTheme, message, type MessageArgsProps, + Pagination, + type PaginationProps, + Popconfirm, + type PopconfirmProps, + Popover, + type PopoverProps, + Progress, + type ProgressProps, + QRCode, + type QRCodeProps, + type QRPropsCanvas, + type QRPropsSvg, + Rate, + type RateProps, + type RefSelectProps, + Result, + type ResultProps, + Row, + type RowProps, + Segmented, + type SegmentedProps, + Select, + type SelectProps, + Skeleton, + type SkeletonProps, + Slider, + type SliderSingleProps, Space, type SpaceProps, + Spin, + type SpinProps, + Statistic, + type StatisticProps, + type StepProps, + Steps, + type StepsProps, type SubMenuProps, + Switch, + type SwitchProps, + Table, + type TableColumnGroupType, + type TableColumnProps, + type TableColumnsType, + type TableColumnType, + type TablePaginationConfig, + type TableProps, + type TabPaneProps, + Tabs, + type TabsProps, + Tag, + type TagProps, + type TagType, + theme, + Timeline, + type TimelineItemProps, + type TimelineProps, + TimePicker, + type TimePickerProps, + type TimeRangePickerProps, + Tooltip, + type TooltipProps, + Tour, + type TourProps, + type TourStepProps, + Transfer, + type TransferProps, + Tree, + type TreeDataNode, + type TreeNodeProps, + type TreeProps, + TreeSelect, + type TreeSelectProps, + Typography, + type TypographyProps, + Upload, + type UploadFile, + type UploadProps, + version, + Watermark, + type WatermarkProps, } from 'antd'; // ~ @lobehub/ui