import { Field, FieldProps, useFormikContext } from "formik";
import { classNames } from "../../utils";
import { EyeIcon, EyeSlashIcon, CheckCircleIcon, XCircleIcon } from "@heroicons/react/24/solid";
import { useToggle } from "../../hooks/hooks";
import { CustomTooltip } from "../tooltips/CustomTooltip";
import { useEffect } from "react";
type COL_WIDTHS = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
interface TextFieldProps {
name: string;
defaultValue?: string;
label?: string;
placeholder?: string;
columns?: COL_WIDTHS;
autoComplete?: string;
hidden?: boolean;
disabled?: boolean;
tooltip?: JSX.Element;
}
export const TextField = ({
name,
defaultValue,
label,
placeholder,
columns,
autoComplete,
hidden,
tooltip,
disabled
}: TextFieldProps) => (
{label && (
{label}
{tooltip && (
{tooltip}
)}
)}
{({
field,
meta
}: FieldProps) => (
{meta.touched && meta.error && (
* {meta.error}
)}
)}
);
interface RegexFieldProps {
name: string;
defaultValue?: string;
label?: string;
placeholder?: string;
columns?: COL_WIDTHS;
autoComplete?: string;
useRegex?: boolean;
hidden?: boolean;
disabled?: boolean;
tooltip?: JSX.Element;
}
export const RegexField = ({
name,
defaultValue,
label,
placeholder,
columns,
autoComplete,
useRegex,
hidden,
tooltip,
disabled
}: RegexFieldProps) => {
const validRegex = (pattern: string) => {
// Check for unsupported lookahead and lookbehind assertions
if (/\(\?<=|\(\?/.test(pattern)) {
return false;
}
// Check for unsupported recursive patterns
if (/\(\?(R|0)\)/.test(pattern)) {
return false;
}
// Check for unsupported possessive quantifiers
if (/[*+?]{1}\+|\{[0-9]+,[0-9]*\}\+/.test(pattern)) {
return false;
}
// Check for unsupported control verbs
if (/\\g {
let error = "";
if (!validRegex(val)) {
error = "Invalid regex";
}
return error;
};
const { validateForm } = useFormikContext();
useEffect(() => {
if (useRegex) {
validateForm();
}
}, [useRegex]);
return (
{label && (
{label}
{tooltip && {tooltip} }
)}
{({ field, meta }: FieldProps) => (
{useRegex && (
{!meta.error ? (
) : (
)}
)}
)}
);
};
interface TextAreaProps {
name: string;
defaultValue?: string;
label?: string;
placeholder?: string;
columns?: COL_WIDTHS;
rows?: number;
autoComplete?: string;
hidden?: boolean;
disabled?: boolean;
}
export const TextArea = ({
name,
defaultValue,
label,
placeholder,
columns,
rows,
autoComplete,
hidden,
disabled
}: TextAreaProps) => (
{label && (
{label}
)}
{({
field,
meta
}: FieldProps) => (
{meta.touched && meta.error && (
* {meta.error}
)}
)}
);
interface PasswordFieldProps {
name: string;
label?: string;
placeholder?: string;
columns?: COL_WIDTHS;
autoComplete?: string;
defaultValue?: string;
help?: string;
required?: boolean;
}
export const PasswordField = ({
name,
label,
placeholder,
defaultValue,
columns,
autoComplete,
help,
required
}: PasswordFieldProps) => {
const [isVisible, toggleVisibility] = useToggle(false);
return (
{label && (
{label} {required && * }
)}
{({
field,
meta
}: FieldProps) => (
<>
{help && (
{help}
)}
{meta.touched && meta.error && (
* {meta.error}
)}
>
)}
);
};
interface NumberFieldProps {
name: string;
label?: string;
placeholder?: string;
step?: number;
disabled?: boolean;
required?: boolean;
min?: number;
max?: number;
tooltip?: JSX.Element;
}
export const NumberField = ({
name,
label,
placeholder,
step,
min,
max,
tooltip,
disabled,
required
}: NumberFieldProps) => (
{label}
{tooltip && {tooltip} }
{({ field, meta, form }: FieldProps) => (
{
// safeguard and validation if user removes the number
// it will then set 0 by default. Formik can't handle this properly
if (event.target.value == "") {
form.setFieldValue(field.name, 0);
return;
}
form.setFieldValue(field.name, parseInt(event.target.value)); // Convert the input value to an integer using parseInt() to ensure that the backend can properly parse the numberfield as an integer.
}}
onWheel={(event) => {
if (event.currentTarget === document.activeElement) {
event.currentTarget.blur();
setTimeout(() => event.currentTarget.focus(), 0);
}
}}
/>
{meta.touched && meta.error && (
{meta.error}
)}
)}
);