mirror of
https://gitea.toothfairyai.com/ToothFairyAI/tf_code.git
synced 2026-04-10 18:58:48 +00:00
128 lines
2.7 KiB
TypeScript
128 lines
2.7 KiB
TypeScript
import {
|
|
createContext,
|
|
createEffect,
|
|
createMemo,
|
|
createSignal,
|
|
For,
|
|
getOwner,
|
|
Owner,
|
|
ParentProps,
|
|
runWithOwner,
|
|
Show,
|
|
useContext,
|
|
type JSX,
|
|
} from "solid-js"
|
|
import { Dialog as Kobalte } from "@kobalte/core/dialog"
|
|
import { iife } from "@opencode-ai/util/iife"
|
|
|
|
type DialogElement = () => JSX.Element
|
|
|
|
const Context = createContext<ReturnType<typeof init>>()
|
|
|
|
function init() {
|
|
const [store, setStore] = createSignal<
|
|
{
|
|
id: string
|
|
element: DialogElement
|
|
onClose?: () => void
|
|
owner: Owner
|
|
}[]
|
|
>([])
|
|
|
|
const result = {
|
|
get stack() {
|
|
return store()
|
|
},
|
|
pop() {
|
|
const current = store().at(-1)
|
|
if (!current) return
|
|
current?.onClose?.()
|
|
setStore((stack) => {
|
|
stack.pop()
|
|
return [...stack]
|
|
})
|
|
},
|
|
replace(element: DialogElement, owner: Owner, onClose?: () => void) {
|
|
for (const item of store()) {
|
|
item.onClose?.()
|
|
}
|
|
const id = Math.random().toString(36)
|
|
setStore([
|
|
{
|
|
id,
|
|
element: () =>
|
|
runWithOwner(owner, () => (
|
|
<Show when={result.stack.at(-1)?.id === id}>
|
|
<Kobalte
|
|
modal
|
|
defaultOpen
|
|
onOpenChange={(open) => {
|
|
if (!open) {
|
|
onClose?.()
|
|
result.pop()
|
|
}
|
|
}}
|
|
>
|
|
<Kobalte.Portal>
|
|
<Kobalte.Overlay data-component="dialog-overlay" />
|
|
{element()}
|
|
</Kobalte.Portal>
|
|
</Kobalte>
|
|
</Show>
|
|
)),
|
|
onClose,
|
|
owner,
|
|
},
|
|
])
|
|
},
|
|
clear() {
|
|
for (const item of store()) {
|
|
item.onClose?.()
|
|
}
|
|
setStore([])
|
|
},
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
export function DialogProvider(props: ParentProps) {
|
|
const ctx = init()
|
|
createEffect(() => {
|
|
console.log("store", ctx.stack.length)
|
|
})
|
|
return (
|
|
<Context.Provider value={ctx}>
|
|
{props.children}
|
|
<div data-component="dialog-stack">
|
|
<For each={ctx.stack}>{(item) => <>{item.element()}</>}</For>
|
|
</div>
|
|
</Context.Provider>
|
|
)
|
|
}
|
|
|
|
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 stack() {
|
|
return ctx.stack
|
|
},
|
|
replace(element: DialogElement, onClose?: () => void) {
|
|
ctx.replace(element, owner, onClose)
|
|
},
|
|
pop() {
|
|
ctx.pop()
|
|
},
|
|
clear() {
|
|
ctx.clear()
|
|
},
|
|
}
|
|
}
|