mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-28 19:00:35 +01:00
feat(RadioGroup): new component (#730)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
This commit is contained in:
@@ -24,7 +24,7 @@ const name = `U${upperFirst(camelName)}`
|
|||||||
const preset = config[camelName]
|
const preset = config[camelName]
|
||||||
|
|
||||||
const { data: ast } = await useAsyncData(`${name}-preset`, () => transformContent('content:_markdown.md', `
|
const { data: ast } = await useAsyncData(`${name}-preset`, () => transformContent('content:_markdown.md', `
|
||||||
\`\`\`json
|
\`\`\`json [${name}.vue]
|
||||||
${JSON.stringify(preset, null, 2)}
|
${JSON.stringify(preset, null, 2)}
|
||||||
\`\`\`\
|
\`\`\`\
|
||||||
`, {
|
`, {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ const state = reactive({
|
|||||||
checkbox: undefined,
|
checkbox: undefined,
|
||||||
toggle: undefined,
|
toggle: undefined,
|
||||||
radio: undefined,
|
radio: undefined,
|
||||||
|
radioGroup: undefined,
|
||||||
switch: undefined,
|
switch: undefined,
|
||||||
range: undefined
|
range: undefined
|
||||||
})
|
})
|
||||||
@@ -38,6 +39,9 @@ const schema = z.object({
|
|||||||
radio: z.string().refine(value => value === 'option-2', {
|
radio: z.string().refine(value => value === 'option-2', {
|
||||||
message: 'Select Option 2'
|
message: 'Select Option 2'
|
||||||
}),
|
}),
|
||||||
|
radioGroup: z.string().refine(value => value === 'option-2', {
|
||||||
|
message: 'Select Option 2'
|
||||||
|
}),
|
||||||
range: z.number().max(20, { message: 'Must be less than 20' })
|
range: z.number().max(20, { message: 'Must be less than 20' })
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -77,6 +81,10 @@ async function onSubmit (event: FormSubmitEvent<Schema>) {
|
|||||||
<UCheckbox v-model="state.checkbox" label="Check me" />
|
<UCheckbox v-model="state.checkbox" label="Check me" />
|
||||||
</UFormGroup>
|
</UFormGroup>
|
||||||
|
|
||||||
|
<UFormGroup name="radioGroup" label="Radio Group">
|
||||||
|
<URadioGroup v-model="state.radioGroup" :options="options" />
|
||||||
|
</UFormGroup>
|
||||||
|
|
||||||
<UFormGroup name="radio" label="Radio">
|
<UFormGroup name="radio" label="Radio">
|
||||||
<URadio v-for="option in options" :key="option.value" v-model="state.radio" v-bind="option">
|
<URadio v-for="option in options" :key="option.value" v-model="state.radio" v-bind="option">
|
||||||
{{ option.label }}
|
{{ option.label }}
|
||||||
|
|||||||
@@ -1,23 +1,15 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
const methods = [{
|
const methods = [
|
||||||
name: 'email',
|
{ value: 'email', label: 'Email' },
|
||||||
value: 'email',
|
{ value: 'sms', label: 'Phone (SMS)' },
|
||||||
label: 'Email'
|
{ value: 'push', label: 'Push notification' }
|
||||||
}, {
|
]
|
||||||
name: 'sms',
|
|
||||||
value: 'sms',
|
|
||||||
label: 'Phone (SMS)'
|
|
||||||
}, {
|
|
||||||
name: 'push',
|
|
||||||
value: 'push',
|
|
||||||
label: 'Push notification'
|
|
||||||
}]
|
|
||||||
|
|
||||||
const selected = ref('sms')
|
const selected = ref('sms')
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="space-y-1">
|
<div class="space-y-1">
|
||||||
<URadio v-for="method of methods" :key="method.name" v-model="selected" v-bind="method" />
|
<URadio v-for="method of methods" :key="method.value" v-model="selected" v-bind="method" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
18
docs/components/content/examples/RadioGroupExample.vue
Normal file
18
docs/components/content/examples/RadioGroupExample.vue
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<script setup>
|
||||||
|
const options = [{
|
||||||
|
value: 'email',
|
||||||
|
label: 'Email'
|
||||||
|
}, {
|
||||||
|
value: 'sms',
|
||||||
|
label: 'Phone (SMS)'
|
||||||
|
}, {
|
||||||
|
value: 'push',
|
||||||
|
label: 'Push notification'
|
||||||
|
}]
|
||||||
|
|
||||||
|
const selected = ref('sms')
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<URadioGroup v-model="selected" legend="Choose something" :options="options" />
|
||||||
|
</template>
|
||||||
20
docs/components/content/examples/RadioGroupLabelExample.vue
Normal file
20
docs/components/content/examples/RadioGroupLabelExample.vue
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<script setup>
|
||||||
|
const options = [
|
||||||
|
{ value: 'email', label: 'Email', icon: 'i-heroicons-at-symbol' },
|
||||||
|
{ value: 'sms', label: 'Phone (SMS)', icon: 'i-heroicons-phone' },
|
||||||
|
{ value: 'push', label: 'Push notification', icon: 'i-heroicons-bell' }
|
||||||
|
]
|
||||||
|
|
||||||
|
const selected = ref('sms')
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<URadioGroup v-model="selected" :options="options">
|
||||||
|
<template #label="{ option }">
|
||||||
|
<p class="italic">
|
||||||
|
<UIcon :name="option.icon" />
|
||||||
|
{{ option.label }}
|
||||||
|
</p>
|
||||||
|
</template>
|
||||||
|
</URadioGroup>
|
||||||
|
</template>
|
||||||
@@ -38,7 +38,7 @@ props:
|
|||||||
|
|
||||||
### Required
|
### Required
|
||||||
|
|
||||||
Use the `required` prop to display a red star next to the label.
|
Use the `required` prop to display a red star next to the label of the Checkbox.
|
||||||
|
|
||||||
::component-card
|
::component-card
|
||||||
---
|
---
|
||||||
|
|||||||
156
docs/content/3.forms/6.radio-group.md
Normal file
156
docs/content/3.forms/6.radio-group.md
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
---
|
||||||
|
title: RadioGroup
|
||||||
|
description: Display a set of radio buttons.
|
||||||
|
navigation:
|
||||||
|
badge: New
|
||||||
|
links:
|
||||||
|
- label: GitHub
|
||||||
|
icon: i-simple-icons-github
|
||||||
|
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/forms/RadioGroup.vue
|
||||||
|
---
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Use a `v-model` to make the RadioGroup reactive.
|
||||||
|
|
||||||
|
:component-example{component="radio-group-example"}
|
||||||
|
|
||||||
|
Alternatively, you can use individual Radio components:
|
||||||
|
|
||||||
|
:component-example{component="radio-example"}
|
||||||
|
|
||||||
|
### Legend
|
||||||
|
|
||||||
|
Use the `legend` prop to add a legend to the RadioGroup.
|
||||||
|
|
||||||
|
::component-card
|
||||||
|
---
|
||||||
|
baseProps:
|
||||||
|
options: [{ value: 'email', label: 'Email' }, { value: 'sms', label: 'Phone (SMS)' }, { value: 'push', label: 'Push notification' }]
|
||||||
|
modelValue: 'sms'
|
||||||
|
props:
|
||||||
|
legend: 'Legend'
|
||||||
|
---
|
||||||
|
::
|
||||||
|
|
||||||
|
### Style
|
||||||
|
|
||||||
|
Use the `color` prop to change the style of the RadioGroup.
|
||||||
|
|
||||||
|
::component-card
|
||||||
|
---
|
||||||
|
baseProps:
|
||||||
|
options: [{ value: 'email', label: 'Email' }, { value: 'sms', label: 'Phone (SMS)' }, { value: 'push', label: 'Push notification' }]
|
||||||
|
modelValue: 'sms'
|
||||||
|
props:
|
||||||
|
color: 'primary'
|
||||||
|
---
|
||||||
|
::
|
||||||
|
|
||||||
|
::callout{icon="i-heroicons-light-bulb"}
|
||||||
|
This prop also work on the Radio component.
|
||||||
|
::
|
||||||
|
|
||||||
|
### Disabled
|
||||||
|
|
||||||
|
Use the `disabled` prop to disable the RadioGroup.
|
||||||
|
|
||||||
|
::component-card
|
||||||
|
---
|
||||||
|
baseProps:
|
||||||
|
options: [{ value: 'email', label: 'Email' }, { value: 'sms', label: 'Phone (SMS)' }, { value: 'push', label: 'Push notification' }]
|
||||||
|
modelValue: 'sms'
|
||||||
|
props:
|
||||||
|
disabled: true
|
||||||
|
---
|
||||||
|
::
|
||||||
|
|
||||||
|
::callout{icon="i-heroicons-light-bulb"}
|
||||||
|
This prop also work on the Radio component.
|
||||||
|
::
|
||||||
|
|
||||||
|
### Label
|
||||||
|
|
||||||
|
Use the `label` prop to display a label on the right of the Radio.
|
||||||
|
|
||||||
|
::component-card{slug="radio"}
|
||||||
|
---
|
||||||
|
props:
|
||||||
|
label: 'Label'
|
||||||
|
---
|
||||||
|
::
|
||||||
|
|
||||||
|
### Required
|
||||||
|
|
||||||
|
Use the `required` prop to display a red star next to the label of the Radio.
|
||||||
|
|
||||||
|
::component-card{slug="radio"}
|
||||||
|
---
|
||||||
|
props:
|
||||||
|
label: 'Label'
|
||||||
|
required: true
|
||||||
|
---
|
||||||
|
::
|
||||||
|
|
||||||
|
### Help
|
||||||
|
|
||||||
|
Use the `help` prop to display some text under the Radio.
|
||||||
|
|
||||||
|
::component-card{slug="radio"}
|
||||||
|
---
|
||||||
|
props:
|
||||||
|
label: 'Label'
|
||||||
|
help: 'Please choose one'
|
||||||
|
---
|
||||||
|
::
|
||||||
|
|
||||||
|
## Slots
|
||||||
|
|
||||||
|
### `label`
|
||||||
|
|
||||||
|
Use the `#label` slot to override the label of each option.
|
||||||
|
|
||||||
|
:component-example{component="radio-group-label-example"}
|
||||||
|
|
||||||
|
Alternatively, you can do the same with individual Radio:
|
||||||
|
|
||||||
|
::component-card{slug="radio"}
|
||||||
|
---
|
||||||
|
slots:
|
||||||
|
label: <span class="italic">Label</span>
|
||||||
|
---
|
||||||
|
|
||||||
|
#label
|
||||||
|
[Label]{.italic}
|
||||||
|
::
|
||||||
|
|
||||||
|
### `legend`
|
||||||
|
|
||||||
|
Use the `#legend` slot to override the content of the legend.
|
||||||
|
|
||||||
|
::component-card
|
||||||
|
---
|
||||||
|
baseProps:
|
||||||
|
options: [{ value: 'email', label: 'Email' }, { value: 'sms', label: 'Phone (SMS)' }, { value: 'push', label: 'Push notification' }]
|
||||||
|
modelValue: 'sms'
|
||||||
|
slots:
|
||||||
|
legend: <span class="italic">Legend</span>
|
||||||
|
---
|
||||||
|
|
||||||
|
#legend
|
||||||
|
[Legend]{.italic}
|
||||||
|
::
|
||||||
|
|
||||||
|
## Props
|
||||||
|
|
||||||
|
:component-props
|
||||||
|
|
||||||
|
:u-divider{label="Radio" type="dashed" class="my-12"}
|
||||||
|
|
||||||
|
:component-props{slug="radio"}
|
||||||
|
|
||||||
|
## Preset
|
||||||
|
|
||||||
|
:component-preset
|
||||||
|
|
||||||
|
:component-preset{slug="radio"}
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
---
|
|
||||||
description: Display a radio field.
|
|
||||||
links:
|
|
||||||
- label: GitHub
|
|
||||||
icon: i-simple-icons-github
|
|
||||||
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/forms/Radio.vue
|
|
||||||
---
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
Use a `v-model` to make the Radio reactive.
|
|
||||||
|
|
||||||
:component-example{component="radio-example"}
|
|
||||||
|
|
||||||
### Label
|
|
||||||
|
|
||||||
Use the `label` prop to display a label on the right.
|
|
||||||
|
|
||||||
::component-card
|
|
||||||
---
|
|
||||||
props:
|
|
||||||
label: 'Label'
|
|
||||||
---
|
|
||||||
::
|
|
||||||
|
|
||||||
### Style
|
|
||||||
|
|
||||||
Use the `color` prop to change the style of the Radio.
|
|
||||||
|
|
||||||
::component-card
|
|
||||||
---
|
|
||||||
baseProps:
|
|
||||||
label: 'Label'
|
|
||||||
props:
|
|
||||||
color: 'primary'
|
|
||||||
---
|
|
||||||
::
|
|
||||||
|
|
||||||
### Required
|
|
||||||
|
|
||||||
Use the `required` prop to display a red star next to the label.
|
|
||||||
|
|
||||||
::component-card
|
|
||||||
---
|
|
||||||
props:
|
|
||||||
label: 'Label'
|
|
||||||
required: true
|
|
||||||
---
|
|
||||||
::
|
|
||||||
|
|
||||||
### Help
|
|
||||||
|
|
||||||
Use the `help` prop to display some text under the Radio.
|
|
||||||
|
|
||||||
::component-card
|
|
||||||
---
|
|
||||||
props:
|
|
||||||
label: 'Label'
|
|
||||||
help: 'Please choose one'
|
|
||||||
---
|
|
||||||
::
|
|
||||||
|
|
||||||
### Disabled
|
|
||||||
|
|
||||||
Use the `disabled` prop to disable the Radio.
|
|
||||||
|
|
||||||
::component-card
|
|
||||||
---
|
|
||||||
baseProps:
|
|
||||||
label: 'Label'
|
|
||||||
props:
|
|
||||||
disabled: true
|
|
||||||
---
|
|
||||||
::
|
|
||||||
|
|
||||||
## Slots
|
|
||||||
|
|
||||||
### `label`
|
|
||||||
|
|
||||||
Use the `#label` slot to override the content of the label.
|
|
||||||
|
|
||||||
::component-card
|
|
||||||
---
|
|
||||||
slots:
|
|
||||||
label: <span class="italic">Label</span>
|
|
||||||
---
|
|
||||||
|
|
||||||
#label
|
|
||||||
[Label]{.italic}
|
|
||||||
::
|
|
||||||
|
|
||||||
## Props
|
|
||||||
|
|
||||||
:component-props
|
|
||||||
|
|
||||||
## Preset
|
|
||||||
|
|
||||||
:component-preset
|
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
<div :class="ui.wrapper">
|
<div :class="ui.wrapper">
|
||||||
<div class="flex items-center h-5">
|
<div class="flex items-center h-5">
|
||||||
<input
|
<input
|
||||||
:id="inputId"
|
:id="id"
|
||||||
v-model="pick"
|
v-model="pick"
|
||||||
:name="name"
|
:name="name"
|
||||||
:required="required"
|
:required="required"
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="label || $slots.label" class="ms-3 text-sm">
|
<div v-if="label || $slots.label" class="ms-3 text-sm">
|
||||||
<label :for="inputId" :class="ui.label">
|
<label :for="id" :class="ui.label">
|
||||||
<slot name="label">{{ label }}</slot>
|
<slot name="label">{{ label }}</slot>
|
||||||
<span v-if="required" :class="ui.required">*</span>
|
<span v-if="required" :class="ui.required">*</span>
|
||||||
</label>
|
</label>
|
||||||
@@ -27,11 +27,10 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { computed, toRef, defineComponent } from 'vue'
|
import { computed, defineComponent, inject, toRef } from 'vue'
|
||||||
import type { PropType } from 'vue'
|
import type { PropType } from 'vue'
|
||||||
import { twMerge, twJoin } from 'tailwind-merge'
|
import { twMerge, twJoin } from 'tailwind-merge'
|
||||||
import { useUI } from '../../composables/useUI'
|
import { useUI } from '../../composables/useUI'
|
||||||
import { useFormGroup } from '../../composables/useFormGroup'
|
|
||||||
import { mergeConfig } from '../../utils'
|
import { mergeConfig } from '../../utils'
|
||||||
import type { Strategy } from '../../types'
|
import type { Strategy } from '../../types'
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
@@ -39,6 +38,7 @@ import appConfig from '#build/app.config'
|
|||||||
import { radio } from '#ui/ui.config'
|
import { radio } from '#ui/ui.config'
|
||||||
import colors from '#ui-colors'
|
import colors from '#ui-colors'
|
||||||
import { uid } from '../../utils/uid'
|
import { uid } from '../../utils/uid'
|
||||||
|
import { useFormGroup } from '../../composables/useFormGroup'
|
||||||
|
|
||||||
const config = mergeConfig<typeof radio>(appConfig.ui.strategy, appConfig.ui.radio, radio)
|
const config = mergeConfig<typeof radio>(appConfig.ui.strategy, appConfig.ui.radio, radio)
|
||||||
|
|
||||||
@@ -98,11 +98,12 @@ export default defineComponent({
|
|||||||
default: undefined
|
default: undefined
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emits: ['update:modelValue'],
|
emits: ['update:modelValue', 'change'],
|
||||||
setup (props, { emit }) {
|
setup (props, { emit }) {
|
||||||
const { ui, attrs } = useUI('radio', toRef(props, 'ui'), config, toRef(props, 'class'))
|
const { ui, attrs } = useUI('radio', toRef(props, 'ui'), config, toRef(props, 'class'))
|
||||||
|
|
||||||
const { emitFormChange, color, name, inputId } = useFormGroup(props)
|
const radioGroup = inject('radio-group', null)
|
||||||
|
const { emitFormChange, color, name } = radioGroup ?? useFormGroup(props, config)
|
||||||
|
|
||||||
const pick = computed({
|
const pick = computed({
|
||||||
get () {
|
get () {
|
||||||
@@ -110,7 +111,9 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
set (value) {
|
set (value) {
|
||||||
emit('update:modelValue', value)
|
emit('update:modelValue', value)
|
||||||
if (value) {
|
emit('change', value)
|
||||||
|
|
||||||
|
if (!radioGroup) {
|
||||||
emitFormChange()
|
emitFormChange()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -129,7 +132,6 @@ export default defineComponent({
|
|||||||
return {
|
return {
|
||||||
// eslint-disable-next-line vue/no-dupe-keys
|
// eslint-disable-next-line vue/no-dupe-keys
|
||||||
ui,
|
ui,
|
||||||
inputId,
|
|
||||||
attrs,
|
attrs,
|
||||||
pick,
|
pick,
|
||||||
// eslint-disable-next-line vue/no-dupe-keys
|
// eslint-disable-next-line vue/no-dupe-keys
|
||||||
|
|||||||
141
src/runtime/components/forms/RadioGroup.vue
Normal file
141
src/runtime/components/forms/RadioGroup.vue
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
<template>
|
||||||
|
<div :class="ui.wrapper">
|
||||||
|
<fieldset v-bind="attrs">
|
||||||
|
<legend v-if="legend || $slots.legend" :class="ui.legend">
|
||||||
|
<slot name="legend">
|
||||||
|
{{ legend }}
|
||||||
|
</slot>
|
||||||
|
</legend>
|
||||||
|
<URadio
|
||||||
|
v-for="option in normalizedOptions"
|
||||||
|
:key="option.value"
|
||||||
|
:label="option.label"
|
||||||
|
:model-value="modelValue"
|
||||||
|
:value="option.value"
|
||||||
|
:disabled="disabled"
|
||||||
|
@change="onUpdate(option.value)"
|
||||||
|
>
|
||||||
|
<template #label>
|
||||||
|
<slot name="label" v-bind="{ option }" />
|
||||||
|
</template>
|
||||||
|
</URadio>
|
||||||
|
</fieldset>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import URadio from './Radio.vue'
|
||||||
|
import { computed, defineComponent, provide, toRef } from 'vue'
|
||||||
|
import type { PropType } from 'vue'
|
||||||
|
import { useUI } from '../../composables/useUI'
|
||||||
|
import { useFormGroup } from '../../composables/useFormGroup'
|
||||||
|
import { mergeConfig, get } from '../../utils'
|
||||||
|
import type { Strategy } from '../../types'
|
||||||
|
// @ts-expect-error
|
||||||
|
import appConfig from '#build/app.config'
|
||||||
|
import { radioGroup } from '#ui/ui.config'
|
||||||
|
import colors from '#ui-colors'
|
||||||
|
|
||||||
|
const config = mergeConfig<typeof radioGroup>(appConfig.ui.strategy, appConfig.ui.select, radioGroup)
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
components: {
|
||||||
|
URadio
|
||||||
|
},
|
||||||
|
inheritAttrs: false,
|
||||||
|
props: {
|
||||||
|
modelValue: {
|
||||||
|
type: [String, Number, Object],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
type: String,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
|
optionAttribute: {
|
||||||
|
type: String,
|
||||||
|
default: 'label'
|
||||||
|
},
|
||||||
|
valueAttribute: {
|
||||||
|
type: String,
|
||||||
|
default: 'value'
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
color: {
|
||||||
|
type: String as PropType<typeof colors[number]>,
|
||||||
|
default: () => config.default.color,
|
||||||
|
validator (value: string) {
|
||||||
|
return appConfig.ui.colors.includes(value)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
class: {
|
||||||
|
type: [String, Object, Array] as PropType<any>,
|
||||||
|
default: undefined
|
||||||
|
},
|
||||||
|
ui: {
|
||||||
|
type: Object as PropType<Partial<typeof config & { strategy?: Strategy }>>,
|
||||||
|
default: undefined
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: ['update:modelValue', 'change'],
|
||||||
|
setup (props, { emit }) {
|
||||||
|
const { ui, attrs } = useUI('radioGroup', toRef(props, 'ui'), config, toRef(props, 'class'))
|
||||||
|
|
||||||
|
const { emitFormChange, color, name } = useFormGroup(props, config)
|
||||||
|
provide('radio-group', { color, name })
|
||||||
|
|
||||||
|
const onUpdate = (value: any) => {
|
||||||
|
emit('update:modelValue', value)
|
||||||
|
emit('change', value)
|
||||||
|
emitFormChange()
|
||||||
|
}
|
||||||
|
|
||||||
|
const guessOptionValue = (option: any) => {
|
||||||
|
return get(option, props.valueAttribute, get(option, props.optionAttribute))
|
||||||
|
}
|
||||||
|
|
||||||
|
const guessOptionText = (option: any) => {
|
||||||
|
return get(option, props.optionAttribute, get(option, props.valueAttribute))
|
||||||
|
}
|
||||||
|
|
||||||
|
const normalizeOption = (option: any) => {
|
||||||
|
if (['string', 'number', 'boolean'].includes(typeof option)) {
|
||||||
|
return {
|
||||||
|
value: option,
|
||||||
|
label: option
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...option,
|
||||||
|
value: guessOptionValue(option),
|
||||||
|
label: guessOptionText(option)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const normalizedOptions = computed(() => {
|
||||||
|
return props.options.map(option => normalizeOption(option))
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
// eslint-disable-next-line vue/no-dupe-keys
|
||||||
|
ui,
|
||||||
|
attrs,
|
||||||
|
normalizedOptions,
|
||||||
|
// eslint-disable-next-line vue/no-dupe-keys
|
||||||
|
onUpdate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@@ -598,6 +598,14 @@ export const selectMenu = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const radioGroup = {
|
||||||
|
wrapper: 'relative flex items-start',
|
||||||
|
legend: 'text-sm font-medium text-gray-700 dark:text-gray-200 mb-1',
|
||||||
|
default: {
|
||||||
|
color: 'primary'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const radio = {
|
export const radio = {
|
||||||
wrapper: 'relative flex items-start',
|
wrapper: 'relative flex items-start',
|
||||||
base: 'h-4 w-4 dark:checked:bg-current dark:checked:border-transparent disabled:opacity-50 disabled:cursor-not-allowed focus:ring-0 focus:ring-transparent focus:ring-offset-transparent',
|
base: 'h-4 w-4 dark:checked:bg-current dark:checked:border-transparent disabled:opacity-50 disabled:cursor-not-allowed focus:ring-0 focus:ring-transparent focus:ring-offset-transparent',
|
||||||
|
|||||||
Reference in New Issue
Block a user