mirror of
https://github.com/element-plus/element-plus.git
synced 2026-03-13 07:51:17 +08:00
feat(components): [radio-group] support options prop rendering (#21543)
* feat(components): [radio-group] support options * test: add test case * docs: tweak doc * Update basic-usage.vue * docs: tweak doc * Update packages/components/radio/src/radio-group.vue Co-authored-by: Noblet Ouways <91417411+Dsaquel@users.noreply.github.com> * chore: label prop * Update packages/components/radio/src/radio-group.ts Co-authored-by: Noblet Ouways <91417411+Dsaquel@users.noreply.github.com> * Update packages/components/radio/src/radio-group.vue Co-authored-by: btea <2356281422@qq.com> * refactor: use ts logic * Update form.md * Update message.ts * refactor: fix effect lost * refactor: use template logic and update version * Update radio-group.ts * Update options.vue * Update options.vue * refactor: rename props and support additional attributes and render * chore: default key * chore: use optionProps * chore: fix build error * chore: fix build error * chore: fix build error * chore: fix build error * chore: fix build error * Update radio-group.vue * Update basic.vue * refactor: refer checkbox * Update pnpm-lock.yaml * Update pnpm-workspace.yaml * Update package.json * Update package.json * chore: ts error * Update radio-group.ts * Update radio-group.ts * refactor: add more attr support and update version * refactor: props consistent with select * Update radio.md * Update packages/components/radio/src/radio-group.vue Co-authored-by: kooriookami <38392315+kooriookami@users.noreply.github.com> * Update packages/components/radio/src/radio-group.vue Co-authored-by: Noblet Ouways <91417411+Dsaquel@users.noreply.github.com> * chore: type with single line * chore: fix build error * chore: delete radioRenderer testcase --------- Co-authored-by: Noblet Ouways <91417411+Dsaquel@users.noreply.github.com> Co-authored-by: btea <2356281422@qq.com> Co-authored-by: kooriookami <38392315+kooriookami@users.noreply.github.com>
This commit is contained in:
@@ -61,6 +61,14 @@ radio/radio-button-group
|
||||
|
||||
:::
|
||||
|
||||
## Options attribute ^(2.11.2)
|
||||
|
||||
:::demo Shortcut from basic `el-radio-group` usage. You can customize the alias of the `options` through the `props` attribute.
|
||||
|
||||
radio/options
|
||||
|
||||
:::
|
||||
|
||||
## Button style
|
||||
|
||||
Radio with button styles.
|
||||
@@ -119,18 +127,20 @@ radio/with-borders
|
||||
|
||||
### RadioGroup Attributes
|
||||
|
||||
| Name | Description | Type | Default |
|
||||
| --------------------------- | ------------------------------------------------- | ---------------------------------- | ------- |
|
||||
| model-value / v-model | binding value | ^[string] / ^[number] / ^[boolean] | — |
|
||||
| size | the size of radio buttons or bordered radios | ^[string] | default |
|
||||
| disabled | whether the nesting radios are disabled | ^[boolean] | false |
|
||||
| validate-event | whether to trigger form validation | ^[boolean] | true |
|
||||
| text-color | font color when button is active | ^[string] | #ffffff |
|
||||
| fill | border and background color when button is active | ^[string] | #409eff |
|
||||
| aria-label ^(a11y) ^(2.7.2) | same as `aria-label` in RadioGroup | ^[string] | — |
|
||||
| name | native `name` attribute | ^[string] | — |
|
||||
| id | native `id` attribute | ^[string] | — |
|
||||
| label ^(a11y) ^(deprecated) | same as `aria-label` in RadioGroup | ^[string] | — |
|
||||
| Name | Description | Type | Default |
|
||||
| --------------------------- | ---------------------------------------------------------------------------------------------- | ---------------------------------------------------------------- | ------- |
|
||||
| model-value / v-model | binding value | ^[string] / ^[number] / ^[boolean] | — |
|
||||
| size | the size of radio buttons or bordered radios | ^[string] | default |
|
||||
| disabled | whether the nesting radios are disabled | ^[boolean] | false |
|
||||
| validate-event | whether to trigger form validation | ^[boolean] | true |
|
||||
| text-color | font color when button is active | ^[string] | #ffffff |
|
||||
| fill | border and background color when button is active | ^[string] | #409eff |
|
||||
| aria-label ^(a11y) ^(2.7.2) | same as `aria-label` in RadioGroup | ^[string] | — |
|
||||
| name | native `name` attribute | ^[string] | — |
|
||||
| id | native `id` attribute | ^[string] | — |
|
||||
| label ^(a11y) ^(deprecated) | same as `aria-label` in RadioGroup | ^[string] | — |
|
||||
| options ^(2.11.2) | data of the options, the key of `value` and `label` and `disabled` can be customize by `props` | ^[array]`Array<{[key: string]: any}>` | — |
|
||||
| props ^(2.11.2) | configuration options | ^[object]`{ value?: string, label?: string, disabled?: boolean}` |
|
||||
|
||||
### RadioGroup Events
|
||||
|
||||
|
||||
24
docs/examples/radio/options.vue
Normal file
24
docs/examples/radio/options.vue
Normal file
@@ -0,0 +1,24 @@
|
||||
<template>
|
||||
<el-radio-group v-model="radio" :options="options" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const radio = ref(3)
|
||||
|
||||
const options = [
|
||||
{
|
||||
value: 3,
|
||||
label: 'Option A',
|
||||
},
|
||||
{
|
||||
value: 6,
|
||||
label: 'Option B',
|
||||
},
|
||||
{
|
||||
value: 9,
|
||||
label: 'Option C',
|
||||
},
|
||||
]
|
||||
</script>
|
||||
@@ -205,6 +205,77 @@ describe('Radio group', () => {
|
||||
expect(radio.value).toEqual(3)
|
||||
expect(radio1.classes()).toContain('is-active')
|
||||
})
|
||||
|
||||
it('renders el-radio-group using default option fields', async () => {
|
||||
const radio = ref(3)
|
||||
const options = [
|
||||
{
|
||||
value: 3,
|
||||
label: 'Option A',
|
||||
},
|
||||
{
|
||||
value: 6,
|
||||
label: 'Option B',
|
||||
},
|
||||
{
|
||||
value: 9,
|
||||
label: 'Option C',
|
||||
},
|
||||
]
|
||||
const wrapper = mount(() => (
|
||||
<RadioGroup v-model={radio.value} options={options} />
|
||||
))
|
||||
await nextTick()
|
||||
const [radio1, radio2] = wrapper.findAll('.el-radio')
|
||||
expect(radio1.classes()).toContain('is-checked')
|
||||
await radio2.trigger('click')
|
||||
expect(radio2.classes()).toContain('is-checked')
|
||||
expect(radio.value).toEqual(6)
|
||||
})
|
||||
|
||||
it('renders el-radio-group with custom option fields', async () => {
|
||||
const radio = ref(3)
|
||||
const options = [
|
||||
{
|
||||
id: 3,
|
||||
label: 'Option A',
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
label: 'Option B',
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
label: 'Option C',
|
||||
},
|
||||
]
|
||||
const wrapper = mount(() => (
|
||||
<RadioGroup
|
||||
v-model={radio.value}
|
||||
options={options}
|
||||
props={{ value: 'id' }}
|
||||
/>
|
||||
))
|
||||
await nextTick()
|
||||
const [radio1, radio2] = wrapper.findAll('.el-radio')
|
||||
expect(radio1.classes()).toContain('is-checked')
|
||||
await radio2.trigger('click')
|
||||
expect(radio2.classes()).toContain('is-checked')
|
||||
expect(radio.value).toEqual(6)
|
||||
})
|
||||
|
||||
it('passes custom attributes from options to el-radio', () => {
|
||||
const options = [
|
||||
{ value: 'a', label: 'A', 'data-test': 'custom-attr-1' },
|
||||
{ value: 'b', label: 'B', 'data-test': 'custom-attr-2' },
|
||||
]
|
||||
const wrapper = mount(RadioGroup, {
|
||||
props: { options },
|
||||
})
|
||||
const [radio1, radio2] = wrapper.findAll('.el-radio')
|
||||
expect(radio1.attributes('data-test')).toBe('custom-attr-1')
|
||||
expect(radio2.attributes('data-test')).toBe('custom-attr-2')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Radio Button', () => {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { buildProps } from '@element-plus/utils'
|
||||
import { buildProps, definePropType } from '@element-plus/utils'
|
||||
import { useAriaProps, useSizeProp } from '@element-plus/hooks'
|
||||
import { radioEmits } from './radio'
|
||||
|
||||
import type { RadioPropsPublic } from './radio'
|
||||
import type { ExtractPropTypes, __ExtractPublicPropTypes } from 'vue'
|
||||
import type RadioGroup from './radio-group.vue'
|
||||
|
||||
@@ -56,6 +57,13 @@ export const radioGroupProps = buildProps({
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
options: {
|
||||
type: definePropType<radioOption[]>(Array),
|
||||
},
|
||||
props: {
|
||||
type: definePropType<radioOptionProp>(Object),
|
||||
default: () => radioDefaultProps,
|
||||
},
|
||||
...useAriaProps(['ariaLabel']),
|
||||
} as const)
|
||||
export type RadioGroupProps = ExtractPropTypes<typeof radioGroupProps>
|
||||
@@ -66,3 +74,16 @@ export type RadioGroupPropsPublic = __ExtractPublicPropTypes<
|
||||
export const radioGroupEmits = radioEmits
|
||||
export type RadioGroupEmits = typeof radioGroupEmits
|
||||
export type RadioGroupInstance = InstanceType<typeof RadioGroup> & unknown
|
||||
|
||||
export type radioOption = RadioPropsPublic & Record<string, any>
|
||||
|
||||
export const radioDefaultProps: Required<radioOptionProp> = {
|
||||
label: 'label',
|
||||
value: 'value',
|
||||
disabled: 'disabled',
|
||||
}
|
||||
export type radioOptionProp = {
|
||||
value?: string
|
||||
label?: string
|
||||
disabled?: string
|
||||
}
|
||||
|
||||
@@ -7,7 +7,13 @@
|
||||
:aria-label="!isLabeledByFormItem ? ariaLabel || 'radio-group' : undefined"
|
||||
:aria-labelledby="isLabeledByFormItem ? formItem!.labelId : undefined"
|
||||
>
|
||||
<slot />
|
||||
<slot>
|
||||
<el-radio
|
||||
v-for="(item, index) in props.options"
|
||||
:key="index"
|
||||
v-bind="getOptionProps(item)"
|
||||
/>
|
||||
</slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -26,9 +32,14 @@ import { useFormItem, useFormItemInputId } from '@element-plus/components/form'
|
||||
import { CHANGE_EVENT, UPDATE_MODEL_EVENT } from '@element-plus/constants'
|
||||
import { useId, useNamespace } from '@element-plus/hooks'
|
||||
import { debugWarn } from '@element-plus/utils'
|
||||
import { radioGroupEmits, radioGroupProps } from './radio-group'
|
||||
import {
|
||||
radioDefaultProps,
|
||||
radioGroupEmits,
|
||||
radioGroupProps,
|
||||
} from './radio-group'
|
||||
import { radioGroupKey } from './constants'
|
||||
import { isEqual } from 'lodash-unified'
|
||||
import ElRadio from './radio.vue'
|
||||
|
||||
import type { RadioGroupProps } from './radio-group'
|
||||
|
||||
@@ -65,6 +76,19 @@ const name = computed(() => {
|
||||
return props.name || radioId.value
|
||||
})
|
||||
|
||||
const aliasProps = computed(() => ({
|
||||
...radioDefaultProps,
|
||||
...props.props,
|
||||
}))
|
||||
const getOptionProps = (option: Record<string, any>) => {
|
||||
const base = {
|
||||
label: option[aliasProps.value.label],
|
||||
value: option[aliasProps.value.value],
|
||||
disabled: option[aliasProps.value.disabled],
|
||||
}
|
||||
return { ...option, ...base }
|
||||
}
|
||||
|
||||
provide(
|
||||
radioGroupKey,
|
||||
reactive({
|
||||
|
||||
Reference in New Issue
Block a user