sanniassin / react-input-mask

Input masking component for React. Made with attention to UX.
MIT License
2.21k stars 257 forks source link

'InputMask' cannot be used as a JSX component. How to solve? #315

Closed paulinha-19 closed 10 months ago

paulinha-19 commented 11 months ago

i am getting below error in vscode terminal.

I am recive 'InputMask' cannot be used as a JSX component.
  Its instance type 'ReactInputMask' is not a valid JSX element.
    The types returned by 'render()' are incompatible between these types.
      Type 'React.ReactNode' is not assignable to type 'import("c:/Users/John/node_modules/@types/react/index").ReactNode'.
        Type '{}' is not assignable to type 'ReactNode'.

This is my package.json

{
  "name": "frontend",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "@chakra-ui/react": "^1.8.9",
    "@emotion/react": "^11.11.1",
    "@emotion/styled": "^11.11.0",
    "@hookform/resolvers": "^3.2.0",
    "framer-motion": "^6.5.1",
    "next": "^12.3.4",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-hook-form": "^7.45.4",
    "react-input-mask": "^2.0.4",
    "styled-components": "^6.0.7",
    "zod": "^3.21.4"
  },
  "devDependencies": {
    "@types/node": "20.4.8",
    "@types/react": "^17.0.64",
    "@types/react-dom": "^17.0.20",
    "@types/react-input-mask": "^3.0.2",
    "@typescript-eslint/eslint-plugin": "^6.3.0",
    "@typescript-eslint/parser": "^6.3.0",
    "eslint": "^8.46.0",
    "eslint-config-next": "13.4.13",
    "eslint-config-prettier": "^9.0.0",
    "eslint-plugin-import-helpers": "^1.3.1",
    "eslint-plugin-prettier": "^5.0.0",
    "eslint-plugin-react": "^7.33.1",
    "eslint-plugin-react-hooks": "^5.0.0-canary-7118f5dd7-20230705",
    "install": "^0.13.0",
    "prettier": "3.0.1",
    "typescript": "^5.1.6"
  }
}

This is the component with error.

import React from 'react';
import { useForm, Controller } from 'react-hook-form';
import { z } from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';
import userSchema from '../../schema/signup';
import { useRouter } from 'next/router';
import {
  Button,
  Flex,
  Box,
  FormControl,
  FormLabel,
  Heading,
  Input,
  Stack,
  Image,
  Select,
  FormErrorMessage,
  Switch
} from '@chakra-ui/react';
import InputMask from 'react-input-mask';

type FormData = z.infer<typeof userSchema>;

