Newer
Older
<template>
<div class="tw-flex tw-items-center" role="radiogroup">
<template v-for="(choice, index) in normalizedChoices" :key="choice.value">
<span v-if="index !== 0" class="tw-self-stretch tw-w-px tw-bg-black/10" />
<button
type="button"
role="radio"
class="btn tw-p-2 tw-m-0 tw-rounded-none tw-justify-center first:tw-rounded-l last:tw-rounded-r tw-relative tw-ring-offset-2 focus:tw-outline-none focus-visible:tw-ring-2 focus-visible:tw-z-10"
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
tabindex="0"
:aria-checked="modelValue === choice.value"
:class="choice.value === modelValue ? 'tw-bg-aura-primary tw-text-white' : 'tw-bg-gray-100'"
@keyup.enter="modelValue = choice.value"
@click="modelValue = choice.value"
>
<slot name="icon" :value="choice.value" />
<span v-if="choice.label">{{ choice.label }}</span>
</button>
</template>
</div>
</template>
<script lang="ts" setup generic="T extends string">
import { computed } from 'vue'
defineOptions({ compatConfig: { MODE: 3 } })
type Choice<T> = { value: T; label?: string }
type Choices<T> = (Choice<T> | T)[]
const modelValue = defineModel({ required: true })
const props = defineProps<{
name: string
choices: Choices<T>
}>()
const normalizedChoices = computed(() => {
return props.choices.map((choice) => {
if (typeof choice === 'string') {
return { value: choice }
}
return choice
})
})
</script>