summaryrefslogtreecommitdiffhomepage
path: root/packages/ui/src
diff options
context:
space:
mode:
authorAdam <[email protected]>2026-01-06 08:18:17 -0600
committerAdam <[email protected]>2026-01-06 08:19:17 -0600
commitb88bcd49fdea0955f2efc8f09a3614c188d22107 (patch)
tree8ab04d7a9d2b892cd884eab5ab3bb5da9187191a /packages/ui/src
parent3f463bc9168abd907be9ae582e161ff89c3a27c9 (diff)
downloadopencode-b88bcd49fdea0955f2efc8f09a3614c188d22107.tar.gz
opencode-b88bcd49fdea0955f2efc8f09a3614c188d22107.zip
fix(app): code splitting for web load perf gains
Diffstat (limited to 'packages/ui/src')
-rw-r--r--packages/ui/src/components/list.tsx5
-rw-r--r--packages/ui/src/components/markdown.tsx3
-rw-r--r--packages/ui/src/context/dialog.tsx109
-rw-r--r--packages/ui/src/hooks/use-filtered-list.tsx6
4 files changed, 70 insertions, 53 deletions
diff --git a/packages/ui/src/components/list.tsx b/packages/ui/src/components/list.tsx
index b94405c81..60161f6dc 100644
--- a/packages/ui/src/components/list.tsx
+++ b/packages/ui/src/components/list.tsx
@@ -175,12 +175,13 @@ export function List<T>(props: ListProps<T> & { ref?: (ref: ListRef) => void })
fallback={
<div data-slot="list-empty-state">
<div data-slot="list-message">
- {props.emptyMessage ?? "No results"} for <span data-slot="list-filter">&quot;{filter()}&quot;</span>
+ {props.emptyMessage ?? (grouped.loading ? "Loading" : "No results")} for{" "}
+ <span data-slot="list-filter">&quot;{filter()}&quot;</span>
</div>
</div>
}
>
- <For each={grouped()}>
+ <For each={grouped.latest}>
{(group) => (
<div data-slot="list-group">
<Show when={group.category}>
diff --git a/packages/ui/src/components/markdown.tsx b/packages/ui/src/components/markdown.tsx
index 7615d1737..6e40b700a 100644
--- a/packages/ui/src/components/markdown.tsx
+++ b/packages/ui/src/components/markdown.tsx
@@ -15,6 +15,7 @@ export function Markdown(
async (markdown) => {
return marked.parse(markdown)
},
+ { initialValue: "" },
)
return (
<div
@@ -23,7 +24,7 @@ export function Markdown(
...(local.classList ?? {}),
[local.class ?? ""]: !!local.class,
}}
- innerHTML={html()}
+ innerHTML={html.latest}
{...others}
/>
)
diff --git a/packages/ui/src/context/dialog.tsx b/packages/ui/src/context/dialog.tsx
index f85eb48df..8e770750a 100644
--- a/packages/ui/src/context/dialog.tsx
+++ b/packages/ui/src/context/dialog.tsx
@@ -1,11 +1,11 @@
import {
createContext,
+ createRoot,
createSignal,
getOwner,
- Owner,
- ParentProps,
+ type Owner,
+ type ParentProps,
runWithOwner,
- Show,
useContext,
type JSX,
} from "solid-js"
@@ -13,58 +13,66 @@ import { Dialog as Kobalte } from "@kobalte/core/dialog"
type DialogElement = () => JSX.Element
+type Active = {
+ id: string
+ node: JSX.Element
+ dispose: () => void
+ owner: Owner
+ onClose?: () => void
+}
+
const Context = createContext<ReturnType<typeof init>>()
function init() {
- const [active, setActive] = createSignal<
- | {
- id: string
- element: DialogElement
- onClose?: () => void
- owner: Owner
- }
- | undefined
- >()
+ const [active, setActive] = createSignal<Active | undefined>()
+
+ const close = () => {
+ const current = active()
+ if (!current) return
+ current.onClose?.()
+ current.dispose()
+ setActive(undefined)
+ }
+
+ const show = (element: DialogElement, owner: Owner, onClose?: () => void) => {
+ close()
- const result = {
+ const id = Math.random().toString(36).slice(2)
+ let dispose: (() => void) | undefined
+
+ const node = runWithOwner(owner, () =>
+ createRoot((d) => {
+ dispose = d
+ return (
+ <Kobalte
+ modal
+ open={true}
+ onOpenChange={(open) => {
+ if (open) return
+ close()
+ }}
+ >
+ <Kobalte.Portal>
+ <Kobalte.Overlay data-component="dialog-overlay" />
+ {element()}
+ </Kobalte.Portal>
+ </Kobalte>
+ )
+ }),
+ )
+
+ if (!dispose) return
+
+ setActive({ id, node, dispose, owner, onClose })
+ }
+
+ return {
get active() {
return active()
},
- close() {
- active()?.onClose?.()
- setActive(undefined)
- },
- show(element: DialogElement, owner: Owner, onClose?: () => void) {
- active()?.onClose?.()
- const id = Math.random().toString(36).slice(2)
- setActive({
- id,
- element: () =>
- runWithOwner(owner, () => (
- <Show when={active()?.id === id}>
- <Kobalte
- modal
- open={true}
- onOpenChange={(open) => {
- if (!open) {
- result.close()
- }
- }}
- >
- <Kobalte.Portal>
- <Kobalte.Overlay data-component="dialog-overlay" />
- {element()}
- </Kobalte.Portal>
- </Kobalte>
- </Show>
- )),
- onClose,
- owner,
- })
- },
+ close,
+ show,
}
-
- return result
}
export function DialogProvider(props: ParentProps) {
@@ -72,7 +80,7 @@ export function DialogProvider(props: ParentProps) {
return (
<Context.Provider value={ctx}>
{props.children}
- <div data-component="dialog-stack">{ctx.active?.element?.()}</div>
+ <div data-component="dialog-stack">{ctx.active?.node}</div>
</Context.Provider>
)
}
@@ -80,18 +88,21 @@ export function DialogProvider(props: ParentProps) {
export function useDialog() {
const ctx = useContext(Context)
const owner = getOwner()
+
if (!owner) {
throw new Error("useDialog must be used within a DialogProvider")
}
if (!ctx) {
throw new Error("useDialog must be used within a DialogProvider")
}
+
return {
get active() {
return ctx.active
},
show(element: DialogElement, onClose?: () => void) {
- ctx.show(element, owner, onClose)
+ const base = ctx.active?.owner ?? owner
+ ctx.show(element, base, onClose)
},
close() {
ctx.close()
diff --git a/packages/ui/src/hooks/use-filtered-list.tsx b/packages/ui/src/hooks/use-filtered-list.tsx
index 416f030ef..94099d786 100644
--- a/packages/ui/src/hooks/use-filtered-list.tsx
+++ b/packages/ui/src/hooks/use-filtered-list.tsx
@@ -18,6 +18,9 @@ export interface FilteredListProps<T> {
export function useFilteredList<T>(props: FilteredListProps<T>) {
const [store, setStore] = createStore<{ filter: string }>({ filter: "" })
+ type Group = { category: string; items: [T, ...T[]] }
+ const empty: Group[] = []
+
const [grouped, { refetch }] = createResource(
() => ({
filter: store.filter,
@@ -42,11 +45,12 @@ export function useFilteredList<T>(props: FilteredListProps<T>) {
)
return result
},
+ { initialValue: empty },
)
const flat = createMemo(() => {
return pipe(
- grouped() || [],
+ grouped.latest || [],
flatMap((x) => x.items),
)
})