60 lines
1.5 KiB
Vue
60 lines
1.5 KiB
Vue
<script setup lang="ts">
|
|
import { computed } from 'vue'
|
|
import type { HTMLAttributes } from 'vue'
|
|
import { Check } from 'lucide-vue-next'
|
|
import { cn } from '@/lib/utils'
|
|
|
|
interface Props {
|
|
checked?: boolean
|
|
disabled?: boolean
|
|
required?: boolean
|
|
name?: string
|
|
value?: string
|
|
id?: string
|
|
class?: HTMLAttributes['class']
|
|
}
|
|
|
|
const props = withDefaults(defineProps<Props>(), {
|
|
checked: false,
|
|
disabled: false,
|
|
required: false,
|
|
})
|
|
|
|
const emit = defineEmits<{
|
|
'update:checked': [value: boolean]
|
|
}>()
|
|
|
|
const handleChange = (event: Event) => {
|
|
const target = event.target as HTMLInputElement
|
|
emit('update:checked', target.checked)
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="relative inline-flex items-center">
|
|
<input
|
|
type="checkbox"
|
|
:id="props.id"
|
|
:checked="props.checked"
|
|
:disabled="props.disabled"
|
|
:required="props.required"
|
|
:name="props.name"
|
|
:value="props.value"
|
|
@change="handleChange"
|
|
:class="
|
|
cn(
|
|
'peer h-4 w-4 shrink-0 rounded-sm border border-primary shadow focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 cursor-pointer',
|
|
'appearance-none bg-background',
|
|
'checked:bg-primary checked:border-primary',
|
|
props.class
|
|
)
|
|
"
|
|
/>
|
|
<Check
|
|
v-if="props.checked"
|
|
class="absolute h-4 w-4 text-primary-foreground pointer-events-none"
|
|
:class="{ 'opacity-50': props.disabled }"
|
|
/>
|
|
</div>
|
|
</template>
|