@kwiz/fluentui
Version:
KWIZ common controls for FluentUI
129 lines • 6.92 kB
JavaScript
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());
});
};
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
import { makeStyles, shorthands, tokens } from "@fluentui/react-components";
import { ArrowUploadRegular } from "@fluentui/react-icons";
import { isFunction, isNotEmptyArray, isNotEmptyString, isNullOrEmptyString, lastOrNull } from '@kwiz/common';
import * as React from "react";
import { useDragDropContext, useEffectOnlyOnMount } from "../helpers";
import { ButtonEX, CompoundButtonEXSecondary } from "./button";
const useStyles = makeStyles({
addRowIsOver: Object.assign({}, shorthands.borderColor(tokens.colorBrandBackground))
});
export const FileUpload = React.forwardRef((props, ref) => {
const classes = useStyles();
const hiddenFileInput = React.useRef(null);
const onChangeRef = React.useRef(props.onChange);
const asBase64Ref = React.useRef(props.asBase64);
const isMulti = props.allowMultiple === true;
const icon = props.icon || _jsx(ArrowUploadRegular, {});
const title = isNotEmptyString(props.title) ? props.title : `Drop or select ${isMulti ? 'files' : 'file'}`;
//keep onChange up to date
React.useEffect(() => {
onChangeRef.current = props.onChange;
}, [props.onChange]);
//keep onChange up to date
React.useEffect(() => {
asBase64Ref.current = props.asBase64;
}, [props.asBase64]);
const onGotFiles = React.useCallback((rawFiles) => __awaiter(void 0, void 0, void 0, function* () {
var _a, _b, _c;
let errors = [];
let acceptedFiles = [];
if (rawFiles && rawFiles.length > 0) {
//filter by types and size
for (let i = 0; i < (isMulti ? rawFiles.length : 1); i++) {
const currentFile = rawFiles[i];
let hadError = false;
if (props.fileSizeLimit > 0) {
const megabytes = currentFile.size / (1024 * 1024);
if (megabytes > props.fileSizeLimit) {
errors.push(`File ${currentFile.name} is over the size limit`);
hadError = true;
}
}
if (!hadError) {
if (isNotEmptyArray(props.limitFileTypes)) {
let fileType = lastOrNull(currentFile.name.split('.')).toLowerCase();
if (props.limitFileTypes.indexOf(fileType) < 0) {
errors.push(`File ${currentFile.name} is not allowed`);
hadError = true;
}
}
}
if (!hadError)
acceptedFiles.push(currentFile);
}
}
if (isMulti) {
(_a = onChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onChangeRef, acceptedFiles, errors);
}
else {
const fileUploaded = acceptedFiles[0];
(_b = onChangeRef.current) === null || _b === void 0 ? void 0 : _b.call(onChangeRef, fileUploaded, errors);
}
if (isFunction(asBase64Ref.current)) {
const filesAs64 = [];
for (let i = 0; i < (isMulti ? acceptedFiles.length : 1); i++) {
const currentFile = acceptedFiles[i];
let hadError = false;
if (props.fileSizeLimit > 0) {
const megabytes = currentFile.size / (1024 * 1024);
if (megabytes > props.fileSizeLimit) {
errors.push(`File ${currentFile.name} is over the size limit`);
hadError = true;
}
}
if (!hadError) {
let as64 = yield getFileAsBase64(acceptedFiles[i]);
if (as64)
filesAs64.push(as64);
else
errors.push(`Could not read file ${acceptedFiles[i].name}`);
}
}
(_c = asBase64Ref.current) === null || _c === void 0 ? void 0 : _c.call(asBase64Ref, filesAs64, errors);
}
}), useEffectOnlyOnMount);
const dropContext = useDragDropContext({
dropInfo: {
acceptTypes: ["__NATIVE_FILE__"],
onItemDrop: item => {
onGotFiles(item.files);
}
}
});
return _jsxs(_Fragment, { children: [isNullOrEmptyString(props.secondaryContent)
? _jsx(ButtonEX, Object.assign({ ref: ref || dropContext.dragDropRef }, (props.buttonProps || {}), { icon: icon, showTitleWithIcon: props.showTitleWithIcon, onClick: () => {
hiddenFileInput.current.value = "";
hiddenFileInput.current.click();
}, title: title, disabled: props.disabled, className: dropContext.drop.isOver && classes.addRowIsOver }))
: _jsx(CompoundButtonEXSecondary, Object.assign({ ref: ref || dropContext.dragDropRef }, (props.buttonProps || {}), { icon: icon, secondaryContent: props.secondaryContent, onClick: () => {
hiddenFileInput.current.value = "";
hiddenFileInput.current.click();
}, title: title, disabled: props.disabled, className: dropContext.drop.isOver && classes.addRowIsOver })), _jsx("input", { type: "file", ref: hiddenFileInput, style: { display: "none" }, multiple: isMulti, accept: isNotEmptyArray(props.limitFileTypes) ? props.limitFileTypes.map(ft => `.${ft}`).join() : undefined, onChange: (e) => __awaiter(void 0, void 0, void 0, function* () { return onGotFiles(e.target.files); }) })] });
});
function getFileAsBase64(file) {
return __awaiter(this, void 0, void 0, function* () {
return new Promise(resolve => {
const reader = new FileReader();
reader.onloadend = () => {
if (!isNullOrEmptyString(reader.result))
resolve({ filename: file.name, base64: reader.result });
else {
console.warn("Empty file selected");
resolve(null);
}
};
reader.readAsDataURL(file);
});
});
}
//# sourceMappingURL=file-upload.js.map