SPB Git

spb/findata

Public
2.3 KB · 62 lines tsx
1"use client";2import { useEffect, useRef, type ReactNode } from "react";3import clsx from "clsx";45interface Props {6  open: boolean;7  title: string;8  children?: ReactNode;9  confirmLabel?: string;10  danger?: boolean;11  busy?: boolean;12  onConfirm: () => void;13  onCancel: () => void;14}1516export function ConfirmDialog({ open, title, children, confirmLabel = "Confirm", danger, busy, onConfirm, onCancel }: Props) {17  const ref = useRef<HTMLDialogElement>(null);18  useEffect(() => {19    const d = ref.current;20    if (!d) return;21    if (open && !d.open) d.showModal();22    if (!open && d.open) d.close();23  }, [open]);24  return (25    <dialog ref={ref} onClose={onCancel} onCancel={onCancel} className="m-auto w-[min(92vw,28rem)] rounded-lg border border-border bg-surface-1 p-0 text-ink-1 shadow-xl">26      <div className="p-4">27        <h2 className="text-base font-semibold">{title}</h2>28        {children && <div className="mt-2 text-sm text-ink-2">{children}</div>}29      </div>30      <div className="flex justify-end gap-2 border-t border-hairline px-4 py-3">31        <button className="btn" onClick={onCancel} disabled={busy}>32          Cancel33        </button>34        <button className={clsx("btn", danger ? "btn-danger" : "btn-primary")} onClick={onConfirm} disabled={busy}>35          {busy ? "Working…" : confirmLabel}36        </button>37      </div>38    </dialog>39  );40}4142export function Modal({ open, title, children, onClose, wide }: { open: boolean; title: string; children: ReactNode; onClose: () => void; wide?: boolean }) {43  const ref = useRef<HTMLDialogElement>(null);44  useEffect(() => {45    const d = ref.current;46    if (!d) return;47    if (open && !d.open) d.showModal();48    if (!open && d.open) d.close();49  }, [open]);50  return (51    <dialog ref={ref} onClose={onClose} onCancel={onClose} className={clsx("m-auto rounded-lg border border-border bg-surface-1 p-0 text-ink-1 shadow-xl", wide ? "w-[min(96vw,56rem)]" : "w-[min(92vw,32rem)]")}>52      <div className="flex items-center justify-between border-b border-hairline px-4 py-3">53        <h2 className="text-base font-semibold">{title}</h2>54        <button className="btn btn-ghost btn-sm" onClick={onClose} aria-label="Close">55          ✕56        </button>57      </div>58      <div className="max-h-[80dvh] overflow-y-auto p-4">{children}</div>59    </dialog>60  );61}62
Files · 17d97adc36cc25b48b7afafe2f7c8bc86b240e41
Menu

Theme