{"version":3,"sources":["../src/components/FileAttachment/FileAttachment.tsx"],"sourcesContent":["import React, { useRef } from 'react';\nimport { PaperclipIcon } from '@phosphor-icons/react/dist/csr/Paperclip';\nimport { FileTextIcon } from '@phosphor-icons/react/dist/csr/FileText';\nimport { XIcon } from '@phosphor-icons/react/dist/csr/X';\nimport Button from '../Button/Button';\nimport Text from '../Text/Text';\nimport { cn } from '../../utils/utils';\n\n/**\n * Represents an attached file with unique identifier\n */\nexport interface AttachedFile {\n  /** The file object */\n  file: File;\n  /** Unique identifier for the file */\n  id: string;\n}\n\n/**\n * Props for the FileAttachment component\n */\nexport interface FileAttachmentProps {\n  /** List of attached files */\n  files: AttachedFile[];\n  /** Callback when files are added */\n  onFilesAdd: (files: File[]) => void;\n  /** Callback when a file is removed */\n  onFileRemove: (id: string) => void;\n  /** Whether the files are read-only (no removal allowed) */\n  readOnly?: boolean;\n  /** Text for the attach button */\n  buttonLabel?: string;\n  /** Whether to accept multiple files */\n  multiple?: boolean;\n  /** Additional CSS class */\n  className?: string;\n  /** Whether to hide the attach button */\n  hideButton?: boolean;\n}\n\n/**\n * Formats file size to human-readable string\n * @param bytes - File size in bytes\n * @returns Formatted string (e.g., \"1.5 MB\")\n */\nconst formatFileSize = (bytes: number): string => {\n  if (bytes < 1024) return `${bytes} B`;\n  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n  if (bytes < 1024 * 1024 * 1024)\n    return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n  return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`;\n};\n\n/**\n * Generates a unique ID for file tracking\n * @returns Unique string identifier\n */\nconst generateFileId = (): string => {\n  return crypto.randomUUID();\n};\n\n/**\n * Reusable file attachment component\n *\n * Allows users to attach multiple files with preview and removal functionality.\n * No file size or type restrictions are applied on the client side.\n *\n * @param props - Component props\n * @returns JSX element\n *\n * @example\n * ```tsx\n * const [files, setFiles] = useState<AttachedFile[]>([]);\n *\n * <FileAttachment\n *   files={files}\n *   onFilesAdd={(newFiles) => {\n *     const attachedFiles = newFiles.map(file => ({\n *       file,\n *       id: generateFileId()\n *     }));\n *     setFiles(prev => [...prev, ...attachedFiles]);\n *   }}\n *   onFileRemove={(id) => setFiles(prev => prev.filter(f => f.id !== id))}\n *   multiple\n * />\n * ```\n */\nconst FileAttachment = ({\n  files,\n  onFilesAdd,\n  onFileRemove,\n  readOnly = false,\n  buttonLabel = 'Anexar',\n  multiple = true,\n  className,\n  hideButton = false,\n}: FileAttachmentProps) => {\n  const fileInputRef = useRef<HTMLInputElement>(null);\n\n  /**\n   * Handle file input change\n   * @param event - Input change event\n   */\n  const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n    const selectedFiles = event.target.files;\n    if (selectedFiles && selectedFiles.length > 0) {\n      const filesArray: File[] = Array.from(selectedFiles);\n      onFilesAdd(filesArray);\n    }\n    // Reset input to allow selecting the same file again\n    if (fileInputRef.current) {\n      fileInputRef.current.value = '';\n    }\n  };\n\n  /**\n   * Trigger file input click\n   */\n  const handleAttachClick = () => {\n    fileInputRef.current?.click();\n  };\n\n  return (\n    <div className={cn('flex flex-col gap-2', className)}>\n      {/* Hidden file input */}\n      <input\n        type=\"file\"\n        ref={fileInputRef}\n        className=\"hidden\"\n        onChange={handleFileChange}\n        multiple={multiple}\n        aria-label=\"Selecionar arquivos\"\n      />\n\n      {/* Attach button */}\n      {!readOnly && !hideButton && (\n        <Button\n          type=\"button\"\n          variant=\"outline\"\n          size=\"small\"\n          onClick={handleAttachClick}\n          className=\"self-start flex items-center gap-2\"\n        >\n          <PaperclipIcon size={16} />\n          {buttonLabel}\n        </Button>\n      )}\n\n      {/* Attached files list */}\n      {files.length > 0 && (\n        <div className=\"flex flex-wrap gap-2\">\n          {files.map((attachedFile) => (\n            <div\n              key={attachedFile.id}\n              className=\"flex items-center gap-2 bg-background-50 px-3 py-2 rounded-lg border border-border-100\"\n            >\n              <FileTextIcon size={16} className=\"text-text-500 shrink-0\" />\n              <Text className=\"text-sm text-text-700 truncate max-w-[200px]\">\n                {attachedFile.file.name}\n              </Text>\n              <Text className=\"text-xs text-text-400 shrink-0\">\n                {formatFileSize(attachedFile.file.size)}\n              </Text>\n              {!readOnly && (\n                <button\n                  type=\"button\"\n                  onClick={() => onFileRemove(attachedFile.id)}\n                  className=\"text-text-400 hover:text-error-500 transition-colors shrink-0\"\n                  aria-label={`Remover ${attachedFile.file.name}`}\n                >\n                  <XIcon size={14} />\n                </button>\n              )}\n            </div>\n          ))}\n        </div>\n      )}\n    </div>\n  );\n};\n\nexport { generateFileId, formatFileSize };\nexport default FileAttachment;\n"],"mappings":";;;;;;;;;;;AAAA,SAAgB,cAAc;AAC9B,SAAS,qBAAqB;AAC9B,SAAS,oBAAoB;AAC7B,SAAS,aAAa;AA2HhB,cAWE,YAXF;AAjFN,IAAM,iBAAiB,CAAC,UAA0B;AAChD,MAAI,QAAQ,KAAM,QAAO,GAAG,KAAK;AACjC,MAAI,QAAQ,OAAO,KAAM,QAAO,IAAI,QAAQ,MAAM,QAAQ,CAAC,CAAC;AAC5D,MAAI,QAAQ,OAAO,OAAO;AACxB,WAAO,IAAI,SAAS,OAAO,OAAO,QAAQ,CAAC,CAAC;AAC9C,SAAO,IAAI,SAAS,OAAO,OAAO,OAAO,QAAQ,CAAC,CAAC;AACrD;AAMA,IAAM,iBAAiB,MAAc;AACnC,SAAO,OAAO,WAAW;AAC3B;AA6BA,IAAM,iBAAiB,CAAC;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,cAAc;AAAA,EACd,WAAW;AAAA,EACX;AAAA,EACA,aAAa;AACf,MAA2B;AACzB,QAAM,eAAe,OAAyB,IAAI;AAMlD,QAAM,mBAAmB,CAAC,UAA+C;AACvE,UAAM,gBAAgB,MAAM,OAAO;AACnC,QAAI,iBAAiB,cAAc,SAAS,GAAG;AAC7C,YAAM,aAAqB,MAAM,KAAK,aAAa;AACnD,iBAAW,UAAU;AAAA,IACvB;AAEA,QAAI,aAAa,SAAS;AACxB,mBAAa,QAAQ,QAAQ;AAAA,IAC/B;AAAA,EACF;AAKA,QAAM,oBAAoB,MAAM;AAC9B,iBAAa,SAAS,MAAM;AAAA,EAC9B;AAEA,SACE,qBAAC,SAAI,WAAW,GAAG,uBAAuB,SAAS,GAEjD;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,KAAK;AAAA,QACL,WAAU;AAAA,QACV,UAAU;AAAA,QACV;AAAA,QACA,cAAW;AAAA;AAAA,IACb;AAAA,IAGC,CAAC,YAAY,CAAC,cACb;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAQ;AAAA,QACR,MAAK;AAAA,QACL,SAAS;AAAA,QACT,WAAU;AAAA,QAEV;AAAA,8BAAC,iBAAc,MAAM,IAAI;AAAA,UACxB;AAAA;AAAA;AAAA,IACH;AAAA,IAID,MAAM,SAAS,KACd,oBAAC,SAAI,WAAU,wBACZ,gBAAM,IAAI,CAAC,iBACV;AAAA,MAAC;AAAA;AAAA,QAEC,WAAU;AAAA,QAEV;AAAA,8BAAC,gBAAa,MAAM,IAAI,WAAU,0BAAyB;AAAA,UAC3D,oBAAC,gBAAK,WAAU,gDACb,uBAAa,KAAK,MACrB;AAAA,UACA,oBAAC,gBAAK,WAAU,kCACb,yBAAe,aAAa,KAAK,IAAI,GACxC;AAAA,UACC,CAAC,YACA;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS,MAAM,aAAa,aAAa,EAAE;AAAA,cAC3C,WAAU;AAAA,cACV,cAAY,WAAW,aAAa,KAAK,IAAI;AAAA,cAE7C,8BAAC,SAAM,MAAM,IAAI;AAAA;AAAA,UACnB;AAAA;AAAA;AAAA,MAlBG,aAAa;AAAA,IAoBpB,CACD,GACH;AAAA,KAEJ;AAEJ;AAGA,IAAO,yBAAQ;","names":[]}