Files
cozsweet-frontend-nextjs/src/app/chat/components/chat-input-text-field.tsx
T
Codex abb6e4235f
Docker Image / Quality and Bundle Budgets (push) Successful in 3s
Docker Image / Build and Push Docker Image (push) Successful in 1m52s
Add chat gifts and relationship diary UI
2026-07-21 18:35:01 +08:00

83 lines
2.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
/**
* ChatInputTextField 输入框
*
*
*
* 行为:
* - 多行输入(min 1 行 / max 5 行 ≈ max-height 120px
* - Enter 直接发送(无 Shift/Ctrl/Meta
* - Shift+Enter / Ctrl+Enter / Meta+Enter 换行
* - 外层白底圆角容器
*
* 通过 `forwardRef` 暴露 textarea 节点,父组件可在 send 后调用 `.focus()`
* 通过 `onFocusChange` 回调通知父组件焦点状态,用于外层容器的聚焦样式切换。
*/
import {
forwardRef,
type FormEvent,
type KeyboardEvent,
useImperativeHandle,
useRef,
} from "react";
export interface ChatInputTextFieldProps {
value: string;
onChange: (value: string) => void;
onSubmit: () => void;
/** 焦点变化回调(用于父组件 ChatInputBar 切换聚焦态视觉) */
onFocusChange?: (focused: boolean) => void;
placeholder?: string;
disabled?: boolean;
autoFocus?: boolean;
}
export const ChatInputTextField = forwardRef<
HTMLTextAreaElement,
ChatInputTextFieldProps
>(function ChatInputTextField(
{
value,
onChange,
onSubmit,
onFocusChange,
placeholder = "Say anything thats on your mind ^U^…",
disabled = false,
autoFocus = false,
},
ref,
) {
const innerRef = useRef<HTMLTextAreaElement>(null);
// 对外暴露与 forwardRef 同名的 ref(指向内部 textarea 节点)
useImperativeHandle(ref, () => innerRef.current as HTMLTextAreaElement, []);
const handleKeyDown = (e: KeyboardEvent<HTMLTextAreaElement>) => {
if (e.key !== "Enter") return;
if (e.shiftKey || e.ctrlKey || e.metaKey) return; // 修饰键 → 换行
e.preventDefault();
onSubmit();
};
return (
<div className="flex min-w-0 flex-auto items-center rounded-full bg-transparent px-[clamp(10px,3vw,14px)]">
<textarea
ref={innerRef}
className="min-h-(--chat-send-button-size,40px) max-h-[min(30vh,120px)] w-full min-w-0 flex-auto resize-none border-0 bg-transparent pb-0 pl-0 pr-0 pt-[clamp(5px,1.111vw,6px)] font-[inherit] text-[16px] leading-[clamp(22px,4.444vw,24px)] text-(--color-text-foreground,#000) caret-accent outline-none placeholder:text-(--color-text-hint,#757575)"
value={value}
onChange={(e: FormEvent<HTMLTextAreaElement>) =>
onChange(e.currentTarget.value)
}
onKeyDown={handleKeyDown}
onFocus={() => onFocusChange?.(true)}
onBlur={() => onFocusChange?.(false)}
placeholder={placeholder}
disabled={disabled}
maxLength={4000}
autoFocus={autoFocus}
rows={1}
aria-label="Message"
/>
</div>
);
});