<template>
  <button
    type="button"
    class="vm-copy-btn"
    :class="[`is-${size}`]"
    :disabled="disabled || copying || !text"
    @click="copy"
  >
    <i :class="copying ? 'ri-loader-4-line is-spin' : icon" aria-hidden="true" />
    <span>{{ copying ? (copyingText ?? crudLabel('copying')) : (label ?? crudLabel('copy')) }}</span>
  </button>
</template>

<script setup lang="ts">
import { crudLabel } from '../style'
import { ref } from 'vue'

defineOptions({ name: 'vm-copy-btn' })

const props = withDefaults(
  defineProps<{
    text?: string
    label?: string
    copyingText?: string
    icon?: string
    size?: 'sm' | 'md'
    disabled?: boolean
  }>(),
  {
    label: undefined,
    copyingText: undefined,
    icon: 'ri-file-copy-line',
    size: 'md',
    disabled: false,
  },
)

const emit = defineEmits<{
  copied: []
  error: [e: unknown]
}>()

const copying = ref(false)

async function copy() {
  if (!props.text || copying.value) return
  copying.value = true
  try {
    await navigator.clipboard.writeText(props.text)
    emit('copied')
  } catch (e) {
    emit('error', e)
  } finally {
    copying.value = false
  }
}
</script>

<style lang="scss" scoped>
.vm-copy-btn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  border: none;
  border-radius: 8px;
  background: color-mix(in srgb, var(--brand) 10%, var(--card));
  color: var(--brand);
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;

  &:hover:not(:disabled) {
    background: color-mix(in srgb, var(--brand) 18%, var(--card));
  }

  &:disabled {
    opacity: 0.45;
    cursor: not-allowed;
  }

  &.is-md {
    height: 32px;
    padding: 0 12px;
  }

  &.is-sm {
    height: 28px;
    padding: 0 10px;
    font-size: 11px;
  }

  i.is-spin {
    animation: vm-copy-spin 0.8s linear infinite;
  }
}

@keyframes vm-copy-spin {
  to {
    transform: rotate(360deg);
  }
}
</style>
