135 lines
3.9 KiB
TypeScript
135 lines
3.9 KiB
TypeScript
import React, { useState, useRef } from 'react';
|
|
import { TextField, IconButton, Box, Tooltip, CircularProgress, useTheme } from '@mui/material';
|
|
import { SendRounded } from '@mui/icons-material';
|
|
|
|
interface MessageInputProps {
|
|
value: string;
|
|
onChange: (value: string) => void;
|
|
onSend: () => void;
|
|
onKeyDown: (e: React.KeyboardEvent) => void;
|
|
disabled: boolean;
|
|
}
|
|
|
|
export const MessageInput: React.FC<MessageInputProps> = ({
|
|
value,
|
|
onChange,
|
|
onSend,
|
|
onKeyDown,
|
|
disabled
|
|
}) => {
|
|
const theme = useTheme();
|
|
const textareaRef = useRef<HTMLDivElement>(null);
|
|
const [isFocused, setIsFocused] = useState(false);
|
|
|
|
const handleFocus = () => setIsFocused(true);
|
|
const handleBlur = () => setIsFocused(false);
|
|
|
|
// 自动调整文本框高度
|
|
const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
|
|
onChange(e.target.value);
|
|
// 找到实际的textarea元素
|
|
const textarea = e.target as HTMLTextAreaElement;
|
|
textarea.style.height = 'auto';
|
|
textarea.style.height = Math.min(textarea.scrollHeight, 120) + 'px';
|
|
};
|
|
|
|
return (
|
|
<Box
|
|
sx={{
|
|
p: 2,
|
|
backgroundColor: theme.palette.background.paper,
|
|
borderTop: `1px solid ${theme.palette.divider}`,
|
|
boxShadow: '0 -2px 10px rgba(0, 0, 0, 0.05)',
|
|
}}
|
|
>
|
|
<Box
|
|
display="flex"
|
|
alignItems="flex-end"
|
|
gap={1.5}
|
|
sx={{
|
|
maxWidth: '100%',
|
|
mx: 'auto',
|
|
}}
|
|
>
|
|
<TextField
|
|
ref={textareaRef}
|
|
fullWidth
|
|
variant="outlined"
|
|
placeholder="输入您的问题..."
|
|
value={value}
|
|
onChange={handleChange}
|
|
onKeyDown={onKeyDown}
|
|
onFocus={handleFocus}
|
|
onBlur={handleBlur}
|
|
disabled={disabled}
|
|
multiline
|
|
rows={1}
|
|
inputProps={{
|
|
style: {
|
|
maxHeight: '120px',
|
|
overflowY: 'auto',
|
|
padding: '10px 14px',
|
|
borderRadius: '24px',
|
|
lineHeight: 1.5,
|
|
}
|
|
}}
|
|
sx={{
|
|
'& .MuiOutlinedInput-root': {
|
|
borderRadius: 4,
|
|
'& fieldset': {
|
|
borderColor: theme.palette.divider,
|
|
borderWidth: '2px',
|
|
},
|
|
'&:hover fieldset': {
|
|
borderColor: theme.palette.primary.light,
|
|
},
|
|
'&.Mui-focused fieldset': {
|
|
borderColor: theme.palette.primary.main,
|
|
borderWidth: '2px',
|
|
},
|
|
'&.Mui-disabled fieldset': {
|
|
borderColor: theme.palette.divider,
|
|
opacity: 0.6,
|
|
}
|
|
},
|
|
transition: 'all 0.3s ease',
|
|
transform: isFocused ? 'translateY(-1px)' : 'translateY(0)',
|
|
}}
|
|
/>
|
|
|
|
<Tooltip title="发送消息" placement="top">
|
|
<IconButton
|
|
onClick={onSend}
|
|
disabled={disabled || !value.trim()}
|
|
sx={{
|
|
backgroundColor: (disabled || !value.trim())
|
|
? theme.palette.action.disabledBackground
|
|
: theme.palette.primary.main,
|
|
color: 'white',
|
|
width: 48,
|
|
height: 48,
|
|
'&:hover': {
|
|
backgroundColor: (disabled || !value.trim())
|
|
? theme.palette.action.disabledBackground
|
|
: theme.palette.primary.dark,
|
|
transform: 'scale(1.05)',
|
|
},
|
|
'&:active': {
|
|
transform: 'scale(0.95)',
|
|
},
|
|
transition: 'all 0.2s ease',
|
|
boxShadow: theme.shadows[2],
|
|
}}
|
|
aria-label="发送消息"
|
|
>
|
|
{disabled ? (
|
|
<CircularProgress size={20} color="inherit" />
|
|
) : (
|
|
<SendRounded fontSize="small" />
|
|
)}
|
|
</IconButton>
|
|
</Tooltip>
|
|
</Box>
|
|
</Box>
|
|
);
|
|
}; |