mui-dynamic-field
Version:
A dynamic and customizable input field component for React, built with Material UI & TypeScript.
1,590 lines (1,537 loc) • 179 kB
JavaScript
'use strict';
var material = require('@mui/material');
var React = require('react');
var Visibility = require('@mui/icons-material/Visibility');
var VisibilityOff = require('@mui/icons-material/VisibilityOff');
var jsxRuntime = require('react/jsx-runtime');
var CloseIcon = require('@mui/icons-material/Close');
var VolumeOffIcon = require('@mui/icons-material/VolumeOff');
var HeadsetIcon = require('@mui/icons-material/Headset');
var DescriptionIcon = require('@mui/icons-material/Description');
var LaunchIcon = require('@mui/icons-material/Launch');
var BrokenImageIcon = require('@mui/icons-material/BrokenImage');
var DeleteIcon = require('@mui/icons-material/Delete');
var PictureAsPdfIcon = require('@mui/icons-material/PictureAsPdf');
var ArrowBackIcon = require('@mui/icons-material/ArrowBack');
var ArrowForwardIcon = require('@mui/icons-material/ArrowForward');
var VideocamOffIcon = require('@mui/icons-material/VideocamOff');
var PlayCircleIcon = require('@mui/icons-material/PlayCircle');
var ImageIcon = require('@mui/icons-material/Image');
var CloudUploadIcon = require('@mui/icons-material/CloudUpload');
var DoneIcon = require('@mui/icons-material/Done');
var FlipIcon = require('@mui/icons-material/Flip');
var FlipCameraIcon = require('@mui/icons-material/FlipCameraAndroid');
var Menu = require('@mui/material/Menu');
var MenuItem = require('@mui/material/MenuItem');
var emStyled = require('@emotion/styled');
var react = require('@emotion/react');
var ReplayIcon = require('@mui/icons-material/Replay');
function _interopNamespaceDefault(e) {
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n.default = e;
return Object.freeze(n);
}
var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
const PasswordInput = props => {
const {
color,
name,
error,
errorText,
label,
value,
onChange,
disabled,
size,
slotProps,
...restProps
} = props;
const [showPassword, setShowPassword] = React.useState(false);
const toggleShowPassword = () => setShowPassword(!showPassword);
return /*#__PURE__*/jsxRuntime.jsx(material.TextField, {
type: showPassword ? "text" : "password",
fullWidth: true,
color: color,
error: error,
helperText: errorText,
label: label,
name: name,
disabled: disabled,
variant: "outlined",
value: value ?? "",
onChange: onChange,
size: size,
onWheel: e => e.target.blur(),
slotProps: {
...slotProps,
input: {
...(slotProps?.input || {}),
endAdornment: /*#__PURE__*/jsxRuntime.jsx(material.IconButton, {
onClick: toggleShowPassword,
children: showPassword ? /*#__PURE__*/jsxRuntime.jsx(VisibilityOff, {}) : /*#__PURE__*/jsxRuntime.jsx(Visibility, {})
})
}
},
...restProps
});
};
const getUpdatedKey = _key => `updated_${_key}`;
const getErrorKey = _key => `er_${_key}`;
const getErrorText = _key => `er_txt_${_key}`;
const validateFields = ({
_state,
fields,
getLocalizedText,
customFunctions,
ignoreFields
}) => {
let isValid = true;
const updatedState = {
..._state
};
// Helper to set an error message
const setError = (_key, message, localizedKey, localizedParams) => {
isValid = false;
updatedState[getErrorKey(_key)] = true;
updatedState[getErrorText(_key)] = getLocalizedText && localizedKey ? getLocalizedText(localizedKey, localizedParams) : message;
};
fields.forEach(({
isOptional,
regex,
_key,
dependent,
minLength,
maxLength,
min,
max,
placeholder,
hidden
}) => {
const fieldValue = updatedState[_key];
// Skip if _key is in ignoreFields
if (ignoreFields?.includes(_key) || hidden) return;
// Skip validation if the field is optional and empty
if (!fieldValue && isOptional || !_key) return;
// Skip validation if the field has a dependency that isn't met
if (dependent && updatedState[dependent._key] !== dependent.value) return;
// Handle array fields
if (Array.isArray(fieldValue) && fieldValue.length) {
updatedState[getErrorKey(_key)] = false;
updatedState[getErrorText(_key)] = "";
return;
}
if (Array.isArray(fieldValue) && !fieldValue.length) {
setError(_key, `${placeholder || "Field"} is required`, "placeholderIsRequired", {
placeholder: getLocalizedText?.(placeholder || "field")
});
return;
}
// Handle required fields
if (fieldValue === undefined || fieldValue === null) {
setError(_key, `${placeholder || "Field"} is required`, "placeholderIsRequired", {
placeholder: getLocalizedText?.(placeholder || "field")
});
return;
}
// Handle min/max length validation
if (typeof fieldValue === "string") {
if (minLength && fieldValue.length < minLength || min && fieldValue.length < min) {
setError(_key, `Minimum length should be ${minLength || min}`, "minLengthError", {
minLength: minLength || min
});
return;
}
if (maxLength && fieldValue.length > maxLength || max && fieldValue.length > max) {
setError(_key, `Maximum length should be ${maxLength || max}`, "maxLengthError", {
maxLength: maxLength || max
});
return;
}
}
// Handle negative number validation
if (typeof +fieldValue === "number" && +fieldValue < 0) {
setError(_key, "Please enter a valid value", "invalidValue");
return;
}
// Handle empty or whitespace-only fields
if (typeof fieldValue === "string" && !fieldValue.trim().length) {
setError(_key, "Please enter a valid value", "invalidValue");
return;
}
// Handle regex validation
if (regex && typeof fieldValue === "string") {
const _regexExp = new RegExp(regex.pattern);
if (!_regexExp.test(fieldValue)) {
setError(_key, "Invalid format", regex.message);
return;
}
}
// Validate using custom functions
if (customFunctions?.[_key]) {
const error = customFunctions[_key]();
if (error) {
setError(_key, error);
return;
}
}
// Clear previous errors if validation passes
updatedState[getErrorKey(_key)] = false;
updatedState[getErrorText(_key)] = "";
updatedState[_key] = typeof fieldValue === "string" ? fieldValue.trim() : fieldValue;
});
return {
isValid,
_state: updatedState
};
};
const queryString = obj => {
return Object.entries(obj).reduce((acc, [key, value]) => {
if (value !== undefined && value !== "") {
if (Array.isArray(value)) {
const val = value.map(item => typeof item === "object" ? item.label || item : item);
val.forEach(v => {
acc.push(`${encodeURIComponent(key)}=${encodeURIComponent(v)}`);
});
} else {
acc.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
}
}
return acc;
}, []).join("&");
};
function extractValue(obj, key) {
if (!obj?.toString()) {
return "";
}
return obj[key] ?? obj ?? "";
}
const AutocompleteSelect = props => {
const {
_key,
error,
errorText,
value,
onChange,
disabled,
size,
placeholder,
extraProps = {},
extraData = []
} = props;
const {
textFieldProps = {},
...restProps
} = extraProps || {};
const {
slotProps = {},
...restTextFieldProps
} = textFieldProps;
return /*#__PURE__*/jsxRuntime.jsx(material.Autocomplete, {
size: size,
openOnFocus: true,
disablePortal: false,
disabled: disabled,
isOptionEqualToValue: (option, value) => extractValue(option, "value") === value,
getOptionLabel: option => {
if (!option?.toString()) return "";
const selected = extraData?.find(item => {
return extractValue(option, "value") === extractValue(item, "value");
});
if (!selected) {
return "";
}
return String(extractValue(selected, "label"));
},
options: extraData,
value: extractValue(value, "value"),
onChange: (_, value) => {
if (onChange) onChange({
value: extractValue(value, "value"),
_key,
textValue: extractValue(value, "label")
});
},
renderOption: ({
key,
...restProps
}, option) => {
return /*#__PURE__*/jsxRuntime.jsx(material.MenuItem, {
...restProps,
children: String(extractValue(option, "label"))
}, key);
},
renderInput: params => {
return /*#__PURE__*/jsxRuntime.jsx(material.TextField, {
...params,
label: placeholder,
helperText: errorText,
error: error,
sx: {
"& .MuiAutocomplete-inputRoot": {
...(slotProps?.input?.style || {})
}
},
...restTextFieldProps
});
},
...restProps
});
};
const ModalHeader = ({
title,
closeBtn,
onClose
}) => {
return /*#__PURE__*/jsxRuntime.jsxs(material.Typography, {
id: "modal-modal-title",
component: "div",
sx: {
display: "flex",
borderTopLeftRadius: "8px",
borderTopRightRadius: "8px",
alignItems: "center",
justifyContent: "space-between"
},
children: [/*#__PURE__*/jsxRuntime.jsx(material.Typography, {
variant: "h6",
component: "h2",
children: title
}), onClose && closeBtn && /*#__PURE__*/jsxRuntime.jsx(material.IconButton, {
onClick: onClose,
children: /*#__PURE__*/jsxRuntime.jsx(CloseIcon, {
fontSize: "small"
})
})]
});
};
const ModalFooter = ({
children,
sx = {}
}) => {
return /*#__PURE__*/jsxRuntime.jsx(material.Typography, {
id: "modal-modal-footer",
component: "div",
sx: sx,
children: children
});
};
const CustomModal = ({
title,
isOpen,
onClose,
children,
sx,
className = "",
buttons
}) => {
return /*#__PURE__*/jsxRuntime.jsx(material.Modal, {
open: isOpen,
"aria-labelledby": "modal-modal-title",
"aria-describedby": "modal-modal-description",
sx: {
outline: "none",
overflow: "auto"
},
onClose: (_, reason) => {
if (reason === "backdropClick") return;
onClose?.();
},
children: /*#__PURE__*/jsxRuntime.jsxs(material.Box, {
component: "div",
sx: {
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
minWidth: "40vw",
width: {
xs: "80%",
sm: "30%"
},
bgcolor: "background.paper",
boxShadow: 4,
borderRadius: "8px",
p: 2,
maxHeight: "100%",
overflow: "auto",
...sx
},
color: "primary",
className: `hide-scrollbar ${className}`,
children: [title && /*#__PURE__*/jsxRuntime.jsx(ModalHeader, {
title: title,
onClose: onClose
}), /*#__PURE__*/jsxRuntime.jsxs(material.Typography, {
component: "div",
sx: {
display: "flex",
flex: 1,
flexDirection: "column",
justifyContent: "space-between"
},
children: [/*#__PURE__*/jsxRuntime.jsx(material.Typography, {
component: "div",
children: children
}), !!buttons?.length && /*#__PURE__*/jsxRuntime.jsx(ModalFooter, {
children: /*#__PURE__*/jsxRuntime.jsx(material.Typography, {
sx: {
display: "flex",
alignItems: "center",
justifyContent: "flex-end",
gap: 2
},
children: buttons.map(({
title,
hidden,
...rest
}) => !hidden && /*#__PURE__*/jsxRuntime.jsx(material.Button, {
...rest,
children: title
}, title))
})
})]
})]
})
});
};
async function getMedia(deviceId) {
console.log("getMedia");
let stream = null;
try {
stream = await navigator.mediaDevices.getUserMedia({
video: {
deviceId
},
audio: false
});
return stream;
} catch (err) {
console.log(err);
}
}
async function takePicture(canvas, video, width, height) {
const context = canvas.getContext("2d");
const ratio = window.devicePixelRatio || 1;
if (context) {
canvas.width = width * ratio;
canvas.height = height * ratio;
// Scale the context to match the devicePixelRatio
context.setTransform(ratio, 0, 0, ratio, 0, 0);
context.imageSmoothingEnabled = true;
context.imageSmoothingQuality = "high";
context.clearRect(0, 0, width, height);
context.drawImage(video, 0, 0, width, height);
return getImageFromCanvas(canvas);
}
console.error("Canvas context is not available.");
return false;
}
async function flipPicture(canvas) {
const context = canvas.getContext("2d");
const ratio = window.devicePixelRatio || 1;
if (context) {
// Save the current image as a source
const imageBitmap = await createImageBitmap(canvas);
// Clear the canvas
context.clearRect(0, 0, canvas.width, canvas.height);
// Save the context state before applying transformations
context.save();
// Apply horizontal flip transformation with devicePixelRatio compensation
context.scale(-1, 1);
context.translate(-canvas.width / ratio, 0);
// Draw the flipped image
context.drawImage(imageBitmap, 0, 0, canvas.width / ratio, canvas.height / ratio);
// Restore the context state to reset transformations
context.restore();
return getImageFromCanvas(canvas);
}
console.error("Canvas context is not available.");
return false;
}
async function getImageFromCanvas(canvas) {
const blob = await new Promise(resolve => canvas.toBlob(resolve, "image/jpeg", 1.0));
if (blob) {
return new File([blob], "fileName.jpg", {
type: "image/jpeg"
});
}
return false;
}
async function getVideoDeviceList() {
try {
console.log("getVideoDeviceList");
const stream = await navigator.mediaDevices.getUserMedia({
audio: false,
video: true
});
if (!navigator.mediaDevices?.enumerateDevices || !stream) {
console.log("enumerateDevices() not supported.");
} else {
const devices = await navigator.mediaDevices.enumerateDevices();
return devices.filter(device => device.kind === "videoinput");
}
} catch (error) {
console.log(error);
}
}
function RenderCameraList({
list,
selectedCamera,
onChangeCamera
}) {
const [anchorEl, setAnchorEl] = React__namespace.useState(null);
const open = Boolean(anchorEl);
const handleClick = event => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
const handleCameraChange = deviceId => {
onChangeCamera(deviceId);
handleClose();
};
return /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
children: [/*#__PURE__*/jsxRuntime.jsx(material.IconButton, {
id: "basic-button",
"aria-controls": open ? "basic-menu" : undefined,
"aria-haspopup": "true",
"aria-expanded": open ? "true" : undefined,
onClick: handleClick,
autoFocus: true,
sx: {
justifySelf: "self-start",
":focus-visible": {
outline: `1px solid #fff`
},
aspectRatio: 1
},
children: /*#__PURE__*/jsxRuntime.jsx(FlipCameraIcon, {
fontSize: "medium",
sx: {
color: "white"
}
})
}), /*#__PURE__*/jsxRuntime.jsx(Menu, {
id: "basic-menu",
anchorEl: anchorEl,
open: open,
onClose: handleClose,
slotProps: {
list: {
"aria-labelledby": "basic-button"
}
},
children: list.map(device => /*#__PURE__*/jsxRuntime.jsx(MenuItem, {
selected: selectedCamera === device.deviceId,
onClick: () => handleCameraChange(device.deviceId),
children: device.label
}, device.deviceId))
})]
});
}
const CameraFooter = ({
devices,
selectedDeviceId,
onChangeSelectedDevice,
isPictureClicked,
onClickPicture,
onAccept,
onDecline,
onMirror
}) => {
const iconButtons = React.useMemo(() => [{
Icon: CloseIcon,
onClick: onDecline
}, {
Icon: FlipIcon,
onClick: onMirror
}, {
Icon: DoneIcon,
onClick: onAccept
}], [onAccept, onDecline, onMirror]);
return /*#__PURE__*/jsxRuntime.jsx(material.Typography, {
component: "div",
sx: {
position: "absolute",
bottom: 0,
background: "rgba(0, 0, 0, 0.5)",
width: "100%",
zIndex: 9999,
p: 2,
height: 80
},
children: isPictureClicked ? /*#__PURE__*/jsxRuntime.jsx(material.Typography, {
sx: {
width: "100%",
display: "flex",
alignItems: "center",
justifyContent: "space-between"
},
children: iconButtons.map(({
Icon,
onClick
}, index) => /*#__PURE__*/jsxRuntime.jsx(material.IconButton, {
autoFocus: index === 0,
sx: {
":focus-visible": {
outline: `1px solid #fff`
}
},
onClick: onClick,
children: /*#__PURE__*/jsxRuntime.jsx(Icon, {
fontSize: "large",
sx: {
color: "#fff"
}
})
}, index))
}) : /*#__PURE__*/jsxRuntime.jsxs(material.Typography, {
sx: {
width: "100%",
textAlign: "center",
display: "grid",
gridTemplateColumns: "0.9fr 1.1fr"
},
children: [/*#__PURE__*/jsxRuntime.jsx(RenderCameraList, {
list: devices,
selectedCamera: selectedDeviceId,
onChangeCamera: onChangeSelectedDevice
}), /*#__PURE__*/jsxRuntime.jsx(material.Button, {
autoFocus: true,
sx: {
background: "#fff",
borderRadius: "100%",
border: "none",
outline: "none",
cursor: "pointer",
width: 5,
aspectRatio: 1 / 1
},
onClick: onClickPicture
})]
})
});
};
const UploadFromCamera = ({
onChange,
getLocalizedText
}) => {
const [isCameraLoading, setIsCameraLoading] = React.useState(false);
const [selectedDeviceId, setSelectedDeviceId] = React.useState("");
const [devices, setDevices] = React.useState([]);
const [clickedPicture, setClickedPicture] = React.useState(null);
const [isMirrored, setIsMirrored] = React.useState(false);
const streamRef = React.useRef(null);
const audioRef = React.useRef(null);
const videoRef = React.useRef(null);
const canvasRef = React.useRef(null);
// handling accept picture
const handleAcceptPicture = async () => {
if (clickedPicture) {
onChange([clickedPicture]);
}
setClickedPicture(null);
};
// handling decline picture
const handleDeclinePicture = async () => {
setClickedPicture(null);
};
// handling flip picture
const handleFlipPicture = async () => {
if (canvasRef.current) {
const pic = await flipPicture(canvasRef.current);
if (pic) {
setClickedPicture(pic);
setIsMirrored(!isMirrored);
}
}
};
// handling click picture
const handleClickPicture = async () => {
const canvas = canvasRef.current;
const video = videoRef.current;
const audio = audioRef.current;
if (canvas && video && audio) {
// await audio.play();
setTimeout(async () => {
const {
width,
height
} = video.getBoundingClientRect();
canvas.width = width;
canvas.height = height;
const pic = await takePicture(canvas, video, canvas.width, canvas.height);
if (pic) setClickedPicture(pic);
}, 1000);
}
};
const playMediaStream = React.useCallback(deviceId => {
if (streamRef.current) {
stopMediaStream();
}
getMedia(deviceId).then(mediaStream => {
const video = videoRef.current;
if (video && mediaStream) {
streamRef.current = mediaStream;
video.srcObject = mediaStream;
video.onloadedmetadata = () => {
setIsCameraLoading(false);
};
}
});
}, []);
const stopMediaStream = () => {
if (videoRef.current) {
videoRef.current.srcObject = null;
videoRef.current.src = "";
}
if (streamRef.current) {
console.log("stopping track");
const track = streamRef.current.getVideoTracks()[0];
track.stop();
track.enabled = false;
streamRef.current = null;
}
};
const getDevices = async () => {
const deviceList = (await getVideoDeviceList()) || [];
setDevices(deviceList);
setSelectedDeviceId(deviceList[0]?.deviceId || "");
};
const handleCameraChange = deviceId => {
setSelectedDeviceId(deviceId);
};
React.useEffect(() => {
if (selectedDeviceId) playMediaStream(selectedDeviceId);
}, [selectedDeviceId, playMediaStream]);
React.useEffect(() => {
getDevices();
setIsCameraLoading(true);
return () => {
stopMediaStream();
};
}, []);
return /*#__PURE__*/jsxRuntime.jsx("div", {
style: {
textAlign: "center"
},
children: /*#__PURE__*/jsxRuntime.jsxs("div", {
style: {
margin: "auto",
position: "relative",
background: "rgba(0, 0, 0, 0.1)"
},
children: [/*#__PURE__*/jsxRuntime.jsx("video", {
ref: videoRef,
style: {
width: "100%",
height: "100%",
objectFit: "contain",
display: clickedPicture ? "none" : "block"
},
autoPlay: true,
playsInline: true
}), /*#__PURE__*/jsxRuntime.jsx("canvas", {
ref: canvasRef,
style: {
display: clickedPicture ? "block" : "none",
margin: "auto",
width: "100%",
height: "auto"
}
}), isCameraLoading && /*#__PURE__*/jsxRuntime.jsx("div", {
style: {
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)"
},
children: getLocalizedText?.("loading") || "Loading..."
}), /*#__PURE__*/jsxRuntime.jsx("audio", {
ref: audioRef,
style: {
display: "none"
}
}), /*#__PURE__*/jsxRuntime.jsx(CameraFooter, {
devices: devices,
selectedDeviceId: selectedDeviceId,
onChangeSelectedDevice: handleCameraChange,
isPictureClicked: !!clickedPicture,
onClickPicture: handleClickPicture,
onAccept: handleAcceptPicture,
onDecline: handleDeclinePicture,
onMirror: handleFlipPicture
})]
})
});
};
const filterFilesByMaxSize = ({
files,
maxSize
}) => {
const filteredFiles = [];
for (const file of files) {
if (Number((file.size / (1024 * 1024)).toFixed(2)) <= maxSize) {
filteredFiles.push(file);
}
}
return filteredFiles;
};
// export const getFileType = (file: IMedia.FileData) => {
// if (!file) return null;
// if (file instanceof File) {
// if (file.type.startsWith("application")) {
// return file.type.split("/")[1];
// }
// return file.type.split("/")[0];
// }
// if (typeof file === "string") {
// return file;
// }
// if (file.fileType.startsWith("application")) {
// return file.fileType.split("/")[1];
// }
// return file.fileType.split("/")[0];
// };
function getFileType(file) {
const ext = file.name?.split(".").pop()?.toLowerCase();
if (!ext) return "unknown";
if (["jpg", "jpeg", "png", "gif", "webp"].includes(ext)) return "image";
if (["mp4", "webm", "ogg", "mov"].includes(ext)) return "video";
if (["mp3", "wav", "aac", "flac"].includes(ext)) return "audio";
if (["pdf"].includes(ext)) return "pdf";
if (["doc", "docx", "xls", "xlsx", "ppt", "pptx", "txt"].includes(ext)) return "document";
return "unknown";
}
function getFileExtension(filePath) {
if (!filePath) return "";
return filePath.split(".").pop() || "jpg";
}
function getFileMetaData(file, filePath) {
return {
url: URL.createObjectURL(file),
name: file.name,
type: file.type,
size: file.size,
path: filePath || file.name,
extension: getFileExtension(file.name),
file
};
}
function checkIsMobile() {
if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
return true;
}
return false;
}
function isFile(file) {
return !!(file instanceof File);
}
const handleA11yKeyDown = callback => event => {
if (!callback) return;
if (event.code === "Space" || event.code === "Enter") {
event.preventDefault();
event.stopPropagation();
callback();
}
};
const UploadFromGallery = ({
name,
multiple = false,
onChange,
disabled,
extraProps,
inputProps,
onError,
getLocalizedText
}) => {
const {
maxFileSize = 5,
supportedFiles = ["*"]
} = extraProps || {};
const supportedFilesString = React.useMemo(() => {
if (supportedFiles.includes("*")) {
return getLocalizedText?.("allFileTypesSupported") || "All file types are supported";
}
const friendlyTypesMap = {
"image/*": "images",
"video/*": "videos",
"audio/*": "audio files",
"application/pdf": "PDFs",
"application/msword": "Word documents",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document": "Word documents",
"application/vnd.ms-excel": "Excel spreadsheets",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "Excel spreadsheets",
"application/vnd.ms-powerpoint": "PowerPoint presentations",
"application/vnd.openxmlformats-officedocument.presentationml.presentation": "PowerPoint presentations",
"text/plain": "text files"
};
const friendlyNames = supportedFiles.map(type => friendlyTypesMap[type] || type).filter((value, index, self) => self.indexOf(value) === index); // remove duplicates
return `${getLocalizedText?.("supportedFiles") || "Supported files"}: ${friendlyNames.join(", ")}`;
}, [supportedFiles, getLocalizedText]);
const handleChange = files => {
const filteredFiles = filterFilesByMaxSize({
files,
maxSize: maxFileSize
});
if (filteredFiles.length < files.length) {
onError?.(getLocalizedText?.("ignoringFilesGreaterSize") || "Ignoring files greater than max size");
}
onChange(filteredFiles);
};
const fileInputId = `input-file-${name}`;
return /*#__PURE__*/jsxRuntime.jsx(material.Typography, {
component: "div",
children: /*#__PURE__*/jsxRuntime.jsxs(material.Typography, {
tabIndex: 0,
component: "label",
htmlFor: fileInputId,
color: "primary",
sx: {
border: "1px dashed",
outlineColor: "primary.main",
height: 200,
width: "100%",
borderRadius: 2,
display: "flex",
alignItems: "center",
justifyContent: "center",
cursor: "pointer"
},
onDragOver: e => e.preventDefault(),
onDrop: e => {
e.preventDefault();
handleChange(e.dataTransfer.files);
},
onKeyDown: handleA11yKeyDown(() => {
document.getElementById(fileInputId)?.click();
}),
children: [/*#__PURE__*/jsxRuntime.jsxs(material.Typography, {
sx: {
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center"
},
children: [/*#__PURE__*/jsxRuntime.jsx(material.Typography, {
component: "span",
children: /*#__PURE__*/jsxRuntime.jsx(CloudUploadIcon, {
fontSize: "large"
})
}), /*#__PURE__*/jsxRuntime.jsx(material.Typography, {
component: "span",
color: "textPrimary",
children: getLocalizedText?.("dropFile") || "Drop your file here, or browse"
}), /*#__PURE__*/jsxRuntime.jsx(material.Typography, {
component: "span",
sx: {
fontSize: 14
},
children: supportedFilesString
}), /*#__PURE__*/jsxRuntime.jsx(material.Typography, {
component: "span",
color: "warning",
sx: {
fontSize: 12
},
children: getLocalizedText?.("maxFileSize", {
size: maxFileSize
}) || `Max file size ${maxFileSize}MB`
})]
}), /*#__PURE__*/jsxRuntime.jsx("input", {
id: `input-file-${name}`,
type: "file",
style: {
display: "none"
},
accept: supportedFiles.join(", "),
multiple: multiple,
disabled: disabled,
onChange: e => {
if (e.target.files) {
handleChange(e.target.files);
}
},
...inputProps
})]
})
});
};
const RenderUploadOption = ({
uploadOption,
...rest
}) => {
switch (uploadOption) {
case "camera":
return /*#__PURE__*/jsxRuntime.jsx(UploadFromCamera, {
...rest
});
case "gallery":
return /*#__PURE__*/jsxRuntime.jsx(UploadFromGallery, {
...rest
});
}
};
function ScrollableTabs({
groups,
onTabChange,
activeTab,
renderContent,
getLocalizedText
}) {
return /*#__PURE__*/jsxRuntime.jsxs(material.Box, {
sx: {
width: "100%"
},
children: [/*#__PURE__*/jsxRuntime.jsx(material.Box, {
sx: {
display: "flex",
overflowX: "auto"
},
children: groups.map(({
label,
_key
}, index) => /*#__PURE__*/jsxRuntime.jsx(material.Button, {
onClick: () => onTabChange(index),
sx: {
flex: "0 0 auto",
borderRadius: 0,
borderBottom: 2,
borderColor: activeTab === index ? "primary.main" : "transparent",
color: activeTab === index ? "primary.main" : "text.primary",
fontWeight: 600,
textTransform: "uppercase",
"&:hover": {
backgroundColor: "transparent"
},
fontSize: "0.875rem",
lineHeight: 1.25,
letterSpacing: "0.02857em",
maxWidth: "360px",
minWidth: "90px",
position: "relative",
minHeight: "48px",
flexShrink: 0,
padding: "12px 16px",
overflow: "hidden",
whiteSpace: "normal",
textAlign: "center",
flexDirection: "column"
},
children: getLocalizedText?.(`${_key}`) || label
}, _key))
}), /*#__PURE__*/jsxRuntime.jsx(material.Box, {
sx: {
my: 2
},
children: renderContent
})]
});
}
const Image = ({
src,
alt = "Media image",
width = "100%",
height = "100%",
containerStyle = {},
style = {},
...rest
}) => {
const [loading, setLoading] = React.useState(true);
const [error, setError] = React.useState(false);
return /*#__PURE__*/jsxRuntime.jsxs(material.Box, {
position: "relative",
width: width,
height: height,
display: "flex",
alignItems: "center",
justifyContent: "center",
borderRadius: 1,
overflow: "hidden",
style: containerStyle,
children: [loading && !error && /*#__PURE__*/jsxRuntime.jsx(material.CircularProgress, {
size: 32
}), !error ? /*#__PURE__*/jsxRuntime.jsx("img", {
src: src,
alt: alt,
onLoad: () => {
setLoading(false);
},
onError: () => {
setLoading(false);
setError(true);
},
style: {
display: loading ? "none" : "block",
width: "100%",
height: "100%",
objectFit: "cover",
...style
},
...rest
}) : /*#__PURE__*/jsxRuntime.jsxs(material.Box, {
display: "flex",
flexDirection: "column",
alignItems: "center",
children: [/*#__PURE__*/jsxRuntime.jsx(BrokenImageIcon, {
color: "disabled",
fontSize: "large"
}), /*#__PURE__*/jsxRuntime.jsx("span", {
style: {
fontSize: 12,
color: "#888"
},
children: "Image not found"
})]
})]
});
};
const Video = ({
src,
poster,
width = "100%",
style = {},
isPlaceholder,
iconProps = {},
...rest
}) => {
const theme = material.useTheme();
const [loading, setLoading] = React.useState(true);
const [error, setError] = React.useState(false);
const videoRef = React.useRef(null);
const handleLoadedData = React.useCallback(() => {
setLoading(false);
}, []);
const handleError = React.useCallback(() => {
setLoading(false);
setError(true);
}, []);
React.useEffect(() => {
if (videoRef.current && videoRef.current.readyState > 3) {
setLoading(false);
}
}, []);
return /*#__PURE__*/jsxRuntime.jsxs(material.Box, {
position: "relative",
width: width,
display: "flex",
alignItems: "center",
justifyContent: "center",
borderRadius: 1,
overflow: "hidden",
style: {
aspectRatio: 1,
background: isPlaceholder ? "transparent" : "black",
...style
},
children: [loading && !error && !isPlaceholder && /*#__PURE__*/jsxRuntime.jsx(material.CircularProgress, {
size: 32
}), !!isPlaceholder && /*#__PURE__*/jsxRuntime.jsx(PlayCircleIcon, {
sx: {
fontSize: "auto",
zIndex: 10,
position: "absolute",
color: theme.palette.primary.main
},
...iconProps
}), !isPlaceholder && (!error ? /*#__PURE__*/jsxRuntime.jsx("video", {
ref: videoRef,
src: src,
poster: poster,
preload: "metadata",
loop: false,
onLoadedMetadata: handleLoadedData,
onError: handleError,
style: {
display: loading ? "none" : "block",
width: "100%",
// height: "100%",
aspectRatio: 1,
objectFit: isPlaceholder ? "cover" : "contain",
opacity: isPlaceholder ? 0 : 1
},
...rest
}) : /*#__PURE__*/jsxRuntime.jsxs(material.Box, {
display: "flex",
flexDirection: "column",
alignItems: "center",
children: [/*#__PURE__*/jsxRuntime.jsx(VideocamOffIcon, {
color: "disabled",
fontSize: "large"
}), /*#__PURE__*/jsxRuntime.jsx("span", {
style: {
fontSize: 12,
color: "#888"
},
children: "Video not available"
})]
}))]
});
};
const Audio = ({
src,
style = {}
}) => {
const audioRef = React.useRef(null);
const [loading, setLoading] = React.useState(true);
const [error, setError] = React.useState(false);
React.useEffect(() => {
if (audioRef.current && audioRef.current.readyState >= 3) {
setLoading(false);
}
}, []);
const handleLoaded = () => setLoading(false);
const handleError = () => {
setLoading(false);
setError(true);
};
return /*#__PURE__*/jsxRuntime.jsxs(material.Box, {
width: "100%",
height: "100%",
padding: 2,
borderRadius: 1,
style: {
position: "relative",
display: "flex",
alignItems: "flex-end",
justifyContent: "flex-end",
...style
},
children: [loading && !error && /*#__PURE__*/jsxRuntime.jsx(material.CircularProgress, {
sx: {
position: "absolute",
top: "50%",
left: "50%",
translate: "-50% -50%"
},
size: 32
}), !error ? /*#__PURE__*/jsxRuntime.jsxs(material.Box, {
sx: {
width: "100%",
height: "100%",
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "space-between",
bgcolor: "grey.300",
borderRadius: 2
},
children: [!loading && /*#__PURE__*/jsxRuntime.jsx(AudioPlaceholder, {
sx: {
fontSize: 120
}
}), /*#__PURE__*/jsxRuntime.jsx("audio", {
ref: audioRef,
src: src,
controls: true,
onLoadedMetadata: handleLoaded
// onCanPlayThrough={handleLoaded}
,
onError: handleError,
style: {
display: loading ? "none" : "block",
width: "100%",
borderRadius: 0
}
})]
}) : /*#__PURE__*/jsxRuntime.jsxs(material.Box, {
display: "flex",
alignItems: "center",
flexDirection: "column",
children: [/*#__PURE__*/jsxRuntime.jsx(VolumeOffIcon, {
color: "disabled",
fontSize: "large"
}), /*#__PURE__*/jsxRuntime.jsx(material.Typography, {
variant: "body2",
color: "textSecondary",
children: "Audio not available"
})]
})]
});
};
const AudioPlaceholder = ({
sx,
containerSx
}) => {
const theme = material.useTheme();
return /*#__PURE__*/jsxRuntime.jsx(material.Box, {
sx: {
width: "100%",
height: "100%",
display: "flex",
alignItems: "center",
justifyContent: "center",
...containerSx
},
children: /*#__PURE__*/jsxRuntime.jsx(HeadsetIcon, {
sx: {
fontSize: "auto",
color: theme.palette.primary.main,
...sx
}
})
});
};
const Document = ({
data
}) => {
const handleRedirect = () => {
window.open(data.url);
};
return /*#__PURE__*/jsxRuntime.jsxs(material.Box, {
sx: {
width: "100%",
height: "100%",
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "space-between",
bgcolor: "grey.300",
borderRadius: 2,
position: "relative",
overflow: "hidden"
},
children: [/*#__PURE__*/jsxRuntime.jsx(LaunchIcon, {
sx: {
position: "absolute",
right: 0,
bgcolor: "white",
width: "40px",
height: "40px",
p: "5px",
cursor: "pointer"
},
onClick: handleRedirect
}), /*#__PURE__*/jsxRuntime.jsx(DocumentPlaceholder, {
sx: {
fontSize: 50
}
})]
});
};
const DocumentPlaceholder = ({
sx,
containerSx
}) => {
const theme = material.useTheme();
return /*#__PURE__*/jsxRuntime.jsx(material.Box, {
sx: {
width: "100%",
height: "100%",
display: "flex",
alignItems: "center",
justifyContent: "center",
...containerSx
},
children: /*#__PURE__*/jsxRuntime.jsx(DescriptionIcon, {
sx: {
fontSize: "auto",
color: theme.palette.primary.main,
...sx
}
})
});
};
/**
* WARNING: Don't import this directly. It's imported by the code generated by
* `@mui/interal-babel-plugin-minify-errors`. Make sure to always use string literals in `Error`
* constructors to ensure the plugin works as expected. Supported patterns include:
* throw new Error('My message');
* throw new Error(`My message: ${foo}`);
* throw new Error(`My message: ${foo}` + 'another string');
* ...
* @param {number} code
*/
function formatMuiErrorMessage(code, ...args) {
const url = new URL(`https://mui.com/production-error/?code=${code}`);
args.forEach(arg => url.searchParams.append('args[]', arg));
return `Minified MUI error #${code}; visit ${url} for the full message.`;
}
function getDefaultExportFromCjs (x) {
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
}
var propTypes = {exports: {}};
var reactIs$1 = {exports: {}};
var reactIs_production_min = {};
/** @license React v16.13.1
* react-is.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
var hasRequiredReactIs_production_min;
function requireReactIs_production_min () {
if (hasRequiredReactIs_production_min) return reactIs_production_min;
hasRequiredReactIs_production_min = 1;
var b="function"===typeof Symbol&&Symbol.for,c=b?Symbol.for("react.element"):60103,d=b?Symbol.for("react.portal"):60106,e=b?Symbol.for("react.fragment"):60107,f=b?Symbol.for("react.strict_mode"):60108,g=b?Symbol.for("react.profiler"):60114,h=b?Symbol.for("react.provider"):60109,k=b?Symbol.for("react.context"):60110,l=b?Symbol.for("react.async_mode"):60111,m=b?Symbol.for("react.concurrent_mode"):60111,n=b?Symbol.for("react.forward_ref"):60112,p=b?Symbol.for("react.suspense"):60113,q=b?
Symbol.for("react.suspense_list"):60120,r=b?Symbol.for("react.memo"):60115,t=b?Symbol.for("react.lazy"):60116,v=b?Symbol.for("react.block"):60121,w=b?Symbol.for("react.fundamental"):60117,x=b?Symbol.for("react.responder"):60118,y=b?Symbol.for("react.scope"):60119;
function z(a){if("object"===typeof a&&null!==a){var u=a.$$typeof;switch(u){case c:switch(a=a.type,a){case l:case m:case e:case g:case f:case p:return a;default:switch(a=a&&a.$$typeof,a){case k:case n:case t:case r:case h:return a;default:return u}}case d:return u}}}function A(a){return z(a)===m}reactIs_production_min.AsyncMode=l;reactIs_production_min.ConcurrentMode=m;reactIs_production_min.ContextConsumer=k;reactIs_production_min.ContextProvider=h;reactIs_production_min.Element=c;reactIs_production_min.ForwardRef=n;reactIs_production_min.Fragment=e;reactIs_production_min.Lazy=t;reactIs_production_min.Memo=r;reactIs_production_min.Portal=d;
reactIs_production_min.Profiler=g;reactIs_production_min.StrictMode=f;reactIs_production_min.Suspense=p;reactIs_production_min.isAsyncMode=function(a){return A(a)||z(a)===l};reactIs_production_min.isConcurrentMode=A;reactIs_production_min.isContextConsumer=function(a){return z(a)===k};reactIs_production_min.isContextProvider=function(a){return z(a)===h};reactIs_production_min.isElement=function(a){return "object"===typeof a&&null!==a&&a.$$typeof===c};reactIs_production_min.isForwardRef=function(a){return z(a)===n};reactIs_production_min.isFragment=function(a){return z(a)===e};reactIs_production_min.isLazy=function(a){return z(a)===t};
reactIs_production_min.isMemo=function(a){return z(a)===r};reactIs_production_min.isPortal=function(a){return z(a)===d};reactIs_production_min.isProfiler=function(a){return z(a)===g};reactIs_production_min.isStrictMode=function(a){return z(a)===f};reactIs_production_min.isSuspense=function(a){return z(a)===p};
reactIs_production_min.isValidElementType=function(a){return "string"===typeof a||"function"===typeof a||a===e||a===m||a===g||a===f||a===p||a===q||"object"===typeof a&&null!==a&&(a.$$typeof===t||a.$$typeof===r||a.$$typeof===h||a.$$typeof===k||a.$$typeof===n||a.$$typeof===w||a.$$typeof===x||a.$$typeof===y||a.$$typeof===v)};reactIs_production_min.typeOf=z;
return reactIs_production_min;
}
var reactIs_development$1 = {};
/** @license React v16.13.1
* react-is.development.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
var hasRequiredReactIs_development$1;
function requireReactIs_development$1 () {
if (hasRequiredReactIs_development$1) return reactIs_development$1;
hasRequiredReactIs_development$1 = 1;
if (process.env.NODE_ENV !== "production") {
(function() {
// The Symbol used to tag the ReactElement-like types. If there is no native Symbol
// nor polyfill, then a plain number is used for performance.
var hasSymbol = typeof Symbol === 'function' && Symbol.for;
var REACT_ELEMENT_TYPE = hasSymbol ? Symbol.for('react.element') : 0xeac7;
var REACT_PORTAL_TYPE = hasSymbol ? Symbol.for('react.portal') : 0xeaca;
var REACT_FRAGMENT_TYPE = hasSymbol ? Symbol.for('react.fragment') : 0xeacb;
var REACT_STRICT_MODE_TYPE = hasSymbol ? Symbol.for('react.strict_mode') : 0xeacc;
var REACT_PROFILER_TYPE = hasSymbol ? Symbol.for('react.profiler') : 0xead2;
var REACT_PROVIDER_TYPE = hasSymbol ? Symbol.for('react.provider') : 0xeacd;
var REACT_CONTEXT_TYPE = hasSymbol ? Symbol.for('react.context') : 0xeace; // TODO: We don't use AsyncMode or ConcurrentMode anymore. They were temporary
// (unstable) APIs that have been removed. Can we remove the symbols?
var REACT_ASYNC_MODE_TYPE = hasSymbol ? Symbol.for('react.async_mode') : 0xeacf;
var REACT_CONCURRENT_MODE_TYPE = hasSymbol ? Symbol.for('react.concurrent_mode') : 0xeacf;
var REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for('react.forward_ref') : 0xead0;
var REACT_SUSPENSE_TYPE = hasSymbol ? Symbol.for('react.suspense') : 0xead1;
var REACT_SUSPENSE_LIST_TYPE = hasSymbol ? Symbol.for('react.suspense_list') : 0xead8;
var REACT_MEMO_TYPE = hasSymbol ? Symbol.for('react.memo') : 0xead3;
var REACT_LAZY_TYPE = hasSymbol ? Symbol.for('react.lazy') : 0xead4;
var REACT_BLOCK_TYPE = hasSymbol ? Symbol.for('react.block') : 0xead9;
var REACT_FUNDAMENTAL_TYPE = hasSymbol ? Symbol.for('react.fundamental') : 0xead5;
var REACT_RESPONDER_TYPE = hasSymbol ? Symbol.for('react.responder') : 0xead6;
var REACT_SCOPE_TYPE = hasSymbol ? Symbol.for('react.scope') : 0xead7;
function isValidElementType(type) {
return typeof type === 'string' || typeof type === 'function' || // Note: its typeof might be other than 'symbol' or 'number' if it's a polyfill.
type === REACT_FRAGMENT_TYPE || type === REACT_CONCURRENT_MODE_TYPE || type === REACT_PROFILER_TYPE || type === REACT_STRICT_MODE_TYPE || type === REACT_SUSPENSE_TYPE || type === REACT_SUSPENSE_LIST_TYPE || typeof type === 'object' && type !== null && (type.$$typeof === REACT_LAZY_TYPE || type.$$typeof === REACT_MEMO_TYPE || type.$$typeof === REACT_PROVIDER_TYPE || type.$$typeof === REACT_CONTEXT_TYPE || type.$$typeof === REACT_FORWARD_REF_TYPE || type.$$typeof === REACT_FUNDAMENTAL_TYPE || type.$$typeof === REACT_RESPONDER_TYPE || type.$$typeof === REACT_SCOPE_TYPE || type.$$typeof === REACT_BLOCK_TYPE);
}
function typeOf(object) {
if (typeof object === 'object' && object !== null) {
var $$typeof = object.$$typeof;
switch ($$typeof) {
case REACT_ELEMENT_TYPE:
var type = object.type;
switch (type) {
case REACT_ASYNC_MODE_TYPE:
case REACT_CONCURRENT_MODE_TYPE:
case REACT_FRAGMENT_TYPE:
case REACT_PROFILER_TYPE:
case REACT_STRICT_MODE_TYPE:
case REACT_SUSPENSE_TYPE:
return type;
default:
var $$typeofType = type && type.$$typeof;
switch ($$typeofType) {
case REACT_CONTEXT_TYPE:
case REACT_FORWARD_REF_TYPE:
case REACT_LAZY_TYPE:
case REACT_MEMO_TYPE:
case REACT_PROVIDER_TYPE:
return $$typeofType;
default:
return $$typeof;
}
}
case REACT_PORTAL_TYPE:
return $$typeof;
}
}
return undefined;
} // AsyncMode is deprecated along with isAsyncMode
var AsyncMode = REACT_ASYNC_MODE_TYPE;
var ConcurrentMode = REACT_CONCURRENT_MODE_TYPE;
var ContextConsumer = REACT_CONTEXT_TYPE;
var ContextProvider = REACT_PROVIDER_TYPE;
var Element = REACT_ELEMENT_TYPE;
var ForwardRef = REACT_FORWARD_REF_TYPE;
var Fragment = REACT_FRAGMENT_TYPE;
var Lazy = REACT_LAZY_TYPE;
var Memo = REACT_MEMO_TYPE;
var Portal = REACT_PORTAL_TYPE;
var Profiler = REACT_PROFILER_TYPE;
var StrictMode = REACT_STRICT_MODE_TYPE;
var Suspense = REACT_SUSPENSE_TYPE;
var hasWarnedAboutDeprecatedIsAsyncMode = false; // AsyncMode should be deprecated
function isAsyncMode(object) {
{
if (!hasWarnedAboutDeprecatedIsAsyncMode) {
hasWarnedAboutDeprecatedIsAsyncMode = true; // Using console['warn'] to evade Babel and ESLint
console['warn']('The ReactIs.isAsyncMode() alias has been deprecated, ' + 'and will be removed in React 17+. Update your code to use ' + 'ReactIs.isConcurrentMode() instead. It has the exact same API.');
}
}
return isConcurrentMode(object) || typeOf(object) === REACT_ASYNC_MODE_TYPE;
}
function isConcurrentMode(object) {
return typeOf(object) === REACT_CONCURRENT_MODE_TYPE;
}
function isContextConsumer(object) {
return typeOf(object) === REACT_CONTEXT_TYPE;
}
function isContextProvider(object) {
return typeOf(object) === REACT_PROVIDER_TYPE;
}
function isElement(object) {
return typeof object === 'object' && object !== null && object.$$typeof === REACT_ELEMENT_TYPE;
}
function isForwardRef(object) {
return typeOf(object) === REACT_FORWARD_REF_TYPE;
}
function isFragment(object) {
return typeOf(object) === REACT_FRAGMENT_TYPE;
}
function isLazy(object) {
return typeOf(object) === REACT_LAZY_TYPE;
}
function isMemo(object) {
return typeOf(object) === REACT_MEMO_TYPE;
}
function isPortal(object) {
return typeOf(object) === REACT_PORTAL_TYPE;
}
function isProfiler(object) {
return typeOf(object) === REACT_PROFILER_TYPE;
}
function isStrictMode(object) {
return typeOf(object) === REACT_STRICT_MODE_TYPE;
}
function isSuspense(object) {
return typeOf(object) === REACT_SUSPENSE_TYPE;
}
reactIs_development$1.AsyncMode = AsyncMode;
reactIs_development$1.ConcurrentMode = ConcurrentMode;
reactIs_development$1.ContextConsumer = ContextConsumer;
reactIs_development$1.ContextProvider = ContextProvider;
reactIs_development$1.Element = Element;
reactIs_development$1.ForwardRef = ForwardRef;
reactIs_development$1.Fragment = Fragment;
reactIs_development$1.Lazy = Lazy;
reactIs_development$1.Memo = Memo;
reactIs_development$1.Portal = Portal;
reactIs_development$1.Profiler = Profiler;
reactIs_development$1.StrictMode = StrictMode;
reactIs_development$1.Suspense = Suspense;
reactIs_development$1.isAsyncMode = isAsyncMode;
reactIs_development$1.isConcurrentMode = isConcurrentMode;
reactIs_development$1.isContextConsumer = isContextConsumer;
reactIs_development$1.isContextProvider = isContextProv