diff options
| author | Adam <[email protected]> | 2026-03-09 10:43:56 -0500 |
|---|---|---|
| committer | Adam <[email protected]> | 2026-03-09 10:44:02 -0500 |
| commit | b749fa90f23d187d5428de1a2d321cc6497b6667 (patch) | |
| tree | 46fbaed687ce73fc39f493d81235c89fe761aa7c /packages/ui/src/components | |
| parent | 8a51cbd25381768be438696d8209eaaef6a6d41e (diff) | |
| download | opencode-b749fa90f23d187d5428de1a2d321cc6497b6667.tar.gz opencode-b749fa90f23d187d5428de1a2d321cc6497b6667.zip | |
fix(app): scroll jitter/loop
Diffstat (limited to 'packages/ui/src/components')
| -rw-r--r-- | packages/ui/src/components/scroll-view.test.ts | 19 | ||||
| -rw-r--r-- | packages/ui/src/components/scroll-view.tsx | 36 |
2 files changed, 48 insertions, 7 deletions
diff --git a/packages/ui/src/components/scroll-view.test.ts b/packages/ui/src/components/scroll-view.test.ts new file mode 100644 index 000000000..d28b51fea --- /dev/null +++ b/packages/ui/src/components/scroll-view.test.ts @@ -0,0 +1,19 @@ +import { describe, expect, test } from "bun:test" +import { scrollKey } from "./scroll-view" + +describe("scrollKey", () => { + test("maps plain navigation keys", () => { + expect(scrollKey({ key: "PageDown", altKey: false, ctrlKey: false, metaKey: false, shiftKey: false })).toBe( + "page-down", + ) + expect(scrollKey({ key: "ArrowUp", altKey: false, ctrlKey: false, metaKey: false, shiftKey: false })).toBe("up") + }) + + test("ignores modified keybinds", () => { + expect( + scrollKey({ key: "ArrowDown", altKey: false, ctrlKey: false, metaKey: true, shiftKey: false }), + ).toBeUndefined() + expect(scrollKey({ key: "PageUp", altKey: false, ctrlKey: true, metaKey: false, shiftKey: false })).toBeUndefined() + expect(scrollKey({ key: "End", altKey: false, ctrlKey: false, metaKey: false, shiftKey: true })).toBeUndefined() + }) +}) diff --git a/packages/ui/src/components/scroll-view.tsx b/packages/ui/src/components/scroll-view.tsx index 52ed39a46..c3d878af6 100644 --- a/packages/ui/src/components/scroll-view.tsx +++ b/packages/ui/src/components/scroll-view.tsx @@ -6,6 +6,25 @@ export interface ScrollViewProps extends ComponentProps<"div"> { orientation?: "vertical" | "horizontal" // currently only vertical is fully implemented for thumb } +export const scrollKey = (event: Pick<KeyboardEvent, "key" | "altKey" | "ctrlKey" | "metaKey" | "shiftKey">) => { + if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) return + + switch (event.key) { + case "PageDown": + return "page-down" + case "PageUp": + return "page-up" + case "Home": + return "home" + case "End": + return "end" + case "ArrowUp": + return "up" + case "ArrowDown": + return "down" + } +} + export function ScrollView(props: ScrollViewProps) { const i18n = useI18n() const merged = mergeProps({ orientation: "vertical" }, props) @@ -133,31 +152,34 @@ export function ScrollView(props: ScrollViewProps) { return } + const next = scrollKey(e) + if (!next) return + const scrollAmount = viewportRef.clientHeight * 0.8 const lineAmount = 40 - switch (e.key) { - case "PageDown": + switch (next) { + case "page-down": e.preventDefault() viewportRef.scrollBy({ top: scrollAmount, behavior: "smooth" }) break - case "PageUp": + case "page-up": e.preventDefault() viewportRef.scrollBy({ top: -scrollAmount, behavior: "smooth" }) break - case "Home": + case "home": e.preventDefault() viewportRef.scrollTo({ top: 0, behavior: "smooth" }) break - case "End": + case "end": e.preventDefault() viewportRef.scrollTo({ top: viewportRef.scrollHeight, behavior: "smooth" }) break - case "ArrowUp": + case "up": e.preventDefault() viewportRef.scrollBy({ top: -lineAmount, behavior: "smooth" }) break - case "ArrowDown": + case "down": e.preventDefault() viewportRef.scrollBy({ top: lineAmount, behavior: "smooth" }) break |
