見出し画像

#1. [shadcn-chat] 正しいインターフェース継承を通じた textArea コンポーネントの合成文字処理の改善

1. 課題

interface Err on ChatInput

shadcn-chatが提供するChatInputコンポーネントは、`TextAreaをさらに抽象化した高次コンポーネント`です。 textAreaでcomposition-based languageを送信する場合、最後の単語が重複して送信される問題が存在します。


composition event error with TextArea(React)

2. 原因の特定

原因は`interfaceの継承`にありました。 コンポーネントを再び抽象化する過程では、意図的に機能を制限しない限り、既存のinterfaceを適切に継承することが重要です。

以前のコード

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を修正しましょう。 選択肢は2つあります。

  1. HTMLTextAreaElementを継承する

  2. 依存モジュールを使うので、shadcnが使用しているTextareaをそのまま継承する。

もちろん、2つ目のほうが望ましいですが、既存のモジュールで抽象化された方法を確認したところ、shadcnが提供しているinterfaceではなく、すべて直接抽象化して継承する方法を採用していました。 この場合、shadcnが提供するinterfaceがHTML APIではなく独自の宣言方式に変更された場合、このモジュールも再作業が必要になるという問題がありますが、HeadlessUI(shadcn)の性質上、HTML APIを超える可能性は低いと判断し、従来のコンベンションに従い(HTMLTextAreaElementを継承)作業することにしました。


3. 解決

interfaceを正しく継承し、不要なパラメーターを削除する簡単な作業後、PRを提出しました。

Code Diff

4. PRおよびマージ

> PR #1410

メンテナーは1人で、contributionに関するドキュメントがTODOに含まれていた初期プロジェクトだったため、LinkedInプロフィールを通じてgentle pingを送りました。


マージ後、丁寧なDMまでいただきました。 メンテナーのgentleさがオープンソースに与える影響の大きさを感じました。 しばらく停滞していたオープンソース活動を再び始めてみようと思います。


この記事が気に入ったらサポートをしてみませんか?