refactor(radio): use composition api (#4720)
* refactor(radio): use composition api * docs: update * chore: update * docs: update * Update Group.tsx Co-authored-by: tangjinzhou <415800467@qq.com>pull/4723/head
parent
f653955c97
commit
cf3fe6b9e0
|
@ -1,133 +1,133 @@
|
|||
import { provide, inject, nextTick, defineComponent } from 'vue';
|
||||
import { provide, nextTick, defineComponent, ref, watch, onBeforeMount } from 'vue';
|
||||
import type { PropType, ExtractPropTypes } from 'vue';
|
||||
import classNames from '../_util/classNames';
|
||||
import PropTypes from '../_util/vue-types';
|
||||
import Radio from './Radio';
|
||||
import { getOptionProps, filterEmpty, hasProp, getSlot } from '../_util/props-util';
|
||||
import { defaultConfigProvider } from '../config-provider';
|
||||
import useConfigInject from '../_util/hooks/useConfigInject';
|
||||
import { tuple } from '../_util/type';
|
||||
import type { RadioChangeEvent } from './interface';
|
||||
import { useInjectFormItemContext } from '../form/FormItemContext';
|
||||
|
||||
const RadioGroupSizeTypes = tuple('large', 'default', 'small');
|
||||
|
||||
export type RadioGroupSize = typeof RadioGroupSizeTypes[number];
|
||||
|
||||
const RadioGroupOptionTypes = tuple('default', 'button');
|
||||
|
||||
export type RadioGroupOption = typeof RadioGroupOptionTypes[number];
|
||||
|
||||
export type RadioGroupChildOption = {
|
||||
label: string;
|
||||
value: string;
|
||||
disabled?: boolean;
|
||||
};
|
||||
|
||||
const radioGroupProps = {
|
||||
prefixCls: PropTypes.string,
|
||||
value: PropTypes.any,
|
||||
size: PropTypes.oneOf(RadioGroupSizeTypes).def('default'),
|
||||
options: {
|
||||
type: Array as PropType<Array<String | RadioGroupChildOption>>,
|
||||
},
|
||||
disabled: PropTypes.looseBool,
|
||||
name: PropTypes.string,
|
||||
buttonStyle: PropTypes.string.def('outline'),
|
||||
id: PropTypes.string,
|
||||
optionType: PropTypes.oneOf(RadioGroupOptionTypes).def('default'),
|
||||
};
|
||||
|
||||
export type RadioGroupProps = Partial<ExtractPropTypes<typeof radioGroupProps>>;
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ARadioGroup',
|
||||
props: {
|
||||
prefixCls: PropTypes.string,
|
||||
defaultValue: PropTypes.any,
|
||||
value: PropTypes.any,
|
||||
size: PropTypes.oneOf(tuple('large', 'default', 'small')).def('default'),
|
||||
options: PropTypes.array,
|
||||
disabled: PropTypes.looseBool,
|
||||
name: PropTypes.string,
|
||||
buttonStyle: PropTypes.string.def('outline'),
|
||||
onChange: PropTypes.func,
|
||||
id: PropTypes.string,
|
||||
},
|
||||
props: radioGroupProps,
|
||||
emits: ['update:value', 'change'],
|
||||
setup() {
|
||||
setup(props, { slots, emit }) {
|
||||
const formItemContext = useInjectFormItemContext();
|
||||
return {
|
||||
formItemContext,
|
||||
updatingValue: false,
|
||||
configProvider: inject('configProvider', defaultConfigProvider),
|
||||
radioGroupContext: null,
|
||||
};
|
||||
},
|
||||
data() {
|
||||
const { value, defaultValue } = this;
|
||||
return {
|
||||
stateValue: value === undefined ? defaultValue : value,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
value(val) {
|
||||
this.updatingValue = false;
|
||||
this.stateValue = val;
|
||||
},
|
||||
},
|
||||
// computed: {
|
||||
// radioOptions() {
|
||||
// const { disabled } = this;
|
||||
// return this.options.map(option => {
|
||||
// return typeof option === 'string'
|
||||
// ? { label: option, value: option }
|
||||
// : { ...option, disabled: option.disabled === undefined ? disabled : option.disabled };
|
||||
// });
|
||||
// },
|
||||
// },
|
||||
created() {
|
||||
this.radioGroupContext = provide('radioGroupContext', this);
|
||||
},
|
||||
methods: {
|
||||
onRadioChange(ev: RadioChangeEvent) {
|
||||
const lastValue = this.stateValue;
|
||||
const { prefixCls } = useConfigInject('radio', props);
|
||||
const stateValue = ref(props.value === undefined ? props.defaultValue : props.value);
|
||||
const updatingValue = ref<boolean>(false);
|
||||
watch(
|
||||
() => props.value,
|
||||
val => {
|
||||
stateValue.value = val;
|
||||
updatingValue.value = false;
|
||||
},
|
||||
);
|
||||
|
||||
const onRadioChange = (ev: RadioChangeEvent) => {
|
||||
const lastValue = stateValue.value;
|
||||
const { value } = ev.target;
|
||||
if (!hasProp(this, 'value')) {
|
||||
this.stateValue = value;
|
||||
|
||||
if (!('value' in props)) {
|
||||
stateValue.value = value;
|
||||
}
|
||||
// nextTick for https://github.com/vueComponent/ant-design-vue/issues/1280
|
||||
if (!this.updatingValue && value !== lastValue) {
|
||||
this.updatingValue = true;
|
||||
this.$emit('update:value', value);
|
||||
this.$emit('change', ev);
|
||||
this.formItemContext.onFieldChange();
|
||||
if (!updatingValue.value && value !== lastValue) {
|
||||
updatingValue.value = true;
|
||||
emit('update:value', value);
|
||||
emit('change', ev);
|
||||
formItemContext.onFieldChange();
|
||||
}
|
||||
nextTick(() => {
|
||||
this.updatingValue = false;
|
||||
updatingValue.value = false;
|
||||
});
|
||||
},
|
||||
},
|
||||
render() {
|
||||
const props = getOptionProps(this);
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
options,
|
||||
buttonStyle,
|
||||
id = this.formItemContext.id.value,
|
||||
} = props;
|
||||
const { getPrefixCls } = this.configProvider;
|
||||
const prefixCls = getPrefixCls('radio', customizePrefixCls);
|
||||
|
||||
const groupPrefixCls = `${prefixCls}-group`;
|
||||
const classString = classNames(groupPrefixCls, `${groupPrefixCls}-${buttonStyle}`, {
|
||||
[`${groupPrefixCls}-${props.size}`]: props.size,
|
||||
};
|
||||
|
||||
provide('radioGroupContext', {
|
||||
onRadioChange,
|
||||
stateValue,
|
||||
props,
|
||||
});
|
||||
|
||||
let children = filterEmpty(getSlot(this));
|
||||
return () => {
|
||||
const { options, optionType, buttonStyle, id = formItemContext.id.value } = props;
|
||||
|
||||
// 如果存在 options, 优先使用
|
||||
if (options && options.length > 0) {
|
||||
children = options.map(option => {
|
||||
if (typeof option === 'string') {
|
||||
const groupPrefixCls = `${prefixCls.value}-group`;
|
||||
|
||||
const classString = classNames(groupPrefixCls, `${groupPrefixCls}-${buttonStyle}`, {
|
||||
[`${groupPrefixCls}-${props.size}`]: props.size,
|
||||
});
|
||||
|
||||
let children = null;
|
||||
if (options && options.length > 0) {
|
||||
const optionsPrefixCls =
|
||||
optionType === 'button' ? `${prefixCls.value}-button` : prefixCls.value;
|
||||
children = options.map(option => {
|
||||
if (typeof option === 'string') {
|
||||
return (
|
||||
<Radio
|
||||
key={option}
|
||||
prefixCls={optionsPrefixCls}
|
||||
disabled={props.disabled}
|
||||
value={option}
|
||||
checked={stateValue.value === option}
|
||||
>
|
||||
{option}
|
||||
</Radio>
|
||||
);
|
||||
}
|
||||
const { value, disabled, label } = option as RadioGroupChildOption;
|
||||
return (
|
||||
<Radio
|
||||
key={option}
|
||||
prefixCls={prefixCls}
|
||||
disabled={props.disabled}
|
||||
value={option}
|
||||
checked={this.stateValue === option}
|
||||
key={`radio-group-value-options-${value}`}
|
||||
prefixCls={optionsPrefixCls}
|
||||
disabled={disabled || props.disabled}
|
||||
value={value}
|
||||
checked={stateValue.value === value}
|
||||
>
|
||||
{option}
|
||||
{label}
|
||||
</Radio>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Radio
|
||||
key={`radio-group-value-options-${option.value}`}
|
||||
prefixCls={prefixCls}
|
||||
disabled={option.disabled || props.disabled}
|
||||
value={option.value}
|
||||
checked={this.stateValue === option.value}
|
||||
>
|
||||
{option.label}
|
||||
</Radio>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div class={classString} id={id}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
} else {
|
||||
children = slots.default?.();
|
||||
}
|
||||
return (
|
||||
<div class={classString} id={id}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
import type { ExtractPropTypes } from 'vue';
|
||||
import { defineComponent, inject } from 'vue';
|
||||
import { defineComponent, inject, ref } from 'vue';
|
||||
import PropTypes from '../_util/vue-types';
|
||||
import VcCheckbox from '../vc-checkbox';
|
||||
import classNames from '../_util/classNames';
|
||||
import { getOptionProps } from '../_util/props-util';
|
||||
import { defaultConfigProvider } from '../config-provider';
|
||||
import type { RadioChangeEvent } from './interface';
|
||||
import useConfigInject from '../_util/hooks/useConfigInject';
|
||||
import type { RadioChangeEvent, RadioGroupContext } from './interface';
|
||||
import { useInjectFormItemContext } from '../form/FormItemContext';
|
||||
|
||||
export const radioProps = {
|
||||
prefixCls: PropTypes.string,
|
||||
defaultChecked: PropTypes.looseBool,
|
||||
checked: PropTypes.looseBool,
|
||||
disabled: PropTypes.looseBool,
|
||||
isGroup: PropTypes.looseBool,
|
||||
|
@ -30,72 +28,67 @@ export default defineComponent({
|
|||
name: 'ARadio',
|
||||
props: radioProps,
|
||||
emits: ['update:checked', 'update:value', 'change', 'blur', 'focus'],
|
||||
setup() {
|
||||
setup(props, { emit, expose, slots }) {
|
||||
const formItemContext = useInjectFormItemContext();
|
||||
return {
|
||||
configProvider: inject('configProvider', defaultConfigProvider),
|
||||
radioGroupContext: inject('radioGroupContext', null),
|
||||
formItemContext,
|
||||
const vcCheckbox = ref<HTMLElement>();
|
||||
const radioGroupContext = inject<RadioGroupContext>('radioGroupContext');
|
||||
const { prefixCls } = useConfigInject('radio', props);
|
||||
|
||||
const focus = () => {
|
||||
vcCheckbox.value.focus();
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
focus() {
|
||||
(this.$refs.vcCheckbox as HTMLInputElement).focus();
|
||||
},
|
||||
blur() {
|
||||
(this.$refs.vcCheckbox as HTMLInputElement).blur();
|
||||
},
|
||||
handleChange(event: RadioChangeEvent) {
|
||||
|
||||
const blur = () => {
|
||||
vcCheckbox.value.blur();
|
||||
};
|
||||
|
||||
expose({ focus, blur });
|
||||
|
||||
const handleChange = (event: RadioChangeEvent) => {
|
||||
const targetChecked = event.target.checked;
|
||||
this.$emit('update:checked', targetChecked);
|
||||
this.$emit('update:value', targetChecked);
|
||||
this.$emit('change', event);
|
||||
this.formItemContext.onFieldChange();
|
||||
},
|
||||
onChange2(e: RadioChangeEvent) {
|
||||
this.$emit('change', e);
|
||||
if (this.radioGroupContext && this.radioGroupContext.onRadioChange) {
|
||||
this.radioGroupContext.onRadioChange(e);
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
render() {
|
||||
const { $slots, radioGroupContext: radioGroup } = this;
|
||||
const props = getOptionProps(this);
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
id = this.formItemContext.id.value,
|
||||
...restProps
|
||||
} = props;
|
||||
const { getPrefixCls } = this.configProvider;
|
||||
const prefixCls = getPrefixCls('radio', customizePrefixCls);
|
||||
|
||||
const rProps: RadioProps = {
|
||||
prefixCls,
|
||||
id,
|
||||
...restProps,
|
||||
emit('update:checked', targetChecked);
|
||||
emit('update:value', targetChecked);
|
||||
emit('change', event);
|
||||
formItemContext.onFieldChange();
|
||||
};
|
||||
|
||||
if (radioGroup) {
|
||||
rProps.name = radioGroup.name;
|
||||
rProps.onChange = this.onChange2;
|
||||
rProps.checked = props.value === radioGroup.stateValue;
|
||||
rProps.disabled = props.disabled || radioGroup.disabled;
|
||||
} else {
|
||||
rProps.onChange = this.handleChange;
|
||||
}
|
||||
const wrapperClassString = classNames({
|
||||
[`${prefixCls}-wrapper`]: true,
|
||||
[`${prefixCls}-wrapper-checked`]: rProps.checked,
|
||||
[`${prefixCls}-wrapper-disabled`]: rProps.disabled,
|
||||
});
|
||||
const onChange = (e: RadioChangeEvent) => {
|
||||
emit('change', e);
|
||||
if (radioGroupContext && radioGroupContext.onRadioChange) {
|
||||
radioGroupContext.onRadioChange(e);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<label class={wrapperClassString}>
|
||||
<VcCheckbox {...rProps} ref="vcCheckbox" />
|
||||
{$slots.default && <span>{$slots.default()}</span>}
|
||||
</label>
|
||||
);
|
||||
return () => {
|
||||
const radioGroup = radioGroupContext;
|
||||
const { prefixCls: customizePrefixCls, id = formItemContext.id.value, ...restProps } = props;
|
||||
|
||||
const rProps: RadioProps = {
|
||||
prefixCls: prefixCls.value,
|
||||
id,
|
||||
...restProps,
|
||||
};
|
||||
|
||||
if (radioGroup) {
|
||||
rProps.name = radioGroup.props.name;
|
||||
rProps.onChange = onChange;
|
||||
rProps.checked = props.value === radioGroup.stateValue.value;
|
||||
rProps.disabled = props.disabled || radioGroup.props.disabled;
|
||||
} else {
|
||||
rProps.onChange = handleChange;
|
||||
}
|
||||
const wrapperClassString = classNames({
|
||||
[`${prefixCls.value}-wrapper`]: true,
|
||||
[`${prefixCls.value}-wrapper-checked`]: rProps.checked,
|
||||
[`${prefixCls.value}-wrapper-disabled`]: rProps.disabled,
|
||||
});
|
||||
|
||||
return (
|
||||
<label class={wrapperClassString}>
|
||||
<VcCheckbox {...rProps} ref={vcCheckbox} />
|
||||
{slots.default && <span>{slots.default()}</span>}
|
||||
</label>
|
||||
);
|
||||
};
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,35 +1,28 @@
|
|||
import { defineComponent, inject } from 'vue';
|
||||
import type { RadioProps } from './Radio';
|
||||
import Radio, { radioProps } from './Radio';
|
||||
import { getOptionProps, getSlot } from '../_util/props-util';
|
||||
import { defaultConfigProvider } from '../config-provider';
|
||||
import useConfigInject from '../_util/hooks/useConfigInject';
|
||||
import type { RadioGroupContext } from './interface';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ARadioButton',
|
||||
props: {
|
||||
...radioProps,
|
||||
},
|
||||
setup() {
|
||||
return {
|
||||
configProvider: inject('configProvider', defaultConfigProvider),
|
||||
radioGroupContext: inject<any>('radioGroupContext', {}),
|
||||
};
|
||||
},
|
||||
render() {
|
||||
const props = getOptionProps(this) as RadioProps;
|
||||
const { prefixCls: customizePrefixCls, ...otherProps } = props;
|
||||
const { getPrefixCls } = this.configProvider;
|
||||
const prefixCls = getPrefixCls('radio-button', customizePrefixCls);
|
||||
props: radioProps,
|
||||
setup(props: RadioProps, { slots }) {
|
||||
const { prefixCls } = useConfigInject('radio-button', props);
|
||||
const radioGroupContext = inject<RadioGroupContext>('radioGroupContext');
|
||||
|
||||
const rProps: RadioProps = {
|
||||
prefixCls,
|
||||
...otherProps,
|
||||
return () => {
|
||||
const rProps: RadioProps = {
|
||||
...props,
|
||||
prefixCls: prefixCls.value,
|
||||
};
|
||||
|
||||
if (radioGroupContext) {
|
||||
rProps.onChange = radioGroupContext.onRadioChange;
|
||||
rProps.checked = rProps.value === radioGroupContext.stateValue.value;
|
||||
rProps.disabled = rProps.disabled || radioGroupContext.props.disabled;
|
||||
}
|
||||
return <Radio {...rProps}>{slots.default?.()}</Radio>;
|
||||
};
|
||||
if (this.radioGroupContext) {
|
||||
rProps.onChange = this.radioGroupContext.onRadioChange;
|
||||
rProps.checked = props.value === this.radioGroupContext.stateValue;
|
||||
rProps.disabled = props.disabled || this.radioGroupContext.disabled;
|
||||
}
|
||||
return <Radio {...rProps}>{getSlot(this)}</Radio>;
|
||||
},
|
||||
});
|
||||
|
|
|
@ -41,13 +41,16 @@ exports[`renders ./components/radio/demo/radioGroup.vue correctly 1`] = `
|
|||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/radio/demo/radioGroup-more.vue correctly 1`] = `<div class="ant-radio-group ant-radio-group-outline ant-radio-group-default"><label class="ant-radio-wrapper ant-radio-wrapper-checked" style="display: block; height: 30px; line-height: 30px;"><span class="ant-radio ant-radio-checked"><input type="radio" class="ant-radio-input" value="1"><span class="ant-radio-inner"></span></span><span>Option A</span></label><label class="ant-radio-wrapper" style="display: block; height: 30px; line-height: 30px;"><span class="ant-radio"><input type="radio" class="ant-radio-input" value="2"><span class="ant-radio-inner"></span></span><span>Option B</span></label><label class="ant-radio-wrapper" style="display: block; height: 30px; line-height: 30px;"><span class="ant-radio"><input type="radio" class="ant-radio-input" value="3"><span class="ant-radio-inner"></span></span><span>Option C</span></label><label class="ant-radio-wrapper" style="display: block; height: 30px; line-height: 30px;"><span class="ant-radio"><input type="radio" class="ant-radio-input" value="4"><span class="ant-radio-inner"></span></span><span> More... <!--v-if--></span></label></div>`;
|
||||
exports[`renders ./components/radio/demo/radioGroup-more.vue correctly 1`] = `<div class="ant-radio-group ant-radio-group-outline ant-radio-group-default"><label class="ant-radio-wrapper ant-radio-wrapper-checked" style="display: flex; height: 30px; line-height: 30px;"><span class="ant-radio ant-radio-checked"><input type="radio" class="ant-radio-input" value="1"><span class="ant-radio-inner"></span></span><span>Option A</span></label><label class="ant-radio-wrapper" style="display: flex; height: 30px; line-height: 30px;"><span class="ant-radio"><input type="radio" class="ant-radio-input" value="2"><span class="ant-radio-inner"></span></span><span>Option B</span></label><label class="ant-radio-wrapper" style="display: flex; height: 30px; line-height: 30px;"><span class="ant-radio"><input type="radio" class="ant-radio-input" value="3"><span class="ant-radio-inner"></span></span><span>Option C</span></label><label class="ant-radio-wrapper" style="display: flex; height: 30px; line-height: 30px;"><span class="ant-radio"><input type="radio" class="ant-radio-input" value="4"><span class="ant-radio-inner"></span></span><span> More... <!--v-if--></span></label></div>`;
|
||||
|
||||
exports[`renders ./components/radio/demo/radioGroup-options.vue correctly 1`] = `
|
||||
<div>
|
||||
<div class="ant-radio-group ant-radio-group-outline ant-radio-group-default"><label class="ant-radio-wrapper ant-radio-wrapper-checked"><span class="ant-radio ant-radio-checked"><input type="radio" class="ant-radio-input" value="Apple"><span class="ant-radio-inner"></span></span><span>Apple</span></label><label class="ant-radio-wrapper"><span class="ant-radio"><input type="radio" class="ant-radio-input" value="Pear"><span class="ant-radio-inner"></span></span><span>Pear</span></label><label class="ant-radio-wrapper"><span class="ant-radio"><input type="radio" class="ant-radio-input" value="Orange"><span class="ant-radio-inner"></span></span><span>Orange</span></label></div><br>
|
||||
<div class="ant-radio-group ant-radio-group-outline ant-radio-group-default"><label class="ant-radio-wrapper ant-radio-wrapper-checked"><span class="ant-radio ant-radio-checked"><input type="radio" class="ant-radio-input" value="Apple"><span class="ant-radio-inner"></span></span><span>Apple</span></label><label class="ant-radio-wrapper"><span class="ant-radio"><input type="radio" class="ant-radio-input" value="Pear"><span class="ant-radio-inner"></span></span><span>Pear</span></label><label class="ant-radio-wrapper"><span class="ant-radio"><input type="radio" class="ant-radio-input" value="Orange"><span class="ant-radio-inner"></span></span><span>Orange</span></label></div><br>
|
||||
<div class="ant-radio-group ant-radio-group-outline ant-radio-group-default"><label class="ant-radio-wrapper ant-radio-wrapper-checked ant-radio-wrapper-disabled"><span class="ant-radio ant-radio-checked ant-radio-disabled"><input type="radio" disabled="" class="ant-radio-input" value="Apple"><span class="ant-radio-inner"></span></span><span>Apple</span></label><label class="ant-radio-wrapper ant-radio-wrapper-disabled"><span class="ant-radio ant-radio-disabled"><input type="radio" disabled="" class="ant-radio-input" value="Pear"><span class="ant-radio-inner"></span></span><span>Pear</span></label><label class="ant-radio-wrapper ant-radio-wrapper-disabled"><span class="ant-radio ant-radio-disabled"><input type="radio" disabled="" class="ant-radio-input" value="Orange"><span class="ant-radio-inner"></span></span><span>Orange</span></label></div>
|
||||
<div class="ant-radio-group ant-radio-group-outline ant-radio-group-default"><label class="ant-radio-wrapper ant-radio-wrapper-checked"><span class="ant-radio ant-radio-checked"><input type="radio" class="ant-radio-input" value="Apple"><span class="ant-radio-inner"></span></span><span>Apple</span></label><label class="ant-radio-wrapper"><span class="ant-radio"><input type="radio" class="ant-radio-input" value="Pear"><span class="ant-radio-inner"></span></span><span>Pear</span></label><label class="ant-radio-wrapper ant-radio-wrapper-disabled"><span class="ant-radio ant-radio-disabled"><input type="radio" disabled="" class="ant-radio-input" value="Orange"><span class="ant-radio-inner"></span></span><span>Orange</span></label></div><br>
|
||||
<div class="ant-radio-group ant-radio-group-outline ant-radio-group-default"><label class="ant-radio-wrapper ant-radio-wrapper-checked ant-radio-wrapper-disabled"><span class="ant-radio ant-radio-checked ant-radio-disabled"><input type="radio" disabled="" class="ant-radio-input" value="Apple"><span class="ant-radio-inner"></span></span><span>Apple</span></label><label class="ant-radio-wrapper ant-radio-wrapper-disabled"><span class="ant-radio ant-radio-disabled"><input type="radio" disabled="" class="ant-radio-input" value="Pear"><span class="ant-radio-inner"></span></span><span>Pear</span></label><label class="ant-radio-wrapper ant-radio-wrapper-disabled"><span class="ant-radio ant-radio-disabled"><input type="radio" disabled="" class="ant-radio-input" value="Orange"><span class="ant-radio-inner"></span></span><span>Orange</span></label></div><br>
|
||||
<div class="ant-radio-group ant-radio-group-outline ant-radio-group-default"><label class="ant-radio-button-wrapper ant-radio-button-wrapper-checked"><span class="ant-radio-button ant-radio-button-checked"><input type="radio" class="ant-radio-button-input" value="Apple"><span class="ant-radio-button-inner"></span></span><span>Apple</span></label><label class="ant-radio-button-wrapper"><span class="ant-radio-button"><input type="radio" class="ant-radio-button-input" value="Pear"><span class="ant-radio-button-inner"></span></span><span>Pear</span></label><label class="ant-radio-button-wrapper"><span class="ant-radio-button"><input type="radio" class="ant-radio-button-input" value="Orange"><span class="ant-radio-button-inner"></span></span><span>Orange</span></label></div><br>
|
||||
<div class="ant-radio-group ant-radio-group-outline ant-radio-group-default"><label class="ant-radio-button-wrapper ant-radio-button-wrapper-checked"><span class="ant-radio-button ant-radio-button-checked"><input type="radio" class="ant-radio-button-input" value="Apple"><span class="ant-radio-button-inner"></span></span><span>Apple</span></label><label class="ant-radio-button-wrapper"><span class="ant-radio-button"><input type="radio" class="ant-radio-button-input" value="Pear"><span class="ant-radio-button-inner"></span></span><span>Pear</span></label><label class="ant-radio-button-wrapper ant-radio-button-wrapper-disabled"><span class="ant-radio-button ant-radio-button-disabled"><input type="radio" disabled="" class="ant-radio-button-input" value="Orange"><span class="ant-radio-button-inner"></span></span><span>Orange</span></label></div><br>
|
||||
<div class="ant-radio-group ant-radio-group-outline ant-radio-group-default"><label class="ant-radio-button-wrapper ant-radio-button-wrapper-checked ant-radio-button-wrapper-disabled"><span class="ant-radio-button ant-radio-button-checked ant-radio-button-disabled"><input type="radio" disabled="" class="ant-radio-button-input" value="Apple"><span class="ant-radio-button-inner"></span></span><span>Apple</span></label><label class="ant-radio-button-wrapper ant-radio-button-wrapper-disabled"><span class="ant-radio-button ant-radio-button-disabled"><input type="radio" disabled="" class="ant-radio-button-input" value="Pear"><span class="ant-radio-button-inner"></span></span><span>Pear</span></label><label class="ant-radio-button-wrapper ant-radio-button-wrapper-disabled"><span class="ant-radio-button ant-radio-button-disabled"><input type="radio" disabled="" class="ant-radio-button-input" value="Orange"><span class="ant-radio-button-inner"></span></span><span>Orange</span></label></div><br>
|
||||
</div>
|
||||
`;
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
exports[`Radio all children should have a name property 1`] = `<div class="ant-radio-group ant-radio-group-outline ant-radio-group-default"><label class="ant-radio-wrapper"><span class="ant-radio"><input name="radiogroup" type="radio" class="ant-radio-input" value="A"><span class="ant-radio-inner"></span></span><span>A</span></label><label class="ant-radio-wrapper"><span class="ant-radio"><input name="radiogroup" type="radio" class="ant-radio-input" value="B"><span class="ant-radio-inner"></span></span><span>B</span></label><label class="ant-radio-wrapper"><span class="ant-radio"><input name="radiogroup" type="radio" class="ant-radio-input" value="C"><span class="ant-radio-inner"></span></span><span>C</span></label></div>`;
|
||||
|
||||
exports[`Radio fire change events when value changes 1`] = `<div class="ant-radio-group ant-radio-group-outline ant-radio-group-default"><label class="ant-radio-wrapper ant-radio-wrapper-checked"><span class="ant-radio ant-radio-checked"><input type="radio" class="ant-radio-input" value="A"><span class="ant-radio-inner"></span></span><span>A</span></label><label class="ant-radio-wrapper"><span class="ant-radio"><input type="radio" class="ant-radio-input" value="B"><span class="ant-radio-inner"></span></span><span>B</span></label><label class="ant-radio-wrapper"><span class="ant-radio"><input type="radio" class="ant-radio-input" value="C"><span class="ant-radio-inner"></span></span><span>C</span></label></div>`;
|
||||
exports[`Radio fire change events when value changes 1`] = `<div class="ant-radio-group ant-radio-group-outline ant-radio-group-default"><label class="ant-radio-wrapper"><span class="ant-radio"><input type="radio" class="ant-radio-input" value="A"><span class="ant-radio-inner"></span></span><span>A</span></label><label class="ant-radio-wrapper"><span class="ant-radio"><input type="radio" class="ant-radio-input" value="B"><span class="ant-radio-inner"></span></span><span>B</span></label><label class="ant-radio-wrapper"><span class="ant-radio"><input type="radio" class="ant-radio-input" value="C"><span class="ant-radio-inner"></span></span><span>C</span></label></div>`;
|
||||
|
||||
exports[`Radio fire change events when value changes 2`] = `<div class="ant-radio-group ant-radio-group-outline ant-radio-group-default"><label class="ant-radio-wrapper ant-radio-wrapper-checked"><span class="ant-radio ant-radio-checked"><input type="radio" class="ant-radio-input" value="A"><span class="ant-radio-inner"></span></span><span>A</span></label><label class="ant-radio-wrapper"><span class="ant-radio"><input type="radio" class="ant-radio-input" value="B"><span class="ant-radio-inner"></span></span><span>B</span></label><label class="ant-radio-wrapper"><span class="ant-radio"><input type="radio" class="ant-radio-input" value="C"><span class="ant-radio-inner"></span></span><span>C</span></label></div>`;
|
||||
|
||||
|
|
|
@ -46,4 +46,3 @@ export default defineComponent({
|
|||
},
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
|
|
@ -32,7 +32,7 @@ export default defineComponent({
|
|||
setup() {
|
||||
const value = ref<number>(1);
|
||||
const radioStyle = reactive({
|
||||
display: 'block',
|
||||
display: 'flex',
|
||||
height: '30px',
|
||||
lineHeight: '30px',
|
||||
});
|
||||
|
|
|
@ -19,9 +19,16 @@ Render radios by configuring `options`.
|
|||
<div>
|
||||
<a-radio-group v-model:value="value1" :options="plainOptions" />
|
||||
<br />
|
||||
<a-radio-group v-model:value="value2" :options="options" />
|
||||
<a-radio-group v-model:value="value2" :options="optionsWithDisabled" />
|
||||
<br />
|
||||
<a-radio-group v-model:value="value3" :options="plainOptions" disabled />
|
||||
<br />
|
||||
<a-radio-group v-model:value="value1" option-type="button" :options="plainOptions" />
|
||||
<br />
|
||||
<a-radio-group v-model:value="value2" option-type="button" :options="optionsWithDisabled" />
|
||||
<br />
|
||||
<a-radio-group v-model:value="value3" option-type="button" :options="plainOptions" disabled />
|
||||
<br />
|
||||
<a-radio-group v-model:value="value3" :options="optionsWithDisabled" disabled />
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
|
@ -35,7 +42,7 @@ const options = [
|
|||
const optionsWithDisabled = [
|
||||
{ label: 'Apple', value: 'Apple' },
|
||||
{ label: 'Pear', value: 'Pear' },
|
||||
{ label: 'Orange', value: 'Orange', disabled: false },
|
||||
{ label: 'Orange', value: 'Orange', disabled: true },
|
||||
];
|
||||
export default defineComponent({
|
||||
data() {
|
||||
|
|
|
@ -14,7 +14,7 @@ Radio.
|
|||
|
||||
## API
|
||||
|
||||
### Radio
|
||||
### Radio/Radio.Button
|
||||
|
||||
| Property | Description | Type | Default |
|
||||
| --- | --- | --- | --- |
|
||||
|
@ -27,15 +27,15 @@ Radio.
|
|||
|
||||
Radio group can wrap a group of `Radio`。
|
||||
|
||||
| Property | Description | Type | Default |
|
||||
| --- | --- | --- | --- |
|
||||
| defaultValue | Default selected value | any | - |
|
||||
| disabled | Disable all radio buttons | boolean | false |
|
||||
| name | The `name` property of all `input[type="radio"]` children | string | - |
|
||||
| options | set children optional | string\[] \| Array<{ label: string value: string disabled?: boolean }> | - |
|
||||
| size | size for radio button style | `large` \| `default` \| `small` | `default` |
|
||||
| value(v-model) | Used for setting the currently selected value. | any | - |
|
||||
| buttonStyle | style type of radio button | `outline` \| `solid` | `outline` |
|
||||
| Property | Description | Type | Default | Version |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| buttonStyle | style type of radio button | `outline` \| `solid` | `outline` | |
|
||||
| disabled | Disable all radio buttons | boolean | false | |
|
||||
| name | The `name` property of all `input[type="radio"]` children | string | - | |
|
||||
| options | set children optional | string\[] \| Array<{ label: string value: string disabled?: boolean }> | - | |
|
||||
| optionType | Set Radio optionType | `default` \| `button` | `default` | 3.0.0 |
|
||||
| size | size for radio button style | `large` \| `default` \| `small` | `default` | |
|
||||
| value(v-model) | Used for setting the currently selected value. | any | - | |
|
||||
|
||||
### RadioGroup Events
|
||||
|
||||
|
|
|
@ -15,27 +15,28 @@ cover: https://gw.alipayobjects.com/zos/alicdn/8cYb5seNB/Radio.svg
|
|||
|
||||
## API
|
||||
|
||||
### Radio
|
||||
### Radio/Radio.Button
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| ---------------- | --------------------------------- | ------- | ------ |
|
||||
| autofocus | 自动获取焦点 | boolean | false |
|
||||
| checked(v-model) | 指定当前是否选中 | boolean | false |
|
||||
| disabled | 禁用 Radio | boolean | false |
|
||||
| value | 根据 value 进行比较,判断是否选中 | any | - |
|
||||
|
||||
### RadioGroup
|
||||
|
||||
单选框组合,用于包裹一组 `Radio`。
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| --- | --- | --- | --- |
|
||||
| defaultValue | 默认选中的值 | any | - |
|
||||
| disabled | 禁选所有子单选器 | boolean | false |
|
||||
| name | RadioGroup 下所有 `input[type="radio"]` 的 `name` 属性 | string | - |
|
||||
| options | 以配置形式设置子元素 | string\[] \| Array<{ label: string value: string disabled?: boolean }> | - |
|
||||
| size | 大小,只对按钮样式生效 | `large` \| `default` \| `small` | `default` |
|
||||
| value(v-model) | 用于设置当前选中的值 | any | - |
|
||||
| buttonStyle | RadioButton 的风格样式,目前有描边和填色两种风格 | `outline` \| `solid` | `outline` |
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| buttonStyle | RadioButton 的风格样式,目前有描边和填色两种风格 | `outline` \| `solid` | `outline` | |
|
||||
| disabled | 禁选所有子单选器 | boolean | false | |
|
||||
| name | RadioGroup 下所有 `input[type="radio"]` 的 `name` 属性 | string | - | |
|
||||
| options | 以配置形式设置子元素 | string\[] \| Array<{ label: string value: string disabled?: boolean }> | - | |
|
||||
| optionType | 用于设置 Radio `options` 类型 | `default` \| `button` | `default` | 3.0.0 |
|
||||
| size | 大小,只对按钮样式生效 | `large` \| `default` \| `small` | `default` | |
|
||||
| value(v-model) | 用于设置当前选中的值 | any | - | |
|
||||
|
||||
### RadioGroup 事件
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import type { RadioProps } from './Radio';
|
||||
|
||||
import type { Ref } from 'vue';
|
||||
export interface RadioChangeEventTarget extends RadioProps {
|
||||
checked: boolean;
|
||||
}
|
||||
|
@ -10,3 +10,9 @@ export interface RadioChangeEvent {
|
|||
preventDefault: () => void;
|
||||
nativeEvent: MouseEvent;
|
||||
}
|
||||
|
||||
export interface RadioGroupContext {
|
||||
stateValue: Ref;
|
||||
props: RadioProps;
|
||||
onRadioChange: (e: RadioChangeEvent) => void;
|
||||
}
|
||||
|
|
|
@ -5,34 +5,47 @@
|
|||
@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 fade(@radio-dot-color, 8%);
|
||||
@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-block;
|
||||
margin-right: 8px;
|
||||
white-space: nowrap;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
margin-right: @radio-wrapper-margin-right;
|
||||
cursor: pointer;
|
||||
|
||||
&::after {
|
||||
display: inline-block;
|
||||
width: 0;
|
||||
overflow: hidden;
|
||||
content: '\a0';
|
||||
}
|
||||
}
|
||||
|
||||
.@{radio-prefix-cls} {
|
||||
.reset-component();
|
||||
|
||||
position: relative;
|
||||
top: @radio-top;
|
||||
display: inline-block;
|
||||
line-height: 1;
|
||||
white-space: nowrap;
|
||||
vertical-align: sub;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
|
||||
|
@ -67,12 +80,10 @@
|
|||
|
||||
&-inner {
|
||||
&::after {
|
||||
@radio-dot-size: @radio-size - 8px;
|
||||
|
||||
position: absolute;
|
||||
top: ((@radio-size - @radio-dot-size) / 2) - @radio-border-width;
|
||||
left: ((@radio-size - @radio-dot-size) / 2) - @radio-border-width;
|
||||
display: table;
|
||||
display: block;
|
||||
width: @radio-dot-size;
|
||||
height: @radio-dot-size;
|
||||
background-color: @radio-dot-color;
|
||||
|
@ -95,7 +106,7 @@
|
|||
border-color: @border-color-base;
|
||||
border-style: solid;
|
||||
border-width: @radio-border-width;
|
||||
border-radius: 100px;
|
||||
border-radius: 50%;
|
||||
transition: all @radio-duration;
|
||||
}
|
||||
|
||||
|
@ -124,6 +135,8 @@
|
|||
}
|
||||
|
||||
.@{radio-prefix-cls}-disabled {
|
||||
cursor: not-allowed;
|
||||
|
||||
.@{radio-inner-prefix-cls} {
|
||||
background-color: @input-disabled-bg;
|
||||
border-color: @border-color-base !important;
|
||||
|
@ -155,13 +168,14 @@ span.@{radio-prefix-cls} + * {
|
|||
margin: 0;
|
||||
padding: 0 @padding-md - 1px;
|
||||
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: 0;
|
||||
border-left-width: 0;
|
||||
cursor: pointer;
|
||||
transition: color 0.3s, background 0.3s, border-color 0.3s, box-shadow 0.3s;
|
||||
|
||||
|
@ -170,10 +184,12 @@ span.@{radio-prefix-cls} + * {
|
|||
}
|
||||
|
||||
> .@{radio-prefix-cls}-button {
|
||||
display: block;
|
||||
width: 0;
|
||||
height: 0;
|
||||
margin-left: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: -1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.@{radio-group-prefix-cls}-large & {
|
||||
|
@ -203,6 +219,7 @@ span.@{radio-prefix-cls} + * {
|
|||
content: '';
|
||||
}
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
border-left: @border-width-base @border-style-base @border-color-base;
|
||||
border-radius: @border-radius-base 0 0 @border-radius-base;
|
||||
|
@ -324,9 +341,4 @@ span.@{radio-prefix-cls} + * {
|
|||
}
|
||||
}
|
||||
|
||||
// Firefox hack
|
||||
@supports (-moz-appearance: meterbar) and (background-blend-mode: difference, normal) {
|
||||
.@{radio-prefix-cls} {
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
}
|
||||
@import './rtl';
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
@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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue