UNPKG

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
'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