mirror of
https://github.com/ant-design/ant-design.git
synced 2026-02-09 02:49:18 +08:00
feat: ConfigProvider support classNames and styles for radio (#52780)
* feat: ConfigProvider support classNames and styles for radio * Update components/radio/__tests__/radio.test.tsx Signed-off-by: thinkasany <480968828@qq.com> * update input to icon * Update components/radio/demo/_semantic.tsx Signed-off-by: thinkasany <480968828@qq.com> --------- Signed-off-by: thinkasany <480968828@qq.com>
This commit is contained in:
@@ -47,6 +47,7 @@ import type { TransferProps } from '../transfer';
|
||||
import type { TreeSelectProps } from '../tree-select';
|
||||
import type { RenderEmptyHandler } from './defaultRenderEmpty';
|
||||
import type { CheckboxProps } from '../checkbox';
|
||||
import type { RadioProps } from '../radio';
|
||||
|
||||
export const defaultPrefixCls = 'ant';
|
||||
export const defaultIconPrefixCls = 'anticon';
|
||||
@@ -230,6 +231,8 @@ export type StatisticConfig = ComponentStyleConfig & Pick<StatisticProps, 'class
|
||||
|
||||
export type ResultConfig = ComponentStyleConfig & Pick<ResultProps, 'classNames' | 'styles'>;
|
||||
|
||||
export type RadioConfig = ComponentStyleConfig & Pick<RadioProps, 'classNames' | 'styles'>;
|
||||
|
||||
export type InputNumberConfig = ComponentStyleConfig & Pick<InputNumberProps, 'variant'>;
|
||||
|
||||
export type CascaderConfig = ComponentStyleConfig & Pick<CascaderProps, 'variant'>;
|
||||
@@ -311,7 +314,7 @@ export interface ConfigComponentProps {
|
||||
descriptions?: DescriptionsConfig;
|
||||
empty?: EmptyConfig;
|
||||
badge?: BadgeConfig;
|
||||
radio?: ComponentStyleConfig;
|
||||
radio?: RadioConfig;
|
||||
rate?: ComponentStyleConfig;
|
||||
switch?: ComponentStyleConfig;
|
||||
transfer?: TransferConfig;
|
||||
|
||||
@@ -145,7 +145,7 @@ const {
|
||||
| notification | Set Notification common props | { className?: string, style?: React.CSSProperties, closeIcon?: React.ReactNode, classNames?: [NotificationConfig\["classNames"\]](/components/notification#api), styles?: [NotificationConfig\["styles"\]](/components/notification#api) } | - | 5.7.0, `closeIcon`: 5.14.0, `classNames` and `styles`: 6.0.0 |
|
||||
| pagination | Set Pagination common props | { showSizeChanger?: boolean, className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| progress | Set Progress common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| radio | Set Radio common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| radio | Set Radio common props | { className?: string, style?: React.CSSProperties, classNames?: [RadioConfig\["classNames"\]](/components/radio#api), styles?: [RadioConfig\["styles"\]](/components/radio#api) } | - | 5.7.0, `classNames` and `styles`: 6.0.0 |
|
||||
| rate | Set Rate common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| result | Set Result common props | { className?: string, style?: React.CSSProperties , classNames?: [ResultProps\["classNames"\]](/components/result#api), styles?: [ResultProps\["styles"\]](/components/result#api)} | - | 5.7.0, `classNames` and `styles`: 6.0.0 |
|
||||
| ribbon | Set Ribbon common props | { className?: string, style?: React.CSSProperties, , classNames?: [RibbonProps\["classNames"\]](/components/badge#api), styles?: [RibbonProps\["styles"\]](/components/badge#api) } | - | 6.0.0 |
|
||||
|
||||
@@ -45,6 +45,7 @@ import type {
|
||||
PopconfirmConfig,
|
||||
PopoverConfig,
|
||||
PopupOverflow,
|
||||
RadioConfig,
|
||||
RangePickerConfig,
|
||||
RibbonConfig,
|
||||
SelectConfig,
|
||||
@@ -219,7 +220,7 @@ export interface ConfigProviderProps {
|
||||
descriptions?: ComponentStyleConfig;
|
||||
empty?: EmptyConfig;
|
||||
badge?: BadgeConfig;
|
||||
radio?: ComponentStyleConfig;
|
||||
radio?: RadioConfig;
|
||||
rate?: ComponentStyleConfig;
|
||||
ribbon?: RibbonConfig;
|
||||
switch?: ComponentStyleConfig;
|
||||
|
||||
@@ -147,7 +147,7 @@ const {
|
||||
| notification | 设置 Notification 组件的通用属性 | { className?: string, style?: React.CSSProperties, closeIcon?: React.ReactNode, classNames?: [NotificationConfig\["classNames"\]](/components/notification-cn#api), styles?: [NotificationConfig\["styles"\]](/components/notification-cn#api) } | - | 5.7.0, `closeIcon`: 5.14.0, `classNames` 和 `styles`: 6.0.0 |
|
||||
| pagination | 设置 Pagination 组件的通用属性 | { showSizeChanger?: boolean, className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| progress | 设置 Progress 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| radio | 设置 Radio 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| radio | 设置 Radio 组件的通用属性 | { className?: string, style?: React.CSSProperties, classNames?: [RadioConfig\["classNames"\]](/components/radio-cn#api), styles?: [RadioConfig\["styles"\]](/components/radio-cn#api) } | - | 5.7.0, `classNames` 和 `styles`: 6.0.0 |
|
||||
| rate | 设置 Rate 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| result | 设置 Result 组件的通用属性 | { className?: string, style?: React.CSSProperties, classNames?: [ResultProps\["classNames"\]](/components/result-cn#api), styles?: [ResultProps\["styles"\]](/components/result-cn#api) } | - | 5.7.0, `classNames` 和 `styles`: 6.0.0 |
|
||||
| ribbon | 设置 Ribbon 组件的通用属性 | { className?: string, style?: React.CSSProperties, , classNames?: [RibbonProps\["classNames"\]](/components/badge-cn#api), styles?: [RibbonProps\["styles"\]](/components/badge-cn#api) } | - | 6.0.0 |
|
||||
|
||||
@@ -98,4 +98,34 @@ describe('Radio', () => {
|
||||
expect(onClick).toHaveBeenCalledTimes(3);
|
||||
expect(onRootClick).toHaveBeenCalledTimes(3);
|
||||
});
|
||||
it('should support custom styles', () => {
|
||||
const customClassNames = {
|
||||
root: 'custom-root',
|
||||
icon: 'custom-icon',
|
||||
label: 'custom-label',
|
||||
};
|
||||
|
||||
const customStyles = {
|
||||
root: { backgroundColor: 'red' },
|
||||
icon: { backgroundColor: 'black' },
|
||||
label: { backgroundColor: 'gray' },
|
||||
};
|
||||
const { container } = render(
|
||||
<Radio classNames={customClassNames} styles={customStyles}>
|
||||
Test
|
||||
</Radio>,
|
||||
);
|
||||
|
||||
const rootElement = container.querySelector('.ant-radio-wrapper') as HTMLElement;
|
||||
const iconElement = container.querySelector('.ant-radio') as HTMLElement;
|
||||
const labelElement = container.querySelector('.ant-radio-label') as HTMLElement;
|
||||
|
||||
expect(rootElement.classList).toContain('custom-root');
|
||||
expect(iconElement.classList).toContain('custom-icon');
|
||||
expect(labelElement.classList).toContain('custom-label');
|
||||
|
||||
expect(rootElement.style.backgroundColor).toBe('red');
|
||||
expect(iconElement.style.backgroundColor).toBe('black');
|
||||
expect(labelElement.style.backgroundColor).toBe('gray');
|
||||
});
|
||||
});
|
||||
|
||||
35
components/radio/demo/_semantic.tsx
Normal file
35
components/radio/demo/_semantic.tsx
Normal file
@@ -0,0 +1,35 @@
|
||||
import React from 'react';
|
||||
import { Radio } from 'antd';
|
||||
|
||||
import SemanticPreview from '../../../.dumi/components/SemanticPreview';
|
||||
import useLocale from '../../../.dumi/hooks/useLocale';
|
||||
|
||||
const locales = {
|
||||
cn: {
|
||||
root: '根元素',
|
||||
icon: '选中框元素',
|
||||
label: '文本元素',
|
||||
},
|
||||
en: {
|
||||
root: 'Root element',
|
||||
icon: 'Icon element',
|
||||
label: 'Label element',
|
||||
},
|
||||
};
|
||||
|
||||
const App: React.FC = () => {
|
||||
const [locale] = useLocale(locales);
|
||||
return (
|
||||
<SemanticPreview
|
||||
semantics={[
|
||||
{ name: 'root', desc: locale.root, version: '6.0.0' },
|
||||
{ name: 'icon', desc: locale.icon, version: '6.0.0' },
|
||||
{ name: 'label', desc: locale.label, version: '6.0.0' },
|
||||
]}
|
||||
>
|
||||
<Radio>Radio</Radio>
|
||||
</SemanticPreview>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
@@ -20,9 +20,9 @@ return (
|
||||
<Radio.Group
|
||||
value={value}
|
||||
options={[
|
||||
{ value: 1, label: "A" },
|
||||
{ value: 2, label: "B"},
|
||||
{ value: 3, label: "C" },
|
||||
{ value: 1, label: 'A' },
|
||||
{ value: 2, label: 'B' },
|
||||
{ value: 3, label: 'C' },
|
||||
]}
|
||||
/>
|
||||
);
|
||||
@@ -109,6 +109,10 @@ Radio group can wrap a group of `Radio`。
|
||||
| blur() | Remove focus |
|
||||
| focus() | Get focus |
|
||||
|
||||
## Semantic DOM
|
||||
|
||||
<code src="./demo/_semantic.tsx" simplify="true"></code>
|
||||
|
||||
## Design Token
|
||||
|
||||
<ComponentTokenTable component="Radio"></ComponentTokenTable>
|
||||
|
||||
@@ -21,9 +21,9 @@ return (
|
||||
<Radio.Group
|
||||
value={value}
|
||||
options={[
|
||||
{ value: 1, label: "A" },
|
||||
{ value: 2, label: "B"},
|
||||
{ value: 3, label: "C" },
|
||||
{ value: 1, label: 'A' },
|
||||
{ value: 2, label: 'B' },
|
||||
{ value: 3, label: 'C' },
|
||||
]}
|
||||
/>
|
||||
);
|
||||
@@ -112,6 +112,10 @@ return (
|
||||
| blur() | 移除焦点 |
|
||||
| focus() | 获取焦点 |
|
||||
|
||||
## Semantic DOM
|
||||
|
||||
<code src="./demo/_semantic.tsx" simplify="true"></code>
|
||||
|
||||
## 主题变量(Design Token)
|
||||
|
||||
<ComponentTokenTable component="Radio"></ComponentTokenTable>
|
||||
|
||||
@@ -41,6 +41,7 @@ export interface RadioGroupContextProps {
|
||||
block?: boolean;
|
||||
}
|
||||
|
||||
type SemanticName = 'root' | 'icon' | 'label';
|
||||
export interface RadioProps extends AbstractCheckboxProps<RadioChangeEvent> {
|
||||
/**
|
||||
* Control the appearance for Radio to display as button or not
|
||||
@@ -49,6 +50,8 @@ export interface RadioProps extends AbstractCheckboxProps<RadioChangeEvent> {
|
||||
* @internal
|
||||
*/
|
||||
optionType?: RadioGroupOptionType;
|
||||
classNames?: Partial<Record<SemanticName, string>>;
|
||||
styles?: Partial<Record<SemanticName, React.CSSProperties>>;
|
||||
}
|
||||
|
||||
export interface RadioChangeEventTarget extends RadioProps {
|
||||
|
||||
@@ -7,7 +7,7 @@ import { devUseWarning } from '../_util/warning';
|
||||
import Wave from '../_util/wave';
|
||||
import { TARGET_CLS } from '../_util/wave/interface';
|
||||
import useBubbleLock from '../checkbox/useBubbleLock';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
import { useComponentConfig } from '../config-provider/context';
|
||||
import DisabledContext from '../config-provider/DisabledContext';
|
||||
import useCSSVarCls from '../config-provider/hooks/useCSSVarCls';
|
||||
import { FormItemInputContext } from '../form/context';
|
||||
@@ -19,7 +19,14 @@ const InternalRadio: React.ForwardRefRenderFunction<RadioRef, RadioProps> = (pro
|
||||
const groupContext = React.useContext(RadioGroupContext);
|
||||
const radioOptionTypeContext = React.useContext(RadioOptionTypeContext);
|
||||
|
||||
const { getPrefixCls, direction, radio } = React.useContext(ConfigContext);
|
||||
const {
|
||||
getPrefixCls,
|
||||
direction,
|
||||
className: contextClassName,
|
||||
style: contextStyle,
|
||||
classNames: contextClassNames,
|
||||
styles: contextStyles,
|
||||
} = useComponentConfig('radio');
|
||||
const innerRef = React.useRef<RadioRef>(null);
|
||||
const mergedRef = composeRef(ref, innerRef);
|
||||
const { isFormItemInput } = React.useContext(FormItemInputContext);
|
||||
@@ -42,6 +49,8 @@ const InternalRadio: React.ForwardRefRenderFunction<RadioRef, RadioProps> = (pro
|
||||
children,
|
||||
style,
|
||||
title,
|
||||
classNames: radioClassNames,
|
||||
styles,
|
||||
...restProps
|
||||
} = props;
|
||||
const radioPrefixCls = getPrefixCls('radio', customizePrefixCls);
|
||||
@@ -75,9 +84,11 @@ const InternalRadio: React.ForwardRefRenderFunction<RadioRef, RadioProps> = (pro
|
||||
[`${prefixCls}-wrapper-in-form-item`]: isFormItemInput,
|
||||
[`${prefixCls}-wrapper-block`]: !!groupContext?.block,
|
||||
},
|
||||
radio?.className,
|
||||
contextClassName,
|
||||
className,
|
||||
rootClassName,
|
||||
contextClassNames.root,
|
||||
radioClassNames?.root,
|
||||
hashId,
|
||||
cssVarCls,
|
||||
rootCls,
|
||||
@@ -91,7 +102,7 @@ const InternalRadio: React.ForwardRefRenderFunction<RadioRef, RadioProps> = (pro
|
||||
<Wave component="Radio" disabled={radioProps.disabled}>
|
||||
<label
|
||||
className={wrapperClassString}
|
||||
style={{ ...radio?.style, ...style }}
|
||||
style={{ ...contextStyles.root, ...styles?.root, ...contextStyle, ...style }}
|
||||
onMouseEnter={props.onMouseEnter}
|
||||
onMouseLeave={props.onMouseLeave}
|
||||
title={title}
|
||||
@@ -100,13 +111,27 @@ const InternalRadio: React.ForwardRefRenderFunction<RadioRef, RadioProps> = (pro
|
||||
{/* @ts-ignore */}
|
||||
<RcCheckbox
|
||||
{...radioProps}
|
||||
className={classNames(radioProps.className, { [TARGET_CLS]: !isButtonType })}
|
||||
className={classNames(radioClassNames?.icon, contextClassNames.icon, {
|
||||
[TARGET_CLS]: !isButtonType,
|
||||
})}
|
||||
style={{ ...contextStyles.icon, ...styles?.icon }}
|
||||
type="radio"
|
||||
prefixCls={prefixCls}
|
||||
ref={mergedRef}
|
||||
onClick={onInputClick}
|
||||
/>
|
||||
{children !== undefined ? <span className={`${prefixCls}-label`}>{children}</span> : null}
|
||||
{children !== undefined ? (
|
||||
<span
|
||||
className={classNames(
|
||||
`${prefixCls}-label`,
|
||||
contextClassNames.label,
|
||||
radioClassNames?.label,
|
||||
)}
|
||||
style={{ ...contextStyles.label, ...styles?.label }}
|
||||
>
|
||||
{children}
|
||||
</span>
|
||||
) : null}
|
||||
</label>
|
||||
</Wave>,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user