Hooks
useChatInput
Controlled composer text and submit state.
Installed to components/refined-ui/hooks/use-chat-input.ts with the ChatInput component. It is local UI behavior — yours to own and edit.
Source
Installed hook source
Behavior hook
src/registry/hooks/use-chat-input.ts
import type { FormEvent } from "react";import { useState } from "react";import type { ChatInputProps, ChatInputSubmitPayload } from "../contracts";function useControllableText({ value, defaultValue = "", onValueChange,}: Pick<ChatInputProps, "value" | "defaultValue" | "onValueChange">) { const [internalValue, setInternalValue] = useState(defaultValue); const isControlled = value !== undefined; const currentValue = isControlled ? value : internalValue; function setValue(nextValue: string) { if (!isControlled) setInternalValue(nextValue); onValueChange?.(nextValue); } return [currentValue, setValue] as const;}export function useChatInput({ value, defaultValue, onValueChange, onSubmit, state = "idle", density = "comfortable", disabled = false, trackSends = false,}: Pick<ChatInputProps, "value" | "defaultValue" | "onValueChange" | "onSubmit" | "state" | "density" | "disabled"> & { /** Count successful submits — only enabled when something reads the counter (the send-layer anchor), so idle apps pay no extra state update. */ trackSends?: boolean;}) { const [inputValue, setInputValue] = useControllableText({ value, defaultValue, onValueChange }); const [sendCount, setSendCount] = useState(0); const normalizedValue = inputValue.trim(); const isDisabled = disabled || state === "disabled" || state === "submitting"; const canSubmit = normalizedValue.length > 0 && !isDisabled; const isCompact = density === "compact"; function clear() { setInputValue(""); } // shared path: plain textarea via handleSubmit, rich editor calls submit() directly with extras (mentions) function submit(extra?: Partial<ChatInputSubmitPayload>) { if (!canSubmit) return; if (trackSends) setSendCount((count) => count + 1); void onSubmit?.({ value: normalizedValue, clear, ...extra }); } function handleSubmit(event: FormEvent<HTMLFormElement>) { event.preventDefault(); submit(); } return { value: inputValue, setValue: setInputValue, normalizedValue, state, density, isCompact, isDisabled, canSubmit, rows: isCompact ? 2 : 4, sendCount, clear, submit, handleSubmit, };}