188 lines
5.8 KiB
TypeScript
188 lines
5.8 KiB
TypeScript
import React from "react";
|
|
|
|
import tw from "twin.macro";
|
|
import { useField as useFormikField, useFormikContext, FieldHookConfig } from "formik";
|
|
import { IMaskInput, IMaskInputProps, IMaskMixinProps } from 'react-imask';
|
|
//const useFormikField = null;
|
|
//const useFormikContext = ()=>{};
|
|
|
|
export function useField<Val=any>(props) {
|
|
let getField = useFormikField<Val>;
|
|
const context = useFormikContext();
|
|
if (!context) {
|
|
getField = (propsOrFieldName: FieldHookConfig<any>) => {
|
|
return [props, null, null];
|
|
}
|
|
}
|
|
return getField(props);
|
|
}
|
|
|
|
export default function Input(
|
|
props: React.InputHTMLAttributes<HTMLInputElement> & FieldHookConfig<any> & {
|
|
label?: React.ComponentPropsWithoutRef<"label">;
|
|
title?: string;
|
|
children?: React.ReactNode;
|
|
className?: string;
|
|
}
|
|
) {
|
|
/*name, id*/
|
|
let { children, ...otherProps } = props;
|
|
|
|
const [field, meta, helpers] = useField(otherProps);
|
|
|
|
return (
|
|
<div css={[props.title && tw`my-1`, tw`relative`]} className={props.className}>
|
|
{props.title && (
|
|
<label
|
|
{...props.label}
|
|
htmlFor={props.id ?? props.name ?? props.title}
|
|
css={[tw`block text-secondary text-sm font-bold mb-2`, props.label?.css]}
|
|
>
|
|
{/*htmlFor={id ?? name ?? title}*/}
|
|
{props.title}
|
|
</label>
|
|
)}
|
|
{/*name={name || title} id={id || name || title}*/}
|
|
<input
|
|
id={props.id ?? props.name ?? props.title}
|
|
{...field}
|
|
{...otherProps as any}
|
|
tw="bg-primary appearance-none border-2 border-secondary rounded w-full py-2 px-4 text-primary leading-tight focus:outline-none focus:bg-secondary focus:border-accent transition duration-150 "
|
|
/>
|
|
{props.children}
|
|
{meta?.touched && meta.error ? (
|
|
<div tw="text-[#c23c3c]">{meta.error}</div>
|
|
) : null}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export function MaskedInput(
|
|
props: Omit<IMaskInputProps<HTMLInputElement>, "validate" | "label"> & FieldHookConfig<any> & {
|
|
definitions: { [k: string]: RegExp };
|
|
|
|
label?: React.ComponentPropsWithoutRef<"label">;
|
|
title?: string;
|
|
children?: React.ReactNode;
|
|
className?: string;
|
|
}
|
|
) {
|
|
/*name, id*/
|
|
let { children, validate, ...otherProps } = props;
|
|
|
|
const [field, meta, helpers] = useField({ ...otherProps, validate });
|
|
|
|
return (
|
|
<div css={[props.title && tw`my-1`, tw`relative`]} className={props.className}>
|
|
{props.title && (
|
|
<label
|
|
{...props.label}
|
|
//htmlFor={props.id ?? props.name ?? props.title}
|
|
css={[tw`block text-secondary text-sm font-bold mb-2`, props.label?.css]}
|
|
>
|
|
{/*htmlFor={id ?? name ?? title}*/}
|
|
{props.title}
|
|
</label>
|
|
)}
|
|
{/*name={name || title} id={id || name || title}*/}
|
|
<IMaskInput
|
|
//id={props.id ?? props.name ?? props.title}
|
|
{...otherProps as any}
|
|
value={field.value}
|
|
unmask="typed"
|
|
onAccept={
|
|
(value, mask) => field.onChange({ target: { value, name: field.name } })
|
|
}
|
|
onBlur={field.onBlur}
|
|
tw="bg-primary appearance-none border-2 border-secondary rounded w-full py-2 px-4 text-primary leading-tight focus:outline-none focus:bg-secondary focus:border-accent transition duration-150 "
|
|
/>
|
|
{props.children}
|
|
{meta?.touched && meta.error ? (
|
|
<div tw="text-[#c23c3c]">{meta.error}</div>
|
|
) : null}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export function TextArea({
|
|
title,
|
|
children = null,
|
|
label = null,
|
|
...props
|
|
}) {
|
|
|
|
const [field, meta, helpers] = useField(props);
|
|
|
|
return (
|
|
<div css={[title && tw`my-1`]} >
|
|
{title && (
|
|
<label
|
|
{...label}
|
|
css={[tw`block text-secondary text-sm font-bold mb-2`, label?.css]}
|
|
|
|
>
|
|
{title}
|
|
</label>
|
|
)}
|
|
<textarea
|
|
{...props}
|
|
{...field}
|
|
tw="bg-primary appearance-none border-2 border-secondary rounded w-full py-2 px-4 text-primary leading-tight focus:outline-none focus:bg-secondary focus:border-accent transition duration-150 "
|
|
/>
|
|
{children}
|
|
{meta?.touched && meta.error ? (
|
|
<div tw="text-[#c23c3c]">{meta.error}</div>
|
|
) : null}
|
|
</div>
|
|
);
|
|
}
|
|
/**
|
|
* Renders a checkbox input with optional label and error message.
|
|
*
|
|
* @param {Object} props - The properties for the CheckBox component.
|
|
* @param {string} props.label - The label for the checkbox.
|
|
* @param {string} props.title - The title for the checkbox.
|
|
* @param {string} props.className - The class name for the container div.
|
|
* @param {ReactNode} props.children - The children components.
|
|
* @param {Object} props... - Additional properties for the checkbox input.
|
|
* @return {ReactElement} The rendered CheckBox component.
|
|
*/
|
|
export function CheckBox(
|
|
props: (Omit<React.InputHTMLAttributes<HTMLInputElement>, "value" | "checked"> | Omit<FieldHookConfig<boolean>, "value">) & {
|
|
label?: React.ComponentPropsWithoutRef<"label">;
|
|
title?: string;
|
|
children?: React.ReactNode;
|
|
className?: string;
|
|
value?: boolean
|
|
}
|
|
) {
|
|
/*name, id*/
|
|
const { children, ...otherProps } = props;
|
|
|
|
const [field, meta, helpers] = useField<boolean>(otherProps);
|
|
|
|
return (
|
|
<div tw="my-1 flex text-secondary">
|
|
<input
|
|
id={props.id ?? props.name ?? props.title}
|
|
checked={otherProps?.value == undefined ? field.value : otherProps?.value}
|
|
{...field}
|
|
{...otherProps as any}
|
|
type="checkbox"
|
|
tw="checked:bg-accent w-6 h-6 rounded-full bg-secondary border-secondary border-4 appearance-none cursor-pointer "
|
|
/>
|
|
{props.title && (
|
|
<label
|
|
{...props.label}
|
|
htmlFor={props.id ?? props.name ?? props.title}
|
|
css={[tw`block text-secondary text-sm font-bold mb-2`, props.label?.css]}
|
|
>
|
|
{/*htmlFor={id ?? name ?? title}*/}
|
|
{props.title}
|
|
</label>
|
|
)}
|
|
{children}
|
|
</div>
|
|
);
|
|
}
|