UNPKG

@aokiapp/rjsf-mantine-corporate

Version:

Corporational variant of theme, based on @aokiapp/rjsf-mantine-theme

223 lines (220 loc) 7.49 kB
import { jsx, jsxs } from 'react/jsx-runtime'; import { createContext, useCallback, useMemo, useContext } from 'react'; import { getTemplate, descriptionId, dataURItoBlob } from '@rjsf/utils'; import { Stack, Text, Group, Card, AspectRatio, Badge, CloseButton, Image, Box } from '@mantine/core'; import { Dropzone } from '@mantine/dropzone'; import { IconFile, IconFileDigit, IconCode, IconFileTypeTxt, IconFileZip, IconPhoto, IconPdf } from '@tabler/icons-react'; function addNameToDataURL(dataURL, name) { if (dataURL === null) { return null; } return dataURL.replace(";base64", `;name=${encodeURIComponent(name)};base64`); } function processFile(file) { const { name, size, type } = file; return new Promise((resolve, reject) => { const reader = new window.FileReader(); reader.onerror = reject; reader.onload = (event) => { if (typeof event.target?.result === "string") { resolve({ dataURL: addNameToDataURL(event.target.result, name), name, size, type }); } else { resolve({ dataURL: null, name, size, type }); } }; reader.readAsDataURL(file); }); } function processFiles(files) { return Promise.all(files.map(processFile)); } const fileInfoCtx = createContext(null); function FileInfoPreview({ fileInfo }) { const { preview } = useContext(fileInfoCtx); const { dataURL, type, name } = fileInfo; if (!dataURL) { return null; } if (preview && type.indexOf("image") !== -1) { return /* @__PURE__ */ jsx(Image, { src: dataURL, alt: name }); } let IconComponent; switch (type) { case "application/pdf": case "application/x-pdf": IconComponent = IconPdf; break; case "image/svg+xml": case "image/svg": IconComponent = IconFile; break; case "image/png": case "image/jpeg": case "image/gif": case "image/bmp": IconComponent = IconPhoto; break; case "application/zip": case "application/x-zip-compressed": case "application/x-gzip": case "application/x-tar": case "application/x-bzip": case "application/x-bzip2": case "application/x-7z-compressed": case "application/x-rar-compressed": IconComponent = IconFileZip; break; case "text/plain": IconComponent = IconFileTypeTxt; break; case "text/html": case "application/xhtml+xml": case "application/xml": case "application/json": case "application/javascript": IconComponent = IconCode; break; case "application/octet-stream": IconComponent = IconFileDigit; break; default: IconComponent = IconFile; break; } return /* @__PURE__ */ jsxs( Box, { style: { width: "100%", height: "100%", display: "flex", alignItems: "center", justifyContent: "center", flexDirection: "column" }, children: [ /* @__PURE__ */ jsx(IconComponent, { size: 30 }), /* @__PURE__ */ jsx(Badge, { variant: "outline", children: type }) ] } ); } function convertUnitPrefix(size) { const prefixes = ["B", "KB", "MB", "GB", "TB"]; const index = Math.floor(Math.log(size) / Math.log(1024)); return `${(size / Math.pow(1024, index)).toFixed(2)} ${prefixes[index]}`; } function FilesInfo() { const { filesInfo, onRemove } = useContext(fileInfoCtx); if (filesInfo.length === 0) { return null; } return /* @__PURE__ */ jsx(Group, { m: "sm", children: filesInfo.map((fileInfo, key) => { const { name, size } = fileInfo; const rmFile = () => onRemove(key); return /* @__PURE__ */ jsxs(Card, { shadow: "sm", padding: "xs", radius: "md", w: 200, withBorder: true, children: [ /* @__PURE__ */ jsx(Card.Section, { children: /* @__PURE__ */ jsx(AspectRatio, { ratio: 2, maw: 240, mx: "auto", children: /* @__PURE__ */ jsx(FileInfoPreview, { fileInfo }) }) }), /* @__PURE__ */ jsx(Text, { fw: 600, truncate: "end", children: name }), /* @__PURE__ */ jsxs(Group, { gap: "xs", justify: "space-between", children: [ /* @__PURE__ */ jsx(Badge, { color: "blue", variant: "light", children: convertUnitPrefix(size) }), /* @__PURE__ */ jsx(CloseButton, { onClick: rmFile }) ] }) ] }, key); }) }); } function extractFileInfo(dataURLs) { return dataURLs.filter((dataURL) => dataURL).map((dataURL) => { const { blob, name } = dataURItoBlob(dataURL); return { dataURL, name, size: blob.size, type: blob.type }; }); } function FileWidget(props) { const { disabled, readonly, required, multiple, onChange, value, options, registry, schema, hideLabel, label, id } = props; const TitleFieldTemplate = getTemplate("TitleFieldTemplate", registry, options); const DescriptionFieldTemplate = getTemplate( "DescriptionFieldTemplate", registry, options ); const handleChange = useCallback( (files) => { if (!files || files.length === 0) { return; } processFiles(files).then((filesInfoEvent) => { const newValue = filesInfoEvent.map((fileInfo) => fileInfo.dataURL); if (multiple) { onChange(value.filter((e) => !!e).concat(newValue[0])); } else { onChange(newValue[0]); } }); }, [multiple, value, onChange] ); const filesInfo = useMemo(() => extractFileInfo(Array.isArray(value) ? value : [value]), [value]); const rmFile = useCallback( (index) => { if (multiple) { const newValue = value.filter((_, i) => i !== index); onChange(newValue); } else { onChange(void 0); } }, [multiple, value, onChange] ); let accept = options.accept ?? void 0; if (accept && !Array.isArray(accept) && typeof accept !== "object") { console.warn("accept must be string[] or Record<string, string[]>. ignoring..."); accept = void 0; } const description = options.description || schema.description; return /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs(fileInfoCtx.Provider, { value: { filesInfo, onRemove: rmFile, preview: options.filePreview ?? true }, children: [ label && !hideLabel && /* @__PURE__ */ jsx(TitleFieldTemplate, { id, title: label, required, schema, registry }), description && !hideLabel && /* @__PURE__ */ jsx( DescriptionFieldTemplate, { id: descriptionId(id), description: props.description, registry, schema } ), /* @__PURE__ */ jsx( Dropzone, { accept, onDrop: handleChange, disabled: disabled || readonly, maxSize: ( // @ts-expect-error strict type check rarely need for this easy case, as long as the schema is correct options.maxSize || schema.maxLength || schema.items?.maxLength ), multiple, children: /* @__PURE__ */ jsxs(Stack, { gap: "0", align: "center", children: [ /* @__PURE__ */ jsx(Text, { size: "xl", fw: 700, children: "\u30D5\u30A1\u30A4\u30EB\u3092\u30C9\u30ED\u30C3\u30D7\u3057\u3066\u304F\u3060\u3055\u3044" }), /* @__PURE__ */ jsx(Text, { size: "sm", children: "\u307E\u305F\u306F\u3001\u30D5\u30A1\u30A4\u30EB\u3092\u9078\u629E\u3059\u308B" }) ] }) } ), /* @__PURE__ */ jsx(FilesInfo, {}) ] }) }); } export { FileWidget as default }; //# sourceMappingURL=FileWidget.mjs.map