105 lines
2.8 KiB
TypeScript
105 lines
2.8 KiB
TypeScript
/**
|
|
* ChatInput -- Shared chat input component.
|
|
*
|
|
* Simple text input with send button, usable by both Workspace and Editor.
|
|
*/
|
|
import React, { useState, useCallback, useRef, useEffect } from 'react';
|
|
import { useLanguage } from '../../providers/language/LanguageContext';
|
|
|
|
interface ChatInputProps {
|
|
onSend: (message: string) => void;
|
|
isProcessing?: boolean;
|
|
placeholder?: string;
|
|
disabled?: boolean;
|
|
autoFocus?: boolean;
|
|
style?: React.CSSProperties;
|
|
}
|
|
|
|
export const ChatInput: React.FC<ChatInputProps> = ({
|
|
onSend,
|
|
isProcessing,
|
|
placeholder,
|
|
disabled,
|
|
autoFocus = true,
|
|
style,
|
|
}) => {
|
|
const { t } = useLanguage();
|
|
const resolvedPlaceholder = placeholder ?? t('Nachricht eingeben…');
|
|
const [value, setValue] = useState('');
|
|
const inputRef = useRef<HTMLTextAreaElement>(null);
|
|
|
|
useEffect(() => {
|
|
if (autoFocus) inputRef.current?.focus();
|
|
}, [autoFocus]);
|
|
|
|
const _handleSend = useCallback(() => {
|
|
const trimmed = value.trim();
|
|
if (!trimmed || isProcessing || disabled) return;
|
|
onSend(trimmed);
|
|
setValue('');
|
|
}, [value, isProcessing, disabled, onSend]);
|
|
|
|
const _handleKeyDown = useCallback(
|
|
(e: React.KeyboardEvent) => {
|
|
if (e.key === 'Enter' && !e.shiftKey) {
|
|
e.preventDefault();
|
|
_handleSend();
|
|
}
|
|
},
|
|
[_handleSend]
|
|
);
|
|
|
|
return (
|
|
<div
|
|
style={{
|
|
display: 'flex',
|
|
gap: '8px',
|
|
padding: '8px 12px',
|
|
borderTop: '1px solid var(--border-color, #e0e0e0)',
|
|
alignItems: 'flex-end',
|
|
...style,
|
|
}}
|
|
>
|
|
<textarea
|
|
ref={inputRef}
|
|
value={value}
|
|
onChange={(e) => setValue(e.target.value)}
|
|
onKeyDown={_handleKeyDown}
|
|
placeholder={resolvedPlaceholder}
|
|
disabled={isProcessing || disabled}
|
|
rows={1}
|
|
style={{
|
|
flex: 1,
|
|
resize: 'none',
|
|
border: '1px solid var(--border-color, #ddd)',
|
|
borderRadius: '8px',
|
|
padding: '8px 12px',
|
|
fontSize: '13px',
|
|
fontFamily: 'inherit',
|
|
outline: 'none',
|
|
minHeight: '36px',
|
|
maxHeight: '120px',
|
|
background: 'var(--bg-primary, #fff)',
|
|
color: 'var(--text-primary, #333)',
|
|
}}
|
|
/>
|
|
<button
|
|
onClick={_handleSend}
|
|
disabled={!value.trim() || isProcessing || disabled}
|
|
style={{
|
|
padding: '8px 16px',
|
|
borderRadius: '8px',
|
|
border: 'none',
|
|
background: !value.trim() || isProcessing || disabled ? '#ccc' : 'var(--color-primary, #2563eb)',
|
|
color: '#fff',
|
|
fontSize: '13px',
|
|
fontWeight: 600,
|
|
cursor: !value.trim() || isProcessing || disabled ? 'not-allowed' : 'pointer',
|
|
whiteSpace: 'nowrap',
|
|
}}
|
|
>
|
|
{isProcessing ? '…' : t('Senden')}
|
|
</button>
|
|
</div>
|
|
);
|
|
};
|