summaryrefslogtreecommitdiffhomepage
path: root/packages/ui/src/components/list.tsx
diff options
context:
space:
mode:
authorAdam <[email protected]>2025-12-29 09:47:53 -0600
committerAdam <[email protected]>2025-12-29 09:47:57 -0600
commit831e9bce51c035ec22ce9562bf0257d6b59b2fe4 (patch)
treeb6e86b44cbc980d737a63cb571cb61a9003d237b /packages/ui/src/components/list.tsx
parent5de73abd820d9425e82f85f95f50568332ca7cdc (diff)
downloadopencode-831e9bce51c035ec22ce9562bf0257d6b59b2fe4.tar.gz
opencode-831e9bce51c035ec22ce9562bf0257d6b59b2fe4.zip
fix(desktop): jankiness
Diffstat (limited to 'packages/ui/src/components/list.tsx')
-rw-r--r--packages/ui/src/components/list.tsx55
1 files changed, 29 insertions, 26 deletions
diff --git a/packages/ui/src/components/list.tsx b/packages/ui/src/components/list.tsx
index 808c9b032..a549c19e9 100644
--- a/packages/ui/src/components/list.tsx
+++ b/packages/ui/src/components/list.tsx
@@ -1,5 +1,5 @@
import { type FilteredListProps, useFilteredList } from "@opencode-ai/ui/hooks"
-import { createEffect, createSignal, For, type JSX, on, Show } from "solid-js"
+import { createEffect, createSignal, For, onCleanup, type JSX, on, Show } from "solid-js"
import { createStore } from "solid-js/store"
import { Icon, type IconProps } from "./icon"
import { IconButton } from "./icon-button"
@@ -116,6 +116,33 @@ export function List<T>(props: ListProps<T> & { ref?: (ref: ListRef) => void })
setScrollRef,
})
+ function GroupHeader(props: { category: string }): JSX.Element {
+ const [stuck, setStuck] = createSignal(false)
+ const [header, setHeader] = createSignal<HTMLDivElement | undefined>(undefined)
+
+ createEffect(() => {
+ const scroll = scrollRef()
+ const node = header()
+ if (!scroll || !node) return
+
+ const handler = () => {
+ const rect = node.getBoundingClientRect()
+ const scrollRect = scroll.getBoundingClientRect()
+ setStuck(rect.top <= scrollRect.top + 1 && scroll.scrollTop > 0)
+ }
+
+ scroll.addEventListener("scroll", handler, { passive: true })
+ handler()
+ onCleanup(() => scroll.removeEventListener("scroll", handler))
+ })
+
+ return (
+ <div data-slot="list-header" data-stuck={stuck()} ref={setHeader}>
+ {props.category}
+ </div>
+ )
+ }
+
return (
<div data-component="list" classList={{ [props.class ?? ""]: !!props.class }}>
<Show when={!!props.search}>
@@ -157,31 +184,7 @@ export function List<T>(props: ListProps<T> & { ref?: (ref: ListRef) => void })
{(group) => (
<div data-slot="list-group">
<Show when={group.category}>
- {(() => {
- const [stuck, setStuck] = createSignal(false)
- return (
- <div
- data-slot="list-header"
- data-stuck={stuck()}
- ref={(el) => {
- createEffect(() => {
- const scroll = scrollRef()
- if (!scroll) return
- const handler = () => {
- const rect = el.getBoundingClientRect()
- const scrollRect = scroll.getBoundingClientRect()
- setStuck(rect.top <= scrollRect.top + 1 && scroll.scrollTop > 0)
- }
- scroll.addEventListener("scroll", handler, { passive: true })
- handler()
- return () => scroll.removeEventListener("scroll", handler)
- })
- }}
- >
- {group.category}
- </div>
- )
- })()}
+ <GroupHeader category={group.category} />
</Show>
<div data-slot="list-items">
<For each={group.items}>