UNPKG

analytica-frontend-lib

Version:

Repositório público dos componentes utilizados nas plataformas da Analytica Ensino

338 lines (329 loc) 13.8 kB
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _chunk34ST3MKOjs = require('./chunk-34ST3MKO.js'); var _chunkANT66KVKjs = require('./chunk-ANT66KVK.js'); var _chunkTN3AYOMVjs = require('./chunk-TN3AYOMV.js'); // src/components/FileDropzone/FileDropzone.tsx var _react = require('react'); var _Upload = require('@phosphor-icons/react/dist/csr/Upload'); var _WarningCircle = require('@phosphor-icons/react/dist/csr/WarningCircle'); var _CheckCircle = require('@phosphor-icons/react/dist/csr/CheckCircle'); var _FileVideo = require('@phosphor-icons/react/dist/csr/FileVideo'); var _FileAudio = require('@phosphor-icons/react/dist/csr/FileAudio'); var _FilePdf = require('@phosphor-icons/react/dist/csr/FilePdf'); var _ClosedCaptioning = require('@phosphor-icons/react/dist/csr/ClosedCaptioning'); var _Paperclip = require('@phosphor-icons/react/dist/csr/Paperclip'); var _PencilSimple = require('@phosphor-icons/react/dist/csr/PencilSimple'); var _X = require('@phosphor-icons/react/dist/csr/X'); var _jsxruntime = require('react/jsx-runtime'); var FILE_TYPE_CONFIG = { image: { icon: _Upload.UploadIcon, defaultPlaceholder: "para subir a imagem ou arraste aqui" }, video: { icon: _FileVideo.FileVideoIcon, defaultPlaceholder: "para subir o v\xEDdeo ou arraste aqui" }, audio: { icon: _FileAudio.FileAudioIcon, defaultPlaceholder: "para subir o \xE1udio ou arraste aqui" }, pdf: { icon: _FilePdf.FilePdfIcon, defaultPlaceholder: "para subir o PDF ou arraste aqui" }, subtitle: { icon: _ClosedCaptioning.ClosedCaptioningIcon, defaultPlaceholder: "para subir a legenda ou arraste aqui" } }; function FileDropzone({ label, helperText, errorMessage, fileUrl, selectedFile, onFileSelect, onRemoveFile, accept, fileType, actionText = "Clique aqui", placeholder, changeText, changeButtonText = "Trocar", disabled = false, required = false, className, maxSize, onSizeError, onTypeError, showPreview = true, previewMaxHeight = "max-h-48" }) { const fileInputRef = _react.useRef.call(void 0, null); const dragCounterRef = _react.useRef.call(void 0, 0); const [isDragging, setIsDragging] = _react.useState.call(void 0, false); const [previewUrl, setPreviewUrl] = _react.useState.call(void 0, null); const generatedId = _react.useId.call(void 0, ); const inputId = `file-dropzone-${generatedId}`; const hasError = Boolean(errorMessage); const config = FILE_TYPE_CONFIG[fileType]; const IconComponent = config.icon; const defaultPlaceholder = placeholder || config.defaultPlaceholder; const defaultChangeText = changeText || (fileType === "image" ? "Clique para alterar a imagem" : "Clique para trocar o arquivo"); _react.useEffect.call(void 0, () => { if (!selectedFile || fileType !== "image") { setPreviewUrl(null); return; } const url = URL.createObjectURL(selectedFile); setPreviewUrl(url); return () => { URL.revokeObjectURL(url); }; }, [selectedFile, fileType]); const displayUrl = fileType === "image" ? previewUrl || fileUrl : null; const hasFile = Boolean(selectedFile || fileUrl); const validateFile = _react.useCallback.call(void 0, (file) => { const acceptedTypes = accept.split(",").map((type) => type.trim()); const isValidType = acceptedTypes.some((type) => { if (type.startsWith(".")) { return file.name.toLowerCase().endsWith(type.toLowerCase()); } if (!file.type) { return false; } if (type.endsWith("/*")) { const mainType = type.split("/")[0]; return file.type.startsWith(mainType + "/"); } return file.type === type; }); if (!isValidType) { _optionalChain([onTypeError, 'optionalCall', _ => _(file)]); return false; } if (maxSize != null && file.size > maxSize) { _optionalChain([onSizeError, 'optionalCall', _2 => _2(file, maxSize)]); return false; } return true; }, [accept, maxSize, onSizeError, onTypeError] ); const handleFileChange = (event) => { const file = _optionalChain([event, 'access', _3 => _3.target, 'access', _4 => _4.files, 'optionalAccess', _5 => _5[0]]); if (!file || disabled) return; if (validateFile(file)) { _optionalChain([onFileSelect, 'optionalCall', _6 => _6(file)]); } event.target.value = ""; }; const handleDragEnter = (e) => { e.preventDefault(); e.stopPropagation(); dragCounterRef.current += 1; if (!disabled && dragCounterRef.current === 1) { setIsDragging(true); } }; const handleDragLeave = (e) => { e.preventDefault(); e.stopPropagation(); dragCounterRef.current -= 1; if (dragCounterRef.current === 0) { setIsDragging(false); } }; const handleDragOver = (e) => { e.preventDefault(); e.stopPropagation(); }; const handleDrop = (e) => { e.preventDefault(); e.stopPropagation(); dragCounterRef.current = 0; setIsDragging(false); if (disabled) return; const file = _optionalChain([e, 'access', _7 => _7.dataTransfer, 'access', _8 => _8.files, 'optionalAccess', _9 => _9[0]]); if (!file) return; if (validateFile(file)) { _optionalChain([onFileSelect, 'optionalCall', _10 => _10(file)]); } }; const handleRemove = (e) => { e.preventDefault(); e.stopPropagation(); if (!disabled) { _optionalChain([onRemoveFile, 'optionalCall', _11 => _11()]); } }; const handleChangeClick = (e) => { e.preventDefault(); e.stopPropagation(); if (!disabled) { _optionalChain([fileInputRef, 'access', _12 => _12.current, 'optionalAccess', _13 => _13.click, 'call', _14 => _14()]); } }; const fileName = _optionalChain([selectedFile, 'optionalAccess', _15 => _15.name]) || (fileUrl ? "Arquivo carregado" : ""); const getBorderClasses = () => { if (hasError) { return disabled ? "border-indicator-error" : "border-indicator-error hover:border-indicator-error"; } if (isDragging) { return "border-primary-500 bg-primary-50"; } return disabled ? "border-border-200" : "border-border-200 hover:border-primary-500"; }; const dropzoneClasses = _chunkTN3AYOMVjs.cn.call(void 0, "flex flex-col items-center justify-center p-6 border-2 border-dashed rounded-lg cursor-pointer transition-colors", getBorderClasses(), disabled && "cursor-not-allowed opacity-50" ); const isImagePreview = fileType === "image" && showPreview && Boolean(displayUrl); const imageCardClasses = _chunkTN3AYOMVjs.cn.call(void 0, "flex flex-col items-center justify-center gap-3 p-6 rounded-lg bg-background-100", hasError && "border-2 border-indicator-error", disabled && "opacity-50" ); const getAriaDescribedBy = () => { if (errorMessage) return `${inputId}-error`; if (helperText) return `${inputId}-helper`; return void 0; }; const renderImagePreview = () => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "img", { src: _nullishCoalesce(displayUrl, () => ( void 0)), alt: "Preview do arquivo", className: _chunkTN3AYOMVjs.cn.call(void 0, "max-w-full rounded-lg object-contain", previewMaxHeight) } ), /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-2 rounded-full border border-border-200 bg-background px-3 py-1.5", children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _Paperclip.PaperclipIcon, { size: 16, className: "text-text-600" }), /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkANT66KVKjs.Text_default, { size: "sm", className: "text-text-700 max-w-[200px] truncate", children: fileName }), onRemoveFile && !disabled && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk34ST3MKOjs.Button_default, { variant: "raw", type: "button", onClick: handleRemove, className: "p-0.5 rounded-full hover:bg-error-100 transition-colors", "aria-label": "Remover arquivo", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _X.XIcon, { size: 14, className: "text-indicator-error" }) } ) ] }), !disabled && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk34ST3MKOjs.Button_default, { variant: "outline", action: "primary", size: "small", iconLeft: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _PencilSimple.PencilSimpleIcon, { size: 16 }), onClick: handleChangeClick, children: changeButtonText } ) ] }); const renderFilePreview = () => { if (hasFile) { return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col items-center gap-3", children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex items-center justify-center w-12 h-12 rounded-full bg-success-100", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _CheckCircle.CheckCircleIcon, { size: 28, className: "text-success-600", weight: "fill" } ) }), /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-2", children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, IconComponent, { size: 20, className: "text-text-600" }), /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkANT66KVKjs.Text_default, { size: "sm", className: "text-text-700 max-w-[200px] truncate", children: fileName }), onRemoveFile && !disabled && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk34ST3MKOjs.Button_default, { variant: "raw", type: "button", onClick: handleRemove, className: "p-1 rounded-full hover:bg-error-100 transition-colors", "aria-label": "Remover arquivo", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _X.XIcon, { size: 14, className: "text-indicator-error" }) } ) ] }), /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkANT66KVKjs.Text_default, { size: "xs", className: "text-text-500", children: defaultChangeText }) ] }); } return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, IconComponent, { size: 24, className: "text-primary-500 mb-2" }), /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkANT66KVKjs.Text_default, { size: "sm", className: "text-text-600 text-center", children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-primary-500 font-medium", children: actionText }), " ", defaultPlaceholder ] }) ] }); }; return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className, children: [ label && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "label", { htmlFor: inputId, className: "block font-bold text-text-900 mb-2 text-sm", children: [ label, " ", required && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-indicator-error", children: "*" }) ] } ), /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { ref: fileInputRef, id: inputId, type: "file", accept, onChange: handleFileChange, className: "hidden", disabled, "aria-invalid": hasError, "aria-describedby": getAriaDescribedBy() } ), isImagePreview ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: imageCardClasses, onDragEnter: handleDragEnter, onDragLeave: handleDragLeave, onDragOver: handleDragOver, onDrop: handleDrop, children: renderImagePreview() } ) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { htmlFor: inputId, className: dropzoneClasses, onDragEnter: handleDragEnter, onDragLeave: handleDragLeave, onDragOver: handleDragOver, onDrop: handleDrop, children: renderFilePreview() } ), /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "mt-1", children: [ helperText && !errorMessage && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkANT66KVKjs.Text_default, { id: `${inputId}-helper`, size: "xs", className: "text-text-500", children: helperText }), errorMessage && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkANT66KVKjs.Text_default, { id: `${inputId}-error`, size: "xs", color: "text-indicator-error", children: [ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _WarningCircle.WarningCircleIcon, { size: 14 }), " ", errorMessage ] }) ] }) ] }); } exports.FileDropzone = FileDropzone; //# sourceMappingURL=chunk-ZAKVMSVA.js.map