import { useEffect, useRef, useState } from "preact/hooks"; import { MiniEditor } from "./mini_editor.tsx"; import type { ComponentChildren, Ref } from "preact"; export function Prompt({ message, defaultValue, darkMode, callback, }: { message: string; defaultValue?: string; darkMode: boolean | undefined; callback: (value?: string) => void; }) { const [text, setText] = useState(defaultValue || ""); const returnEl = ( { callback(); }} >
{ callback(text); return true; }} onEscape={() => { callback(); }} onChange={(text) => { setText(text); }} editable={true} />
); return returnEl; } export function Confirm({ message, callback, }: { message: string; callback: (value: boolean) => void; }) { const okButtonRef = useRef(null); setTimeout(() => { okButtonRef.current?.focus(); }); const returnEl = ( { callback(false); }} >
); return returnEl; } export function Button({ children, primary, onActivate, buttonRef, }: { children: ComponentChildren; primary?: boolean; onActivate: () => void; buttonRef?: Ref; }) { return ( ); } export function AlwaysShownModal({ children, onCancel, }: { children: ComponentChildren; onCancel?: () => void; }) { const dialogRef = useRef(null); useEffect(() => { const dialog = dialogRef.current; if (dialog) { dialog.style.opacity = "0"; dialog.showModal(); // Workaround for Safari layout bug: CodeMirror's flex sizing inside // creates a circular height dependency on first render. // Watch for the .cm-editor to appear, then toggle a layout property // to force Safari to recalculate correctly. Dialog stays hidden // (opacity 0) until the fix has been applied to avoid visible reflow. const fixSafariLayout = () => { // Wait for Safari to paint the (wrong) layout, then force reflow requestAnimationFrame(() => { setTimeout(() => { dialog.style.display = "flex"; void dialog.offsetHeight; dialog.style.display = ""; dialog.style.opacity = ""; }); }); }; if (dialog.querySelector(".cm-editor")) { fixSafariLayout(); } else { const observer = new MutationObserver(() => { if (dialog.querySelector(".cm-editor")) { observer.disconnect(); fixSafariLayout(); } }); observer.observe(dialog, { childList: true, subtree: true }); // Fallback: reveal dialog even if no .cm-editor appears (e.g. // Confirm dialogs that don't use CodeMirror) setTimeout(() => { observer.disconnect(); dialog.style.opacity = ""; }, 500); } } }, []); return ( { e.preventDefault(); onCancel?.(); }} onKeyDown={(e) => { e.stopPropagation(); }} ref={dialogRef} > {children} ); }