diff --git a/Client/src/Components/Inputs/Field/index.css b/Client/src/Components/Inputs/Field/index.css new file mode 100644 index 000000000..3a8904b27 --- /dev/null +++ b/Client/src/Components/Inputs/Field/index.css @@ -0,0 +1,89 @@ +.field { + min-width: 250px; +} +.field h3.MuiTypography-root, +.field h5.MuiTypography-root, +.field input, +.field textarea, +.field .input-error { + font-size: var(--env-var-font-size-medium); +} +.field h3.MuiTypography-root, +.field h5.MuiTypography-root, +.field input, +.field textarea { + color: var(--env-var-color-5); +} +.field h3.MuiTypography-root { + font-weight: 500; +} +.field h3.MuiTypography-root span.field-required { + color: var(--env-var-color-19); + margin-left: 2px; +} +.field h3.MuiTypography-root span.field-optional { + opacity: 0.6; + margin-left: 4px; +} +.field h5.MuiTypography-root { + position: relative; + opacity: 0.8; + padding-right: var(--env-var-spacing-1-minus); +} +.field .MuiInputBase-root:has(input) { + height: 34px; +} +.field .MuiInputBase-root:has(.MuiInputAdornment-root) { + padding-right: var(--env-var-spacing-1-minus); +} +.field .MuiInputBase-root:has(.copy.MuiInputAdornment-root > .MuiButtonBase-root) { + padding-right: 0; +} +.field .MuiInputBase-root .copy.MuiInputAdornment-root .MuiButtonBase-root { + padding: 0 var(--env-var-spacing-1-minus); + font-size: var(--env-var-font-size-medium); + border-radius: 0; + height: 34px; +} +.field .MuiInputBase-root .copy.MuiInputAdornment-root .MuiButtonBase-root svg { + width: 20px; + height: 20px; + margin-right: 5px; +} +.field .MuiInputBase-root .MuiInputAdornment-root .MuiButtonBase-root:hover { + border-color: var(--env-var-color-29); +} +.field input { + height: 100%; + padding: 0 var(--env-var-spacing-1-minus); +} +.field .MuiInputBase-root:has(textarea) { + padding: var(--env-var-spacing-1-minus); +} +.field .MuiOutlinedInput-root fieldset { + border-color: var(--env-var-color-29); + border-radius: var(--env-var-radius-1); +} +.field:not(:has(.input-error)) + .MuiOutlinedInput-root:hover:not(:has(input:focus)):not(:has(textarea:focus)) + fieldset { + border-color: var(--env-var-color-29); +} +.field .input-error { + color: var(--env-var-color-24); + opacity: 0.8; +} +.field:has(.input-error) .MuiOutlinedInput-root fieldset { + border-color: var(--env-var-color-19); +} + +.register-page .field .MuiOutlinedInput-root fieldset, +.register-page .field input, +.login-page .field .MuiOutlinedInput-root fieldset, +.login-page .field input, +.forgot-password-page .field .MuiOutlinedInput-root fieldset, +.forgot-password-page .field input, +.set-new-password-page .field .MuiOutlinedInput-root fieldset, +.set-new-password-page .field input { + border-radius: var(--env-var-radius-2); +} diff --git a/Client/src/Components/Inputs/Field/index.jsx b/Client/src/Components/Inputs/Field/index.jsx new file mode 100644 index 000000000..06594450a --- /dev/null +++ b/Client/src/Components/Inputs/Field/index.jsx @@ -0,0 +1,158 @@ +import PropTypes from "prop-types"; +import { useTheme } from "@emotion/react"; +import { + IconButton, + InputAdornment, + Stack, + TextField, + Typography, +} from "@mui/material"; +import VisibilityOff from "@mui/icons-material/VisibilityOff"; +import Visibility from "@mui/icons-material/Visibility"; +import ContentCopyIcon from "@mui/icons-material/ContentCopy"; +import Button from "../../Button"; +import "./index.css"; +import { useState } from "react"; + +/** + * @param {Object} props + * @param {string} [props.type] - Type of input field (e.g., 'text', 'password'). + * @param {string} props.id - ID of the input field. + * @param {string} [props.label] - Label for the input field. + * @param {boolean} [props.isRequired] - Indicates if the field is required, will display a red asterisk. + * @param {boolean} [props.isOptional] - Indicates if the field is optional, will display optional text. + * @param {boolean} [props.hasCopy] - Indicates if the field supports copying. + * @param {string} [props.autoComplete] - Autocomplete value for the input field. + * @param {string} [props.placeholder] - Placeholder text for the input field. + * @param {string} props.value - Value of the input field. + * @param {function} props.onChange - Function called on input change. + * @param {string} [props.error] - Error message to display for the input field. + * @param {boolean} [props.disabled] - Indicates if the input field is disabled. + */ + +const Field = ({ + type = "text", + id, + label, + isRequired, + isOptional, + hasCopy, + autoComplete, + placeholder, + value, + onChange, + error, + disabled, +}) => { + const theme = useTheme(); + + // TODO - are we using this feature anywhere ? + const [copy, setCopy] = useState(false); + const handleCopy = () => { + setCopy(true); + setTimeout(() => setCopy(false), 1000); + }; + + const [isVisible, setVisible] = useState(false); + + return ( + + {label && ( + + {label} + {isRequired ? * : ""} + {isOptional ? (optional) : ""} + + )} + + https:// + + ), + endAdornment: + type === "password" ? ( + + setVisible((show) => !show)} + tabIndex={-1} + sx={{ + color: theme.palette.section.borderColor, + padding: `calc(${theme.gap.xs} / 2)`, + "&:focus": { + outline: "none", + }, + "& .MuiTouchRipple-root": { + pointerEvents: "none", + display: "none", + }, + }} + > + {!isVisible ? : } + + + ) : ( + hasCopy && ( + +