summaryrefslogtreecommitdiffhomepage
path: root/packages/ui/src/components/select.tsx
diff options
context:
space:
mode:
authorAdam <[email protected]>2026-01-20 07:10:40 -0600
committerAdam <[email protected]>2026-01-20 07:33:44 -0600
commit340285575b510f4ab466fa80d0de1cf20b4e048a (patch)
tree9587a21664547875d060258ad7ee7b3de0dba290 /packages/ui/src/components/select.tsx
parentdd5b5f5482df86959f0ea90e20f86ca7a5e19b08 (diff)
downloadopencode-340285575b510f4ab466fa80d0de1cf20b4e048a.tar.gz
opencode-340285575b510f4ab466fa80d0de1cf20b4e048a.zip
chore: cleanup
Diffstat (limited to 'packages/ui/src/components/select.tsx')
-rw-r--r--packages/ui/src/components/select.tsx44
1 files changed, 42 insertions, 2 deletions
diff --git a/packages/ui/src/components/select.tsx b/packages/ui/src/components/select.tsx
index e60fcbee1..245a36d38 100644
--- a/packages/ui/src/components/select.tsx
+++ b/packages/ui/src/components/select.tsx
@@ -1,5 +1,5 @@
import { Select as Kobalte } from "@kobalte/core/select"
-import { createMemo, splitProps, type ComponentProps, type JSX } from "solid-js"
+import { createMemo, onCleanup, splitProps, type ComponentProps, type JSX } from "solid-js"
import { pipe, groupBy, entries, map } from "remeda"
import { Button, ButtonProps } from "./button"
import { Icon } from "./icon"
@@ -12,6 +12,7 @@ export type SelectProps<T> = Omit<ComponentProps<typeof Kobalte<T>>, "value" | "
label?: (x: T) => string
groupBy?: (x: T) => string
onSelect?: (value: T | undefined) => void
+ onHighlight?: (value: T | undefined) => (() => void) | void
class?: ComponentProps<"div">["class"]
classList?: ComponentProps<"div">["classList"]
children?: (item: T | undefined) => JSX.Element
@@ -28,8 +29,40 @@ export function Select<T>(props: SelectProps<T> & ButtonProps) {
"label",
"groupBy",
"onSelect",
+ "onHighlight",
+ "onOpenChange",
"children",
])
+
+ const state = {
+ key: undefined as string | undefined,
+ cleanup: undefined as (() => void) | void,
+ }
+
+ const stop = () => {
+ state.cleanup?.()
+ state.cleanup = undefined
+ state.key = undefined
+ }
+
+ const keyFor = (item: T) => (local.value ? local.value(item) : (item as string))
+
+ const move = (item: T | undefined) => {
+ if (!local.onHighlight) return
+ if (!item) {
+ stop()
+ return
+ }
+
+ const key = keyFor(item)
+ if (state.key === key) return
+ state.cleanup?.()
+ state.cleanup = local.onHighlight(item)
+ state.key = key
+ }
+
+ onCleanup(stop)
+
const grouped = createMemo(() => {
const result = pipe(
local.options,
@@ -58,12 +91,14 @@ export function Select<T>(props: SelectProps<T> & ButtonProps) {
)}
itemComponent={(itemProps) => (
<Kobalte.Item
+ {...itemProps}
data-slot="select-select-item"
classList={{
...(local.classList ?? {}),
[local.class ?? ""]: !!local.class,
}}
- {...itemProps}
+ onPointerEnter={() => move(itemProps.item.rawValue)}
+ onPointerMove={() => move(itemProps.item.rawValue)}
>
<Kobalte.ItemLabel data-slot="select-select-item-label">
{local.children
@@ -79,6 +114,11 @@ export function Select<T>(props: SelectProps<T> & ButtonProps) {
)}
onChange={(v) => {
local.onSelect?.(v ?? undefined)
+ stop()
+ }}
+ onOpenChange={(open) => {
+ local.onOpenChange?.(open)
+ if (!open) stop()
}}
>
<Kobalte.Trigger