@agions/taroviz 1.2.0 → 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 (37) hide show
  1. package/README.md +42 -36
  2. package/dist/cjs/index.js +1 -0
  3. package/dist/{index.esm.js → esm/index.js} +73473 -59179
  4. package/package.json +67 -8
  5. package/src/adapters/__tests__/index.test.ts +2 -2
  6. package/src/adapters/h5/index.ts +1 -1
  7. package/src/adapters/index.ts +99 -167
  8. package/src/charts/bar/index.tsx +2 -11
  9. package/src/charts/common/BaseChartWrapper.tsx +2 -2
  10. package/src/charts/funnel/index.tsx +2 -17
  11. package/src/charts/gauge/index.tsx +2 -17
  12. package/src/charts/heatmap/index.tsx +2 -17
  13. package/src/charts/line/index.tsx +2 -11
  14. package/src/charts/pie/index.tsx +3 -6
  15. package/src/charts/radar/index.tsx +2 -17
  16. package/src/charts/scatter/index.tsx +2 -17
  17. package/src/charts/types.ts +503 -30
  18. package/src/charts/utils.ts +1 -1
  19. package/src/core/__tests__/platform.test.ts +1 -1
  20. package/src/core/animation/AnimationManager.ts +2 -2
  21. package/src/core/components/BaseChart.tsx +12 -18
  22. package/src/core/components/ErrorBoundary.tsx +458 -0
  23. package/src/core/echarts.ts +58 -0
  24. package/src/core/index.ts +4 -1
  25. package/src/core/utils/__tests__/common.test.ts +1 -1
  26. package/src/core/utils/chartInstances.ts +2 -2
  27. package/src/core/utils/codeGenerator/CodeGenerator.ts +2 -2
  28. package/src/core/utils/codeGenerator/types.ts +0 -2
  29. package/src/core/utils/configGenerator/ConfigGenerator.ts +12 -12
  30. package/src/core/utils/debug/DebugPanel.tsx +1 -1
  31. package/src/core/utils/debug/debugger.ts +1 -1
  32. package/src/core/utils/index.ts +1 -1
  33. package/src/core/utils/performance/PerformanceAnalyzer.ts +5 -5
  34. package/src/editor/ThemeEditor.tsx +9 -9
  35. package/src/hooks/index.ts +441 -61
  36. package/src/main.tsx +1 -1
  37. package/src/themes/index.ts +651 -256
@@ -1,119 +1,235 @@
1
1
  /**
2
- * TaroViz React Hooks
3
- * 提供与图表相关的React Hooks
2
+ * TaroViz React Hooks - 增强版
3
+ * 提供与图表相关的 React Hooks
4
4
  */
5
- import { useState, useEffect, useMemo } from 'react';
6
-
5
+ import { useState, useEffect, useMemo, useCallback, useRef } from 'react';
7
6
  import { getAdapter } from '../adapters';
8
- import { EventHandler } from '../core';
7
+ import type { EChartsOption } from 'echarts';
9
8
 
10
- // 通用图表配置类型
11
- interface ChartOptions {
12
- [key: string]: any;
13
- }
9
+ // ============================================================================
10
+ // 类型定义
11
+ // ============================================================================
14
12
 
