MathiasGilson/Tailwind-Styled-Component

Typing Error when I pass ref to tw component

theaungmyatmoe opened this issue · 0 comments

Error is occurred when I am building next .

web:build: cache miss, executing 1a17b82bd68f9942
web:build: 
web:build: > web@0.0.0 build /home/amm834/workspace/component-lib/apps/web
web:build: > next build
web:build: 
web:build: info  - Linting and checking validity of types...
web:build: Failed to compile.
web:build: 
web:build: ../../packages/ui/components/field/Input.tsx:16:9
web:build: Type error: No overload matches this call.
web:build:   Overload 2 of 2, '(props: TailwindComponentPropsWith$As<DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, IStyledInputProps, "input", Pick<...> & { ...; }>): ReactElement<...>', gave the following error.
web:build:     Type 'ForwardedRef<HTMLLabelElement>' is not assignable to type '((string | ((instance: HTMLInputElement | null) => void) | RefObject<HTMLInputElement>) & RefObject<HTMLInputElement> & (((instance: HTMLInputElement | null) => void) | RefObject<...>)) | null | undefined'.
web:build:       Type '(instance: HTMLLabelElement | null) => void' is not assignable to type '((string | ((instance: HTMLInputElement | null) => void) | RefObject<HTMLInputElement>) & RefObject<HTMLInputElement> & (((instance: HTMLInputElement | null) => void) | RefObject<...>)) | null | undefined'.
web:build:         Type '(instance: HTMLLabelElement | null) => void' is not assignable to type '((instance: HTMLInputElement | null) => void) & RefObject<HTMLInputElement>'.
web:build: 
web:build:   14 |       <StyledInput
web:build:   15 |         $as="input"
web:build: > 16 |         ref={ref}
web:build:      |         ^
web:build:   17 |         id={id}
web:build:   18 |         disabled={disabled}
web:build:   19 |         {...rest}
web:build:  ELIFECYCLE  Command failed with exit code 1.
web:build: ERROR: command finished with error: command (/home/amm834/workspace/component-lib/apps/web) pnpm run build exited (1)
command (/home/amm834/workspace/component-lib/apps/web) pnpm run build exited (1)

 Tasks:    0 successful, 1 total
Cached:    0 cached, 1 total
  Time:    8.346s 

 ERROR  run failed: command  exited (1)
 ELIFECYCLE  Command failed with exit code 1.
➜  component-lib git:(main

StyledInput.tsx

import tw from "tailwind-styled-components";
import { IInputProps } from "./Input";

export const StyledInput = tw.input<IInputProps>`
      mt-1 block w-full px-3 py-2 bg-white border border-slate-300 rounded-md text-sm shadow-sm placeholder-slate-400
      focus:outline-none focus:border-zinc-500 focus:ring-1 focus:ring-zinc-500
      invalid:border-pink-500 invalid:text-pink-600
      focus:invalid:border-pink-500 focus:invalid:ring-pink-500
  
  ${({ disabled }) =>
    disabled &&
    "disabled:bg-slate-50 disabled:text-slate-500 disabled:border-slate-200 disabled:shadow-none"}
`;

Input.tsx
This is a ref wrapper for Styled Input.

import { ComponentPropsWithRef, forwardRef, PropsWithChildren } from "react";
import { useFieldId } from "./FieldContext";
import { StyledInput } from "./StyledInput";

export interface IInputProps
  extends PropsWithChildren<ComponentPropsWithRef<"input">> {
  disabled?: boolean;
}

export const Input = forwardRef<HTMLLabelElement, IInputProps>(
  ({ children, disabled, ...rest }, ref) => {
    const id = useFieldId();
    return (
      <StyledInput
        $as="input"
        ref={ref}
        id={id}
        disabled={disabled}
        {...rest}
      />
    );
  }
);

Input.displayName = "Field.Input";

It was a composite component like that.

import { nanoid } from "nanoid";
import { FC, PropsWithChildren, ReactNode } from "react";
import { FieldContext } from "./FieldContext";
import { Input } from "./Input";
import { Label } from "./Label";
import { TextArea } from "./TextArea";

interface IFieldComposition {
  Label: typeof Label;
  Input: typeof Input;
  TextArea: typeof TextArea;
}

export const Field: FC<PropsWithChildren> & IFieldComposition = ({
  children,
}) => {
  const id = nanoid();
  return (
    <FieldContext.Provider value={{ id }}>{children}</FieldContext.Provider>
  );
};

Field.Label = Label;
Field.Input = Input;
Field.TextArea = TextArea;

It is used something like that.

  <Field>
          <Field.Label>Email</Field.Label>
          <Field.Input type="text" />
        </Field>