refactor:radio (#6299)

* refactor:radio

* fix attrs
pull/6300/head^2
果冻橙 2023-02-21 11:33:54 +08:00 committed by GitHub
parent 8fcb3fdfe3
commit e04f73dfef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 620 additions and 478 deletions

View File

@ -1,5 +1,5 @@
import { nextTick, defineComponent, ref, watch, computed } from 'vue';
import type { PropType, ExtractPropTypes } from 'vue';
import type { ExtractPropTypes } from 'vue';
import classNames from '../_util/classNames';
import PropTypes from '../_util/vue-types';
import Radio from './Radio';
@ -8,6 +8,10 @@ import { tuple } from '../_util/type';
import type { RadioChangeEvent, RadioGroupButtonStyle, RadioGroupOptionType } from './interface';
import { useInjectFormItemContext } from '../form/FormItemContext';
import { useProvideRadioGroupContext } from './context';
import { booleanType, stringType, arrayType, functionType } from '../_util/type';
// CSSINJS
import useStyle from './style';
const RadioGroupSizeTypes = tuple('large', 'default', 'small');
@ -25,16 +29,14 @@ export const radioGroupProps = () => ({
prefixCls: String,
value: PropTypes.any,
size: PropTypes.oneOf(RadioGroupSizeTypes),
options: {
type: Array as PropType<Array<string | RadioGroupChildOption | number>>,
},
disabled: { type: Boolean, default: undefined },
options: arrayType<Array<string | RadioGroupChildOption | number>>(),
disabled: booleanType(),
name: String,
buttonStyle: { type: String as PropType<RadioGroupButtonStyle>, default: 'outline' },
buttonStyle: stringType<RadioGroupButtonStyle>('outline'),
id: String,
optionType: { type: String as PropType<RadioGroupOptionType>, default: 'default' },
onChange: Function as PropType<(e: RadioChangeEvent) => void>,
'onUpdate:value': Function as PropType<(val: any) => void>,
optionType: stringType<RadioGroupOptionType>('default'),
onChange: functionType<(e: RadioChangeEvent) => void>(),
'onUpdate:value': functionType<(val: any) => void>(),
});
export type RadioGroupProps = Partial<ExtractPropTypes<ReturnType<typeof radioGroupProps>>>;
@ -42,11 +44,16 @@ export type RadioGroupProps = Partial<ExtractPropTypes<ReturnType<typeof radioGr
export default defineComponent({
compatConfig: { MODE: 3 },
name: 'ARadioGroup',
inheritAttrs: false,
props: radioGroupProps(),
// emits: ['update:value', 'change'],
setup(props, { slots, emit }) {
setup(props, { slots, emit, attrs }) {
const formItemContext = useInjectFormItemContext();
const { prefixCls, direction, size } = useConfigInject('radio', props);
// Style
const [wrapSSR, hashId] = useStyle(prefixCls);
const stateValue = ref(props.value);
const updatingValue = ref<boolean>(false);
watch(
@ -89,10 +96,16 @@ export default defineComponent({
const groupPrefixCls = `${prefixCls.value}-group`;
const classString = classNames(groupPrefixCls, `${groupPrefixCls}-${buttonStyle}`, {
[`${groupPrefixCls}-${size.value}`]: size.value,
[`${groupPrefixCls}-rtl`]: direction.value === 'rtl',
});
const classString = classNames(
groupPrefixCls,
`${groupPrefixCls}-${buttonStyle}`,
{
[`${groupPrefixCls}-${size.value}`]: size.value,
[`${groupPrefixCls}-rtl`]: direction.value === 'rtl',
},
attrs.class,
hashId.value,
);
let children = null;
if (options && options.length > 0) {
@ -126,10 +139,10 @@ export default defineComponent({
} else {
children = slots.default?.();
}
return (
<div class={classString} id={id}>
return wrapSSR(
<div {...attrs} class={classString} id={id}>
{children}
</div>
</div>,
);
};
},

View File

@ -1,4 +1,4 @@
import type { ExtractPropTypes, PropType } from 'vue';
import type { ExtractPropTypes } from 'vue';
import { computed, defineComponent, ref } from 'vue';
import PropTypes from '../_util/vue-types';
import VcCheckbox from '../vc-checkbox/Checkbox';
@ -9,22 +9,26 @@ import { FormItemInputContext, useInjectFormItemContext } from '../form/FormItem
import omit from '../_util/omit';
import type { FocusEventHandler, MouseEventHandler } from '../_util/EventInterface';
import { useInjectRadioGroupContext, useInjectRadioOptionTypeContext } from './context';
import { booleanType, functionType } from '../_util/type';
// CSSINJS
import useStyle from './style';
export const radioProps = () => ({
prefixCls: String,
checked: { type: Boolean, default: undefined },
disabled: { type: Boolean, default: undefined },
isGroup: { type: Boolean, default: undefined },
checked: booleanType(),
disabled: booleanType(),
isGroup: booleanType(),
value: PropTypes.any,
name: String,
id: String,
autofocus: { type: Boolean, default: undefined },
onChange: Function as PropType<(event: RadioChangeEvent) => void>,
onFocus: Function as PropType<FocusEventHandler>,
onBlur: Function as PropType<FocusEventHandler>,
onClick: Function as PropType<MouseEventHandler>,
'onUpdate:checked': Function as PropType<(checked: boolean) => void>,
'onUpdate:value': Function as PropType<(checked: boolean) => void>,
autofocus: booleanType(),
onChange: functionType<(event: RadioChangeEvent) => void>(),
onFocus: functionType<FocusEventHandler>(),
onBlur: functionType<FocusEventHandler>(),
onClick: functionType<MouseEventHandler>(),
'onUpdate:checked': functionType<(checked: boolean) => void>(),
'onUpdate:value': functionType<(checked: boolean) => void>(),
});
export type RadioProps = Partial<ExtractPropTypes<ReturnType<typeof radioProps>>>;
@ -32,8 +36,9 @@ export type RadioProps = Partial<ExtractPropTypes<ReturnType<typeof radioProps>>
export default defineComponent({
compatConfig: { MODE: 3 },
name: 'ARadio',
inheritAttrs: false,
props: radioProps(),
setup(props, { emit, expose, slots }) {
setup(props, { emit, expose, slots, attrs }) {
const formItemContext = useInjectFormItemContext();
const formItemInputContext = FormItemInputContext.useInject();
const radioOptionTypeContext = useInjectRadioOptionTypeContext();
@ -42,10 +47,14 @@ export default defineComponent({
const { prefixCls: radioPrefixCls, direction } = useConfigInject('radio', props);
const prefixCls = computed(() =>
(radioGroupContext?.optionType.value || radioOptionTypeContext) === 'button'
radioGroupContext?.optionType.value === 'button' || radioOptionTypeContext === 'button'
? `${radioPrefixCls.value}-button`
: radioPrefixCls.value,
);
// Style
const [wrapSSR, hashId] = useStyle(radioPrefixCls);
const focus = () => {
vcCheckbox.value.focus();
};
@ -89,19 +98,23 @@ export default defineComponent({
} else {
rProps.onChange = handleChange;
}
const wrapperClassString = classNames({
[`${prefixCls.value}-wrapper`]: true,
[`${prefixCls.value}-wrapper-checked`]: rProps.checked,
[`${prefixCls.value}-wrapper-disabled`]: rProps.disabled,
[`${prefixCls.value}-wrapper-rtl`]: direction.value === 'rtl',
[`${prefixCls.value}-wrapper-in-form-item`]: formItemInputContext.isFormItemInput,
});
const wrapperClassString = classNames(
{
[`${prefixCls.value}-wrapper`]: true,
[`${prefixCls.value}-wrapper-checked`]: rProps.checked,
[`${prefixCls.value}-wrapper-disabled`]: rProps.disabled,
[`${prefixCls.value}-wrapper-rtl`]: direction.value === 'rtl',
[`${prefixCls.value}-wrapper-in-form-item`]: formItemInputContext.isFormItemInput,
},
attrs.class,
hashId.value,
);
return (
<label class={wrapperClassString}>
return wrapSSR(
<label {...attrs} class={wrapperClassString}>
<VcCheckbox {...rProps} type="radio" ref={vcCheckbox} />
{slots.default && <span>{slots.default()}</span>}
</label>
</label>,
);
};
},

View File

@ -6,13 +6,14 @@ import { useProvideRadioOptionTypeContext } from './context';
export default defineComponent({
compatConfig: { MODE: 3 },
name: 'ARadioButton',
inheritAttrs: false,
props: radioProps(),
setup(props, { slots }) {
const { prefixCls } = useConfigInject('radio-button', props);
setup(props, { slots, attrs }) {
const { prefixCls } = useConfigInject('radio', props);
useProvideRadioOptionTypeContext('button');
return () => {
return (
<Radio {...props} prefixCls={prefixCls.value}>
<Radio {...attrs} {...props} prefixCls={prefixCls.value}>
{slots.default?.()}
</Radio>
);

View File

@ -2,7 +2,7 @@
category: Components
type: Data Entry
title: Radio
cover: https://gw.alipayobjects.com/zos/alicdn/8cYb5seNB/Radio.svg
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*M-YKTJnWM2kAAAAAAAAAAAAADrJ8AQ/original
---
Radio.

View File

@ -3,7 +3,7 @@ category: Components
type: 数据录入
title: Radio
subtitle: 单选框
cover: https://gw.alipayobjects.com/zos/alicdn/8cYb5seNB/Radio.svg
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*M-YKTJnWM2kAAAAAAAAAAAAADrJ8AQ/original
---
单选框。

View File

@ -1,366 +0,0 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
@radio-prefix-cls: ~'@{ant-prefix}-radio';
@radio-group-prefix-cls: ~'@{radio-prefix-cls}-group';
@radio-inner-prefix-cls: ~'@{radio-prefix-cls}-inner';
@radio-duration: 0.3s;
@radio-focus-shadow: 0 0 0 3px @primary-1;
@radio-button-focus-shadow: @radio-focus-shadow;
.@{radio-group-prefix-cls} {
.reset-component();
display: inline-block;
font-size: 0;
.@{ant-prefix}-badge-count {
z-index: 1;
}
> .@{ant-prefix}-badge:not(:first-child) > .@{radio-prefix-cls}-button-wrapper {
border-left: none;
}
}
// 一般状态
.@{radio-prefix-cls}-wrapper {
.reset-component();
position: relative;
display: inline-flex;
align-items: baseline;
margin-right: @radio-wrapper-margin-right;
cursor: pointer;
&-disabled {
cursor: not-allowed;
}
&::after {
display: inline-block;
width: 0;
overflow: hidden;
content: '\a0';
}
&&-in-form-item {
input[type='radio'] {
width: 14px;
height: 14px;
}
}
}
.@{radio-prefix-cls} {
.reset-component();
position: relative;
top: @radio-top;
display: inline-block;
outline: none;
cursor: pointer;
.@{radio-prefix-cls}-wrapper:hover &,
&:hover .@{radio-inner-prefix-cls},
&-input:focus + .@{radio-inner-prefix-cls} {
border-color: @radio-dot-color;
}
&-input:focus + .@{radio-inner-prefix-cls} {
box-shadow: @radio-focus-shadow;
}
&-checked::after {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border: 1px solid @radio-dot-color;
border-radius: 50%;
visibility: hidden;
animation: antRadioEffect 0.36s ease-in-out;
animation-fill-mode: both;
content: '';
}
&:hover::after,
.@{radio-prefix-cls}-wrapper:hover &::after {
visibility: visible;
}
&-inner {
&::after {
position: absolute;
top: 50%;
left: 50%;
display: block;
width: @radio-size;
height: @radio-size;
margin-top: -(@radio-size / 2);
margin-left: -(@radio-size / 2);
background-color: @radio-dot-color;
border-top: 0;
border-left: 0;
border-radius: @radio-size;
transform: scale(0);
opacity: 0;
transition: all @radio-duration @ease-in-out-circ;
content: ' ';
}
position: relative;
top: 0;
left: 0;
display: block;
width: @radio-size;
height: @radio-size;
background-color: @radio-button-bg;
border-color: @border-color-base;
border-style: solid;
border-width: @radio-border-width;
border-radius: 50%;
transition: all @radio-duration;
}
&-input {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 1;
cursor: pointer;
opacity: 0;
}
}
// 选中状态
.@{radio-prefix-cls}-checked {
.@{radio-inner-prefix-cls} {
border-color: @radio-dot-color;
&::after {
transform: scale((unit(@radio-dot-size) / unit(@radio-size)));
opacity: 1;
transition: all @radio-duration @ease-in-out-circ;
}
}
}
.@{radio-prefix-cls}-disabled {
cursor: not-allowed;
.@{radio-inner-prefix-cls} {
background-color: @input-disabled-bg;
border-color: @border-color-base !important;
cursor: not-allowed;
&::after {
background-color: @radio-dot-disabled-color;
}
}
.@{radio-prefix-cls}-input {
cursor: not-allowed;
}
& + span {
color: @disabled-color;
cursor: not-allowed;
}
}
span.@{radio-prefix-cls} + * {
padding-right: 8px;
padding-left: 8px;
}
.@{radio-prefix-cls}-button-wrapper {
position: relative;
display: inline-block;
height: @btn-height-base;
margin: 0;
padding: 0 @radio-button-padding-horizontal;
color: @radio-button-color;
font-size: @font-size-base;
line-height: @btn-height-base - 2px;
background: @radio-button-bg;
border: @border-width-base @border-style-base @border-color-base;
// strange align fix for chrome but works
// https://gw.alipayobjects.com/zos/rmsportal/VFTfKXJuogBAXcvfAUWJ.gif
border-top-width: @border-width-base + 0.02px;
border-left-width: 0;
cursor: pointer;
transition: color 0.3s, background 0.3s, border-color 0.3s, box-shadow 0.3s;
a {
color: @radio-button-color;
}
> .@{radio-prefix-cls}-button {
position: absolute;
top: 0;
left: 0;
z-index: -1;
width: 100%;
height: 100%;
}
.@{radio-group-prefix-cls}-large & {
height: @input-height-lg;
font-size: @font-size-lg;
line-height: @input-height-lg - 2px;
}
.@{radio-group-prefix-cls}-small & {
height: @input-height-sm;
padding: 0 @control-padding-horizontal-sm - 1px;
line-height: @input-height-sm - 2px;
}
&:not(:first-child) {
&::before {
position: absolute;
top: @border-width-base * -1;
left: -1px;
display: block;
box-sizing: content-box;
width: 1px;
height: 100%;
padding: @border-width-base 0;
background-color: @border-color-base;
transition: background-color 0.3s;
content: '';
}
}
&:first-child {
border-left: @border-width-base @border-style-base @border-color-base;
border-radius: @border-radius-base 0 0 @border-radius-base;
}
&:last-child {
border-radius: 0 @border-radius-base @border-radius-base 0;
}
&:first-child:last-child {
border-radius: @border-radius-base;
}
&:hover {
position: relative;
color: @radio-dot-color;
}
&:focus-within {
box-shadow: @radio-button-focus-shadow;
}
.@{radio-prefix-cls}-inner,
input[type='checkbox'],
input[type='radio'] {
width: 0;
height: 0;
opacity: 0;
pointer-events: none;
}
&-checked:not(&-disabled) {
z-index: 1;
color: @radio-dot-color;
background: @radio-button-checked-bg;
border-color: @radio-dot-color;
&::before {
background-color: @radio-dot-color;
}
&:first-child {
border-color: @radio-dot-color;
}
&:hover {
color: @radio-button-hover-color;
border-color: @radio-button-hover-color;
&::before {
background-color: @radio-button-hover-color;
}
}
&:active {
color: @radio-button-active-color;
border-color: @radio-button-active-color;
&::before {
background-color: @radio-button-active-color;
}
}
&:focus-within {
box-shadow: @radio-button-focus-shadow;
}
}
.@{radio-group-prefix-cls}-solid &-checked:not(&-disabled) {
color: @radio-solid-checked-color;
background: @radio-dot-color;
border-color: @radio-dot-color;
&:hover {
color: @radio-solid-checked-color;
background: @radio-button-hover-color;
border-color: @radio-button-hover-color;
}
&:active {
color: @radio-solid-checked-color;
background: @radio-button-active-color;
border-color: @radio-button-active-color;
}
&:focus-within {
box-shadow: @radio-button-focus-shadow;
}
}
&-disabled {
color: @disabled-color;
background-color: @input-disabled-bg;
border-color: @border-color-base;
cursor: not-allowed;
&:first-child,
&:hover {
color: @disabled-color;
background-color: @input-disabled-bg;
border-color: @border-color-base;
}
&:first-child {
border-left-color: @border-color-base;
}
}
&-disabled&-checked {
color: @radio-disabled-button-checked-color;
background-color: @radio-disabled-button-checked-bg;
border-color: @border-color-base;
box-shadow: none;
}
}
@keyframes antRadioEffect {
0% {
transform: scale(1);
opacity: 0.5;
}
100% {
transform: scale(1.6);
opacity: 0;
}
}
@import './rtl';

View File

@ -1,3 +1,545 @@
import '../../style/index.less';
import './index.less';
// deps-lint-skip: form
import { Keyframes } from '../../_util/cssinjs';
import type { FullToken, GenerateStyle } from '../../theme/internal';
import { genComponentStyleHook, mergeToken } from '../../theme/internal';
import { genFocusOutline, resetComponent } from '../../_style';
// ============================== Tokens ==============================
export interface ComponentToken {}
interface RadioToken extends FullToken<'Radio'> {
radioFocusShadow: string;
radioButtonFocusShadow: string;
radioSize: number;
radioTop: number;
radioDotSize: number;
radioDotDisabledSize: number;
radioCheckedColor: string;
radioDotDisabledColor: string;
radioSolidCheckedColor: string;
radioButtonBg: string;
radioButtonCheckedBg: string;
radioButtonColor: string;
radioButtonHoverColor: string;
radioButtonActiveColor: string;
radioButtonPaddingHorizontal: number;
radioDisabledButtonCheckedBg: string;
radioDisabledButtonCheckedColor: string;
radioWrapperMarginRight: number;
}
// ============================== Styles ==============================
const antRadioEffect = new Keyframes('antRadioEffect', {
'0%': { transform: 'scale(1)', opacity: 0.5 },
'100%': { transform: 'scale(1.6)', opacity: 0 },
});
// styles from RadioGroup only
const getGroupRadioStyle: GenerateStyle<RadioToken> = token => {
const { componentCls, antCls } = token;
const groupPrefixCls = `${componentCls}-group`;
return {
[groupPrefixCls]: {
...resetComponent(token),
display: 'inline-block',
fontSize: 0,
// RTL
[`&${groupPrefixCls}-rtl`]: {
direction: 'rtl',
},
[`${antCls}-badge ${antCls}-badge-count`]: {
zIndex: 1,
},
[`> ${antCls}-badge:not(:first-child) > ${antCls}-button-wrapper`]: {
borderInlineStart: 'none',
},
},
};
};
// Styles from radio-wrapper
const getRadioBasicStyle: GenerateStyle<RadioToken> = token => {
const {
componentCls,
radioWrapperMarginRight,
radioCheckedColor,
radioSize,
motionDurationSlow,
motionDurationMid,
motionEaseInOut,
motionEaseInOutCirc,
radioButtonBg,
colorBorder,
lineWidth,
radioDotSize,
colorBgContainerDisabled,
colorTextDisabled,
paddingXS,
radioDotDisabledColor,
lineType,
radioDotDisabledSize,
wireframe,
colorWhite,
} = token;
const radioInnerPrefixCls = `${componentCls}-inner`;
return {
[`${componentCls}-wrapper`]: {
...resetComponent(token),
position: 'relative',
display: 'inline-flex',
alignItems: 'baseline',
marginInlineStart: 0,
marginInlineEnd: radioWrapperMarginRight,
cursor: 'pointer',
// RTL
[`&${componentCls}-wrapper-rtl`]: {
direction: 'rtl',
},
'&-disabled': {
cursor: 'not-allowed',
color: token.colorTextDisabled,
},
'&::after': {
display: 'inline-block',
width: 0,
overflow: 'hidden',
content: '"\\a0"',
},
// hashId wrapper
[`${componentCls}-checked::after`]: {
position: 'absolute',
insetBlockStart: 0,
insetInlineStart: 0,
width: '100%',
height: '100%',
border: `${lineWidth}px ${lineType} ${radioCheckedColor}`,
borderRadius: '50%',
visibility: 'hidden',
animationName: antRadioEffect,
animationDuration: motionDurationSlow,
animationTimingFunction: motionEaseInOut,
animationFillMode: 'both',
content: '""',
},
[componentCls]: {
...resetComponent(token),
position: 'relative',
display: 'inline-block',
outline: 'none',
cursor: 'pointer',
alignSelf: 'center',
},
[`${componentCls}-wrapper:hover &,
&:hover ${radioInnerPrefixCls}`]: {
borderColor: radioCheckedColor,
},
[`${componentCls}-input:focus-visible + ${radioInnerPrefixCls}`]: {
...genFocusOutline(token),
},
[`${componentCls}:hover::after, ${componentCls}-wrapper:hover &::after`]: {
visibility: 'visible',
},
[`${componentCls}-inner`]: {
'&::after': {
boxSizing: 'border-box',
position: 'absolute',
insetBlockStart: '50%',
insetInlineStart: '50%',
display: 'block',
width: radioSize,
height: radioSize,
marginBlockStart: radioSize / -2,
marginInlineStart: radioSize / -2,
backgroundColor: wireframe ? radioCheckedColor : colorWhite,
borderBlockStart: 0,
borderInlineStart: 0,
borderRadius: radioSize,
transform: 'scale(0)',
opacity: 0,
transition: `all ${motionDurationSlow} ${motionEaseInOutCirc}`,
content: '""',
},
boxSizing: 'border-box',
position: 'relative',
insetBlockStart: 0,
insetInlineStart: 0,
display: 'block',
width: radioSize,
height: radioSize,
backgroundColor: radioButtonBg,
borderColor: colorBorder,
borderStyle: 'solid',
borderWidth: lineWidth,
borderRadius: '50%',
transition: `all ${motionDurationMid}`,
},
[`${componentCls}-input`]: {
position: 'absolute',
insetBlockStart: 0,
insetInlineEnd: 0,
insetBlockEnd: 0,
insetInlineStart: 0,
zIndex: 1,
cursor: 'pointer',
opacity: 0,
},
//
[`${componentCls}-checked`]: {
[radioInnerPrefixCls]: {
borderColor: radioCheckedColor,
backgroundColor: wireframe ? radioButtonBg : radioCheckedColor,
'&::after': {
transform: `scale(${radioDotSize / radioSize})`,
opacity: 1,
transition: `all ${motionDurationSlow} ${motionEaseInOutCirc}`,
},
},
},
[`${componentCls}-disabled`]: {
cursor: 'not-allowed',
[radioInnerPrefixCls]: {
backgroundColor: colorBgContainerDisabled,
borderColor: colorBorder,
cursor: 'not-allowed',
'&::after': {
backgroundColor: radioDotDisabledColor,
},
},
[`${componentCls}-input`]: {
cursor: 'not-allowed',
},
[`${componentCls}-disabled + span`]: {
color: colorTextDisabled,
cursor: 'not-allowed',
},
[`&${componentCls}-checked`]: {
[radioInnerPrefixCls]: {
'&::after': {
transform: `scale(${radioDotDisabledSize / radioSize})`,
},
},
},
},
[`span${componentCls} + *`]: {
paddingInlineStart: paddingXS,
paddingInlineEnd: paddingXS,
},
},
};
};
// Styles from radio-button
const getRadioButtonStyle: GenerateStyle<RadioToken> = token => {
const {
radioButtonColor,
controlHeight,
componentCls,
lineWidth,
lineType,
colorBorder,
motionDurationSlow,
motionDurationMid,
radioButtonPaddingHorizontal,
fontSize,
radioButtonBg,
fontSizeLG,
controlHeightLG,
controlHeightSM,
paddingXS,
borderRadius,
borderRadiusSM,
borderRadiusLG,
radioCheckedColor,
radioButtonCheckedBg,
radioButtonHoverColor,
radioButtonActiveColor,
radioSolidCheckedColor,
colorTextDisabled,
colorBgContainerDisabled,
radioDisabledButtonCheckedColor,
radioDisabledButtonCheckedBg,
} = token;
return {
[`${componentCls}-button-wrapper`]: {
position: 'relative',
display: 'inline-block',
height: controlHeight,
margin: 0,
paddingInline: radioButtonPaddingHorizontal,
paddingBlock: 0,
color: radioButtonColor,
fontSize,
lineHeight: `${controlHeight - lineWidth * 2}px`,
background: radioButtonBg,
border: `${lineWidth}px ${lineType} ${colorBorder}`,
// strange align fix for chrome but works
// https://gw.alipayobjects.com/zos/rmsportal/VFTfKXJuogBAXcvfAUWJ.gif
borderBlockStartWidth: lineWidth + 0.02,
borderInlineStartWidth: 0,
borderInlineEndWidth: lineWidth,
cursor: 'pointer',
transition: [
`color ${motionDurationMid}`,
`background ${motionDurationMid}`,
`border-color ${motionDurationMid}`,
`box-shadow ${motionDurationMid}`,
].join(','),
a: {
color: radioButtonColor,
},
[`> ${componentCls}-button`]: {
position: 'absolute',
insetBlockStart: 0,
insetInlineStart: 0,
zIndex: -1,
width: '100%',
height: '100%',
},
'&:not(:first-child)': {
'&::before': {
position: 'absolute',
insetBlockStart: -lineWidth,
insetInlineStart: -lineWidth,
display: 'block',
boxSizing: 'content-box',
width: 1,
height: '100%',
paddingBlock: lineWidth,
paddingInline: 0,
backgroundColor: colorBorder,
transition: `background-color ${motionDurationSlow}`,
content: '""',
},
},
'&:first-child': {
borderInlineStart: `${lineWidth}px ${lineType} ${colorBorder}`,
borderStartStartRadius: borderRadius,
borderEndStartRadius: borderRadius,
},
'&:last-child': {
borderStartEndRadius: borderRadius,
borderEndEndRadius: borderRadius,
},
'&:first-child:last-child': {
borderRadius,
},
[`${componentCls}-group-large &`]: {
height: controlHeightLG,
fontSize: fontSizeLG,
lineHeight: `${controlHeightLG - lineWidth * 2}px`,
'&:first-child': {
borderStartStartRadius: borderRadiusLG,
borderEndStartRadius: borderRadiusLG,
},
'&:last-child': {
borderStartEndRadius: borderRadiusLG,
borderEndEndRadius: borderRadiusLG,
},
},
[`${componentCls}-group-small &`]: {
height: controlHeightSM,
paddingInline: paddingXS - lineWidth,
paddingBlock: 0,
lineHeight: `${controlHeightSM - lineWidth * 2}px`,
'&:first-child': {
borderStartStartRadius: borderRadiusSM,
borderEndStartRadius: borderRadiusSM,
},
'&:last-child': {
borderStartEndRadius: borderRadiusSM,
borderEndEndRadius: borderRadiusSM,
},
},
'&:hover': {
position: 'relative',
color: radioCheckedColor,
},
'&:has(:focus-visible)': {
...genFocusOutline(token),
},
[`${componentCls}-inner, input[type='checkbox'], input[type='radio']`]: {
width: 0,
height: 0,
opacity: 0,
pointerEvents: 'none',
},
[`&-checked:not(${componentCls}-button-wrapper-disabled)`]: {
zIndex: 1,
color: radioCheckedColor,
background: radioButtonCheckedBg,
borderColor: radioCheckedColor,
'&::before': {
backgroundColor: radioCheckedColor,
},
'&:first-child': {
borderColor: radioCheckedColor,
},
'&:hover': {
color: radioButtonHoverColor,
borderColor: radioButtonHoverColor,
'&::before': {
backgroundColor: radioButtonHoverColor,
},
},
'&:active': {
color: radioButtonActiveColor,
borderColor: radioButtonActiveColor,
'&::before': {
backgroundColor: radioButtonActiveColor,
},
},
},
[`${componentCls}-group-solid &-checked:not(${componentCls}-button-wrapper-disabled)`]: {
color: radioSolidCheckedColor,
background: radioCheckedColor,
borderColor: radioCheckedColor,
'&:hover': {
color: radioSolidCheckedColor,
background: radioButtonHoverColor,
borderColor: radioButtonHoverColor,
},
'&:active': {
color: radioSolidCheckedColor,
background: radioButtonActiveColor,
borderColor: radioButtonActiveColor,
},
},
'&-disabled': {
color: colorTextDisabled,
backgroundColor: colorBgContainerDisabled,
borderColor: colorBorder,
cursor: 'not-allowed',
'&:first-child, &:hover': {
color: colorTextDisabled,
backgroundColor: colorBgContainerDisabled,
borderColor: colorBorder,
},
},
[`&-disabled${componentCls}-button-wrapper-checked`]: {
color: radioDisabledButtonCheckedColor,
backgroundColor: radioDisabledButtonCheckedBg,
borderColor: colorBorder,
boxShadow: 'none',
},
},
};
};
// ============================== Export ==============================
export default genComponentStyleHook('Radio', token => {
const {
padding,
lineWidth,
controlItemBgActiveDisabled,
colorTextDisabled,
colorBgContainer,
fontSizeLG,
controlOutline,
colorPrimaryHover,
colorPrimaryActive,
colorText,
colorPrimary,
marginXS,
controlOutlineWidth,
colorTextLightSolid,
wireframe,
} = token;
// Radio
const radioFocusShadow = `0 0 0 ${controlOutlineWidth}px ${controlOutline}`;
const radioButtonFocusShadow = radioFocusShadow;
const radioSize = fontSizeLG;
const dotPadding = 4; // Fixed value
const radioDotDisabledSize = radioSize - dotPadding * 2;
const radioDotSize = wireframe ? radioDotDisabledSize : radioSize - (dotPadding + lineWidth) * 2;
const radioCheckedColor = colorPrimary;
// Radio buttons
const radioButtonColor = colorText;
const radioButtonHoverColor = colorPrimaryHover;
const radioButtonActiveColor = colorPrimaryActive;
const radioButtonPaddingHorizontal = padding - lineWidth;
const radioDisabledButtonCheckedColor = colorTextDisabled;
const radioWrapperMarginRight = marginXS;
const radioToken = mergeToken<RadioToken>(token, {
radioFocusShadow,
radioButtonFocusShadow,
radioSize,
radioDotSize,
radioDotDisabledSize,
radioCheckedColor,
radioDotDisabledColor: colorTextDisabled,
radioSolidCheckedColor: colorTextLightSolid,
radioButtonBg: colorBgContainer,
radioButtonCheckedBg: colorBgContainer,
radioButtonColor,
radioButtonHoverColor,
radioButtonActiveColor,
radioButtonPaddingHorizontal,
radioDisabledButtonCheckedBg: controlItemBgActiveDisabled,
radioDisabledButtonCheckedColor,
radioWrapperMarginRight,
});
return [
getGroupRadioStyle(radioToken),
getRadioBasicStyle(radioToken),
getRadioButtonStyle(radioToken),
];
});

View File

@ -1,61 +0,0 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
@radio-prefix-cls: ~'@{ant-prefix}-radio';
@radio-group-prefix-cls: ~'@{radio-prefix-cls}-group';
@radio-prefix-cls-button-wrapper: ~'@{radio-prefix-cls}-button-wrapper';
.@{radio-group-prefix-cls} {
&&-rtl {
direction: rtl;
}
}
// 一般状态
.@{radio-prefix-cls}-wrapper {
&&-rtl {
margin-right: 0;
margin-left: @radio-wrapper-margin-right;
direction: rtl;
}
}
.@{radio-prefix-cls-button-wrapper} {
&&-rtl {
border-right-width: 0;
border-left-width: @border-width-base;
}
&:not(:first-child) {
&::before {
.@{radio-prefix-cls-button-wrapper}.@{radio-prefix-cls-button-wrapper}-rtl& {
right: -1px;
left: 0;
}
}
}
&:first-child {
.@{radio-prefix-cls-button-wrapper}.@{radio-prefix-cls-button-wrapper}-rtl& {
border-right: @border-width-base @border-style-base @border-color-base;
border-radius: 0 @border-radius-base @border-radius-base 0;
}
.@{radio-prefix-cls-button-wrapper}-checked:not([class*=~"' @{radio-prefix-cls}-button-wrapper-disabled'"])& {
border-right-color: @radio-button-hover-color;
}
}
&:last-child {
.@{radio-prefix-cls-button-wrapper}.@{radio-prefix-cls-button-wrapper}-rtl& {
border-radius: @border-radius-base 0 0 @border-radius-base;
}
}
&-disabled {
&:first-child {
.@{radio-prefix-cls-button-wrapper}.@{radio-prefix-cls-button-wrapper}-rtl& {
border-right-color: @border-color-base;
}
}
}
}

View File

@ -1,6 +1,6 @@
// import './button/style';
// import './icon/style';
import './radio/style';
// import './radio/style';
// import './checkbox/style';
// import './grid/style';
// import './tag/style';

View File

@ -27,7 +27,7 @@ import type { ComponentToken as NotificationComponentToken } from '../../notific
import type { ComponentToken as PopconfirmComponentToken } from '../../popconfirm/style';
import type { ComponentToken as PopoverComponentToken } from '../../popover/style';
import type { ComponentToken as ProgressComponentToken } from '../../progress/style';
// import type { ComponentToken as RadioComponentToken } from '../../radio/style';
import type { ComponentToken as RadioComponentToken } from '../../radio/style';
import type { ComponentToken as RateComponentToken } from '../../rate/style';
import type { ComponentToken as ResultComponentToken } from '../../result/style';
// import type { ComponentToken as SegmentedComponentToken } from '../../segmented/style';
@ -87,7 +87,7 @@ export interface ComponentTokenMap {
Popover?: PopoverComponentToken;
Popconfirm?: PopconfirmComponentToken;
Rate?: RateComponentToken;
// Radio?: RadioComponentToken;
Radio?: RadioComponentToken;
Result?: ResultComponentToken;
Segmented?: SegmentedComponentToken;
Select?: SelectComponentToken;