Skip to content

Commit 44be872

Browse files
committed
refactor: radio context
1 parent a435e2c commit 44be872

File tree

7 files changed

+82
-40
lines changed

7 files changed

+82
-40
lines changed

components/radio/Group.tsx

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { provide, nextTick, defineComponent, ref, watch } from 'vue';
1+
import { nextTick, defineComponent, ref, watch, computed } from 'vue';
22
import type { PropType, ExtractPropTypes } from 'vue';
33
import classNames from '../_util/classNames';
44
import PropTypes from '../_util/vue-types';
@@ -7,6 +7,7 @@ import useConfigInject from '../_util/hooks/useConfigInject';
77
import { tuple } from '../_util/type';
88
import type { RadioChangeEvent, RadioGroupButtonStyle, RadioGroupOptionType } from './interface';
99
import { useInjectFormItemContext } from '../form/FormItemContext';
10+
import { useProvideRadioGroupContext } from './context';
1011

1112
const RadioGroupSizeTypes = tuple('large', 'default', 'small');
1213

@@ -74,14 +75,16 @@ export default defineComponent({
7475
});
7576
};
7677

77-
provide('radioGroupContext', {
78-
onRadioChange,
79-
stateValue,
80-
props,
78+
useProvideRadioGroupContext({
79+
onChange: onRadioChange,
80+
value: stateValue,
81+
disabled: computed(() => props.disabled),
82+
name: computed(() => props.name),
83+
optionType: computed(() => props.optionType),
8184
});
8285

8386
return () => {
84-
const { options, optionType, buttonStyle, id = formItemContext.id.value } = props;
87+
const { options, buttonStyle, id = formItemContext.id.value } = props;
8588

8689
const groupPrefixCls = `${prefixCls.value}-group`;
8790

@@ -92,14 +95,12 @@ export default defineComponent({
9295

9396
let children = null;
9497
if (options && options.length > 0) {
95-
const optionsPrefixCls =
96-
optionType === 'button' ? `${prefixCls.value}-button` : prefixCls.value;
9798
children = options.map(option => {
9899
if (typeof option === 'string' || typeof option === 'number') {
99100
return (
100101
<Radio
101102
key={option}
102-
prefixCls={optionsPrefixCls}
103+
prefixCls={prefixCls.value}
103104
disabled={props.disabled}
104105
value={option}
105106
checked={stateValue.value === option}
@@ -112,7 +113,7 @@ export default defineComponent({
112113
return (
113114
<Radio
114115
key={`radio-group-value-options-${value}`}
115-
prefixCls={optionsPrefixCls}
116+
prefixCls={prefixCls.value}
116117
disabled={disabled || props.disabled}
117118
value={value}
118119
checked={stateValue.value === value}

components/radio/Radio.tsx

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import type { ExtractPropTypes, PropType } from 'vue';
2-
import { defineComponent, inject, ref } from 'vue';
2+
import { computed, defineComponent, ref } from 'vue';
33
import PropTypes from '../_util/vue-types';
44
import VcCheckbox from '../vc-checkbox/Checkbox';
55
import classNames from '../_util/classNames';
66
import useConfigInject from '../_util/hooks/useConfigInject';
7-
import type { RadioChangeEvent, RadioGroupContext } from './interface';
8-
import { useInjectFormItemContext } from '../form/FormItemContext';
7+
import type { RadioChangeEvent } from './interface';
8+
import { FormItemInputContext, useInjectFormItemContext } from '../form/FormItemContext';
99
import omit from '../_util/omit';
1010
import type { FocusEventHandler, MouseEventHandler } from '../_util/EventInterface';
11+
import { useInjectRadioGroupContext, useInjectRadioOptionTypeContext } from './context';
1112

1213
export const radioProps = () => ({
1314
prefixCls: String,
@@ -31,13 +32,19 @@ export type RadioProps = Partial<ExtractPropTypes<ReturnType<typeof radioProps>>
3132
export default defineComponent({
3233
name: 'ARadio',
3334
props: radioProps(),
34-
// emits: ['update:checked', 'update:value', 'change', 'blur', 'focus'],
3535
setup(props, { emit, expose, slots }) {
3636
const formItemContext = useInjectFormItemContext();
37+
const formItemInputContext = FormItemInputContext.useInject();
38+
const radioOptionTypeContext = useInjectRadioOptionTypeContext();
39+
const radioGroupContext = useInjectRadioGroupContext();
3740
const vcCheckbox = ref<HTMLElement>();
38-
const radioGroupContext = inject<RadioGroupContext>('radioGroupContext', undefined);
39-
const { prefixCls, direction } = useConfigInject('radio', props);
4041

42+
const { prefixCls: radioPrefixCls, direction } = useConfigInject('radio', props);
43+
const prefixCls = computed(() =>
44+
(radioGroupContext?.optionType.value || radioOptionTypeContext) === 'button'
45+
? `${radioPrefixCls.value}-button`
46+
: radioPrefixCls.value,
47+
);
4148
const focus = () => {
4249
vcCheckbox.value.focus();
4350
};
@@ -58,8 +65,8 @@ export default defineComponent({
5865

5966
const onChange = (e: RadioChangeEvent) => {
6067
emit('change', e);
61-
if (radioGroupContext && radioGroupContext.onRadioChange) {
62-
radioGroupContext.onRadioChange(e);
68+
if (radioGroupContext && radioGroupContext.onChange) {
69+
radioGroupContext.onChange(e);
6370
}
6471
};
6572

@@ -74,10 +81,10 @@ export default defineComponent({
7481
};
7582

7683
if (radioGroup) {
77-
rProps.name = radioGroup.props.name;
84+
rProps.name = radioGroup.name.value;
7885
rProps.onChange = onChange;
79-
rProps.checked = props.value === radioGroup.stateValue.value;
80-
rProps.disabled = props.disabled || radioGroup.props.disabled;
86+
rProps.checked = props.value === radioGroup.value.value;
87+
rProps.disabled = props.disabled || radioGroup.disabled.value;
8188
} else {
8289
rProps.onChange = handleChange;
8390
}
@@ -86,6 +93,7 @@ export default defineComponent({
8693
[`${prefixCls.value}-wrapper-checked`]: rProps.checked,
8794
[`${prefixCls.value}-wrapper-disabled`]: rProps.disabled,
8895
[`${prefixCls.value}-wrapper-rtl`]: direction.value === 'rtl',
96+
[`${prefixCls.value}-wrapper-in-form-item`]: formItemInputContext.isFormItemInput,
8997
});
9098

9199
return (

components/radio/RadioButton.tsx

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,20 @@
1-
import { defineComponent, inject } from 'vue';
2-
import type { RadioProps } from './Radio';
1+
import { defineComponent } from 'vue';
32
import Radio, { radioProps } from './Radio';
43
import useConfigInject from '../_util/hooks/useConfigInject';
5-
import type { RadioGroupContext } from './interface';
4+
import { useProvideRadioOptionTypeContext } from './context';
65

76
export default defineComponent({
87
name: 'ARadioButton',
98
props: radioProps(),
109
setup(props, { slots }) {
1110
const { prefixCls } = useConfigInject('radio-button', props);
12-
const radioGroupContext = inject<RadioGroupContext>('radioGroupContext', undefined);
13-
11+
useProvideRadioOptionTypeContext('button');
1412
return () => {
15-
const rProps: RadioProps = {
16-
...props,
17-
prefixCls: prefixCls.value,
18-
};
19-
20-
if (radioGroupContext) {
21-
rProps.onChange = radioGroupContext.onRadioChange;
22-
rProps.checked = rProps.value === radioGroupContext.stateValue.value;
23-
rProps.disabled = rProps.disabled || radioGroupContext.props.disabled;
24-
}
25-
return <Radio {...rProps}>{slots.default?.()}</Radio>;
13+
return (
14+
<Radio {...props} prefixCls={prefixCls.value} type="radio">
15+
{slots.default?.()}
16+
</Radio>
17+
);
2618
};
2719
},
2820
});

components/radio/context.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import type { InjectionKey } from 'vue';
2+
import { inject, provide } from 'vue';
3+
import type { RadioGroupContext, RadioOptionTypeContextProps } from './interface';
4+
5+
const radioGroupContextKey: InjectionKey<RadioGroupContext> = Symbol('radioGroupContextKey');
6+
export const useProvideRadioGroupContext = (props: RadioGroupContext) => {
7+
provide(radioGroupContextKey, props);
8+
};
9+
10+
export const useInjectRadioGroupContext = () => {
11+
return inject(radioGroupContextKey, undefined);
12+
};
13+
14+
const radioOptionTypeContextKey: InjectionKey<RadioOptionTypeContextProps> = Symbol(
15+
'radioOptionTypeContextKey',
16+
);
17+
export const useProvideRadioOptionTypeContext = (props: RadioOptionTypeContextProps) => {
18+
provide(radioOptionTypeContextKey, props);
19+
};
20+
21+
export const useInjectRadioOptionTypeContext = () => {
22+
return inject(radioOptionTypeContextKey, undefined);
23+
};

components/radio/interface.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,17 @@ export interface RadioChangeEvent {
1515
}
1616

1717
export interface RadioGroupContext {
18-
stateValue: Ref;
19-
props: RadioProps;
20-
onRadioChange: (e: RadioChangeEvent) => void;
18+
onChange: (e: RadioChangeEvent) => void;
19+
value: Ref<any>;
20+
disabled: Ref<boolean>;
21+
name: Ref<string>;
22+
/**
23+
* Control the appearance for Radio to display as button or not
24+
*
25+
* @default 'default'
26+
* @internal
27+
*/
28+
optionType?: Ref<RadioGroupOptionType>;
2129
}
30+
31+
export type RadioOptionTypeContextProps = RadioGroupOptionType;

components/radio/style/index.less

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,13 @@
4242
overflow: hidden;
4343
content: '\a0';
4444
}
45+
46+
&&-in-form-item {
47+
input[type='radio'] {
48+
width: 14px;
49+
height: 14px;
50+
}
51+
}
4552
}
4653

4754
.@{radio-prefix-cls} {

components/radio/style/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
import '../../style/index.less';
22
import './index.less';
3+
// deps-lint-skip: form

0 commit comments

Comments
 (0)