Skip to content
Snippets Groups Projects
RadioGroup.vue 1.42 KiB
Newer Older
  • Learn to ignore specific revisions
  • <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"
    
            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>