11<script lang="ts">
2- import type { AcceptableValue , RadioGroupRootEmits , RadioGroupRootProps } from ' reka-ui '
3- import type { VariantProps } from ' tailwind-variants '
2+ import type { AcceptableValue , ComponentConfig } from ' @/ui/types/utils '
3+ import type { RadioGroupRootEmits , RadioGroupRootProps } from ' reka-ui '
44import { useFormField } from ' @/ui/composables/useFormField'
55import theme from ' @/ui/theme/radio-group'
66import { get } from ' @/ui/utils/get'
77import { reactivePick } from ' @vueuse/shared'
8- import { Label , RadioGroupIndicator , RadioGroupRoot , RadioGroupItem as RRadioGroupItem , useForwardPropsEmits } from ' reka-ui'
8+ import { Label , RadioGroupIndicator , RadioGroupRoot , RadioGroupItem as RekaRadiopGroupItem , useForwardPropsEmits } from ' reka-ui'
99import { tv } from ' tailwind-variants'
1010import { computed , useId } from ' vue'
1111
12- const radioGroup = tv ( theme )
12+ type RadioGroup = ComponentConfig < typeof theme >
1313
14- type RadioGroupVariants = VariantProps <typeof radioGroup >
15-
16- export interface RadioGroupItem {
14+ export type RadioGroupValue = AcceptableValue
15+ export type RadioGroupItem = {
1716 label? : string
1817 description? : string
1918 disabled? : boolean
2019 value? : string
21- }
20+ [key : string ]: any
21+ } | RadioGroupValue
2222
23- export interface RadioGroupProps <T > extends Pick <RadioGroupRootProps , ' defaultValue' | ' disabled' | ' loop' | ' modelValue' | ' name' | ' required' > {
23+ export interface RadioGroupProps <T extends RadioGroupItem = RadioGroupItem > extends Pick <RadioGroupRootProps , ' defaultValue' | ' disabled' | ' loop' | ' modelValue' | ' name' | ' required' > {
2424 as? : any
2525 legend? : string
2626 valueKey? : string
2727 labelKey? : string
2828 descriptionKey? : string
2929 items? : T []
30- size? : RadioGroupVariants [' size' ]
31- color? : RadioGroupVariants [' color' ]
32- /**
33- * The orientation the radio buttons are laid out.
34- * @defaultValue 'vertical'
35- */
30+ size? : RadioGroup [' variants' ][' size' ]
31+ variant? : RadioGroup [' variants' ][' variant' ]
32+ color? : RadioGroup [' variants' ][' color' ]
3633 orientation? : RadioGroupRootProps [' orientation' ]
34+ indicator? : RadioGroup [' variants' ][' indicator' ]
3735 class? : any
38- ui? : Partial < typeof radioGroup . slots >
36+ ui? : RadioGroup [ ' slots' ]
3937}
4038
4139export type RadioGroupEmits = RadioGroupRootEmits & {
4240 change: [payload : Event ]
4341}
4442
45- type SlotProps <T > = (props : { item: T , modelValue? : AcceptableValue }) => any
43+ type SlotProps <T extends RadioGroupItem > = (props : { item: T & { id : string } , modelValue? : RadioGroupValue }) => any
4644
47- export interface RadioGroupSlots <T > {
45+ export interface RadioGroupSlots <T extends RadioGroupItem = RadioGroupItem > {
4846 legend: (props ? : object ) => any
4947 label: SlotProps <T >
5048 description: SlotProps <T >
5149}
5250 </script >
5351
54- <script setup lang="ts" generic =" T extends RadioGroupItem | AcceptableValue " >
52+ <script setup lang="ts" generic =" T extends RadioGroupItem " >
5553const props = withDefaults (defineProps <RadioGroupProps <T >>(), {
5654 valueKey: ' value' ,
5755 labelKey: ' label' ,
@@ -63,23 +61,33 @@ const slots = defineSlots<RadioGroupSlots<T>>()
6361
6462const rootProps = useForwardPropsEmits (reactivePick (props , ' as' , ' modelValue' , ' defaultValue' , ' orientation' , ' loop' , ' required' ), emits )
6563
66- const { color, name, size, id : _id, disabled, ariaAttrs } = useFormField <RadioGroupProps <T >>(props )
64+ const { color, name, size, id : _id, disabled, ariaAttrs } = useFormField <RadioGroupProps <T >>(props , { bind: false } )
6765const id = _id .value ?? useId ()
6866
69- const ui = computed (() => radioGroup ({
67+ const ui = computed (() => tv ( theme ) ({
7068 size: size .value ,
7169 color: color .value ,
7270 disabled: disabled .value ,
7371 required: props .required ,
7472 orientation: props .orientation ,
73+ variant: props .variant ,
74+ indicator: props .indicator ,
7575}))
7676
7777function normalizeItem(item : any ) {
78- if ([' string' , ' number' , ' boolean' ].includes (typeof item )) {
78+ if (item === null ) {
79+ return {
80+ id: ` ${id }:null ` ,
81+ value: undefined ,
82+ label: undefined ,
83+ }
84+ }
85+
86+ if (typeof item === ' string' || typeof item === ' number' ) {
7987 return {
8088 id: ` ${id }:${item } ` ,
81- value: item ,
82- label: item ,
89+ value: String ( item ) ,
90+ label: String ( item ) ,
8391 }
8492 }
8593
@@ -127,29 +135,32 @@ function onUpdate(value: any) {
127135 {{ legend }}
128136 </slot >
129137 </legend >
130- <div v-for =" item in normalizedItems" :key =" item.value" :class =" ui.item({ class: props.ui?.item })" >
138+
139+ <component :is =" variant === 'list' ? 'div' : Label" v-for =" item in normalizedItems" :key =" item.value" :class =" ui.item({ class: props.ui?.item })" >
131140 <div :class =" ui.container({ class: props.ui?.container })" >
132- <RRadioGroupItem
141+ <RekaRadiopGroupItem
133142 :id =" item.id"
134143 :value =" item.value"
135- :disabled =" disabled"
136- :class =" ui.base({ class: props.ui?.base })"
144+ :disabled =" item. disabled"
145+ :class =" ui.base({ class: props.ui?.base, disabled: item.disabled })"
137146 >
138147 <RadioGroupIndicator :class =" ui.indicator({ class: props.ui?.indicator })" />
139- </RRadioGroupItem >
148+ </RekaRadiopGroupItem >
140149 </div >
141150
142- <div :class =" ui.wrapper({ class: props.ui?.wrapper })" >
143- <Label :class =" ui.label({ class: props.ui?.label })" :for =" item.id" >
144- <slot name =" label" :item =" item" :model-value =" modelValue" >{{ item.label }}</slot >
145- </Label >
151+ <div v-if =" (item.label || !!slots.label) || (item.description || !!slots.description)" :class =" ui.wrapper({ class: props.ui?.wrapper })" >
152+ <component :is =" variant === 'list' ? Label : 'p'" v-if =" item.label || !!slots.label" :for =" item.id" :class =" ui.label({ class: props.ui?.label })" >
153+ <slot name =" label" :item =" item" :model-value =" (modelValue as RadioGroupValue)" >
154+ {{ item.label }}
155+ </slot >
156+ </component >
146157 <p v-if =" item.description || !!slots.description" :class =" ui.description({ class: props.ui?.description })" >
147- <slot name =" description" :item =" item" :model-value =" modelValue" >
158+ <slot name =" description" :item =" item" :model-value =" ( modelValue as RadioGroupValue) " >
148159 {{ item.description }}
149160 </slot >
150161 </p >
151162 </div >
152- </div >
163+ </component >
153164 </fieldset >
154165 </RadioGroupRoot >
155166</template >
0 commit comments