@rjsf/utils
Version:
Utility functions for @rjsf/core
120 lines • 4.36 kB
JavaScript
'use client';
import { useCallback, useMemo } from 'react';
import dataURItoBlob from './dataURItoBlob.js';
/** Updated the given `dataUrl` to add the `name` to it
*
* @param dataURL - The url description string
* @param name - The name of the file to add to the dataUrl
* @returns - The `dataUrl` updated to include the name
*/
function addNameToDataURL(dataURL, name) {
return dataURL.replace(';base64', `;name=${encodeURIComponent(name)};base64`);
}
/** Returns a promise that will read the file from the browser and return it as the result of the promise.
*
* @param file - The `File` information to read
* @returns - A promise that resolves to the read file.
*/
function processFile(file) {
const { name, size, type } = file;
return new Promise((resolve, reject) => {
const reader = new window.FileReader();
reader.onerror = reject;
reader.onload = (event) => {
var _a;
if (typeof ((_a = event.target) === null || _a === void 0 ? void 0 : _a.result) === 'string') {
resolve({
dataURL: addNameToDataURL(event.target.result, name),
name,
size,
type,
});
}
else {
resolve({
dataURL: null,
name,
size,
type,
});
}
};
reader.readAsDataURL(file);
});
}
/** Reads a list of files from the browser, returning the results of the promises of each individual file read.
*
* @param files - The list of files to read
* @returns - The list of read files
*/
function processFiles(files) {
return Promise.all(Array.from(files).map(processFile));
}
/** Extracts the file information from the data URLs
*
* @param dataURLs - The information about the files
* @returns - The list of `FileInfoType` objects extracted from the data urls
*/
function extractFileInfo(dataURLs) {
return dataURLs.reduce((acc, dataURL) => {
if (!dataURL) {
return acc;
}
try {
const { blob, name } = dataURItoBlob(dataURL);
return [
...acc,
{
dataURL,
name: name,
size: blob.size,
type: blob.type,
},
];
}
catch (_a) {
// Invalid dataURI, so just ignore it.
return acc;
}
}, []);
}
/** Hook which encapsulates the logic needed to read and convert a `value` of `File` or `File[]` into the
* `filesInfo: FileInfoType[]` and the two callback implementations needed to change the list or to remove a
* `File` from the list. To be used by theme specific `FileWidget` implementations.
*
* @param value - The current value of the `FileWidget`
* @param onChange - The onChange handler for the `FileWidget`
* @param [multiple=false] - Flag indicating whether the control supports multiple selections
* @returns - The `UseFileWidgetPropsResult` to be used within a `FileWidget` implementation
*/
export default function useFileWidgetProps(value, onChange, multiple = false) {
const values = useMemo(() => {
if (multiple && value) {
return Array.isArray(value) ? value : [value];
}
return [];
}, [value, multiple]);
const filesInfo = useMemo(() => (Array.isArray(value) ? extractFileInfo(value) : extractFileInfo([value || ''])), [value]);
const handleChange = useCallback((files) => {
processFiles(files).then((filesInfoEvent) => {
const newValue = filesInfoEvent.map((fileInfo) => fileInfo.dataURL || null);
if (multiple) {
onChange(values.concat(...newValue));
}
else {
onChange(newValue[0]);
}
});
}, [values, multiple, onChange]);
const handleRemove = useCallback((index) => {
if (multiple) {
const newValue = values.filter((_, i) => i !== index);
onChange(newValue);
}
else {
onChange(undefined);
}
}, [values, multiple, onChange]);
return { filesInfo, handleChange, handleRemove };
}
//# sourceMappingURL=useFileWidgetProps.js.map