fix input resize

This commit is contained in:
Mathew Pareles 2025-01-01 21:29:56 -05:00
parent dd4548466a
commit dcb708758d
5 changed files with 80 additions and 12 deletions

View file

@ -159,7 +159,7 @@ export class InputBox extends Widget {
this.scrollableElement = new ScrollableElement(this.element, { vertical: ScrollbarVisibility.Auto });
if (this.options.flexibleWidth) {
this.input.setAttribute('wrap', 'off');
this.input.setAttribute('wrap', 'on');
this.mirror.style.whiteSpace = 'pre';
this.mirror.style.wordWrap = 'initial';
}

View file

@ -83,7 +83,7 @@ export function getLanguageFromFileName(fileName: string): string {
export const BlockCode = ({ text, buttonsOnHover, language }: { text: string, buttonsOnHover?: ReactNode, language?: string }) => {
return (<>
<div className={`relative group w-full bg-vscode-sidebar-bg overflow-hidden isolate`}>
<div className={`relative group w-full bg-vscode-editor-bg overflow-hidden isolate`}>
{buttonsOnHover === null ? null : (
<div className="z-[1] absolute top-0 right-0 opacity-0 group-hover:opacity-100 duration-200">

View file

@ -22,7 +22,7 @@ export const Sidebar = ({ className }: { className: string }) => {
const { isHistoryOpen, currentTab: tab } = sidebarState
const isDark = useIsDark()
return <div className={`@@void-scope ${isDark ? 'dark' : ''}`} style={{ width: '100%', height: '100%' }}>
return <div className={`@@void-scope ${isDark ? 'dark' : ''}`} style={{ width: '100%', height: '100%' }}>
<div className={`flex flex-col px-2 py-2 w-full h-full bg-vscode-sidebar-bg`}>
{/* <span onClick={() => {

View file

@ -109,6 +109,65 @@ export const IconWarning = ({ size, className = '' }: { size: number, className?
);
};
export const IconLoading = ({ className = '' }: { className?: string }) => {
const [loadingText, setLoadingText] = useState('.');
useEffect(() => {
let intervalId;
// Function to handle the animation
const toggleLoadingText = () => {
if (loadingText === '...') {
setLoadingText('.');
} else {
setLoadingText(loadingText + '.');
}
};
// Start the animation loop
intervalId = setInterval(toggleLoadingText, 300);
// Cleanup function to clear the interval when component unmounts
return () => clearInterval(intervalId);
}, [loadingText, setLoadingText]);
return <div className={`${className}`}>{loadingText}</div>;
}
const useResizeObserver = () => {
const ref = useRef(null);
const [dimensions, setDimensions] = useState({ height: 0, width: 0 });
useEffect(() => {
if (ref.current) {
const resizeObserver = new ResizeObserver((entries) => {
if (entries.length > 0) {
const entry = entries[0];
setDimensions({
height: entry.contentRect.height,
width: entry.contentRect.width
});
}
});
resizeObserver.observe(ref.current);
return () => {
if (ref.current)
resizeObserver.unobserve(ref.current);
};
}
}, []);
return [ref, dimensions] as const;
};
type ButtonProps = ButtonHTMLAttributes<HTMLButtonElement>
const DEFAULT_BUTTON_SIZE = 20;
export const ButtonSubmit = ({ className, disabled, ...props }: ButtonProps & Required<Pick<ButtonProps, 'disabled'>>) => {
@ -301,8 +360,9 @@ export const SelectedFiles = (
}
const ChatBubble = ({ chatMessage }: {
chatMessage: ChatMessage
const ChatBubble = ({ chatMessage, isLoading }: {
chatMessage: ChatMessage,
isLoading?: boolean,
}) => {
const role = chatMessage.role
@ -325,6 +385,7 @@ const ChatBubble = ({ chatMessage }: {
return <div className={`${role === 'user' ? 'text-right' : 'text-left'}`}>
<div className={`text-left inline-block p-2 rounded-lg space-y-2 ${role === 'user' ? 'bg-vscode-input-bg text-vscode-input-fg' : ''} max-w-full overflow-auto`}>
{chatbubbleContents}
{isLoading && <IconLoading className='opacity-50 text-sm' />}
</div>
</div>
}
@ -369,8 +430,12 @@ export const SidebarChat = () => {
// state of current message
const [instructions, setInstructions] = useState('') // the user's instructions
const isDisabled = !instructions.trim()
const [formHeight, setFormHeight] = useState(0) // TODO should use resize observer instead
const [sidebarHeight, setSidebarHeight] = useState(0)
const [sidebarRef, sidebarDimensions] = useResizeObserver()
const [formRef, formDimensions] = useResizeObserver()
// const [formHeight, setFormHeight] = useState(0) // TODO should use resize observer instead
// const [sidebarHeight, setSidebarHeight] = useState(0)
const onChangeText = useCallback((newStr: string) => { setInstructions(newStr) }, [setInstructions])
@ -455,6 +520,8 @@ export const SidebarChat = () => {
threadsStateService.setStaging([]) // clear staging
inputBoxRef.current?.focus() // focus input after submit
}
const onAbort = () => {
@ -481,18 +548,18 @@ export const SidebarChat = () => {
// const [_test_messages, _set_test_messages] = useState<string[]>([])
return <div
ref={(ref) => { if (ref) { setSidebarHeight(ref.clientHeight); } }}
ref={sidebarRef}
className={`w-full h-full`}
>
<ScrollToBottomContainer
className={`overflow-x-hidden overflow-y-auto`}
style={{ maxHeight: sidebarHeight - formHeight - 30 }}
style={{ maxHeight: sidebarDimensions.height - formDimensions.height - 30 }}
>
{/* previous messages */}
{previousMessages.map((message, i) => <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 }} isLoading={isLoading} />
{/* {_test_messages.map((_, i) => <div key={i}>div {i}</div>)}
<div>{`totalHeight: ${sidebarHeight - formHeight - 30}`}</div>
@ -508,7 +575,7 @@ export const SidebarChat = () => {
className={`right-0 left-0 m-2 z-[999] overflow-hidden ${previousMessages.length > 0 ? 'absolute bottom-0' : ''}`}
>
<form
ref={(ref) => { if (ref) { setFormHeight(ref.clientHeight); } }}
ref={formRef}
className={`
flex flex-col gap-2 p-2 relative input text-left shrink-0
transition-all duration-200

View file

@ -66,6 +66,7 @@ export const VoidInputBox = ({ onChangeText, onCreateInstance, inputBoxRef, plac
{
inputBoxStyles: {
...defaultInputBoxStyles,
inputForeground: "var(--vscode-foreground)",
// inputBackground: 'transparent',
// inputBorder: 'none',
...styles,
@ -74,7 +75,7 @@ export const VoidInputBox = ({ onChangeText, onCreateInstance, inputBoxRef, plac
tooltip: '',
flexibleHeight: multiline,
flexibleMaxHeight: 500,
flexibleWidth: true,
flexibleWidth: false,
}
] as const, [contextViewProvider, placeholder, multiline])}
dispose={useCallback((instance: InputBox) => {