UNPKG

@kwiz/fluentui

Version:

KWIZ common controls for FluentUI

129 lines 6.92 kB
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