SnowLuma v2.4.2 source snapshot
Dev Build / cleanup (push) Waiting to run
Dev Build / typecheck (push) Waiting to run
Publish MCP to npm / Build, test, and publish MCP (push) Waiting to run
Publish SDK to npm / Build, test, and publish SDK (push) Waiting to run
Sync action catalog to docs / sync (push) Waiting to run
Publish UI to npm / Build and publish UI (push) Waiting to run
Build and Release / preflight (push) Waiting to run

This commit is contained in:
TanTan committed 2026-11-13 09:02:00 +08:00
commit fa9c73363d
1367 files changed
+355735

No files matched your search

@@ -0,0 +1,123 @@
import { useRef, useState, type ReactNode } from 'react';
import { Modal } from '@/components/interior/modal';
import { Button } from '@/components/ui/button';
import {
actionErrorMessage,
useActionFeedback,
type ActionFeedbackOptions,
} from '@/contexts/ActionFeedbackContext';
interface ConfirmDialogProps {
open: boolean;
onOpenChange: (open: boolean) => void;
title: string;
description?: ReactNode;
confirmText?: string;
cancelText?: string;
destructive?: boolean;
content?: ReactNode;
confirmDisabled?: boolean;
activity?: ActionFeedbackOptions<void>;
onConfirm: () => void | Promise<void>;
}
export function ConfirmDialog({
open,
onOpenChange,
title,
description,
confirmText = '确认',
cancelText = '取消',
destructive = false,
content,
confirmDisabled = false,
activity,
onConfirm,
}: ConfirmDialogProps) {
const [busy, setBusy] = useState(false);
const [error, setError] = useState<string | null>(null);
const { runAction } = useActionFeedback();
const cancelRef = useRef<HTMLButtonElement>(null);
const handleConfirm = async () => {
setBusy(true);
setError(null);
try {
if (!activity) {
await onConfirm();
} else {
await runAction(activity, onConfirm);
}
onOpenChange(false);
} catch (caught) {
const message = actionErrorMessage(caught);
setError(message);
console.error('confirm action failed', caught);
} finally {
setBusy(false);
}
};
const handleOpenChange = (nextOpen: boolean) => {
if (busy && !nextOpen) {
return;
}
if (!nextOpen) {
setError(null);
}
onOpenChange(nextOpen);
};
return (
<Modal
open={open}
onClose={() => handleOpenChange(false)}
title={title}
description={description}
showClose={false}
closeOnBackdrop={!busy}
closeOnEscape={!busy}
initialFocusRef={cancelRef}
maxWidth={512}
footer={
<>
<Button
ref={cancelRef}
type="button"
variant="outline"
disabled={busy}
onClick={() => handleOpenChange(false)}
>
{cancelText}
</Button>
<Button
type="button"
variant={destructive ? 'destructive' : 'default'}
onClick={() => {
void handleConfirm();
}}
disabled={busy || confirmDisabled}
>
{busy ? '处理中…' : confirmText}
</Button>
</>
}
>
<div className="flex flex-col gap-4">
{error && (
<div
role="alert"
className="rounded-lg bg-destructive/10 px-3 py-2 text-sm text-destructive"
>
{error}
</div>
)}
{content}
</div>
</Modal>
);
}