返回 presentation-ai
1 import { Trash2 } from "lucide-react";
2 import type React from "react";
3
4 import { cn } from "@/lib/utils";
5 import { GridCell } from "./grid-cell";
6 import { type ChartDataField, type ChartDataRow } from "./schemas";
7
8 interface GridRowProps {
9 row: ChartDataRow;
10 fields: ChartDataField[];
11 rowIndex: number;
12 focusedCol: number | null;
13 canDelete: boolean;
14 onUpdateCell: (field: string, value: string) => void;
15 onRemoveRow: () => void;
16 onKeyDown: (e: React.KeyboardEvent<HTMLInputElement>, col: number) => void;
17 onFocus: (col: number) => void;
18 registerCell: (col: number, el: HTMLInputElement | null) => void;
19 }
20
21 export function GridRow({
22 row,
23 fields,
24 rowIndex,
25 focusedCol,
26 canDelete,
27 onUpdateCell,
28 onRemoveRow,
29 onKeyDown,
30 onFocus,
31 registerCell,
32 }: GridRowProps) {
33 return (
34 <tr
35 className={cn(
36 "border-b border-border transition-colors",
37 focusedCol !== null && "bg-primary/5",
38 rowIndex % 2 === 1 && focusedCol === null && "bg-muted/30",
39 )}
40 >
41 <td className="h-8 w-10 border-r border-border bg-muted/40 text-center font-mono text-xs text-muted-foreground select-none">
42 {rowIndex + 1}
43 </td>
44
45 {fields.map((field, colIndex) => (
46 <td
47 key={field.key}
48 className="border-r border-border p-0 last:border-r-0"
49 >
50 <GridCell
51 value={row[field.key] ?? (field.type === "number" ? 0 : "")}
52 type={field.type}
53 rowIndex={rowIndex}
54 colIndex={colIndex}
55 placeholder={
56 field.placeholder ?? (field.type === "number" ? "0" : field.label)
57 }
58 onUpdate={(val) => onUpdateCell(field.key, val)}
59 onKeyDown={(e) => onKeyDown(e, colIndex)}
60 onFocus={() => onFocus(colIndex)}
61 registerRef={(el) => registerCell(colIndex, el)}
62 isFocused={focusedCol === colIndex}
63 />
64 </td>
65 ))}
66
67 <td className="h-8 w-10 border-l border-border bg-muted/20 text-center">
68 <button
69 onClick={onRemoveRow}
70 disabled={!canDelete}
71 className={cn(
72 "mx-auto flex h-6 w-6 items-center justify-center rounded",
73 "text-muted-foreground transition-colors hover:bg-destructive/10 hover:text-destructive",
74 !canDelete && "cursor-not-allowed opacity-30",
75 )}
76 type="button"
77 >
78 <Trash2 className="size-3.5" />
79 <span className="sr-only">Remove row</span>
80 </button>
81 </td>
82 </tr>
83 );
84 }
85
85 lines Plain Text