first commit
This commit is contained in:
135
app/components/MessageInput.tsx
Normal file
135
app/components/MessageInput.tsx
Normal file
@ -0,0 +1,135 @@
|
||||
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>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user