fix(app): stabilize server routes and selects
This commit is contained in:
parent
e8b0992788
commit
8be2027a2a
13 changed files with 115 additions and 35 deletions
12
packages/ui/src/components/select-defer.test.ts
Normal file
12
packages/ui/src/components/select-defer.test.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import { expect, test } from "bun:test"
|
||||
import { deferSelect } from "./select-defer"
|
||||
|
||||
test("defers controlled select updates until the current selection closes", async () => {
|
||||
const order: string[] = []
|
||||
deferSelect(() => order.push("update"), "theme")
|
||||
order.push("close")
|
||||
|
||||
expect(order).toEqual(["close"])
|
||||
await Promise.resolve()
|
||||
expect(order).toEqual(["close", "update"])
|
||||
})
|
||||
5
packages/ui/src/components/select-defer.ts
Normal file
5
packages/ui/src/components/select-defer.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
export function deferSelect<T>(callback: ((value: T) => void) | undefined, value: T) {
|
||||
// Kobalte closes the popup after onChange returns. Controlled updates must wait
|
||||
// so they cannot rebuild the value or options during portal cleanup.
|
||||
queueMicrotask(() => callback?.(value))
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ import { createMemo, onCleanup, splitProps, type ComponentProps, type JSX } from
|
|||
import { pipe, groupBy, entries, map } from "remeda"
|
||||
import { Button, ButtonProps } from "./button"
|
||||
import { Icon } from "./icon"
|
||||
import { deferSelect } from "./select-defer"
|
||||
|
||||
export type SelectProps<T> = Omit<ComponentProps<typeof Kobalte<T>>, "value" | "onSelect" | "children"> & {
|
||||
placeholder?: string
|
||||
|
|
@ -124,7 +125,7 @@ export function Select<T>(props: SelectProps<T> & Omit<ButtonProps, "children">)
|
|||
</Kobalte.Item>
|
||||
)}
|
||||
onChange={(v) => {
|
||||
local.onSelect?.(v ?? undefined)
|
||||
deferSelect(local.onSelect, v ?? undefined)
|
||||
stop()
|
||||
}}
|
||||
onOpenChange={(open) => {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { Select as Kobalte } from "@kobalte/core/select"
|
||||
import { Show, createMemo, onCleanup, splitProps, type ComponentProps, type JSX } from "solid-js"
|
||||
import { deferSelect } from "../../components/select-defer"
|
||||
import "./select-v2.css"
|
||||
|
||||
function groupOptions<T>(options: T[], groupBy?: (x: T) => string): { category: string; options: T[] }[] {
|
||||
|
|
@ -165,7 +166,7 @@ export function SelectV2<T>(props: SelectV2Props<T>) {
|
|||
)}
|
||||
onChange={(next) => {
|
||||
const v = next == null ? null : Array.isArray(next) ? ((next[0] as T) ?? null) : (next as T)
|
||||
local.onSelect?.(v)
|
||||
deferSelect(local.onSelect, v)
|
||||
stop()
|
||||
}}
|
||||
onOpenChange={(open) => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue