1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
|
import {
createContext,
createSignal,
getOwner,
Owner,
ParentProps,
runWithOwner,
Show,
useContext,
type JSX,
} from "solid-js"
import { Dialog as Kobalte } from "@kobalte/core/dialog"
type DialogElement = () => JSX.Element
const Context = createContext<ReturnType<typeof init>>()
function init() {
const [active, setActive] = createSignal<
| {
id: string
element: DialogElement
onClose?: () => void
owner: Owner
}
| undefined
>()
const result = {
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,
})
},
}
return result
}
export function DialogProvider(props: ParentProps) {
const ctx = init()
return (
<Context.Provider value={ctx}>
{props.children}
<div data-component="dialog-stack">{ctx.active?.element?.()}</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 active() {
return ctx.active
},
show(element: DialogElement, onClose?: () => void) {
ctx.show(element, owner, onClose)
},
close() {
ctx.close()
},
}
}
|