inputbox ref is now an internal widget (and works better!)

This commit is contained in:
Andrew Pareles 2024-12-04 23:49:45 -08:00
parent 86294c676a
commit 18e3f19512
2 changed files with 71 additions and 41 deletions

View file

@ -1,36 +1,59 @@
// import { useEffect, useRef } from 'react'
// import { HistoryInputBox } from '../../../../../../../base/browser/ui/inputbox/inputBox.js'
// import { useService } from '../util/services.js'
// import { defaultInputBoxStyles } from '../../../../../../../platform/theme/browser/defaultStyles.js'
import React, { useEffect, useRef } from 'react';
import { useService } from '../util/services.js';
import { HistoryInputBox } from '../../../../../../../base/browser/ui/inputbox/inputBox.js';
import { defaultInputBoxStyles } from '../../../../../../../platform/theme/browser/defaultStyles.js';
// export const InputBox = ({ onChangeText, placeholder, className }: { onChangeText: (value: string) => void, placeholder: string, className: string }) => {
export const InputBox = ({ onChangeText, placeholder, historyInputBoxRef, }: {
onChangeText: (value: string) => void;
placeholder: string;
historyInputBoxRef: React.MutableRefObject<HistoryInputBox | null>; // update this whenever historyInputBoxRef.current changes
}) => {
const contextViewProvider = useService('contextViewService');
// const domNodeRef = useRef<HTMLDivElement | null>(null)
const containerRef = useRef<HTMLDivElement>(null);
// const contextViewProvider = useService('contextViewService')
useEffect(() => {
if (!containerRef.current) return;
// create and mount the HistoryInputBox
historyInputBoxRef.current = new HistoryInputBox(
containerRef.current,
contextViewProvider,
{
inputBoxStyles: {
...defaultInputBoxStyles,
inputBackground: 'transparent',
},
placeholder,
history: [],
flexibleHeight: true,
flexibleMaxHeight: 500,
flexibleWidth: false,
}
);
// useEffect(() => {
historyInputBoxRef.current.onDidChange((newStr) => {
onChangeText(newStr)
})
// const htmlNode = domNodeRef.current
// if (!htmlNode) return
// historyInputBoxRef.current.onDidHeightChange((newHeight) => {
// console.log('CHANGE height', newHeight);
// })
// cleanup
return () => {
if (historyInputBoxRef.current) {
historyInputBoxRef.current.dispose();
if (containerRef.current) {
while (containerRef.current.firstChild) {
containerRef.current.removeChild(containerRef.current.firstChild);
}
}
historyInputBoxRef.current = null;
}
};
}, [onChangeText, placeholder, contextViewProvider]); // Empty dependency array since we only want to mount/unmount once
// console.log('creating inputbox')
// const widget = new HistoryInputBox(htmlNode, contextViewProvider, {
// inputBoxStyles: defaultInputBoxStyles,
// placeholder,
// history: [],
// })
// widget.onDidChange((newStr) => { onChangeText(newStr) })
// return () => {
// console.log('disposing inputbox')
// widget.dispose()
// }
// }, [onChangeText, contextViewProvider, placeholder])
// return <div ref={domNodeRef}className={className}/>
// }
return <div ref={containerRef} className="w-full" />;
};

View file

@ -19,6 +19,8 @@ import { IDisposable } from '../../../../../../../base/common/lifecycle.js';
import { ErrorDisplay } from './ErrorDisplay.js';
import { LLMMessageServiceParams } from '../../../../../../../platform/void/common/llmMessageTypes.js';
import { getCmdKey } from '../../../getCmdKey.js'
import { InputBox } from './InputBox.js';
import { HistoryInputBox } from '../../../../../../../base/browser/ui/inputbox/inputBox.js';
// read files from VSCode
const VSReadFile = async (modelService: IModelService, uri: URI): Promise<string | null> => {
@ -147,8 +149,6 @@ export const SidebarChat = () => {
const threadsStateService = useService('threadsStateService')
// ----- SIDEBAR CHAT state (local) -----
// state of current message
const [instructions, setInstructions] = useState('') // the user's instructions
// state of chat
const [messageStream, setMessageStream] = useState<string | null>(null)
@ -159,9 +159,14 @@ export const SidebarChat = () => {
const sendLLMMessageService = useService('sendLLMMessageService')
const isDisabled = !instructions
// state of current message
const [instructions, setInstructions] = useState('') // the user's instructions
const onChangeText = useCallback((newStr: string) => { setInstructions(newStr) }, [setInstructions])
const isDisabled = !instructions
const formRef = useRef<HTMLFormElement | null>(null)
const inputBoxRef: React.MutableRefObject<HistoryInputBox | null> = useRef(null);
const onSubmit = async (e: FormEvent<HTMLFormElement>) => {
e.preventDefault()
@ -223,8 +228,10 @@ export const SidebarChat = () => {
setIsLoading(true)
setInstructions('');
formRef.current?.reset(); // reset the form's text when clear instructions or unexpected behavior happens
if (inputBoxRef.current) {
inputBoxRef.current.value = ''; // this triggers onDidChangeText
inputBoxRef.current.blur();
}
threadsStateService.setStaging([]) // clear staging
setLatestError(null)
@ -257,7 +264,7 @@ export const SidebarChat = () => {
<ChatBubble key={i} chatMessage={message} />
)}
{/* message stream */}
<ChatBubble chatMessage={{ role: 'assistant', content: messageStream , displayContent: messageStream || null }} />
<ChatBubble chatMessage={{ role: 'assistant', content: messageStream, displayContent: messageStream || null }} />
</div>
{/* chatbar */}
<div className="shrink-0 py-4">
@ -288,20 +295,20 @@ export const SidebarChat = () => {
}}>
{/* input */}
{/* <InputBox
<InputBox
placeholder={`${getCmdKey()}+L to select`}
onChangeText={(newStr) => { setInstructions(newStr) }}
className='w-full p-2 leading-tight resize-none max-h-[50vh] overflow-auto bg-transparent border-none !outline-none'
/> */}
onChangeText={onChangeText}
historyInputBoxRef={inputBoxRef}
/>
<textarea
{/* <textarea
ref={chatInputRef}
placeholder={`Press ${getCmdKey()}+L to select.`}
onChange={(e) => { setInstructions(e.target.value) }}
className={`w-full p-2 leading-tight resize-none max-h-[50vh] overflow-auto bg-transparent border-none !outline-none`}
placeholder={`${getCmdKey()}+L to select`}
rows={1}
onInput={e => { e.currentTarget.style.height = 'auto'; e.currentTarget.style.height = e.currentTarget.scrollHeight + 'px' }} // Adjust height dynamically
/>
/> */}
{isLoading ?
// stop button