71 lines
2.2 KiB
TypeScript
71 lines
2.2 KiB
TypeScript
import { useEffect, useRef, useState } from "react";
|
|
import { Button } from "./primitives";
|
|
|
|
export interface ChatInputProps {
|
|
onSend: (text: string) => void;
|
|
sending: boolean;
|
|
onVoice: () => void;
|
|
placeholder?: string;
|
|
}
|
|
|
|
export function ChatInput({
|
|
onSend,
|
|
sending,
|
|
onVoice,
|
|
placeholder = "给昔涟发消息…",
|
|
}: ChatInputProps): React.ReactNode {
|
|
const [value, setValue] = useState("");
|
|
const taRef = useRef<HTMLTextAreaElement>(null);
|
|
|
|
// auto-grow the textarea up to a max height
|
|
useEffect(() => {
|
|
const el = taRef.current;
|
|
if (!el) return;
|
|
el.style.height = "auto";
|
|
el.style.height = Math.min(el.scrollHeight, 140) + "px";
|
|
}, [value]);
|
|
|
|
const submit = () => {
|
|
const t = value.trim();
|
|
if (!t || sending) return;
|
|
onSend(t);
|
|
setValue("");
|
|
};
|
|
|
|
return (
|
|
<div className="glass sticky bottom-0 border-t border-[var(--mu-glass-border)] p-3 md:p-4">
|
|
<div className="mx-auto flex max-w-2xl items-end gap-2 rounded-[var(--mu-radius-lg)] bg-[var(--mu-surface-2)] p-2 shadow-[var(--mu-shadow-1)]">
|
|
<textarea
|
|
ref={taRef}
|
|
value={value}
|
|
onChange={(e) => setValue(e.target.value)}
|
|
onKeyDown={(e) => {
|
|
if (e.key === "Enter" && !e.shiftKey) {
|
|
e.preventDefault();
|
|
submit();
|
|
}
|
|
}}
|
|
rows={1}
|
|
placeholder={placeholder}
|
|
className="max-h-[140px] flex-1 resize-none bg-transparent px-2 py-2 text-sm text-[var(--mu-text-hi)] outline-none placeholder:text-[var(--mu-text-lo)]"
|
|
/>
|
|
<button
|
|
onClick={onVoice}
|
|
aria-label="语音"
|
|
className="inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-[var(--mu-radius)] bg-[var(--mu-surface-4)] text-base transition-all duration-200 ease-[var(--mu-spring)] hover:bg-[var(--mu-surface-5)] active:scale-95"
|
|
>
|
|
🎙
|
|
</button>
|
|
<Button
|
|
variant="primary"
|
|
onClick={submit}
|
|
disabled={sending || value.trim().length === 0}
|
|
className="shrink-0"
|
|
>
|
|
{sending ? "发送中…" : "发送"}
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|