{
  "name": "image",
  "dependencies": [],
  "registryDependencies": [],
  "files": [
    {
      "name": "Image.vue",
      "content": "<script setup lang=\"ts\">\nimport { nextTick, ref, watch } from 'vue';\nimport { useForwardProps } from 'radix-vue';\nimport { ImageIcon, LoaderCircleIcon } from 'lucide-vue-next';\nimport { type ImageVariants, imageVariants } from '.';\nimport { cn } from '@ui/utils';\n\ntype Emits = {\n  load: [];\n  error: [];\n};\n\nconst props = withDefaults(defineProps<{\n  src?: string;\n  alt?: string;\n  glow?: boolean;\n\n  shape?: ImageVariants['shape'];\n}>(), {\n  alt: 'image',\n  shape: 'rounded',\n});\n\nconst emit = defineEmits<Emits>();\n\ndefineSlots<{\n  fallback: () => any;\n}>();\n\nconst forwardedProps = useForwardProps(props);\n\nconst isError = ref(false);\nconst isLoading = ref(true);\n\nwatch(() => props.src, (value) => {\n  if (!value) {\n    nextTick(() => {\n      isError.value = true;\n      isLoading.value = false;\n    });\n  } else {\n    isError.value = false;\n    isLoading.value = true;\n  }\n}, { immediate: true });\n\nfunction onError() {\n  emit('error');\n  isError.value = true;\n}\n\nfunction onLoad() {\n  emit('load');\n  isError.value = false;\n  isLoading.value = false;\n}\n</script>\n\n<template>\n  <div\n    :class=\"[\n      cn(imageVariants({ shape }), $attrs.class ?? ''),\n      {\n        'overflow-hidden': !glow,\n      },\n    ]\"\n    class=\"relative\"\n  >\n    <div\n      v-if=\"isError\"\n      class=\"animate-fade-in flex items-center justify-center w-full h-full\"\n    >\n      <slot name=\"fallback\">\n        <div\n          class=\"flex flex-col gap-1 items-center justify-center text-foreground/50\"\n        >\n          <ImageIcon class=\"w-[50%] max-w-[50px] h-[50%] max-h-[50px]\" />\n          no photo\n        </div>\n      </slot>\n    </div>\n    <div\n      v-else\n      class=\"flex items-center justify-center w-full h-full\"\n    >\n      <div class=\"animate-fade-in\">\n        <LoaderCircleIcon\n          v-if=\"isLoading\"\n          class=\"animate-spin w-[20px] h-[20px]\"\n        />\n      </div>\n      <img\n        v-show=\"!isLoading\"\n        v-if=\"glow && !isError && props.src\"\n        class=\"z-1 animate-fade-in absolute left-0 top-[2%] w-full h-full scale-105 object-cover blur-lg brightness-200 saturate-200 dark:brightness-100 rounded-md\"\n        v-bind=\"forwardedProps\"\n        @error=\"onError\"\n        @load=\"onLoad\"\n      >\n      <img\n        v-show=\"!isLoading\"\n        v-if=\"!isError && props.src\"\n        class=\"z-2 relative animate-fade-in w-full h-full object-cover rounded-md\"\n        v-bind=\"forwardedProps\"\n        @error=\"onError\"\n        @load=\"onLoad\"\n      >\n    </div>\n  </div>\n</template>\n"
    },
    {
      "name": "index.ts",
      "content": "import { type VariantProps, cva } from 'class-variance-authority';\n\nexport { default as Image } from './Image.vue';\n\nexport const imageVariants = cva(\n  'w-full h-full animate-fade-in flex items-center justify-center font-normal text-foreground select-none shrink-0 bg-secondary/30',\n  {\n    variants: {\n      shape: {\n        rounded: 'rounded-md [&_img]:rounded-md',\n        circle: 'rounded-full [&_img]:rounded-full',\n      },\n    },\n    defaultVariants: {\n      shape: 'rounded',\n    },\n  },\n);\n\nexport type ImageVariants = VariantProps<typeof imageVariants>;\n"
    }
  ],
  "type": "components:ui"
}