/** * @fileoverview Version Actions component * * Action buttons for version operations: restore, compare, download, delete. * Includes confirmation dialogs for destructive actions. * Includes focus trap for accessibility compliance. * * @module @writenex/astro/client/components/VersionHistory/VersionActions */ import { AlertTriangle, Download, GitCompare, Loader2, RotateCcw, Trash2, X, } from "lucide-react"; import { useEffect, useRef, useState } from "react"; import type { VersionEntry } from "../../../types"; import { useFocusTrap } from "../../hooks/useFocusTrap"; import "./VersionActions.css"; /** * Props for the VersionActions component */ interface VersionActionsProps { /** The selected version */ version: VersionEntry; /** Callback to restore the version */ onRestore: () => void; /** Callback to compare the version */ onCompare: () => void; /** Callback to download the version */ onDownload: () => void; /** Callback to delete the version */ onDelete: () => void; /** Current loading action */ loading: string | null; } /** * Props for ConfirmModal component */ interface ConfirmModalProps { title: string; message: string; confirmLabel: string; confirmVariant?: "danger" | "primary"; onConfirm: () => void; onCancel: () => void; loading?: boolean; } /** * Confirmation modal component with focus trap */ function ConfirmModal({ title, message, confirmLabel, confirmVariant = "danger", onConfirm, onCancel, loading, }: ConfirmModalProps): React.ReactElement { const triggerRef = useRef(null); const cancelButtonRef = useRef(null); // Store the trigger element when modal mounts useEffect(() => { triggerRef.current = document.activeElement as HTMLElement; }, []); // Focus trap for accessibility const { containerRef } = useFocusTrap({ enabled: true, onEscape: loading ? undefined : onCancel, returnFocusTo: triggerRef.current, }); // Focus cancel button when modal opens useEffect(() => { setTimeout(() => { cancelButtonRef.current?.focus(); }, 50); }, []); const handleOverlayClick = (e: React.MouseEvent) => { if (e.target === e.currentTarget && !loading) onCancel(); }; return (

{title}

{message}

); } /** * Version Actions component * * @component * @example * ```tsx * * ``` */ export function VersionActions({ version, onRestore, onCompare, onDownload, onDelete, loading, }: VersionActionsProps): React.ReactElement { const [showRestoreConfirm, setShowRestoreConfirm] = useState(false); const [showDeleteConfirm, setShowDeleteConfirm] = useState(false); const handleRestoreClick = () => { setShowRestoreConfirm(true); }; const handleRestoreConfirm = () => { onRestore(); setShowRestoreConfirm(false); }; const handleDeleteClick = () => { setShowDeleteConfirm(true); }; const handleDeleteConfirm = () => { onDelete(); setShowDeleteConfirm(false); }; const isLoading = loading !== null; return ( <>
{/* Restore Confirmation Modal */} {showRestoreConfirm && ( setShowRestoreConfirm(false)} loading={loading === "restore"} /> )} {/* Delete Confirmation Modal */} {showDeleteConfirm && ( setShowDeleteConfirm(false)} loading={loading === "delete"} /> )} ); }