mirror of
https://github.com/aljazceru/opencode.git
synced 2025-12-25 03:34:22 +01:00
84 lines
2.5 KiB
TypeScript
84 lines
2.5 KiB
TypeScript
import { ComponentProps, createEffect, createSignal, type JSX } from "solid-js"
|
|
import { VirtualizerHandle, VList } from "virtua/solid"
|
|
import { createList } from "solid-list"
|
|
import { createStore } from "solid-js/store"
|
|
|
|
export interface ListProps<T> {
|
|
data: T[]
|
|
children: (x: T) => JSX.Element
|
|
key: (x: T) => string
|
|
current?: T
|
|
onSelect?: (value: T | undefined) => void
|
|
onHover?: (value: T | undefined) => void
|
|
class?: ComponentProps<"div">["class"]
|
|
}
|
|
|
|
export function List<T>(props: ListProps<T>) {
|
|
const [virtualizer, setVirtualizer] = createSignal<VirtualizerHandle | undefined>(undefined)
|
|
const [store, setStore] = createStore({
|
|
mouseActive: false,
|
|
})
|
|
const list = createList({
|
|
items: () => props.data.map(props.key),
|
|
initialActive: props.current ? props.key(props.current) : undefined,
|
|
loop: true,
|
|
})
|
|
|
|
createEffect(() => {
|
|
if (props.current) list.setActive(props.key(props.current))
|
|
})
|
|
// const resetSelection = () => {
|
|
// if (props.data.length === 0) return
|
|
// list.setActive(props.key(props.data[0]))
|
|
// }
|
|
const handleSelect = (item: T) => {
|
|
props.onSelect?.(item)
|
|
list.setActive(props.key(item))
|
|
}
|
|
|
|
const handleKey = (e: KeyboardEvent) => {
|
|
setStore("mouseActive", false)
|
|
|
|
if (e.key === "Enter") {
|
|
e.preventDefault()
|
|
const selected = props.data.find((x) => props.key(x) === list.active())
|
|
if (selected) handleSelect(selected)
|
|
} else {
|
|
list.onKeyDown(e)
|
|
}
|
|
}
|
|
|
|
createEffect(() => {
|
|
if (store.mouseActive || props.data.length === 0) return
|
|
const index = props.data.findIndex((x) => props.key(x) === list.active())
|
|
props.onHover?.(props.data[index])
|
|
if (index === 0) {
|
|
virtualizer()?.scrollTo(0)
|
|
return
|
|
}
|
|
// virtualizer()?.scrollTo(list.active())
|
|
// const element = virtualizer()?.querySelector(`[data-key="${list.active()}"]`)
|
|
// element?.scrollIntoView({ block: "nearest", behavior: "smooth" })
|
|
})
|
|
|
|
return (
|
|
<VList data-component="list" ref={setVirtualizer} data={props.data} onKeyDown={handleKey} class={props.class}>
|
|
{(item) => (
|
|
<button
|
|
data-slot="item"
|
|
data-key={props.key(item)}
|
|
data-active={props.key(item) === list.active()}
|
|
onClick={() => handleSelect(item)}
|
|
onMouseMove={() => {
|
|
// e.currentTarget.focus()
|
|
setStore("mouseActive", true)
|
|
// list.setActive(props.key(item))
|
|
}}
|
|
>
|
|
{props.children(item)}
|
|
</button>
|
|
)}
|
|
</VList>
|
|
)
|
|
}
|