返回 DeepSeek-Reasonix
InlineConfirmButton.tsx
根目录 / desktop / frontend / src / components / InlineConfirmButton.tsx
1 import { useEffect, useState } from "react";
2 import type { ReactNode } from "react";
3
4 // Compact row and menu actions confirm in place instead of opening a global
5 // modal. First click arms the action, second click confirms it, and the adjacent
6 // Cancel button or any disabled state returns the button to normal.
7 export function InlineConfirmButton({
8 label,
9 confirmLabel,
10 cancelLabel,
11 disabled = false,
12 danger = false,
13 primary = false,
14 buttonRole,
15 onConfirm,
16 }: {
17 label: ReactNode;
18 confirmLabel: ReactNode;
19 cancelLabel: ReactNode;
20 disabled?: boolean;
21 danger?: boolean;
22 primary?: boolean;
23 buttonRole?: "menuitem";
24 onConfirm: () => void | Promise<void>;
25 }) {
26 const [armed, setArmed] = useState(false);
27
28 useEffect(() => {
29 if (disabled) setArmed(false);
30 }, [disabled]);
31
32 const run = async () => {
33 if (!armed) {
34 setArmed(true);
35 return;
36 }
37 setArmed(false);
38 await onConfirm();
39 };
40
41 return (
42 <span className="inline-confirm" role={buttonRole ? "none" : undefined}>
43 <button
44 className={`btn btn--small${armed && danger ? " btn--danger" : primary ? " btn--primary" : ""}`}
45 disabled={disabled}
46 type="button"
47 role={buttonRole}
48 onClick={run}
49 >
50 {armed ? confirmLabel : label}
51 </button>
52 {armed && (
53 <button className="btn btn--small" disabled={disabled} type="button" role={buttonRole} onClick={() => setArmed(false)}>
54 {cancelLabel}
55 </button>
56 )}
57 </span>
58 );
59 }
60
60 lines Plain Text