@agions/taroviz 1.11.1 → 2.0.3

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 (164) hide show
  1. package/CHANGELOG.md +245 -0
  2. package/README.md +104 -302
  3. package/dist/cjs/index.js +1 -1
  4. package/dist/cjs/vendors.js +1 -0
  5. package/dist/cjs/vendors~echarts.js +1 -0
  6. package/dist/esm/index.js +1 -58151
  7. package/dist/esm/vendors.js +1 -0
  8. package/dist/esm/vendors~echarts.js +1 -0
  9. package/package.json +19 -25
  10. package/src/adapters/MiniAppAdapter.ts +136 -0
  11. package/src/adapters/__tests__/index.test.ts +1 -1
  12. package/src/adapters/h5/__tests__/index.test.ts +4 -2
  13. package/src/adapters/h5/index.ts +63 -64
  14. package/src/adapters/harmony/index.ts +23 -245
  15. package/src/adapters/index.ts +49 -45
  16. package/src/adapters/swan/index.ts +6 -69
  17. package/src/adapters/tt/index.ts +7 -70
  18. package/src/adapters/types.ts +25 -58
  19. package/src/adapters/weapp/index.ts +6 -69
  20. package/src/charts/__tests__/testUtils.tsx +87 -0
  21. package/src/charts/boxplot/__tests__/index.test.tsx +49 -103
  22. package/src/charts/boxplot/index.tsx +2 -1
  23. package/src/charts/boxplot/types.ts +17 -16
  24. package/src/charts/common/BaseChartWrapper.tsx +90 -82
  25. package/src/charts/common/__mocks__/BaseChartWrapper.tsx +17 -0
  26. package/src/charts/createChartComponent.tsx +36 -0
  27. package/src/charts/createOptionChartComponent.tsx +32 -0
  28. package/src/charts/funnel/__tests__/index.test.tsx +99 -0
  29. package/src/charts/funnel/index.tsx +60 -10
  30. package/src/charts/funnel/types.ts +6 -0
  31. package/src/charts/graph/__tests__/index.test.tsx +102 -33
  32. package/src/charts/graph/index.tsx +66 -9
  33. package/src/charts/graph/types.ts +6 -0
  34. package/src/charts/heatmap/__tests__/index.test.tsx +139 -0
  35. package/src/charts/heatmap/index.tsx +103 -10
  36. package/src/charts/heatmap/types.ts +6 -0
  37. package/src/charts/index.ts +74 -26
  38. package/src/charts/liquid/__tests__/index.test.tsx +52 -0
  39. package/src/charts/liquid/index.tsx +239 -182
  40. package/src/charts/liquid/types.ts +11 -11
  41. package/src/charts/parallel/__tests__/index.test.tsx +40 -67
  42. package/src/charts/parallel/index.tsx +2 -1
  43. package/src/charts/parallel/types.ts +19 -18
  44. package/src/charts/radar/__tests__/index.test.tsx +210 -0
  45. package/src/charts/radar/index.tsx +143 -10
  46. package/src/charts/radar/types.ts +13 -0
  47. package/src/charts/sankey/__tests__/index.test.tsx +124 -0
  48. package/src/charts/sankey/index.tsx +62 -10
  49. package/src/charts/sankey/types.ts +6 -0
  50. package/src/charts/tree/__tests__/index.test.tsx +71 -0
  51. package/src/charts/tree/index.tsx +5 -2
  52. package/src/charts/tree/types.ts +9 -9
  53. package/src/charts/types.ts +208 -106
  54. package/src/charts/utils.ts +9 -7
  55. package/src/charts/wordcloud/__tests__/index.test.tsx +98 -31
  56. package/src/charts/wordcloud/index.tsx +75 -9
  57. package/src/charts/wordcloud/types.ts +6 -0
  58. package/src/components/DataFilter/index.tsx +32 -10
  59. package/src/core/animation/types.ts +6 -6
  60. package/src/core/components/Annotation.tsx +6 -7
  61. package/src/core/components/BaseChart.tsx +110 -168
  62. package/src/core/components/ErrorBoundary.tsx +17 -4
  63. package/src/core/components/LazyChart.tsx +54 -55
  64. package/src/core/components/hooks/index.ts +6 -2
  65. package/src/core/components/hooks/useChartInit.ts +6 -3
  66. package/src/core/components/hooks/usePerformance.ts +8 -2
  67. package/src/core/components/hooks/useVirtualScroll.ts +2 -1
  68. package/src/core/index.ts +1 -1
  69. package/src/core/themes/ThemeManager.ts +1 -1
  70. package/src/core/types/common.ts +2 -1
  71. package/src/core/types/index.ts +0 -12
  72. package/src/core/types/platform.ts +3 -5
  73. package/src/core/utils/__tests__/deepClone.test.ts +317 -0
  74. package/src/core/utils/__tests__/index.test.ts +2 -1
  75. package/src/core/utils/chartInstances.ts +13 -0
  76. package/src/core/utils/common.ts +20 -29
  77. package/src/core/utils/deepClone.ts +114 -0
  78. package/src/core/utils/download.ts +128 -0
  79. package/src/core/utils/drillDown.ts +34 -353
  80. package/src/core/utils/drillDownHelpers.ts +426 -0
  81. package/src/core/utils/events.ts +12 -0
  82. package/src/core/utils/export/ExportUtils.ts +36 -67
  83. package/src/core/utils/format.ts +44 -0
  84. package/src/core/utils/index.ts +21 -154
  85. package/src/core/utils/merge.ts +25 -0
  86. package/src/core/utils/performance/PerformanceAnalyzer.ts +38 -21
  87. package/src/core/utils/performance/hooks.ts +7 -0
  88. package/src/core/utils/performance/index.ts +2 -0
  89. package/src/{hooks → core/utils/performance}/useAnimation.ts +45 -41
  90. package/src/core/utils/performance/useDataZoom.ts +324 -0
  91. package/src/{hooks → core/utils/performance}/usePerformance.ts +49 -41
  92. package/src/core/utils/performance/usePerformanceHooks.ts +278 -0
  93. package/src/core/utils/performanceUtils.ts +310 -0
  94. package/src/core/utils/runtime.ts +190 -0
  95. package/src/core/utils/setOptionUtils.ts +59 -0
  96. package/src/core/version.ts +14 -0
  97. package/src/editor/EnhancedThemeEditor.tsx +362 -540
  98. package/src/editor/ThemeEditor.tsx +55 -321
  99. package/src/editor/components/ThemeBasicSettings.tsx +113 -0
  100. package/src/editor/components/ThemeColorEditor.tsx +105 -0
  101. package/src/editor/components/ThemeSelector.tsx +70 -0
  102. package/src/editor/hooks/useThemeEditorState.ts +201 -0
  103. package/src/editor/index.ts +10 -2
  104. package/src/hooks/__tests__/index.test.tsx +3 -1
  105. package/src/hooks/chartConnectHelpers.ts +341 -0
  106. package/src/hooks/index.ts +55 -660
  107. package/src/hooks/types.ts +189 -0
  108. package/src/hooks/useChartAutoResize.ts +73 -0
  109. package/src/hooks/useChartConnect.ts +92 -238
  110. package/src/hooks/useChartDownload.ts +25 -27
  111. package/src/hooks/useChartHistory.ts +34 -49
  112. package/src/hooks/useChartInit.ts +59 -0
  113. package/src/hooks/useChartOptions.ts +259 -0
  114. package/src/hooks/useChartPerformance.ts +109 -0
  115. package/src/hooks/useChartSelection.ts +52 -49
  116. package/src/hooks/useChartTheme.ts +51 -0
  117. package/src/hooks/useDataTransform.ts +19 -4
  118. package/src/hooks/utils/chartDownloadUtils.ts +40 -53
  119. package/src/hooks/utils/dataTransformUtils.ts +22 -0
  120. package/src/index.ts +48 -34
  121. package/src/main.tsx +4 -9
  122. package/src/react-dom.d.ts +3 -3
  123. package/src/themes/index.ts +30 -855
  124. package/src/themes/palettes/blue-green.ts +13 -0
  125. package/src/themes/palettes/chalk.ts +13 -0
  126. package/src/themes/palettes/cyber.ts +44 -0
  127. package/src/themes/palettes/dark.ts +52 -0
  128. package/src/themes/palettes/default.ts +52 -0
  129. package/src/themes/palettes/elegant.ts +34 -0
  130. package/src/themes/palettes/forest.ts +13 -0
  131. package/src/themes/palettes/glass.ts +49 -0
  132. package/src/themes/palettes/golden.ts +13 -0
  133. package/src/themes/palettes/neon.ts +43 -0
  134. package/src/themes/palettes/ocean.ts +39 -0
  135. package/src/themes/palettes/pastel.ts +37 -0
  136. package/src/themes/palettes/purple-passion.ts +13 -0
  137. package/src/themes/palettes/retro.ts +33 -0
  138. package/src/themes/palettes/sunset.ts +40 -0
  139. package/src/themes/palettes/walden.ts +13 -0
  140. package/src/themes/registry.ts +184 -0
  141. package/src/themes/types.ts +213 -0
  142. package/src/charts/bar/__tests__/index.test.tsx +0 -113
  143. package/src/charts/bar/index.tsx +0 -14
  144. package/src/charts/candlestick/__tests__/index.test.tsx +0 -40
  145. package/src/charts/candlestick/index.tsx +0 -13
  146. package/src/charts/gauge/index.tsx +0 -14
  147. package/src/charts/line/__tests__/index.test.tsx +0 -107
  148. package/src/charts/line/index.tsx +0 -15
  149. package/src/charts/pie/__tests__/index.test.tsx +0 -112
  150. package/src/charts/pie/index.tsx +0 -14
  151. package/src/charts/scatter/index.tsx +0 -14
  152. package/src/charts/sunburst/index.tsx +0 -18
  153. package/src/charts/treemap/index.tsx +0 -18
  154. package/src/core/utils/codeGenerator/CodeGenerator.ts +0 -669
  155. package/src/core/utils/codeGenerator/index.ts +0 -13
  156. package/src/core/utils/codeGenerator/types.ts +0 -198
  157. package/src/core/utils/configGenerator/ConfigGenerator.ts +0 -583
  158. package/src/core/utils/configGenerator/index.ts +0 -13
  159. package/src/core/utils/configGenerator/types.ts +0 -445
  160. package/src/core/utils/debug/DebugPanel.tsx +0 -637
  161. package/src/core/utils/debug/debugger.ts +0 -322
  162. package/src/core/utils/debug/index.ts +0 -21
  163. package/src/core/utils/debug/types.ts +0 -142
  164. package/src/hooks/useDataZoom.ts +0 -323