export const SignUp = () => {
  const {
    register,
    handleSubmit,
    control,
    formState: { errors, isValid }
  } = useForm<FormData>({
    resolver: zodResolver(userSchema)
  });
  const router = useRouter();
  const handleLogin = () => {
    // router.push('/login');
  };
  const handleForm = (data: FormData) => {
    console.log('submitted data', data);
    // handleLogin();
  };
  console.log(errors);
  return (
    <Stack minH={'100vh'} direction={{ base: 'column', lg: 'row' }}>
      <Flex p={8} flex={1} align={'center'} justify={'center'} bg="gray.300">
        <Stack spacing={4} w={'full'} maxW={'xl'}>
          <form onSubmit={handleSubmit(handleForm)}>
            <Heading fontSize={'2xl'}>Sign in to your account</Heading>
            <FormControl id="name" isInvalid={!!errors.name}>
              <FormLabel>Name</FormLabel>
              <Input
                type="text"
                {...register('name')}
                placeholder="Insert name"
              />
              <FormErrorMessage>{errors.name?.message}</FormErrorMessage>
            </FormControl>
            <FormControl id="username" isInvalid={!!errors.username}>
              <FormLabel>Username</FormLabel>
              <Input
                type="text"
                {...register('username')}
                placeholder="Insert username"
              />
              <FormErrorMessage>{errors.username?.message}</FormErrorMessage>
            </FormControl>
            <FormControl id="email" isInvalid={!!errors.email}>
              <FormLabel>Email</FormLabel>
              <Input
                type="email"
                {...register('email')}
                placeholder="Insert email"
              />
              <FormErrorMessage>{errors.email?.message}</FormErrorMessage>
            </FormControl>
            <FormControl id="password" isInvalid={!!errors.password}>
              <FormLabel>Password</FormLabel>
              <Input
                type="password"
                {...register('password')}
                placeholder="Insert password"
              />
              <FormErrorMessage>{errors.password?.message}</FormErrorMessage>
            </FormControl>
            <FormControl
              id="confirm-password"
              isInvalid={!!errors.confirmPassword}
            >
              <FormLabel>Confirm password</FormLabel>
              <Input
                type="password"
                {...register('confirmPassword')}
                placeholder="Confirm password"
              />
              <FormErrorMessage>
                {errors.confirmPassword?.message}
              </FormErrorMessage>
            </FormControl>
            <FormControl id="birth" isInvalid={!!errors.birth}>
              <FormLabel>Date birth</FormLabel>
              <Input
                type="text"
                {...register('birth')}
                placeholder="Insert birth"
              />
              <FormErrorMessage>{errors.birth?.message}</FormErrorMessage>
            </FormControl>
            <FormControl id="cpf" isInvalid={!!errors.cpf}>
              <FormLabel>Cpf</FormLabel>
              <Controller
                name="cpf"
                control={control}
                render={({ field: { onChange, value } }) => (
                  <>
                    <InputMask
                      mask="999.999.999-99"
                      placeholder="000.000.000-00"
                      value={value}
                      onChange={onChange}
                    >
                      {(inputProps: any) => <Input {...inputProps} />}
                    </InputMask>
                    <FormErrorMessage>{errors.cpf?.message}</FormErrorMessage>
                  </>
                )}
              />
            </FormControl>
            <FormControl id="phone" isInvalid={!!errors.phone}>
              <FormLabel>Phone</FormLabel>
              <Input
                type="text"
                {...register('phone')}
                placeholder="Insert phone"
              />
              <FormErrorMessage>{errors.phone?.message}</FormErrorMessage>
            </FormControl>
            <FormControl id="gender" isInvalid={!!errors.gender}>
              <FormLabel>Gender</FormLabel>
              <Select {...register('gender')}>
                <option value="">Select gender</option>
                <option value="Feminino">Feminino</option>
                <option value="Masculino">Masculino</option>
                <option value="Não binario">Não binario</option>
                <option value="Prefiro não informar">
                  Prefiro não informar
                </option>
              </Select>
              <FormErrorMessage>{errors.gender?.message}</FormErrorMessage>
            </FormControl>
            <Box w="100%">
              <Button
                colorScheme={'blue'}
                variant={'solid'}
                type="submit"
                // disabled={!!isValid}
              >
                Sign in
              </Button>
            </Box>
          </form>
        </Stack>
      </Flex>
      <Flex flex={1}>
        <Image
          alt={'Login Image'}
          objectFit={'fill'}
          src={
            'https://images.unsplash.com/photo-1486312338219-ce68d2c6f44d?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1352&q=80'
          }
        />
      </Flex>
    </Stack>
  );
};

Why this error? What is the reason? Help

react-input-mask

chris-snow commented 9 months ago

@paulinha-19 Interested to know whether or not you found a solution?

manojadams commented 3 months ago

I have faced the same problem and manually resolved this by using own declaration file which is a copy from original @types/react-input-mask (not installed) with some modification. Below is the file index.d.ts

declare module "react-input-mask" {
    export interface Selection {
        start: number;
        end: number;
    }

    export interface InputState {
        value: string;
        selection: Selection | null;
    }

    export interface BeforeMaskedStateChangeStates {
        previousState: InputState;
        currentState: InputState;
        nextState: InputState;
    }

    export interface Props extends React.InputHTMLAttributes<HTMLInputElement> {
        /**
         * Mask string. Format characters are:
         * * `9`: `0-9`
         * * `a`: `A-Z, a-z`
         * * `\*`: `A-Z, a-z, 0-9`
         *
         * Any character can be escaped with backslash, which usually will appear as double backslash in JS strings.
         * For example, German phone mask with unremoveable prefix +49 will look like `mask="+4\\9 99 999 99"` or `mask={"+4\\\\9 99 999 99"}`
         */
        mask: string | Array<(string | RegExp)>;
        /**
         * Character to cover unfilled editable parts of mask. Default character is "_". If set to null, unfilled parts will be empty, like in ordinary input.
         */
        maskChar?: string | null | undefined;
        maskPlaceholder?: string | null | undefined;
        /**
         * Show mask even in empty input without focus.
         */
        alwaysShowMask?: boolean | undefined;
        /**
         * Use inputRef instead of ref if you need input node to manage focus, selection, etc.
         */
        inputRef?: React.Ref<HTMLInputElement> | undefined;
        /**
         * In case you need to implement more complex masking behavior, you can provide
         * beforeMaskedStateChange function to change masked value and cursor position
         * before it will be applied to the input.
         *
         * * previousState: Input state before change. Only defined on change event.
         * * currentState: Current raw input state. Not defined during component render.
         * * nextState: Input state with applied mask. Contains value and selection fields.
         */
        beforeMaskedStateChange?(states: BeforeMaskedStateChangeStates): InputState;
        children: (props: any) => JSX.Element;
    }
    function InputMask(props: Props): JSX.Element;
    export default InputMask;
}