You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
246 lines
9.0 KiB
246 lines
9.0 KiB
"use strict";
|
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
if (k2 === undefined) k2 = k;
|
|
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
}) : (function(o, m, k, k2) {
|
|
if (k2 === undefined) k2 = k;
|
|
o[k2] = m[k];
|
|
}));
|
|
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
}) : function(o, v) {
|
|
o["default"] = v;
|
|
});
|
|
var __importStar = (this && this.__importStar) || function (mod) {
|
|
if (mod && mod.__esModule) return mod;
|
|
var result = {};
|
|
if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
__setModuleDefault(result, mod);
|
|
return result;
|
|
};
|
|
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;
|
|
};
|
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
};
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.DropZone = void 0;
|
|
const react_1 = __importStar(require("react"));
|
|
const styled_components_1 = __importDefault(require("styled-components"));
|
|
const label_1 = require("../../atoms/label");
|
|
const box_1 = require("../../atoms/box");
|
|
const text_1 = require("../../atoms/text");
|
|
const message_box_1 = require("../message-box");
|
|
const drop_zone_item_1 = require("./drop-zone-item");
|
|
const human_file_size_1 = require("../../utils/human-file-size");
|
|
const validateContentType = (mimeTypes, mimeType) => {
|
|
if (!mimeTypes || !mimeTypes.length) {
|
|
return true;
|
|
}
|
|
return mimeTypes.includes(mimeType);
|
|
};
|
|
const validateSize = (maxSize, size) => {
|
|
if (!maxSize) {
|
|
return true;
|
|
}
|
|
if (!size) {
|
|
return true;
|
|
}
|
|
return +maxSize >= +size;
|
|
};
|
|
const inUnit = (size, unit) => {
|
|
if (!size) {
|
|
return '';
|
|
}
|
|
return human_file_size_1.humanFileSize(size, unit);
|
|
};
|
|
const UploadInput = styled_components_1.default.input `
|
|
font-size: 100px;
|
|
position: absolute;
|
|
left: 0;
|
|
top: 0;
|
|
opacity: 0;
|
|
bottom: 0;
|
|
cursor: pointer;
|
|
width: 100%;
|
|
`;
|
|
const StyledDropZone = styled_components_1.default(box_1.Box) `
|
|
border: 1px dashed ${({ theme }) => theme.colors.grey80};
|
|
position: relative;
|
|
text-align: center;
|
|
|
|
& ${label_1.Label} {
|
|
color: ${({ theme }) => theme.colors.grey60};
|
|
font-size: ${({ theme }) => theme.fontSizes.xs};
|
|
padding-right: 4px;
|
|
letter-spacing: 1px;
|
|
}
|
|
`;
|
|
/**
|
|
* @classdesc
|
|
*
|
|
* <img src="components/drop-zone.png" />
|
|
*
|
|
* DropZone which can be used for uploading files.
|
|
*
|
|
* ### usage
|
|
*
|
|
* ```javascript
|
|
* import { DropZone, DropZoneProps } from '@adminjs/design-system'
|
|
* ```
|
|
*
|
|
* how to use it in your custom component.tsx (TypesScript):
|
|
* ```
|
|
* import React, { useState } from 'react'
|
|
* import { DropZone, Label, BasePropertyProps } from '@adminjs/design-system'
|
|
* import { unflatten } from 'flat'
|
|
*
|
|
* const UploadPhoto: React.FC<BasePropertyProps> = (props) => {
|
|
* const { property, record, onChange } = props
|
|
*
|
|
* const onUpload = (files: FileList) => {
|
|
* const newRecord = {...record}
|
|
* const file = files.length && files[0]
|
|
*
|
|
* onChange({
|
|
* ...newRecord,
|
|
* params: {
|
|
* ...newRecord.params,
|
|
* [property.name]: file,
|
|
* }
|
|
* })
|
|
* event.preventDefault()
|
|
* }
|
|
*
|
|
* return (
|
|
* <Box>
|
|
* <Label>{property.label}</Label>
|
|
* <DropZone onChange={onUpload} />
|
|
* </Box>
|
|
* )
|
|
* }
|
|
* ```
|
|
* @hideconstructor
|
|
* @component
|
|
* @subcategory Molecules
|
|
* @see FileSizeUnit
|
|
* @see OnDropDownChange
|
|
* @see DropZoneProps
|
|
* @see {@link https://storybook.adminjs.co/?path=/story/designsystem-molecules-dropzone--default Storybook}
|
|
* @example <caption>Single file with validation</caption>
|
|
* const maxSize = 1024 * 100
|
|
* const mimeTypes = ['application/pdf']
|
|
* const onUpload = (files) => { alert(files,length ? files[0].name : 'no files' ) }
|
|
* return (
|
|
* <Box>
|
|
* <DropZone
|
|
* onChange={onUpload}
|
|
* validate= { { maxSize, mimeTypes } }
|
|
* />
|
|
* </Box>
|
|
* )
|
|
*
|
|
* @example <caption>Multi file of photos</caption>
|
|
* const mimeTypes = ['image/png']
|
|
* const onUpload = (files) => { alert(files.length ? files.length : 'no files' ) }
|
|
* return (
|
|
* <Box>
|
|
* <DropZone
|
|
* multiple
|
|
* onChange={onUpload}
|
|
* validate= { { mimeTypes } }
|
|
* />
|
|
* </Box>
|
|
* )
|
|
* @section design-system
|
|
*/
|
|
const DropZone = (props) => {
|
|
const { validate, onChange, multiple, files: filesFromProps, uploadLimitIn } = props, other = __rest(props, ["validate", "onChange", "multiple", "files", "uploadLimitIn"]);
|
|
const [, setIsDragging] = react_1.useState(false);
|
|
const [error, setError] = react_1.useState(null);
|
|
const [filesToUpload, setFilesToUpload] = react_1.useState(filesFromProps !== null && filesFromProps !== void 0 ? filesFromProps : []);
|
|
react_1.useEffect(() => {
|
|
if (filesFromProps) {
|
|
setFilesToUpload(filesFromProps);
|
|
}
|
|
}, [filesFromProps]);
|
|
const onDragEnter = () => setIsDragging(true);
|
|
const onDragLeave = () => setIsDragging(false);
|
|
const onDragOver = () => setIsDragging(true);
|
|
const removeItem = react_1.useCallback((index) => {
|
|
const newItems = [...filesToUpload];
|
|
newItems.splice(index, 1);
|
|
if (onChange) {
|
|
onChange(newItems);
|
|
}
|
|
setFilesToUpload(newItems);
|
|
}, [filesToUpload, setFilesToUpload, onChange]);
|
|
const onDrop = react_1.useCallback((event) => {
|
|
event.preventDefault();
|
|
setIsDragging(false);
|
|
const { files } = (event.dataTransfer || event.target);
|
|
const validatedFiles = [];
|
|
for (let i = 0; i < files.length; i += 1) {
|
|
const file = files.item(i);
|
|
if (!file) {
|
|
return;
|
|
}
|
|
if (validate && !validateSize(validate.maxSize, file && file.size)) {
|
|
setError({ message: `File: ${file.name} size is too big`, title: 'Wrong Size' });
|
|
return;
|
|
}
|
|
if (validate && !validateContentType(validate.mimeTypes, file.type)) {
|
|
setError({ message: `File: ${file.name} has unsupported type: ${file.type}`, title: 'Wrong Type' });
|
|
return;
|
|
}
|
|
validatedFiles.push(file);
|
|
setError(null);
|
|
}
|
|
let newFiles;
|
|
if (!multiple && validatedFiles.length) {
|
|
newFiles = [validatedFiles[0]];
|
|
}
|
|
else {
|
|
newFiles = [
|
|
...filesToUpload,
|
|
...validatedFiles,
|
|
];
|
|
}
|
|
if (onChange) {
|
|
onChange(newFiles);
|
|
}
|
|
setFilesToUpload(newFiles);
|
|
}, [onChange, setFilesToUpload, setIsDragging]);
|
|
const displayUploadLimit = react_1.useCallback(() => {
|
|
if (validate && validate.maxSize) {
|
|
return inUnit(validate.maxSize, uploadLimitIn);
|
|
}
|
|
return '';
|
|
}, [validate]);
|
|
return (react_1.default.createElement(box_1.Box, null,
|
|
react_1.default.createElement(StyledDropZone, Object.assign({ onDragEnter: onDragEnter, onDragOver: onDragOver, onDragLeave: onDragLeave, onDrop: onDrop }, other, { p: "xl" }),
|
|
react_1.default.createElement(UploadInput, { type: "file", onChange: (event) => onDrop(event), multiple: multiple }),
|
|
react_1.default.createElement(box_1.Box, null,
|
|
react_1.default.createElement(text_1.Text, { fontSize: "sm" }, "Pick or Drop File here to upload it."),
|
|
react_1.default.createElement(box_1.Box, null,
|
|
validate && validate.maxSize ? (react_1.default.createElement(text_1.Text, { variant: "xs", color: "grey60", lineHeight: "default", mt: "sm" },
|
|
react_1.default.createElement(label_1.Label, { inline: true, uppercase: true }, "Max size:"),
|
|
displayUploadLimit())) : '',
|
|
validate && validate.mimeTypes && validate.mimeTypes.length ? (react_1.default.createElement(text_1.Text, { variant: "xs", color: "grey60", lineHeight: "default", mt: "sm" }, validate.mimeTypes.join(', '))) : ''))),
|
|
error ? (react_1.default.createElement(message_box_1.MessageBox, { mt: "default", variant: "danger", size: "sm", icon: "Warning", message: error.title, onCloseClick: () => setError(null) }, error.message)) : '',
|
|
filesToUpload.map((file, index) => (
|
|
// eslint-disable-next-line react/no-array-index-key
|
|
react_1.default.createElement(drop_zone_item_1.DropZoneItem, { file: file, key: index, onRemove: () => removeItem(index) })))));
|
|
};
|
|
exports.DropZone = DropZone;
|
|
exports.default = DropZone;
|