@@ -2,9 +2,13 @@
2
2
  * TaroViz 主题编辑器组件
3
3
  * 提供可视化的主题编辑功能
4
4
  */
5
- import React, { useState, useEffect } from 'react';
5
+ import React from 'react';
6
6
 
7
- import { ThemeOptions, getRegisteredThemes, registerTheme, switchTheme } from '../themes';
7
+ import type { ThemeOptions } from '../themes';
8
+ import { useThemeEditorState } from './hooks/useThemeEditorState';
9
+ import ThemeSelector from './components/ThemeSelector';
10
+ import ThemeColorEditor from './components/ThemeColorEditor';
11
+ import ThemeBasicSettings from './components/ThemeBasicSettings';
8
12
 
9
13
  /**
10
14
  * 主题编辑器属性
@@ -52,126 +56,29 @@ const ThemeEditor: React.FC<ThemeEditorProps> = ({
52
56
  style = {},
53
57
  className = '',
54
58
  }) => {
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
- updateCurrentTheme({ colors: newColors });
107
- };
108
-
109
- // 处理背景色变化
110
- const handleBackgroundColorChange = (color: string) => {
111
- updateCurrentTheme({ backgroundColor: color });
112
- };
113
-
114
- // 处理文本颜色变化
115
- const handleTextColorChange = (color: string) => {
116
- updateCurrentTheme({ textColor: color });
117
- };
118
-
119
- // 处理深色模式切换
120
- const handleDarkModeToggle = () => {
121
- updateCurrentTheme({ darkMode: !darkMode });
122
- };
123
-
124
- // 更新当前主题
125
- const updateCurrentTheme = (updates: Partial<ThemeOptions>) => {
126
- const updatedTheme = { ...currentTheme, ...updates };
127
- setCurrentTheme(updatedTheme);
128
- if (onThemeChange) {
129
- onThemeChange(updatedTheme);
130
- }
131
- switchTheme(updatedTheme);
132
- };
133
-
134
- // 保存主题
59
+ const {
60
+ currentTheme,
61
+ registeredThemes,
62
+ colors,
63
+ backgroundColor,
64
+ textColor,
65
+ darkMode,
66
+ isEditing,
67
+ newThemeName,
68
+ setCurrentTheme,
69
+ updateTheme,
70
+ handleColorChange,
71
+ handleAddColor,
72
+ handleRemoveColor,
73
+ handleStartEdit,
74
+ setNewThemeName,
75
+ saveTheme,
76
+ } = useThemeEditorState({ selectedTheme, onThemeChange });
77
+
78
+ // 处理保存主题
135
79
  const handleSaveTheme = () => {
136
- const themeToSave = {
137
- ...currentTheme,
138
- colors,
139
- backgroundColor,
140
- textColor,
141
- darkMode,
142
- };
143
-
144
- if (isEditing && newThemeName) {
145
- // 保存为新主题
146
- registerTheme(newThemeName, themeToSave);
147
- setIsEditing(false);
148
- setNewThemeName('');
149
- } else {
150
- // 更新现有主题
151
- registerTheme(currentTheme.name || 'custom', themeToSave);
152
- }
153
-
154
- if (onThemeSave) {
155
- onThemeSave(themeToSave);
156
- }
157
- };
158
-
159
- // 添加新颜色
160
- const handleAddColor = () => {
161
- setColors([...colors, '#000000']);
162
- };
163
-
164
- // 删除颜色
165
- const handleRemoveColor = (index: number) => {
166
- const newColors = colors.filter((_, i) => i !== index);
167
- setColors(newColors);
168
- updateCurrentTheme({ colors: newColors });
169
- };
170
-
171
- // 开始编辑新主题
172
- const handleStartEdit = () => {
173
- setIsEditing(true);
174
- setNewThemeName('');
80
+ const themeToSave = saveTheme();
81
+ onThemeSave?.(themeToSave);
175
82
  };
176
83
 
177
84
  return (
@@ -188,45 +95,14 @@ const ThemeEditor: React.FC<ThemeEditorProps> = ({
188
95
  >
189
96
  <h3>主题编辑器</h3>
190
97
 
191
- {/* 主题列表 */}
192
- <div style={{ marginBottom: '20px' }}>
193
- <h4>选择主题</h4>
194
- <div style={{ display: 'flex', flexWrap: 'wrap', gap: '10px', marginTop: '10px' }}>
195
- {themes.map((theme) => (
196
- <button
197
- key={theme.name}
198
- onClick={() => handleThemeSelect(theme)}
199
- disabled={disabled}
200
- style={{
201
- padding: '8px 16px',
202
- border: `2px solid ${currentTheme.name === theme.name ? '#1890ff' : '#e0e0e0'}`,
203
- borderRadius: '4px',
204
- backgroundColor: currentTheme.name === theme.name ? '#1890ff' : '#ffffff',
205
- color: currentTheme.name === theme.name ? '#ffffff' : '#333333',
206
- cursor: disabled ? 'not-allowed' : 'pointer',
207
- opacity: disabled ? 0.6 : 1,
208
- }}
209
- >
210
- {theme.name}
211
- </button>
212
- ))}
213
- <button
214
- onClick={handleStartEdit}
215
- disabled={disabled}
216
- style={{
217
- padding: '8px 16px',
218
- border: '2px dashed #e0e0e0',
219
- borderRadius: '4px',
220
- backgroundColor: '#f5f5f5',
221
- color: '#333333',
222
- cursor: disabled ? 'not-allowed' : 'pointer',
223
- opacity: disabled ? 0.6 : 1,
224
- }}
225
- >
226
- + 新主题
227
- </button>
228
- </div>
229
- </div>
98
+ {/* 主题选择 */}
99
+ <ThemeSelector
100
+ themes={registeredThemes}
101
+ currentTheme={currentTheme}
102
+ disabled={disabled}
103
+ onSelect={setCurrentTheme}
104
+ onCreateNew={handleStartEdit}
105
+ />
230
106
 
