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