15
- // 通用图表实例类型
16
- interface ChartInstance {
17
- setOption: (option: any, notMerge?: boolean) => void;
18
- resize: () => void;
13
+ /** 图表实例类型 */
14
+ export interface ChartInstance {
15
+ setOption: (option: EChartsOption, notMerge?: boolean, lazyUpdate?: boolean) => void;
16
+ getOption: () => EChartsOption;
17
+ resize: (option?: { width?: number | string; height?: number | string }) => void;
19
18
  on: (event: string, handler: EventHandler) => void;
20
19
  off: (event: string, handler?: EventHandler) => void;
21
- showLoading: (opts?: any) => void;
20
+ showLoading: (opts?: LoadingOptions) => void;
22
21
  hideLoading: () => void;
23
22
  dispose: () => void;
23
+ isDisposed: () => boolean;
24
+ getWidth: () => number;
25
+ getHeight: () => number;
26
+ getDom: () => HTMLElement;
27
+ getDataURL?: (options?: {
28
+ type?: string;
29
+ pixelRatio?: number;
30
+ backgroundColor?: string;
31
+ }) => string;
32
+ getSvgData?: () => string;
33
+ getCompressedDataURL?: (options?: { seriesIndex?: number; dimension?: number }) => string;
34
+ clear?: () => void;
35
+ dispatchAction?: (action: { type: string; [key: string]: unknown }) => void;
24
36
  [key: string]: any;
25
37
  }
26
38
 
39
+ /** 事件处理器 */
40
+ export type EventHandler = (params?: unknown) => void;
41
+
42
+ /** 加载选项 */
43
+ export interface LoadingOptions {
44
+ text?: string;
45
+ color?: string;
46
+ textColor?: string;
47
+ maskColor?: string;
48
+ zlevel?: number;
49
+ }
50
+
51
+ /** 图表配置 */
52
+ export interface ChartConfig {
53
+ width?: number | string;
54
+ height?: number | string;
55
+ renderer?: 'canvas' | 'svg';
56
+ theme?: string | Record<string, unknown>;
57
+ }
58
+
59
+ /** 数据转换器 */
60
+ export type DataTransformer<T = unknown> = (data: T) => EChartsOption;
61
+
62
+ /** 响应式断点 */
63
+ export type Breakpoint = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
64
+
65
+ /** 断点配置 */
66
+ export interface BreakpointConfig {
67
+ width: number;
68
+ }
69
+
70
+ /** 主题切换回调 */
71
+ export type ThemeChangeCallback = (theme: string | Record<string, unknown>) => void;
72
+
73
+ // ============================================================================
74
+ // Hooks
75
+ // ============================================================================
76
+
27
77
  /**
28
- * 使用图表Hook
78
+ * 使用图表 Hook
29
79
  * @param chartRef 图表容器的引用
30
- * @returns [图表实例, setInstance]
80
+ * @param config 图表配置
81
+ * @returns [图表实例, 设置实例函数, 是否已初始化]
31
82
  */
32
- export function useChart(chartRef: React.RefObject<HTMLElement>) {
83
+ export function useChart(
84
+ chartRef: React.RefObject<HTMLElement>,
85
+ config?: ChartConfig
86
+ ): [ChartInstance | null, React.Dispatch<React.SetStateAction<ChartInstance | null>>, boolean] {
33
87
  const [instance, setInstance] = useState<ChartInstance | null>(null);
88
+ const [initialized, setInitialized] = useState(false);
89
+ const configRef = useRef(config);
90
+ configRef.current = config;
34
91
 
35
92
  useEffect(() => {
36
- if (chartRef.current && !instance) {
37
- // 使用默认配置初始化适配器
38
- const adapter = getAdapter({});
39
-
40
- // 注意:Adapter接口可能没有直接定义setComponent方法
41
- // 但多数适配器实现中都有这个方法,我们可以通过类型断言使用
42
- if (typeof (adapter as any).setComponent === 'function') {
43
- (adapter as any).setComponent(chartRef.current);
44
- }
93
+ if (!chartRef.current || instance) {
94
+ return;
95
+ }
45
96
 
46
- // 初始化并保存实例
97
+ try {
98
+ const adapter = getAdapter(configRef.current || {});
47
99
  const chartInstance = adapter as unknown as ChartInstance;
48
100
  setInstance(chartInstance);
101
+ setInitialized(true);
102
+ } catch (error) {
103
+ console.error('Failed to initialize chart:', error);
49
104
  }
50
105
 
51
106
  return () => {
52
107
  if (instance) {
53
108
  try {
54
- instance.dispose();
109
+ const inst = instance as any;
110
+ if (!inst.isDisposed?.()) {
111
+ inst.dispose();
112
+ }
55
113
  } catch (e) {
56
114
  console.warn('Failed to dispose chart instance:', e);
57
115
  }
116
+ setInstance(null);
117
+ setInitialized(false);
58
118
  }
59
119
  };
60
- }, [chartRef, instance]);
120
+ }, [chartRef]);
61
121
 
62
- return [instance, setInstance] as const;
122
+ return [instance, setInstance, initialized];
63
123
  }
64
124
 
65
125
  /**
66
- * 设置图表选项Hook
126
+ * 设置图表选项 Hook
67
127
  * @param instance 图表实例
68
128
  * @param option 图表选项
69
- * @param deps 依赖数组
129
+ * @param options 配置选项
70
130
  */
71
- export function useOption(instance: ChartInstance | null, option: ChartOptions, deps: any[] = []) {
131
+ export function useOption(
132
+ instance: ChartInstance | null,
133
+ option: EChartsOption | null,
134
+ options?: {
135
+ /** 是否不合并 */
136
+ notMerge?: boolean;
137
+ /** 是否延迟更新 */
138
+ lazyUpdate?: boolean;
139
+ /** 是否在数据变化时替换 */
140
+ replaceMerge?: string[];
141
+ /** 依赖数组 */
142
+ deps?: unknown[];
143
+ }
144
+ ) {
145
+ const { notMerge = false, lazyUpdate = false, replaceMerge, deps = [] } = options || {};
146
+
72
147
  useEffect(() => {
73
148
  if (instance && option) {
74
149
  try {
75
- instance.setOption(option);
150
+ instance.setOption(option, notMerge, lazyUpdate);
76
151
  } catch (e) {
77
152
  console.warn('Failed to set chart option:', e);
78
153
  }
79
154
  }
80
- }, [instance, option, ...deps]);
155
+ }, [instance, option, notMerge, lazyUpdate, replaceMerge, ...deps]);
81
156
  }
