feat(FN-4514): complete Step 2 — swap quick chat composer to autosizing textarea

Fusion-Task-Id: FN-4514
Fusion-Task-Lineage: 5910815a-9d67-4312-97d4-44d65d01dbc7
This commit is contained in:
Fusion
2026-05-14 12:42:48 -07:00
committed by gsxdsm
parent ec2f5418c9
commit afdebd1530

View File

@@ -1888,6 +1888,15 @@ export function QuickChatFAB({
setMentionStartPos(-1); setMentionStartPos(-1);
}, []); }, []);
const resizeQuickChatComposer = useCallback((composer: HTMLTextAreaElement | null = inputRef.current) => {
if (!composer) {
return;
}
composer.style.height = "auto";
composer.style.height = `${clampQuickChatInputHeight(composer.scrollHeight)}px`;
}, []);
const handleSkillSelect = useCallback((skill: DiscoveredSkill) => { const handleSkillSelect = useCallback((skill: DiscoveredSkill) => {
setMessageInput((currentInput) => { setMessageInput((currentInput) => {
const triggerMatch = getSkillTriggerMatch(currentInput); const triggerMatch = getSkillTriggerMatch(currentInput);
@@ -1900,6 +1909,7 @@ export function QuickChatFAB({
window.requestAnimationFrame(() => { window.requestAnimationFrame(() => {
if (!inputRef.current) return; if (!inputRef.current) return;
resizeQuickChatComposer(inputRef.current);
inputRef.current.focus(); inputRef.current.focus();
}); });
@@ -1909,7 +1919,7 @@ export function QuickChatFAB({
setShowSkillMenu(false); setShowSkillMenu(false);
setSkillFilter(""); setSkillFilter("");
setHighlightedSkillIndex(0); setHighlightedSkillIndex(0);
}, []); }, [resizeQuickChatComposer]);
const handleMentionSelect = useCallback( const handleMentionSelect = useCallback(
(agent: Agent) => { (agent: Agent) => {
@@ -1935,17 +1945,19 @@ export function QuickChatFAB({
window.requestAnimationFrame(() => { window.requestAnimationFrame(() => {
if (!inputRef.current) return; if (!inputRef.current) return;
resizeQuickChatComposer(inputRef.current);
inputRef.current.focus(); inputRef.current.focus();
inputRef.current.setSelectionRange(nextCursorPos, nextCursorPos); inputRef.current.setSelectionRange(nextCursorPos, nextCursorPos);
}); });
}, },
[mentionStartPos, messageInput], [mentionStartPos, messageInput, resizeQuickChatComposer],
); );
const handleInputChange = useCallback( const handleInputChange = useCallback(
(event: React.ChangeEvent<HTMLTextAreaElement>) => { (event: React.ChangeEvent<HTMLTextAreaElement>) => {
const nextValue = event.target.value; const nextValue = event.target.value;
const cursorPos = event.target.selectionStart ?? nextValue.length; const cursorPos = event.target.selectionStart ?? nextValue.length;
resizeQuickChatComposer(event.target);
mentionCursorPosRef.current = cursorPos; mentionCursorPosRef.current = cursorPos;
setMessageInput(nextValue); setMessageInput(nextValue);
if (helpMessageVisible && nextValue.trim().length > 0) { if (helpMessageVisible && nextValue.trim().length > 0) {
@@ -1969,9 +1981,13 @@ export function QuickChatFAB({
updateFileMentionPosition(event.target); updateFileMentionPosition(event.target);
} }
}, },
[helpMessageVisible, updateMentionState, fileMention, updateFileMentionPosition], [fileMention, helpMessageVisible, resizeQuickChatComposer, updateFileMentionPosition, updateMentionState],
); );
useLayoutEffect(() => {
resizeQuickChatComposer();
}, [messageInput, resizeQuickChatComposer]);
const handleInputBlur = useCallback(() => { const handleInputBlur = useCallback(() => {
if (preserveComposerFocusRef.current) { if (preserveComposerFocusRef.current) {
window.requestAnimationFrame(() => { window.requestAnimationFrame(() => {
@@ -2627,9 +2643,10 @@ export function QuickChatFAB({
> >
<Paperclip size={16} /> <Paperclip size={16} />
</button> </button>
<input <textarea
ref={inputRef} ref={inputRef}
type="text" rows={1}
className="quick-chat-textarea"
value={messageInput} value={messageInput}
onChange={handleInputChange} onChange={handleInputChange}
onKeyDown={handleInputKeyDown} onKeyDown={handleInputKeyDown}