231
107
  {/* 新主题编辑 */}
232
108
  {isEditing && (
@@ -259,167 +135,25 @@ const ThemeEditor: React.FC<ThemeEditorProps> = ({
259
135
  </div>
260
136
  )}
261
137
 
262
- {/* 主题颜色配置 */}
263
- <div style={{ marginBottom: '20px' }}>
264
- <div
265
- style={{
266
- display: 'flex',
267
- justifyContent: 'space-between',
268
- alignItems: 'center',
269
- marginBottom: '10px',
270
- }}
271
- >
272
- <h4>主题颜色</h4>
273
- <button
274
- onClick={handleAddColor}
275
- disabled={disabled}
276
- style={{
277
- padding: '4px 8px',
278
- border: '1px solid #e0e0e0',
279
- borderRadius: '4px',
280
- backgroundColor: '#ffffff',
281
- color: '#333333',
282
- cursor: disabled ? 'not-allowed' : 'pointer',
283
- opacity: disabled ? 0.6 : 1,
284
- }}
285
- >
286
- + 添加颜色
287
- </button>
288
- </div>
289
- <div style={{ display: 'flex', flexWrap: 'wrap', gap: '10px' }}>
290
- {colors.map((color, index) => (
291
- <div key={index} style={{ display: 'flex', alignItems: 'center', gap: '5px' }}>
292
- <input
293
- type="color"
294
- value={color}
295
- onChange={(e) => handleColorChange(index, e.target.value)}
296
- disabled={disabled}
297
- style={{
298
- width: '50px',
299
- height: '30px',
300
- border: 'none',
301
- cursor: disabled ? 'not-allowed' : 'pointer',
302
- opacity: disabled ? 0.6 : 1,
303
- }}
304
- />
305
- <input
306
- type="text"
307
- value={color}
308
- onChange={(e) => handleColorChange(index, e.target.value)}
309
- disabled={disabled}
310
- style={{
311
- width: '80px',
312
- padding: '4px',
313
- border: '1px solid #e0e0e0',
314
- borderRadius: '4px',
315
- opacity: disabled ? 0.6 : 1,
316
- }}
317
- />
318
- <button
319
- onClick={() => handleRemoveColor(index)}
320
- disabled={disabled || colors.length <= 1}
321
- style={{
322
- padding: '4px 8px',
323
- border: '1px solid #ff4d4f',
324
- borderRadius: '4px',
325
- backgroundColor: '#ffffff',
326
- color: '#ff4d4f',
327
- cursor: disabled || colors.length <= 1 ? 'not-allowed' : 'pointer',
328
- opacity: disabled || colors.length <= 1 ? 0.6 : 1,
329
- }}
330
- >
331
- 删除
332
- </button>
333
- </div>
334
- ))}
335
- </div>
336
- </div>
337
-
338
- {/* 主题基础配置 */}
339
- <div style={{ marginBottom: '20px' }}>
340
- <h4>基础配置</h4>
341
-
342
- {/* 背景色 */}
343
- <div style={{ marginBottom: '10px' }}>
344
- <label style={{ display: 'block', marginBottom: '5px' }}>背景色:</label>
345
- <div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
346
- <input
347
- type="color"
348
- value={backgroundColor}
349
- onChange={(e) => handleBackgroundColorChange(e.target.value)}
350
- disabled={disabled}
351
- style={{
352
- width: '50px',
353
- height: '30px',
354
- border: 'none',
355
- cursor: disabled ? 'not-allowed' : 'pointer',
356
- opacity: disabled ? 0.6 : 1,
357
- }}
358
- />
359
- <input
360
- type="text"
361
- value={backgroundColor}
362
- onChange={(e) => handleBackgroundColorChange(e.target.value)}
363
- disabled={disabled}
364
- style={{
365
- width: '120px',
366
- padding: '4px',
367
- border: '1px solid #e0e0e0',
368
- borderRadius: '4px',
369
- opacity: disabled ? 0.6 : 1,
370
- }}
371
- />
372
- </div>
373
- </div>
374
-
375
- {/* 文本颜色 */}
376
- <div style={{ marginBottom: '10px' }}>
377
- <label style={{ display: 'block', marginBottom: '5px' }}>文本颜色:</label>
378
- <div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
379
- <input
380
- type="color"
381
- value={textColor}
382
- onChange={(e) => handleTextColorChange(e.target.value)}
383
- disabled={disabled}
384
- style={{
385
- width: '50px',
386
- height: '30px',
387
- border: 'none',
388
- cursor: disabled ? 'not-allowed' : 'pointer',
389
- opacity: disabled ? 0.6 : 1,
390
- }}
391
- />
392
- <input
393
- type="text"
394
- value={textColor}
395
- onChange={(e) => handleTextColorChange(e.target.value)}
396
- disabled={disabled}
397
- style={{
398
- width: '120px',
399
- padding: '4px',
400
- border: '1px solid #e0e0e0',
401
- borderRadius: '4px',
402
- opacity: disabled ? 0.6 : 1,
403
- }}
404
- />
405
- </div>
406
- </div>
407
-
408
- {/* 深色模式 */}
409
- <div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
410
- <label>深色模式:</label>
411
- <input
412
- type="checkbox"
413
- checked={darkMode}
414
- onChange={handleDarkModeToggle}
415
- disabled={disabled}
416
- style={{
417
- cursor: disabled ? 'not-allowed' : 'pointer',
418
- opacity: disabled ? 0.6 : 1,
419
- }}
420
- />
421
- </div>
422
- </div>
138
+ {/* 颜色配置 */}
139
+ <ThemeColorEditor
140
+ colors={colors}
141
+ disabled={disabled}
142
+ onColorChange={handleColorChange}
143
+ onAddColor={handleAddColor}
144
+ onRemoveColor={handleRemoveColor}
145
+ />
146
+
147
+ {/* 基础配置 */}
148
+ <ThemeBasicSettings
149
+ backgroundColor={backgroundColor}
150
+ textColor={textColor}
151
+ darkMode={darkMode}
152
+ disabled={disabled}
153
+ onBackgroundColorChange={(color) => updateTheme({ backgroundColor: color })}
154
+ onTextColorChange={(color) => updateTheme({ textColor: color })}
155
+ onDarkModeChange={(mode) => updateTheme({ darkMode: mode })}
156
+ />
423
157
 
424
158
  {/* 保存按钮 */}
425
159
  <button
@@ -0,0 +1,113 @@
1
+ /**
2
+ * 主题基础设置组件
3
+ * 包含背景色、文本颜色和深色模式开关
4
+ */
5
+ import React from 'react';
6
+
7
+ export interface ThemeBasicSettingsProps {
8
+ /** 背景色 */
9
+ backgroundColor: string;
10
+ /** 文本颜色 */
11
+ textColor: string;
12
+ /** 深色模式 */
13
+ darkMode: boolean;
14
+ /** 是否禁用 */
15
+ disabled?: boolean;
16
+ /** 背景色变化回调 */
17
+ onBackgroundColorChange: (color: string) => void;
18
+ /** 文本颜色变化回调 */
19
+ onTextColorChange: (color: string) => void;
20
+ /** 深色模式变化回调 */
21
+ onDarkModeChange: (darkMode: boolean) => void;
22
+ }
23
+
24
+ const ThemeBasicSettings: React.FC<ThemeBasicSettingsProps> = ({
25
+ backgroundColor,
26
+ textColor,
27
+ darkMode,
28
+ disabled = false,
29
+ onBackgroundColorChange,
30
+ onTextColorChange,
31
+ onDarkModeChange,
32
+ }) => {
33
+ const colorInputStyle: React.CSSProperties = {
34
+ width: '50px',
35
+ height: '30px',
36
+ border: 'none',
37
+ cursor: disabled ? 'not-allowed' : 'pointer',
38
+ opacity: disabled ? 0.6 : 1,
39
+ };
40
+
41
+ const textInputStyle: React.CSSProperties = {
42
+ width: '120px',
43
+ padding: '4px',
44
+ border: '1px solid #e0e0e0',
45
+ borderRadius: '4px',
46
+ opacity: disabled ? 0.6 : 1,
47
+ };
48
+
49
+ return (
50
+ <div style={{ marginBottom: '20px' }}>
51
+ <h4>基础配置</h4>
52
+
53
+ {/* 背景色 */}
54
+ <div style={{ marginBottom: '10px' }}>
55
+ <label style={{ display: 'block', marginBottom: '5px' }}>背景色:</label>
56
+ <div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
57
+ <input
58
+ type="color"
59
+ value={backgroundColor}
60
+ onChange={(e) => onBackgroundColorChange(e.target.value)}
61
+ disabled={disabled}
62
+ style={colorInputStyle}
63
+ />
64
+ <input
65
+ type="text"
66
+ value={backgroundColor}
67
+ onChange={(e) => onBackgroundColorChange(e.target.value)}
68
+ disabled={disabled}
69
+ style={textInputStyle}
70
+ />
71
+ </div>
72
+ </div>
73
+
74
+ {/* 文本颜色 */}
75
+ <div style={{ marginBottom: '10px' }}>
76
+ <label style={{ display: 'block', marginBottom: '5px' }}>文本颜色:</label>
77
+ <div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
78
+ <input
79
+ type="color"
80
+ value={textColor}
81
+ onChange={(e) => onTextColorChange(e.target.value)}
82
+ disabled={disabled}
83
+ style={colorInputStyle}
84
+ />
85
+ <input
86
+ type="text"
87
+ value={textColor}
88
+ onChange={(e) => onTextColorChange(e.target.value)}
89
+ disabled={disabled}
90
+ style={textInputStyle}
91
+ />
92
+ </div>
93
+ </div>
94
+
95
+ {/* 深色模式 */}
96
+ <div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
97
+ <label>深色模式:</label>
98
+ <input
99
+ type="checkbox"
100
+ checked={darkMode}
101
+ onChange={(e) => onDarkModeChange(e.target.checked)}
102
+ disabled={disabled}
103
+ style={{
104
+ cursor: disabled ? 'not-allowed' : 'pointer',
105
+ opacity: disabled ? 0.6 : 1,
106
+ }}
107
+ />
108
+ </div>
109
+ </div>
110
+ );
111
+ };
112
+
113
+ export default ThemeBasicSettings;
@@ -0,0 +1,105 @@
1
+ /**
2
+ * 主题颜色编辑器组件
3
+ * 管理主题颜色列表的增加、删除和修改
4
+ */
5
+ import React from 'react';
6
+
7
+ export interface ThemeColorEditorProps {
8
+ /** 颜色列表 */
9
+ colors: string[];
10
+ /** 是否禁用 */
11
+ disabled?: boolean;
12
+ /** 颜色变化回调 */
13
+ onColorChange: (index: number, color: string) => void;
14
+ /** 添加颜色回调 */
15
+ onAddColor: () => void;
16
+ /** 删除颜色回调 */
17
+ onRemoveColor: (index: number) => void;
18
+ }
19
+
20
+ const ThemeColorEditor: React.FC<ThemeColorEditorProps> = ({
21
+ colors,
22
+ disabled = false,
23
+ onColorChange,
24
+ onAddColor,
25
+ onRemoveColor,
26
+ }) => {
27
+ return (
28
+ <div style={{ marginBottom: '20px' }}>
29
+ <div
30
+ style={{
31
+ display: 'flex',
32
+ justifyContent: 'space-between',
33
+ alignItems: 'center',
34
+ marginBottom: '10px',
35
+ }}
36
+ >
37
+ <h4>主题颜色</h4>
38
+ <button
39
+ onClick={onAddColor}
40
+ disabled={disabled}
41
+ style={{
42
+ padding: '4px 8px',
43
+ border: '1px solid #e0e0e0',
44
+ borderRadius: '4px',
45
+ backgroundColor: '#ffffff',
46
+ color: '#333333',
47
+ cursor: disabled ? 'not-allowed' : 'pointer',
48
+ opacity: disabled ? 0.6 : 1,
49
+ }}
50
+ >
51
+ + 添加颜色
52
+ </button>
53
+ </div>
54
+ <div style={{ display: 'flex', flexWrap: 'wrap', gap: '10px' }}>
55
+ {colors.map((color, index) => (
56
+ <div key={index} style={{ display: 'flex', alignItems: 'center', gap: '5px' }}>
57
+ <input
58
+ type="color"
59
+ value={color}
60
+ onChange={(e) => onColorChange(index, e.target.value)}
61
+ disabled={disabled}
62
+ style={{
63
+ width: '50px',
64
+ height: '30px',
65
+ border: 'none',
66
+ cursor: disabled ? 'not-allowed' : 'pointer',
67
+ opacity: disabled ? 0.6 : 1,
68
+ }}
69
+ />
70
+ <input
71
+ type="text"
72
+ value={color}
73
+ onChange={(e) => onColorChange(index, e.target.value)}
74
+ disabled={disabled}
75
+ style={{
76
+ width: '80px',
77
+ padding: '4px',
78
+ border: '1px solid #e0e0e0',
79
+ borderRadius: '4px',
80
+ opacity: disabled ? 0.6 : 1,
81
+ }}
82
+ />
83
+ <button
84
+ onClick={() => onRemoveColor(index)}
85
+ disabled={disabled || colors.length <= 1}
86
+ style={{
87
+ padding: '4px 8px',
88
+ border: '1px solid #ff4d4f',
89
+ borderRadius: '4px',
90
+ backgroundColor: '#ffffff',
91
+ color: '#ff4d4f',
92
+ cursor: disabled || colors.length <= 1 ? 'not-allowed' : 'pointer',
93
+ opacity: disabled || colors.length <= 1 ? 0.6 : 1,
94
+ }}
95
+ >
96
+ 删除
97
+ </button>
98
+ </div>
99
+ ))}
100
+ </div>
101
+ </div>
102
+ );
103
+ };
104
+
105
+ export default ThemeColorEditor;
@@ -0,0 +1,70 @@
1
+ /**
2
+ * 主题选择器组件
3
+ * 显示已注册的主题列表和新建主题按钮
4
+ */
5
+ import React from 'react';
6
+ import type { ThemeOptions } from '../../themes';
7
+
8
+ export interface ThemeSelectorProps {
9
+ /** 已注册的主题列表 */
10
+ themes: ThemeOptions[];
11
+ /** 当前选中的主题 */
12
+ currentTheme: ThemeOptions;
13
+ /** 是否禁用 */
14
+ disabled?: boolean;
15
+ /** 主题选择回调 */
16
+ onSelect: (theme: ThemeOptions) => void;
17
+ /** 新建主题回调 */
18
+ onCreateNew: () => void;
19
+ }
20
+
21
+ const ThemeSelector: React.FC<ThemeSelectorProps> = ({
22
+ themes,
23
+ currentTheme,
24
+ disabled = false,
25
+ onSelect,
26
+ onCreateNew,
27
+ }) => {
28
+ return (
29
+ <div style={{ marginBottom: '20px' }}>
30
+ <h4>选择主题</h4>
31
+ <div style={{ display: 'flex', flexWrap: 'wrap', gap: '10px', marginTop: '10px' }}>
32
+ {themes.map((theme) => (
33
+ <button
34
+ key={theme.name}
35
+ onClick={() => onSelect(theme)}
36
+ disabled={disabled}
37
+ style={{
38
+ padding: '8px 16px',
39
+ border: `2px solid ${currentTheme.name === theme.name ? '#1890ff' : '#e0e0e0'}`,
40
+ borderRadius: '4px',
41
+ backgroundColor: currentTheme.name === theme.name ? '#1890ff' : '#ffffff',
42
+ color: currentTheme.name === theme.name ? '#ffffff' : '#333333',
43
+ cursor: disabled ? 'not-allowed' : 'pointer',
44
+ opacity: disabled ? 0.6 : 1,
45
+ }}
46
+ >
47
+ {theme.name}
48
+ </button>
49
+ ))}
50
+ <button
51
+ onClick={onCreateNew}
52
+ disabled={disabled}
53
+ style={{
54
+ padding: '8px 16px',
55
+ border: '2px dashed #e0e0e0',
56
+ borderRadius: '4px',
57
+ backgroundColor: '#fafafa',
58
+ color: '#999999',
59
+ cursor: disabled ? 'not-allowed' : 'pointer',
60
+ opacity: disabled ? 0.6 : 1,
61
+ }}
62
+ >
63
+ + 新建主题
64
+ </button>
65
+ </div>
66
+ </div>
67
+ );
68
+ };
69
+
70
+ export default ThemeSelector;