{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "sender",
  "title": "Sender",
  "description": "MateChat Sender",
  "files": [
    {
      "path": "src/sender.tsx",
      "content": "import clsx from \"clsx\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport interface InputCountProps extends React.ComponentProps<\"span\"> {\n  count: number;\n  limit: number;\n}\n\nexport function InputCount({\n  count,\n  limit,\n  className,\n  ...props\n}: InputCountProps) {\n  return (\n    <span className={clsx(\"text-gray-400\", className)} {...props}>\n      {count} / {limit}\n    </span>\n  );\n}\n\nexport interface SenderButtonProps extends React.ComponentProps<\"button\"> {\n  icon?: React.ReactNode;\n  isSending?: boolean;\n}\nexport function SenderButton({\n  className,\n  icon,\n  isSending = false,\n  ...props\n}: SenderButtonProps) {\n  return (\n    <button\n      type=\"button\"\n      data-slot=\"sender-button\"\n      className={twMerge(\n        clsx(\n          \"flex h-8 w-8 items-center justify-center rounded-full bg-blue-500 hover:bg-blue-500/90 text-white cursor-pointer\",\n          className,\n        ),\n      )}\n      {...props}\n    >\n      {icon ?? (\n        <span className={clsx(\"text-white\")}>{isSending ? \"■\" : \"→\"}</span>\n      )}\n    </button>\n  );\n}\n\nexport interface SenderProps extends React.ComponentProps<\"div\"> {\n  initialMessage?: string;\n  placeholder?: string;\n  sendMessage: (message: { text: string }) => void;\n  onMessageChange?: (message: string) => void;\n  onSend?: () => void;\n  toolbar?: React.ReactNode;\n  suggestion?: (context: {\n    message: string;\n    textareaRef: React.RefObject<HTMLTextAreaElement | null>;\n    onInject: (text: string, position: number) => void;\n  }) => React.ReactNode;\n}\n\nexport function Sender({\n  className,\n  initialMessage = \"\",\n  placeholder = \"Type your message here...\",\n  onMessageChange,\n  sendMessage,\n  onSend,\n  toolbar,\n  suggestion,\n  ...props\n}: SenderProps) {\n  const textareaRef = useRef<HTMLTextAreaElement>(null);\n  const [message, setMessage] = useState(initialMessage);\n  const [caretPosition, setCaretPosition] = useState<number | null>(null);\n\n  useEffect(() => {\n    if (textareaRef.current) {\n      textareaRef.current.style.height = \"auto\";\n      textareaRef.current.style.height = `${textareaRef.current.scrollHeight}px`;\n    }\n    onMessageChange?.(message);\n  }, [message, onMessageChange]);\n\n  useEffect(() => {\n    if (textareaRef.current && caretPosition !== null) {\n      textareaRef.current.focus();\n      textareaRef.current.selectionStart = caretPosition;\n      textareaRef.current.selectionEnd = caretPosition;\n      setCaretPosition(null);\n    }\n  }, [caretPosition]);\n\n  const handleSend = useCallback(() => {\n    if (message.trim() === \"\") return;\n    const trimmedMessage = message.trim();\n    setMessage(\"\");\n    sendMessage({ text: trimmedMessage });\n    onSend?.();\n  }, [message, sendMessage, onSend]);\n\n  const handleKeyDown = useCallback(\n    (event: React.KeyboardEvent<HTMLTextAreaElement>) => {\n      if (\n        event.key === \"Enter\" &&\n        !event.shiftKey &&\n        !event.nativeEvent.isComposing\n      ) {\n        event.preventDefault();\n        handleSend();\n      }\n    },\n    [handleSend],\n  );\n\n  const handleChange = useCallback(\n    (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n      setMessage(e.target.value);\n    },\n    [],\n  );\n\n  const handleTextInject: (newText: string, newCursorPosition: number) => void =\n    useCallback((newText, suggestionStartPosition) => {\n      setMessage((prevMessage) => {\n        const currentCaretPosition =\n          textareaRef.current?.selectionStart ?? prevMessage.length;\n        const textBefore = prevMessage.slice(0, suggestionStartPosition);\n        const textAfter = prevMessage.slice(currentCaretPosition);\n        const newMessage = textBefore + newText + textAfter;\n        return newMessage;\n      });\n      setCaretPosition(suggestionStartPosition + newText.length);\n    }, []);\n\n  return (\n    <div\n      data-slot=\"sender\"\n      className={twMerge(\n        clsx(\n          \"relative px-1 flex flex-col items-center border rounded-2xl\",\n          \"border-gray-200 dark:border-gray-700 shadow-sm transition-all duration-300 hover:shadow-md\",\n          \"focus-within:ring-2 focus-within:ring-blue-500 focus-within:border-blue-500\",\n          className,\n        ),\n      )}\n      {...props}\n    >\n      {suggestion?.({\n        message,\n        textareaRef,\n        onInject: handleTextInject,\n      })}\n      <textarea\n        ref={textareaRef}\n        value={message}\n        onChange={handleChange}\n        onKeyDown={handleKeyDown}\n        placeholder={placeholder}\n        className={clsx(\n          \"w-full pt-4 px-4 border-0 rounded-2xl resize-none! bg-transparent\",\n          \"focus:ring-0 focus:outline-none text-gray-700 placeholder-gray-400\",\n          \"overflow-y-auto max-h-32\",\n          \"scrollbar-gutter-stable [&::-webkit-scrollbar]:w-1.5 [&::-webkit-scrollbar-thumb]:rounded-full\",\n          \"[&::-webkit-scrollbar-thumb]:cursor-auto\",\n          \"[&::-webkit-scrollbar-thumb]:bg-gray-300 dark:[&::-webkit-scrollbar-thumb]:bg-gray-600\",\n          \"[&::-webkit-scrollbar-thumb:hover]:bg-gray-400 dark:[&::-webkit-scrollbar-thumb:hover]:bg-gray-500\",\n          \"[&::-webkit-scrollbar-track]:mt-3\",\n        )}\n        rows={2}\n      />\n      <div className=\"flex items-center w-full px-4 py-2 gap-4\">\n        {toolbar}\n        <SenderButton onClick={handleSend} className=\"ml-auto\" />\n      </div>\n    </div>\n  );\n}\n",
      "type": "registry:component"
    }
  ],
  "type": "registry:component"
}