#4. [shadcn-chat] 올바른 interface 상속을 통한 textArea 컴포넌트 조합문자 처리 개선

pengooseDev·2024년 9월 29일
0
post-thumbnail

1. Issue

shadcn-chat에서 제공하는 ChatInput 컴포넌트는 TextArea를 한 단계 더 추상화한 고차 컴포넌트이다.
textArea에서 composition-based language를 submit할 경우, 마지막 단어가 중복되어 전달되는 이슈가 존재한다.
onComposition (**react) 메서드로 제어하고자 하였으나 interface에서 이를 제공하지 않아 에러가 발생하였다. (기능적으로는 동작. 따라서 type선언 문제)


2. 원인 파악

원인은 interface 상속에 있었다.
하나의 컴포넌트를 다시 추상화하는 과정에서, 의도적으로 기능을 제한하는 경우가 아니라면 기존에 사용하던 interface를 적절히 잘 상속해주는 것이 중요하다.

Prev

import { Textarea } from "@/components/ui/textarea";
import { cn } from "@/lib/utils";

// ⛳️ TextArea를 상속하여 그대로 spread하는 것이 아닌 직접 추상화하여 상속
interface ChatInputProps {
  className?: string;
  value?: string;
  onKeyDown?: (event: React.KeyboardEvent<HTMLTextAreaElement>) => void;
  onChange?: (event: React.ChangeEvent<HTMLTextAreaElement>) => void;
  placeholder?: string;
}

const ChatInput = React.forwardRef<HTMLTextAreaElement, ChatInputProps>(
  ({ className, value, onKeyDown, onChange, placeholder, ...props }, ref) => (
    <Textarea
      autoComplete="off"
      value={value}
      ref={ref}
      onKeyDown={onKeyDown}
      onChange={onChange}
      name="message"
      placeholder={placeholder}
      className={cn(
        "max-h-12 px-4 py-3 bg-background text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 w-full rounded-md flex items-center h-16 resize-none",
        className,
      )}
      {...props}
    />
  ),
);
ChatInput.displayName = "ChatInput";
export { ChatInput };

물론, 해당 모듈은 기존의 모듈을 다시 추상화한 컴포넌트이기 때문에, 기존 shadcn의 Textarea 컴포넌트 의존성으로 이런 추상화가 발생한 것이 아닌지 히스토리를 체크해야한다.

Textarea(shadcn)

import * as React from "react"

import { cn } from "@/lib/utils"

export interface TextareaProps
  extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}

const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
  ({ className, ...props }, ref) => {
    return (
      <textarea
        className={cn(
          "flex min-h-[60px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
          className
        )}
        ref={ref}
        {...props}
      />
    )
  }
)
Textarea.displayName = "Textarea"

export { Textarea }

그런거 없었다. 그저 실수였다는 것을 확인하였으니 상속되는 interface를 정정해주자.
두 가지 선택지가 있다.
1. HTMLTextAreaElement 상속하기
2. 의존성 모듈을 사용하니 shadcn에서 사용한 Textarea 그대로 상속하기.

물론, 2가 더 바람직하겠지만, 기존 모듈에서 추상화 해둔 방식을 살펴보니, shadcn에서 추상화 해둔 interface가 아닌 전부 직접 추상화 하여 상속하는 방식을 채택했다.
이럴 경우, shadcn에서 제공하는 interface가 HTML API가 아닌 자체 선언방식으로 변경되면 해당 모듈 또한 재작업을 진행해야 한다는 문제점이 발생하지만, HeadlessUI(shadcn) 특성상 HTML API를 벗어날 가능성이 낮다고 판단하여 기존 컨벤션(HTMLTextAreaElement 상속하기)을 따르기로 하였다.


3. 해결

interface를 올바르게 상속하고, 불필요한 매개변수를 제거하는 간단한 작업 후, PR하였다.


4. PR 및 merged

> PR #1410

maintainer가 한 분이시고, contribution에 대한 문서 작성이 TODO에 담겨있던 초기 프로젝트라 LinkedIn 프로필로 gentle ping을 PR 컨텍스트를 한 번 날리게 되었다.

Merge 후 서윗하게 DM까지 보내주셨다.
Maintainer의 gentle함이 오픈소스에 주는 영향을 크게 느끼게 되었다.
한동안 멈췄던 오픈소스를 다시 잡아볼까 한다.

0개의 댓글