@agions/taroviz 1.1.1 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/README.md +324 -53
  2. package/dist/cjs/index.js +1 -0
  3. package/dist/esm/index.js +82979 -0
  4. package/package.json +160 -30
  5. package/src/__tests__/integration.test.tsx +168 -0
  6. package/src/adapters/__tests__/index.test.ts +91 -0
  7. package/src/adapters/h5/__tests__/index.test.ts +156 -0
  8. package/src/adapters/h5/index.ts +301 -0
  9. package/src/adapters/harmony/index.ts +274 -0
  10. package/src/adapters/index.ts +166 -0
  11. package/src/adapters/swan/index.ts +274 -0
  12. package/src/adapters/tt/index.ts +274 -0
  13. package/src/adapters/types.ts +162 -0
  14. package/src/adapters/weapp/index.ts +237 -0
  15. package/src/charts/bar/__tests__/index.test.tsx +113 -0
  16. package/src/charts/bar/index.tsx +18 -0
  17. package/src/charts/common/BaseChartWrapper.tsx +136 -0
  18. package/src/charts/funnel/index.tsx +18 -0
  19. package/src/charts/gauge/index.tsx +18 -0
  20. package/src/charts/heatmap/index.tsx +18 -0
  21. package/src/charts/index.ts +21 -0
  22. package/src/charts/line/__tests__/index.test.tsx +107 -0
  23. package/src/charts/line/index.tsx +18 -0
  24. package/src/charts/pie/__tests__/index.test.tsx +112 -0
  25. package/src/charts/pie/index.tsx +19 -0
  26. package/src/charts/radar/index.tsx +18 -0
  27. package/src/charts/scatter/index.tsx +18 -0
  28. package/src/charts/types.ts +619 -0
  29. package/src/charts/utils.ts +56 -0
  30. package/src/core/__tests__/platform.test.ts +48 -0
  31. package/src/core/animation/AnimationManager.ts +391 -0
  32. package/src/core/animation/index.ts +20 -0
  33. package/src/core/animation/types.ts +248 -0
  34. package/src/core/components/BaseChart.tsx +1313 -0
  35. package/src/core/components/ErrorBoundary.tsx +458 -0
  36. package/src/core/echarts.ts +58 -0
  37. package/src/core/index.ts +22 -0
  38. package/src/core/types/chart.ts +66 -0
  39. package/src/core/types/common.ts +224 -0
  40. package/src/core/types/index.ts +281 -0
  41. package/src/core/types/platform.ts +325 -0
  42. package/src/core/utils/__tests__/common.test.ts +52 -0
  43. package/src/core/utils/__tests__/environment.test.ts +94 -0
  44. package/src/core/utils/__tests__/i18n.test.ts +247 -0
  45. package/src/core/utils/__tests__/index.test.ts +219 -0
  46. package/src/core/utils/__tests__/uuid.test.ts +78 -0
  47. package/src/core/utils/chartInstances.ts +69 -0
  48. package/src/core/utils/codeGenerator/CodeGenerator.ts +655 -0
  49. package/src/core/utils/codeGenerator/index.ts +13 -0
  50. package/src/core/utils/codeGenerator/types.ts +198 -0
  51. package/src/core/utils/common.ts +58 -0
  52. package/src/core/utils/configGenerator/ConfigGenerator.ts +583 -0
  53. package/src/core/utils/configGenerator/index.ts +13 -0
  54. package/src/core/utils/configGenerator/types.ts +445 -0
  55. package/src/core/utils/debug/DebugPanel.tsx +637 -0
  56. package/src/core/utils/debug/debugger.ts +322 -0
  57. package/src/core/utils/debug/index.ts +21 -0
  58. package/src/core/utils/debug/types.ts +142 -0
  59. package/src/core/utils/i18n.ts +452 -0
  60. package/src/core/utils/index.ts +162 -0
  61. package/src/core/utils/performance/PerformanceAnalyzer.ts +586 -0
  62. package/src/core/utils/performance/index.ts +13 -0
  63. package/src/core/utils/performance/types.ts +180 -0
  64. package/src/core/utils/uuid.ts +30 -0
  65. package/src/editor/ThemeEditor.tsx +449 -0
  66. package/src/editor/index.ts +10 -0
  67. package/src/hooks/__tests__/index.test.tsx +333 -0
  68. package/src/hooks/index.ts +594 -0
  69. package/src/index.ts +75 -0
  70. package/src/main.tsx +247 -0
  71. package/src/react-dom.d.ts +7 -0
  72. package/src/themes/__tests__/index.test.ts +91 -0
  73. package/src/themes/index.ts +860 -0
  74. package/dist/389.index.esm.js +0 -1
  75. package/dist/389.index.js +0 -1
  76. package/dist/633.index.esm.js +0 -1
  77. package/dist/633.index.js +0 -1
  78. package/dist/967.index.esm.js +0 -1
  79. package/dist/967.index.js +0 -1
  80. package/dist/index.esm.js +0 -1
  81. package/dist/index.js +0 -1
