mirror of
https://github.com/voideditor/void
synced 2026-05-23 17:38:23 +00:00
add native input selection in settings
This commit is contained in:
parent
18e3f19512
commit
a647530d77
5 changed files with 167 additions and 82 deletions
|
|
@ -1,59 +0,0 @@
|
|||
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, historyInputBoxRef, }: {
|
||||
onChangeText: (value: string) => void;
|
||||
placeholder: string;
|
||||
historyInputBoxRef: React.MutableRefObject<HistoryInputBox | null>; // update this whenever historyInputBoxRef.current changes
|
||||
}) => {
|
||||
const contextViewProvider = useService('contextViewService');
|
||||
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
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,
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
historyInputBoxRef.current.onDidChange((newStr) => {
|
||||
onChangeText(newStr)
|
||||
})
|
||||
|
||||
// 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
|
||||
|
||||
return <div ref={containerRef} className="w-full" />;
|
||||
};
|
||||
|
|
@ -19,7 +19,7 @@ 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 { InputBox } from './inputs.js';
|
||||
import { HistoryInputBox } from '../../../../../../../base/browser/ui/inputbox/inputBox.js';
|
||||
|
||||
// read files from VSCode
|
||||
|
|
@ -298,7 +298,9 @@ export const SidebarChat = () => {
|
|||
<InputBox
|
||||
placeholder={`${getCmdKey()}+L to select`}
|
||||
onChangeText={onChangeText}
|
||||
historyInputBoxRef={inputBoxRef}
|
||||
inputBoxRef={inputBoxRef}
|
||||
multiline={true}
|
||||
initVal=''
|
||||
/>
|
||||
|
||||
{/* <textarea
|
||||
|
|
|
|||
|
|
@ -2,9 +2,12 @@
|
|||
* Copyright (c) Glass Devtools, Inc. All rights reserved.
|
||||
* Void Editor additions licensed under the AGPLv3 License.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { useConfigState, useService } from '../util/services.js';
|
||||
import { IVoidConfigStateService, nonDefaultConfigFields, PartialVoidConfig, VoidConfig, VoidConfigField, VoidConfigInfo, SetFieldFnType, ConfigState } from '../../../registerConfig.js';
|
||||
import { EnumInputBox, InputBox } from './inputs.js';
|
||||
import { HistoryInputBox } from '../../../../../../../base/browser/ui/inputbox/inputBox.js';
|
||||
import { SelectBox } from '../../../../../../../base/browser/ui/selectBox/selectBox.js';
|
||||
|
||||
|
||||
const SettingOfFieldAndParam = ({ field, param, configState, configStateService }:
|
||||
|
|
@ -16,13 +19,30 @@ const SettingOfFieldAndParam = ({ field, param, configState, configStateService
|
|||
const { enumArr, defaultVal, description } = configStateService.voidConfigInfo[field][param]
|
||||
const val = partialVoidConfig[field]?.[param] ?? defaultVal // current value of this item
|
||||
|
||||
const updateState = (newValue: string) => { configStateService.setField(field, param, newValue) }
|
||||
const updateState = useCallback((newValue: string) => {
|
||||
configStateService.setField(field, param, newValue)
|
||||
}, [configStateService, field, param])
|
||||
|
||||
|
||||
const inputBoxRef = useRef<HistoryInputBox | null>(null);
|
||||
const selectBoxRef = useRef<SelectBox | null>(null);
|
||||
const forceState = useCallback((newValue: string) => {
|
||||
if (inputBoxRef.current) {
|
||||
// inputBoxRef.current.addToHistory();
|
||||
inputBoxRef.current.value = newValue;
|
||||
}
|
||||
if (selectBoxRef.current) {
|
||||
selectBoxRef.current.select(enumArr?.indexOf(newValue) ?? 0);
|
||||
}
|
||||
updateState(newValue);
|
||||
}, [enumArr, updateState])
|
||||
|
||||
|
||||
const resetButton = <button
|
||||
disabled={val === defaultVal}
|
||||
title={val === defaultVal ? 'This is the default value.' : `Revert value to '${defaultVal}'?`}
|
||||
className='group btn btn-sm disabled:opacity-75 disabled:cursor-default'
|
||||
onClick={() => updateState(defaultVal)}
|
||||
onClick={() => forceState(defaultVal)}
|
||||
>
|
||||
<svg
|
||||
className='size-5 group-disabled:stroke-current group-disabled:fill-current group-hover:stroke-red-600 group-hover:fill-red-600 duration-200'
|
||||
|
|
@ -30,27 +50,42 @@ const SettingOfFieldAndParam = ({ field, param, configState, configStateService
|
|||
</svg>
|
||||
</button>
|
||||
|
||||
|
||||
|
||||
const inputElement = enumArr === undefined ?
|
||||
// string
|
||||
(<input
|
||||
className='input p-1 w-full'
|
||||
type='text'
|
||||
value={val}
|
||||
onChange={(e) => updateState(e.target.value)}
|
||||
(<InputBox
|
||||
onChangeText={updateState}
|
||||
initVal={val}
|
||||
multiline={false}
|
||||
placeholder=''
|
||||
inputBoxRef={inputBoxRef}
|
||||
/>)
|
||||
// <input
|
||||
// className='input p-1 w-full'
|
||||
// type='text'
|
||||
// value={val}
|
||||
// onChange={(e) => updateState(e.target.value)}
|
||||
// />
|
||||
:
|
||||
// enum
|
||||
(<select
|
||||
className='dropdown p-1 w-full'
|
||||
value={val}
|
||||
onChange={(e) => updateState(e.target.value)}
|
||||
>
|
||||
{enumArr.map((option) => (
|
||||
<option key={option} value={option}>
|
||||
{option}
|
||||
</option>
|
||||
))}
|
||||
</select>)
|
||||
(<EnumInputBox
|
||||
onChangeSelection={updateState}
|
||||
initVal={val}
|
||||
options={enumArr}
|
||||
selectBoxRef={selectBoxRef}
|
||||
/>)
|
||||
// (<select
|
||||
// className='dropdown p-1 w-full'
|
||||
// value={val}
|
||||
// onChange={(e) => updateState(e.target.value)}
|
||||
// >
|
||||
// {enumArr.map((option) => (
|
||||
// <option key={option} value={option}>
|
||||
// {option}
|
||||
// </option>
|
||||
// ))}
|
||||
// </select>)
|
||||
|
||||
return <div>
|
||||
<label className='hidden'>{param}</label>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,104 @@
|
|||
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';
|
||||
import { SelectBox, unthemedSelectBoxStyles } from '../../../../../../../base/browser/ui/selectBox/selectBox.js';
|
||||
|
||||
export const InputBox = ({ onChangeText, initVal, placeholder, inputBoxRef, multiline }: {
|
||||
onChangeText: (value: string) => void;
|
||||
placeholder: string;
|
||||
inputBoxRef: React.MutableRefObject<HistoryInputBox | null>;
|
||||
multiline: boolean;
|
||||
initVal: string;
|
||||
}) => {
|
||||
const contextViewProvider = useService('contextViewService');
|
||||
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!containerRef.current) return;
|
||||
|
||||
// create and mount the HistoryInputBox
|
||||
inputBoxRef.current = new HistoryInputBox(
|
||||
containerRef.current,
|
||||
contextViewProvider,
|
||||
{
|
||||
inputBoxStyles: {
|
||||
...defaultInputBoxStyles,
|
||||
inputBackground: 'transparent',
|
||||
},
|
||||
placeholder,
|
||||
history: [initVal],
|
||||
flexibleHeight: multiline,
|
||||
flexibleMaxHeight: 500,
|
||||
flexibleWidth: false,
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
inputBoxRef.current.onDidChange((newStr) => {
|
||||
console.log('CHANGE TEXT on inputbox', newStr)
|
||||
onChangeText(newStr)
|
||||
})
|
||||
|
||||
|
||||
// cleanup
|
||||
return () => {
|
||||
if (inputBoxRef.current) {
|
||||
inputBoxRef.current.dispose();
|
||||
if (containerRef.current) {
|
||||
while (containerRef.current.firstChild) {
|
||||
containerRef.current.removeChild(containerRef.current.firstChild);
|
||||
}
|
||||
}
|
||||
inputBoxRef.current = null;
|
||||
}
|
||||
};
|
||||
}, [inputBoxRef, onChangeText, placeholder, contextViewProvider, initVal, multiline]); // Empty dependency array since we only want to mount/unmount once
|
||||
|
||||
return <div ref={containerRef} className="w-full" />;
|
||||
};
|
||||
|
||||
|
||||
|
||||
export const EnumInputBox = ({ onChangeSelection, initVal, selectBoxRef, options }: {
|
||||
onChangeSelection: (value: string) => void;
|
||||
initVal: string;
|
||||
selectBoxRef: React.MutableRefObject<SelectBox | null>;
|
||||
options: readonly string[];
|
||||
|
||||
}) => {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const contextViewProvider = useService('contextViewService');
|
||||
|
||||
useEffect(() => {
|
||||
if (!containerRef.current) return;
|
||||
|
||||
const defaultIndex = options.indexOf(initVal);
|
||||
|
||||
selectBoxRef.current = new SelectBox(
|
||||
options.map(opt => ({ text: opt })),
|
||||
defaultIndex,
|
||||
contextViewProvider,
|
||||
unthemedSelectBoxStyles
|
||||
);
|
||||
|
||||
selectBoxRef.current.render(containerRef.current);
|
||||
|
||||
selectBoxRef.current.onDidSelect(e => { onChangeSelection(e.selected); });
|
||||
|
||||
// cleanup
|
||||
return () => {
|
||||
if (selectBoxRef.current) {
|
||||
selectBoxRef.current.dispose();
|
||||
if (containerRef.current) {
|
||||
while (containerRef.current.firstChild) {
|
||||
containerRef.current.removeChild(containerRef.current.firstChild);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}, [options, initVal, onChangeSelection, contextViewProvider]);
|
||||
|
||||
return <div ref={containerRef} className="w-full" />;
|
||||
};
|
||||
|
|
@ -69,8 +69,10 @@ export type ReactServicesType = {
|
|||
modelService: IModelService;
|
||||
inlineDiffService: IInlineDiffsService;
|
||||
sendLLMMessageService: ISendLLMMessageService;
|
||||
contextViewService: IContextViewService;
|
||||
clipboardService: IClipboardService;
|
||||
|
||||
contextViewService: IContextViewService;
|
||||
contextMenuService: IContextMenuService;
|
||||
}
|
||||
|
||||
// ---------- Define viewpane ----------
|
||||
|
|
@ -115,8 +117,9 @@ class VoidSidebarViewPane extends ViewPane {
|
|||
modelService: accessor.get(IModelService),
|
||||
inlineDiffService: accessor.get(IInlineDiffsService),
|
||||
sendLLMMessageService: accessor.get(ISendLLMMessageService),
|
||||
contextViewService: accessor.get(IContextViewService),
|
||||
clipboardService: accessor.get(IClipboardService),
|
||||
contextViewService: accessor.get(IContextViewService),
|
||||
contextMenuService: accessor.get(IContextMenuService),
|
||||
}
|
||||
mountFn(parent, services);
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue