var __assign = (this && this.__assign) || function () {
    __assign = Object.assign || function(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
                t[p] = s[p];
        }
        return t;
    };
    return __assign.apply(this, arguments);
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __generator = (this && this.__generator) || function (thisArg, body) {
    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
    return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
    function verb(n) { return function (v) { return step([n, v]); }; }
    function step(op) {
        if (f) throw new TypeError("Generator is already executing.");
        while (g && (g = 0, op[0] && (_ = 0)), _) try {
            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
            if (y = 0, t) op = [op[0] & 2, t.value];
            switch (op[0]) {
                case 0: case 1: t = op; break;
                case 4: _.label++; return { value: op[1], done: false };
                case 5: _.label++; y = op[1]; op = [0]; continue;
                case 7: op = _.ops.pop(); _.trys.pop(); continue;
                default:
                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                    if (t[2]) _.ops.pop();
                    _.trys.pop(); continue;
            }
            op = body.call(thisArg, _);
        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
    }
};
var __rest = (this && this.__rest) || function (s, e) {
    var t = {};
    for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
        t[p] = s[p];
    if (s != null && typeof Object.getOwnPropertySymbols === "function")
        for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
            if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
                t[p[i]] = s[p[i]];
        }
    return t;
};
import React, { useCallback, useContext, useEffect, useImperativeHandle, useRef, useState } from 'react';
import { useEmotion, useGlobal, useStyles } from '../../lib/renderEnvironment/index.js';
import { isBrowser } from '../../lib/globalObject.js';
import { useMemoObject } from '../../hooks/useMemoObject.js';
import { useDrop } from '../../hooks/useDrop.js';
import { ThemeContext } from '../../lib/theming/ThemeContext.js';
import { useKeyListener } from '../../lib/events/keyListener.js';
import { CommonWrapper } from '../../internal/CommonWrapper/index.js';
import { forwardRefAndName } from '../../lib/forwardRefAndName.js';
import { FocusControlWrapper } from '../../internal/FocusControlWrapper/index.js';
import { useFileUploaderSize } from './hooks/useFileUploaderSize.js';
import { FileUploaderFileValidationResult } from './FileUploaderFileValidationResult.js';
import { FileUploaderFileList } from './FileUploaderFileList/FileUploaderFileList.js';
import { withFileUploaderControlProvider } from './withFileUploaderControlProvider.js';
import { useUpload } from './hooks/useUpload.js';
import { useControlLocale } from './hooks/useControlLocale.js';
import { FileUploaderControlContext } from './FileUploaderControlContext.js';
import { FileUploaderFileStatus, getAttachedFile } from './fileUtils.js';
import { FileUploaderFile } from './FileUploaderFile.js';
import { UploadIcon } from './icons/UploadIcon.js';
import { globalClasses, getJsStyles, getJsRowStyles, getJsTileStyles } from './FileUploader.styles.js';
var stopPropagation = function (e) { return e.stopPropagation(); };
export var FileUploaderDataTids = {
    root: 'FileUploader__root',
    content: 'FileUploader__content',
    link: 'FileUploader__link',
    input: 'FileUploader__input',
};
var defaultRenderFile = function (props) { return React.createElement(FileUploaderFile, __assign({}, props)); };
var _FileUploader = forwardRefAndName('FileUploader', function (props, ref) {
    var _a, _b, _c, _d, _e, _f;
    var _g, _h;
    var theme = useContext(ThemeContext);
    var globalObject = useGlobal();
    var cx = useEmotion().cx;
    var jsStyles = useStyles(getJsStyles);
    var jsRowStyles = useStyles(getJsRowStyles);
    var jsTileStyles = useStyles(getJsTileStyles);
    var keyListener = useKeyListener();
    var disabled = props.disabled, error = props.error, warning = props.warning, _j = props.withValidationTooltip, withValidationTooltip = _j === void 0 ? false : _j, validationTooltipPosition = props.validationTooltipPosition, _k = props.withWarningIcon, withWarningIcon = _k === void 0 ? false : _k, _l = props.multiple, multiple = _l === void 0 ? false : _l, uploaderText = props.uploaderText, uploaderIcon = props.uploaderIcon, _m = props.view, view = _m === void 0 ? 'row' : _m, _o = props.uploadButtonPosition, uploadButtonPosition = _o === void 0 ? 'start' : _o, _p = props.validationSummary, validationSummary = _p === void 0 ? 'auto' : _p, _q = props.validationSummaryStart, validationSummaryStart = _q === void 0 ? 5 : _q, _r = props.width, width = _r === void 0 ? theme.fileUploaderWidth : _r, _s = props.hideFiles, hideFiles = _s === void 0 ? false : _s, onBlur = props.onBlur, onFocus = props.onFocus, onChange = props.onChange, request = props.request, validateBeforeUpload = props.validateBeforeUpload, onRequestSuccess = props.onRequestSuccess, onRequestError = props.onRequestError, _t = props.size, size = _t === void 0 ? 'small' : _t, _u = props.renderFile, renderFile = _u === void 0 ? defaultRenderFile : _u, inputProps = __rest(props, ["disabled", "error", "warning", "withValidationTooltip", "validationTooltipPosition", "withWarningIcon", "multiple", "uploaderText", "uploaderIcon", "view", "uploadButtonPosition", "validationSummary", "validationSummaryStart", "width", "hideFiles", "onBlur", "onFocus", "onChange", "request", "validateBeforeUpload", "onRequestSuccess", "onRequestError", "size", "renderFile"]);
    var _v = useContext(FileUploaderControlContext), files = _v.files, setFiles = _v.setFiles, removeFile = _v.removeFile, reset = _v.reset, setFileValidationResult = _v.setFileValidationResult;
    var locale = useControlLocale();
    var inputRef = useRef(null);
    var fileDivRef = useRef(null);
    var isAsync = !!request;
    var isSingleMode = !multiple;
    var _w = useState(false), hovered = _w[0], setHovered = _w[1];
    var upload = useUpload(request, onRequestSuccess, onRequestError);
    var tryValidateAndUpload = useCallback(function (files) {
        files.forEach(function (file) { return __awaiter(void 0, void 0, void 0, function () {
            var validationMessage, _a;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        _a = validateBeforeUpload;
                        if (!_a) return [3 /*break*/, 2];
                        return [4 /*yield*/, validateBeforeUpload(file)];
                    case 1:
                        _a = (_b.sent());
                        _b.label = 2;
                    case 2:
                        validationMessage = _a;
                        if (!validationMessage) {
                            isAsync && upload(file);
                        }
                        else if (typeof validationMessage === 'object') {
                            setFileValidationResult(file.id, FileUploaderFileValidationResult.error(validationMessage.message), validationMessage.status);
                        }
                        else {
                            setFileValidationResult(file.id, FileUploaderFileValidationResult.error(validationMessage), FileUploaderFileStatus.Error);
                        }
                        return [2 /*return*/];
                }
            });
        }); });
    }, [validateBeforeUpload, isAsync, upload, setFileValidationResult]);
    var isTileView = view === 'tile';
    var jsViewStyles = isTileView ? jsTileStyles : jsRowStyles;
    var sizeClassName = useFileUploaderSize(size, {
        small: jsViewStyles.sizeSmall(theme),
        medium: jsViewStyles.sizeMedium(theme),
        large: jsViewStyles.sizeLarge(theme),
    });
    var uploadButtonTileWithFileClassName = useFileUploaderSize(size, {
        small: jsTileStyles.uploadButtonTileWithFileSmall(theme),
        medium: jsTileStyles.uploadButtonTileWithFileMedium(theme),
        large: jsTileStyles.uploadButtonTileWithFileLarge(theme),
    });
    var uploadButtonIconGapClass = useFileUploaderSize(size, {
        small: jsViewStyles.uploadButtonIconGapSmall(theme),
        medium: jsViewStyles.uploadButtonIconGapMedium(theme),
        large: jsViewStyles.uploadButtonIconGapLarge(theme),
    });
    var sizeIconClass = useFileUploaderSize(size, {
        small: jsStyles.iconSmall(theme),
        medium: jsStyles.iconMedium(theme),
        large: jsStyles.iconLarge(theme),
    });
    var sizeWrapperClass = useFileUploaderSize(size, {
        small: jsTileStyles.uploadButtonWrapperSmall(theme),
        medium: jsTileStyles.uploadButtonWrapperMedium(theme),
        large: jsTileStyles.uploadButtonWrapperLarge(theme),
    });
    var sizeWrapperEmptyFileClass = useFileUploaderSize(size, {
        small: jsTileStyles.uploadButtonWrapperEmptyFileSmall(theme),
        medium: jsTileStyles.uploadButtonWrapperEmptyFileMedium(theme),
        large: jsTileStyles.uploadButtonWrapperEmptyFileLarge(theme),
    });
    var contentInnerClass = useFileUploaderSize(size, {
        small: jsStyles.contentInnerSmall(theme),
        medium: jsStyles.contentInnerMedium(theme),
        large: jsStyles.contentInnerLarge(theme),
    });
    /** common part **/
    var handleChange = useCallback(function (newFiles) {
        if (!newFiles || !newFiles.length) {
            return;
        }
        var filesArray = Array.from(newFiles);
        if (isSingleMode) {
            filesArray = [filesArray[0]];
        }
        var attachedFiles = filesArray.map(getAttachedFile);
        if (isSingleMode && attachedFiles.length && files.length) {
            removeFile(files[0].id);
        }
        if (attachedFiles.length) {
            setFiles(attachedFiles);
            tryValidateAndUpload(attachedFiles);
        }
    }, [tryValidateAndUpload, setFiles, isSingleMode, files, removeFile]);
    var handleDrop = useCallback(function (event) {
        var _a;
        if (disabled) {
            return;
        }
        var dataTransfer = event.dataTransfer;
        if (dataTransfer) {
            if (isSingleMode && dataTransfer.files.length > 1) {
                dataTransfer.dropEffect = 'none';
                return;
            }
            if (((_a = dataTransfer.files) === null || _a === void 0 ? void 0 : _a.length) > 0) {
                inputRef.current && (inputRef.current.files = dataTransfer.files);
                handleChange(dataTransfer.files);
            }
        }
    }, [handleChange, disabled]);
    var _x = useDrop({ onDrop: handleDrop }), isDraggable = _x.isDraggable, labelRef = _x.ref;
    var _y = useDrop(), isWindowDraggable = _y.isDraggable, windowRef = _y.ref;
    if (isBrowser(globalObject)) {
        windowRef.current = globalObject.document;
    }
    var focus = useCallback(function () {
        var _a;
        keyListener.isTabPressed = true;
        (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
    }, []);
    var blur = useCallback(function () {
        var _a;
        (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.blur();
    }, []);
    var removeFileFromNativeInput = useCallback(function (fileId) {
        var dataTransfer = new DataTransfer();
        files
            .filter(function (f) { return f.id !== fileId; })
            .forEach(function (file) {
            dataTransfer.items.add(file.originalFile);
        });
        inputRef.current && (inputRef.current.files = dataTransfer.files);
    }, [files]);
    var handleRemoveFile = useCallback(function (fileId) {
        removeFile(fileId);
        removeFileFromNativeInput(fileId);
    }, [removeFileFromNativeInput, removeFile]);
    var handleReset = useCallback(function () {
        reset();
        var dataTransfer = new DataTransfer();
        inputRef.current && (inputRef.current.files = dataTransfer.files);
    }, [reset, handleRemoveFile]);
    useImperativeHandle(ref, function () { return ({
        focus: focus,
        blur: blur,
        reset: handleReset,
        removeFile: handleRemoveFile,
        getRootNode: function () { return rootNodeRef.current; },
    }); }, [ref, blur, focus, handleReset, handleRemoveFile]);
    var _z = useState(false), focusedByTab = _z[0], setFocusedByTab = _z[1];
    var handleInputChange = function (event) {
        onChange === null || onChange === void 0 ? void 0 : onChange(event);
        handleChange(event.target.files);
        setHovered(false);
    };
    var handleFocus = function (e) {
        var _a;
        if (!disabled) {
            // focus event fires before keyDown eventlistener
            // so we should check tabPressed in async way
            (_a = globalObject.requestAnimationFrame) === null || _a === void 0 ? void 0 : _a.call(globalObject, function () {
                if (keyListener.isTabPressed) {
                    setFocusedByTab(true);
                }
            });
            onFocus === null || onFocus === void 0 ? void 0 : onFocus(e);
        }
    };
    var handleBlur = function (e) {
        setFocusedByTab(false);
        if (!disabled) {
            onBlur === null || onBlur === void 0 ? void 0 : onBlur(e);
        }
    };
    var hasFiles = files.length > 0;
    var hasOneFile = files.length === 1;
    var hasOneFileForSingle = isSingleMode && hasOneFile && !hideFiles;
    var hasError = !!error || ((_g = files[0]) === null || _g === void 0 ? void 0 : _g.status) === FileUploaderFileStatus.Error;
    var hasWarning = !!warning || ((_h = files[0]) === null || _h === void 0 ? void 0 : _h.status) === FileUploaderFileStatus.Warning;
    var uploadButtonClassNames = cx(jsStyles.uploadButton(theme), jsViewStyles.uploadButton(), sizeClassName, hasOneFileForSingle && jsViewStyles.uploadButtonWithFile(theme), focusedByTab && jsStyles.uploadButtonFocus(theme), disabled && (_a = {},
        _a[jsStyles.disabled(theme)] = true,
        _a[jsStyles.disabledBackground(theme)] = !hasFiles,
        _a), (focusedByTab || !hasOneFileForSingle) && (_b = {},
        _b[jsStyles.warningButton(theme)] = hasWarning,
        _b[jsStyles.errorButton(theme)] = hasError,
        _b), hasOneFileForSingle && (_c = {},
        _c[uploadButtonTileWithFileClassName] = isTileView,
        _c[jsTileStyles.verticalAlign()] = isTileView,
        _c[jsStyles.warningFile(theme)] = (!isTileView || hovered) && hasWarning,
        _c[jsStyles.errorFile(theme)] = (!isTileView || hovered) && hasError,
        _c), !disabled &&
        hovered && (_d = {},
        _d[jsStyles.hovered(theme)] = true,
        _d), isDraggable && !disabled && jsStyles.dragOver(theme));
    var canDrop = isWindowDraggable && !disabled;
    var uploadButtonWrapperClassNames = cx(isTileView && (_e = {},
        _e[sizeWrapperClass] = true,
        _e[sizeWrapperEmptyFileClass] = !hasOneFileForSingle,
        _e), jsViewStyles.uploadButtonWrapper(), canDrop && jsStyles.windowDragOver(theme));
    var uploadButtonIconClassNames = cx(jsStyles.icon(theme), sizeIconClass, disabled && jsStyles.iconDisabled(theme), uploadButtonIconGapClass);
    var rootClassNames = cx(jsStyles.root(theme), !isTileView && jsRowStyles.root());
    var contentClassNames = cx(jsViewStyles.content(), (_f = {},
        _f[jsViewStyles.contentWithFiles()] = hasOneFileForSingle,
        _f[contentInnerClass] = !isTileView && (!files.length || !isSingleMode),
        _f));
    var afterLinkTextClassNames = cx(globalClasses.afterLinkText, hasOneFileForSingle ? jsStyles.afterLinkText_HasFiles() : jsStyles.afterLinkText());
    var linkClassNames = cx(jsStyles.link(theme), !disabled && hovered && jsStyles.linkHovered(theme), disabled && jsStyles.linkDisabled(theme));
    useEffect(function () {
        if (!files || !files.length || !inputRef.current) {
            return;
        }
        var dataTransfer = new DataTransfer();
        files.forEach(function (file) { return dataTransfer.items.add(file.originalFile); });
        inputRef.current.files = dataTransfer.files;
    }, []);
    var rootNodeRef = useRef(null);
    var icon = uploaderIcon !== null && uploaderIcon !== void 0 ? uploaderIcon : React.createElement(UploadIcon, { size: size, view: view });
    var chooseFileText = uploaderText !== null && uploaderText !== void 0 ? uploaderText : locale.chooseFile;
    var chooseFileLocale = "".concat(chooseFileText).concat(String.fromCharCode(0xa0)); /* &nbsp; */
    var hideUploaderText = isTileView && uploaderText === '';
    var renderChooseFileText = function () {
        return !hideUploaderText && (React.createElement("span", { "data-tid": FileUploaderDataTids.link, className: linkClassNames }, !hasOneFileForSingle && chooseFileLocale));
    };
    var renderFileList = function () {
        return (!hideFiles &&
            !isSingleMode &&
            !!files.length && (React.createElement(FileUploaderFileList, { renderFile: renderFile, size: size, view: view, onRemove: handleRemoveFile, validationTooltipPosition: validationTooltipPosition, withValidationTooltip: withValidationTooltip, validationSummary: validationSummary, validationSummaryStart: validationSummaryStart, withWarningIcon: withWarningIcon, disabled: disabled })));
    };
    var fileProps = {
        file: files[0],
        size: size,
        view: view,
        onRemove: handleRemoveFile,
        error: error,
        warning: warning,
        withValidationTooltip: withValidationTooltip,
        validationTooltipPosition: validationTooltipPosition,
        withWarningIcon: withWarningIcon,
        hovered: hovered,
        disabled: disabled,
    };
    var fileElement = renderFile(fileProps);
    return (React.createElement(CommonWrapper, __assign({}, props),
        React.createElement("div", { "data-tid": FileUploaderDataTids.root, className: rootClassNames, style: useMemoObject({ width: isTileView && !multiple ? theme.fileUploaderTileWidth : width }), ref: rootNodeRef },
            uploadButtonPosition === 'end' && renderFileList(),
            React.createElement("div", { className: uploadButtonWrapperClassNames },
                React.createElement("label", { onMouseEnter: function () { return setHovered(true); }, onMouseLeave: function () { return setHovered(false); }, ref: labelRef, className: uploadButtonClassNames },
                    !hasOneFileForSingle && React.createElement("div", { className: uploadButtonIconClassNames }, icon),
                    React.createElement("div", { "data-tid": FileUploaderDataTids.content, className: contentClassNames },
                        renderChooseFileText(),
                        React.createElement("div", { className: afterLinkTextClassNames }, hasOneFileForSingle && (React.createElement("div", { ref: fileDivRef, className: jsStyles.singleFile() }, fileElement)))),
                    React.createElement(FocusControlWrapper, { onBlurWhenDisabled: function () { return setFocusedByTab(false); } },
                        React.createElement("input", __assign({}, inputProps, { "data-tid": FileUploaderDataTids.input, ref: inputRef, tabIndex: disabled ? -1 : 0, type: "file", disabled: disabled, multiple: multiple, className: jsStyles.visuallyHidden(), onClick: stopPropagation, onChange: handleInputChange, onFocus: handleFocus, onBlur: handleBlur }))))),
            uploadButtonPosition === 'start' && renderFileList())));
});
/**
 * `FileUploader` — контрол для выбора пользователем файла на компьютере и отображения статуса его отправки на сервер.
 *
 * Можно использовать для синхронной отправки данных, например, в форме. Или же можно использовать в асинхронном режиме.
 */
export var FileUploader = withFileUploaderControlProvider(React.memo(_FileUploader));
FileUploader.displayName = 'FileUploader';
//# sourceMappingURL=FileUploader.js.map