2024-07-24 13:16:43 -04:00
|
|
|
import PropTypes from "prop-types";
|
2024-07-24 13:11:38 -04:00
|
|
|
import { useTheme } from "@emotion/react";
|
2024-10-17 12:05:06 +08:00
|
|
|
import { MenuItem, Select as MuiSelect, Stack, Typography } from "@mui/material";
|
2024-07-24 13:11:38 -04:00
|
|
|
import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown";
|
|
|
|
|
|
|
|
|
|
import "./index.css";
|
2025-03-05 09:11:15 +05:30
|
|
|
import { useEffect, useRef, useState } from "react";
|
|
|
|
|
import { renderTruncatedValue } from "../../../Utils/truncateUtils.jsx";
|
2024-07-24 13:11:38 -04:00
|
|
|
|
2024-07-24 13:16:43 -04:00
|
|
|
/**
|
|
|
|
|
* @component
|
|
|
|
|
* @param {object} props
|
|
|
|
|
* @param {string} props.id - The ID attribute for the select element.
|
2024-07-24 14:09:24 -04:00
|
|
|
* @param {string} props.placeholder - The label of the select element.
|
2024-07-24 13:16:43 -04:00
|
|
|
* @param {string} props.placeholder - The placeholder text when no option is selected.
|
|
|
|
|
* @param {boolean} props.isHidden - Whether the placeholder should be hidden.
|
|
|
|
|
* @param {string} props.value - The currently selected value.
|
|
|
|
|
* @param {object[]} props.items - The array of items to populate in the select dropdown.
|
2024-07-24 14:33:25 -04:00
|
|
|
* @param {(string | number)} props.items._id - The unique identifier of each item.
|
2024-07-24 13:16:43 -04:00
|
|
|
* @param {string} props.items.name - The display name of each item.
|
|
|
|
|
* @param {function} props.onChange - The function to handle onChange event.
|
|
|
|
|
* @param {object} props.sx - The custom styles object for MUI Select component.
|
|
|
|
|
* @returns {JSX.Element}
|
2024-07-24 14:28:32 -04:00
|
|
|
*
|
|
|
|
|
* @example
|
|
|
|
|
* const frequencies = [
|
|
|
|
|
* { _id: 1, name: "1 minute" },
|
|
|
|
|
* { _id: 2, name: "2 minutes" },
|
|
|
|
|
* { _id: 3, name: "3 minutes" },
|
|
|
|
|
* ];
|
|
|
|
|
*
|
|
|
|
|
* <Select
|
|
|
|
|
* id="frequency-id"
|
2024-10-03 15:24:22 +08:00
|
|
|
* name="my-name"
|
2024-07-24 14:28:32 -04:00
|
|
|
* label="Check frequency"
|
2024-07-24 14:35:00 -04:00
|
|
|
* placeholder="Select frequency"
|
2024-07-24 14:28:32 -04:00
|
|
|
* value={value}
|
|
|
|
|
* onChange={handleChange}
|
|
|
|
|
* items={frequencies}
|
|
|
|
|
* />
|
2024-07-24 13:16:43 -04:00
|
|
|
*/
|
|
|
|
|
|
2024-07-24 14:09:24 -04:00
|
|
|
const Select = ({
|
2024-10-17 12:05:06 +08:00
|
|
|
id,
|
|
|
|
|
label,
|
|
|
|
|
placeholder,
|
|
|
|
|
isHidden,
|
|
|
|
|
value,
|
|
|
|
|
items,
|
|
|
|
|
onChange,
|
2024-10-23 13:18:00 -04:00
|
|
|
onBlur,
|
2024-10-17 12:05:06 +08:00
|
|
|
sx,
|
|
|
|
|
name = "",
|
2024-12-05 17:29:12 +05:30
|
|
|
labelControlSpacing = 2,
|
2025-03-05 09:11:15 +05:30
|
|
|
truncate = false,
|
|
|
|
|
maxStringLength = 10,
|
2024-07-24 14:09:24 -04:00
|
|
|
}) => {
|
2025-03-05 09:21:08 +05:30
|
|
|
const [maxLength, setMaxLength] = useState(0);
|
|
|
|
|
const selectRef = useRef(null);
|
2025-03-05 09:11:15 +05:30
|
|
|
|
2024-10-17 12:05:06 +08:00
|
|
|
const theme = useTheme();
|
|
|
|
|
const itemStyles = {
|
|
|
|
|
fontSize: "var(--env-var-font-size-medium)",
|
2025-01-12 09:39:31 -05:00
|
|
|
color: theme.palette.primary.contrastTextTertiary,
|
2024-10-17 12:05:06 +08:00
|
|
|
borderRadius: theme.shape.borderRadius,
|
|
|
|
|
margin: theme.spacing(2),
|
|
|
|
|
};
|
2025-01-07 21:27:52 -05:00
|
|
|
|
2025-03-05 09:11:15 +05:30
|
|
|
// Dynamically adjust maxLength based on window width
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (!truncate) return; // If truncate is false, do not run this effect
|
|
|
|
|
|
|
|
|
|
const calculateMaxLength = () => {
|
|
|
|
|
if (selectRef.current) {
|
|
|
|
|
const width = selectRef.current.offsetWidth;
|
|
|
|
|
const calculatedMaxLength = Math.floor(width / maxStringLength);
|
|
|
|
|
setMaxLength(calculatedMaxLength);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
calculateMaxLength();
|
|
|
|
|
window.addEventListener("resize", calculateMaxLength);
|
|
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
|
window.removeEventListener("resize", calculateMaxLength); // Cleanup on unmount
|
|
|
|
|
};
|
|
|
|
|
}, [maxStringLength, truncate]);
|
|
|
|
|
|
|
|
|
|
const selectedItemName = truncate
|
|
|
|
|
? items.find((item) => item._id === value)?.name // Only calculate if truncate is true
|
|
|
|
|
: null;
|
|
|
|
|
|
2024-10-17 12:05:06 +08:00
|
|
|
return (
|
|
|
|
|
<Stack
|
2024-12-05 17:29:12 +05:30
|
|
|
gap={theme.spacing(labelControlSpacing)}
|
2024-10-17 12:05:06 +08:00
|
|
|
className="select-wrapper"
|
|
|
|
|
>
|
|
|
|
|
{label && (
|
|
|
|
|
<Typography
|
|
|
|
|
component="h3"
|
2025-01-12 09:39:31 -05:00
|
|
|
color={theme.palette.primary.contrastTextSecondary}
|
2024-10-17 12:05:06 +08:00
|
|
|
fontWeight={500}
|
|
|
|
|
fontSize={13}
|
|
|
|
|
>
|
|
|
|
|
{label}
|
|
|
|
|
</Typography>
|
|
|
|
|
)}
|
|
|
|
|
<MuiSelect
|
2025-03-05 09:11:15 +05:30
|
|
|
ref={selectRef}
|
2024-10-17 12:05:06 +08:00
|
|
|
className="select-component"
|
|
|
|
|
value={value}
|
|
|
|
|
onChange={onChange}
|
2024-10-23 13:18:00 -04:00
|
|
|
onBlur={onBlur}
|
2024-10-17 12:05:06 +08:00
|
|
|
displayEmpty
|
|
|
|
|
name={name}
|
|
|
|
|
inputProps={{ id: id }}
|
|
|
|
|
IconComponent={KeyboardArrowDownIcon}
|
|
|
|
|
MenuProps={{ disableScrollLock: true }}
|
|
|
|
|
sx={{
|
|
|
|
|
fontSize: 13,
|
|
|
|
|
minWidth: "125px",
|
|
|
|
|
"& fieldset": {
|
|
|
|
|
borderRadius: theme.shape.borderRadius,
|
2025-01-08 21:41:59 -05:00
|
|
|
borderColor: theme.palette.primary.lowContrast,
|
2024-10-17 12:05:06 +08:00
|
|
|
},
|
|
|
|
|
"&:not(.Mui-focused):hover fieldset": {
|
2025-01-08 21:41:59 -05:00
|
|
|
borderColor: theme.palette.primary.lowContrast,
|
2024-10-17 12:05:06 +08:00
|
|
|
},
|
|
|
|
|
"& svg path": {
|
2025-01-12 09:39:31 -05:00
|
|
|
fill: theme.palette.primary.contrastTextTertiary,
|
2024-10-17 12:05:06 +08:00
|
|
|
},
|
|
|
|
|
...sx,
|
|
|
|
|
}}
|
2025-03-05 09:11:15 +05:30
|
|
|
renderValue={() =>
|
|
|
|
|
renderTruncatedValue(selectedItemName, truncate, maxLength, placeholder)
|
|
|
|
|
}
|
2024-10-17 12:05:06 +08:00
|
|
|
>
|
|
|
|
|
{placeholder && (
|
|
|
|
|
<MenuItem
|
|
|
|
|
className="select-placeholder"
|
|
|
|
|
value="0"
|
|
|
|
|
sx={{
|
|
|
|
|
display: isHidden ? "none" : "flex",
|
|
|
|
|
visibility: isHidden ? "none" : "visible",
|
|
|
|
|
...itemStyles,
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{placeholder}
|
|
|
|
|
</MenuItem>
|
|
|
|
|
)}
|
|
|
|
|
{items.map((item) => (
|
|
|
|
|
<MenuItem
|
|
|
|
|
value={item._id}
|
|
|
|
|
key={`${id}-${item._id}`}
|
|
|
|
|
sx={{
|
|
|
|
|
...itemStyles,
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{item.name}
|
|
|
|
|
</MenuItem>
|
|
|
|
|
))}
|
|
|
|
|
</MuiSelect>
|
|
|
|
|
</Stack>
|
|
|
|
|
);
|
2024-07-24 13:11:38 -04:00
|
|
|
};
|
|
|
|
|
|
2024-07-24 13:16:43 -04:00
|
|
|
Select.propTypes = {
|
2024-10-17 12:05:06 +08:00
|
|
|
id: PropTypes.string.isRequired,
|
|
|
|
|
name: PropTypes.string,
|
|
|
|
|
label: PropTypes.string,
|
|
|
|
|
placeholder: PropTypes.string,
|
|
|
|
|
isHidden: PropTypes.bool,
|
|
|
|
|
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
|
|
|
|
|
items: PropTypes.arrayOf(
|
|
|
|
|
PropTypes.shape({
|
|
|
|
|
_id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
|
|
|
|
|
name: PropTypes.string.isRequired,
|
|
|
|
|
})
|
|
|
|
|
).isRequired,
|
|
|
|
|
onChange: PropTypes.func.isRequired,
|
2024-10-23 13:18:00 -04:00
|
|
|
onBlur: PropTypes.func,
|
2024-10-17 12:05:06 +08:00
|
|
|
sx: PropTypes.object,
|
2024-12-05 17:46:55 +05:30
|
|
|
labelControlSpacing: PropTypes.number,
|
2025-03-05 09:11:15 +05:30
|
|
|
truncate: PropTypes.bool,
|
|
|
|
|
maxStringLength: PropTypes.number,
|
2024-07-24 13:16:43 -04:00
|
|
|
};
|
|
|
|
|
|
2024-07-24 13:11:38 -04:00
|
|
|
export default Select;
|