<script setup lang="ts">
import { CheckIcon } from '@lucide/vue'
import type { HTMLAttributes } from 'vue'
import { useVModel } from '@vueuse/core'
import { cn } from '@/lib/utils'

const props = defineProps<{
  modelValue?: boolean
  defaultValue?: boolean
  disabled?: boolean
  required?: boolean
  class?: HTMLAttributes['class']
}>()

const emit = defineEmits<{ 'update:modelValue': [value: boolean] }>()

const checked = useVModel(props, 'modelValue', emit, {
  passive: true,
  defaultValue: props.defaultValue ?? false,
})

function toggle() {
  if (props.disabled) return
  checked.value = !checked.value
}
</script>

<template>
  <button
    type="button"
    role="checkbox"
    data-slot="checkbox"
    :aria-checked="checked"
    :aria-required="required"
    :data-state="checked ? 'checked' : 'unchecked'"
    :disabled="disabled"
    :class="cn('border-input dark:bg-input/30 data-checked:bg-primary data-checked:text-primary-foreground dark:data-checked:bg-primary data-checked:border-primary aria-invalid:aria-checked:border-primary aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 flex size-4 items-center justify-center rounded-[4px] border transition-colors group-has-disabled/field:opacity-50 focus-visible:ring-3 aria-invalid:ring-3 peer relative shrink-0 outline-none after:absolute after:-inset-x-3 after:-inset-y-2 disabled:cursor-not-allowed disabled:opacity-50 hover:border-ring', props.class)"
    @click="toggle"
  >
    <Transition
      enter-active-class="animate-in fade-in-0 zoom-in-50 animation-duration-100"
      leave-active-class="animate-out fade-out-0 zoom-out-50 animation-duration-100"
    >
      <span
        v-if="checked"
        data-slot="checkbox-indicator"
        class="[&>svg]:size-3.5 grid place-content-center text-current"
      >
        <slot>
          <CheckIcon />
        </slot>
      </span>
    </Transition>
  </button>
</template>