82
157
 
83
158
  /**
84
- * 图表自适应Hook
159
+ * 图表自适应 Hook
85
160
  * @param instance 图表实例
161
+ * @param options 配置选项
86
162
  */
87
- export function useResize(instance: ChartInstance | null) {
163
+ export function useResize(
164
+ instance: ChartInstance | null,
165
+ options?: {
166
+ /** 延迟时间 (ms) */
167
+ delay?: number;
168
+ /** 最小宽度 */
169
+ minWidth?: number;
170
+ /** 最小高度 */
171
+ minHeight?: number;
172
+ /** 是否启用 */
173
+ enabled?: boolean;
174
+ }
175
+ ) {
176
+ const { delay = 300, minWidth, minHeight, enabled = true } = options || {};
177
+ const timeoutRef = useRef<NodeJS.Timeout>();
178
+
88
179
  useEffect(() => {
89
- if (!instance) {
180
+ if (!instance || !enabled) {
90
181
  return;
91
182
  }
92
183
 
93
184
  const handleResize = () => {
94
- try {
95
- instance.resize();
96
- } catch (e) {
97
- console.warn('Failed to resize chart:', e);
185
+ if (timeoutRef.current) {
186
+ clearTimeout(timeoutRef.current);
98
187
  }
188
+
189
+ timeoutRef.current = setTimeout(() => {
190
+ try {
191
+ const dom = instance.getDom?.();
192
+ if (dom) {
193
+ const { clientWidth, clientHeight } = dom;
194
+ if (minWidth && clientWidth < minWidth) return;
195
+ if (minHeight && clientHeight < minHeight) return;
196
+ }
197
+ instance.resize?.();
198
+ } catch (e) {
199
+ console.warn('Failed to resize chart:', e);
200
+ }
201
+ }, delay);
99
202
  };
100
203
 
101
204
  window.addEventListener('resize', handleResize);
102
205
 
206
+ // 创建一个 ResizeObserver 来监听容器大小变化
207
+ const dom = instance.getDom?.();
208
+ if (dom && typeof ResizeObserver !== 'undefined') {
209
+ const observer = new ResizeObserver(handleResize);
210
+ observer.observe(dom);
211
+ return () => {
212
+ observer.disconnect();
213
+ window.removeEventListener('resize', handleResize);
214
+ if (timeoutRef.current) clearTimeout(timeoutRef.current);
215
+ };
216
+ }
217
+
103
218
  return () => {
104
219
  window.removeEventListener('resize', handleResize);
220
+ if (timeoutRef.current) clearTimeout(timeoutRef.current);
105
221
  };
106
- }, [instance]);
222
+ }, [instance, delay, minWidth, minHeight, enabled]);
107
223
  }
108
224
 
109
225
  /**
110
- * 图表事件Hook
226
+ * 图表事件 Hook
111
227
  * @param instance 图表实例
112
228
  * @param events 事件对象
113
229
  */
114
230
  export function useEvents(instance: ChartInstance | null, events: Record<string, EventHandler>) {
115
231
  useEffect(() => {
116
- if (!instance) {
232
+ if (!instance || !events) {
117
233
  return;
118
234
  }
119
235
 
@@ -142,11 +258,16 @@ export function useEvents(instance: ChartInstance | null, events: Record<string,
142
258
  }
143
259
 
144
260
  /**
145
- * 图表加载状态Hook
261
+ * 图表加载状态 Hook
146
262
  * @param instance 图表实例
147
263
  * @param loading 是否加载中
264
+ * @param options 加载选项
148
265
  */
149
- export function useLoading(instance: ChartInstance | null, loading: boolean) {
266
+ export function useLoading(
267
+ instance: ChartInstance | null,
268
+ loading: boolean,
269
+ options?: LoadingOptions
270
+ ) {
150
271
  useEffect(() => {
151
272
  if (!instance) {
152
273
  return;
@@ -154,28 +275,33 @@ export function useLoading(instance: ChartInstance | null, loading: boolean) {
154
275
 
155
276
  try {
156
277
  if (loading) {
157
- instance.showLoading();
278
+ instance.showLoading(options);
158
279
  } else {
159
280
  instance.hideLoading();
160
281
  }
161
282
  } catch (e) {
162
283
  console.warn('Failed to set chart loading state:', e);
163
284
  }
164
- }, [instance, loading]);
285
+ }, [instance, loading, options]);
165
286
  }
166
287
 
167
288
  /**
168
289
  * 使用图表主题
169
290
  * @param theme 主题名称或配置
170
- * @param darkMode 是否为暗黑模式
291
+ * @param darkMode 是否为暗色模式
171
292
  * @returns 处理后的主题
172
293
  */
173
- export function useChartTheme(theme: string | Record<string, any>, darkMode = false) {
294
+ export function useChartTheme(theme: string | Record<string, unknown>, darkMode = false) {
174
295
  return useMemo(() => {
175
296
  if (typeof theme === 'string') {
176
- return darkMode ? 'dark' : theme;
297
+ // 如果是字符串,尝试获取内置主题
298
+ try {
299
+ const builtinTheme = getTheme(theme);
300
+ return builtinTheme || (darkMode ? 'dark' : theme);
301
+ } catch {
302
+ return darkMode ? 'dark' : theme;
303
+ }
177
304
  }
178
-
179
305
  return theme;
180
306
  }, [theme, darkMode]);
181
307
  }
@@ -186,20 +312,269 @@ export function useChartTheme(theme: string | Record<string, any>, darkMode = fa
186
312
  * @param transformer 数据转换函数
187
313
  * @returns 转换后的图表选项
188
314
  */
189
- export function useChartData<T = any>(data: T[] | null, transformer: (data: T[]) => ChartOptions) {
315
+ export function useChartData<T = unknown>(data: T | null, transformer: DataTransformer<T>) {
190
316
  return useMemo(() => {
191
- if (!data || data.length === 0) {
192
- return { series: [] };
317
+ if (!data) {
318
+ return {};
193
319
  }
194
-
195
320
  return transformer(data);
196
321
  }, [data, transformer]);
197
322
  }
198
323
 
199
- // 导出版本号
200
- export const version = '1.1.1';
324
+ /**
325
+ * 使用响应式图表配置
326
+ * @param config 响应式配置
327
+ * @returns 当前断点和配置
328
+ */
329
+ export function useResponsive(config?: {
330
+ /** 断点配置 */
331
+ breakpoints?: Record<Breakpoint, number>;
332
+ /** 默认断点 */
333
+ defaultBreakpoint?: Breakpoint;
334
+ }) {
335
+ const { breakpoints = { xs: 0, sm: 576, md: 768, lg: 992, xl: 1200 }, defaultBreakpoint = 'md' } =
336
+ config || {};
337
+
338
+ const [breakpoint, setBreakpoint] = useState<Breakpoint>(defaultBreakpoint);
339
+ const [windowSize, setWindowSize] = useState({ width: 0, height: 0 });
340
+
341
+ useEffect(() => {
342
+ const handleResize = () => {
343
+ const width = window.innerWidth;
344
+ setWindowSize({ width, height: window.innerHeight });
345
+
346
+ // 确定当前断点
347
+ let current: Breakpoint = 'xs';
348
+ if (width >= breakpoints.xl) current = 'xl';
349
+ else if (width >= breakpoints.lg) current = 'lg';
350
+ else if (width >= breakpoints.md) current = 'md';
351
+ else if (width >= breakpoints.sm) current = 'sm';
352
+
353
+ setBreakpoint(current);
354
+ };
355
+
356
+ handleResize();
357
+ window.addEventListener('resize', handleResize);
358
+
359
+ return () => window.removeEventListener('resize', handleResize);
360
+ }, [breakpoints]);
361
+
362
+ return { breakpoint, windowSize };
363
+ }
364
+
365
+ /**
366
+ * 使用主题切换
367
+ * @param initialTheme 初始主题
368
+ * @returns [当前主题, 切换主题函数]
369
+ */
370
+ export function useThemeSwitcher(initialTheme = 'default') {
371
+ const [theme, setTheme] = useState<string | Record<string, unknown>>(initialTheme);
372
+ const [isDark, setIsDark] = useState(false);
373
+
374
+ const switchTheme = useCallback((newTheme: string | Record<string, unknown>) => {
375
+ setTheme(newTheme);
376
+ if (typeof newTheme === 'string') {
377
+ setIsDark(newTheme === 'dark' || newTheme.includes('dark'));
378
+ }
379
+ }, []);
380
+
381
+ const toggleDark = useCallback(() => {
382
+ setIsDark((prev) => !prev);
383
+ setTheme((prev) => (prev === 'dark' ? 'default' : 'dark'));
384
+ }, []);
385
+
386
+ return { theme, isDark, switchTheme, toggleDark, setTheme };
387
+ }
388
+
389
+ /**
390
+ * 使用数据轮询
391
+ * @param fetchFn 数据获取函数
392
+ * @param options 配置选项
393
+ * @returns [数据, 加载状态, 错误, 刷新函数]
394
+ */
395
+ export function useDataPolling<T>(
396
+ fetchFn: () => Promise<T>,
397
+ options?: {
398
+ /** 轮询间隔 (ms) */
399
+ interval?: number;
400
+ /** 是否自动开始 */
401
+ autoStart?: boolean;
402
+ /** 错误重试次数 */
403
+ retryCount?: number;
404
+ /** 重试延迟 (ms) */
405
+ retryDelay?: number;
406
+ }
407
+ ) {
408
+ const { interval = 5000, autoStart = false, retryCount = 3, retryDelay = 1000 } = options || {};
409
+
410
+ const [data, setData] = useState<T | null>(null);
411
+ const [loading, setLoading] = useState(autoStart);
412
+ const [error, setError] = useState<Error | null>(null);
413
+ const [refreshIndex, setRefreshIndex] = useState(0);
414
+
415
+ const fetchData = useCallback(async () => {
416
+ let retries = retryCount;
417
+ setLoading(true);
418
+ setError(null);
419
+
420
+ while (retries >= 0) {
421
+ try {
422
+ const result = await fetchFn();
423
+ setData(result);
424
+ setLoading(false);
425
+ return;
426
+ } catch (e) {
427
+ retries--;
428
+ if (retries < 0) {
429
+ setError(e as Error);
430
+ setLoading(false);
431
+ } else {
432
+ await new Promise((resolve) => setTimeout(resolve, retryDelay));
433
+ }
434
+ }
435
+ }
436
+ }, [fetchFn, retryCount, retryDelay]);
437
+
438
+ useEffect(() => {
439
+ if (autoStart) {
440
+ fetchData();
441
+ }
442
+
443
+ if (interval > 0) {
444
+ const timer = setInterval(fetchData, interval);
445
+ return () => clearInterval(timer);
446
+ }
447
+ }, [interval, autoStart, fetchData, refreshIndex]);
448
+
449
+ const refresh = useCallback(() => {
450
+ setRefreshIndex((prev) => prev + 1);
451
+ fetchData();
452
+ }, [fetchData]);
453
+
454
+ return { data, loading, error, refresh };
455
+ }
456
+
457
+ /**
458
+ * 使用图表全屏
459
+ * @param chartRef 图表容器引用
460
+ * @returns [是否全屏, 进入/退出全屏函数]
461
+ */
462
+ export function useFullscreen(chartRef: React.RefObject<HTMLElement>) {
463
+ const [isFullscreen, setIsFullscreen] = useState(false);
464
+
465
+ const toggle = useCallback(() => {
466
+ if (!chartRef.current) return;
467
+
468
+ if (!isFullscreen) {
469
+ if (chartRef.current.requestFullscreen) {
470
+ chartRef.current.requestFullscreen();
471
+ }
472
+ } else {
473
+ if (document.exitFullscreen) {
474
+ document.exitFullscreen();
475
+ }
476
+ }
477
+ }, [chartRef, isFullscreen]);
478
+
479
+ useEffect(() => {
480
+ const handleChange = () => {
481
+ setIsFullscreen(!!document.fullscreenElement);
482
+ };
483
+
484
+ document.addEventListener('fullscreenchange', handleChange);
485
+ return () => document.removeEventListener('fullscreenchange', handleChange);
486
+ }, []);
487
+
488
+ return { isFullscreen, toggle };
489
+ }
490
+
491
+ /**
492
+ * 使用图表导出
493
+ * @param instance 图表实例
494
+ * @returns 导出函数
495
+ */
496
+ export function useExport(instance: ChartInstance | null) {
497
+ const inst = instance as any;
498
+ const exportImage = useCallback(
499
+ (options?: { type?: 'png' | 'jpeg'; pixelRatio?: number; backgroundColor?: string }) => {
500
+ if (!inst) return null;
501
+ const { type = 'png', pixelRatio = 2, backgroundColor } = options || {};
502
+ return inst.getDataURL?.({ type, pixelRatio, backgroundColor });
503
+ },
504
+ [inst]
505
+ );
506
+
507
+ const exportSVG = useCallback(() => {
508
+ if (!inst) return null;
509
+ return inst.getSvgData?.();
510
+ }, [inst]);
511
+
512
+ const exportCSV = useCallback(
513
+ (options?: { seriesIndex?: number; dimension?: number }) => {
514
+ if (!inst) return null;
515
+ return inst.getCompressedDataURL?.(options);
516
+ },
517
+ [inst]
518
+ );
519
+
520
+ return { exportImage, exportSVG, exportCSV };
521
+ }
522
+
523
+ /**
524
+ * 使用图表工具
525
+ * @param instance 图表实例
526
+ * @returns 工具函数
527
+ */
528
+ export function useChartTools(instance: ChartInstance | null) {
529
+ const inst = instance as any;
530
+ const getInstance = useCallback(() => instance, [instance]);
531
+
532
+ const clear = useCallback(() => {
533
+ inst?.clear?.();
534
+ }, [inst]);
535
+
536
+ const repaint = useCallback(() => {
537
+ inst?.resize?.();
538
+ }, [inst]);
539
+
540
+ const dispatchAction = useCallback(
541
+ (action: { type: string; [key: string]: unknown }) => {
542
+ inst?.dispatchAction?.(action);
543
+ },
544
+ [inst]
545
+ );
546
+
547
+ const showTip = useCallback(
548
+ (seriesIndex?: number, dataIndex?: number) => {
549
+ inst?.dispatchAction?.({ type: 'showTip', seriesIndex, dataIndex });
550
+ },
551
+ [inst]
552
+ );
553
+
554
+ const hideTip = useCallback(() => {
555
+ inst?.dispatchAction?.({ type: 'hideTip' });
556
+ }, [inst]);
557
+
558
+ const zoom = useCallback(
559
+ (start?: number, end?: number) => {
560
+ inst?.dispatchAction?.({
561
+ type: 'dataZoom',
562
+ start: start ?? 0,
563
+ end: end ?? 100,
564
+ });
565
+ },
566
+ [inst]
567
+ );
568
+
569
+ return { getInstance, clear, repaint, dispatchAction, showTip, hideTip, zoom };
570
+ }
571
+
572
+ // ============================================================================
573
+ // 导出
574
+ // ============================================================================
575
+
576
+ export const version = '1.2.0';
201
577
 
202
- // 导出所有hooks到默认导出对象
203
578
  const hooks = {
204
579
  useChart,
205
580
  useOption,
@@ -208,7 +583,12 @@ const hooks = {
208
583
  useLoading,
209
584
  useChartTheme,
210
585
  useChartData,
586
+ useResponsive,
587
+ useThemeSwitcher,
588
+ useDataPolling,
589
+ useFullscreen,
590
+ useExport,
591
+ useChartTools,
211
592
  };
212
593
 
213
- // 为了同时支持具名导入和默认导入
214
594
  export default hooks;
package/src/main.tsx CHANGED
@@ -163,7 +163,7 @@ const TestApp = () => {
163
163
  <select
164
164
  id="theme"
165
165
  value={darkMode ? 'dark' : 'light'}
166
- onChange={e => setDarkMode(e.target.value === 'dark')}
166
+ onChange={(e) => setDarkMode(e.target.value === 'dark')}
167
167
  >
168
168
  <option value="light">Light</option>
169
169
  <option value="dark">Dark</option>