{"version":3,"file":"useFilesUploader.mjs","sources":[""],"sourcesContent":["import { bubble } from \"@web3r/flowerkit/evt\";\r\nimport { useEffect, useRef, useState } from \"react\";\nimport type { RefObject } from \"react\";\r\nimport { getElRefHelper } from \"../../../utils/react/getElRefHelper\";\r\nimport type { IInputRef } from \"../../input\";\r\nimport type {\r\n  IFilesUploaderItem,\r\n  IUseFilesUploaderResult,\r\n  TOnFileDelete,\r\n  TOnFilesChange,\r\n  IOnFilesChangeArg,\r\n  TDOMDragEvent,\r\n  TInputChangeEvent,\r\n  TMaxSizeTypes,\n} from \"../config/types\";\r\nimport {\n  disableEvent,\r\n  getConvertedFilesArrayToMap,\r\n  getIfFilesValid,\r\n  setEachFileIntoInput,\r\n} from \"./index\";\n\nconst isPromiseLike = (value: unknown): value is PromiseLike<void> => {\n  return typeof value === \"object\" && value !== null && \"then\" in value && typeof value.then === \"function\";\n};\n\r\n/**\r\n * Хук компонента загрузчика файлов, инкапсулирующий основную логику взаимодействия с пользователем\r\n * @returns {IUseFilesUploaderResult}\r\n */\r\nexport const useFilesUploader = (\r\n  initialFiles: IFilesUploaderItem[] = [],\r\n  isDisabled: boolean = false,\r\n  fileTypes: string[] = [],\r\n  maxSize: number = Infinity,\r\n  maxFiles: number = Infinity,\r\n  hiddenInputRef: RefObject<IInputRef | null> | null = null,\r\n  inputRef: RefObject<HTMLInputElement | null> | null = null,\r\n  onFilesChange: TOnFilesChange | null = null,\r\n  onFileDelete: TOnFileDelete | null = null,\r\n  maxSizeType: TMaxSizeTypes = \"all\"\r\n): IUseFilesUploaderResult => {\r\n\r\n  // Loading state (async operations)\r\n  const [ isLoading, setIsLoading ] = useState<boolean>(false);\r\n\r\n  // Error state\r\n  const [ isError, setIsError ] = useState<boolean>(false);\r\n\r\n  // Dragging state\r\n  const [ isDragging, setIsDragging ] = useState<boolean>(false);\r\n\r\n  // Current files state\r\n  const [ filesMap, setFilesMap ] = useState<Map<string, Required<IFilesUploaderItem> | File>>(() => getConvertedFilesArrayToMap(initialFiles));\r\n\r\n  // Drag count ref\r\n  const dragCounterDeepRef = useRef<number>(0);\r\n\r\n  // Prev files state\r\n  const prevFilesMap = useRef<Map<string, Required<IFilesUploaderItem> | File>>(filesMap);\r\n\r\n  useEffect(() => {\r\n    if (prevFilesMap.current !== filesMap) {\r\n\r\n      const hiddenInputEl = getElRefHelper(hiddenInputRef);\r\n\r\n      setIsError(false);\r\n      const currentFiles: (Required<IFilesUploaderItem> | File)[] = [ ...filesMap.values() ];\r\n\r\n      const setFiles = (files: Array<IFilesUploaderItem | File>) => setEachFileIntoInput(files, hiddenInputEl as HTMLInputElement);\r\n\r\n      if (typeof onFilesChange === \"function\") { // custom user for inserting to input\r\n        const arg: IOnFilesChangeArg = {\r\n          ref: hiddenInputRef,\r\n          data: {\r\n            files: currentFiles,\r\n            prevFiles: prevFilesMap.current,\r\n            dragCounter: dragCounterDeepRef.current,\r\n          },\r\n          stateActions: {\r\n            /** Перезапись файлов в скрытое поле */\r\n            setFiles: async (files = new Map()) => {\r\n              const filesArray = Array.isArray(files) ? files : [ ...filesMap.values() ];\r\n              await setFiles(filesArray);\r\n            },\r\n            setIsError,\r\n            setIsLoading,\r\n            setIsDragging,\r\n          },\r\n        };\r\n\r\n        try {\n          const result = onFilesChange(arg);\n          if (isPromiseLike(result)) {\n            setIsLoading(true);\n            Promise.resolve(result)\n              .catch((error) => {\n                console.error(`[FilesUploader] Something is wrong while loading files to input`, error);\n                setIsError(true);\n              })\r\n              .finally(() => {\r\n                setIsLoading(false);\n                prevFilesMap.current = filesMap;\n              });\n          } else {\n            prevFilesMap.current = filesMap;\n          }\n        } catch (error) {\n          console.error(`[FilesUploader] Something is wrong while loading files to input`, error);\n          setIsError(true);\n          prevFilesMap.current = filesMap;\n        }\n      } else { // non-user fn\r\n        setIsLoading(true);\r\n        setFiles(currentFiles)\r\n          .catch((error) => {\r\n            // Невозможно присвоить файлы в инпут в тестовой среде\r\n            if (process.env.NODE_ENV === \"test\") {\r\n              return;\r\n            }\r\n            console.error(`[FilesUploader] Something is wrong while loading files to input`, error);\r\n            setIsError(true);\r\n          })\r\n          .finally(() => {\r\n            setIsLoading(false);\r\n            prevFilesMap.current = filesMap;\r\n            // fix for live validation\r\n            if (hiddenInputEl && (hiddenInputEl as HTMLInputElement)?.files?.length) {\r\n              bubble(hiddenInputEl, \"blur\");\r\n            }\r\n          });\r\n      }\r\n    }\r\n  }, [ filesMap ]);\r\n\r\n  const handleDragStart = (e: TDOMDragEvent): void => {\r\n    e.dataTransfer?.clearData();\r\n  };\r\n\r\n  const handleDragEnter = (e: TDOMDragEvent): void => {\r\n    disableEvent(e as Event);\r\n    dragCounterDeepRef.current++;\r\n    const items = e.dataTransfer?.items;\r\n    if (!isDisabled && !!items && items.length) {\r\n      setIsDragging(true);\r\n    }\r\n  };\r\n\r\n  const handleDragLeave = (e: TDOMDragEvent): void => {\r\n    disableEvent(e as Event);\r\n    dragCounterDeepRef.current--;\r\n    if (dragCounterDeepRef.current <= 0) {\r\n      setIsDragging(false);\r\n    }\r\n  };\r\n\r\n  const handleDragOver = (e: TDOMDragEvent): void => {\r\n    disableEvent(e as Event);\r\n  };\r\n\r\n  const handleDrop = (e: TDOMDragEvent): void => {\r\n    disableEvent(e as Event);\r\n    if (isDisabled) {\r\n      return;\r\n    }\r\n\r\n    setIsDragging(false);\n\n    const files: File[] = [ ...(e.dataTransfer?.files ? Array.from(e.dataTransfer.files) : []) ];\n    dragCounterDeepRef.current = 0;\n    if (files.length) {\n      addFilesToFilesMap(files);\n    }\n  };\r\n\r\n  const handleChangeFiles = (e: TInputChangeEvent): void => {\r\n    const rawFiles = e.target.files;\r\n    const files: File[] = rawFiles ? Array.from(rawFiles) : [];\n    const input = getElRefHelper(inputRef) as HTMLInputElement | null;\n    if (files.length) {\n      addFilesToFilesMap(files);\n    }\n    if (input) {\n      input.value = \"\";\n    }\n  };\r\n\r\n  const addFilesToFilesMap = (files: File[]): void => {\r\n    const filesForValidation = (() => {\r\n      if (maxSizeType === \"every\") {\r\n        return files;\r\n      }\r\n\r\n      const nextFilesMap = new Map(filesMap);\r\n      files.forEach((file) => {\r\n        nextFilesMap.set(file.name, file);\r\n      });\r\n\r\n      return Array.from(nextFilesMap.values());\r\n    })();\r\n\r\n    const isValid = getIfFilesValid(filesForValidation, maxSize, fileTypes, maxSizeType);\r\n    setIsError(!isValid);\r\n\r\n    if (isValid) {\r\n      updateFilesMap(files);\r\n    }\r\n  };\r\n\r\n  const updateFilesMap = (files: File[]): void => {\n    if (!files.length) {\n      return;\n    }\n    if (maxFiles === 1) {\n      if (files.length > 1) {\n        setIsError(true);\n        return;\n      }\n      const newFiles = new Map<string, Required<IFilesUploaderItem> | File>();\n      const [ file ] = files;\n      newFiles.set(file.name, file);\n      setIsError(false);\n      setFilesMap(newFiles);\n    } else {\n      const nextFilesMap = new Map(filesMap);\n      files.forEach((file) => nextFilesMap.set(file.name, file));\n      if (nextFilesMap.size > maxFiles) {\n        setIsError(true);\n        return;\n      }\n      setIsError(false);\n      setFilesMap(nextFilesMap);\n    }\r\n\r\n  };\r\n\r\n  const deleteFilesFromMap = (files: Array<Pick<Required<IFilesUploaderItem>, \"size\" | \"name\">> = []): void => {\r\n    if (files.length) {\r\n      const newMap = new Map(filesMap);\r\n      files.forEach(({ name, size }) => {\r\n        if (newMap.get(name)?.size === size) {\r\n          newMap.delete(name);\r\n        }\r\n      });\r\n      setFilesMap(newMap);\r\n    }\r\n  };\r\n\r\n  const handleFileItemDeleteClick = async (file: Required<IFilesUploaderItem> | File) => {\r\n    const { name, size } = file || {};\r\n    if (name && typeof size === \"number\") {\n      if (typeof onFileDelete === \"function\") {\n        setIsError(false);\n        try {\n          const result = onFileDelete({\n            data: {\n              file,\n              dragCounter: dragCounterDeepRef,\n            },\r\n            stateActions: {\r\n              setIsError,\r\n              setIsDragging,\r\n              setFiles: setFilesMap,\n            },\n          });\n          if (!isPromiseLike(result)) {\n            return Promise.resolve();\n          }\n          setIsLoading(true);\n          return Promise.resolve(result)\n            .catch((error) => {\n              setIsError(true);\n              console.error(`[FilesUploader] Something is wrong while deleting files`, error);\n            })\r\n            .finally(() => {\n              setIsLoading(false);\n            });\n        } catch (error) {\n          setIsError(true);\n          console.error(`[FilesUploader] Something is wrong while deleting files`, error);\n          return Promise.resolve();\n        }\n      } else {\n        deleteFilesFromMap([ { name, size } ]);\r\n        return Promise.resolve();\r\n      }\r\n    } else {\r\n      console.error(`[FilesUploader] Can't parse file name or size`);\r\n      return Promise.reject();\r\n    }\r\n  };\r\n\r\n  return {\r\n    isLoading,\r\n    isDragging,\r\n    isError,\r\n    filesMap,\r\n    setFilesMap,\r\n    handleDragStart,\r\n    handleDragEnter,\r\n    handleDragLeave,\r\n    handleDragOver,\r\n    handleDrop,\r\n    handleChangeFiles,\r\n    handleFileItemDeleteClick,\r\n  };\r\n};\r\n"],"names":["isPromiseLike","value","then","useFilesUploader","initialFiles","isDisabled","fileTypes","maxSize","Infinity","maxFiles","hiddenInputRef","inputRef","onFilesChange","onFileDelete","maxSizeType","isLoading","setIsLoading","useState","isError","setIsError","isDragging","setIsDragging","filesMap","setFilesMap","getConvertedFilesArrayToMap","dragCounterDeepRef","useRef","prevFilesMap","useEffect","current","hiddenInputEl","getElRefHelper","currentFiles","values","setFiles","files","setEachFileIntoInput","arg","ref","data","prevFiles","dragCounter","stateActions","async","Map","filesArray","Array","isArray","result","Promise","resolve","catch","error","console","finally","process","env","NODE_ENV","length","bubble","handleDragStart","e","dataTransfer","clearData","handleDragEnter","disableEvent","items","handleDragLeave","handleDragOver","handleDrop","from","addFilesToFilesMap","handleChangeFiles","rawFiles","target","input","filesForValidation","nextFilesMap","forEach","file","set","name","isValid","getIfFilesValid","updateFilesMap","newFiles","size","deleteFilesFromMap","newMap","get","delete","handleFileItemDeleteClick","reject"],"mappings":"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"}