UNPKG

@react-md/form

Version:

This package is for creating all the different form input types.

388 lines 13.9 kB
var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); import { nanoid } from "nanoid"; /** * An error that will be created if a user tries dragging and dropping files * from a shared directory that they do not have access to. This error will not * occur much. * * @remarks \@since 2.9.0 */ var FileAccessError = /** @class */ (function (_super) { __extends(FileAccessError, _super); /** * * @param message - An optional message for the error. */ function FileAccessError(message) { var _this = _super.call(this, message) || this; _this.key = nanoid(); _this.name = "FileAccessError"; return _this; } return FileAccessError; }(Error)); export { FileAccessError }; /** * An error that just requires a `File` to be passed as the first argument. * * @remarks \@since 2.9.0 */ var GenericFileError = /** @class */ (function (_super) { __extends(GenericFileError, _super); /** * * @param files - A list of files that caused the error. * @param reason - An optional reason for the error */ function GenericFileError(files, reason) { var _this = _super.call(this, "Invalid files") || this; _this.files = files; _this.reason = reason; _this.key = nanoid(); _this.name = "GenericFileError"; return _this; } return GenericFileError; }(Error)); export { GenericFileError }; /** * An error that is created during the upload process if the number of files * exceeds the {@link FileUploadOptions.maxFiles} amount. * * @remarks \@since 2.9.0 */ var TooManyFilesError = /** @class */ (function (_super) { __extends(TooManyFilesError, _super); /** * * @param files - The list of files that could not be uploaded due to the file * limit defined. * @param limit - The max limit of files allowed. */ function TooManyFilesError(files, limit) { var _this = _super.call(this, files, "file limit") || this; _this.limit = limit; _this.name = "TooManyFilesError"; return _this; } return TooManyFilesError; }(GenericFileError)); export { TooManyFilesError }; /** * An error that will be created if a user tries to upload a file that * is either: * - less than the {@link FileValidationOptions.minFileSize} * - greater than the {@link FileValidationOptions.maxFileSize} * - including the file would be greater than the {@link FileValidationOptions.totalFileSize} * * @remarks \@since 2.9.0 */ var FileSizeError = /** @class */ (function (_super) { __extends(FileSizeError, _super); /** * * @param files - The list of files that have the file size error * @param type - The file size error type * @param limit - The number of bytes allowed based on the type */ function FileSizeError(files, type, limit) { var _this = _super.call(this, files, "file size") || this; _this.type = type; _this.limit = limit; _this.name = "FileSizeError"; return _this; } return FileSizeError; }(GenericFileError)); export { FileSizeError }; /** * An error that will be created if a user tries to upload a file that does not * end with one of the {@link FileValidationOptions.extensions}. * * @remarks \@since 2.9.0 */ var FileExtensionError = /** @class */ (function (_super) { __extends(FileExtensionError, _super); /** * * @param files - The file that caused the error * @param extensions - The allowed list of file extensions */ function FileExtensionError(files, extensions) { var _this = _super.call(this, files, "extension") || this; _this.extensions = extensions; _this.name = "FileExtensionError"; return _this; } return FileExtensionError; }(GenericFileError)); export { FileExtensionError }; /** * A simple type-guard that can be used to check if the * {@link FileValidationError} is the {@link GenericFileError} which can be * useful when displaying the errors to the user. * * @param error - The error to check * @returns true if the error is a {@link FileAccessError} */ export function isGenericFileError(error) { return "name" in error && error.name === "GenericFileError"; } /** * A simple type-guard that can be used to check if the * {@link FileValidationError} is the {@link FileAccessError} which can be * useful when displaying the errors to the user. * * @param error - The error to check * @returns true if the error is a {@link FileAccessError} */ export function isFileAccessError(error) { return "name" in error && error.name === "FileAccessError"; } /** * A simple type-guard that can be used to check if the * {@link FileValidationError} is the {@link TooManyFilesError} which can be * useful when displaying the errors to the user. * * @param error - The error to check * @returns true if the error is a {@link TooManyFilesError} */ export function isTooManyFilesError(error) { return "name" in error && error.name === "TooManyFilesError"; } /** * A simple type-guard that can be used to check if the * {@link FileValidationError} is the {@link FileSizeError} which can be * useful when displaying the errors to the user. * * @param error - The error to check * @returns true if the error is a {@link FileSizeError} */ export function isFileSizeError(error) { return "name" in error && error.name === "FileSizeError"; } /** * A simple type-guard that can be used to check if the * {@link FileValidationError} is the {@link FileExtensionError} which can be * useful when displaying the errors to the user. * * @param error - The error to check * @returns true if the error is a {@link FileExtensionError} */ export function isFileExtensionError(error) { return "name" in error && error.name === "FileExtensionError"; } /** * * @defaultValue `matcher?.test(file.name) ?? true` * @remarks \@since 3.1.0 */ export var isValidFileName = function (file, matcher) { var _a; return (_a = matcher === null || matcher === void 0 ? void 0 : matcher.test(file.name)) !== null && _a !== void 0 ? _a : true; }; /** * A pretty decent default implementation for validating files with the * {@link useFileUpload} that ensures the {@link FilesValidationOptions} are * enforced before allowing a file to be uploaded. * * @typeparam E - An optional custom file validation error. * @param files - The list of files to check * @param options - The {@link FilesValidationOptions} * @returns the {@link ValidatedFilesResult} * @remarks \@since 2.9.0 */ export function validateFiles(files, _a) { var maxFiles = _a.maxFiles, extensions = _a.extensions, minFileSize = _a.minFileSize, maxFileSize = _a.maxFileSize, totalBytes = _a.totalBytes, totalFiles = _a.totalFiles, totalFileSize = _a.totalFileSize, isValidFileName = _a.isValidFileName; var errors = []; var pending = []; var extraFiles = []; var extensionRegExp = extensions.length > 0 ? new RegExp("\\.(".concat(extensions.join("|"), ")$"), "i") : undefined; var maxFilesReached = maxFiles > 0 && totalFiles >= maxFiles; var remainingBytes = totalFileSize - totalBytes; var extensionErrors = []; var minErrors = []; var maxErrors = []; var totalSizeErrors = []; for (var i = 0; i < files.length; i += 1) { var file = files[i]; var valid = true; var size = file.size; if (!isValidFileName(file, extensionRegExp, extensions)) { valid = false; extensionErrors.push(file); } if (minFileSize > 0 && size < minFileSize) { valid = false; minErrors.push(file); } if (maxFileSize > 0 && size > maxFileSize) { valid = false; maxErrors.push(file); } else if (totalFileSize > 0 && remainingBytes - file.size < 0) { // don't want both errors displaying valid = false; totalSizeErrors.push(file); } if (maxFilesReached && valid) { extraFiles.push(file); } else if (!maxFilesReached && valid) { pending.push(file); remainingBytes -= file.size; maxFilesReached = maxFilesReached || (maxFiles > 0 && totalFiles + pending.length >= maxFiles); } } if (extensionErrors.length) { errors.push(new FileExtensionError(extensionErrors, extensions)); } if (minErrors.length) { errors.push(new FileSizeError(minErrors, "min", minFileSize)); } if (maxErrors.length) { errors.push(new FileSizeError(maxErrors, "max", maxFileSize)); } if (totalSizeErrors.length) { errors.push(new FileSizeError(totalSizeErrors, "total", totalFileSize)); } if (extraFiles.length) { errors.push(new TooManyFilesError(extraFiles, maxFiles)); } return { pending: pending, errors: errors }; } /** * This will first check if the mime-type of the file starts with `text/` and * fallback to checking a few file names or extensions that should be considered * text. * * This function is not guaranteed to be 100% correct and is only useful if * trying to generate a preview of files uploaded to the browser. * * @param file - The file to check * @returns `true` if the file should be considered as a text-content file. * @remarks \@since 2.9.0 */ export function isTextFile(file) { return /\.((j|t)sx?|json|lock|hbs|ya?ml|log|txt|md)$/i.test(file.name); } /** * This will first check if the mime-type of the file starts with `text\/` and * fallback to checking a few file names or extensions that should be considered * text. * * This function is not guaranteed to be 100% correct and is only useful if * trying to generate a preview of files uploaded to the browser. * * @param file - The file to check * @returns `true` if the file should be considered as a text content file. * @remarks \@since 2.9.0 */ export function isImageFile(file) { return /\.(a?png|avif|svg|tiff|gifv?|jpe?g)/i.test(file.name); } /** * This will first check if the mime-type of the file starts with `audio/` and * fallback to checking a few file names or extensions that should be considered * audio. * * This function is not guaranteed to be 100% correct and is only useful if * trying to generate a preview of files uploaded to the browser. * * @param file - The file to check * @returns `true` if the file should be considered as a audio content file. * @remarks \@since 2.9.0 */ export function isAudioFile(file) { return /\.(mp3|wav|ogg|m4p|flac)$/i.test(file.name); } /** * This will first check if the mime-type of the file starts with `video/` and * fallback to checking a few file names or extensions that should be considered * video. * * This function is not guaranteed to be 100% correct and is only useful if * trying to generate a preview of files uploaded to the browser. * * @param file - The file to check * @returns `true` if the file should be considered as a video content file. * @remarks \@since 2.9.0 */ export function isVideoFile(file) { return /\.(mkv|mpe?g|mov|avi|flv|webm|mp4)$/i.test(file.name); } /** * This function is not guaranteed to be 100% correct and is only useful if * trying to generate a preview of files uploaded to the browser. * * @param file - The file to check * @returns `true` if the file matches an image, audio, or video file. * @remarks \@since 2.9.0 */ export function isMediaFile(file) { return isImageFile(file) || isAudioFile(file) || isVideoFile(file); } /** * This function will attempt to read: * - media (image, audio, and video) files as a data url so they can be * previewed in `<img>`, `<audio>`, and `<video>` tags * - text files as plain text * - everything else as an `ArrayBuffer` which can be manually converted into a * data url if needed with `URL.createObjectURL` * * @remarks \@since 2.9.0 */ export var getFileParser = function (file) { if (isMediaFile(file)) { return "readAsDataURL"; } if (isTextFile(file)) { return "readAsText"; } return "readAsArrayBuffer"; }; /** * This util will split all the current upload stats by status. * * @param stats - The {@link FileUploadStats} list generally returned by the * {@link useFileUpload} hook. * @returns the {@link SplitFileUploads}. * @remarks \@since 2.9.0 */ export function getSplitFileUploads(stats) { var pending = []; var uploading = []; var complete = []; stats.forEach(function (stat) { if (stat.status === "pending") { pending.push(stat); } else if (stat.status === "uploading") { uploading.push(stat); } else if (stat.status === "complete") { complete.push(stat); } else { /* istanbul ignore next */ throw new Error("Invalid upload stat"); } }); return { pending: pending, uploading: uploading, complete: complete }; } //# sourceMappingURL=utils.js.map