import { h } from 'preact' import { useEffect, useRef, useState } from 'preact/hooks' type Message = string type Alert = { type: 'alert' | 'prompt' | 'confirm', message: Message, resolve: (data: string | boolean | null) => void } export type DialogManager = ReturnType export function createDialogManager() { const [alerts, setAlerts] = useState({} as Record) const id = crypto.randomUUID() function add(alert: Alert) { setAlerts({ ...alerts, alert }) } function remove() { delete alerts[id] setAlerts({ ...alerts }) } return { useAlerts() { return alerts }, async alert(message: Message) { return await new Promise((resolve) => add({ message, type: 'alert', resolve: () => { resolve() remove() } })) }, async prompt(message: Message) { return await new Promise((resolve) => add({ message, type: 'prompt', resolve: (data) => { resolve(data?.toString() ?? null) remove() } })) }, async confirm(message: Message) { return await new Promise((resolve) => add({ message, type: 'confirm', resolve: (data) => { resolve(!!data) remove() } })) } } } export function Dialogs(params: { manager: ReturnType }) { const alerts = params.manager.useAlerts() let currentAlert = Object.values(alerts)[0] if (!currentAlert) return const [value, setValue] = useState(null as Parameters[0]) let cancelled = false const dialog = useRef(null as any as HTMLDialogElement) useEffect(() => { if (!dialog.current) return if (!dialog.current.open) dialog.current.showModal() const onClose = () => currentAlert.resolve(null) dialog.current.addEventListener('close', onClose) return dialog.current.removeEventListener('close', onClose) }) return
{ event.preventDefault() currentAlert.resolve(cancelled ? null : currentAlert.type === 'confirm' ? true : value) }}>
{currentAlert.message}
{currentAlert.type === 'prompt' && setValue(event.currentTarget.value)} />}
{/* This is here to capture, return key */} {currentAlert.type !== 'alert' && }
}