summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAdam <[email protected]>2026-01-19 11:44:20 -0600
committerAdam <[email protected]>2026-01-19 11:44:20 -0600
commit092428633fe05b33c26a94549d6e65d2235da514 (patch)
treebf95acb39d959ba576706bbfe86fd16623402dc3
parentfc50b2962c24dc37fa131759cd56460fbc1f43fa (diff)
downloadopencode-092428633fe05b33c26a94549d6e65d2235da514.tar.gz
opencode-092428633fe05b33c26a94549d6e65d2235da514.zip
fix(app): layout jumping
-rw-r--r--packages/ui/src/components/list.tsx38
1 files changed, 32 insertions, 6 deletions
diff --git a/packages/ui/src/components/list.tsx b/packages/ui/src/components/list.tsx
index b8a8f7460..874638c5a 100644
--- a/packages/ui/src/components/list.tsx
+++ b/packages/ui/src/components/list.tsx
@@ -35,6 +35,25 @@ export function List<T>(props: ListProps<T> & { ref?: (ref: ListRef) => void })
mouseActive: false,
})
+ const scrollIntoView = (container: HTMLDivElement, node: HTMLElement, block: "center" | "nearest") => {
+ const containerRect = container.getBoundingClientRect()
+ const nodeRect = node.getBoundingClientRect()
+ const top = nodeRect.top - containerRect.top + container.scrollTop
+ const bottom = top + nodeRect.height
+ const viewTop = container.scrollTop
+ const viewBottom = viewTop + container.clientHeight
+ const target =
+ block === "center"
+ ? top - container.clientHeight / 2 + nodeRect.height / 2
+ : top < viewTop
+ ? top
+ : bottom > viewBottom
+ ? bottom - container.clientHeight
+ : viewTop
+ const max = Math.max(0, container.scrollHeight - container.clientHeight)
+ container.scrollTop = Math.max(0, Math.min(target, max))
+ }
+
const { filter, grouped, flat, active, setActive, onKeyDown, onInput } = useFilteredList<T>(props)
const searchProps = () => (typeof props.search === "object" ? props.search : {})
@@ -65,24 +84,31 @@ export function List<T>(props: ListProps<T> & { ref?: (ref: ListRef) => void })
)
createEffect(() => {
- if (!scrollRef()) return
+ const scroll = scrollRef()
+ if (!scroll) return
if (!props.current) return
const key = props.key(props.current)
requestAnimationFrame(() => {
- const element = scrollRef()?.querySelector(`[data-key="${CSS.escape(key)}"]`)
- element?.scrollIntoView({ block: "center" })
+ const element = scroll.querySelector(`[data-key="${CSS.escape(key)}"]`)
+ if (!(element instanceof HTMLElement)) return
+ scrollIntoView(scroll, element, "center")
})
})
createEffect(() => {
const all = flat()
if (store.mouseActive || all.length === 0) return
+ const scroll = scrollRef()
+ if (!scroll) return
if (active() === props.key(all[0])) {
- scrollRef()?.scrollTo(0, 0)
+ scroll.scrollTo(0, 0)
return
}
- const element = scrollRef()?.querySelector(`[data-key="${CSS.escape(active()!)}"]`)
- element?.scrollIntoView({ block: "center" })
+ const key = active()
+ if (!key) return
+ const element = scroll.querySelector(`[data-key="${CSS.escape(key)}"]`)
+ if (!(element instanceof HTMLElement)) return
+ scrollIntoView(scroll, element, "center")
})
createEffect(() => {