返回 presentation-ai
1 "use client";
2
3 import { useEffect } from "react";
4
5 import { Grid } from "./grid";
6 import { Toolbar } from "./toolbar";
7 import {
8 type ChartDataMode,
9 type ChartDataType,
10 type SeriesChartType,
11 } from "./types";
12 import { useChartEditor } from "./use-chart-editor";
13
14 interface ChartDataEditorProps {
15 data: ChartDataType;
16 chartType: ChartDataMode;
17 onDataChange: (data: ChartDataType) => void;
18 isComposedChart?: boolean;
19 seriesChartTypes?: Record<string, SeriesChartType>;
20 onSeriesChartTypesChange?: (types: Record<string, SeriesChartType>) => void;
21 }
22
23 export function ChartDataEditor({
24 data: initialData,
25 chartType,
26 onDataChange,
27 isComposedChart = false,
28 seriesChartTypes: initialSeriesChartTypes,
29 onSeriesChartTypesChange,
30 }: ChartDataEditorProps) {
31 const {
32 data,
33 seriesNames,
34 seriesChartTypes,
35 focusedCell,
36 setFocusedCell,
37 updateCell,
38 addRow,
39 removeRow,
40 addSeries,
41 removeSeries,
42 renameSeries,
43 updateSeriesChartType,
44 addZColumn,
45 removeZColumn,
46 hasZColumn,
47 fields,
48 schema,
49 labelKey,
50 } = useChartEditor(initialData, chartType, initialSeriesChartTypes);
51
52 // Auto-save on data change (non-blocking)
53 useEffect(() => {
54 onDataChange(data);
55 }, [data, onDataChange]);
56
57 // Auto-save on series chart types change
58 useEffect(() => {
59 if (isComposedChart && onSeriesChartTypesChange) {
60 onSeriesChartTypesChange(seriesChartTypes);
61 }
62 }, [seriesChartTypes, isComposedChart, onSeriesChartTypesChange]);
63
64 const handleFocusCell = (row: number, col: number) => {
65 setFocusedCell({ row, col });
66 };
67
68 return (
69 <div className="flex flex-col gap-3">
70 <Toolbar
71 schema={schema}
72 rowCount={Array.isArray(data) ? data.length : 0}
73 seriesCount={seriesNames.length}
74 hasZColumn={hasZColumn}
75 onAddRow={addRow}
76 onAddSeries={addSeries}
77 onAddZColumn={addZColumn}
78 onRemoveZColumn={removeZColumn}
79 />
80
81 <Grid
82 data={data}
83 fields={fields}
84 schema={schema}
85 seriesNames={seriesNames}
86 focusedCell={focusedCell}
87 onUpdateCell={updateCell}
88 onRemoveRow={removeRow}
89 onRenameSeries={renameSeries}
90 onRemoveSeries={removeSeries}
91 onAddRow={addRow}
92 onFocusCell={handleFocusCell}
93 setFocusedCell={setFocusedCell}
94 seriesChartTypes={seriesChartTypes}
95 onSeriesChartTypeChange={updateSeriesChartType}
96 isComposedChart={isComposedChart}
97 labelKey={labelKey}
98 />
99
100 {Array.isArray(data) && data.length === 0 && (
101 <div className="flex flex-col items-center justify-center py-12 text-muted-foreground">
102 <p className="text-sm">No data points yet</p>
103 <p className="mt-1 text-xs">
104 Click{" "}
105 <kbd className="rounded bg-muted px-1.5 py-0.5 font-mono text-[10px]">
106 Add Row
107 </kbd>{" "}
108 or press{" "}
109 <kbd className="rounded bg-muted px-1.5 py-0.5 font-mono text-[10px]">
110 Enter
111 </kbd>{" "}
112 to get started
113 </p>
114 </div>
115 )}
116 </div>
117 );
118 }
119
120 export * from "./types";
121
121 lines Plain Text