diff --git a/.changeset/fix-model-dropdown-scrollbar.md b/.changeset/fix-model-dropdown-scrollbar.md new file mode 100644 index 00000000000..1e8bd84805d --- /dev/null +++ b/.changeset/fix-model-dropdown-scrollbar.md @@ -0,0 +1,7 @@ +--- +"kilo-code": patch +--- + +Fix double scrollbar in model dropdown and make search box sticky + +The model selection dropdown previously showed two scrollbars - one on the outer container and one on the inner items list. Additionally, the search box would scroll out of view when browsing through the model list. This fix restructures the dropdown to use a single scrollbar on the items container only, while keeping the search input sticky at the top for better usability. diff --git a/webview-ui/src/components/kilocode/chat/ModelSelector.tsx b/webview-ui/src/components/kilocode/chat/ModelSelector.tsx index dfdd2f32ef4..dcfc7bda0ba 100644 --- a/webview-ui/src/components/kilocode/chat/ModelSelector.tsx +++ b/webview-ui/src/components/kilocode/chat/ModelSelector.tsx @@ -142,7 +142,7 @@ export const ModelSelector = ({ title={t("chat:selectApiConfig")} options={options} onChange={onChange} - contentClassName="max-h-[300px] overflow-y-auto" + contentClassName="max-h-[300px]" triggerClassName={cn( "w-full text-ellipsis overflow-hidden p-0", "bg-transparent border-transparent hover:bg-transparent hover:border-transparent", diff --git a/webview-ui/src/components/ui/select-dropdown.tsx b/webview-ui/src/components/ui/select-dropdown.tsx index 78372b55682..a592b18b6a9 100644 --- a/webview-ui/src/components/ui/select-dropdown.tsx +++ b/webview-ui/src/components/ui/select-dropdown.tsx @@ -272,128 +272,127 @@ export const SelectDropdown = React.memo( align={align} sideOffset={sideOffset} container={portalContainer} - className={cn("p-0 overflow-hidden", contentClassName)}> -
- {/* Search input */} - {!disableSearch && ( -
- setSearchValue(e.target.value)} - placeholder={t("common:ui.search_placeholder")} - className="w-full h-8 px-2 py-1 text-xs bg-vscode-input-background text-vscode-input-foreground border border-vscode-input-border rounded focus:outline-0" - /> - {searchValue.length > 0 && ( -
- -
- )} -
- )} + className={cn("p-0 flex flex-col", contentClassName)}> + {/* Search input - Sticky at top */} + {/* kilocode_change: made search sticky and restructured scroll containers */} + {!disableSearch && ( +
+ setSearchValue(e.target.value)} + placeholder={t("common:ui.search_placeholder")} + className="w-full h-8 px-2 py-1 text-xs bg-vscode-input-background text-vscode-input-foreground border border-vscode-input-border rounded focus:outline-0" + /> + {searchValue.length > 0 && ( +
+ +
+ )} +
+ )} + + {/* Dropdown items - Scrollable container */} + {/* kilocode_change: single scrollbar for items only */} +
+ {groupedOptions.length === 0 && searchValue ? ( +
No results found
+ ) : ( +
+ {groupedOptions.map((option, index) => { + // Memoize rendering of each item type for better performance + if (option.type === DropdownOptionType.SEPARATOR) { + return ( +
+ ) + } - {/* Dropdown items - Use windowing for large lists */} - {/* kilocode_change: different max height: max-h-82 */} -
- {groupedOptions.length === 0 && searchValue ? ( -
No results found
- ) : ( -
- {groupedOptions.map((option, index) => { - // Memoize rendering of each item type for better performance - if (option.type === DropdownOptionType.SEPARATOR) { - return ( -
- ) - } - - // kilocode_change start: render LABEL type as section header - if (option.type === DropdownOptionType.LABEL) { - return ( -
- {option.label} -
- ) - } - // kilocode_change end - - if ( - option.type === DropdownOptionType.SHORTCUT || - (option.disabled && shortcutText && option.label.includes(shortcutText)) - ) { - return ( -
- {option.label} -
- ) - } - - // Use stable keys for better reconciliation - const itemKey = `item-${option.value || option.label || index}` + // kilocode_change start: render LABEL type as section header + if (option.type === DropdownOptionType.LABEL) { + return ( +
+ {option.label} +
+ ) + } + // kilocode_change end + if ( + option.type === DropdownOptionType.SHORTCUT || + (option.disabled && shortcutText && option.label.includes(shortcutText)) + ) { return (
!option.disabled && handleSelect(option.value)} - className={cn( - "text-sm cursor-pointer flex items-center", // kilocode_change - option.disabled - ? "opacity-50 cursor-not-allowed" - : "hover:bg-vscode-list-hoverBackground", - option.value === value - ? "bg-vscode-list-activeSelectionBackground text-vscode-list-activeSelectionForeground" - : "", - itemClassName, - )} - data-testid="dropdown-item"> - {renderItem ? ( - renderItem(option) - ) : ( - <> - {/* kilocode_change start */} -
- -
-
{option.label}
- {option.description && ( -
- {option.description} -
- )} -
- {/* kilocode_change end */} - {option.value === value && ( - - )} -
- - )} + key={`shortcut-${index}`} + className="px-3 py-1.5 text-sm opacity-50"> + {option.label}
) - })} -
- )} -
+ } + + // Use stable keys for better reconciliation + const itemKey = `item-${option.value || option.label || index}` + + return ( +
!option.disabled && handleSelect(option.value)} + className={cn( + "text-sm cursor-pointer flex items-center", // kilocode_change + option.disabled + ? "opacity-50 cursor-not-allowed" + : "hover:bg-vscode-list-hoverBackground", + option.value === value + ? "bg-vscode-list-activeSelectionBackground text-vscode-list-activeSelectionForeground" + : "", + itemClassName, + )} + data-testid="dropdown-item"> + {renderItem ? ( + renderItem(option) + ) : ( + <> + {/* kilocode_change start */} +
+ +
+
{option.label}
+ {option.description && ( +
+ {option.description} +
+ )} +
+ {/* kilocode_change end */} + {option.value === value && ( + + )} +
+ + )} +
+ ) + })} +
+ )}