|
|
@@ -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()
|