import { Loader2Icon } from 'lucide-react' import * as React from 'react' import { useState } from 'react' import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from '../ui/alert-dialog' import { isolateCellEvent as isolate } from '../lib/isolate' import { Button } from '../ui/button' import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../ui/tooltip' import type { CellAction, CellActionButton, TableRowData } from '../types' type CellActionsProps = { actions: CellAction[] row: TRow isSubmitting?: boolean } function ActionButton({ action, row, isSubmitting, }: { action: CellActionButton row: TRow isSubmitting?: boolean }) { const [busy, setBusy] = useState(false) const [confirmOpen, setConfirmOpen] = useState(false) const disabled = busy || isSubmitting === true || action.isDisabled?.(row) === true const run = async (event: React.MouseEvent) => { const result = action.onClick(row, event) if (result instanceof Promise) { setBusy(true) try { await result } finally { setBusy(false) } } } const handleClick = (event: React.MouseEvent) => { isolate(event) if (disabled) return if (action.confirm) { setConfirmOpen(true) return } void run(event) } const iconOnly = !action.label let button = ( ) if (action.tooltip) { button = ( {button} {action.tooltip} ) } if (!action.confirm) return button return ( <> {button} {action.confirm.title} {action.confirm.description && ( {action.confirm.description} )} Cancel { isolate(event) setConfirmOpen(false) void run(event) }} > {action.confirm.confirmLabel ?? 'Confirm'} ) } /** * Declarative cell action buttons (spec ยง20). Right-aligned after the value, * click-isolated from selection/expansion/edit, with hidden/disabled/confirm/ * busy states. */ export function CellActions({ actions, row, isSubmitting, }: CellActionsProps) { const visible = actions.filter((action) => action.isHidden?.(row) !== true) if (visible.length === 0) return null return ( {visible.map((action) => 'render' in action ? ( {action.render(row)} ) : ( ), )} ) }