{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "attachment",
  "title": "Attachment",
  "type": "registry:ui",
  "files": [
    {
      "path": "packages/registry-svelte/components/attachment/Attachment.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { HTMLAttributes } from 'svelte/elements'\n\n  export interface AttachmentProps extends HTMLAttributes<HTMLDivElement> {\n    title: string\n    description?: string\n    state?: 'idle' | 'uploading' | 'processing' | 'error' | 'done'\n    size?: 'default' | 'sm' | 'xs'\n    orientation?: 'horizontal' | 'vertical'\n    media?: 'file' | 'image' | 'code'\n    src?: string\n    alt?: string\n    removable?: boolean\n    ref?: HTMLDivElement | null\n    onRemove?: () => void\n  }\n</script>\n\n<script lang=\"ts\">\n  import { FileCode, FileText, Image as ImageIcon, LoaderCircle, X } from '@lucide/svelte'\n  import { cn } from '$lib/utils'\n  import { attachmentMediaVariants, attachmentVariants } from './attachment.variants'\n\n  let {\n    title,\n    description,\n    state = 'done',\n    size = 'default',\n    orientation = 'horizontal',\n    media = 'file',\n    src,\n    alt = '',\n    removable = false,\n    class: className,\n    ref = $bindable(null),\n    onRemove,\n    ...restProps\n  }: AttachmentProps = $props()\n\n  const busy = $derived(state === 'uploading' || state === 'processing')\n</script>\n\n<div\n  bind:this={ref}\n  data-uipkge=\"\"\n  data-slot=\"attachment\"\n  data-state={state}\n  data-size={size}\n  data-orientation={orientation}\n  class={cn(attachmentVariants({ size, orientation }), className)}\n  {...restProps}\n>\n  <div data-slot=\"attachment-media\" class={cn(attachmentMediaVariants({ size }))}>\n    {#if src && media === 'image' && !busy}\n      <img {src} {alt} class=\"size-full object-cover\" />\n    {:else if busy}\n      <LoaderCircle class=\"size-4 motion-safe:animate-spin\" aria-hidden=\"true\" />\n    {:else if media === 'code'}\n      <FileCode aria-hidden=\"true\" />\n    {:else if media === 'image'}\n      <ImageIcon aria-hidden=\"true\" />\n    {:else}\n      <FileText aria-hidden=\"true\" />\n    {/if}\n  </div>\n  <div data-slot=\"attachment-content\" class=\"min-w-0 flex-1 leading-tight\">\n    <span data-slot=\"attachment-title\" class={cn('block truncate font-medium', busy && 'animate-pulse')}>\n      {title}\n    </span>\n    {#if description}\n      <span\n        data-slot=\"attachment-description\"\n        class={cn('text-muted-foreground mt-0.5 block truncate text-xs', state === 'error' && 'text-destructive/80')}\n      >\n        {description}\n      </span>\n    {/if}\n  </div>\n  {#if removable}\n    <button\n      type=\"button\"\n      data-slot=\"attachment-remove\"\n      class=\"text-muted-foreground hover:bg-accent hover:text-foreground relative z-10 inline-flex size-7 shrink-0 items-center justify-center rounded-md\"\n      aria-label={`Remove ${title}`}\n      onclick={() => onRemove?.()}\n    >\n      <X class=\"size-3.5\" />\n    </button>\n  {/if}\n</div>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/attachment/Attachment.svelte"
    },
    {
      "path": "packages/registry-svelte/components/attachment/attachment.variants.ts",
      "content": "import type { VariantProps } from 'class-variance-authority'\nimport { cva } from 'class-variance-authority'\n\n/**\n * Variant definitions live in their own file (rather than the package\n * `index.ts`) so consuming Vue SFCs can import without creating a circular\n * dependency through the index. See card.variants.ts for the canonical\n * example + the SSR symptom that motivated the split.\n */\n\nexport const attachmentVariants = cva(\n  'group/attachment relative flex w-fit max-w-full min-w-0 shrink-0 rounded-xl border bg-card text-card-foreground transition-colors data-[state=error]:border-destructive/30 data-[state=idle]:border-dashed',\n  {\n    variants: {\n      size: {\n        default: 'gap-2 p-2 text-sm',\n        sm: 'gap-2 p-1.5 text-xs',\n        xs: 'gap-1.5 rounded-lg p-1 text-xs',\n      },\n      orientation: {\n        horizontal: 'min-w-40 items-center',\n        vertical: 'w-24 flex-col',\n      },\n    },\n    defaultVariants: {\n      size: 'default',\n      orientation: 'horizontal',\n    },\n  },\n)\n\nexport const attachmentMediaVariants = cva(\n  \"relative flex aspect-square shrink-0 items-center justify-center overflow-hidden rounded-lg bg-muted text-foreground group-data-[orientation=vertical]/attachment:w-full group-data-[state=error]/attachment:bg-destructive/10 group-data-[state=error]/attachment:text-destructive [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4\",\n  {\n    variants: {\n      size: {\n        default: 'w-10',\n        sm: 'w-8',\n        xs: 'w-7 rounded-md [&_svg:not([class*=\"size-\"])]:size-3.5',\n      },\n    },\n    defaultVariants: {\n      size: 'default',\n    },\n  },\n)\n\nexport type AttachmentVariants = VariantProps<typeof attachmentVariants>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/attachment/attachment.variants.ts"
    },
    {
      "path": "packages/registry-svelte/components/attachment/index.ts",
      "content": "export { default as Attachment, type AttachmentProps } from './Attachment.svelte'\nexport { attachmentVariants, attachmentMediaVariants, type AttachmentVariants } from './attachment.variants'\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/attachment/index.ts"
    }
  ],
  "dependencies": [
    "class-variance-authority",
    "@lucide/svelte"
  ],
  "devDependencies": [],
  "registryDependencies": [],
  "description": "Single file or image chip. Drive look with props: state, size, orientation, media, src, removable. Not a dropzone (see file-upload).",
  "categories": [
    "data-display"
  ]
}