Files
IdeA/frontend/src/features/plugins/PluginConfirmDialog.tsx
Blomios ac726d075e feat(frontend): système de plugins — runtime, menus, layouts custom (#43)
Lots F1-F4 : runtime de chargement/registre plugin, extension des menus
existants, panneau de gestion des plugins, types de layout custom
(sélecteur, fallback, cellule dédiée) branchés sur le port plugin.
Suite npm typecheck/test verte (947/947).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-22 07:37:11 +02:00

77 lines
2.1 KiB
TypeScript

/**
* A small modal confirmation, local to the plugins feature (ticket #43, F2).
* Mirrors `features/devices/ConfirmDialog` (not shared — that dialog is itself
* feature-local by design, see its header comment); duplicated rather than
* cross-imported to keep each feature's public surface to its own `index.ts`.
*/
import { useEffect, useRef } from "react";
import { Button, zIndex } from "@/shared";
interface PluginConfirmDialogProps {
title: string;
body: string;
confirmLabel: string;
danger?: boolean;
busy?: boolean;
onConfirm: () => void | Promise<void>;
onCancel: () => void;
}
export function PluginConfirmDialog({
title,
body,
confirmLabel,
danger = false,
busy = false,
onConfirm,
onCancel,
}: PluginConfirmDialogProps) {
const cancelRef = useRef<HTMLButtonElement>(null);
useEffect(() => {
cancelRef.current?.focus();
}, []);
useEffect(() => {
function onKeyDown(e: KeyboardEvent) {
if (e.key === "Escape") onCancel();
}
window.addEventListener("keydown", onKeyDown);
return () => window.removeEventListener("keydown", onKeyDown);
}, [onCancel]);
return (
<div
className="fixed inset-0 flex items-center justify-center bg-black/50 p-4"
style={{ zIndex: zIndex.floatingWindow }}
onClick={onCancel}
>
<div
role="dialog"
aria-modal="true"
aria-label={title}
onClick={(e) => e.stopPropagation()}
className="flex w-full max-w-md flex-col gap-3 rounded-lg border border-border bg-raised p-4 shadow-xl"
>
<h3 className="text-sm font-semibold text-content">{title}</h3>
<p className="whitespace-pre-line text-sm text-muted">{body}</p>
<div className="flex justify-end gap-2">
<Button ref={cancelRef} size="sm" variant="ghost" onClick={onCancel}>
Annuler
</Button>
<Button
size="sm"
variant={danger ? "danger" : "primary"}
loading={busy}
onClick={() => void onConfirm()}
>
{confirmLabel}
</Button>
</div>
</div>
</div>
);
}