diff --git a/packages/app/src/components/settings-general.tsx b/packages/app/src/components/settings-general.tsx index cbbf33d2b135..32f2d5e3618f 100644 --- a/packages/app/src/components/settings-general.tsx +++ b/packages/app/src/components/settings-general.tsx @@ -30,6 +30,7 @@ import { decode64 } from "@/utils/base64" import { playSoundById, SOUND_OPTIONS } from "@/utils/sound" import { Link } from "./link" import { SettingsList } from "./settings-list" +import { SettingsScroll } from "./settings-scroll" let demoSoundState = { cleanup: undefined as (() => void) | undefined, @@ -720,7 +721,7 @@ export const SettingsGeneral: Component = () => { ) return ( -
+

{language.t("settings.tab.general")}

@@ -744,7 +745,7 @@ export const SettingsGeneral: Component = () => {
-
+
) } diff --git a/packages/app/src/components/settings-keybinds.tsx b/packages/app/src/components/settings-keybinds.tsx index 3e3db45bcf5f..140e50349a21 100644 --- a/packages/app/src/components/settings-keybinds.tsx +++ b/packages/app/src/components/settings-keybinds.tsx @@ -13,7 +13,9 @@ import fuzzysort from "fuzzysort" import { formatKeybind, parseKeybind, useCommand } from "@/context/command" import { useLanguage } from "@/context/language" import { useSettings } from "@/context/settings" +import { ScrollView } from "@opencode-ai/ui/scroll-view" import { SettingsList } from "./settings-list" +import { SettingsScroll } from "./settings-scroll" import { SettingsListV2 } from "./settings-v2/parts/list" const IconV2 = lazy(() => import("@opencode-ai/ui/v2/icon").then((module) => ({ default: module.Icon }))) @@ -480,7 +482,7 @@ export const SettingsKeybinds: Component<{ v2?: boolean }> = (props) => { +
@@ -511,10 +513,10 @@ export const SettingsKeybinds: Component<{ v2?: boolean }> = (props) => {
{groups} -
+
} > - <> +

{language.t("settings.shortcuts.title")}

@@ -548,7 +550,7 @@ export const SettingsKeybinds: Component<{ v2?: boolean }> = (props) => {
{groups}
- +
) } diff --git a/packages/app/src/components/settings-models.tsx b/packages/app/src/components/settings-models.tsx index f3d9e1522ff4..41f2a9ca7d0e 100644 --- a/packages/app/src/components/settings-models.tsx +++ b/packages/app/src/components/settings-models.tsx @@ -9,6 +9,7 @@ import { useLanguage } from "@/context/language" import { useModels } from "@/context/models" import { popularProviders } from "@/hooks/use-providers" import { SettingsList } from "./settings-list" +import { SettingsScroll } from "./settings-scroll" import { SettingsServerPicker, SettingsServerScope } from "./settings-server-picker" type ModelItem = ReturnType["list"]>[number] @@ -67,7 +68,7 @@ const SettingsModelsContent: Component = () => { }) return ( -
+
@@ -144,6 +145,6 @@ const SettingsModelsContent: Component = () => {
-
+ ) } diff --git a/packages/app/src/components/settings-providers.tsx b/packages/app/src/components/settings-providers.tsx index bcd30edbc7de..0205108a2352 100644 --- a/packages/app/src/components/settings-providers.tsx +++ b/packages/app/src/components/settings-providers.tsx @@ -11,6 +11,7 @@ import { useServerSync } from "@/context/server-sync" import { DialogConnectProvider, useProviderConnectController } from "./dialog-connect-provider" import { DialogCustomProvider } from "./dialog-custom-provider" import { SettingsList } from "./settings-list" +import { SettingsScroll } from "./settings-scroll" import { SettingsServerPicker, SettingsServerScope } from "./settings-server-picker" type ProviderSource = "env" | "api" | "config" | "custom" @@ -143,7 +144,7 @@ const SettingsProvidersContent: Component<{ onBack?: () => void }> = (props) => } return ( -
+

{language.t("settings.providers.title")}

@@ -254,6 +255,6 @@ const SettingsProvidersContent: Component<{ onBack?: () => void }> = (props) =>
-
+ ) } diff --git a/packages/app/src/components/settings-scroll.tsx b/packages/app/src/components/settings-scroll.tsx new file mode 100644 index 000000000000..17a9a243a4ed --- /dev/null +++ b/packages/app/src/components/settings-scroll.tsx @@ -0,0 +1,10 @@ +import { type Component, type JSX } from "solid-js" +import { ScrollView } from "@opencode-ai/ui/scroll-view" + +export const SettingsScroll: Component<{ children: JSX.Element }> = (props) => { + return ( + +
{props.children}
+
+ ) +} diff --git a/packages/app/src/components/settings-v2/general.tsx b/packages/app/src/components/settings-v2/general.tsx index 0dd48a5523cc..a9a36184a73f 100644 --- a/packages/app/src/components/settings-v2/general.tsx +++ b/packages/app/src/components/settings-v2/general.tsx @@ -4,6 +4,7 @@ import { ButtonV2 } from "@opencode-ai/ui/v2/button-v2" import { SelectV2 } from "@opencode-ai/ui/v2/select-v2" import { Switch } from "@opencode-ai/ui/v2/switch-v2" import { TextInputV2 } from "@opencode-ai/ui/v2/text-input-v2" +import { ScrollView } from "@opencode-ai/ui/scroll-view" import { useTheme, type ColorScheme } from "@opencode-ai/ui/theme/context" import { useDialog } from "@opencode-ai/ui/context/dialog" import { useLanguage } from "@/context/language" @@ -687,7 +688,7 @@ export const SettingsGeneralV2: Component<{ ) return ( - <> +

{language.t("settings.tab.general")}

@@ -709,6 +710,6 @@ export const SettingsGeneralV2: Component<{
- + ) } diff --git a/packages/app/src/components/settings-v2/models.tsx b/packages/app/src/components/settings-v2/models.tsx index a3f058670e4a..6ac544b23024 100644 --- a/packages/app/src/components/settings-v2/models.tsx +++ b/packages/app/src/components/settings-v2/models.tsx @@ -4,6 +4,7 @@ import { Switch } from "@opencode-ai/ui/v2/switch-v2" import { Icon as IconV2 } from "@opencode-ai/ui/v2/icon" import { IconButtonV2 } from "@opencode-ai/ui/v2/icon-button-v2" import { TextInputV2 } from "@opencode-ai/ui/v2/text-input-v2" +import { ScrollView } from "@opencode-ai/ui/scroll-view" import { type Component, For, Show } from "solid-js" import { useLanguage } from "@/context/language" import { useModels } from "@/context/models" @@ -43,7 +44,7 @@ export const SettingsModelsV2: Component = () => { }) return ( - <> +

{language.t("settings.models.title")}

- + ) } diff --git a/packages/app/src/components/settings-v2/providers.tsx b/packages/app/src/components/settings-v2/providers.tsx index f945fa33c643..77959a31d86c 100644 --- a/packages/app/src/components/settings-v2/providers.tsx +++ b/packages/app/src/components/settings-v2/providers.tsx @@ -2,6 +2,7 @@ import { ButtonV2 } from "@opencode-ai/ui/v2/button-v2" import { Tag } from "@opencode-ai/ui/v2/badge-v2" import { useDialog } from "@opencode-ai/ui/context/dialog" import { ProviderIcon } from "@opencode-ai/ui/provider-icon" +import { ScrollView } from "@opencode-ai/ui/scroll-view" import { showToast } from "@/utils/toast" import { popularProviders, useProviders } from "@/hooks/use-providers" import { createMemo, type Component, For, Show } from "solid-js" @@ -137,7 +138,7 @@ export const SettingsProvidersV2: Component<{ onBack?: () => void }> = (props) = } return ( - <> +

{language.t("settings.providers.title")}

@@ -252,6 +253,6 @@ export const SettingsProvidersV2: Component<{ onBack?: () => void }> = (props) =
- + ) } diff --git a/packages/app/src/components/settings-v2/servers.tsx b/packages/app/src/components/settings-v2/servers.tsx index b93f700d24cf..98fded32630b 100644 --- a/packages/app/src/components/settings-v2/servers.tsx +++ b/packages/app/src/components/settings-v2/servers.tsx @@ -2,6 +2,7 @@ import { Tag } from "@opencode-ai/ui/v2/badge-v2" import { Icon as IconV2 } from "@opencode-ai/ui/v2/icon" import { IconButtonV2 } from "@opencode-ai/ui/v2/icon-button-v2" import { TextInputV2 } from "@opencode-ai/ui/v2/text-input-v2" +import { ScrollView } from "@opencode-ai/ui/scroll-view" import { useDialog } from "@opencode-ai/ui/context/dialog" import fuzzysort from "fuzzysort" import { type Component, For, Show, createMemo } from "solid-js" @@ -47,7 +48,7 @@ export const SettingsServersV2: Component = () => { } return ( - <> +
{
- +
) } diff --git a/packages/ui/src/components/scroll-view.tsx b/packages/ui/src/components/scroll-view.tsx index 0a567ce1c50f..3a12602bf4c6 100644 --- a/packages/ui/src/components/scroll-view.tsx +++ b/packages/ui/src/components/scroll-view.tsx @@ -208,6 +208,9 @@ export function ScrollView(props: ScrollViewProps) { // We can also explicitly catch PageUp/Down if we want smooth scroll or specific behavior, // but native usually handles this perfectly. Let's explicitly ensure it behaves well. const onKeyDown = (e: KeyboardEvent) => { + // Defer to a descendant that already handled the key (e.g. an opening/open + // dropdown, listbox, or menu) — don't additionally scroll the viewport. + if (e.defaultPrevented) return // If user is focused on an input inside the scroll view, don't hijack keys if (document.activeElement && ["INPUT", "TEXTAREA", "SELECT"].includes(document.activeElement.tagName)) { return