add masking
This commit is contained in:
parent
b46be19a22
commit
5859820f2e
|
|
@ -2,6 +2,7 @@ import React from "react";
|
||||||
|
|
||||||
import tw from "twin.macro";
|
import tw from "twin.macro";
|
||||||
import { useField as useFormikField, useFormikContext, FieldHookConfig } from "formik";
|
import { useField as useFormikField, useFormikContext, FieldHookConfig } from "formik";
|
||||||
|
import { IMaskInput, IMaskInputProps, IMaskMixinProps } from 'react-imask';
|
||||||
//const useFormikField = null;
|
//const useFormikField = null;
|
||||||
//const useFormikContext = ()=>{};
|
//const useFormikContext = ()=>{};
|
||||||
|
|
||||||
|
|
@ -17,7 +18,7 @@ export function useField(props) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Input(
|
export default function Input(
|
||||||
props: React.InputHTMLAttributes<HTMLInputElement> & {
|
props: React.InputHTMLAttributes<HTMLInputElement> & FieldHookConfig<any> & {
|
||||||
label?: React.ComponentPropsWithoutRef<"label">;
|
label?: React.ComponentPropsWithoutRef<"label">;
|
||||||
title?: string;
|
title?: string;
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
|
|
@ -44,7 +45,7 @@ export default function Input(
|
||||||
{/*name={name || title} id={id || name || title}*/}
|
{/*name={name || title} id={id || name || title}*/}
|
||||||
<input
|
<input
|
||||||
id={props.id ?? props.name ?? props.title}
|
id={props.id ?? props.name ?? props.title}
|
||||||
{...otherProps}
|
{...otherProps as any}
|
||||||
{...field}
|
{...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 "
|
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 "
|
||||||
/>
|
/>
|
||||||
|
|
@ -55,6 +56,54 @@ export default function Input(
|
||||||
</div>
|
</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({
|
export function TextArea({
|
||||||
title,
|
title,
|
||||||
children = null,
|
children = null,
|
||||||
|
|
|
||||||
37
Parts/PreMaskedInput.tsx
Normal file
37
Parts/PreMaskedInput.tsx
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
import { MaskedInput } from "./Input";
|
||||||
|
|
||||||
|
export type PreMaskedProps = Omit<React.ComponentPropsWithoutRef<typeof MaskedInput>, "mask" | "definitions">
|
||||||
|
|
||||||
|
export function IbanInput(props: PreMaskedProps) {
|
||||||
|
return <MaskedInput {...props}
|
||||||
|
mask="XXXX XXXX XXXX XXXX [XXXX] [XXXX] [XXXX] [XX]"
|
||||||
|
definitions={{ 'X': /[0-9A-Z]/ }}
|
||||||
|
prepare={(str: string) => str.toUpperCase()}
|
||||||
|
validate={(iban: string) => {
|
||||||
|
console.log(iban);
|
||||||
|
|
||||||
|
if (iban.length < 15 || iban.length > 34)
|
||||||
|
return "Invalid length";
|
||||||
|
|
||||||
|
// Rearranged IBAN
|
||||||
|
const rearranged = iban.slice(4) + iban.slice(0, 4);
|
||||||
|
|
||||||
|
// Convert letters to numbers (A=10 ... Z=35)
|
||||||
|
const converted = rearranged.replace(/[A-Z]/g, ch => (ch.charCodeAt(0) - 55).toString());
|
||||||
|
|
||||||
|
// Perform mod-97 check
|
||||||
|
let remainder = converted;
|
||||||
|
let block;
|
||||||
|
|
||||||
|
while (remainder.length > 2) {
|
||||||
|
block = remainder.slice(0, 9);
|
||||||
|
remainder = (parseInt(block, 10) % 97).toString() + remainder.slice(block.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parseInt(remainder, 10) % 97 !== 1)
|
||||||
|
return "Invalid checksum";
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user