Spaces:
Running
Running
File size: 4,783 Bytes
d4017c8 c44fab6 0bb4dfa d4017c8 0bb4dfa d4017c8 0bb4dfa 4944128 a763505 d4017c8 4944128 d4017c8 4944128 d4017c8 c44fab6 a763505 c44fab6 4944128 0bb4dfa 4944128 c44fab6 d4017c8 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | import React, { useState, useRef, useCallback, forwardRef, useImperativeHandle } from 'react';
import { Play } from 'lucide-react';
const DEMO_SUFFIX = ' [Or type your own question]';
function formatDemoDisplay(question) {
if (!question) return '';
const label = (question.title || question.text || '').trim();
return `Demo Question: ${label}${DEMO_SUFFIX}`;
}
/**
* Question field pre-filled with a cycling demo prompt; "Start Chat"
* uses the demo question text or whatever the user typed.
*/
const ChatControls = forwardRef(function ChatControls({
demoQuestions = [],
onStart,
onStop,
disabled,
isRunning,
disabledReason,
disabledTooltip,
activeQuestion,
}, ref) {
const demoIndexRef = useRef(0);
const [demoIndex, setDemoIndex] = useState(0);
const [mode, setMode] = useState('demo');
const [userText, setUserText] = useState('');
const currentDemo = demoQuestions.length > 0
? demoQuestions[demoIndex % demoQuestions.length]
: null;
const demoDisplay = formatDemoDisplay(currentDemo);
const inputValue = mode === 'demo' ? demoDisplay : userText;
const resolveQuestion = useCallback(() => {
if (mode === 'custom') return userText.trim();
return (currentDemo?.text || '').trim();
}, [mode, userText, currentDemo]);
useImperativeHandle(ref, () => ({
getDraftQuestion: resolveQuestion,
}), [resolveQuestion]);
const advanceDemo = useCallback(() => {
if (demoQuestions.length === 0) return;
const next = (demoIndexRef.current + 1) % demoQuestions.length;
demoIndexRef.current = next;
setDemoIndex(next);
setMode('demo');
setUserText('');
}, [demoQuestions.length]);
const handleChange = (e) => {
const v = e.target.value;
if (mode === 'demo') {
if (v === '' || v === demoDisplay) return;
setMode('custom');
setUserText(v);
return;
}
if (v === '') {
setMode('demo');
setUserText('');
return;
}
setUserText(v);
};
const handleKeyDown = (e) => {
if (mode !== 'demo') return;
if (e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey) {
setMode('custom');
setUserText(e.key);
e.preventDefault();
return;
}
if (e.key === 'Backspace' || e.key === 'Delete') {
setMode('custom');
setUserText('');
e.preventDefault();
}
};
const handleStart = () => {
const question = resolveQuestion();
if (!question || disabled) return;
onStart(question);
advanceDemo();
};
const canStart = !disabled && !!resolveQuestion();
const startButtonTitle = !canStart && disabledTooltip ? disabledTooltip : undefined;
return (
<div className="chat-controls">
{isRunning ? (
<>
<button className="btn-stop" onClick={onStop}>
Stop Chat
</button>
{activeQuestion && (
<div
className="ccai-active-question"
title={activeQuestion}
>
<span className="ccai-active-question-label">Question:</span>
<span className="ccai-active-question-text">{activeQuestion}</span>
</div>
)}
</>
) : (
<>
<div className="chat-controls-row">
<input
type="text"
className="chat-controls-question"
value={inputValue}
placeholder={
disabled && disabledReason
? disabledReason
: demoQuestions.length === 0
? 'Loading demo questions…'
: ''
}
onChange={handleChange}
onKeyDown={(e) => {
handleKeyDown(e);
if (e.key === 'Enter' && canStart) {
e.preventDefault();
handleStart();
}
}}
/>
<span
className={
'chat-start-btn-wrap'
+ (startButtonTitle ? ' chat-start-btn-wrap-disabled' : '')
}
title={startButtonTitle}
>
<button
type="button"
className="btn-primary chat-controls-start"
disabled={!canStart}
onClick={handleStart}
aria-disabled={!canStart}
>
<Play size={14} style={{ marginRight: 4, verticalAlign: 'middle' }} />
Start Chat
</button>
</span>
</div>
{startButtonTitle && (
<span className="chat-start-hint" role="status">
{startButtonTitle}
</span>
)}
</>
)}
</div>
);
});
export default ChatControls;
|