@@ -0,0 +1,180 @@
1
+ /**
2
+ * TaroViz 性能分析工具类型定义
3
+ */
4
+
5
+ /**
6
+ * 性能指标类型
7
+ */
8
+ export type PerformanceMetricType =
9
+ | 'initTime'
10
+ | 'renderTime'
11
+ | 'updateTime'
12
+ | 'dataSize'
13
+ | 'frameRate'
14
+ | 'memoryUsage'
15
+ | 'cpuUsage';
16
+
17
+ /**
18
+ * 性能指标数据
19
+ */
20
+ export interface PerformanceMetric {
21
+ /**
22
+ * 指标类型
23
+ */
24
+ type: PerformanceMetricType;
25
+
26
+ /**
27
+ * 指标值
28
+ */
29
+ value: number;
30
+
31
+ /**
32
+ * 指标单位
33
+ */
34
+ unit: string;
35
+
36
+ /**
37
+ * 采集时间
38
+ */
39
+ timestamp: number;
40
+
41
+ /**
42
+ * 指标描述
43
+ */
44
+ description?: string;
45
+ }
46
+
47
+ /**
48
+ * 性能分析配置
49
+ */
50
+ export interface PerformanceAnalysisConfig {
51
+ /**
52
+ * 是否启用性能监控
53
+ */
54
+ enabled?: boolean;
55
+
56
+ /**
57
+ * 监控的指标列表
58
+ */
59
+ metrics?: PerformanceMetricType[];
60
+
61
+ /**
62
+ * 采样间隔(毫秒)
63
+ */
64
+ sampleInterval?: number;
65
+
66
+ /**
67
+ * 最大采样数据点数量
68
+ */
69
+ maxSamples?: number;
70
+
71
+ /**
72
+ * 是否启用实时监控
73
+ */
74
+ realTime?: boolean;
75
+
76
+ /**
77
+ * 是否自动开始监控
78
+ */
79
+ autoStart?: boolean;
80
+ }
81
+
82
+ /**
83
+ * 性能分析结果
84
+ */
85
+ export interface PerformanceAnalysisResult {
86
+ /**
87
+ * 平均指标值
88
+ */
89
+ averages: Record<PerformanceMetricType, number>;
90
+
91
+ /**
92
+ * 最大指标值
93
+ */
94
+ maxValues: Record<PerformanceMetricType, number>;
95
+
96
+ /**
97
+ * 最小指标值
98
+ */
99
+ minValues: Record<PerformanceMetricType, number>;
100
+
101
+ /**
102
+ * 指标趋势数据
103
+ */
104
+ trends: Record<PerformanceMetricType, PerformanceMetric[]>;
105
+
106
+ /**
107
+ * 性能评分(0-100)
108
+ */
109
+ score: number;
110
+
111
+ /**
112
+ * 性能建议
113
+ */
114
+ suggestions: string[];
115
+
116
+ /**
117
+ * 采集的总数据点数量
118
+ */
119
+ totalSamples: number;
120
+
121
+ /**
122
+ * 监控持续时间(毫秒)
123
+ */
124
+ duration: number;
125
+ }
126
+
127
+ /**
128
+ * 性能事件类型
129
+ */
130
+ export enum PerformanceEventType {
131
+ /**
132
+ * 性能监控开始事件
133
+ */
134
+ MONITORING_START = 'performanceMonitoringStart',
135
+
136
+ /**
137
+ * 性能监控结束事件
138
+ */
139
+ MONITORING_END = 'performanceMonitoringEnd',
140
+
141
+ /**
142
+ * 性能指标更新事件
143
+ */
144
+ METRIC_UPDATE = 'performanceMetricUpdate',
145
+
146
+ /**
147
+ * 性能分析完成事件
148
+ */
149
+ ANALYSIS_COMPLETE = 'performanceAnalysisComplete',
150
+ }
151
+
152
+ /**
153
+ * 性能事件回调类型
154
+ */
155
+ export type PerformanceEventHandler = (event: { type: PerformanceEventType; data?: any }) => void;
156
+
157
+ /**
158
+ * 性能分析报告配置
159
+ */
160
+ export interface PerformanceReportConfig {
161
+ /**
162
+ * 报告格式
163
+ */
164
+ format?: 'json' | 'html' | 'csv';
165
+
166
+ /**
167
+ * 是否包含图表
168
+ */
169
+ includeCharts?: boolean;
170
+
171
+ /**
172
+ * 是否包含建议
173
+ */
174
+ includeSuggestions?: boolean;
175
+
176
+ /**
177
+ * 是否包含详细数据
178
+ */
179
+ includeDetailedData?: boolean;
180
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * 生成唯一标识符
3
+ * 用于生成图表ID等需要唯一标识的场景
4
+ * @returns 唯一标识符字符串
5
+ */
6
+ export function uuid(): string {
7
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
8
+ const r = (Math.random() * 16) | 0;
9
+ const v = c === 'x' ? r : (r & 0x3) | 0x8;
10
+ return v.toString(16);
11
+ });
12
+ }
13
+
14
+ /**
15
+ * 生成简短的唯一标识符
16
+ * 适用于图表ID等不需要完整UUID的场景
17
+ * @returns 简短的唯一标识符
18
+ */
19
+ export function shortId(): string {
20
+ return Math.random().toString(36).substring(2, 10);
21
+ }
22
+
23
+ /**
24
+ * 生成带有前缀的唯一标识符
25
+ * @param prefix 前缀字符串
26
+ * @returns 带前缀的唯一标识符
27
+ */
28
+ export function prefixedId(prefix: string): string {
29
+ return `${prefix}-${shortId()}`;
30
+ }
@@ -0,0 +1,449 @@
1
+ /**
2
+ * TaroViz 主题编辑器组件
3
+ * 提供可视化的主题编辑功能
4
+ */
5
+ import React, { useState, useEffect } from 'react';
6
+
7
+ import { ThemeOptions, getRegisteredThemes, registerTheme, switchTheme } from '../themes';
8
+
9
+ /**
10
+ * 主题编辑器属性
11
+ */
12
+ export interface ThemeEditorProps {
13
+ /**
14
+ * 当前选中的主题名称
15
+ */
16
+ selectedTheme?: string;
17
+
18
+ /**
19
+ * 主题变更回调函数
20
+ */
21
+ onThemeChange?: (theme: ThemeOptions) => void;
22
+
23
+ /**
24
+ * 主题保存回调函数
25
+ */
26
+ onThemeSave?: (theme: ThemeOptions) => void;
27
+
28
+ /**
29
+ * 是否禁用编辑器
30
+ */
31
+ disabled?: boolean;
32
+
33
+ /**
34
+ * 编辑器样式
35
+ */
36
+ style?: React.CSSProperties;
37
+
38
+ /**
39
+ * 编辑器类名
40
+ */
41
+ className?: string;
42
+ }
43
+
44
+ /**
45
+ * 主题编辑器组件
46
+ */
47
+ const ThemeEditor: React.FC<ThemeEditorProps> = ({
48
+ selectedTheme,
49
+ onThemeChange,
50
+ onThemeSave,
51
+ disabled = false,
52
+ style = {},
53
+ className = '',
54
+ }) => {
55
+ // 获取已注册的主题列表
56
+ const themes = getRegisteredThemes();
57
+
58
+ // 状态管理
59
+ const [currentTheme, setCurrentTheme] = useState<ThemeOptions>(themes[0] || ({} as ThemeOptions));
60
+ const [newThemeName, setNewThemeName] = useState<string>('');
61
+ const [isEditing, setIsEditing] = useState<boolean>(false);
62
+
63
+ // 主题颜色状态
64
+ const [colors, setColors] = useState<string[]>(currentTheme.colors || []);
65
+ const [backgroundColor, setBackgroundColor] = useState<string>(
66
+ currentTheme.backgroundColor || '#ffffff'
67
+ );
68
+ const [textColor, setTextColor] = useState<string>(currentTheme.textColor || '#333333');
69
+ const [darkMode, setDarkMode] = useState<boolean>(currentTheme.darkMode || false);
70
+
71
+ // 当选中主题变化时,更新当前主题
72
+ useEffect(() => {
73
+ if (selectedTheme) {
74
+ const theme = themes.find((t) => t.name === selectedTheme);
75
+ if (theme) {
76
+ setCurrentTheme(theme);
77
+ setColors(theme.colors || []);
78
+ setBackgroundColor(theme.backgroundColor || '#ffffff');
79
+ setTextColor(theme.textColor || '#333333');
80
+ setDarkMode(theme.darkMode || false);
81
+ }
82
+ }
83
+ }, [selectedTheme, themes]);
84
+
85
+ // 当当前主题变化时,更新颜色等状态
86
+ useEffect(() => {
87
+ setColors(currentTheme.colors || []);
88
+ setBackgroundColor(currentTheme.backgroundColor || '#ffffff');
89
+ setTextColor(currentTheme.textColor || '#333333');
90
+ setDarkMode(currentTheme.darkMode || false);
91
+ }, [currentTheme]);
92
+
93
+ // 处理主题选择
94
+ const handleThemeSelect = (theme: ThemeOptions) => {
95
+ setCurrentTheme(theme);
96
+ if (onThemeChange) {
97
+ onThemeChange(theme);
98
+ }
99
+ switchTheme(theme);
100
+ };
101
+
102
+ // 处理颜色变化
103
+ const handleColorChange = (index: number, color: string) => {
104
+ const newColors = [...colors];
105
+ newColors[index] = color;
106
+ setColors(newColors);
107
+ updateCurrentTheme({ colors: newColors });
108
+ };
109
+
110
+ // 处理背景色变化
111
+ const handleBackgroundColorChange = (color: string) => {
112
+ setBackgroundColor(color);
113
+ updateCurrentTheme({ backgroundColor: color });
114
+ };
115
+
116
+ // 处理文本颜色变化
117
+ const handleTextColorChange = (color: string) => {
118
+ setTextColor(color);
119
+ updateCurrentTheme({ textColor: color });
120
+ };
121
+
122
+ // 处理深色模式切换
123
+ const handleDarkModeToggle = () => {
124
+ const newDarkMode = !darkMode;
125
+ setDarkMode(newDarkMode);
126
+ updateCurrentTheme({ darkMode: newDarkMode });
127
+ };
128
+
129
+ // 更新当前主题
130
+ const updateCurrentTheme = (updates: Partial<ThemeOptions>) => {
131
+ const updatedTheme = { ...currentTheme, ...updates };
132
+ setCurrentTheme(updatedTheme);
133
+ if (onThemeChange) {
134
+ onThemeChange(updatedTheme);
135
+ }
136
+ switchTheme(updatedTheme);
137
+ };
138
+
139
+ // 保存主题
140
+ const handleSaveTheme = () => {
141
+ const themeToSave = {
142
+ ...currentTheme,
143
+ colors,
144
+ backgroundColor,
145
+ textColor,
146
+ darkMode,
147
+ };
148
+
149
+ if (isEditing && newThemeName) {
150
+ // 保存为新主题
151
+ registerTheme(newThemeName, themeToSave);
152
+ setIsEditing(false);
153
+ setNewThemeName('');
154
+ } else {
155
+ // 更新现有主题
156
+ registerTheme(currentTheme.name || 'custom', themeToSave);
157
+ }
158
+
159
+ if (onThemeSave) {
160
+ onThemeSave(themeToSave);
161
+ }
162
+ };
163
+
164
+ // 添加新颜色
165
+ const handleAddColor = () => {
166
+ setColors([...colors, '#000000']);
167
+ };
168
+
169
+ // 删除颜色
170
+ const handleRemoveColor = (index: number) => {
171
+ const newColors = colors.filter((_, i) => i !== index);
172
+ setColors(newColors);
173
+ updateCurrentTheme({ colors: newColors });
174
+ };
175
+
176
+ // 开始编辑新主题
177
+ const handleStartEdit = () => {
178
+ setIsEditing(true);
179
+ setNewThemeName('');
180
+ };
181
+
182
+ return (
183
+ <div
184
+ className={`taroviz-theme-editor ${className}`}
185
+ style={{
186
+ padding: '20px',
187
+ border: '1px solid #e0e0e0',
188
+ borderRadius: '8px',
189
+ backgroundColor: '#ffffff',
190
+ boxShadow: '0 2px 8px rgba(0, 0, 0, 0.1)',
191
+ ...style,
192
+ }}
193
+ >
194
+ <h3>主题编辑器</h3>
195
+
196
+ {/* 主题列表 */}
197
+ <div style={{ marginBottom: '20px' }}>
198
+ <h4>选择主题</h4>
199
+ <div style={{ display: 'flex', flexWrap: 'wrap', gap: '10px', marginTop: '10px' }}>
200
+ {themes.map((theme) => (
201
+ <button
202
+ key={theme.name}
203
+ onClick={() => handleThemeSelect(theme)}
204
+ disabled={disabled}
205
+ style={{
206
+ padding: '8px 16px',
207
+ border: `2px solid ${currentTheme.name === theme.name ? '#1890ff' : '#e0e0e0'}`,
208
+ borderRadius: '4px',
209
+ backgroundColor: currentTheme.name === theme.name ? '#1890ff' : '#ffffff',
210
+ color: currentTheme.name === theme.name ? '#ffffff' : '#333333',
211
+ cursor: disabled ? 'not-allowed' : 'pointer',
212
+ opacity: disabled ? 0.6 : 1,
213
+ }}
214
+ >
215
+ {theme.name}
216
+ </button>
217
+ ))}
218
+ <button
219
+ onClick={handleStartEdit}
220
+ disabled={disabled}
221
+ style={{
222
+ padding: '8px 16px',
223
+ border: '2px dashed #e0e0e0',
224
+ borderRadius: '4px',
225
+ backgroundColor: '#f5f5f5',
226
+ color: '#333333',
227
+ cursor: disabled ? 'not-allowed' : 'pointer',
228
+ opacity: disabled ? 0.6 : 1,
229
+ }}
230
+ >
231
+ + 新主题
232
+ </button>
233
+ </div>
234
+ </div>
235
+
236
+ {/* 新主题编辑 */}
237
+ {isEditing && (
238
+ <div
239
+ style={{
240
+ marginBottom: '20px',
241
+ padding: '15px',
242
+ backgroundColor: '#f9f9f9',
243
+ borderRadius: '4px',
244
+ }}
245
+ >
246
+ <h4>新建主题</h4>
247
+ <div style={{ marginBottom: '10px' }}>
248
+ <label style={{ display: 'block', marginBottom: '5px' }}>主题名称:</label>
249
+ <input
250
+ type="text"
251
+ value={newThemeName}
252
+ onChange={(e) => setNewThemeName(e.target.value)}
253
+ disabled={disabled}
254
+ style={{
255
+ padding: '8px',
256
+ border: '1px solid #e0e0e0',
257
+ borderRadius: '4px',
258
+ width: '100%',
259
+ opacity: disabled ? 0.6 : 1,
260
+ }}
261
+ placeholder="输入主题名称"
262
+ />
263
+ </div>
264
+ </div>
265
+ )}
266
+
267
+ {/* 主题颜色配置 */}
268
+ <div style={{ marginBottom: '20px' }}>
269
+ <div
270
+ style={{
271
+ display: 'flex',
272
+ justifyContent: 'space-between',
273
+ alignItems: 'center',
274
+ marginBottom: '10px',
275
+ }}
276
+ >
277
+ <h4>主题颜色</h4>
278
+ <button
279
+ onClick={handleAddColor}
280
+ disabled={disabled}
281
+ style={{
282
+ padding: '4px 8px',
283
+ border: '1px solid #e0e0e0',
284
+ borderRadius: '4px',
285
+ backgroundColor: '#ffffff',
286
+ color: '#333333',
287
+ cursor: disabled ? 'not-allowed' : 'pointer',
288
+ opacity: disabled ? 0.6 : 1,
289
+ }}
290
+ >
291
+ + 添加颜色
292
+ </button>
293
+ </div>
294
+ <div style={{ display: 'flex', flexWrap: 'wrap', gap: '10px' }}>
295
+ {colors.map((color, index) => (
296
+ <div key={index} style={{ display: 'flex', alignItems: 'center', gap: '5px' }}>
297
+ <input
298
+ type="color"
299
+ value={color}
300
+ onChange={(e) => handleColorChange(index, e.target.value)}
301
+ disabled={disabled}
302
+ style={{
303
+ width: '50px',
304
+ height: '30px',
305
+ border: 'none',
306
+ cursor: disabled ? 'not-allowed' : 'pointer',
307
+ opacity: disabled ? 0.6 : 1,
308
+ }}
309
+ />
310
+ <input
311
+ type="text"
312
+ value={color}
313
+ onChange={(e) => handleColorChange(index, e.target.value)}
314
+ disabled={disabled}
315
+ style={{
316
+ width: '80px',
317
+ padding: '4px',
318
+ border: '1px solid #e0e0e0',
319
+ borderRadius: '4px',
320
+ opacity: disabled ? 0.6 : 1,
321
+ }}
322
+ />
323
+ <button
324
+ onClick={() => handleRemoveColor(index)}
325
+ disabled={disabled || colors.length <= 1}
326
+ style={{
327
+ padding: '4px 8px',
328
+ border: '1px solid #ff4d4f',
329
+ borderRadius: '4px',
330
+ backgroundColor: '#ffffff',
331
+ color: '#ff4d4f',
332
+ cursor: disabled || colors.length <= 1 ? 'not-allowed' : 'pointer',
333
+ opacity: disabled || colors.length <= 1 ? 0.6 : 1,
334
+ }}
335
+ >
336
+ 删除
337
+ </button>
338
+ </div>
339
+ ))}
340
+ </div>
341
+ </div>
342
+
343
+ {/* 主题基础配置 */}
344
+ <div style={{ marginBottom: '20px' }}>
345
+ <h4>基础配置</h4>
346
+
347
+ {/* 背景色 */}
348
+ <div style={{ marginBottom: '10px' }}>
349
+ <label style={{ display: 'block', marginBottom: '5px' }}>背景色:</label>
350
+ <div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
351
+ <input
352
+ type="color"
353
+ value={backgroundColor}
354
+ onChange={(e) => handleBackgroundColorChange(e.target.value)}
355
+ disabled={disabled}
356
+ style={{
357
+ width: '50px',
358
+ height: '30px',
359
+ border: 'none',
360
+ cursor: disabled ? 'not-allowed' : 'pointer',
361
+ opacity: disabled ? 0.6 : 1,
362
+ }}
363
+ />
364
+ <input
365
+ type="text"
366
+ value={backgroundColor}
367
+ onChange={(e) => handleBackgroundColorChange(e.target.value)}
368
+ disabled={disabled}
369
+ style={{
370
+ width: '120px',
371
+ padding: '4px',
372
+ border: '1px solid #e0e0e0',
373
+ borderRadius: '4px',
374
+ opacity: disabled ? 0.6 : 1,
375
+ }}
376
+ />
377
+ </div>
378
+ </div>
379
+
380
+ {/* 文本颜色 */}
381
+ <div style={{ marginBottom: '10px' }}>
382
+ <label style={{ display: 'block', marginBottom: '5px' }}>文本颜色:</label>
383
+ <div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
384
+ <input
385
+ type="color"
386
+ value={textColor}
387
+ onChange={(e) => handleTextColorChange(e.target.value)}
388
+ disabled={disabled}
389
+ style={{
390
+ width: '50px',
391
+ height: '30px',
392
+ border: 'none',
393
+ cursor: disabled ? 'not-allowed' : 'pointer',
394
+ opacity: disabled ? 0.6 : 1,
395
+ }}
396
+ />
397
+ <input
398
+ type="text"
399
+ value={textColor}
400
+ onChange={(e) => handleTextColorChange(e.target.value)}
401
+ disabled={disabled}
402
+ style={{
403
+ width: '120px',
404
+ padding: '4px',
405
+ border: '1px solid #e0e0e0',
406
+ borderRadius: '4px',
407
+ opacity: disabled ? 0.6 : 1,
408
+ }}
409
+ />
410
+ </div>
411
+ </div>
412
+
413
+ {/* 深色模式 */}
414
+ <div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
415
+ <label>深色模式:</label>
416
+ <input
417
+ type="checkbox"
418
+ checked={darkMode}
419
+ onChange={handleDarkModeToggle}
420
+ disabled={disabled}
421
+ style={{
422
+ cursor: disabled ? 'not-allowed' : 'pointer',
423
+ opacity: disabled ? 0.6 : 1,
424
+ }}
425
+ />
426
+ </div>
427
+ </div>
428
+
429
+ {/* 保存按钮 */}
430
+ <button
431
+ onClick={handleSaveTheme}
432
+ disabled={disabled}
433
+ style={{
434
+ padding: '10px 20px',
435
+ border: 'none',
436
+ borderRadius: '4px',
437
+ backgroundColor: '#1890ff',
438
+ color: '#ffffff',
439
+ cursor: disabled ? 'not-allowed' : 'pointer',
440
+ opacity: disabled ? 0.6 : 1,
441
+ }}
442
+ >
443
+ 保存主题
444
+ </button>
445
+ </div>
446
+ );
447
+ };
448
+
449
+ export default ThemeEditor;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * TaroViz 编辑器组件
3
+ * 提供可视化的主题编辑功能
4
+ */
5
+ import ThemeEditor from './ThemeEditor';
6
+ import type { ThemeEditorProps } from './ThemeEditor';
7
+
8
+ export { ThemeEditor, ThemeEditorProps };
9
+
10
+ export default ThemeEditor;