mirror of
https://github.com/bluewave-labs/Checkmate.git
synced 2026-01-20 16:49:46 -06:00
148 lines
2.9 KiB
JavaScript
148 lines
2.9 KiB
JavaScript
import { Stack, TextField, Typography } from "@mui/material";
|
|
import { useTheme } from "@emotion/react";
|
|
import { forwardRef, useState, cloneElement } from "react";
|
|
import PropTypes from "prop-types";
|
|
|
|
const getSx = (theme, type, maxWidth) => {
|
|
const sx = {
|
|
maxWidth: maxWidth,
|
|
"& .MuiFormHelperText-root": {
|
|
position: "absolute",
|
|
bottom: `-${theme.spacing(12)}`,
|
|
minHeight: theme.spacing(12),
|
|
},
|
|
};
|
|
|
|
if (type === "url") {
|
|
return {
|
|
...sx,
|
|
"& .MuiInputBase-root": { padding: 0 },
|
|
"& .MuiStack-root": {
|
|
borderTopLeftRadius: theme.shape.borderRadius,
|
|
borderBottomLeftRadius: theme.shape.borderRadius,
|
|
},
|
|
};
|
|
}
|
|
return sx;
|
|
};
|
|
|
|
const Required = () => {
|
|
const theme = useTheme();
|
|
return (
|
|
<Typography
|
|
component="span"
|
|
ml={theme.spacing(1)}
|
|
color={theme.palette.error.main}
|
|
>
|
|
*
|
|
</Typography>
|
|
);
|
|
};
|
|
|
|
const Optional = ({ optionalLabel }) => {
|
|
const theme = useTheme();
|
|
return (
|
|
<Typography
|
|
component="span"
|
|
fontSize="inherit"
|
|
fontWeight={400}
|
|
ml={theme.spacing(2)}
|
|
sx={{ opacity: 0.6 }}
|
|
>
|
|
{optionalLabel || "(optional)"}
|
|
</Typography>
|
|
);
|
|
};
|
|
|
|
Optional.propTypes = {
|
|
optionalLabel: PropTypes.string,
|
|
};
|
|
|
|
const TextInput = forwardRef(
|
|
(
|
|
{
|
|
id,
|
|
name,
|
|
type,
|
|
value,
|
|
placeholder,
|
|
isRequired,
|
|
isOptional,
|
|
optionalLabel,
|
|
onChange,
|
|
onBlur,
|
|
error = false,
|
|
helperText = null,
|
|
startAdornment = null,
|
|
endAdornment = null,
|
|
label = null,
|
|
maxWidth = "100%",
|
|
disabled = false,
|
|
},
|
|
ref
|
|
) => {
|
|
const [fieldType, setFieldType] = useState(type);
|
|
const theme = useTheme();
|
|
return (
|
|
<Stack>
|
|
<Typography
|
|
component="h3"
|
|
fontSize={"var(--env-var-font-size-medium)"}
|
|
color={theme.palette.text.secondary}
|
|
fontWeight={500}
|
|
>
|
|
{label}
|
|
{isRequired && <Required />}
|
|
{isOptional && <Optional optionalLabel={optionalLabel} />}
|
|
</Typography>
|
|
<TextField
|
|
id={id}
|
|
name={name}
|
|
type={fieldType}
|
|
value={value}
|
|
placeholder={placeholder}
|
|
onChange={onChange}
|
|
onBlur={onBlur}
|
|
error={error}
|
|
helperText={helperText}
|
|
inputRef={ref}
|
|
sx={getSx(theme, type, maxWidth)}
|
|
slotProps={{
|
|
input: {
|
|
startAdornment: startAdornment,
|
|
endAdornment: endAdornment
|
|
? cloneElement(endAdornment, { fieldType, setFieldType })
|
|
: null,
|
|
},
|
|
}}
|
|
disabled={disabled}
|
|
/>
|
|
</Stack>
|
|
);
|
|
}
|
|
);
|
|
|
|
TextInput.displayName = "TextInput";
|
|
|
|
TextInput.propTypes = {
|
|
type: PropTypes.string,
|
|
id: PropTypes.string.isRequired,
|
|
name: PropTypes.string,
|
|
value: PropTypes.string,
|
|
placeholder: PropTypes.string,
|
|
isRequired: PropTypes.bool,
|
|
isOptional: PropTypes.bool,
|
|
optionalLabel: PropTypes.string,
|
|
onChange: PropTypes.func,
|
|
onBlur: PropTypes.func,
|
|
error: PropTypes.bool,
|
|
helperText: PropTypes.string,
|
|
startAdornment: PropTypes.node,
|
|
endAdornment: PropTypes.node,
|
|
label: PropTypes.string,
|
|
maxWidth: PropTypes.string,
|
|
disabled: PropTypes.bool,
|
|
};
|
|
|
|
export default TextInput;
|